Skip to content

feat(registry): add Code Animations catalog section (9 blocks, incl. GPU)#1472

Open
miguel-heygen wants to merge 7 commits into
mainfrom
feat/code-animation-catalog
Open

feat(registry): add Code Animations catalog section (9 blocks, incl. GPU)#1472
miguel-heygen wants to merge 7 commits into
mainfrom
feat/code-animation-catalog

Conversation

@miguel-heygen

@miguel-heygen miguel-heygen commented Jun 15, 2026

Copy link
Copy Markdown
Collaborator

Code Animations catalog section

Adds a new Code Animations catalog section (now the first group in the catalog) with 9 self-contained, deterministic blocks for building beautiful code-snippet videos — including three GPU-driven effects that go beyond 2D code animation.

GPU / WebGL blocks (Three.js)

  • code-3d-extrude — syntax-highlighted code on a lit, beveled 3D slab that rotates through space and settles to a readable rest
  • code-shader-dissolve — the code "compiles" out of seeded GPU noise via a fragment shader (chromatic dissolve front + edge glow), then holds crisp
  • code-particle-assemble — thousands of GPU points scatter and fly to the exact glyph pixels, resolving into readable syntax-highlighted code

2D blocks (paused GSAP timeline over baked Shiki tokens)

  • code-morph — one snippet morphs into another; tokens glide/fade between states
  • code-snippet-flight — discrete snippets fly in and assemble into a stacked program
  • code-typing — per-character typing reveal with a gliding caret
  • code-diff — line-level add/remove coloring
  • code-highlight — animated highlight sweep with context dim
  • code-scroll — scroll-to-line with spotlight

How it works

Every block is a single self-contained HTML composition. Shiki syntax tokens are baked at author time; the animation is a paused GSAP timeline the engine seeks per frame. The GPU blocks bridge the baked tokens into WebGL via an offscreen CanvasTexture (slab face / shader sampler / particle target-sampling) and render via tl.eventCallback("onUpdate") — never requestAnimationFrame — with a seeded mulberry32, so every block is frame-exact and reproducible. (GSAP and Three.js load from jsdelivr at pinned versions — gsap@3.14.2, three@0.147.0 — matching the existing catalog convention; the blocks themselves issue no render-time data fetches, so output stays deterministic.)

Catalog wiring

  • New "Code Animations" group, first in the catalog nav
  • New code-animation Studio block category
  • 9 catalog pages + registry.json entries
  • Preview videos + posters uploaded to the docs CDN (static.heygen.ai)

Validation

  • hyperframes lint — 0 errors on all 9 blocks
  • hyperframes validate — no console errors on all 9 (incl. WebGL/shader compile)
  • Determinism — each block renders byte-identical across two independent renders (incl. the seeded particle scatter)
  • oxfmt / typecheck / commitlint — clean

Review follow-ups

rev 40be261

  • Single GPU render — dropped a redundant per-frame renderer.render() in the three WebGL blocks (the effect closure and the boot loop each issued one, doubling GPU work for identical pixels). Closures now only mutate state; the boot loop does the single render. Byte-identical, still deterministic.

rev d8b9af1

  • Dead engine copies removed — each block now inlines only the effect it dispatches; the generator strips the other effect bodies and their dispatch branches at build time. No dead copies are left to drift (resolves the fxExtrude / flight() divergence at the root) and ~1960 lines come out across the 9 blocks. Render output byte-identical to the prior revision — previews unchanged.
  • WebGL teardown — GPU blocks now dispose the renderer, geometries, materials and textures on beforeunload. One-shot renders already exit per job; this frees resources in long-lived Studio/player sessions. (A per-composition unmount hook for block-swap-without-reload is still a runtime concern.)
  • Vendor scripts left as-is (rev b3b3f60) — kept GSAP/Three on jsdelivr without SRI to match the catalog's 88+ existing blocks; no-SRI is the deliberate convention, and pinning it on only these 9 would create an inconsistency and a divergent failure mode.

Adds a "Code Animations" catalog section with six self-contained,
deterministic code-animation blocks for building beautiful code-snippet
videos: code-morph, code-snippet-flight, code-typing, code-diff,
code-highlight, code-scroll.

Each block reuses Shiki Magic Move's tokenizer + diff (baked at author
time) and drives the motion as a paused GSAP timeline the engine seeks
per frame — no CSS transitions, no render-time network. They group
separately from the static code-snippet themes via a dedicated
code-animation tag.

- registry: 6 blocks (html + registry-item.json) + registry.json entries
- catalog: 6 docs pages + a Code Animations nav group
- studio: new code-animation block category (resolveBlockCategory keys on
  the code-animation tag; existing code-snippet themes are untouched)
- generator: groupForItem maps code-animation -> Code Animations
Three WebGL "Code Animations" blocks driven by the GPU — effects Remotion's
2D code plugins (Shiki Magic Move / CodeHike) can't easily match:

