CI failures were two root causes (preview-regression was a cascade — its gate
mirrors preview-parity, which was skipped because the Preflight lint+format job
failed):
- Preflight (lint + format): the migrated registry comps (flowchart,
flowchart-vertical, liquid-glass-notification, vignette demo) were committed
unformatted — the lefthook format step only ran oxfmt on staged TS, not HTML,
so `oxfmt --check .` failed in CI. Ran oxfmt on all four. The vignette title's
per-glyph spans use oxfmt's `</span>`-split form, which keeps the glyphs
adjacent (no inter-element whitespace), so rendering is unchanged.
- Skills: manifest in sync: the pre-commit hook's manifest generator and CI's
canonical `gen-skills-manifest.ts` produced different content hashes for the
same skill; regenerated with the canonical generator so the committed manifest
matches what CI computes.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Animating layout properties (left/right/top/bottom/margin*) or using
roundProps snaps motion to integer device pixels. Under the seek-by-frame
capture engine this is invisible at high per-frame deltas (fast tweens) but
visibly stutters at low deltas (slow tweens / ease-out tails): sub-pixel
movement rounds to the same pixel for several frames, then jumps a whole
pixel. Transforms (x/y/scale) interpolate sub-pixel and stay smooth.
New rule gsap_non_transform_motion (error):
- Sources timeline tweens from the acorn parser's full animation list, so
label- and relative-positioned tweens (tl.to(..., "label") / "+=1") are
covered and real AST keys avoid phantom-prop / nested-brace misreads.
- Exempts html-in-canvas elements (a <canvas layoutsubtree> ancestor): they
are rasterized from sub-pixel getComputedStyle and do not integer-snap.
Per-element resolution, so a grouped glass+text tween still flags the
plain-DOM half. roundProps is never exempt (it rounds before the style).
- Uses Object.hasOwn for the layout-prop lookup, skips set(), and merges
standalone gsap.* calls.
Migrated 9 registry compositions off layout-prop animation onto transforms,
each render-verified visually identical:
- liquid-glass-{notification,widgets,media-controls,context-menu}: plain-DOM
text overlays -> transforms; glass panels stay on left/top (canvas-exempt).
- vignelli: curtain wipes left:% -> xPercent.
- lt-mask-reveal: sweep left:% -> x px.
- flowchart, flowchart-vertical, decision-tree: cursor paths left/top -> x/y.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(core): register sub-composition timelines after async build + lint rule
When a composition builds its GSAP timeline inside document.fonts.ready (or any
async callback), registering window.__timelines[id] BEFORE the build leaves an
EMPTY timeline registered. The runtime's sub-composition readiness gate treats
"key present" as "ready" and nests the child once — an empty timeline gets
nested empty and is never re-nested, so the frame renders blank when used as a
sub-composition.
- registry/blocks/code-{diff,highlight,morph,scroll,typing}: register the
timeline AFTER the fonts.ready build completes, then call
window.__hfForceTimelineRebind() to re-nest now that it is populated.
- core lint: add rule gsap_timeline_registered_before_async_build to flag the
early-registration anti-pattern, with tests.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(studio): import commitGsapPositionFromDrag from its actual module
The function was split out into gsapDragPositionCommit.ts in #1605, but the
test kept importing it from ./gsapDragCommit, which no longer exports it —
yielding 'is not a function' at runtime. Import from the correct module.
Inherited main breakage (same fix as #1631/#1635); fixes the Test CI check on
this branch independently of merge order.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds a Code Animations catalog section — 9 self-contained, installable blocks:
morph, snippet-flight, typing, diff, highlight, scroll (DOM/GSAP) and 3d-extrude,
shader-dissolve, particle-assemble (WebGL). Each block ships only its own effect and
renders deterministically (paused GSAP timeline seeked per frame, seeded RNG, no
render-time data fetch). Wires the catalog nav, registry.json, a new code-animation
Studio category, and preview assets.
* feat(registry): add Apple Terminal theme code snippet blocks
Adds 12 Apple Terminal built-in profile visualizer blocks to the
Code Snippets catalog section, following the same pattern as the
VS Code theme blocks (commit 5245e190).
Themes: Basic, Clear Dark, Clear Light, Grass, Homebrew, Man Page,
Novel, Ocean, Pro, Red Sands, Silver Aerogel, Solid Colors.
Each block is a self-contained 1920×1080 composition showing a
macOS Terminal.app window in the matching profile colors, with
per-character GSAP typing animation and window.__timelines contract.
Install individually:
npx hyperframes add code-snippet-apple-terminal-basic
Install all Apple Terminal themes:
npx hyperframes add apple-terminal
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(registry): remove placeholder preview URLs for unrendered Apple Terminal themes
The 8 themes without rendered videos (clear-dark, homebrew, novel,
ocean, pro, red-sands, silver-aerogel, solid-colors) had preview.video
URLs pointing to non-existent S3 objects, returning 403. Removed the
preview field from their registry-item.json and the video embed from
their MDX pages until renders are available.
The 4 themes with uploaded videos (basic, clear-light, grass, man-page)
retain their preview URLs and are live on CDN.
* fix(registry): add apple-terminal tag so npx hyperframes add apple-terminal works
* feat(registry): render + upload all 12 Apple Terminal preview videos to CDN
Rendered the 8 missing themes (clear-dark, homebrew, novel, ocean, pro,
red-sands, silver-aerogel, solid-colors) using npx hyperframes@latest
render and uploaded to the hyperframes CDN. All 12 themes now have
live preview.video URLs and video embeds in their MDX pages.
All 12 CDN URLs return 200.
* style: format Apple Terminal HTML and JSON files with oxfmt
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(registry): add VS Code theme visualizer example
Full VS Code workbench recreation with per-character typing animation
across 12 built-in themes. Includes activity bar, sidebar, tabs,
editor with line-by-line cursor tracking, terminal panel, and status
bar — all driven by official VS Code theme JSON files.
Themes: Dark Modern, Dark 2026, Dark+, Light Modern, Light 2026,
Light+, Visual Studio Dark, Visual Studio Light, High Contrast,
High Contrast Light, Solarized Light, Monokai.
Includes build scripts to regenerate compositions from theme JSON.
* feat(registry): add 12 code snippet blocks for hyperframes add code
Individual blocks for each VS Code built-in theme, all tagged "code"
so `npx hyperframes add code` installs the full set.
Each block is a self-contained VS Code workbench with per-character
typing animation, activity bar, sidebar, tabs, terminal, and status
bar driven by official theme JSON data.
* docs: add mdx pages for code snippet blocks and example
- 12 block doc pages under catalog/blocks/code-snippet-*
- "Code Snippets" nav group in docs.json
- vscode-theme-visualizer entry in examples.mdx
* docs: revert examples.mdx — code snippets belong in catalog only
* docs: drop redundant 'Code Snippet' prefix from sidebar titles
* docs: add video previews to code snippet catalog pages
* style: format HTML, CSS, and MJS files for CI
* fix: address review feedback — build pipeline, LICENSE, dead code, nav order
1. Build script now regenerates both example compositions AND published
blocks in registry/blocks/code-snippet-*/, keeping them in sync.
2. Add MIT LICENSE for vendored VS Code theme JSONs (microsoft/vscode).
3. Remove dead `chars` variable from runtime, build script, all blocks,
and all example compositions.
4. Alphabetize Code Snippets nav group in docs.json to match catalog
convention.
* style: format all build-generated files (render-entries, CSS, index)
Adds WebGPU support to the Chrome launch args alongside the existing
CanvasDrawElement flag. Use PRODUCER_HEADLESS_SHELL_PATH to point to
Brave for full WebGPU + drawElementImage support.
Also fixes flicker in liquid glass blocks by removing onpaint/requestPaint
callbacks that conflicted with GSAP's deterministic onUpdate rendering.
Adds macos-tahoe-liquid-glass block (WIP).
Replaces the phone screen content in vfx-iphone-device with an iOS 26
home screen: glass app icons (Weather, Stocks, ChatGPT, Slack, X, etc.),
status bar with battery/signal, search pill, dock with badges. All on a
real GLTF iPhone model with camera choreography.
Complete rewrite of all 4 liquid glass registry blocks using
jeantimex/liquid-glass-html-in-canvas for real WebGPU glass rendering.
Architecture: Three.js aurora shader (z:0) + empty glass panels in
layoutsubtree canvas (z:1) + CSS text overlay (z:2). Text is crisp
and never passes through the glass shader.
- Renders via Brave with WebGPU + drawElementImage flags
- Continuous motion throughout — panels sweep across the screen
- liquid-glass.iife.js bundle (25KB) replaces liquid-dom (88KB)
Adds a Blocks tab to the Studio left sidebar with the full 78-item registry
catalog (58 blocks + 20 components). Users can browse by category, search by
title/description, preview CDN-hosted poster thumbnails with video-on-hover,
and install items on-demand with one click or drag-to-timeline.
Core changes:
- BlockCategory type + resolveBlockCategory() for 7 categories (Captions, VFX,
Transitions, Effects, Social, Data, Scenes)
- Registry API routes: GET /api/registry/blocks (catalog) + POST install
- StudioApiAdapter extended with listRegistryCatalog + installRegistryBlock
- Vite adapter reads from disk; CLI adapter fetches from GitHub (24h cache)
- BlockParam interface + params on 6 blocks for future parameter controls
Studio UI:
- 4th sidebar tab "Blocks" with responsive grid, category pills, search bar
- BlockCard: CDN poster thumbnail, video autoplay on hover, duration + WebGL badges
- On-demand install: blocks append as sub-compositions on timeline; components
overlay at start=0 spanning full duration with transparent background patching
- TIMELINE_BLOCK_MIME drag-and-drop to timeline
- BlockParamsPanel (Phase 3 scaffold) auto-opens for parameterized blocks
Registry manifests:
- All 58 blocks backfilled with preview: { video, poster } CDN URLs
- All 20 components normalized to object format + poster URLs added
- 6 blocks annotated with params (Liquid Glass/Background, Portal, Chart,
Logo Outro, Magnetic)
- flowchart-vertical preview generated and uploaded to CDN
- Replace from:"random" with from:"center" stagger in us-map,
world-map, spain-map — random stagger is non-deterministic across
parallel render workers, causing visual jumps at chunk boundaries.
- Exempt type="importmap" and type="module" inline scripts from the
invalid_inline_script_syntax lint rule. The rule used new Function()
to parse, which rejects import statements and JSON import maps.
Closes#929.
- Cache-bust all map MDX preview video URLs after re-rendering with
the deterministic stagger fix.
New block: spain-map — animated Spain choropleth by autonomous
community using D3 conic conformal projection with GDP per capita
data and red-to-amber color scale.
Also switches all map MDX preview URLs from S3 to local paths
so they render in mintlify dev without needing S3 upload first.
New blocks: world-map (D3 Natural Earth choropleth), us-map-bubble
(proportional city markers), us-map-hex (hexagonal tile grid),
us-map-flow (animated connection arcs between cities).
All blocks share the same dark theme and are composable — layer
bubble or flow on top of the choropleth via track indexes.
Adds "Maps" section to the catalog docs with MDX pages for all 5
map blocks (including the us-map from the previous commit).
Animated US population density choropleth using D3 geoAlbersUsa
projection with TopoJSON. Includes staggered state reveals, label
fade-ins, gradient legend, and highlight pulses on densest states.
* fix(player): replay from start when play is pressed after video ends
When a non-looping composition reaches its end, pressing play again
had no effect because the playhead stayed at the final frame. Now
play() detects the ended state and seeks to 0 before resuming.
* chore: fix pre-existing format issues in registry files
* docs: group VFX blocks under HTML-in-Canvas, captions under Captions in sidebar
* docs: add HTML-in-Canvas guide, Chrome flag disclaimer, remove captions
- Add docs/guides/html-in-canvas.mdx — comprehensive guide covering the
API, feature detection, re-capture patterns, and catalog blocks
- Add Chrome flag Warning banner to every HTML-in-Canvas block page
- Remove captions blocks from registry (will ship separately)
- Add html-in-canvas guide to docs navigation (top of Guides section)
* feat: update liquid glass, portal, shatter with HyperFrames branding
Replace generic placeholder content with HyperFrames-themed text:
- Liquid Glass: 'Ship videos 10x faster' with stats and gradient text
- Portal: 'Write HTML / Render Video' with HyperFrames nav
- Shatter: 'HTML is Video' with render speed/file size metrics
Re-rendered and uploaded preview videos to S3.
hyperframes add now auto-detects whether the argument is a single
block name or a tag. No --tag flag needed:
hyperframes add html-in-canvas # installs all 7 html-in-canvas blocks
hyperframes add captions # installs all 5 caption blocks
hyperframes add vfx-shatter # installs one block
When the name doesn't match a registry item, the CLI falls back to
tag-based resolution and bulk-installs all matching blocks.
Also fixes tag assignments:
- VFX blocks tagged "html-in-canvas" (not "vfx")
- Caption blocks tagged "captions" only (no html-in-canvas)
All 12 blocks now share the 'html-in-canvas' tag, enabling:
hyperframes add --tag html-in-canvas
This installs all VFX + caption blocks in one command.