Skip to content

ci: render catalog previews on PR#262

Merged
jrusso1020 merged 1 commit into
mainfrom
04-14-ci_render_catalog_previews_on_pr
Apr 14, 2026
Merged

ci: render catalog previews on PR#262
jrusso1020 merged 1 commit into
mainfrom
04-14-ci_render_catalog_previews_on_pr

Conversation

@jrusso1020

@jrusso1020 jrusso1020 commented Apr 14, 2026

Copy link
Copy Markdown
Collaborator

What

CI workflow that auto-renders preview thumbnails for new/changed registry blocks and components on pull requests.

New files:

  • scripts/generate-catalog-previews.ts — catalog preview renderer supporting all three registry item types
  • .github/workflows/catalog-previews.yml — GitHub Actions workflow triggered on PRs touching registry/blocks/ or registry/components/

Why

Phase B of the catalog plan (PR 8). After this lands, future block/component PRs don't need to manually generate preview images — CI handles it automatically.

How

The preview script discovers items from the registry directory structure:

  • Examples: renders index.html (same as the existing generate-template-previews.ts)
  • Blocks: renders the block's standalone HTML file directly (e.g., data-chart.html)
  • Components: renders the component's demo.html (the demo.html convention from PR 7)

The CI workflow:

  1. Detects which blocks/components changed in the PR via git diff
  2. Renders thumbnails for only the changed items (not the full catalog)
  3. Uploads preview PNGs as artifacts

Output goes to docs/images/catalog/<type>/<name>.{png,mp4} (separate from the existing docs/images/templates/ directory).

Supports CLI flags: --only <name>, --type <example|block|component>, --skip-video.

Test plan

  • Script compiles and passes typecheck (lefthook pre-commit ran lint + typecheck + format)
  • Workflow YAML is valid (standard GitHub Actions syntax, follows existing ci.yml patterns)
  • Full end-to-end test requires Chrome + FFmpeg (runs in CI, not testable locally without producer deps)

@miguel-heygen miguel-heygen left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: ci: render catalog previews on PR

Solid foundation — the script follows the established generate-template-previews.ts patterns well, and the workflow structure is clean. However, the CI run already exposed two real bugs, plus there are a few things worth tightening up before this lands.


Critical (must fix)

1. grep -P lookbehind fails on Ubuntu runner

The CI logs show:

grep: lookbehind assertion is not fixed length

This is the line:

grep -oP '(?<=registry/(blocks|components)/)[^/]+'

grep -P with a variable-length lookbehind ((blocks|components) has alternation of different lengths) is not supported by PCRE on the Ubuntu runner's grep. This silently fails, meaning no items are ever detected as changed.

Fix — use sed or awk instead:

sed -n 's|^registry/\(blocks\|components\)/\([^/]*\)/.*|\2|p' | sort -u

Or restructure as two greps:

grep -E '^registry/(blocks|components)/' | sed 's|^registry/[^/]*/\([^/]*\)/.*|\1|' | sort -u

2. origin/main ref does not exist — shallow checkout

The CI logs also show:

fatal: bad revision 'origin/main...HEAD'

actions/checkout@v4 performs a shallow clone of the PR merge ref by default. origin/main is not fetched. The workflow needs to either:

(a) Add fetch-depth: 0 to checkout (fetches full history — heavier), or
(b) Use ${{ github.event.pull_request.base.sha }} instead of origin/main:

git diff --name-only ${{ github.event.pull_request.base.sha }}...HEAD -- registry/blocks/ registry/components/

