From 663f3e8325c192324520113fa1819b3e1fcdd07a Mon Sep 17 00:00:00 2001 From: ukimsanov Date: Tue, 4 Aug 2026 11:53:37 -0700 Subject: [PATCH] fix(docs): the poster guard again, for the catalog index this time MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous commit claimed all 597 media URLs returned 200. They did not — 13 still 403'd, and I pushed that claim without re-running the check after the fix. The message was wrong; this is the correction. Two files carry a poster, not one. Guarding the page generator left catalog-index.json still pointing at 13 .png files that were never produced, which is a broken thumbnail in the catalog grid rather than a missing one. catalogPreviewFor now returns undefined when the file is absent, the same rule the page preview uses, and the 13 stale entries are dropped from the written index. Verified after the change, not before: 584 media URLs on this branch, 0 dead. --- docs/public/catalog-index.json | 115 +++++++++++++----------------- scripts/generate-catalog-pages.ts | 8 ++- 2 files changed, 57 insertions(+), 66 deletions(-) diff --git a/docs/public/catalog-index.json b/docs/public/catalog-index.json index 4789619fb..851827ebd 100644 --- a/docs/public/catalog-index.json +++ b/docs/public/catalog-index.json @@ -76,7 +76,7 @@ "name": "caption-blend-difference", "type": "component", "title": "Blend Difference", - "description": "Auto-inverting text using mix-blend-mode: difference — flips between white and black per-pixel against the background", + "description": "Auto-inverting text using mix-blend-mode: difference \u2014 flips between white and black per-pixel against the background", "tags": [ "text", "text-effect", @@ -284,7 +284,7 @@ "name": "caption-texture", "type": "component", "title": "Texture", - "description": "Flowing texture mask over large uppercase text — ships with 6 textures (lava, marble, metal, wood, concrete, rock), configurable via the texture variable", + "description": "Flowing texture mask over large uppercase text \u2014 ships with 6 textures (lava, marble, metal, wood, concrete, rock), configurable via the texture variable", "tags": [ "captions", "caption-style", @@ -336,7 +336,7 @@ "name": "code-3d-extrude", "type": "block", "title": "Code 3D Extrude", - "description": "Syntax-highlighted code on a lit, beveled 3D slab that rotates through real space and settles to a readable rest — true WebGL depth and lighting, not a 2D transform.", + "description": "Syntax-highlighted code on a lit, beveled 3D slab that rotates through real space and settles to a readable rest \u2014 true WebGL depth and lighting, not a 2D transform.", "tags": [ "code", "code-animation", @@ -351,7 +351,7 @@ "name": "code-diff", "type": "block", "title": "Code Diff", - "description": "An edit shown as a colored diff — removed lines collapse in red, added lines expand in green.", + "description": "An edit shown as a colored diff \u2014 removed lines collapse in red, added lines expand in green.", "tags": [ "code", "code-animation", @@ -365,7 +365,7 @@ "name": "code-highlight", "type": "block", "title": "Code Highlight Sweep", - "description": "A highlight band sweeps across a target line while the surrounding context dims — draws the eye to one line. `line` is 0-based: `line: 1` targets the second displayed line (unlike code-scroll, whose target is 1-based).", + "description": "A highlight band sweeps across a target line while the surrounding context dims \u2014 draws the eye to one line. `line` is 0-based: `line: 1` targets the second displayed line (unlike code-scroll, whose target is 1-based).", "tags": [ "code", "code-animation", @@ -379,7 +379,7 @@ "name": "code-morph", "type": "block", "title": "Code Morph", - "description": "One snippet transforms into another — tokens glide between positions, leavers fade out, enterers fade in. Shiki Magic Move re-driven as a paused GSAP timeline.", + "description": "One snippet transforms into another \u2014 tokens glide between positions, leavers fade out, enterers fade in. Shiki Magic Move re-driven as a paused GSAP timeline.", "tags": [ "code", "code-animation", @@ -394,7 +394,7 @@ "name": "code-particle-assemble", "type": "block", "title": "Code Particle Assemble", - "description": "Thousands of GPU points scatter through space and fly to the exact glyph pixels of the code, resolving into readable syntax-highlighted text — a particle system, not a token tween.", + "description": "Thousands of GPU points scatter through space and fly to the exact glyph pixels of the code, resolving into readable syntax-highlighted text \u2014 a particle system, not a token tween.", "tags": [ "code", "code-animation", @@ -410,7 +410,7 @@ "name": "code-scroll", "type": "block", "title": "Code Scroll To Line", - "description": "The camera scrolls a long file to bring a target line to center and spotlights it — for walking through real modules.", + "description": "The camera scrolls a long file to bring a target line to center and spotlights it \u2014 for walking through real modules.", "tags": [ "code", "code-animation", @@ -448,8 +448,7 @@ "apple", "apple-terminal" ], - "href": "/catalog/blocks/code-snippet-apple-terminal-basic", - "preview": "https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-apple-terminal-basic.png" + "href": "/catalog/blocks/code-snippet-apple-terminal-basic" }, { "name": "code-snippet-apple-terminal-clear-dark", @@ -464,8 +463,7 @@ "apple", "apple-terminal" ], - "href": "/catalog/blocks/code-snippet-apple-terminal-clear-dark", - "preview": "https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-apple-terminal-clear-dark.png" + "href": "/catalog/blocks/code-snippet-apple-terminal-clear-dark" }, { "name": "code-snippet-apple-terminal-clear-light", @@ -480,8 +478,7 @@ "apple", "apple-terminal" ], - "href": "/catalog/blocks/code-snippet-apple-terminal-clear-light", - "preview": "https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-apple-terminal-clear-light.png" + "href": "/catalog/blocks/code-snippet-apple-terminal-clear-light" }, { "name": "code-snippet-apple-terminal-grass", @@ -496,8 +493,7 @@ "apple", "apple-terminal" ], - "href": "/catalog/blocks/code-snippet-apple-terminal-grass", - "preview": "https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-apple-terminal-grass.png" + "href": "/catalog/blocks/code-snippet-apple-terminal-grass" }, { "name": "code-snippet-apple-terminal-homebrew", @@ -512,8 +508,7 @@ "apple", "apple-terminal" ], - "href": "/catalog/blocks/code-snippet-apple-terminal-homebrew", - "preview": "https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-apple-terminal-homebrew.png" + "href": "/catalog/blocks/code-snippet-apple-terminal-homebrew" }, { "name": "code-snippet-apple-terminal-man-page", @@ -528,8 +523,7 @@ "apple", "apple-terminal" ], - "href": "/catalog/blocks/code-snippet-apple-terminal-man-page", - "preview": "https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-apple-terminal-man-page.png" + "href": "/catalog/blocks/code-snippet-apple-terminal-man-page" }, { "name": "code-snippet-apple-terminal-novel", @@ -544,8 +538,7 @@ "apple", "apple-terminal" ], - "href": "/catalog/blocks/code-snippet-apple-terminal-novel", - "preview": "https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-apple-terminal-novel.png" + "href": "/catalog/blocks/code-snippet-apple-terminal-novel" }, { "name": "code-snippet-apple-terminal-ocean", @@ -560,8 +553,7 @@ "apple", "apple-terminal" ], - "href": "/catalog/blocks/code-snippet-apple-terminal-ocean", - "preview": "https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-apple-terminal-ocean.png" + "href": "/catalog/blocks/code-snippet-apple-terminal-ocean" }, { "name": "code-snippet-apple-terminal-pro", @@ -576,8 +568,7 @@ "apple", "apple-terminal" ], - "href": "/catalog/blocks/code-snippet-apple-terminal-pro", - "preview": "https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-apple-terminal-pro.png" + "href": "/catalog/blocks/code-snippet-apple-terminal-pro" }, { "name": "code-snippet-apple-terminal-red-sands", @@ -592,8 +583,7 @@ "apple", "apple-terminal" ], - "href": "/catalog/blocks/code-snippet-apple-terminal-red-sands", - "preview": "https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-apple-terminal-red-sands.png" + "href": "/catalog/blocks/code-snippet-apple-terminal-red-sands" }, { "name": "code-snippet-apple-terminal-silver-aerogel", @@ -608,8 +598,7 @@ "apple", "apple-terminal" ], - "href": "/catalog/blocks/code-snippet-apple-terminal-silver-aerogel", - "preview": "https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-apple-terminal-silver-aerogel.png" + "href": "/catalog/blocks/code-snippet-apple-terminal-silver-aerogel" }, { "name": "code-snippet-apple-terminal-solid-colors", @@ -624,8 +613,7 @@ "apple", "apple-terminal" ], - "href": "/catalog/blocks/code-snippet-apple-terminal-solid-colors", - "preview": "https://static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/code-snippet-apple-terminal-solid-colors.png" + "href": "/catalog/blocks/code-snippet-apple-terminal-solid-colors" }, { "name": "code-snippet-dark-2026", @@ -813,7 +801,7 @@ "name": "code-typing", "type": "block", "title": "Code Typing", - "description": "Token-streamed typing reveal with a caret that tracks the frontier — deterministic, no CSS animation.", + "description": "Token-streamed typing reveal with a caret that tracks the frontier \u2014 deterministic, no CSS animation.", "tags": [ "code", "code-animation", @@ -949,7 +937,7 @@ "name": "grain-overlay", "type": "component", "title": "Grain Overlay", - "description": "Animated film grain texture overlay using CSS keyframes — adds warmth and analog character to any composition", + "description": "Animated film grain texture overlay using CSS keyframes \u2014 adds warmth and analog character to any composition", "tags": [ "texture", "grain", @@ -975,7 +963,7 @@ "name": "grid-pixelate-wipe", "type": "component", "title": "Grid Pixelate Wipe", - "description": "Transition effect where the screen dissolves into a grid of squares that fade out with staggered timing — use between scenes", + "description": "Transition effect where the screen dissolves into a grid of squares that fade out with staggered timing \u2014 use between scenes", "tags": [ "transition", "wipe", @@ -1244,7 +1232,7 @@ { "name": "lower-third-bild", "type": "block", - "title": "Lower Third — BILD Style", + "title": "Lower Third \u2014 BILD Style", "description": "News-style lower third with tight-fit text boxes: white headline bar with red drop-shadow, red sub-line with white drop-shadow.", "tags": [ "broadcast", @@ -1258,7 +1246,7 @@ { "name": "lt-accent-underline", "type": "block", - "title": "Lower Third — Accent Underline", + "title": "Lower Third \u2014 Accent Underline", "description": "Cardless lower third for footage overlay: name rises, an accent rule draws left-to-right, role fades in; text-shadowed for legibility", "tags": [ "lower-third", @@ -1273,7 +1261,7 @@ { "name": "lt-bold-block", "type": "block", - "title": "Lower Third — Bold Block", + "title": "Lower Third \u2014 Bold Block", "description": "High-energy podcast lower third: solid dark block wipes in, uppercase name slams up, accent tag pops", "tags": [ "lower-third", @@ -1288,7 +1276,7 @@ { "name": "lt-clean-bar", "type": "block", - "title": "Lower Third — Clean Bar", + "title": "Lower Third \u2014 Clean Bar", "description": "Minimal white-card lower third for podcasts/interviews: accent tab, name + role, clip-wipe entrance", "tags": [ "lower-third", @@ -1302,7 +1290,7 @@ { "name": "lt-color-block", "type": "block", - "title": "Lower Third — Color Block", + "title": "Lower Third \u2014 Color Block", "description": "High-energy lower third: bold accent-color block slides in with overshoot, condensed name + mono role", "tags": [ "lower-third", @@ -1317,7 +1305,7 @@ { "name": "lt-dark-card", "type": "block", - "title": "Lower Third — Dark Card", + "title": "Lower Third \u2014 Dark Card", "description": "Charcoal card lower third for bright footage: name, drawn accent underline, role; slide-up entrance", "tags": [ "lower-third", @@ -1332,7 +1320,7 @@ { "name": "lt-kicker-name", "type": "block", - "title": "Lower Third — Kicker Name", + "title": "Lower Third \u2014 Kicker Name", "description": "Cardless lower third with an accent eyebrow/kicker tag, heavy name, and a drawn baseline; for footage", "tags": [ "lower-third", @@ -1347,7 +1335,7 @@ { "name": "lt-mask-reveal", "type": "block", - "title": "Lower Third — Mask Reveal", + "title": "Lower Third \u2014 Mask Reveal", "description": "Cardless lower third: an accent sweep crosses and clip-path-reveals a heavy name, role fades up; for footage", "tags": [ "lower-third", @@ -1362,7 +1350,7 @@ { "name": "lt-side-rule", "type": "block", - "title": "Lower Third — Side Rule", + "title": "Lower Third \u2014 Side Rule", "description": "Cardless lower third with a vertical accent bar; condensed display name + mono role, text-shadowed for footage", "tags": [ "lower-third", @@ -1377,7 +1365,7 @@ { "name": "lt-soft-pill", "type": "block", - "title": "Lower Third — Soft Pill", + "title": "Lower Third \u2014 Soft Pill", "description": "Rounded white pill lower third for podcasts/interviews: status dot, name + role, scale-pop entrance", "tags": [ "lower-third", @@ -1392,7 +1380,7 @@ { "name": "lt-stack-bars", "type": "block", - "title": "Lower Third — Stack Bars", + "title": "Lower Third \u2014 Stack Bars", "description": "Two stacked bars: a dark name bar wipes from the left, an accent role bar wipes from the right", "tags": [ "lower-third", @@ -1451,7 +1439,7 @@ "name": "mk-callout-highlight", "type": "block", "title": "Word-Sweep Highlight", - "description": "A sentence whose word-by-word emphasis is driven by a single scalar — tween it to sync the highlight with a voiceover", + "description": "A sentence whose word-by-word emphasis is driven by a single scalar \u2014 tween it to sync the highlight with a voiceover", "tags": [ "typography", "karaoke", @@ -1465,7 +1453,7 @@ "name": "mk-clone-wall-transition", "type": "block", "title": "Text Clone Wall Transition", - "description": "Overlay transition: a tiled word wall covers the frame, inverts via difference blending, and clears — hard-cut the content beneath while covered", + "description": "Overlay transition: a tiled word wall covers the frame, inverts via difference blending, and clears \u2014 hard-cut the content beneath while covered", "tags": [ "transition", "typography", @@ -1478,7 +1466,7 @@ "name": "mk-emphasis-type", "type": "component", "title": "Background Emphasis Type", - "description": "Oversized low-contrast background word drifting slowly behind the subject — typography as texture", + "description": "Oversized low-contrast background word drifting slowly behind the subject \u2014 typography as texture", "tags": [ "typography", "text-treatment", @@ -1559,7 +1547,7 @@ "name": "morph-text", "type": "component", "title": "Morph Text", - "description": "Gooey text morph — cycles through an editable word list using SVG threshold + GSAP-driven blur for a fluid, satisfying transition effect", + "description": "Gooey text morph \u2014 cycles through an editable word list using SVG threshold + GSAP-driven blur for a fluid, satisfying transition effect", "tags": [ "text", "text-effect", @@ -1569,14 +1557,13 @@ "kinetic", "animation" ], - "href": "/catalog/components/morph-text", - "preview": "https://static.heygen.ai/hyperframes-oss/docs/images/catalog/components/morph-text.png" + "href": "/catalog/components/morph-text" }, { "name": "motion-blur", "type": "component", "title": "Motion Blur", - "description": "Velocity-driven motion blur — samples element position each frame and applies a one-sided SVG feGaussianBlur ghost trail proportional to speed", + "description": "Velocity-driven motion blur \u2014 samples element position each frame and applies a one-sided SVG feGaussianBlur ghost trail proportional to speed", "tags": [ "effect", "motion-blur", @@ -1651,7 +1638,7 @@ "name": "parallax-unzoom", "type": "component", "title": "Parallax Unzoom", - "description": "Reveal transition — focus card scales down from full frame as siblings parallax in to form a grid (reverse of parallax-zoom)", + "description": "Reveal transition \u2014 focus card scales down from full frame as siblings parallax in to form a grid (reverse of parallax-zoom)", "tags": [ "transition", "reveal", @@ -1667,7 +1654,7 @@ "name": "parallax-zoom", "type": "component", "title": "Parallax Zoom", - "description": "Center card scales up to fill the frame while siblings parallax outward — inspired by the eBay Playbook hero transition", + "description": "Center card scales up to fill the frame while siblings parallax outward \u2014 inspired by the eBay Playbook hero transition", "tags": [ "transition", "zoom", @@ -1731,7 +1718,7 @@ "name": "shimmer-sweep", "type": "component", "title": "Shimmer Sweep", - "description": "Animated light sweep across text or elements using a CSS gradient mask — ideal for AI accents and premium reveals", + "description": "Animated light sweep across text or elements using a CSS gradient mask \u2014 ideal for AI accents and premium reveals", "tags": [ "text", "shimmer", @@ -1745,7 +1732,7 @@ "name": "spain-map", "type": "block", "title": "Spain Map", - "description": "Animated Spain choropleth by autonomous community with staggered reveals and gradient legend — D3 conic conformal projection", + "description": "Animated Spain choropleth by autonomous community with staggered reveals and gradient legend \u2014 D3 conic conformal projection", "tags": [ "data", "map", @@ -1995,7 +1982,7 @@ "name": "us-map", "type": "block", "title": "US Map", - "description": "Animated US choropleth map with staggered state reveals, value labels, and gradient legend — pure inline SVG with GSAP", + "description": "Animated US choropleth map with staggered state reveals, value labels, and gradient legend \u2014 pure inline SVG with GSAP", "tags": [ "data", "map", @@ -2010,7 +1997,7 @@ "name": "us-map-bubble", "type": "block", "title": "US Bubble Map", - "description": "Animated US bubble map with proportional city markers, value callouts, and connection lines — composable with us-map", + "description": "Animated US bubble map with proportional city markers, value callouts, and connection lines \u2014 composable with us-map", "tags": [ "data", "map", @@ -2026,7 +2013,7 @@ "name": "us-map-flow", "type": "block", "title": "US Flow Map", - "description": "Animated connection arcs between US cities over a base map — composable origin-destination flow visualization", + "description": "Animated connection arcs between US cities over a base map \u2014 composable origin-destination flow visualization", "tags": [ "data", "map", @@ -2043,7 +2030,7 @@ "name": "us-map-hex", "type": "block", "title": "US Hex Grid Map", - "description": "Animated hexagonal tile grid map — each state as an equal-weight hex with data fill and abbreviation label", + "description": "Animated hexagonal tile grid map \u2014 each state as an equal-weight hex with data fill and abbreviation label", "tags": [ "data", "map", @@ -2059,7 +2046,7 @@ "name": "vfx-iphone-device", "type": "block", "title": "iPhone & MacBook 3D Showcase", - "description": "Real GLTF iPhone 15 Pro Max and MacBook Pro models with live HTML-in-Canvas screen content, morphing glass lens, product review camera choreography, and 360° turntable.", + "description": "Real GLTF iPhone 15 Pro Max and MacBook Pro models with live HTML-in-Canvas screen content, morphing glass lens, product review camera choreography, and 360\u00b0 turntable.", "tags": [ "html-in-canvas", "3d", @@ -2153,7 +2140,7 @@ "name": "vignette", "type": "component", "title": "Vignette", - "description": "Cinematic radial vignette overlay using a pure-CSS gradient — darkens the edges to pull focus toward the center", + "description": "Cinematic radial vignette overlay using a pure-CSS gradient \u2014 darkens the edges to pull focus toward the center", "tags": [ "vignette", "overlay", @@ -2193,7 +2180,7 @@ "name": "world-map", "type": "block", "title": "World Map", - "description": "Animated world choropleth with country-by-country reveal, tooltip labels, and rotating globe inset — D3 Natural Earth projection", + "description": "Animated world choropleth with country-by-country reveal, tooltip labels, and rotating globe inset \u2014 D3 Natural Earth projection", "tags": [ "data", "map", diff --git a/scripts/generate-catalog-pages.ts b/scripts/generate-catalog-pages.ts index 1c7e67242..645bb240f 100644 --- a/scripts/generate-catalog-pages.ts +++ b/scripts/generate-catalog-pages.ts @@ -403,9 +403,13 @@ function generateTexturePreview(manifest: RegistryItem, textureGroups: TextureGr return lines; } -function catalogPreviewFor(kind: ItemKind, manifest: RegistryItem): string { +function catalogPreviewFor(kind: ItemKind, manifest: RegistryItem): string | undefined { const dir = typeDir(kind); - return `${catalogImageBase}/${dir}/${manifest.name}.png`; + // Same rule as the page preview: thirteen items have an .mp4 and no .png, and + // a preview pointing at a file that does not exist is a broken thumbnail in + // the catalog grid rather than a missing one. + const file = join(REPO_ROOT, "docs", "images", "catalog", dir, `${manifest.name}.png`); + return existsSync(file) ? `${catalogImageBase}/${dir}/${manifest.name}.png` : undefined; } function yamlString(value: string): string {