Getting Started
1
Verify your environment
Run the diagnostics command to check for required dependencies:Expected output:
Terminal
2
Preview your composition
Before rendering, preview your composition in the browser to verify it looks correct:
Terminal
3
Render to MP4
Run the render command from your project directory:Expected output:
Terminal
Rendering Modes
- Local Mode
- Docker Mode
Local Mode (default)
Uses Puppeteer (bundled Chromium) and your system’s FFmpeg. Fast for iteration during development.Requires: FFmpeg installed on your system. See Troubleshooting if FFmpeg is not found.Terminal
- Fast startup, no container overhead
- Can use your system GPU for Chrome/WebGL capture by default
- Can use your system GPU for hardware-accelerated encoding (with
--gpu) - Best for iterative development
- Output may vary across platforms due to font and Chrome version differences
- Not suitable for CI/CD pipelines that require reproducibility
When to Use Each Mode
Options
Quality and Encoding
The--quality flag selects a preset that controls the H.264 CRF (Constant Rate Factor) and encoder speed:
For finer control, use
--crf or --video-bitrate to override the preset:
standard preset (CRF 18) is visually lossless at 1080p — most people cannot distinguish it from the source. Use --quality draft for faster iteration, or --quality high / --crf 10 when file size is no concern.
Input Video Codecs
Video assets referenced by a composition (a<video src="..."> clip) are decoded by FFmpeg, not by the browser: the pipeline pre-extracts every input video into frame images and injects them during capture, so the render never depends on what the capture browser can play. Any codec your FFmpeg build decodes works as an input, including:
- H.264 / AVC
- HEVC / H.265, 8-bit and 10-bit (
hvc1andhev1): common for storage-optimized asset libraries; renders identically on macOS and Linux, no hardware decoder required - VP8 / VP9 and ProRes 4444 (with alpha; see Transparent Video)
- HDR sources (HLG / PQ) are tone-mapped for SDR renders; see the HDR guide
preview, play, Studio, and published player pages play the file in a real browser, so playback there depends on that browser’s codec support. Chrome (107+), Edge, and Safari hardware-decode HEVC on most modern machines; Firefox does not. If an HEVC asset shows a black frame in preview while rendering fine, generate an H.264 proxy for authoring (for example with ffmpeg -i asset.mp4 -c:v libx264 -crf 18 proxy.mp4, or via the media-use skill) and swap the original back in for the final render, or just keep the HEVC source, since the rendered output is unaffected.
hyperframes lint emits an info-level hevc_preview_codec note when a composition references an HEVC video, as a reminder of this preview-only limitation.
Animated GIF
Use GIF when the output needs to autoplay inline in GitHub PRs, READMEs, issue reports, and docs pages:Terminal
palettegen with diff statistics, then paletteuse with Sierra dithering) for better gradients and text edges than a single-pass conversion. GIFs are still much larger than MP4/WebM at the same dimensions, so prefer short compositions. GIF renders are capped at 30fps; pass --fps 15 for smaller files.
GIF does not carry audio and only has 1-bit transparency. For transparent overlays, use --format webm, --format mov, or --format png-sequence instead.
For UI recordings, screen captures, or other source videos where saturated interface colors matter, pass --video-frame-format png to extract source video layers as PNG before browser capture. The default auto mode preserves the historical behavior: alpha-capable sources use PNG, opaque sources use JPG.
GPU Acceleration
Hyperframes has two separate GPU acceleration surfaces:--gpuuses a hardware video encoder in FFmpeg when one is available. Supported backends include VideoToolbox on macOS, NVENC on NVIDIA systems, AMD AMF on Windows, VAAPI on Linux, and Intel QSV on supported Windows/Linux hosts.- Browser GPU uses the host GPU for local Chrome/WebGL capture. It is enabled automatically for local renders and disabled in Docker. Use
--no-browser-gputo opt out.
Terminal
--no-browser-gpu or Docker mode when exact cross-machine reproducibility matters more than local render speed.
Workers
Each render worker launches a separate Chrome browser process to capture frames in parallel. More workers can speed up rendering, but each one consumes ~256 MB of RAM and significant CPU.Default behavior
By default, Hyperframes uses CPU cores minus 2 (reserving headroom for FFmpeg encoding and your other applications):
Each worker spawns its own Chrome process (~256 MB RAM), so the per-worker overhead is significant. The maximum is 24 workers (hard ceiling).
Choosing a worker count
Terminal
When to use 1 worker
- Short compositions (under 2 seconds / 60 frames) — parallelism overhead exceeds the benefit
- Low-memory machines (4 GB or less)
- Running renders alongside other heavy processes (video editing, large builds)
When to increase workers
- Long compositions (30+ seconds) on a machine with 8+ cores and 16+ GB RAM
- Dedicated render machines or CI runners
- Docker mode on a well-provisioned host
Batch Rendering
Batch rendering runs the same composition once per variables row:rows.json
Terminal
--output is a template. Use {index} or any scalar key from the row to make each path unique. Hyperframes preflights the full batch before rendering: malformed rows, missing placeholders, duplicate output paths, and strict variable mismatches fail before the first video starts. A manifest.json file is written next to the outputs with per-row status, output path, render time, duration when available, and error details.
Rows continue after failures by default so a bad data row does not discard the rest of the batch. Add --batch-fail-fast to stop launching new rows after the first failure, or --json to stream machine-readable progress events while the manifest is updated.
Concurrent Renders
When multiple render requests hit the producer server simultaneously (common with AI agents), each render spawns its own set of Chrome worker processes. Too many concurrent renders can exhaust CPU and cause failures. The producer server uses a request-level semaphore to queue renders. OnlymaxConcurrentRenders renders execute at a time — additional requests wait in a FIFO queue until a slot opens.
Configuration
Terminal
Queue status
The producer server exposes aGET /render/queue endpoint that returns the current state:
SSE queue events
When using the streaming endpoint (POST /render/stream), queued requests receive a queued event before rendering begins:
Choosing a concurrency limit
Transparent Video
Hyperframes supports rendering with a transparent background — useful for overlays, lower thirds, subscribe cards, and any element you want to composite over other footage in a video editor.Recommended format: MOV (ProRes 4444)
Terminal
- CapCut
- Final Cut Pro
- Adobe Premiere Pro
- DaVinci Resolve
- After Effects
Format comparison
WebM VP9 alpha is technically supported but all major video editors ignore the alpha channel and render transparent areas as black. Only Chromium-based browsers (Chrome, Arc, Brave, Edge) decode VP9 alpha correctly. Safari does not support it. Use MOV for editor workflows and WebM only for browser-based playback.
PNG sequence (no encoding)
Terminal
--format png-sequence skips the encoder entirely. The captured RGBA frames are copied to <output>/frame_NNNNNN.png (zero-padded) and, if the composition has audio, an audio.aac sidecar is written alongside. Use this when you want lossless frames — for compositing in After Effects / Nuke / Fusion, or as the input to a custom encode pipeline. --output is treated as a directory and is created if it doesn’t exist.
How it works
When you render with--format mov, --format webm, or --format png-sequence, Hyperframes:
- Captures each frame as a PNG with alpha channel (instead of JPEG for MP4)
- Sets Chrome’s page background to transparent via
Emulation.setDefaultBackgroundColorOverride - Encodes with an alpha-capable codec (ProRes 4444 for MOV, VP9 for WebM);
png-sequenceskips encoding and writes the captured frames directly
background on html or body — leave it unset so the transparent background comes through.
Authoring transparent compositions
Verifying transparency
- In a browser: Open the MOV file — it won’t play (ProRes is not a browser codec). Instead, render a WebM copy and open it in Chrome on a checkerboard background page.
- In a video editor: Import the MOV file and place it on a track above other footage. Transparent areas should show the footage below.
- Online tool: Use rotato.app/tools/transparent-video to verify your MOV or WebM has working transparency.
ffprobe reports a transparent WebM as yuv420p, not yuva420p. This is expected and does not mean the alpha is missing. VP9 stores its alpha plane in a Matroska BlockAdditional sidecar, not in the primary stream’s pixel format, so ffprobe reports the primary stream as pix_fmt=yuv420p even when the file genuinely carries alpha. First check that the WebM declares the alpha sidecar, then force the VP9 library decoder to verify per-pixel alpha:frame.raw reads 00 00 00 00. MOV (ProRes 4444) and png-sequence report their alpha directly, so this caveat is WebM-only.Tips
- Use
npx hyperframes benchmarkto find optimal settings for your system - Docker mode is slower but guarantees identical output across platforms
- For compositions with many frames,
--gpucan significantly speed up local encoding
Next Steps
Deterministic Rendering
Understand the determinism guarantees
HDR Rendering
Render HDR10 MP4 from HDR video and image sources
Cloud Rendering
Render on HeyGen’s hosted cloud — no local Chrome or FFmpeg
CLI Reference
Full list of CLI commands and flags
Troubleshooting
Fix common rendering issues