Codifies the pattern for building high-energy launch/promo videos that
avoid the slideshow feel: one focus element per frame, fast smash cuts,
distinct visual worlds per beat, and pro easing curves per intent.
Includes beat sequencing architecture, easing vocabulary (snap, whip,
soft land, mechanical, bounce settle), contact sheet review workflow,
and anti-patterns to avoid.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add mintlify docs page for contributing blocks/components to the
registry catalog. Rename skill from contribute to contribute-catalog
for clearer intent.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Narrow description to disambiguate from hyperframes-registry (install)
and hyperframes (in-project authoring) skills
- Add "adjust" comments on dimensions/duration defaults so agents don't
blindly copy 1920x1080/10s for all composition shapes
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds a new docs page under Getting Started that links to the
heygen-com/hyperframes-launches repo — open-source HyperFrames
compositions behind HeyGen's product launch videos. Includes a brief
catalog of the 5 projects currently in there, framing on why these are
useful (multi-composition shape, real adapter mix, production-grade
timing), and the LFS-aware clone recipe.
Cross-linked from `docs/examples.mdx`'s Next Steps and from
`docs/community/adopters.mdx`.
Came from a Discord ask via blackNoir (forwarded by James) — users
landing on the docs want to see how the internal team builds their own
videos through HyperFrames; this surfaces that source in one click.
The agent skill loader rejects SKILL.md files whose frontmatter description
exceeds 1024 characters, so remotion-to-hyperframes was being skipped at
startup with a "exceeds maximum length of 1024 characters" warning.
Trimmed the description from 1240 to 896 characters by collapsing the
trigger-phrase examples and tightening prose, while preserving every
trigger / no-trigger guardrail. Moved the detailed list of trigger phrases
and the 4 negative cases into a new "## When to use" section in the body
so the guidance is not lost.
Fixes#688
New skill that guides users through the full workflow of contributing
caption styles, VFX blocks, transitions, and other components to the
HyperFrames registry.
Covers: scaffolding, proven patterns (seeded PRNG, paused timelines,
hard kills, unique ID prefixes), validation, rendering, and PR prep.
Includes copy-paste HTML templates for caption and Three.js components
with all the non-negotiable rules baked in.
Tested by an unbiased agent with zero prior HyperFrames knowledge —
built a working cap-typewriter component that passed lint and validate
on the first attempt. Feedback incorporated: per-character animation
guidance, monospace font size exceptions, positioning variants, and
PREFIX naming convention table.
GitHub strips autoplay/loop from <video> tags in markdown, so the MP4
required a click to play. WebP autoplays via <img> while preserving full
HD source quality (1280x720 vs the previous GIF's 400x225).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Clips whose compositionStart is ahead of the current timeline position
were starting immediately because sourceNode.start() always received
when=0. Use the AudioContext scheduling API to defer future clips:
sourceNode.start(ctx.currentTime + delay, mediaStart).
Closes#674
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace the two-clock architecture (GSAP rAF ticker + HTMLMediaElement
pipeline reconciled by a 50ms polling loop) with a single TransportClock.
GSAP is always paused and seeked to clock.now() on each rAF tick.
Drift between visual timeline and audio is structurally impossible.
Architecture:
TransportClock.now() ──rAF──▶ timeline.seek(t) + el.currentTime
▲
AudioContext.currentTime (~21µs) ← WebAudio active
OR
audio.currentTime (~33ms) ← HTMLMediaElement fallback
OR
performance.now() (~1ms) ← no audio
Key changes:
- TransportClock class with monotonic + audio-master clock sources
- WebAudioTransport: routes audio through AudioBufferSourceNode for
sample-accurate scheduling, falls back gracefully to HTMLMediaElement
- rAF tick loop replaces 50ms setInterval poll; GSAP always paused
- Strict sync (40ms threshold, consecutive-sample gated) + forceSync
on play/pause/seek transitions for sub-frame media accuracy
- Buffer-stall: visuals freeze when audio is buffering instead of
running ahead
- Frame quantization preserved in seek/renderSeek (parity contract)
Browser-verified: 0.0ms drift after 40 pause/play cycles (was 400ms+).
Also fixes: CDN script HTML error responses in validate (pre-existing).
54 tests across clock, clock-drift, webAudioTransport, and media.
Closes#668
The autobuild-2026-04-23-13-16 release was rotated out of BtbN's
recent-dailies window, returning 404 on the Windows test/render jobs.
Switch to the 2026-04-30 month-end snapshot, which BtbN keeps long-term
(visible in the persistent monthly-snapshot history).
## What
Adds `landscape-4k` (3840×2160) and `portrait-4k` (2160×3840) presets to `CanvasResolution` and `CANVAS_DIMENSIONS` in `@hyperframes/core`. Foundation for end-to-end 4K rendering support.
## Why
There is no codified way today to mark a composition as 4K. The string union `CanvasResolution = "landscape" | "portrait"` is the only enum used by templates, generators, and stage-zoom math; without 4K members, scaffolds and helpers always emit 1080p dimensions even when the underlying engine + encoder pipeline can already handle larger viewports (Chrome `setViewport`, ffmpeg `libx264`/`libvpx-vp9`/`prores_ks` all scale fine).
This is PR 1 of a 3-PR stack making 4K a first-class option:
1. **PR #660 (this)** — core types/constants + parser detection.
2. **PR #661** — `hyperframes init --resolution 4k` flag to scaffold 4K projects.
3. **PR #662** — byte-budget the frame data-URI cache so 4K renders don't OOM.
## How
- `CanvasResolution` extended additively (no breaking change).
- `CANVAS_DIMENSIONS` gains `landscape-4k` / `portrait-4k` entries.
- `parseResolutionFromHtml` accepts `data-resolution="landscape-4k|portrait-4k"` and infers 4K from `data-composition-width`/`data-composition-height` (long side ≥ 2560 → UHD variant).
- `parseResolutionFromCss` reuses the same dimension-aware classifier so inline `#stage { width/height }` styles are detected too.
- Helper extracted: `resolveResolutionFromDimensions(w, h)`.
- `cli/info.ts` cleanup: replaces a nested `parsed.resolution === "portrait" ? 1080 : 1920` ternary with a `CANVAS_DIMENSIONS[parsed.resolution]` lookup so it stays correct for 4K.
Stage-CSS generators (`templates/base.ts`, `generators/hyperframes.ts`) already index `CANVAS_DIMENSIONS[resolution]`, so they pick up the new presets automatically.
## Test plan
- [x] Unit tests added/updated — 4 new parser tests, 1 expanded constants test
- [x] Manual testing performed — `bun run --cwd packages/core test` (679 pass), `bun run --cwd packages/cli test` (277 pass)
- [ ] Documentation updated (deferred to PR #661 where the user-facing flag lands)
The first dynamic `await import("./render.js")` cold-load takes >5 s on
Windows runners — long enough to blow vitest's default 5 s timeout in
whichever test ran it first. Subsequent imports are <10 ms because the
module is now cached, so only test #1 ever times out.
The downstream failure is more subtle: when test #1 times out, vitest
moves on, but its leaked async function eventually hits the synchronous
`producer.createRenderJob(...)` line and pushes a stale config to
`producerState.createdJobs`. That push lands AFTER test #2's `beforeEach`
clears the array, so test #2's `createdJobs[0]` is the leaked test #1
entry instead of its own. That's why test #2 saw `browserGpuMode: 'software'`
when it expected `'auto'`.
Hoist the import into `beforeAll` (matching the pattern the existing
`parseVariablesArg` and `validateVariablesAgainstProject` describe blocks
in this file already use). Cold-load happens once outside any test's
timeout window, every test stays fast, no leaked promise can corrupt
state.
Failing run: https://github.com/heygen-com/hyperframes/actions/runs/25470257972/job/74732502915
Started failing on main with the merge of #642 (auto-detect-browser-gpu),
which added the "forwards browserGpuMode='auto'" test as test #2.