- code-3d-extrude: syntax-highlighted code on a lit, beveled 3D slab
  (Three.js) that rotates through space and settles to a readable rest
- code-shader-dissolve: the code "compiles" out of seeded GPU noise via a
  fragment shader (chromatic dissolve front + edge glow), then holds crisp
- code-particle-assemble: thousands of GPU points scatter and fly to the
  exact glyph pixels, resolving into readable syntax-highlighted code

Each is a self-contained single-HTML block (Three.js + GSAP from CDN, Shiki
tokens baked at author time) and fully deterministic: rendered via
tl.eventCallback("onUpdate") — never requestAnimationFrame — with a seeded
mulberry32 and no render-time network. Verified byte-identical across renders.

Also polishes the existing section:
- Code Animations is now the first catalog group
- code-snippet-flight chips are uniform-width, left-aligned, evenly stacked
- code-typing reveals per-character with a gliding caret (smooth)
- code-3d-extrude: render the code face unlit (screen-style) instead of a
  PBR material with an emissiveMap of the same texture, which double-counted
  the color and washed it pale under the lights. 3D depth now comes from the
  lit beveled edges + perspective; the face shows the exact Shiki colors.
- code-particle-assemble: switch points from additive to normal alpha
  blending so overlapping particles no longer accumulate to white — the
  assembled code shows its true syntax colors.

Both remain deterministic (verified byte-identical across renders).
@mintlify

mintlify Bot commented Jun 15, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
hyperframes 🟢 Ready View Preview Jun 15, 2026, 10:23 PM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@james-russo-rames-d-jusso james-russo-rames-d-jusso left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Verified at HEAD 9d3c9563. Reviewing under the canonical engineering rubric lane — HF-domain coherence (animation quality, GSAP/HF idioms, block-author UX, Catalog conventions) is deferred to @via separately.


Headline: determinism contract holds across all 9 blocks

