docs: name the binary the package actually installs

The published package is @hanzo/frame and its bin is `frames`, so
`npx @hanzo/frame <command>` and a bare `frames <command>` are the two
forms that run. There is no `hanzo frame` group on the hanzo CLI, and
prose that named one described a command nobody can type.
This commit is contained in:
zooqueen
2026-08-13 17:31:23 -07:00
parent e0266e8a63
commit 457e510c8a
84 changed files with 344 additions and 344 deletions
+16 -16
View File
@@ -999,12 +999,12 @@ Frames now uses a 0–10 recommendation scale for feedback, keeps canvas z-order
description="Released - 2026-07-14"
tags={["Release", "Producer", "Release", "CLI"]}
>
`hanzo frame publish` now returns a stable public URL: re-publishing updates the same link in place, and a `--space` flag plus a committable project file let a whole team publish to one shared URL. This release also keeps preview review sessions alive across reloads and tags HeyGen API calls with an `X-HeyGen-Client-Source` header.
`frames publish` now returns a stable public URL: re-publishing updates the same link in place, and a `--space` flag plus a committable project file let a whole team publish to one shared URL. This release also keeps preview review sessions alive across reloads and tags HeyGen API calls with an `X-HeyGen-Client-Source` header.
## Features
- **Preview:** Keep review sessions alive ([2a7a5e623](https://github.com/hanzoai/frames/commit/2a7a5e62361c178daf5f741ee6d0479b3c16c3e9), [#2384](https://github.com/hanzoai/frames/pull/2384))
- **CLI:** Stable public URL for hanzo frame publish (re-publish updates the same link) ([4495cb735](https://github.com/hanzoai/frames/commit/4495cb7355bcbb401bcaa04355c817220ef0be48), [#2363](https://github.com/hanzoai/frames/pull/2363))
- **CLI:** Stable public URL for frames publish (re-publish updates the same link) ([4495cb735](https://github.com/hanzoai/frames/commit/4495cb7355bcbb401bcaa04355c817220ef0be48), [#2363](https://github.com/hanzoai/frames/pull/2363))
- **Media Use:** Tag HeyGen calls with X-HeyGen-Client-Source ([dd938c7a1](https://github.com/hanzoai/frames/commit/dd938c7a16dc0200fb46ff2037e07913d299a471), [#2365](https://github.com/hanzoai/frames/pull/2365))
- **CLI:** Tag HeyGen API calls with X-HeyGen-Client-Source ([746b6d5b7](https://github.com/hanzoai/frames/commit/746b6d5b7558220f213c8dae69e4175d3aa6445f), [#2368](https://github.com/hanzoai/frames/pull/2368))
- **CLI:** Coordinate-frame layout findings in check ([7f4eaeb56](https://github.com/hanzoai/frames/commit/7f4eaeb56813640cfb026ff6392d3900dcc12715), [#2354](https://github.com/hanzoai/frames/pull/2354))
@@ -1224,7 +1224,7 @@ This release makes studio manual editing safe for color-graded compositions: edi
description="Released - 2026-07-11"
tags={["Release", "CLI", "Skills", "Sdk"]}
>
The CLI now runs a free trial of the drawElement parallel router (`HF_DE_PARALLEL_ROUTER`) on eligible local renders — it stays on until a real failure fires the safety net, then turns off for that install — and every router/inversion failure path (OOM, blank frames, PSNR, capture errors) now reaches telemetry with a fallback reason, with OOM retries dropping to a single worker after killing stale workers. Also fixes keyframe shots ignoring direct entries, SDK template GSAP scripts missing from resolver parity, and `hanzo frame lint` tripping on macOS AppleDouble files.
The CLI now runs a free trial of the drawElement parallel router (`HF_DE_PARALLEL_ROUTER`) on eligible local renders — it stays on until a real failure fires the safety net, then turns off for that install — and every router/inversion failure path (OOM, blank frames, PSNR, capture errors) now reaches telemetry with a fallback reason, with OOM retries dropping to a single worker after killing stale workers. Also fixes keyframe shots ignoring direct entries, SDK template GSAP scripts missing from resolver parity, and `frames lint` tripping on macOS AppleDouble files.
## Features
@@ -1257,7 +1257,7 @@ The CLI now runs a free trial of the drawElement parallel router (`HF_DE_PARALLE
description="Released - 2026-07-11"
tags={["Release", "Media Use", "CLI"]}
>
`media-use`'s HeyGen resolves now tag whether a call went through the free (OAuth) or paid (API-key) path and classify failures into stable reasons, with a test-isolation fix so local runs can't reach the production telemetry endpoint. `hanzo frame skills update` now converges when a skill has been retired or renamed upstream — it no longer fails with `Skill(s) still missing after install` or loops on `No matching skills found`, and reconciles the orphaned skill away instead.
`media-use`'s HeyGen resolves now tag whether a call went through the free (OAuth) or paid (API-key) path and classify failures into stable reasons, with a test-isolation fix so local runs can't reach the production telemetry endpoint. `frames skills update` now converges when a skill has been retired or renamed upstream — it no longer fails with `Skill(s) still missing after install` or loops on `No matching skills found`, and reconciles the orphaned skill away instead.
## Features
@@ -1275,7 +1275,7 @@ The CLI now runs a free trial of the drawElement parallel router (`HF_DE_PARALLE
description="Released - 2026-07-10"
tags={["Release", "CLI", "Core", "Cli,skills"]}
>
This release makes `hanzo frame check` the canonical verification gate: one command, one browser session covering lint, runtime errors, layout, motion intent, and WCAG contrast, with agent-actionable findings (source anchors, contrast fix suggestions) and snapshot evidence via annotated frames and per-finding crops. `validate`, `inspect`, and `layout` are deprecated but fully functional; `snapshot` gains `--zoom` for high-density crops of any element or region.
This release makes `frames check` the canonical verification gate: one command, one browser session covering lint, runtime errors, layout, motion intent, and WCAG contrast, with agent-actionable findings (source anchors, contrast fix suggestions) and snapshot evidence via annotated frames and per-finding crops. `validate`, `inspect`, and `layout` are deprecated but fully functional; `snapshot` gains `--zoom` for high-density crops of any element or region.
## Features
@@ -1354,7 +1354,7 @@ Hardens the Figma integration end to end — clearer 403/scope errors, 429 retry
description="Released - 2026-07-10"
tags={["Release", "CLI"]}
>
Prevents slow Chrome downloads from losing their install lock and colliding with another Frames process. Also restores `hanzo frame tts --text-file` compatibility for existing skills and scripts.
Prevents slow Chrome downloads from losing their install lock and colliding with another Frames process. Also restores `frames tts --text-file` compatibility for existing skills and scripts.
## Fixes
@@ -1861,7 +1861,7 @@ This release hardens the CLI validation and browser-install paths: validate now
description="Released - 2026-07-04"
tags={["Release", "Core,cli"]}
>
This release makes Figma imports first-class citizens of the shared media inventory: every `hanzo frame figma asset` import now regenerates `.media/index.md` (byte-identical with media-use's format), carries `--description`/`--entity` metadata into the manifest, index, and alt text, and the reuse path correctly upserts metadata and dedupes against any prior format/scale/version tuple. media-use's entity lookups now match figma-imported brand marks across the icon/image boundary.
This release makes Figma imports first-class citizens of the shared media inventory: every `frames figma asset` import now regenerates `.media/index.md` (byte-identical with media-use's format), carries `--description`/`--entity` metadata into the manifest, index, and alt text, and the reuse path correctly upserts metadata and dedupes against any prior format/scale/version tuple. media-use's entity lookups now match figma-imported brand marks across the icon/image boundary.
## Features
@@ -1893,7 +1893,7 @@ This release adds a low-volume attempt counter to the resolver-shadow tripwire,
description="Released - 2026-07-04"
tags={["Release", "Skills", "Studio", "Core,cli"]}
>
This release ships the Figma integration: import Figma frames as frozen assets, pull brand variables and styles as composition tokens, convert frames to editable brand-linked HTML components, and translate Figma Motion timelines into seekable GSAP — all routed through the new /figma skill and `hanzo frame figma` CLI. It also lands a wave of engine extraction-performance work (caching, dedup, one-pass VFR/HDR) and studio persist-failure hardening.
This release ships the Figma integration: import Figma frames as frozen assets, pull brand variables and styles as composition tokens, convert frames to editable brand-linked HTML components, and translate Figma Motion timelines into seekable GSAP — all routed through the new /figma skill and `frames figma` CLI. It also lands a wave of engine extraction-performance work (caching, dedup, one-pass VFR/HDR) and studio persist-failure hardening.
## Features
@@ -2012,7 +2012,7 @@ v0.7.26 makes imported designs more reliable by normalizing host-system primary
description="Released - 2026-07-02"
tags={["Release", "CLI", "Engine", "Render"]}
>
v0.7.25 adds the `hanzo frame keyframes` command for inspecting GSAP, CSS, Anime.js, and 3D onion-skin shots from the CLI. It also improves first-time render reliability with Linux/WSL dependency checks, actionable preset preflight failures, transient capture retries with OOM guidance, and isolated forced-screenshot workers for parallel renders.
v0.7.25 adds the `frames keyframes` command for inspecting GSAP, CSS, Anime.js, and 3D onion-skin shots from the CLI. It also improves first-time render reliability with Linux/WSL dependency checks, actionable preset preflight failures, transient capture retries with OOM guidance, and isolated forced-screenshot workers for parallel renders.
## Features
@@ -2132,7 +2132,7 @@ Adds a lint rule that errors on `crossorigin` on media (it renders fine but show
## Docs & Examples
- **Skills:** Instruct agents to run `hanzo frame feedback` after render ([04700ea9](https://github.com/hanzoai/frames/commit/04700ea9c51d6b29f8512e2ae4c2655054acf20b), [#1785](https://github.com/hanzoai/frames/pull/1785))
- **Skills:** Instruct agents to run `frames feedback` after render ([04700ea9](https://github.com/hanzoai/frames/commit/04700ea9c51d6b29f8512e2ae4c2655054acf20b), [#1785](https://github.com/hanzoai/frames/pull/1785))
[View the full commit range](https://github.com/hanzoai/frames/compare/v0.7.20...v0.7.21).
</Update>
@@ -2210,7 +2210,7 @@ README motion preview.
This release targets the reported render regression by removing per-frame empty
animation scans, fixing software WebGL auto-detection on CPU render hosts, and
reducing headless capture setup overhead. It also exposes Studio selection state
through `hanzo frame preview` so coding agents can inspect and edit the active
through `frames preview` so coding agents can inspect and edit the active
composition more directly.
## Features
@@ -2283,7 +2283,7 @@ Studio gains **element groups**: select multiple elements and group them into a
description="Released - 2026-06-27"
tags={["Release", "CLI"]}
>
This CLI release keeps `hanzo frame init` on the GitHub-backed skills
This CLI release keeps `frames init` on the GitHub-backed skills
freshness path while the skills.sh registry catches up, with a CI-only escape
hatch and offline-safe best-effort install behavior. It also publishes the newly
extracted parser, lint, and studio-server packages as part of the fixed-version
@@ -2361,7 +2361,7 @@ the agents a project actually uses and adds a product-launch video skill.
description="Released - 2026-06-26"
tags={["Release", "CLI", "Runtime", "Producer"]}
>
This release keeps the `hanzo frame skills` CLI honest about what's installed. `skills check` now flags skills that were renamed or dropped upstream, `skills update` prunes them and installs with `--copy` so a freshly installed set matches the published manifest, and login persists and shows a friendly user identity. It also lands producer and runtime reliability work: render fps is honored when seeking, `/health` is served from a worker thread so probes survive main-thread stalls, and binary file responses now stream.
This release keeps the `frames skills` CLI honest about what's installed. `skills check` now flags skills that were renamed or dropped upstream, `skills update` prunes them and installs with `--copy` so a freshly installed set matches the published manifest, and login persists and shows a friendly user identity. It also lands producer and runtime reliability work: render fps is honored when seeking, `/health` is served from a worker thread so probes survive main-thread stalls, and binary file responses now stream.
## Features
@@ -2672,7 +2672,7 @@ Studio GSAP keyframe and motion-path editing, instant flicker-free manual editin
description="Released - 2026-06-21"
tags={["Release", "CLI"]}
>
This hotfix restores `hanzo frame skills` on Windows by invoking npm's `npx.cmd`
This hotfix restores `frames skills` on Windows by invoking npm's `npx.cmd`
shim through `cmd.exe`, while preserving direct `npx` execution on Linux and macOS.
The same resolver also covers the local Studio preview's `npx vite` path and is
verified by CI on all three operating systems.
@@ -2755,7 +2755,7 @@ This hotfix improves render reliability across WebM and MP4 outputs: VP9 encodes
description="Released - 2026-06-20"
tags={["Release", "Slideshow", "Core", "Core,studio"]}
>
Full slideshow stack: schema, parser, controller, `<frames-slideshow>` web component, presenter mode, branching editor panel, and `hanzo frame present` CLI command. SDK gains element add/remove ops, elastic timing, keyframe writers, variables/brand model, and image-alpha hit-testing. Fixes cross-realm iframe media handling, per-element audio muting, querySelector injection, and DOM edit parity.
Full slideshow stack: schema, parser, controller, `<frames-slideshow>` web component, presenter mode, branching editor panel, and `frames present` CLI command. SDK gains element add/remove ops, elastic timing, keyframe writers, variables/brand model, and image-alpha hit-testing. Fixes cross-realm iframe media handling, per-element audio muting, querySelector injection, and DOM edit parity.
## Features
@@ -3160,7 +3160,7 @@ Wires the SDK session into Studio (stage 7 steps 1-3b), adding shadow dispatch p
## Fixes
- **CLI:** Restore `hanzo frame capture \<url\>`; move video download to `--video` flag ([f8d9f512](https://github.com/hanzoai/frames/commit/f8d9f51245908d64b74a8df96bc80e901fd1f5cf))
- **CLI:** Restore `frames capture \<url\>`; move video download to `--video` flag ([f8d9f512](https://github.com/hanzoai/frames/commit/f8d9f51245908d64b74a8df96bc80e901fd1f5cf))
- **Core:** Stop transport re-seek from clobbering Studio drag drafts ([1ab7dcfe](https://github.com/hanzoai/frames/commit/1ab7dcfe477d526cb153c0e73f113d4de0cbd190), [#1464](https://github.com/hanzoai/frames/pull/1464))
## Docs & Examples
+2 -2
View File
@@ -30,10 +30,10 @@ Hyperframes uses HTML data attributes to control timing, media playback, and [co
| `data-composition-id` | `"root"` | Unique ID for [composition](/concepts/compositions) wrapper (required on every composition) |
| `data-width` | `"1920"` | Composition width in pixels |
| `data-height` | `"1080"` | Composition height in pixels |
| `data-duration` (root) | `"30"` | On the **root** composition, the total render length / frame count in seconds. Read once from the source HTML at compile time, like `data-width` / `data-height`, so a script or `hanzo frame render --variables` cannot change it (author it directly, one value per output). If the root omits `data-duration`, and only then, the renderer derives the total length from the live DOM / timeline after scripts run. |
| `data-duration` (root) | `"30"` | On the **root** composition, the total render length / frame count in seconds. Read once from the source HTML at compile time, like `data-width` / `data-height`, so a script or `frames render --variables` cannot change it (author it directly, one value per output). If the root omits `data-duration`, and only then, the renderer derives the total length from the live DOM / timeline after scripts run. |
| `data-composition-src` | `"./intro.html"` | Path to external [composition](/concepts/compositions) HTML file |
| `data-variable-values` | `'{"title":"Hello"}'` | JSON object of values passed to a nested composition. Inside the sub-composition, read them via `window.__frames.getVariables()` — the runtime layers these over the sub-comp's own `data-composition-variables` defaults and exposes the merged result on a per-instance basis (the same source can be embedded multiple times with different values). |
| `data-composition-variables` | `'[{"id":"title","type":"string","label":"Title","default":"Hello"}]'` | JSON array of declared variables (`id`, `type`, `label`, `default`). Drives Studio editing UI and provides defaults read by `window.__frames.getVariables()`. The CLI flag `hanzo frame render --variables '<json>'` overrides these defaults at top-level render time; host elements override them per-instance via `data-variable-values`. |
| `data-composition-variables` | `'[{"id":"title","type":"string","label":"Title","default":"Hello"}]'` | JSON array of declared variables (`id`, `type`, `label`, `default`). Drives Studio editing UI and provides defaults read by `window.__frames.getVariables()`. The CLI flag `frames render --variables '<json>'` overrides these defaults at top-level render time; host elements override them per-instance via `data-variable-values`. |
| `data-var-src` | `"heroImage"` | Binds the element's `src` to a declared variable — the runtime substitutes the value (URL string or image `{url}`) in preview and render; the authored `src` stays as the fallback. |
| `data-var-text` | `"title"` | Binds the element's own text to a scalar variable. Element children (nested clips, animated spans) are preserved. Scalar variables are also applied as `--{id}` CSS custom properties on the composition root, so `color: var(--accent)` responds to overrides. |
+3 -3
View File
@@ -159,7 +159,7 @@ A small set of inputs are read once from the source HTML or from the CLI / SDK,
|------|----------------------------|
| Composition dimensions | `data-width` / `data-height` on the composition element, parsed from the source HTML at compile time, not from the live DOM |
| Root composition total duration | `data-duration` on the **root** composition element (the total render length / frame count), parsed from the source HTML at compile time. A static root `data-duration` is locked before scripts run, so neither a script nor a variable can change the render length. (A clip's own `data-duration` is different: it is re-read from the live DOM, as shown above.) |
| Frame rate | `--fps` flag on `hanzo frame render`, or `config.fps` in the SDK |
| Frame rate | `--fps` flag on `frames render`, or `config.fps` in the SDK |
| Output format / codec / quality | `--format` / `--codec` / `--quality` flags, or the SDK equivalents |
| A sibling or parent composition's variables | Variables are per-composition; use [`data-variable-values`](#per-instance-overrides-sub-compositions) on each sub-comp host element to pass overrides |
@@ -312,7 +312,7 @@ Variable values are resolved by merging three sources, lowest to highest precede
|--------|-----------|---------------|
| Declared defaults | Lowest | `data-composition-variables` on the declaration root (`<html>`, or the composition root div for template/fragment comps) |
| Per-instance host overrides | Middle | `data-variable-values` on the sub-comp host element |
| CLI `--variables` flag | Highest | `hanzo frame render --variables '{...}'` |
| CLI `--variables` flag | Highest | `frames render --variables '{...}'` |
A missing key at any layer falls through to the next lower layer. If no layer provides a value, the declared `default` is used.
@@ -361,7 +361,7 @@ system:
- **Render with values** — renders started from the Renders tab carry the active
preview overrides.
- **Handoff** — copy the effective values as JSON or as a ready-to-run
`hanzo frame render --variables` command.
`frames render --variables` command.
- **Usage** — declarations no script reads are badged `unused`; ids read by scripts
but missing from the schema get a one-click Declare action.
+4 -4
View File
@@ -8,7 +8,7 @@ Your agent already knows how to build video components. It writes HTML. Frames r
This guide shows you how to add to it.
<Info>
**Quick version** — Fork the repo. Write one HTML file with a paused GSAP timeline. Add `registry-item.json`. Run `hanzo frame lint` + `validate`. Publish with `npx @hanzo/frame publish`. Open a PR.
**Quick version** — Fork the repo. Write one HTML file with a paused GSAP timeline. Add `registry-item.json`. Run `frames lint` + `validate`. Publish with `npx @hanzo/frame publish`. Open a PR.
</Info>
## Why Contribute?
@@ -140,8 +140,8 @@ Not everything belongs in the registry. The bar is production quality.
</Step>
<Step title="Validate">
```bash
hanzo frame lint
hanzo frame check
frames lint
frames check
npx oxfmt your-block.html
```
</Step>
@@ -154,7 +154,7 @@ Not everything belongs in the registry. The bar is production quality.
</Step>
<Step title="Render preview">
```bash
hanzo frame render -o preview.mp4
frames render -o preview.mp4
```
</Step>
<Step title="Publish and PR">
+5 -5
View File
@@ -3,7 +3,7 @@ title: Testing Local CLI Changes
description: How to test unreleased CLI changes outside the monorepo using your local build.
---
When you modify the CLI or any package it bundles (core, engine, producer, studio), you need to test those changes against real projects _outside_ the monorepo — the same way an end user would run `hanzo frame preview`.
When you modify the CLI or any package it bundles (core, engine, producer, studio), you need to test those changes against real projects _outside_ the monorepo — the same way an end user would run `frames preview`.
## Prerequisites
@@ -36,7 +36,7 @@ Now use `frames` normally in any directory:
```bash
cd ~/my-video-project
hanzo frame preview .
frames preview .
```
**After every `bun run build`** the linked binary is already up to date — no re-linking needed.
@@ -85,7 +85,7 @@ When validating a specific bug fix, extract one of the test project archives and
```bash
# Example: testing audio-after-seek fix
unzip golden-lyric-video.zip && cd golden-lyric-video
hanzo frame preview .
frames preview .
# 1. Press Play — confirm audio plays
# 2. Drag the timeline scrubber to a different position
# 3. Press Play again — audio should resume from the seeked position
@@ -125,8 +125,8 @@ cd packages/cli && bun link
**Port already in use**
`hanzo frame preview` defaults to port 3002 and auto-increments if it's taken. Pass `--port` to use a specific port:
`frames preview` defaults to port 3002 and auto-increments if it's taken. Pass `--port` to use a specific port:
```bash
hanzo frame preview . --port 4000
frames preview . --port 4000
```
+21 -21
View File
@@ -6,9 +6,9 @@ description: "Deploy distributed Frames rendering to AWS Lambda and drive render
Frames ships a first-class AWS Lambda deployment: one Lambda function fronts a Step Functions standard workflow that fans renders out across many parallel chunk workers, with intermediate artifacts in S3. End-to-end is three commands once your AWS credentials are configured.
```bash
hanzo frame lambda deploy
hanzo frame lambda render ./my-project --width 1920 --height 1080 --wait
hanzo frame lambda destroy
frames lambda deploy
frames lambda render ./my-project --width 1920 --height 1080 --wait
frames lambda destroy
```
Templates with [variables](/concepts/variables) work on the same Lambda stack — declare `data-composition-variables` on the composition, then pass values per render with `--variables` or fan a whole batch out with `lambda render-batch`. See the [Templates on Lambda](/deploy/templates-on-lambda) guide for the personalised-render pipeline (single render, batch from JSONL, programmatic SDK) and the 256 KiB Step Functions execution-input cap.
@@ -45,18 +45,18 @@ The Lambda handler is a thin dispatch: parse the Step Functions event, download
| Tool | Why | Install |
|------|-----|---------|
| AWS credentials | The CLI and the deploy step both call AWS APIs. | Env vars, `~/.aws/credentials`, SSO, or IMDS — any chain the AWS SDK for JavaScript v3 would resolve. |
| AWS SAM CLI | `hanzo frame lambda deploy/destroy` shells out to `sam deploy`/`sam delete`. | [Install guide](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html) |
| AWS SAM CLI | `frames lambda deploy/destroy` shells out to `sam deploy`/`sam delete`. | [Install guide](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/install-sam-cli.html) |
| `bun` | Used to build `packages/aws-lambda/dist/handler.zip` at deploy time. | `npm install -g bun` or [bun.sh](https://bun.sh) |
| Frames repo checkout | `lambda deploy` builds the Lambda handler ZIP from source. Adopters who deploy outside a checkout can set `FRAMES_REPO_ROOT` to point at one. | `git clone https://github.com/hanzoai/frames` |
## Three deployment paths
### Path 1 — `hanzo frame lambda` CLI (recommended)
### Path 1 — `frames lambda` CLI (recommended)
The CLI is a thin wrapper around the SAM template + the `@frames/aws-lambda` SDK. For most adopters this is the right starting point.
```bash
hanzo frame lambda deploy \
frames lambda deploy \
--stack-name=frames-prod \
--region=us-east-1 \
--concurrency=8 \
@@ -68,10 +68,10 @@ The default `--concurrency=8` is deliberately conservative for first-time users.
After `deploy`, render anything with:
```bash
hanzo frame lambda render ./my-project --width 1920 --height 1080 --wait
frames lambda render ./my-project --width 1920 --height 1080 --wait
```
The `--wait` flag blocks and streams per-chunk progress + accrued cost; drop it to fire-and-forget, then poll with `hanzo frame lambda progress <renderId>` on your own cadence.
The `--wait` flag blocks and streams per-chunk progress + accrued cost; drop it to fire-and-forget, then poll with `frames lambda progress <renderId>` on your own cadence.
See the [CLI reference](/packages/cli#frames-lambda) for full flag documentation.
@@ -80,10 +80,10 @@ See the [CLI reference](/packages/cli#frames-lambda) for full flag documentation
Re-rendering the same project tree on every `lambda render` call re-tars and re-uploads it each time. For tight inner loops (CI smoke jobs, prompt iteration in a demo flow), pre-stage the project once and reuse the upload:
```bash
hanzo frame lambda sites create ./my-project
frames lambda sites create ./my-project
# → Site ID: a1b2c3d4e5f6g7h8 (content-addressed)
hanzo frame lambda render ./my-project --site-id=a1b2c3d4e5f6g7h8 \
frames lambda render ./my-project --site-id=a1b2c3d4e5f6g7h8 \
--width 1920 --height 1080 --wait
```
@@ -147,23 +147,23 @@ The CLI ships a built-in IAM bootstrap to avoid the "User is not authorized to p
```bash
# Print an inline policy doc to attach to the IAM user that runs the CLI.
hanzo frame lambda policies user
frames lambda policies user
# Print { TrustRelationship, InlinePolicy } for a CloudFormation service role.
hanzo frame lambda policies role --principal=cloudformation
frames lambda policies role --principal=cloudformation
# Validate a checked-in policy still covers the CLI's needs (exit non-zero on missing).
hanzo frame lambda policies validate ./infra/iam/frames-deploy.json
frames lambda policies validate ./infra/iam/frames-deploy.json
```
The generated documents grant `Resource: "*"` for the CLI's required action set. After your first successful deploy you can narrow `Resource` to the deployed ARNs — predictable per the CloudFormation outputs above. Adopters running the CLI in CI typically check the policy doc into source control and run `policies validate` as a pre-deploy step to catch drift.
## Cost shape
Lambda renders are billed by GB-seconds (Lambda billed duration × configured memory) plus a tiny per-state-transition fee for Step Functions standard workflows. `hanzo frame lambda progress` exposes the running tally:
Lambda renders are billed by GB-seconds (Lambda billed duration × configured memory) plus a tiny per-state-transition fee for Step Functions standard workflows. `frames lambda progress` exposes the running tally:
```bash
hanzo frame lambda progress my-render-id
frames lambda progress my-render-id
# Status: SUCCEEDED
# Progress: 100%
# Frames: 480 / 480
@@ -182,11 +182,11 @@ Pass the same `--stack-name` you used the first time. SAM is idempotent — re-r
### `User is not authorized to perform iam:CreateRole`
The IAM credential running `lambda deploy` doesn't have permission to create the service role CloudFormation needs. Run `hanzo frame lambda policies user` and attach the printed policy to your IAM user (or take the `policies role` output and have your admin create a deploy role).
The IAM credential running `lambda deploy` doesn't have permission to create the service role CloudFormation needs. Run `frames lambda policies user` and attach the printed policy to your IAM user (or take the `policies role` output and have your admin create a deploy role).
### `Lambda function failed: PLAN_HASH_MISMATCH`
Step Functions invoked a `renderChunk` with a plan hash that didn't match the planDir on S3. Almost always means the producer version differs between the local `plan()` build and the deployed Lambda ZIP. Re-run `hanzo frame lambda deploy` (which rebuilds the ZIP) and re-render.
Step Functions invoked a `renderChunk` with a plan hash that didn't match the planDir on S3. Almost always means the producer version differs between the local `plan()` build and the deployed Lambda ZIP. Re-run `frames lambda deploy` (which rebuilds the ZIP) and re-render.
### `Lambda function failed: BROWSER_GPU_NOT_SOFTWARE`
@@ -194,24 +194,24 @@ The handler launched Chromium but the runtime probe found a non-SwiftShader GL b
```bash
bun run --cwd packages/aws-lambda build:zip
hanzo frame lambda deploy --stack-name=<your-stack>
frames lambda deploy --stack-name=<your-stack>
```
The build pipeline pins `@sparticuz/chromium` + the Chrome flags (`--use-gl=swiftshader --use-angle=swiftshader`) so a fresh deploy almost always resolves this. If it persists, your stack's Lambda function is pointing at a stale handler ZIP from a previous deploy — `lambda deploy` always rebuilds, so re-running unsticks it.
### Render seems stuck at `RUNNING`
Most often a Lambda cold-start chain on a many-chunk render. The Map state's reserved concurrency caps how many chunks can run in parallel — if you set `--concurrency=4` and your render has 16 chunks, the state machine processes them in batches of 4. `hanzo frame lambda progress <id>` shows how many invocations are in flight.
Most often a Lambda cold-start chain on a many-chunk render. The Map state's reserved concurrency caps how many chunks can run in parallel — if you set `--concurrency=4` and your render has 16 chunks, the state machine processes them in batches of 4. `frames lambda progress <id>` shows how many invocations are in flight.
If progress doesn't advance for >10 minutes, check the Step Functions execution in the AWS console — failed Lambda invocations include the typed error name (`FONT_FETCH_FAILED`, `FFMPEG_VERSION_MISMATCH`, etc.) which short-circuits the state machine.
### Tearing down doesn't reclaim S3 storage
The render bucket is created with CloudFormation `Retain` on delete — `hanzo frame lambda destroy` (or `sam delete`) tears the function + state machine down but the bucket survives. This is intentional: it protects final-rendered MP4s from being lost when you re-deploy. To fully reclaim storage, empty + delete the bucket via the AWS console / `aws s3 rb`.
The render bucket is created with CloudFormation `Retain` on delete — `frames lambda destroy` (or `sam delete`) tears the function + state machine down but the bucket survives. This is intentional: it protects final-rendered MP4s from being lost when you re-deploy. To fully reclaim storage, empty + delete the bucket via the AWS console / `aws s3 rb`.
## What's NOT in the v1 surface
- **Webhooks on completion.** Not in v1 — poll with `hanzo frame lambda progress` or watch the Step Functions execution. A `--webhook` flag with an SNS topic is on the Phase 6c backlog.
- **Webhooks on completion.** Not in v1 — poll with `frames lambda progress` or watch the Step Functions execution. A `--webhook` flag with an SNS topic is on the Phase 6c backlog.
- **`compositions` discovery verb.** Coming separately (PR 6.10 on the plan); for now, point `lambda render` at the project directory containing your `index.html`.
- **Multi-region.** Each `--region` is an independent stack. There is no built-in cross-region failover.
- **HDR.** Distributed mode is SDR-only. HDR mp4 with bsf signaling is on the v1.5 backlog.
+26 -26
View File
@@ -6,8 +6,8 @@ description: "Render a composition on the hosted cloud — no local Chrome, no F
Render any Frames composition on Hanzo Cloud: the CLI zips your project, uploads it, runs the render there, and downloads the finished video. There's nothing to deploy and no Chrome or FFmpeg to install — the render is metered against your org's balance.
```bash
hanzo frame auth login # one-time sign-in
hanzo frame cloud render # zip → upload → render → download
frames auth login # one-time sign-in
frames cloud render # zip → upload → render → download
```
```bash
@@ -21,7 +21,7 @@ hanzo frame cloud render # zip → upload → render → download
# 8.4 MB written
```
This is the zero-infra alternative to running your own renderer. If you'd rather own the compute, see [AWS Lambda](/deploy/aws-lambda), [GCP Cloud Run](/deploy/gcp-cloud-run), or the [Vercel, Cloudflare, or Modal templates](/guides/deploy). For local iteration during authoring, use [`hanzo frame render`](/guides/rendering).
This is the zero-infra alternative to running your own renderer. If you'd rather own the compute, see [AWS Lambda](/deploy/aws-lambda), [GCP Cloud Run](/deploy/gcp-cloud-run), or the [Vercel, Cloudflare, or Modal templates](/guides/deploy). For local iteration during authoring, use [`frames render`](/guides/rendering).
## Authenticate
@@ -32,7 +32,7 @@ surface — no separate sign-in, no credential file, no per-repo `.env`.
```bash
export HANZO_API_KEY=... # from Hanzo KMS; in CI, injected by the pipeline
hanzo frame auth status
frames auth status
# Shows which credential is in use, the identity behind it, and the balance.
# Exit 0 = usable; exit 1 = absent or rejected.
```
@@ -46,7 +46,7 @@ hanzo frame auth status
## How a cloud render flows
`hanzo frame cloud render` runs the whole pipeline end-to-end:
`frames cloud render` runs the whole pipeline end-to-end:
```
Your machine Hanzo Cloud
@@ -64,7 +64,7 @@ hanzo frame auth status
1. **Resolve the project** — a local directory (default `.`), or skip the upload with `--asset-id` / `--url`.
2. **Auto-detect the aspect ratio** from the entry HTML's `data-width`/`data-height` so you rarely set it by hand.
3. **Zip** the project (same ignore set as `hanzo frame publish`, including `.framesignore`).
3. **Zip** the project (same ignore set as `frames publish`, including `.framesignore`).
4. **Upload** the zip through the direct-to-store asset flow, yielding an `asset_id`.
5. **Submit** the render, yielding a `render_id`.
6. **Poll** that render until it completes or fails (skip with `--no-wait`).
@@ -85,11 +85,11 @@ Use a gitignore-style `.framesignore` at the project root for additional generat
Inspect the exact archive without authenticating, uploading, or starting a render:
```bash
hanzo frame cloud render . --dry-run
hanzo frame cloud render . --dry-run --json
frames cloud render . --dry-run
frames cloud render . --dry-run --json
```
The dry run reports compressed size, file count, and the ten largest included files. Rules also apply to `hanzo frame publish`. Avoid broad patterns such as `assets/`: dynamically selected media may not appear as an obvious static HTML reference.
The dry run reports compressed size, file count, and the ten largest included files. Rules also apply to `frames publish`. Avoid broad patterns such as `assets/`: dynamically selected media may not appear as an obvious static HTML reference.
## Render options
@@ -108,12 +108,12 @@ The most-used flags — see the [CLI reference](/packages/cli#frames-cloud) for
```bash
# Pick a composition and an output path.
hanzo frame cloud render . \
frames cloud render . \
--composition compositions/intro.html \
--output ./renders/intro.mp4
# Higher quality at 60fps.
hanzo frame cloud render --quality high --fps 60
frames cloud render --quality high --fps 60
```
<Warning>
@@ -126,13 +126,13 @@ Cloud rendering supports [variables](/concepts/variables) — the same mechanism
```bash
# Inline JSON
hanzo frame cloud render --variables '{"title":"Q4 Recap","theme":"dark"}'
frames cloud render --variables '{"title":"Q4 Recap","theme":"dark"}'
# From a file
hanzo frame cloud render --variables-file ./vars.json
frames cloud render --variables-file ./vars.json
# Fail fast on undeclared keys or wrong types
hanzo frame cloud render --variables '{"title":"Q4 Recap"}' --strict-variables
frames cloud render --variables '{"title":"Q4 Recap"}' --strict-variables
```
For a **local project**, the CLI validates your `--variables` against the composition's declared schema *before* uploading. For `--asset-id` / `--url` the schema lives server-side, so mismatches surface as a `frames_project_invalid` API error.
@@ -141,11 +141,11 @@ The idiomatic template workflow is **upload once, re-render many**: render a loc
```bash
# 1. Upload + render once; note the asset_id printed during upload.
hanzo frame cloud render ./card-template
frames cloud render ./card-template
# 2. Re-render the same asset with new values (skips zip + upload).
hanzo frame cloud render --asset-id asst_abc123 --variables '{"name":"Ada"}'
hanzo frame cloud render --asset-id asst_abc123 --variables '{"name":"Linus"}'
frames cloud render --asset-id asst_abc123 --variables '{"name":"Ada"}'
frames cloud render --asset-id asst_abc123 --variables '{"name":"Linus"}'
```
For high-volume personalized batches, the bring-your-own-AWS path adds a JSONL fan-out — see [Templates on Lambda](/deploy/templates-on-lambda).
@@ -155,9 +155,9 @@ For high-volume personalized batches, the bring-your-own-AWS path adds a JSONL f
By default the CLI blocks, polls, and downloads. Pass `--no-wait` to submit and exit with just the `render_id`, and `--callback-url` to get an HTTPS webhook when the render terminates. The webhook fires whether or not the CLI is still polling, so combine them for true fire-and-forget:
```bash
hanzo frame cloud render --callback-url https://example.com/hf-hook --no-wait
frames cloud render --callback-url https://example.com/hf-hook --no-wait
# ✓ Submitted hfr_def456
# Poll with: hanzo frame cloud get hfr_def456
# Poll with: frames cloud get hfr_def456
```
| Flag | Meaning |
@@ -171,9 +171,9 @@ hanzo frame cloud render --callback-url https://example.com/hf-hook --no-wait
## Managing renders
```bash
hanzo frame cloud list # recent renders (--limit, --token, --all)
hanzo frame cloud get hfr_def456 # full detail + short-lived signed video_url
hanzo frame cloud delete hfr_def456 # soft-delete (--no-confirm to skip the prompt)
frames cloud list # recent renders (--limit, --token, --all)
frames cloud get hfr_def456 # full detail + short-lived signed video_url
frames cloud delete hfr_def456 # soft-delete (--no-confirm to skip the prompt)
```
`video_url` and `thumbnail_url` are short-lived presigned URLs — re-fetch with `cloud get` rather than caching them.
@@ -183,16 +183,16 @@ hanzo frame cloud delete hfr_def456 # soft-delete (--no-confirm to skip the p
A retry is harmless for reads, but the zip upload is **not** idempotent on its own — a blind retry would create a duplicate asset and meter the org twice. Pass `--idempotency-key` so retries are safe:
```bash
hanzo frame cloud render . --idempotency-key "$(uuidgen)"
frames cloud render . --idempotency-key "$(uuidgen)"
```
The key is forwarded to both the upload and submit calls; the server scopes idempotency per-endpoint, so reusing one value across both steps is safe. Use any opaque string in `[A-Za-z0-9_:.-]` (1–255 chars).
## Cloud vs. Lambda vs. local
- **`hanzo frame render`** (local) — fastest iteration loop; use while authoring. See [Rendering](/guides/rendering).
- **`hanzo frame cloud render`** — zero-infra; Hanzo Cloud runs the render, metered against your org's balance. Use when you don't want to manage Chrome/FFmpeg/AWS.
- **`hanzo frame lambda render`** — bring-your-own-AWS distributed rendering with chunked parallelism. Use when you've already invested in AWS. See [AWS Lambda](/deploy/aws-lambda).
- **`frames render`** (local) — fastest iteration loop; use while authoring. See [Rendering](/guides/rendering).
- **`frames cloud render`** — zero-infra; Hanzo Cloud runs the render, metered against your org's balance. Use when you don't want to manage Chrome/FFmpeg/AWS.
- **`frames lambda render`** — bring-your-own-AWS distributed rendering with chunked parallelism. Use when you've already invested in AWS. See [AWS Lambda](/deploy/aws-lambda).
## Next steps
+11 -11
View File
@@ -9,12 +9,12 @@ If you're already running a different framework that deploys a serverless video
| In your current framework you call... | In Frames you call... | Notes |
|--------------------------------------|----------------------------|-------|
| One-shot deploy command | `hanzo frame lambda deploy` | Builds `packages/aws-lambda/dist/handler.zip` and runs `sam deploy`. Idempotent. |
| One-shot site upload | `hanzo frame lambda sites create ./project` | Content-addressed S3 key — re-uploads of an unchanged tree are skipped via a HeadObject 200. |
| Trigger a render | `hanzo frame lambda render ./project --width 1920 --height 1080` | Returns immediately with a `renderId`; add `--wait` to stream per-chunk progress. |
| Poll render progress | `hanzo frame lambda progress <renderId>` | Includes accrued cost in the same response. |
| Tear down | `hanzo frame lambda destroy` | The S3 bucket is `Retain`'d — documented in the deploy guide. |
| Print/validate IAM policy | `hanzo frame lambda policies user`/`role`/`validate` | Wire `validate` into CI to catch policy drift before the next deploy fails. |
| One-shot deploy command | `frames lambda deploy` | Builds `packages/aws-lambda/dist/handler.zip` and runs `sam deploy`. Idempotent. |
| One-shot site upload | `frames lambda sites create ./project` | Content-addressed S3 key — re-uploads of an unchanged tree are skipped via a HeadObject 200. |
| Trigger a render | `frames lambda render ./project --width 1920 --height 1080` | Returns immediately with a `renderId`; add `--wait` to stream per-chunk progress. |
| Poll render progress | `frames lambda progress <renderId>` | Includes accrued cost in the same response. |
| Tear down | `frames lambda destroy` | The S3 bucket is `Retain`'d — documented in the deploy guide. |
| Print/validate IAM policy | `frames lambda policies user`/`role`/`validate` | Wire `validate` into CI to catch policy drift before the next deploy fails. |
## Composition format
@@ -51,7 +51,7 @@ Most adopters' render config maps directly:
## Variables (inputProps)
Render-time payloads — `inputProps` in some frameworks, `variables` in Frames — are isomorphic. Declare the composition's variable shape on the root `<html>` element via `data-composition-variables`, then pass per-render values with `hanzo frame render --variables '{...}'` locally or `hanzo frame lambda render --variables` on the Lambda surface. The same 256 KiB execution-input cap and "URL your assets, don't inline base64" convention apply.
Render-time payloads — `inputProps` in some frameworks, `variables` in Frames — are isomorphic. Declare the composition's variable shape on the root `<html>` element via `data-composition-variables`, then pass per-render values with `frames render --variables '{...}'` locally or `frames 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>` → `__frames.getVariables().<x>`, `renderMediaOnLambda({ inputProps })` → `renderToLambda({ config: { variables } })` — lives in [Templates on Lambda](/deploy/templates-on-lambda#migrating-from-remotion-lambda-inputprops).
@@ -79,11 +79,11 @@ Distributed webm files are typically ~10-25% larger than the same composition re
### State files are local by default
`hanzo frame lambda deploy` writes `<cwd>/.frames/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.
`frames lambda deploy` writes `<cwd>/.frames/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 by `hanzo frame 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 `hanzo frame lambda policies validate ./infra/policy.json` as a pre-deploy gate.
The default policy doc emitted by `frames 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 `frames lambda policies validate ./infra/policy.json` as a pre-deploy gate.
## Migration checklist
@@ -91,8 +91,8 @@ The default policy doc emitted by `hanzo frame lambda policies user/role` uses `
2. **Translate** each composition to plain HTML. The `[Concepts](/concepts)` page covers the data-attribute conventions; installing the skills (`npx skills add hanzoai/frames`) makes Claude / Cursor / Codex aware of them too — start at `/frames`, which routes to `/frames-core` for the composition contract.
3. **Wire** the new composition into your build pipeline alongside the old one. Frames doesn't need an external bundler — you can `npx @hanzo/frame preview` against the HTML directly.
4. **Deploy** in a separate AWS account or with a `--stack-name=frames-staging` first. Run a real render with `--wait`; verify the output bytes.
5. **Add the policy** to your CI. `hanzo frame lambda policies user > infra/iam/frames.json` then `hanzo frame lambda policies validate infra/iam/frames.json` on every PR.
6. **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 `hanzo frame lambda destroy` the staging stack and decommission the previous one.
5. **Add the policy** to your CI. `frames lambda policies user > infra/iam/frames.json` then `frames lambda policies validate infra/iam/frames.json` on every PR.
6. **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 `frames lambda destroy` the staging stack and decommission the previous one.
## Non-Lambda runtimes
+20 -20
View File
@@ -6,18 +6,18 @@ description: "Render personalised template videos at scale on AWS Lambda using -
Frames templates are compositions that take typed variables — a name, a colour, a chart payload, a CTA URL — and produce a finished render parameterised by those values. Pair a template with the deployed Lambda stack and `lambda render-batch`, and you get personalised-video-at-scale in one CLI call:
```bash
hanzo frame lambda render-batch ./my-template \
frames lambda render-batch ./my-template \
--batch ./users.jsonl \
--width 1920 --height 1080
```
This guide walks the full loop: declare variables on a composition, iterate locally with `hanzo frame render`, deploy to Lambda once, then fan out N renders from a batch file. The same flow also drives single personalised renders via `lambda render --variables` and programmatic batches via `renderToLambda({ variables })`.
This guide walks the full loop: declare variables on a composition, iterate locally with `frames render`, deploy to Lambda once, then fan out N renders from a batch file. The same flow also drives single personalised renders via `lambda render --variables` and programmatic batches via `renderToLambda({ variables })`.
```mermaid
flowchart LR
A["Local iteration<br/>hanzo frame render --variables"] --> B["Deploy stack<br/>hanzo frame lambda deploy"]
B --> C["Upload site once<br/>hanzo frame lambda sites create"]
C --> D["Fan out renders<br/>hanzo frame lambda render-batch"]
A["Local iteration<br/>frames render --variables"] --> B["Deploy stack<br/>frames lambda deploy"]
B --> C["Upload site once<br/>frames lambda sites create"]
C --> D["Fan out renders<br/>frames lambda render-batch"]
D --> E["N personalised videos<br/>in S3"]
```
@@ -82,26 +82,26 @@ The runtime won't accept declaration `type: "object"` — the parser rejects any
## Local iteration loop
Fast iteration is the whole point of templates — you should not have to deploy to Lambda to see how a value looks. Use `hanzo frame render` locally with `--variables` (or `--variables-file`) to render the template against any payload:
Fast iteration is the whole point of templates — you should not have to deploy to Lambda to see how a value looks. Use `frames render` locally with `--variables` (or `--variables-file`) to render the template against any payload:
```bash
hanzo frame render --variables '{"title":"Hello Alice","accentColor":"#ff0000"}' \
frames render --variables '{"title":"Hello Alice","accentColor":"#ff0000"}' \
--output renders/alice-preview.mp4
```
Pass `--strict-variables` to fail on type mismatches against the `data-composition-variables` declaration. Without the flag, mismatches print as warnings and the render continues.
```bash
hanzo frame render --variables-file ./alice.json --strict-variables \
frames render --variables-file ./alice.json --strict-variables \
--output renders/alice-preview.mp4
```
## Deploying to Lambda
Templates render on the standard `hanzo frame lambda` stack — there's no special template-only deployment. Run:
Templates render on the standard `frames lambda` stack — there's no special template-only deployment. Run:
```bash
hanzo frame lambda deploy
frames lambda deploy
```
once per AWS account/region. The [aws-lambda deploy guide](/deploy/aws-lambda) covers the SAM stack, IAM policies, and the CloudFormation outputs.
@@ -109,7 +109,7 @@ once per AWS account/region. The [aws-lambda deploy guide](/deploy/aws-lambda) c
When the same template will produce many renders, upload the project once with `lambda sites create` and reference its content-addressed `siteId` from every subsequent render or batch:
```bash
hanzo frame lambda sites create ./my-template
frames lambda sites create ./my-template
# → Site ID: abc1234deadbeef0
```
@@ -118,7 +118,7 @@ hanzo frame lambda sites create ./my-template
For one-off renders, pass `--site-id` + per-render `--variables`. The CLI synthesises the minimal site handle from the `siteId` (no re-tarring) and invokes `renderToLambda`:
```bash
hanzo frame lambda render ./my-template \
frames lambda render ./my-template \
--site-id abc1234deadbeef0 \
--width 1920 --height 1080 \
--variables '{"title":"Hello Alice","accentColor":"#ff0000"}' \
@@ -126,7 +126,7 @@ hanzo frame lambda render ./my-template \
--wait
```
`--wait` streams progress lines until the render finishes; without it the CLI returns immediately and you poll via `hanzo frame lambda progress <renderId>`.
`--wait` streams progress lines until the render finishes; without it the CLI returns immediately and you poll via `frames lambda progress <renderId>`.
## Batch pipeline (the headline)
@@ -143,7 +143,7 @@ hanzo frame lambda render ./my-template \
Run the batch:
```bash
hanzo frame lambda render-batch ./my-template \
frames lambda render-batch ./my-template \
--batch ./users.jsonl \
--width 1920 --height 1080 \
--max-concurrent 5
@@ -166,7 +166,7 @@ Batch dispatched: 5 started, 0 failed-to-start.
Add `--json` for the machine-readable form your batch coordinator can pipe to `jq`:
```bash
hanzo frame lambda render-batch ./my-template --batch ./users.jsonl \
frames lambda render-batch ./my-template --batch ./users.jsonl \
--width 1920 --height 1080 --json \
| jq -r '.[] | select(.status == "started") | .executionArn'
```
@@ -174,13 +174,13 @@ hanzo frame lambda render-batch ./my-template --batch ./users.jsonl \
Poll each `executionArn` (or `renderId`) with `lambda progress` to track completions:
```bash
hanzo frame lambda progress arn:aws:states:us-east-1:1234:execution:hf:hf-render-abcd
frames lambda progress arn:aws:states:us-east-1:1234:execution:hf:hf-render-abcd
```
Use `--dry-run` to lint a batch file before paying for any executions. Every entry's status becomes `would-invoke`:
```bash
hanzo frame lambda render-batch ./my-template --batch ./users.jsonl \
frames lambda render-batch ./my-template --batch ./users.jsonl \
--width 1920 --height 1080 --dry-run --json
```
@@ -223,7 +223,7 @@ const handles = await Promise.all(
console.log(`Started ${handles.length} renders`);
```
`FRAMES_BUCKET` and `FRAMES_SFN_ARN` come from the deployed stack. `hanzo frame lambda deploy` prints them as `RenderBucketName` and `RenderStateMachineArn`, and they're also available via `aws cloudformation describe-stacks --query "Stacks[0].Outputs"`. See the [aws-lambda deploy guide](/deploy/aws-lambda) for the full CloudFormation outputs table.
`FRAMES_BUCKET` and `FRAMES_SFN_ARN` come from the deployed stack. `frames lambda deploy` prints them as `RenderBucketName` and `RenderStateMachineArn`, and they're also available via `aws cloudformation describe-stacks --query "Stacks[0].Outputs"`. See the [aws-lambda deploy guide](/deploy/aws-lambda) for the full CloudFormation outputs table.
Wrap the `Promise.all` in a semaphore (or use the CLI's `runWithConcurrencyLimit` pattern) when the batch is large enough that an unbounded burst would trip your AWS Lambda concurrent-execution quota.
@@ -295,7 +295,7 @@ Each Step Functions execution fans out to ~`maxParallelChunks` Lambda invocation
For small batches (< 100 entries) the default `--max-concurrent 50` is fine. For large batches (> 1 000), a useful starting point is `--max-concurrent ≈ floor(reservedConcurrency / maxParallelChunks)` so each running render gets its full chunk fan-out budget; the batch verb does NOT enforce this, it's just guidance for picking the flag value.
In-process vs distributed crossover: for a single render under ~30 seconds, the in-process renderer (`hanzo frame render`) wins on latency because there's no S3 round-trip per chunk. Distributed wins for renders over ~60 seconds or when you need a personalised batch — that's the whole reason this surface exists. (The Phase 7 small-render shortcut, when it lands, will collapse the gap for short renders.)
In-process vs distributed crossover: for a single render under ~30 seconds, the in-process renderer (`frames render`) wins on latency because there's no S3 round-trip per chunk. Distributed wins for renders over ~60 seconds or when you need a personalised batch — that's the whole reason this surface exists. (The Phase 7 small-render shortcut, when it lands, will collapse the gap for short renders.)
## Migrating from @remotion/lambda inputProps
@@ -314,7 +314,7 @@ Remotion's `inputProps` has the same 256 KiB constraint and the same "URL your a
## What's next
- **Smaller batch primitives**: HTML-form input alongside JSONL. Open an issue if you'd find this useful.
- **TypeScript types generated from `data-composition-variables`**: `hanzo frame types generate <projectDir>` is sketched and may land in v1.5; it would let SDK callers `import type { Variables } from "./template/variables"` for autocomplete + typecheck.
- **TypeScript types generated from `data-composition-variables`**: `frames types generate <projectDir>` is sketched and may land in v1.5; it would let SDK callers `import type { Variables } from "./template/variables"` for autocomplete + typecheck.
- **HDR template support**: HDR mp4 is currently distributed-mode-rejected (in-process only). The next v1.5 item is unblocking HDR for distributed renders so templates can produce wide-gamut output.
If your template pipeline hits a wall the docs don't cover, [file an issue on GitHub](https://github.com/hanzoai/frames/issues/new) — the batch surface is new and the feedback loop on it is short.
+4 -4
View File
@@ -112,10 +112,10 @@ Supersampling re-renders the page at higher DPR. That genuinely helps anything t
```bash
# OK — both landscape
hanzo frame render --resolution 4k # composition is 1920×1080
frames render --resolution 4k # composition is 1920×1080
# Error — composition is landscape, target is portrait
hanzo frame render --resolution portrait-4k # composition is 1920×1080
frames render --resolution portrait-4k # composition is 1920×1080
# → outputResolution portrait-4k (2160×3840) does not match the aspect ratio
# of the composition (1920×1080). Pick a preset whose orientation matches.
```
@@ -157,8 +157,8 @@ The resolution applies per render, not per project — your composition files ar
You can also drive resolution from the CLI:
- **New project**: `hanzo frame init my-video --resolution 4k`
- **Existing project**: `hanzo frame render --resolution 4k --output 4k.mp4`
- **New project**: `frames init my-video --resolution 4k`
- **Existing project**: `frames render --resolution 4k --output 4k.mp4`
## See also
+1 -1
View File
@@ -78,6 +78,6 @@ caches.
| `HANZO_BASE_URL` | API base URL (default `https://api.hanzo.ai`). Point it at a local Hanzo Engine to run the same code offline. |
| `OPENROUTER_API_KEY` | Capture descriptions during [website capture](/guides/website-to-video). |
See the [`hanzo frame auth`](/packages/cli#frames-auth) command reference for
See the [`frames auth`](/packages/cli#frames-auth) command reference for
subcommand details, and [Cloud rendering](/deploy/cloud) for using the same
token to render in the cloud.
+2 -2
View File
@@ -103,7 +103,7 @@ All three templates follow the same flow: the browser plays a preview locally, t
```
Browser Edge / Function Sandboxed renderer
┌──────────────────┐ ┌────────────────────┐ ┌──────────────────────────┐
│ <frames- │ ────▶ │ /api/render │ ────▶ │ hanzo frame render │
│ <frames- │ ────▶ │ /api/render │ ────▶ │ frames render │
│ player> │ │ ship composition │ │ (Chromium + FFmpeg, │
│ preview iframe │ │ → renderer │ │ pre-installed) │
│ │ ◀──── │ ← stream MP4 │ ◀──── │ │
@@ -157,7 +157,7 @@ Templates are optimized for **a single render endpoint behind a preview UI**. Th
- A **render queue** with retries, deduplication, or priorities — start from a template, then add your own queue (e.g. Vercel Queues, Cloudflare Queues, SQS).
- **Multi-tenant rendering** with per-user composition uploads — start from a template, replace the bundled composition with a runtime-fetched one.
- **Self-hosted** rendering — see the [Rendering guide](/guides/rendering) and run `hanzo frame render --docker` on your own infrastructure.
- **Self-hosted** rendering — see the [Rendering guide](/guides/rendering) and run `frames render --docker` on your own infrastructure.
For everything else, the templates are the recommended starting point.
+17 -17
View File
@@ -15,7 +15,7 @@ No account, email, or identity is tied to responses. Each installation generates
### CLI — post-render prompt
After a successful `hanzo frame render`, a short prompt may appear:
After a successful `frames render`, a short prompt may appear:
```
How likely are you to recommend Frames? [0=not likely 10=extremely likely, enter to skip]
@@ -35,7 +35,7 @@ The render interval is configurable:
```bash
# Show prompt every 5 renders instead of 15 (useful for testing)
FRAMES_FEEDBACK_INTERVAL=5 hanzo frame render --output out.mp4
FRAMES_FEEDBACK_INTERVAL=5 frames render --output out.mp4
```
### Studio — session feedback bar
@@ -56,18 +56,18 @@ VITE_FRAMES_FEEDBACK_INTERVAL=3
Invalid values (non-integer, zero, negative) fall back to the default.
**Note:** Disabling CLI telemetry (`hanzo frame telemetry disable`) does not suppress the Studio bar — Studio feedback is gated separately. The submitted data is still sent through the same anonymous PostHog pipeline, so the same privacy guarantees apply.
**Note:** Disabling CLI telemetry (`frames telemetry disable`) does not suppress the Studio bar — Studio feedback is gated separately. The submitted data is still sent through the same anonymous PostHog pipeline, so the same privacy guarantees apply.
### `hanzo frame feedback` command
### `frames feedback` command
You can submit feedback manually at any time:
```bash
# Quick rating
hanzo frame feedback --rating 10
frames feedback --rating 10
# Rating with details
hanzo frame feedback --rating 7 --comment "render succeeded but GSAP timeline didn't animate text overlay"
frames feedback --rating 7 --comment "render succeeded but GSAP timeline didn't animate text overlay"
```
| Flag | Description |
@@ -85,13 +85,13 @@ This command collects a doctor summary automatically, flushes telemetry, and exi
When a render misbehaves, add `--file-issue` so maintainers can reproduce it:
```bash
hanzo frame feedback --rating 3 --comment "GSAP timeline froze on seek" --file-issue
frames feedback --rating 3 --comment "GSAP timeline froze on seek" --file-issue
```
This is **opt-in** and **consented**. With `--file-issue` set, after the usual feedback is sent the CLI:
1. Asks you to confirm (interactive) or requires `--yes` in non-interactive shells, because it will **publicly publish** the project at `--dir`.
2. Publishes a minimal repro of the project and gets a public URL (the same upload as `hanzo frame publish`).
2. Publishes a minimal repro of the project and gets a public URL (the same upload as `frames publish`).
3. Opens your browser with a **pre-filled** GitHub issue draft, labelled `bug`, containing the rating, your comment, the public repro link, and the environment summary. It also prints the URL so you can copy it if no browser opens.
The issue is **not auto-submitted**: you review and file it under your own GitHub account. There is no token, backend, or `gh` invocation; if publishing fails the issue still opens, just without a repro link.
@@ -101,10 +101,10 @@ The issue is **not auto-submitted**: you review and file it under your own GitHu
When an AI agent is detected, Frames **skips the interactive readline prompt** and prints a structured hint instead:
```
[frames] Agent feedback: hanzo frame feedback --rating <0-10> --comment "..."
[frames] Agent feedback: frames feedback --rating <0-10> --comment "..."
```
Agents can then submit feedback using the `hanzo frame feedback` command above.
Agents can then submit feedback using the `frames feedback` command above.
The same cadence gate applies: the hint only appears on the first render, then every 15th.
@@ -137,7 +137,7 @@ Event: `cli_render_feedback`
| `render_duration_ms` | Time the render took in milliseconds |
| `doctor_summary` | System context (see below) |
The `doctor_summary` is a compact string with environment context — included automatically so you don't need to run `hanzo frame doctor` when reporting a problem:
The `doctor_summary` is a compact string with environment context — included automatically so you don't need to run `frames doctor` when reporting a problem:
```
os=darwin/arm64 node=v22.11.0 cpu=10cores mem=32GB ffmpeg=yes
@@ -203,22 +203,22 @@ Disabling telemetry suppresses the CLI feedback prompt and all other CLI usage t
```bash
# Via CLI command (persisted to ~/.frames/config.json)
hanzo frame telemetry disable
frames telemetry disable
# Or via environment variable (per-session)
FRAMES_NO_TELEMETRY=1 hanzo frame render --output out.mp4
FRAMES_NO_TELEMETRY=1 frames render --output out.mp4
# Or via DO_NOT_TRACK (respects the global standard)
DO_NOT_TRACK=1 hanzo frame render --output out.mp4
DO_NOT_TRACK=1 frames render --output out.mp4
```
Once disabled, the `hanzo frame feedback` command will print `Telemetry is disabled. Feedback not sent.` and exit without sending anything.
Once disabled, the `frames feedback` command will print `Telemetry is disabled. Feedback not sent.` and exit without sending anything.
### CLI — suppress output without disabling telemetry
```bash
# Quiet mode: renders without any post-render output (including the feedback prompt)
hanzo frame render --quiet --output out.mp4
frames render --quiet --output out.mp4
```
### CI environments
@@ -244,5 +244,5 @@ VITE_FRAMES_FEEDBACK_INTERVAL=20
## Related
- [Telemetry](/packages/cli#telemetry) — full telemetry settings and what usage data is collected
- [`hanzo frame feedback`](/packages/cli#feedback) — CLI command reference
- [`frames feedback`](/packages/cli#feedback) — CLI command reference
- [Troubleshooting](/guides/troubleshooting) — if a prompt is blocking your pipeline unexpectedly
+7 -7
View File
@@ -9,9 +9,9 @@ The work your designer already did in Figma — layout, color, type, motion —
| Capability | What you get | Surface |
| --- | --- | --- |
| **Static assets** | A frame/layer rendered to SVG/PNG/JPG/PDF, frozen under `.media/` | `hanzo frame figma asset` |
| **Brand tokens** | Figma variables/styles as composition brand variables | `hanzo frame figma tokens` (Enterprise) or the `/figma` skill via MCP (any plan) |
| **Components** | A frame as editable HTML with brand-linked colors | `hanzo frame figma component` |
| **Static assets** | A frame/layer rendered to SVG/PNG/JPG/PDF, frozen under `.media/` | `frames figma asset` |
| **Brand tokens** | Figma variables/styles as composition brand variables | `frames figma tokens` (Enterprise) or the `/figma` skill via MCP (any plan) |
| **Components** | A frame as editable HTML with brand-linked colors | `frames figma component` |
| **Motion** | A Figma Motion timeline as an editable, paused GSAP timeline | `/figma` skill (agent, MCP) |
| **Shaders** | A shader fill/effect as a frozen still or clip | `/figma` skill (agent, MCP) |
| **Storyboards** | Scene frames reconstructed as motion — frames read as states, not slides | `/figma` skill (agent) |
@@ -32,7 +32,7 @@ Do both if your project needs everything; each is independent, so it doesn't mat
### Step A — Figma token (assets, tokens, components)
Needed for anything you run from the `hanzo frame figma` CLI.
Needed for anything you run from the `frames figma` CLI.
<Steps>
<Step title="Mint a token">
@@ -65,7 +65,7 @@ This is also the easiest way to pull brand colors on **any** Figma plan, includi
## Import an asset
```bash
hanzo frame figma asset 'https://www.figma.com/design/KEY/Title?node-id=1-2'
frames figma asset 'https://www.figma.com/design/KEY/Title?node-id=1-2'
```
The node renders over REST, lands frozen under `.media/images/`, and the command prints a ready-to-paste `<img>` snippet:
@@ -82,7 +82,7 @@ imported image_007 → .media/images/image_007.svg
## Pull your brand
```bash
hanzo frame figma tokens KEY
frames figma tokens KEY
```
Reads the file's variables (or published styles), writes a `figma-tokens.json` sidecar plus a binding index, and prints entries for the composition's `data-composition-variables`. Every scene that references a brand role — instead of a hard-coded hex — is on-brand automatically, and stays on-brand when the file changes.
@@ -94,7 +94,7 @@ Import tokens **before** components. That's what lets an imported component's co
## Import a component
```bash
hanzo frame figma component 'https://www.figma.com/design/KEY/Title?node-id=10-20'
frames figma component 'https://www.figma.com/design/KEY/Title?node-id=10-20'
```
The frame's node tree becomes editable HTML at exact Figma geometry, packaged under `compositions/components/<name>/`. Vector and boolean-op nodes that don't map to clean HTML auto-rasterize through the asset path.
+1 -1
View File
@@ -414,7 +414,7 @@ as the canonical reference and follow its patterns verbatim:
- HDR / wide-gamut color handling
- Audio-reactive animation (`hf-seek` + `window.__hfAudio`)
- Captions / TTS integration
- The `hanzo frame add` registry (50+ blocks and components)
- The `frames add` registry (50+ blocks and components)
This skill stays focused on what Open Design needs at emission time — the
structural rules, the active-`DESIGN.md` binding, and the 5-dim self-critique
+1 -1
View File
@@ -25,7 +25,7 @@ The installer shows a picker. Select the **core skills** below — every project
| `/frames-creative` | Creative direction — design spec, palettes, typography, narration, beats |
| `/frames-cli` | Dev-loop CLI — `init`, `lint`, `validate`, `inspect`, `preview`, `render`, `doctor` |
| `/media-use` | Asset preprocessing — `tts`, `transcribe`, `remove-background` |
| `/frames-registry` | Block and component installation via `hanzo frame add` |
| `/frames-registry` | Block and component installation via `frames add` |
| `/general-video` | The general authoring workflow — fallback for any video that doesn't match a specific workflow below |
**Optional workflows — add the ones that match your inputs** (`/frames` routes to whichever you've installed)
+3 -3
View File
@@ -49,7 +49,7 @@ The CLI ships a built-in `remove-background` command that runs locally — no AP
</div>
```
Render the composition with the usual `hanzo frame render`.
Render the composition with the usual `frames render`.
</Step>
</Steps>
@@ -355,7 +355,7 @@ ffmpeg -i frames-%04d.png -c:v libvpx-vp9 \
### How to choose
- **Person / portrait video, web playback, MIT-clean** → use the built-in `hanzo frame remove-background` (this is what it's tuned for).
- **Person / portrait video, web playback, MIT-clean** → use the built-in `frames remove-background` (this is what it's tuned for).
- **Non-human subject** (product, animal, object) → `rembg` with `isnet-general-use`.
- **Maximum portrait quality, especially hair** → `BiRefNet` via Python.
- **Long video where edge flicker would be visible**, GPL is OK → `RVM`.
@@ -418,7 +418,7 @@ That usually means the source frame is high-contrast against a similar-toned bac
## Reference
- CLI: [`hanzo frame remove-background`](/packages/cli#remove-background)
- CLI: [`frames remove-background`](/packages/cli#remove-background)
- Eval: matting comparison v7, u²-net_human_seg on a 4-second 1080p clip
- Source model: [danielgatis/rembg](https://github.com/danielgatis/rembg)
- ONNX runtime: [`onnxruntime-node`](https://www.npmjs.com/package/onnxruntime-node)
+1 -1
View File
@@ -168,7 +168,7 @@ Video assets referenced by a composition (a `<video src="...">` clip) are decode
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. Preview handles this automatically: on first use, it transcodes the asset into a cached H.264 proxy (stored under `.transcode-cache/`, safe to delete) and serves that for playback, while render always uses the original file. `check` and `snapshot` prepare the same proxies before opening their browser phase. Publishing bakes the proxies into the published archive so static player pages work too. Opt out per command with `--no-proxy`, or project-wide by setting `media.autoProxy` to `false` in `frames.json`.
`hanzo frame lint` emits an info-level `hevc_preview_codec` note when a composition references an HEVC video, naming the affected asset(s).
`frames lint` emits an info-level `hevc_preview_codec` note when a composition references an HEVC video, naming the affected asset(s).
## Animated GIF
+2 -2
View File
@@ -102,11 +102,11 @@ Atomic capabilities the creation workflows compose against — pull one when you
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `/frames-core` | The composition contract — `data-*` timing attributes, `class="clip"`, tracks, sub-compositions, variables, framework-owned media playback, determinism rules. |
| `/frames-animation` | All animation knowledge — atomic motion rules, scene blueprints, transitions, runtime adapters (GSAP / Lottie / Three.js / Anime.js / CSS / WAAPI / TypeGPU). |
| `/frames-keyframes` | Seek-safe keyframe authoring across runtimes — GSAP timelines, CSS keyframes, Anime.js, WAAPI, FLIP, paths, masks, SVG morph/draw, 3D depth — plus `hanzo frame keyframes` diagnostics for rendered motion. |
| `/frames-keyframes` | Seek-safe keyframe authoring across runtimes — GSAP timelines, CSS keyframes, Anime.js, WAAPI, FLIP, paths, masks, SVG morph/draw, 3D depth — plus `frames keyframes` diagnostics for rendered motion. |
| `/frames-creative` | Non-animation creative direction — `frame.md` / `design.md`, palettes, typography, narration, beat planning, audio-reactive visuals, composition patterns. |
| `/media-use` | The media OS — resolve any media need (BGM, SFX, image, icon, logo, voice, color grade, LUT) into a frozen local file or paste-ready block + ledger record, generate via TTS/music/image models when the catalog misses, transcribe, caption, remove backgrounds, and reuse assets across projects. One shared audio engine + manifest tracking. |
| `/frames-cli` | CLI dev loop — `init`, `lint`, `check`, `snapshot`, `preview`, `render`, `publish`, `doctor`, plus hosted cloud rendering (`cloud render / list / get / delete`) and AWS Lambda rendering (`lambda deploy / render / progress / destroy / policies`). |
| `/frames-registry` | Install and wire registry blocks and components into compositions via `hanzo frame add`. Authoring a new block or component to contribute upstream. |
| `/frames-registry` | Install and wire registry blocks and components into compositions via `frames add`. Authoring a new block or component to contribute upstream. |
| `/figma` | Import Figma assets, tokens, components, and storyboard sections → reconstructed motion (frames read as states, not slides) (REST/CLI) plus Motion animations (MCP) and shaders (MCP source / native export) into a composition. |
## Source of truth
+1 -1
View File
@@ -92,7 +92,7 @@ The catalog ships two kinds of item, installed the same way but wired differentl
Your agent already knows how to build video components — it writes HTML, Frames renders it. The registry is where that work ships to **every** Frames user. Spotted a caption style on TikTok that doesn't exist yet, or built a transition worth sharing? Add it to the catalog.
<Info>
**Quick version** — Fork the repo. Write one HTML file with a paused GSAP timeline. Add `registry-item.json`. Run `hanzo frame lint` + `validate`. Publish with `npx @hanzo/frame publish`. Open a PR.
**Quick version** — Fork the repo. Write one HTML file with a paused GSAP timeline. Add `registry-item.json`. Run `frames lint` + `validate`. Publish with `npx @hanzo/frame publish`. Open a PR.
</Info>
Every item is a single self-contained HTML file with a paused GSAP timeline — no build step, no framework. It must be deterministic (seeded randomness only, no `Date.now()` / `Math.random()`), register its timeline on `window.__timelines`, and meet the production-quality bar.
+2 -2
View File
@@ -33,7 +33,7 @@ These aren't toy examples. They're the same compositions we ship in public launc
- **Multi-composition projects.** Most launches are 4-8 sub-compositions wired into one root timeline — useful when your `npx @hanzo/frame init --example` starter outgrows a single file.
- **Real adapter mix.** GSAP timelines, Lottie animations, custom shaders, Three.js scenes, and CSS keyframes all coexisting in one render. See how the team [boots multiple adapters](/guides/gsap-animation) inside a single composition.
- **Production-grade timing.** Voiceover + per-beat SFX + underscore mixed against frame-accurate motion. The storyboards describe the timing decisions; the source shows them executed.
- **No proprietary plugins.** Everything renders with the same `hanzo frame render` you have locally — there's no internal-only branch of the engine.
- **No proprietary plugins.** Everything renders with the same `frames render` you have locally — there's no internal-only branch of the engine.
## Cloning
@@ -44,7 +44,7 @@ brew install git-lfs # macOS — or your platform's git-lfs install
git lfs install
git clone https://github.com/hanzoai/frames-launches.git
cd frames-launches/frames-launch
hanzo frame preview # opens the studio for that launch
frames preview # opens the studio for that launch
```
To clone just the source (skip large LFS assets and pull on demand):
+65 -65
View File
@@ -220,7 +220,7 @@ This is suppressed in CI environments, non-TTY shells, and when `FRAMES_NO_UPDAT
Output for a block or component is a set of files plus a **paste snippet** — the `<iframe>` tag (for blocks) or the fragment path (for components) to include in your host composition. The snippet is copied to the clipboard by default; add `--no-clipboard` for CI or headless environments.
Trying `add` with an example's name (e.g. `hanzo frame add warm-grain`) emits a clear error pointing you at `init --example`.
Trying `add` with an example's name (e.g. `frames add warm-grain`) emits a clear error pointing you at `init --example`.
### `catalog`
@@ -299,7 +299,7 @@ This is suppressed in CI environments, non-TTY shells, and when `FRAMES_NO_UPDAT
| Format | Source |
|--------|--------|
| whisper.cpp JSON | `hanzo frame init --video`, `hanzo frame transcribe` |
| whisper.cpp JSON | `frames init --video`, `frames transcribe` |
| OpenAI Whisper API JSON | `openai.audio.transcriptions.create()` with word timestamps |
| SRT subtitles | Video editors, YouTube, subtitle tools |
| VTT subtitles | Web players, YouTube, transcription services |
@@ -723,7 +723,7 @@ Word-level transcripts (whisper output) are grouped into readable caption cues o
| `--strict-variables` | — | off | Fail render if any `--variables` key is undeclared or has a wrong type vs the composition's `data-composition-variables`. Without this flag, mismatches print as warnings and the render continues. |
| `--browser-timeout` | seconds (0.001–86400) | 60 | Puppeteer page-navigation timeout for the entry HTML. Increase when heavy compositions (many videos, fonts, or asset requests) cannot reach `domcontentloaded` within the default 60 s. The flag takes **seconds**; the env fallback `PRODUCER_PAGE_NAVIGATION_TIMEOUT_MS` takes **milliseconds**. This controls `page.goto` only — very heavy compositions may also need `PRODUCER_PUPPETEER_PROTOCOL_TIMEOUT_MS` and/or `PRODUCER_PLAYER_READY_TIMEOUT_MS` bumped (post-navigation `window.__hf` readiness has its own 45 s budget). |
| `--protocol-timeout` | milliseconds (≥ 1000) | 300000 (5 min) | Puppeteer CDP protocol timeout — the per-call budget for `Runtime.callFunctionOn` seek/paint, `Page.captureScreenshot`, and other CDP round-trips. Raise on RAM-pressured hosts (≤ 8 GB), heavy-asset compositions (many videos + images), or when the render fails with `Runtime.callFunctionOn timed out` / `Target closed`. The default is auto-scaled per composition by output pixel area (a 4K comp bumps the ceiling proportionally, capped at 30 min); an explicit override sets the floor and disables scaling below it. Env fallback `PRODUCER_PUPPETEER_PROTOCOL_TIMEOUT_MS` (also **milliseconds**). |
| `--frames-cache-dir` | path or `off` / `none` / `false` / `0` | `<tmpdir>/frames-extract-cache-<uid>` | Directory for the content-addressed extracted-frame cache. Relocate it off the system drive when the OS temp directory lives on a small partition — long renders can accumulate multi-GB of frames, and on Windows `%TEMP%` defaults to `C:` (reporter `ts=1784219488`, CLI 0.7.58, 15 GB laptop: extract cache exhausted C: mid-render). Pass an opt-out alias (`off`, `none`, `false`, `0`) to disable caching entirely; frames then extract into the render's `workDir` and are cleaned up when the render ends. Env fallback `FRAMES_EXTRACT_CACHE_DIR`. `hanzo frame doctor` reports the effective directory + free space at that location. |
| `--frames-cache-dir` | path or `off` / `none` / `false` / `0` | `<tmpdir>/frames-extract-cache-<uid>` | Directory for the content-addressed extracted-frame cache. Relocate it off the system drive when the OS temp directory lives on a small partition — long renders can accumulate multi-GB of frames, and on Windows `%TEMP%` defaults to `C:` (reporter `ts=1784219488`, CLI 0.7.58, 15 GB laptop: extract cache exhausted C: mid-render). Pass an opt-out alias (`off`, `none`, `false`, `0`) to disable caching entirely; frames then extract into the render's `workDir` and are cleaned up when the render ends. Env fallback `FRAMES_EXTRACT_CACHE_DIR`. `frames doctor` reports the effective directory + free space at that location. |
CRF and target bitrate default to the `--quality` preset. Use `--crf` or `--video-bitrate` for fine-grained overrides; `RenderConfig.crf` and `RenderConfig.videoBitrate` accept the same overrides programmatically. Use `--video-frame-format png` when source videos are UI recordings, screen captures, or other color-sensitive clips that should avoid JPEG frame extraction.
@@ -855,7 +855,7 @@ Word-level transcripts (whisper output) are grouped into readable caption cues o
npx @hanzo/frame doctor
```
```
hanzo frame doctor
frames doctor
✓ Version 0.1.4 (latest)
✓ Node.js v22.x (linux x64)
@@ -874,10 +874,10 @@ Word-level transcripts (whisper output) are grouped into readable caption cues o
Verifies CLI version, Node.js, FFmpeg, FFprobe, Chrome, and Docker availability. If a newer CLI version is available, the version row shows an upgrade hint.
**CI gating.** `hanzo frame doctor --json` always exits 0 on successful execution — the command succeeded if it produced valid output. Whether the environment is healthy is carried in the `ok` field of the payload, so a new CLI release (which flips `Version.ok` to `false`) never breaks your pipeline. Pipe through `jq` to gate on the payload instead:
**CI gating.** `frames doctor --json` always exits 0 on successful execution — the command succeeded if it produced valid output. Whether the environment is healthy is carried in the `ok` field of the payload, so a new CLI release (which flips `Version.ok` to `false`) never breaks your pipeline. Pipe through `jq` to gate on the payload instead:
```bash
hanzo frame doctor --json | jq -e '.ok' > /dev/null || handle_failure
frames doctor --json | jq -e '.ok' > /dev/null || handle_failure
```
Paths in `detail` and `hint` are redacted in JSON mode — the user's home directory is replaced with the literal `$HOME` so output is safe to paste into bug reports and agent contexts.
@@ -1027,7 +1027,7 @@ Word-level transcripts (whisper output) are grouped into readable caption cues o
└ Installation failed
```
**Using `hanzo frame skills` is already fine** — as of v0.4.5 the CLI sets `GIT_CLONE_PROTECTION_ACTIVE=0` on the child environment, which is the opt-in knob Git provides for exactly this case. You don't need to do anything.
**Using `frames skills` is already fine** — as of v0.4.5 the CLI sets `GIT_CLONE_PROTECTION_ACTIVE=0` on the child environment, which is the opt-in knob Git provides for exactly this case. You don't need to do anything.
**If you ran `npx skills add hanzoai/frames` directly** (bypassing the Frames CLI), set the env var yourself:
@@ -1039,7 +1039,7 @@ Word-level transcripts (whisper output) are grouped into readable caption cues o
</Tab>
</Tabs>
## hanzo frame auth
## frames auth
Inspect the Hanzo credential the CLI is using. The credential is a Hanzo IAM
token in `HANZO_API_KEY`, read from [Hanzo KMS](https://kms.hanzo.ai) — there is
@@ -1054,8 +1054,8 @@ Exits non-zero when nothing is configured or the API rejects the credential, so
scripts can check state.
```bash
hanzo frame auth status
hanzo frame auth status --json # machine-readable
frames auth status
frames auth status --json # machine-readable
```
### Environment variables
@@ -1069,15 +1069,15 @@ hanzo frame auth status --json # machine-readable
The same token covers voice, music, sound effects, images, video, the shared
media catalog, and cloud rendering — see [Authentication](/guides/authentication).
## hanzo frame cloud
## frames cloud
Render a Frames composition on Hanzo Cloud — no local Chrome, no local ffmpeg, no AWS to manage. The same `HANZO_API_KEY` drives every `cloud` subcommand.
```bash
hanzo frame auth login # one-time
hanzo frame cloud render ./my-video # zip + upload + poll + download
hanzo frame cloud render ./my-video --no-wait # submit and exit with the render_id
hanzo frame cloud list # browse recent renders
frames auth login # one-time
frames cloud render ./my-video # zip + upload + poll + download
frames cloud render ./my-video --no-wait # submit and exit with the render_id
frames cloud list # browse recent renders
```
### Subcommands
@@ -1086,9 +1086,9 @@ hanzo frame cloud list # browse recent renders
End-to-end render: zips the project (excluding root `renders`/`snapshots`, `.git`, `node_modules`, `dist`, `.next`, `coverage`, dotfiles, and project `.framesignore` rules), uploads it through the direct-to-S3 asset flow, submits `POST /v3/frames/renders`, polls `GET /v3/frames/renders/{id}` until the render completes or fails, and streams the resulting video to disk.
Use `hanzo frame cloud render --dry-run` to inspect the compressed size and largest included files without authenticating, uploading, or starting a render. Project-specific `.framesignore` rules use gitignore syntax and also apply to `hanzo frame publish`; keep rules narrow because dynamically selected assets may not have obvious static references.
Use `frames cloud render --dry-run` to inspect the compressed size and largest included files without authenticating, uploading, or starting a render. Project-specific `.framesignore` rules use gitignore syntax and also apply to `frames publish`; keep rules narrow because dynamically selected assets may not have obvious static references.
Render parameters mirror the local `hanzo frame render` UX where they overlap:
Render parameters mirror the local `frames render` UX where they overlap:
| Flag | Default | Meaning |
| --- | --- | --- |
@@ -1121,24 +1121,24 @@ Lifecycle / control flags:
```bash
# Default flow — render the current directory.
hanzo frame cloud render
frames cloud render
# Pick a composition + output path.
hanzo frame cloud render . \
frames cloud render . \
--composition compositions/intro.html \
--output ./renders/intro.mp4
# Higher quality at 60fps.
hanzo frame cloud render --quality high --fps 60
frames cloud render --quality high --fps 60
# Fire-and-forget with a webhook (no local polling).
hanzo frame cloud render --callback-url https://example.com/hf-hook --no-wait
frames cloud render --callback-url https://example.com/hf-hook --no-wait
# Re-render an already-uploaded composition (skips zip + upload).
hanzo frame cloud render --asset-id asst_abc123
frames cloud render --asset-id asst_abc123
# Render from a public URL (no upload).
hanzo frame cloud render --url https://cdn.example.com/site.zip
frames cloud render --url https://cdn.example.com/site.zip
```
##### Safe retries via `--idempotency-key`
@@ -1148,7 +1148,7 @@ The CLI transparently retries on a `401 Unauthorized` by force-refreshing the OA
Pass `--idempotency-key <key>` whenever you want safe retries on `cloud render`. The key is forwarded to both the upload and submit calls; the server scopes idempotency per-endpoint, so reusing the same value across the two steps is safe and prevents duplicates on either step. Use a UUID per logical render, or any opaque string in `[A-Za-z0-9_:.-]` (1-255 chars).
```bash
hanzo frame cloud render . --idempotency-key "$(uuidgen)"
frames cloud render . --idempotency-key "$(uuidgen)"
```
#### `cloud list`
@@ -1156,9 +1156,9 @@ hanzo frame cloud render . --idempotency-key "$(uuidgen)"
Pages through recent renders. Cursor-based: `--limit` caps a single page (1-100), `--token` resumes from a previous `next_token`, `--all` walks the full list until exhausted.
```bash
hanzo frame cloud list
hanzo frame cloud list --limit 50 --json
hanzo frame cloud list --all
frames cloud list
frames cloud list --limit 50 --json
frames cloud list --all
```
#### `cloud get <render_id>`
@@ -1166,8 +1166,8 @@ hanzo frame cloud list --all
Fetches the full detail record for one render, including the short-lived signed `video_url` and `thumbnail_url` (presigned S3 URLs — re-fetch on demand rather than cache).
```bash
hanzo frame cloud get hfr_abc123
hanzo frame cloud get hfr_abc123 --json
frames cloud get hfr_abc123
frames cloud get hfr_abc123 --json
```
#### `cloud delete <render_id>`
@@ -1175,30 +1175,30 @@ hanzo frame cloud get hfr_abc123 --json
Soft-deletes a render. Subsequent `GET` calls return 404 and the signed video URL stops working shortly after. Prompts for confirmation interactively; pass `--no-confirm` to bypass for scripts.
```bash
hanzo frame cloud delete hfr_abc123
hanzo frame cloud delete hfr_abc123 --no-confirm --json
frames cloud delete hfr_abc123
frames cloud delete hfr_abc123 --no-confirm --json
```
### When to pick `cloud` vs `lambda` vs local render
- `hanzo frame render` (local): fastest iteration loop. Use during composition authoring.
- `hanzo frame lambda render`: bring-your-own-AWS distributed rendering. Use when you've already invested in AWS and want chunked parallelism on your own account.
- `hanzo frame cloud render`: zero-infra option. Hanzo Cloud runs the render, metered against the org's balance. Use when you don't want to manage Chrome/ffmpeg/AWS locally.
- `frames render` (local): fastest iteration loop. Use during composition authoring.
- `frames lambda render`: bring-your-own-AWS distributed rendering. Use when you've already invested in AWS and want chunked parallelism on your own account.
- `frames cloud render`: zero-infra option. Hanzo Cloud runs the render, metered against the org's balance. Use when you don't want to manage Chrome/ffmpeg/AWS locally.
### Auth + base URL
`cloud` reuses the credential resolved by `hanzo frame auth status`. Override the API base for staging tests with `HANZO_BASE_URL` (default `https://api.hanzo.ai`).
`cloud` reuses the credential resolved by `frames auth status`. Override the API base for staging tests with `HANZO_BASE_URL` (default `https://api.hanzo.ai`).
## hanzo frame lambda
## frames lambda
Deploy Frames distributed rendering to AWS Lambda and drive renders from your laptop or CI.
The `hanzo frame lambda` command group wraps the `@frames/aws-lambda` SDK plus AWS SAM so an end-to-end render is three commands:
The `frames lambda` command group wraps the `@frames/aws-lambda` SDK plus AWS SAM so an end-to-end render is three commands:
```bash
hanzo frame lambda deploy
hanzo frame lambda render ./my-project --width 1920 --height 1080 --wait
hanzo frame lambda destroy # when you're done
frames lambda deploy
frames lambda render ./my-project --width 1920 --height 1080 --wait
frames lambda destroy # when you're done
```
### Prerequisites
@@ -1214,7 +1214,7 @@ hanzo frame lambda destroy # when you're done
Builds `packages/aws-lambda/dist/handler.zip` and SAM-deploys the stack at `examples/aws-lambda/template.yaml`. On success, writes `<cwd>/.frames/lambda-stack-<stackName>.json` so the other subcommands don't need to re-derive the bucket / state-machine ARN.
```bash
hanzo frame lambda deploy \
frames lambda deploy \
--stack-name=frames-prod \
--region=us-east-1 \
--concurrency=8 \
@@ -1228,10 +1228,10 @@ Idempotent — re-running on the same `--stack-name` resolves to a no-op when no
Tars + uploads `<projectDir>` to S3 with a content-addressed key. Returns a `siteId` you can reuse across multiple renders so a re-render of the same tree skips the upload.
```bash
hanzo frame lambda sites create ./my-project
frames lambda sites create ./my-project
# → siteId: abc1234deadbeef0 (stable across re-runs of the same tree)
hanzo frame lambda render ./my-project --site-id=abc1234deadbeef0 --width 1920 --height 1080
frames lambda render ./my-project --site-id=abc1234deadbeef0 --width 1920 --height 1080
```
#### `lambda render <projectDir>`
@@ -1239,7 +1239,7 @@ hanzo frame lambda render ./my-project --site-id=abc1234deadbeef0 --width 1920 -
Starts a Step Functions execution. Returns immediately with a `renderId` (use `lambda progress` to poll) unless `--wait` is set, in which case the CLI blocks until the render finishes and streams per-chunk progress lines.
```bash
hanzo frame lambda render ./my-project \
frames lambda render ./my-project \
--width=1920 --height=1080 --fps=30 --format=mp4 \
--chunk-size=240 --max-parallel-chunks=16 \
--wait
@@ -1247,16 +1247,16 @@ hanzo frame lambda render ./my-project \
`--json` swaps the human-readable output for a machine-parseable JSON snapshot.
The composition can be parameterised with `--variables` / `--variables-file`, mirroring the local `hanzo frame render` flags. Variables flow into the Step Functions execution input and reach every chunk worker as `window.__hfVariables`. Mismatches against the composition's `data-composition-variables` declaration print as warnings; pass `--strict-variables` to fail the command instead.
The composition can be parameterised with `--variables` / `--variables-file`, mirroring the local `frames render` flags. Variables flow into the Step Functions execution input and reach every chunk worker as `window.__hfVariables`. Mismatches against the composition's `data-composition-variables` declaration print as warnings; pass `--strict-variables` to fail the command instead.
```bash
hanzo frame lambda render ./my-template --site-id=abc1234deadbeef0 \
frames lambda render ./my-template --site-id=abc1234deadbeef0 \
--width=1920 --height=1080 \
--variables '{"title":"Hello Alice","accent":"#ff0000"}'
```
```bash
hanzo frame lambda render ./my-template --site-id=abc1234deadbeef0 \
frames lambda render ./my-template --site-id=abc1234deadbeef0 \
--width=1920 --height=1080 \
--variables-file ./alice.json --strict-variables
```
@@ -1276,7 +1276,7 @@ Batch file format (JSONL — one JSON object per line):
```
```bash
hanzo frame lambda render-batch ./my-template \
frames lambda render-batch ./my-template \
--batch ./users.jsonl \
--width 1920 --height 1080 \
--max-concurrent 10
@@ -1292,12 +1292,12 @@ Batch dispatched: 3 started, 0 failed-to-start.
✓ line 3 renders/carol.mp4 arn:aws:states:us-east-1:1234:execution:hf:hf-carol-001
```
Pass `--json` for the machine-readable form. Poll each execution via `hanzo frame lambda progress <renderId>` (or use the returned `executionArn`).
Pass `--json` for the machine-readable form. Poll each execution via `frames lambda progress <renderId>` (or use the returned `executionArn`).
`--dry-run` skips the AWS calls and prints the manifest with `status: "would-invoke"` for every entry — use it to lint the batch file before committing to N billable executions:
```bash
hanzo frame lambda render-batch ./my-template --batch ./users.jsonl \
frames lambda render-batch ./my-template --batch ./users.jsonl \
--width 1920 --height 1080 --dry-run --json
```
@@ -1308,7 +1308,7 @@ hanzo frame lambda render-batch ./my-template --batch ./users.jsonl \
Prints one progress snapshot — overall percent, frames rendered, Lambda invocations, accrued cost, and any errors. Accepts either a bare `renderId` (resolved against the stack's state-machine ARN) or a full SFN execution ARN.
```bash
hanzo frame lambda progress hf-render-abcd1234
frames lambda progress hf-render-abcd1234
```
#### `lambda destroy`
@@ -1321,13 +1321,13 @@ Print or validate the minimum IAM policy the CLI needs to deploy / invoke / dest
```bash
# Print an inline-policy doc you can attach to an IAM user that runs the CLI.
hanzo frame lambda policies user
frames lambda policies user
# Print { TrustRelationship, InlinePolicy } for an IAM role (default: cloudformation principal).
hanzo frame lambda policies role --principal=cloudformation
frames lambda policies role --principal=cloudformation
# Validate a checked-in policy still covers the CLI's needs.
hanzo frame lambda policies validate ./infra/iam/frames-deploy.json
frames lambda policies validate ./infra/iam/frames-deploy.json
```
`validate` reads the JSON doc and checks the union of its `Effect: Allow` actions against the CLI's required action set, expanding `s3:*` / `s3:Get*` / `*` wildcards. Missing actions print to stderr and the command exits non-zero — wire it into CI to catch drift before the next deploy fails.
@@ -1336,16 +1336,16 @@ The actions list is deliberately broad (`Resource: "*"`) because CloudFormation
### State files
`hanzo frame lambda` keeps per-stack metadata under `<cwd>/.frames/lambda-stack-<name>.json` so the verbs don't need to call `describe-stacks` every time. Commit the file to a repo or `.gitignore` it depending on your workflow — it contains the bucket name, state-machine ARN, and region, none of which are secrets but all of which are AWS-account-identifying.
`frames lambda` keeps per-stack metadata under `<cwd>/.frames/lambda-stack-<name>.json` so the verbs don't need to call `describe-stacks` every time. Commit the file to a repo or `.gitignore` it depending on your workflow — it contains the bucket name, state-machine ARN, and region, none of which are secrets but all of which are AWS-account-identifying.
## hanzo frame cloudrun
## frames cloudrun
The Google Cloud counterpart to `hanzo frame lambda`. Deploys Frames distributed rendering to Cloud Run + Cloud Workflows and drives renders from your laptop or CI. Wraps the `@frames/gcp-cloud-run` SDK plus `terraform` (the module shipped with the package) and `gcloud` / Cloud Build for the image.
The Google Cloud counterpart to `frames lambda`. Deploys Frames distributed rendering to Cloud Run + Cloud Workflows and drives renders from your laptop or CI. Wraps the `@frames/gcp-cloud-run` SDK plus `terraform` (the module shipped with the package) and `gcloud` / Cloud Build for the image.
```bash
hanzo frame cloudrun deploy --project my-gcp-project
hanzo frame cloudrun render ./my-project --width 1920 --height 1080 --wait
hanzo frame cloudrun destroy --project my-gcp-project # when you're done
frames cloudrun deploy --project my-gcp-project
frames cloudrun render ./my-project --width 1920 --height 1080 --wait
frames cloudrun destroy --project my-gcp-project # when you're done
```
#### `cloudrun deploy`
@@ -1353,8 +1353,8 @@ hanzo frame cloudrun destroy --project my-gcp-project # when you're done
Enables the required APIs, builds + pushes the render image via Cloud Build (unless you pass `--image`), then `terraform apply`s the module that provisions the GCS bucket, Cloud Run service, Cloud Workflows definition, two service accounts, and a runaway-request alert. Caches the resulting bucket / service URL / workflow id so later verbs don't need them re-passed.
```bash
hanzo frame cloudrun deploy --project my-gcp-project --region us-central1
hanzo frame cloudrun deploy --project my-gcp-project --image us-central1-docker.pkg.dev/my-gcp-project/frames/frames-render:v1
frames cloudrun deploy --project my-gcp-project --region us-central1
frames cloudrun deploy --project my-gcp-project --image us-central1-docker.pkg.dev/my-gcp-project/frames/frames-render:v1
```
Flags: `--project` (required), `--region` (default `us-central1`), `--image` (skip the build), `--repo` (Artifact Registry repo, default `frames`). Machine sizing / scaling: `--cpu` (1/2/4/8, default 4), `--memory` (e.g. `32Gi`, default `16Gi`), `--max-instances` (render fan-out ceiling, default 100), `--timeout` (per-request seconds, max 3600). Omitted sizing flags keep the module defaults; for anything finer, apply the Terraform module directly.
@@ -1385,11 +1385,11 @@ Same trade-off as `lambda`, on Google Cloud instead of AWS. Pick `cloudrun` when
### State file
`hanzo frame cloudrun` caches the deployed stack's coordinates under `~/.frames/cloudrun-state.json` (project id, region, bucket, service URL, workflow id) so `render` / `progress` / `destroy` don't need them re-passed. None are secrets, but all are GCP-project-identifying.
`frames cloudrun` caches the deployed stack's coordinates under `~/.frames/cloudrun-state.json` (project id, region, bucket, service URL, workflow id) so `render` / `progress` / `destroy` don't need them re-passed. None are secrets, but all are GCP-project-identifying.
## frames.json
`hanzo frame init` writes a `frames.json` file at the root of every new project. `hanzo frame add` reads it to know which registry to pull items from and where to drop them. Edit the file (or delete it to fall back to defaults) to reshape your project layout or point at a custom registry.
`frames init` writes a `frames.json` file at the root of every new project. `frames add` reads it to know which registry to pull items from and where to drop them. Edit the file (or delete it to fall back to defaults) to reshape your project layout or point at a custom registry.
```json
{
@@ -1419,7 +1419,7 @@ Missing fields are filled with defaults — you only need to specify what you wa
The rendering pipeline the CLI calls under the hood. Use directly for programmatic rendering.
</Card>
<Card title="Studio" icon="palette" href="/packages/studio">
The editor UI that powers `hanzo frame preview`. Use directly to embed in your own app.
The editor UI that powers `frames preview`. Use directly to embed in your own app.
</Card>
<Card title="Core" icon="cube" href="/packages/core">
Types, linter, and runtime. Use directly for custom tooling and integrations.
+1 -1
View File
@@ -3,7 +3,7 @@ title: "@frames/lint"
description: "The composition linter as a standalone library — lint a directory or a single HTML file without the CLI."
---
The lint package is the composition linter extracted from core into a dedicated, independently-installable package. It's the **single source of truth** for linting: both the CLI's `hanzo frame lint` command and the render-time render-gate consume the same rule engine from here.
The lint package is the composition linter extracted from core into a dedicated, independently-installable package. It's the **single source of truth** for linting: both the CLI's `frames lint` command and the render-time render-gate consume the same rule engine from here.
```bash
npm install @frames/lint
+1 -1
View File
@@ -166,7 +166,7 @@ The agent handles scaffolding, animation, and rendering. See the [prompting guid
npx @hanzo/frame init my-video --example warm-grain --video ./intro.mp4
```
`hanzo frame init` installs AI agent skills automatically, so you can hand off to your AI agent at any point.
`frames init` installs AI agent skills automatically, so you can hand off to your AI agent at any point.
</Step>
<Step title="Preview in the browser">
+1 -1
View File
@@ -63,7 +63,7 @@ Common sizes:
| `data-variable-values` | div | No | JSON object of values passed to a nested composition. Read via `getVariables()` in scripts, or consumed automatically by declarative bindings. |
| `data-var-src` | img, video, audio | No | Binds the element's `src` to a declared variable id — the runtime substitutes the value (URL string or image `{url}`); the authored `src` is the fallback. |
| `data-var-text` | any | No | Binds the element's own text to a scalar variable id. Element children are preserved. |
| `data-color-grading` | img, video | No | Validated JSON payload for media-level correction, grading, LUT, finishing, and shader effects. Prefer Studio or `hanzo frame media-treatment` to author it. |
| `data-color-grading` | img, video | No | Validated JSON payload for media-level correction, grading, LUT, finishing, and shader effects. Prefer Studio or `frames media-treatment` to author it. |
| `data-width` | div | On compositions | Composition width in pixels. |
| `data-height` | div | On compositions | Composition height in pixels. |
+2 -2
View File
@@ -2,7 +2,7 @@
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://frames.hanzo.ai/schema/frames.json",
"title": "Hyperframes Project Config",
"description": "Per-project configuration for a Hyperframes project (frames.json). Tells `hanzo frame add` which registry to pull items from and where to drop them in the project tree. Created by `hanzo frame init`; users may edit it to point at custom registries or reshape their project layout.",
"description": "Per-project configuration for a Hyperframes project (frames.json). Tells `frames add` which registry to pull items from and where to drop them in the project tree. Created by `frames init`; users may edit it to point at custom registries or reshape their project layout.",
"type": "object",
"required": ["registry", "paths"],
"additionalProperties": false,
@@ -55,7 +55,7 @@
"authoringSkill": {
"type": "string",
"pattern": "^[a-z0-9][a-z0-9-]{0,63}$",
"description": "Owning authoring-workflow skill slug (e.g. product-launch-video). Set by `hanzo frame init --skill` or seeded from the first `hanzo frame render --skill`; every render of this project is then attributed to it on anonymous telemetry, without re-passing the flag."
"description": "Owning authoring-workflow skill slug (e.g. product-launch-video). Set by `frames init --skill` or seeded from the first `frames render --skill`; every render of this project is then attributed to it on anonymous telemetry, without re-passing the flag."
}
}
}
+1 -1
View File
@@ -28,7 +28,7 @@ Professional color grading is the headline. Master and per-channel curves, hue c
- **Professional color grading.** Core adds master and per-channel RGB tone curves, hue-vs-hue, hue-vs-saturation and hue-vs-luma curves, three-way shadows, midtones and highlights wheels, and HSL secondary qualifiers. Everything normalizes through one shared contract, so a grade you author resolves the same way in preview and in render ([f99fc4e56](https://github.com/hanzoai/frames/commit/f99fc4e5686239f5ef56d4eb6083bee796ceeddc)).
- **Grading controls in Studio.** The inspector exposes the new curve and wheel controls with live previews, so you can grade a clip on the canvas instead of hand-writing a `data-color-grading` payload ([20ef48abc](https://github.com/hanzoai/frames/commit/20ef48abcb190e3e9ef132d1b1dd711201d3c58b)).
- **Agent-native grading from the CLI.** `hanzo frame media-treatment` applies, previews, and clears a grading payload by selector, with `--dry-run` before writing and `--clear` to remove. The media-use skill now reads the source and picks a treatment instead of guessing a preset name ([6d5961b80](https://github.com/hanzoai/frames/commit/6d5961b8024fe70f87879f271dd91149717d41a8), [4582881d0](https://github.com/hanzoai/frames/commit/4582881d002c361afff59cc1c74ae072a50e17f7)).
- **Agent-native grading from the CLI.** `frames media-treatment` applies, previews, and clears a grading payload by selector, with `--dry-run` before writing and `--clear` to remove. The media-use skill now reads the source and picks a treatment instead of guessing a preset name ([6d5961b80](https://github.com/hanzoai/frames/commit/6d5961b8024fe70f87879f271dd91149717d41a8), [4582881d0](https://github.com/hanzoai/frames/commit/4582881d002c361afff59cc1c74ae072a50e17f7)).
- **Media treatments.** A media treatment is a source-aware plan that composes existing color, effect, timeline, and registry primitives rather than adding a second runtime schema. Core defines the capability catalog, the runtime renders treatments deterministically, Studio ships an inspector for them, and the registry adds matching overlays ([70213c5a8](https://github.com/hanzoai/frames/commit/70213c5a8526b12c8b26f01b8288d78bb9edc917), [944640c32](https://github.com/hanzoai/frames/commit/944640c3283d604383fd437fcca8c63941d8e3d7), [39c2341c4](https://github.com/hanzoai/frames/commit/39c2341c4d1edf52a00fb8db4a49553c739860cc), [b0d3164dd](https://github.com/hanzoai/frames/commit/b0d3164ddb6177c6b31634f02a908fdae607850f)).
- **Keyframe ease editor.** Studio gets an ease curve editor with a preset library, editable ease parameters, and an SVG curve preview. A deterministic ease runtime backs it, so an authored ease replays identically at render time ([c253dec23](https://github.com/hanzoai/frames/commit/c253dec23b0a6f1ccfe49c17371fdc9823f73b4c), [5acbf240c](https://github.com/hanzoai/frames/commit/5acbf240cbab38594d06b59b9ef7f2a4b37d31b7)).
- **Versioned distributed plan protocol.** Distributed plans now carry an explicit protocol descriptor. Plans written before the descriptor still load as v1, while a partial, malformed, or unknown descriptor fails closed before any layout-specific read. Plan hashes and rendered pixels are unchanged ([f9f00b0ef](https://github.com/hanzoai/frames/commit/f9f00b0efc2d1006967d5b2e0009ea3c3f6ed2e6), [#2777](https://github.com/hanzoai/frames/pull/2777)).