Option (b) is more precise since it diffs against the actual PR base, not main (the PR's base branch is 04-14-feat_registry_seed_components_..., not main). But it still requires fetching the base SHA. Consider:

- uses: actions/checkout@v4
  with:
    fetch-depth: 0

Or fetch just the base:

- uses: actions/checkout@v4
- run: git fetch origin ${{ github.event.pull_request.base.sha }} --depth=1

Both bugs together mean the workflow currently never renders anything — it always falls through to "No block/component changes detected." The CI passed only because the step has continue-on-error: true and the upload step uses if-no-files-found: ignore.


Important (should fix)

3. continue-on-error: true masks all failures

The render step has continue-on-error: true, which means even if the grep/git bugs above were fixed and rendering genuinely fails, the job still reports green. This defeats the purpose of CI feedback.

The script already has per-item try/catch with ::warning:: annotations. Remove continue-on-error: true from the step and let the exit code propagate. If the intent is "don't block merge on preview failures," make the job non-required in branch protection instead.

4. Script hardcodes origin/main as diff base in the workflow

Even after fixing the checkout issue, diffing against origin/main is wrong when the PR targets a feature branch (like this one targets 04-14-feat_registry_seed_components_...). Use the PR base ref:

git diff --name-only $GITHUB_BASE_REF...HEAD -- registry/blocks/ registry/components/

or use the base SHA from the event payload.

5. The --type example CLI flag is accepted but has no effect

The PR description and doc comment say the script supports --type example, but the ItemKind type is "block" | "component" and the discovery function only scans blocks/ and components/. Passing --type example would silently return zero items (since "example" fails the kindFilter !== kind check for both block and component).

Either:

  • Remove mentions of "example" from the doc comment and PR description, or
  • Add a proper error message for invalid --type values (currently only "block" and "component" are validated in parseArgs, so "example" would hit the error — actually wait, I re-read: parseArgs does validate and process.exit(1) on invalid type. Good. But the doc comment at the top still says "Examples: renders index.html" which is misleading since examples aren't handled by this script.)

Update the doc comment to remove the "Examples" bullet point and clarify this script handles blocks and components only.


Suggestions (nice to have)

6. Pin Chrome and FFmpeg versions

browser-actions/setup-chrome@v1 with chrome-version: stable and FedericoCarboni/setup-ffmpeg@v3 without a version pin mean the rendering environment can change between runs. For reproducible previews, consider pinning to a specific Chrome version or at least latest-stable with a comment.

7. Consider per-item timeout

A single broken HTML file with an infinite animation loop could hang the entire 30-minute job. The producer APIs might handle this, but worth confirming there's a render timeout at the producer level. If not, wrapping each item render in a timeout command in the shell loop would add resilience:

if ! timeout 120 npx tsx scripts/generate-catalog-previews.ts --only "$item" --skip-video; then

8. Temp directory cleanup on script crash

If the script crashes between prepareProjectDir and the finally block (e.g., during createFileServer), the temp dir leaks. Not a big deal in CI (ephemeral runners), but for local use the /tmp/hf-catalog-* dirs accumulate. The existing template preview script has the same pattern, so this is consistent — just noting it.

9. Registry-item.json files field access is unvalidated

const compFile = manifest.files?.find(
  (f: { type: string }) => f.type === "hyperframes:composition",
);
entryFile = compFile?.path ?? `${e.name}.html`;

If manifest.files exists but contains entries without a path property, compFile?.path is undefined and falls back correctly. But manifest.files could also be a non-array (malformed JSON). A quick Array.isArray(manifest.files) guard would be more defensive.


Summary

The two critical bugs (grep PCRE failure + missing git ref) mean the workflow currently does nothing on any PR. These need to be fixed and verified with a re-run before merging. The continue-on-error: true masked both failures, which is why CI shows green despite zero items rendered.

The script itself is well-structured, follows the existing template preview patterns, and the producer API usage looks correct.

jrusso1020 added a commit that referenced this pull request Apr 14, 2026
PR #259: Scope all GSAP JS selectors in flowchart.html under
[data-composition-id="flowchart"] prefix. Remove unnecessary setTimeout
retry in data-chart.html.

PR #261: Replace 'iframe' text with 'sub-composition' / 'data-composition-src'
in SKILL.md description + body, CLAUDE.md skills table + rules. Add
data-composition-id to missing-attributes note in snippet guidance.

PR #262: Fix CI workflow — replace grep -P lookbehind with sed (PCRE
variable-length alternation fails on Ubuntu), use fetch-depth: 0 + base
SHA for diff, remove continue-on-error: true, add per-item timeout, reduce
artifact retention to 7 days. Fix doc comment to remove stale 'examples' reference.

PR #263: Add try/catch around JSON.parse in codegen discovery (prevents
partial wipe on malformed manifest). Guard docs.json tabs array existence.

