mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-01 19:42:03 +00:00
Comprehensive audit of every documentation page against the actual source code, fixing incorrect APIs, wrong CLI flags, nonexistent templates, and missing public exports. Also documents the new agent-friendly CLI design. Key fixes: - Quickstart: `npx create-hyperframe` → `npx hyperframes init`, Node 20→22 - Templates: replaced nonexistent blank/title-card/video-edit with actual templates (blank, warm-grain, play-mode, swiss-grid, vignelli) - CLI: removed nonexistent short flags (-o/-f/-q/-w), added missing commands (browser, docs, telemetry, skills), documented agent-friendly non-interactive default and --human-friendly flag - Producer: replaced nonexistent `render()` API with actual `createRenderJob()`/`executeRenderJob()`, added server API docs - Engine: replaced nonexistent `createEngine()` with actual session-based API, added HfProtocol, encoding, streaming, parallel rendering docs - Core: fixed wrong type names (Composition/Clip→TimelineElement), wrong function names (parseHyperframeHtml→parseHtml), documented all 4 entry points (main, /lint, /compiler, /runtime) - Studio: added all missing exports (NLELayout, SourceEditor, PropertyPanel, FileTree, StudioApp, hooks, Tailwind preset) - All pages: --output not -o, Node 22+ not 20+ Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
102 lines
4.6 KiB
Plaintext
102 lines
4.6 KiB
Plaintext
---
|
|
title: Deterministic Rendering
|
|
description: "Same input, identical output. Every time."
|
|
---
|
|
|
|
Hyperframes is built around a core guarantee: **the same [composition](/concepts/compositions) always produces the same video**. This is what makes automated pipelines, CI testing, and AI-driven workflows reliable.
|
|
|
|
## How It Works
|
|
|
|
The rendering pipeline is frame-by-frame and seek-driven. No realtime playback is involved -- every frame is independently seeked and captured.
|
|
|
|
<Steps>
|
|
<Step title="Frame clock">
|
|
The [engine](/packages/engine) computes the time for each frame using integer math: `time = floor(frame) / fps`. There is no wall-clock dependency -- rendering is entirely decoupled from real time.
|
|
</Step>
|
|
<Step title="Seek">
|
|
The [frame adapter](/concepts/frame-adapters) receives a `seekFrame(frame)` call and deterministically positions all animations, DOM state, and canvas content to the exact frame. The adapter's `renderSeek` pauses all [GSAP](/guides/gsap-animation) timelines and seeks them to the computed time.
|
|
</Step>
|
|
<Step title="Capture">
|
|
Chrome's `HeadlessExperimental.beginFrame` API captures the pixel buffer for the current frame. This is a single, atomic operation -- no partial paints or race conditions.
|
|
</Step>
|
|
<Step title="Encode">
|
|
FFmpeg encodes the captured frames into the final MP4 video. Audio tracks from `<audio>` and `<video>` elements are mixed in during this stage.
|
|
</Step>
|
|
</Steps>
|
|
|
|
```mermaid
|
|
graph LR
|
|
A["Frame Clock<br/>t = frame / fps"] --> B["Seek<br/>adapter.seekFrame(frame)"]
|
|
B --> C["Capture<br/>beginFrame API"]
|
|
C --> D["Encode<br/>FFmpeg"]
|
|
D --> E["MP4"]
|
|
style A fill:#00C4FF,color:#fff
|
|
style B fill:#00C4FF,color:#fff
|
|
style C fill:#00C4FF,color:#fff
|
|
style D fill:#00C4FF,color:#fff
|
|
style E fill:#00A8E1,color:#fff
|
|
```
|
|
|
|
## What Makes It Deterministic
|
|
|
|
- **No wall-clock dependencies** -- rendering does not use `Date.now()`, `requestAnimationFrame`, or system timers
|
|
- **No unseeded randomness** -- `Math.random()` without a seed breaks determinism
|
|
- **No render-time network fetches** -- all assets must be loaded before rendering starts
|
|
- **Fixed output parameters** -- `fps`, `width`, and `height` are locked before the first frame
|
|
- **Finite duration** -- every [composition](/concepts/compositions) has a known, finite length
|
|
|
|
These same rules apply to every [frame adapter](/concepts/frame-adapters). If you are building a custom adapter, you must follow the [determinism contract](/concepts/frame-adapters#determinism-contract).
|
|
|
|
## Docker Mode
|
|
|
|
For maximum reproducibility, render in Docker:
|
|
|
|
```bash
|
|
npx hyperframes render --docker --output output.mp4
|
|
```
|
|
|
|
Docker mode uses an exact Chrome version and font set, ensuring:
|
|
- Same Chromium rendering engine across all platforms
|
|
- Same system fonts (no platform-specific font substitution)
|
|
- Same FFmpeg encoder version
|
|
|
|
See the [Rendering guide](/guides/rendering) for all rendering options.
|
|
|
|
## Preview vs. Render Parity
|
|
|
|
The browser preview and the rendered MP4 should match. Hyperframes achieves this through:
|
|
|
|
- **One runtime** -- the same `hyperframe.runtime` drives both preview and render
|
|
- **Producer-canonical behavior** -- the [producer's](/packages/producer) seek semantics are the source of truth
|
|
- **Readiness gates** -- `__playerReady` and `__renderReady` ensure the [composition](/concepts/compositions) is fully loaded before any frame is captured
|
|
|
|
<Note>
|
|
Local rendering (without Docker) may show slight differences due to platform-specific font rendering and Chrome version. Use Docker mode when exact reproducibility matters.
|
|
</Note>
|
|
|
|
## For Adapter Authors
|
|
|
|
If you are building a [frame adapter](/concepts/frame-adapters), your adapter must follow the determinism contract:
|
|
|
|
- `seekFrame(frame)` must be idempotent -- same frame, same result
|
|
- No side effects that depend on call order (must handle random access)
|
|
- No async operations that resolve after the frame is "committed"
|
|
- Clean lifecycle: `init` -> `seekFrame` (N times) -> `destroy`
|
|
|
|
## Next Steps
|
|
|
|
<CardGroup cols={2}>
|
|
<Card title="Frame Adapters" icon="plug" href="/concepts/frame-adapters">
|
|
Build adapters that uphold the determinism contract
|
|
</Card>
|
|
<Card title="Rendering" icon="film" href="/guides/rendering">
|
|
Render to MP4 locally or in Docker
|
|
</Card>
|
|
<Card title="@hyperframes/producer" icon="clapperboard" href="/packages/producer">
|
|
The full rendering pipeline that orchestrates deterministic output
|
|
</Card>
|
|
<Card title="Common Mistakes" icon="triangle-exclamation" href="/guides/common-mistakes">
|
|
Pitfalls that break determinism and how to avoid them
|
|
</Card>
|
|
</CardGroup>
|