* feat(cli): cloud render uploads heavy media as HeyGen assets Media of 5 MB or more leaves the project zip: it uploads through the direct-upload flow as a HeyGen asset and the zip's HTML and CSS point at the asset URL. Uploads are cached by content hash and re-checked before reuse. Media the asset API refuses or caps is re-encoded at visually lossless quality first. The zip must end under 200 MB or the command stops and names the largest files left. * feat(cli): cloud render offloads GIFs, still images and script-referenced media Animated GIFs in the entry composition go through the renderer's own GIF preparation and upload as the resulting video. Still AVIF, GIF, BMP and TIFF images convert to PNG. Plain string literals in scripts and JSON that name offloaded media point at the asset URL. ffprobe calls end their options with "--", and two comment lines are trimmed for the ratchet. * feat(cli): cloud render uploads only the parts of long media a composition plays A video or audio file that has to be re-encoded is cut to the union of the windows its clips play, with half a second of margin on the source's frame grid, and the staged composition's media starts shift to match. Clips in sub-compositions, looping clips, speed ramps and files a script names keep the full file. * fix(cli): cloud render no longer decodes media files as text when rewriting references * fix(cli): cloud render keeps media chosen at render time and encodes the staged bytes Only media a reference points at is offloaded, so a file picked through --variables or built by a script stays in the zip. Variable-bound clips and clips with a media fragment keep their full length. Entry GIFs resolve the way the renderer rebases a nested entry and are prepared only from 5 MB, and every encode reads the staged bytes its cache key hashes. Query strings and media fragments survive the rewrite, a null cache file reads as empty, and the docs say asset URLs are public and unsigned. * fix(cli): cloud render comments cite only what this repo holds * fix(cli): cloud render handles media over 2 GiB and explains a too-large upload Media of 5 MB or more stays on disk until it is used: it is hashed and uploaded as a stream, and a file edited after staging stops the run instead of caching the wrong upload. Files left in the zip are sized before any is read, so a 4 GB file reports "too large" instead of crashing. The asset API rejects an over-limit upload as invalid_parameter with "File too large"; that now gets the dry-run hint instead of the --help one. * fix(cli): cloud render checks and reads each staged file through one handle Staging, the on-disk staged read and the re-encoded output read each opened the path twice: once to stat, once to read. A file swapped or edited between the two could be read without the size or change check seeing it. Each now opens once, checks the open file's stat before and after the read, and reads from it. * test(cli): a heavy file a script builds from split strings stays in the cloud render zip * fix(cli): cloud render keeps media scripts may reach and never trims clips scripts retime - An offloaded file keeps its zip copy when script code holds both its stem and extension, so a path joined at runtime still loads. - Entry GIFs are prepared from a private copy checked against the staged file, so the GIF cache never stores a later edit. - No cut when any script can write a clip's timing attributes, dataset, currentTime, playbackRate, src or loop.
hyperframes
CLI for creating, previewing, and rendering HTML video compositions.
Install
npm install -g hyperframes
Or use directly with npx:
npx hyperframes <command>
Requirements: Node.js >= 22, FFmpeg
Commands
init
Scaffold a new Hyperframes project from a template:
npx hyperframes init my-video
cd my-video
preview
Start the live preview studio in your browser:
npx hyperframes preview
# Studio: http://localhost:3002/#project/my-video
# Server: http://localhost:3002
npx hyperframes preview --port 4567
In an interactive terminal, the preview stays attached until you press
Ctrl+C. In a non-interactive shell such as a coding-agent session, the same
command starts a managed preview that survives after the command returns. Use
--background or --foreground to choose explicitly, and manage persistent
previews with --status, --stop, --list, and --kill-all. Add --json to
managed lifecycle commands for machine-readable output. --foreground --json
prints the ready-session envelope once, then remains attached until stopped.
audio
Measure where sounds land: onsets, the moment each sound peaks, loudness and silence. Give files, or query the film's own clips in film time:
npx hyperframes audio sfx/whoosh.mp3
npx hyperframes audio --at 12 --json
normalize-audio
Measure two local authored audio clips with integrated LUFS and match the target
to the unchanged reference. The command is a dry run unless --write is passed:
npx hyperframes normalize-audio --reference target-audio --target user-audio
npx hyperframes normalize-audio --reference target-audio --target user-audio --write
It updates only the target element's data-volume and refuses unsafe boosts
that exceed Studio's +12 dB ceiling or would clip.
render
Render a composition to MP4. Run from the project directory; the positional
argument is the project directory (not a file), so render the project's
index.html directly, or point at a specific composition file with -c:
npx hyperframes render -o output.mp4
npx hyperframes render -c ./my-composition.html -o output.mp4
A render stops when the process that started it exits. To keep one running after
its launcher exits, set HYPERFRAMES_RENDER_DETACHED=1 and start it in its own
process group, e.g. bash -c 'set -m; HYPERFRAMES_RENDER_DETACHED=1 npx hyperframes render -o out.mp4 < /dev/null > render.log 2>&1 &'.
Piped, non-quiet renders emit a single @hf-diagnostic JSON line when an audio
failure reaches the CLI error handler. Version 1 has operation: "render" and
at most 16 audioFailures: allowlisted stage, reason, owner, retryable, and
optional subprocess exit code, signal, termination reason and OS code. It omits
messages, stderr, source paths/URLs, element IDs and command arguments. Consumers
must ignore unknown versions and fields. This is local CLI output; uploading it
requires the caller's existing consent and privacy checks. Quiet mode (including
batch JSON mode) emits no diagnostic line.
This covers audio preparation and mix failures, including the typed external interruption path. Probe failures retain their existing stage/reason but do not gain subprocess evidence here; browser/FX failures remain classified as internal. Desktop ingestion and live report delivery are separate changes.
publish
Upload a project directory and get a hosted URL that keeps working after the CLI exits. Published projects are private by default:
npx hyperframes publish
npx hyperframes publish ./my-video
npx hyperframes publish --public
npx hyperframes publish --yes
Signed-out publishing returns an authentication-required claim URL; opening it
lets someone sign in and claim the project. Sign in first with
npx hyperframes auth login to publish an owned project you can update. Use
--public to make the claimed project visible to anyone. --yes only skips the
confirmation prompt and does not change visibility.
Signed-in publishers can use --update <url-or-id> to target an existing project
or --space <space-id> to publish into a shared team space. If the requested
project is missing or inaccessible, publishing can create a new project instead;
check the printed URL and status.
See the publish reference for all options, including video proxy settings.
lint
Validate your Hyperframes HTML:
npx hyperframes lint ./my-composition
npx hyperframes lint ./my-composition --json # JSON output for CI/tooling
npx hyperframes lint ./my-composition --verbose # Include info-level findings
By default only errors and warnings are shown. Use --verbose to also display informational findings (e.g., external script dependency notices). Use --json for machine-readable output with errorCount, warningCount, infoCount, and a findings array.
compositions
List compositions found in the current project:
npx hyperframes compositions
benchmark
Run rendering benchmarks:
npx hyperframes benchmark ./my-composition.html
doctor
Check your environment for required dependencies (Chrome, FFmpeg, Node.js):
npx hyperframes doctor
browser
Manage the bundled Chrome/Chromium installation:
npx hyperframes browser
info
Print version and environment info:
npx hyperframes info
docs
Open the documentation in your browser:
npx hyperframes docs
upgrade
Check for updates and show upgrade instructions:
npx hyperframes upgrade
npx hyperframes upgrade --check --json # machine-readable for agents
Documentation
Full documentation: hyperframes.heygen.com/packages/cli
Related packages
@hyperframes/core— types, parsers, frame adapters@hyperframes/engine— rendering engine@hyperframes/producer— render pipeline@hyperframes/studio— composition editor UI