PR #269: Fix Three.js CDN in ascii-dashboard (was broken relative path).
Fix composition ID mismatches in 6 blocks (instagram-follow, tiktok-follow,
x-post, reddit-post, spotify-card, app-showcase) — IDs now match block names.

@vanceingalls vanceingalls left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One additional finding — the entryFile discovery/usage gap means the preview script likely navigates to a directory listing instead of the composition.


const fileServer = await createFileServer({ projectDir, port: 0 });
try {
const session = await createCaptureSession(fileServer.url, framesDir, {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

entryFile is discovered per item but never used by either generateThumbnail or generateVideo.

generateThumbnail passes the bare fileServer.url (e.g., http://localhost:PORT/) to createCaptureSession without appending the entry file path. For blocks, the temp directory contains data-chart.html (no index.html), so navigating to / will hit a directory listing or 404 instead of the composition.

For components, the temp dir has both demo.html and the snippet .html — auto-discovery could pick the wrong file.

Suggestion: pass the entry file URL to the capture session:

const entryUrl = `${fileServer.url}/${item.entryFile}`;
const session = await createCaptureSession(entryUrl, framesDir, { ... });

And for video, either rename the entry file to index.html in the temp dir or pass it to the render job config.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — this was a real bug in the original code. It's been fixed in a subsequent commit on the stack: prepareProjectDir now copies standalone blocks (those with __timelines) directly to index.html, and for items needing a wrapper it generates an index.html that references the entry file via data-composition-src. The entryFile field is used by both code paths now.

@miguel-heygen miguel-heygen left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CI issues are addressed in #270. Approving.

@jrusso1020
jrusso1020 force-pushed the 04-14-feat_registry_seed_components_grain-overlay_shimmer-sweep_grid-pixelate-wipe branch from 7c0c1d5 to f805fc8 Compare April 14, 2026 23:14
jrusso1020 added a commit that referenced this pull request Apr 14, 2026
PR #259: Scope all GSAP JS selectors in flowchart.html under
[data-composition-id="flowchart"] prefix. Remove unnecessary setTimeout
retry in data-chart.html.

PR #261: Replace 'iframe' text with 'sub-composition' / 'data-composition-src'
in SKILL.md description + body, CLAUDE.md skills table + rules. Add
data-composition-id to missing-attributes note in snippet guidance.

PR #262: Fix CI workflow — replace grep -P lookbehind with sed (PCRE
variable-length alternation fails on Ubuntu), use fetch-depth: 0 + base
SHA for diff, remove continue-on-error: true, add per-item timeout, reduce
artifact retention to 7 days. Fix doc comment to remove stale 'examples' reference.

PR #263: Add try/catch around JSON.parse in codegen discovery (prevents
partial wipe on malformed manifest). Guard docs.json tabs array existence.

PR #269: Fix Three.js CDN in ascii-dashboard (was broken relative path).
Fix composition ID mismatches in 6 blocks (instagram-follow, tiktok-follow,
x-post, reddit-post, spotify-card, app-showcase) — IDs now match block names.
@jrusso1020
jrusso1020 force-pushed the 04-14-ci_render_catalog_previews_on_pr branch from d98ecf3 to c5e2fec Compare April 14, 2026 23:14

jrusso1020 commented Apr 14, 2026

Copy link
Copy Markdown
Collaborator Author

Merge activity

  • Apr 14, 11:16 PM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Apr 14, 11:19 PM UTC: Graphite rebased this pull request as part of a merge.
  • Apr 14, 11:21 PM UTC: @jrusso1020 merged this pull request with Graphite.

@jrusso1020
jrusso1020 changed the base branch from 04-14-feat_registry_seed_components_grain-overlay_shimmer-sweep_grid-pixelate-wipe to graphite-base/262 April 14, 2026 23:17
@jrusso1020
jrusso1020 changed the base branch from graphite-base/262 to main April 14, 2026 23:18
Adds a CI workflow that auto-renders preview thumbnails for new/changed
registry blocks and components on pull requests.

- scripts/generate-catalog-previews.ts: Extends the template preview
  pipeline to handle all three registry item types. Examples use index.html,
  blocks use their standalone HTML, components use demo.html.
  Supports --only, --type, and --skip-video flags.

- .github/workflows/catalog-previews.yml: Triggers on PRs touching
  registry/blocks/ or registry/components/. Detects changed items,
  renders thumbnails, uploads as artifacts.
@jrusso1020
jrusso1020 force-pushed the 04-14-ci_render_catalog_previews_on_pr branch from c5e2fec to 5031369 Compare April 14, 2026 23:19
@jrusso1020
jrusso1020 merged commit ea6f949 into main Apr 14, 2026
15 checks passed
jrusso1020 added a commit that referenced this pull request Apr 14, 2026
PR #259: Scope all GSAP JS selectors in flowchart.html under
[data-composition-id="flowchart"] prefix. Remove unnecessary setTimeout
retry in data-chart.html.

PR #261: Replace 'iframe' text with 'sub-composition' / 'data-composition-src'
in SKILL.md description + body, CLAUDE.md skills table + rules. Add
data-composition-id to missing-attributes note in snippet guidance.

PR #262: Fix CI workflow — replace grep -P lookbehind with sed (PCRE
variable-length alternation fails on Ubuntu), use fetch-depth: 0 + base
SHA for diff, remove continue-on-error: true, add per-item timeout, reduce
artifact retention to 7 days. Fix doc comment to remove stale 'examples' reference.

PR #263: Add try/catch around JSON.parse in codegen discovery (prevents
partial wipe on malformed manifest). Guard docs.json tabs array existence.