Grepped every block at HEAD for Date.now, Math.random, performance.now, requestAnimationFrame, setTimeout, setInterval, fetch(, XMLHttpRequest, new Worker, import("http…, inline <script src="http… other than the pinned vendor deps. The only Date.now / Math.random references across the entire change are in comments that explicitly disclaim usage (code-3d-extrude.html:342,351, code-shader-dissolve.html:288,297, code-particle-assemble.html:198,207). All randomness flows through the inlined mulberry32(seed) PRNG seeded from window.__BLOCK.seed. Render is driven exclusively from tl.eventCallback("onUpdate", …) on a paused GSAP timeline — no requestAnimationFrame, no wall-clock timers, no render-time fetch. The "frame-exact and reproducible" load-bearing claim in the PR body checks out at the file level.


Concerns

  • registry/blocks/code-3d-extrude/code-3d-extrude.html, code-shader-dissolve/code-shader-dissolve.html, code-particle-assemble/code-particle-assemble.htmlWebGLRenderer double-render per onUpdate frame. Each block's inner renderFn already calls renderer.render(scene, camera) (3d-extrude:536, shader-dissolve:493/576/692, particle-assemble:592). The outer render() wrapper installed as tl.eventCallback("onUpdate", render) then calls renderer.render(scene, camera) AGAIN at 3d-extrude:780, shader-dissolve:736, particle-assemble:636. Result: every onUpdate frame submits the full scene to the GPU twice. Output is identical (deterministic) but it's wasted GPU work at 1920×1080 across the render farm. Cheapest fix: drop the trailing renderer.render(scene, camera) from the outer wrapper since the per-effect renderFn already paints. Worth taking before this lands given the GPU blocks will run a lot.

  • All 3 GPU blocks ship duplicated engine code that has already drifted within this PR. Each of code-3d-extrude.html, code-shader-dissolve.html, code-particle-assemble.html includes all three of fxExtrude / fxDissolve / fxParticles + the dispatch table, even though only one effect ever runs per block (selected by window.__BLOCK.effect). Diffing the dead-copy implementations between blocks: fxExtrude in code-3d-extrude.html:437-541 is the good unlit-screen version (MeshBasicMaterial, vivid Shiki colors per the rationale comment), while fxExtrude in code-shader-dissolve.html:383-495 is an older lit version (MeshStandardMaterial + emissive). Similarly fxParticles in code-3d-extrude.html uses NormalBlending while in code-shader-dissolve.html it uses AdditiveBlending. Runtime impact: zero (dispatch never reaches the stale copies). Maintenance impact: real — a future contributor reading code-shader-dissolve.html's fxExtrude to understand the 3D-extrude block would be reading the wrong implementation. Same pattern in the 2D family: flight() in code-snippet-flight.html+code-typing.html is a substantial rewrite (equal-width chips, 2-pass layout, straight-left fly-in) while flight() in code-morph.html+code-diff.html+code-highlight.html+code-scroll.html is the older two-column layout. typing() has the same split. If the catalog intends to keep one-file-per-block self-containment, suggest either (a) a // IGNORE — dead dispatch path banner on the duplicated dead effects per file, or (b) a build step that templates blocks from a single source-of-truth engine module. Today's shape is a foot-loaded maintenance trap.

  • No dispose() path in any of the 3 GPU blocks. Zero matches for dispose|onDestroy|teardown across the change. WebGLRenderer, BufferGeometry, ShaderMaterial, CanvasTexture, ExtrudeGeometry, PlaneGeometry, lights — none are released. Whether this matters depends on whether the HF runtime tears down the entire iframe / page on block unmount (cleanly killing the WebGL context) vs. reuses the page. That's HF-runtime-interop knowledge — flagging for @via to confirm. If pages are reused, this leaks GPU resources block-by-block and will eventually exhaust the ~16 simultaneous WebGL context budget on Chromium.

Nits

  • CDN <script> tags load GSAP and Three.js from cdn.jsdelivr.net with no SRI integrity= hash (every block, line 7-8). This matches the established catalog convention (88+ existing blocks do the same — cross-warp-morph, glitch, flowchart, transitions-cover, gravitational-lens, etc. — searched the repo). Not a regression but worth a catalog-wide hardening pass eventually. Out of scope here.
  • The fillGutter helper is identically duplicated in 6 of the 9 blocks (code-diff.html:671, code-highlight.html:614, code-morph.html:1060, code-scroll.html:1424, code-snippet-flight.html:516, code-typing.html:606). Same self-containment-vs-DRY tradeoff as the GPU engine.
  • scripts/generate-catalog-pages.ts hoists "Code Animations" to GROUP_ORDER: 0, demoting the previously-first Captions section to 1. Intentional per the PR body and PM call; flagging for visibility in case anyone tracks group-order changes.

Questions

  • For @via — the PR body claims "every block is a single self-contained HTML composition" with "no render-time network." The vendor <script src="https://cdn.jsdelivr.net/..."> tags at line 7-8 of every block load over the network at composition load. I'm assuming the HF runtime intercepts these (offline cache / mirror / preflight bundling) so the "no render-time network" claim is true for the block's own JS code, not the dependency script tags. Worth confirming with one sentence in the PR body so a future reader doesn't ding the determinism claim on a literal reading.

What I didn't verify

  • HF-domain coherence (animation quality, GSAP timeline structure, render-output correctness, Shiki token shape consistency, Catalog conventions, block-author UX, render-farm integration) — deferred to @via per our lane split.
  • The 6 2D blocks beyond a structural spot-check + cross-block consistency grep — I deep-read code-shader-dissolve.html end-to-end and code-morph.html's structural skeleton; the others I verified via grep + the cross-block effect-function drift diffs above.
  • Whether the HF runtime's block-unmount path disposes Three.js resources (raised under the dispose concern above).
  • Whether static.heygen.ai/hyperframes-oss/docs/images/catalog/blocks/<name>.{mp4,png} URLs in the 9 registry-item.json preview fields are live — the "Render catalog previews" + "Preview parity" CI checks passed so I trust those.

Canonical-rubric pass by Rames D Jusso — HF-domain coherence deferred to @via

Regenerate all 9 Code Animation blocks from the canonical engine so the
inlined effect code is consistent across blocks. Two dead copies had drifted:
the GPU blocks shipped a stale fxExtrude using MeshStandardMaterial (vs the
live MeshBasicMaterial), and morph/diff/highlight/scroll carried the
pre-symmetry flight(). Live effects were already current — this aligns the
dead copies so they can't mislead a maintainer.

Also remove a redundant per-frame renderer.render() in the three WebGL
blocks: the effect closure and the boot loop's render() each issued one,
doubling GPU work at 1920x1080 for identical pixels. Closures now only mutate
state; the boot loop does the single render. Byte-identical across two
renders (determinism preserved).
…dor scripts

Each block now inlines only the effect it dispatches — the generator strips the
other effect bodies and their dispatch branches at build time. Removes the dead,
drift-prone copies entirely (every block stays a single self-contained file);
render output is byte-identical to the prior revision.

GPU blocks register a beforeunload teardown that disposes the WebGLRenderer,
geometries, materials and textures — one-shot renders already exit per job, but
this frees GPU resources in long-lived Studio/player sessions.

Vendor scripts (GSAP, Three.js) now carry SRI integrity + crossorigin, pinned to
the sha384 of the jsdelivr-served files.
The catalog's 88+ existing blocks load GSAP/Three from jsdelivr without
subresource integrity; adding it to only these 9 created an inconsistency and a
divergent failure mode (a hash mismatch in any render environment would break
only these blocks). Reverting to match convention. Render output unchanged.
The regenerated blocks were raw generator output, which is not oxfmt-canonical and
failed CI's `oxfmt --check .` gate. Format them to match. Whitespace-only — render
output byte-identical (verified on a GLSL block and a DOM block).
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.

2 participants