| title | Migrating to HyperFrames Lambda |
|---|---|
| description | Side-by-side mapping for adopters coming to HyperFrames from another one-command-deploy video renderer. |
If you're already running a different framework that deploys a serverless video renderer with one command, the muscle memory translates cleanly: a single deploy provisions the stack, a single render starts a render, a single progress polls it, and a single destroy tears the stack down. This page maps your existing concepts onto HyperFrames' equivalents so you can spend the migration on the parts that actually differ instead of relearning the workflow.
| In your current framework you call... | In HyperFrames you call... | Notes |
|---|---|---|
| One-shot deploy command | hyperframes lambda deploy |
Builds packages/aws-lambda/dist/handler.zip and runs sam deploy. Idempotent. |
| One-shot site upload | hyperframes lambda sites create ./project |
Content-addressed S3 key — re-uploads of an unchanged tree are skipped via a HeadObject 200. |
| Trigger a render | hyperframes lambda render ./project --width 1920 --height 1080 |
Returns immediately with a renderId; add --wait to stream per-chunk progress. |
| Poll render progress | hyperframes lambda progress <renderId> |
Includes accrued cost in the same response. |
| Tear down | hyperframes lambda destroy |
The S3 bucket is Retain'd — documented in the deploy guide. |
| Print/validate IAM policy | hyperframes lambda policies user/role/validate |
Wire validate into CI to catch policy drift before the next deploy fails. |
If your current framework is React-based, you write JSX components, register them in a Composition, and the renderer compiles them at render time.
In HyperFrames, compositions are plain HTML files. The data-duration, data-width, data-height, and data-fps attributes on the root element drive every render parameter. There is no JSX compilation step — what you write is what the browser renders.
<!doctype html>
<html data-duration="10" data-width="1920" data-height="1080" data-fps="30">
<body>
<h1 style="animation: fade-in 1s">Hello</h1>
</body>
</html>For framework-agnostic animation, HyperFrames supports first-party adapters for GSAP, Anime.js, CSS keyframes, Lottie, Three.js, and the Web Animations API — covered in the Concepts and per-skill docs.
Most adopters' render config maps directly:
| Concept | HyperFrames equivalent | Where it lives |
|---|---|---|
fps |
--fps=30 (CLI) or config.fps (SDK) |
24, 30, 60 only — non-integer NTSC rationals are an in-process-only feature. |
width / height |
--width / --height flags, or config.width / config.height |
Even integers ≤ 7680 (yuv420p parity). |
codec: 'h264' / 'h265' |
--codec=h264 or --codec=h265 (mp4 only) |
h265 uses libx265 with closed-GOP keyint params so chunked concat-copy round-trips losslessly. |
| Output format | --format=mp4 / mov / webm / png-sequence |
webm uses libvpx-vp9 + closed-GOP concat-copy. Distributed mode still refuses HDR mp4 at plan time. |
| Quality preset | --quality=draft / standard / high |
Maps onto ffmpeg encoder presets. |
| Chunk size in frames | --chunk-size=240 (default 240) |
~8s at 30 fps; sized to fit Lambda's 15-min cap with headroom. |
| Max parallel chunks | --max-parallel-chunks=16 (default 16) |
Caps the Map state's fan-out. |
| Bitrate / CRF | --bitrate=10M or --crf=18 |
Mutually exclusive. |
A few areas where the contract is intentionally different from comparable frameworks. Surface them up front so the migration doesn't surprise you mid-deploy.
HyperFrames refuses data-gpu-mode="hardware" in distributed mode — hardware GL is non-deterministic across chunk boundaries, and the per-chunk concat-copy assumes byte-level reproducibility. Compositions that opt into hardware GL in-process must drop it for Lambda renders. The Lambda handler trips a typed BROWSER_GPU_NOT_SOFTWARE non-retryable error on plan that's easy to catch in the progress output.
failClosedFontFetch is default-on in distributed mode. A composition that references a font-family HyperFrames can't fetch will fail at plan time (FONT_FETCH_FAILED) rather than silently falling back to the OS default. If you currently lean on system-font fallbacks, list the fonts you need explicitly via <link rel="stylesheet"> or @fontsource/* imports.
hdrMode: 'force-hdr' is rejected at plan time. The v1.5 backlog covers HDR mp4 via -bsf:v hevc_metadata re-application; for now, HDR renders use the in-process renderer outside Lambda.
webm distributed renders go through libvpx-vp9 with -g <chunkSize>, -keyint_min <chunkSize>, -auto-alt-ref 0, and -cpu-used 2. The alt-ref disable is the load-bearing bit: libvpx-vp9's default non-displayable alt-ref frames can land anywhere in a GOP, which breaks concat-copy at chunk seams. Closed-GOP forces a keyframe at every chunk boundary so ffmpeg -f concat -c copy round-trips losslessly. Output is yuva420p to preserve alpha. Audio is muxed as Opus.
Distributed webm files are typically ~10-25% larger than the same composition rendered in-process at the same CRF, because closed-GOP forces more keyframes than the in-process single-pass would emit. Per-chunk encode is also slower than libvpx-vp9's default speed/quality tradeoff (-cpu-used 2 is more conservative than the default for -deadline good). The single-machine in-process renderer remains the right choice for short webm renders; distributed pays for itself once a render's wall-clock exceeds what one machine delivers.
hyperframes lambda deploy writes <cwd>/.hyperframes/lambda-stack-<name>.json so subsequent verbs don't re-derive the bucket / state-machine ARN. Two worktrees produce two distinct state files. If you need a shared default location across CI workers, symlink the directory or pass --stack-name explicitly on every call.
The default policy doc emitted by hyperframes lambda policies user/role uses Resource: "*" because the CloudFormation stack creates new ARNs on every adopter's first deploy. After your first successful deploy, narrow the Resource to the deployed ARNs — they're predictable from the CFN outputs. CI users typically check the narrowed policy into source and run hyperframes lambda policies validate ./infra/policy.json as a pre-deploy gate.
- Inventory the compositions you want to migrate. Filter out anything that needs HDR — that stays on your current framework for now. webm renders distributed via closed-GOP VP9 + concat-copy (see the webm section above).
- Translate each composition to plain HTML. The
[Concepts](/concepts)page covers the data-attribute conventions; the/hyperframesskill (npx skills add heygen-com/hyperframes) makes Claude / Cursor / Codex aware of them too. - Wire the new composition into your build pipeline alongside the old one. HyperFrames doesn't need an external bundler — you can
npx hyperframes previewagainst the HTML directly. - Deploy in a separate AWS account or with a
--stack-name=hyperframes-stagingfirst. Run a real render with--wait; verify the output bytes. - Add the policy to your CI.
hyperframes lambda policies user > infra/iam/hyperframes.jsonthenhyperframes lambda policies validate infra/iam/hyperframes.jsonon every PR. - Cut over by pointing your existing automation at the new render endpoint. Keep the old deployment alive until you've verified rolling renders for a release cycle, then
hyperframes lambda destroythe staging stack and decommission the previous one.
If you don't want Lambda specifically, the same @hyperframes/producer/distributed primitives run anywhere Node + Chrome + ffmpeg + S3 are available. A reference Dockerfile lives at examples/k8s-jobs/Dockerfile.example for adopters running on:
- Google Cloud Run Jobs
- Azure Container Apps Jobs
- AWS ECS Fargate
- Kubernetes Jobs / Argo Workflows
- Plain Docker on a beefy VM
Build it yourself — we don't publish a Docker image to a registry. The Dockerfile is documented inline and bakes Node 22 + chrome-headless-shell + ffmpeg + the producer at the version your checkout is on.