PR #269: Fix Three.js CDN in ascii-dashboard (was broken relative path).
Fix composition ID mismatches in 6 blocks (instagram-follow, tiktok-follow,
x-post, reddit-post, spotify-card, app-showcase) — IDs now match block names.
Zollicoff pushed a commit to Zollicoff/hyperframes that referenced this pull request Jul 1, 2026
PR heygen-com#259: Scope all GSAP JS selectors in flowchart.html under
[data-composition-id="flowchart"] prefix. Remove unnecessary setTimeout
retry in data-chart.html.

PR heygen-com#261: Replace 'iframe' text with 'sub-composition' / 'data-composition-src'
in SKILL.md description + body, CLAUDE.md skills table + rules. Add
data-composition-id to missing-attributes note in snippet guidance.

PR heygen-com#262: Fix CI workflow — replace grep -P lookbehind with sed (PCRE
variable-length alternation fails on Ubuntu), use fetch-depth: 0 + base
SHA for diff, remove continue-on-error: true, add per-item timeout, reduce
artifact retention to 7 days. Fix doc comment to remove stale 'examples' reference.

PR heygen-com#263: Add try/catch around JSON.parse in codegen discovery (prevents
partial wipe on malformed manifest). Guard docs.json tabs array existence.

PR heygen-com#269: Fix Three.js CDN in ascii-dashboard (was broken relative path).
Fix composition ID mismatches in 6 blocks (instagram-follow, tiktok-follow,
x-post, reddit-post, spotify-card, app-showcase) — IDs now match block names.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants