Files
zooqueen 457e510c8a 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.
2026-08-13 17:31:23 -07:00

213 lines
10 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: Cloud Rendering
description: "Render a composition on the hosted cloud — no local Chrome, no FFmpeg, no AWS to manage."
---
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
frames auth login # one-time sign-in
frames cloud render # zip → upload → render → download
```
```bash
# ◆ Zipping my-video
# 42 files · 3.1 MB
# ◆ Uploading the project
# asset_id: asst_abc123 · 1.2s
# Polling hfr_def456 every 10s …
# completed 47s
# ◆ Downloading to renders/hfr_def456.mp4
# 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 [`frames render`](/guides/rendering).
## Authenticate
Cloud rendering uses the same credential as everything else: a Hanzo IAM token
in `HANZO_API_KEY`, read from [Hanzo KMS](https://kms.hanzo.ai). One token, every
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
frames auth status
# Shows which credential is in use, the identity behind it, and the balance.
# Exit 0 = usable; exit 1 = absent or rejected.
```
<Note>
Point the CLI at a different deployment with `HANZO_BASE_URL` (default
`https://api.hanzo.ai`). A publishable `pk-` key is read-only and is refused;
use an IAM token or an `sk-` key. For what the same token unlocks across the
skills, see [Authentication](/guides/authentication).
</Note>
## How a cloud render flows
`frames cloud render` runs the whole pipeline end-to-end:
```
Your machine Hanzo Cloud
┌─────────────────────────┐ ┌─────────────────────────────────┐
│ zip project │ ──PUT───▶│ direct-to-store asset upload │
│ (.framesignore + │ upload │ → asset_id │
│ generated outputs) │ │ │
│ │ ──POST──▶│ submit the render │
│ │ submit │ → render_id (queued) │
│ │ │ Chromium + FFmpeg render │
│ poll the render │ ◀────────│ queued → rendering → completed │
│ stream video to disk │ ◀────────│ signed video_url │
└─────────────────────────┘ └─────────────────────────────────┘
```
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 `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`).
7. **Download** the signed video URL to disk.
## Control archive size
Hosted cloud project uploads are limited to 200 MB. Frames automatically excludes root-level `renders/` and `snapshots/` plus development-only paths such as `.git`, `node_modules`, `dist`, `.next`, `coverage`, and dotfiles.
Use a gitignore-style `.framesignore` at the project root for additional generated or intermediate files that are not needed at render time:
```gitignore
/snapshots2/
/exports/
/assets/source-master.mp4
```
Inspect the exact archive without authenticating, uploading, or starting a render:
```bash
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 `frames publish`. Avoid broad patterns such as `assets/`: dynamically selected media may not appear as an obvious static HTML reference.
## Render options
The most-used flags — see the [CLI reference](/packages/cli#frames-cloud) for the full list.
| Flag | Default | Meaning |
| --- | --- | --- |
| `--fps` | `30` | Frames per second, 1–240. |
| `--quality` | `standard` | `draft`, `standard`, or `high`. |
| `--format` | `mp4` | `mp4`, `webm`, or `mov` (webm/mov carry alpha). |
| `--resolution` | `1080p` | `1080p` or `4k`. 4k is billed at 1.5×. |
| `--aspect-ratio` | auto | `16:9`, `9:16`, or `1:1`. Auto-detected from a local project's `data-width`/`data-height`; for `--asset-id`/`--url` it defaults to `16:9` unless set. |
| `--composition` / `-c` | `index.html` | Entry HTML file inside the zip. |
| `--output` / `-o` | `renders/<render_id>.<ext>` | Local destination for the download. |
| `--dry-run` | off | Build and inspect a local project zip without authenticating, uploading, or rendering. |
```bash
# Pick a composition and an output path.
frames cloud render . \
--composition compositions/intro.html \
--output ./renders/intro.mp4
# Higher quality at 60fps.
frames cloud render --quality high --fps 60
```
<Warning>
`--resolution 4k` can't be combined with `--format webm` or `--format mov`. The 4k supersampling path runs through the screenshot capture pipeline, which has no alpha channel. Render 4k as `mp4`, or render alpha at the composition's native resolution.
</Warning>
## Templates and variables
Cloud rendering supports [variables](/concepts/variables) — the same mechanism that powers templates everywhere else in Frames. Declare `data-composition-variables` on your composition, then fill them at render time:
```bash
# Inline JSON
frames cloud render --variables '{"title":"Q4 Recap","theme":"dark"}'
# From a file
frames cloud render --variables-file ./vars.json
# Fail fast on undeclared keys or wrong types
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.
The idiomatic template workflow is **upload once, re-render many**: render a local project to get its `asset_id`, then submit new renders against that same asset with different variables — no re-zip, no re-upload.
```bash
# 1. Upload + render once; note the asset_id printed during upload.
frames cloud render ./card-template
# 2. Re-render the same asset with new values (skips zip + upload).
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).
## Fire-and-forget and webhooks
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
frames cloud render --callback-url https://example.com/hf-hook --no-wait
# ✓ Submitted hfr_def456
# Poll with: frames cloud get hfr_def456
```
| Flag | Meaning |
| --- | --- |
| `--no-wait` | Submit and exit immediately; print the `render_id`. |
| `--callback-url` | HTTPS webhook fired when the render terminates. |
| `--callback-id` | Opaque tracking ID echoed in webhook payloads. |
| `--poll-interval` | Poll cadence in seconds (default `10`). |
| `--max-wait` | Max poll duration in minutes (default `60`). |
## Managing renders
```bash
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.
## Safe retries
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
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
- **`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
<CardGroup cols={2}>
<Card title="Variables" icon="sliders" href="/concepts/variables">
Declare and fill template slots in a composition
</Card>
<Card title="Templates on Lambda" icon="layer-group" href="/deploy/templates-on-lambda">
High-volume personalized renders on your own AWS
</Card>
<Card title="Local rendering" icon="film" href="/guides/rendering">
Render locally or in Docker during authoring
</Card>
<Card title="CLI reference" icon="terminal" href="/packages/cli#frames-cloud">
Every `cloud` and `auth` flag in detail
</Card>
</CardGroup>