mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-03 04:38:33 +00:00
feat: add Stronkter catalog blocks (#570)
## Problem The Catalog did not include the four prompt-matched Stronkter one-shot HyperFrames projects, and registry metadata only supported a plain author string, so there was no structured way to show creator attribution or the original generation prompt on generated catalog pages. ## What this fixes - Adds four Catalog blocks matching the provided prompts, in order: - `north-korea-locked-down` - `apple-money-count` - `nyc-paris-flight` - `goonvpn-youtube-spot` - Attributes each block to [Stronkter](https://x.com/Stronkter). - Stores and renders the original source prompt for each generated catalog page. - Adds a local realistic map plate for the North Korea block so rendering does not depend on live map tile requests. - Extends registry item metadata/schema with `authorUrl` and `sourcePrompt`. - Updates catalog page generation to read items from `registry/registry.json`, keeping generated docs aligned to the public registry manifest. - Ignores normal browser media preload `net::ERR_ABORTED` request failures for media assets during `hyperframes validate`, while preserving failures for real missing assets. ## Root cause The imported projects are Catalog-ready compositions, but the registry/docs pipeline did not have first-class source-prompt or linked-author fields to expose creator credit on generated MDX pages. The audio-backed compositions also surfaced a validation edge case: Chrome can report aborted media preload requests as `net::ERR_ABORTED` even when the audio file exists and playback is valid. ## Verification ### Local - `bun run --filter @hyperframes/cli test src/commands/validate.test.ts` - `bun run --filter @hyperframes/core test src/registry/types.test.ts` - `bun run sync-schemas:check` - `bunx oxlint packages/cli/src/commands/validate.ts packages/cli/src/commands/validate.test.ts packages/core/src/registry/types.ts packages/core/src/registry/types.test.ts scripts/generate-catalog-pages.ts` - `bunx oxfmt --check ...` on changed source, registry, docs, and composition files - `git diff --check` - `bun packages/cli/src/cli.ts lint` and `validate` against temp installed projects for all four blocks - Lefthook pre-commit: lint/format/typecheck on the initial commit, plus format on the amend - Lefthook commit-msg: commitlint ### Browser - Exercised all four blocks through HyperFrames preview routes with `agent-browser`. - Captured playback screenshots and WebM recordings for: - `north-korea-locked-down` - `apple-money-count` - `nyc-paris-flight` - `goonvpn-youtube-spot` ## Notes - The zip also contained unrelated project directories, but this PR intentionally includes only the four prompt-matched Catalog blocks requested here. - The imported one-shot compositions may trigger the existing large-composition lint warning, but there are no lint errors and runtime validation passes.
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { shouldIgnoreRequestFailure } from "./validate.js";
|
||||
|
||||
describe("shouldIgnoreRequestFailure", () => {
|
||||
it("ignores aborted media preload requests", () => {
|
||||
expect(
|
||||
shouldIgnoreRequestFailure("http://127.0.0.1:3000/assets/sfx.wav", "net::ERR_ABORTED"),
|
||||
).toBe(true);
|
||||
expect(shouldIgnoreRequestFailure("http://127.0.0.1:3000/video.mp4", "net::ERR_ABORTED")).toBe(
|
||||
true,
|
||||
);
|
||||
});
|
||||
|
||||
it("keeps non-media and non-aborted failures reportable", () => {
|
||||
expect(
|
||||
shouldIgnoreRequestFailure("http://127.0.0.1:3000/assets/map.png", "net::ERR_ABORTED"),
|
||||
).toBe(false);
|
||||
expect(
|
||||
shouldIgnoreRequestFailure("http://127.0.0.1:3000/assets/sfx.wav", "net::ERR_FAILED"),
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -29,6 +29,16 @@ interface ContrastEntry {
|
||||
|
||||
const CONTRAST_SAMPLES = 5;
|
||||
const SEEK_SETTLE_MS = 150;
|
||||
const MEDIA_EXTENSIONS = /\.(aac|flac|m4a|mov|mp3|mp4|oga|ogg|wav|webm)$/i;
|
||||
|
||||
export function shouldIgnoreRequestFailure(url: string, errorText: string | undefined): boolean {
|
||||
if (errorText !== "net::ERR_ABORTED") return false;
|
||||
try {
|
||||
return MEDIA_EXTENSIONS.test(new URL(url).pathname);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function getCompositionDuration(page: import("puppeteer-core").Page): Promise<number> {
|
||||
return page.evaluate(() => {
|
||||
@@ -183,10 +193,12 @@ async function validateInBrowser(
|
||||
page.on("requestfailed", (req) => {
|
||||
const url = req.url();
|
||||
if (url.includes("favicon") || url.startsWith("data:")) return;
|
||||
const failureText = req.failure()?.errorText;
|
||||
if (shouldIgnoreRequestFailure(url, failureText)) return;
|
||||
const path = decodeURIComponent(new URL(url).pathname).replace(/^\//, "");
|
||||
errors.push({
|
||||
level: "error",
|
||||
text: `Failed to load ${path}: ${req.failure()?.errorText ?? "net::ERR_FAILED"}`,
|
||||
text: `Failed to load ${path}: ${failureText ?? "net::ERR_FAILED"}`,
|
||||
url,
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user