If you’re already running a different framework that deploys a serverless video renderer with one command, the muscle memory translates cleanly: a singleDocumentation Index
Fetch the complete documentation index at: https://hyperframes.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
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.
Concept mapping
| 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. |
Composition format
If your current framework is React-based, you write JSX components, register them in aComposition, 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.
Render config
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. |
Variables (inputProps)
Render-time payloads —inputProps in some frameworks, variables in HyperFrames — are isomorphic. Declare the composition’s variable shape on the root <html> element via data-composition-variables, then pass per-render values with hyperframes render --variables '{...}' locally or hyperframes lambda render --variables on the Lambda surface. The same 256 KiB execution-input cap and “URL your assets, don’t inline base64” convention apply.
The full mapping — defaultProps → declarations, useCurrentFrame() + props.<x> → __hyperframes.getVariables().<x>, renderMediaOnLambda({ inputProps }) → renderToLambda({ config: { variables } }) — lives in Templates on Lambda.
What HyperFrames does differently
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.Deterministic Chrome path is mandatory
HyperFrames refusesdata-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.
Font fetching fails closed
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.
No HDR (yet)
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 uses closed-GOP VP9
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.
State files are local by default
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.
IAM policy is print-then-narrow
The default policy doc emitted byhyperframes 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.
Migration checklist
- 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.
Non-Lambda runtimes
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