Skip to main content
Render your Hyperframes compositions to MP4, MOV, WebM, GIF, or PNG sequences with the CLI. The rendering pipeline is frame-by-frame and seek-driven — see Deterministic Rendering for how this works under the hood.

Getting Started

1

Verify your environment

Run the diagnostics command to check for required dependencies:
Terminal
Expected output:
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:
Terminal
Expected output:

Rendering Modes

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
Pros:
  • 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
Cons:
  • 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:
Tip: The default 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 (hvc1 and hev1): 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
The one caveat is live preview: 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
GIF output uses a two-pass FFmpeg palette encode (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:
  • --gpu uses 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-gpu to opt out.
Terminal
Browser GPU capture is local-mode only. It maps to platform-native Chrome GPU backends: Metal on macOS, D3D11 on Windows, and EGL on Linux. Use --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
Start with the default. If renders feel slow and your system has headroom (check Activity Monitor / htop), try increasing --workers. If you see high memory pressure or fan noise, reduce it.

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. Only maxConcurrentRenders renders execute at a time — additional requests wait in a FIFO queue until a slot opens.

Configuration

Terminal
The default is 2 concurrent renders, which works well on 8-core machines where each render uses 2-3 workers.

Queue status

The producer server exposes a GET /render/queue endpoint that returns the current state:
AI agents can poll this endpoint to decide whether to submit a render or wait.

SSE queue events

When using the streaming endpoint (POST /render/stream), queued requests receive a queued event before rendering begins:
This lets agents report “waiting in queue” to users rather than appearing stuck.

Choosing a concurrency limit

When in doubt, use 1. Renders will queue up and execute sequentially, but each one gets full CPU and finishes as fast as possible. This is better than 3 renders fighting for CPU and all finishing slowly — or failing.

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.
Terminal
MOV with ProRes 4444 is the industry standard for transparent video. It works in all major video editors:
  • CapCut
  • Final Cut Pro
  • Adobe Premiere Pro
  • DaVinci Resolve
  • After Effects
ProRes MOV files are large (typically 5-40 MB for short clips) because ProRes is a high-quality intermediate codec optimized for editing, not delivery. This is expected — the same tradeoff Remotion and professional pipelines make.

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:
  1. Captures each frame as a PNG with alpha channel (instead of JPEG for MP4)
  2. Sets Chrome’s page background to transparent via Emulation.setDefaultBackgroundColorOverride
  3. Encodes with an alpha-capable codec (ProRes 4444 for MOV, VP9 for WebM); png-sequence skips encoding and writes the captured frames directly
Your composition’s HTML should not set a background on html or body — leave it unset so the transparent background comes through.

Authoring transparent compositions

Only the visible elements (cards, text, images) will appear in the final video. Everything else will be transparent.

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:
A fully transparent corner pixel in 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 draft quality during development for fast previews. Switch to standard or high for final output.
  • Use npx hyperframes benchmark to find optimal settings for your system
  • Docker mode is slower but guarantees identical output across platforms
  • For compositions with many frames, --gpu can 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