Files
frames/docs/deploy/cloud.mdx
T
zooqueen e0266e8a63 docs: point the skills and the docs site at our own stack
The workflow skills, the CLI reference, and the guides described a vendor's
services: a separate account to sign into, a credential file beside the
project, a music library and asset search that are not ours, and preview
media on a CDN we do not run.

Auth is now one Hanzo IAM token in $HANZO_API_KEY, read from Hanzo KMS —
one credential for voice, music, sound effects, images, video, the shared
catalog, and cloud rendering. The credential guide, the cloud-render
pages, and the CLI auth reference all say the same thing, because there
is now only one thing to say.

Docs previews resolve from the docs site's own /images/ path, produced by
our own generator. They are not committed (docs/images/ is ignored), so a
deploy must run `bun run generate:catalog-previews` first — the same gap
as before, minus a CDN we cannot publish to. Element grounding calls
zen-vl through api.hanzo.ai rather than a third-party vision endpoint,
and the LUT library builds every look from params, so no look needs a
host at all.

Command examples read `npx @hanzo/frame` / `hanzo frame` throughout.
Three navigation entries left dangling by the rebrand now resolve.

The changelog and the weekly archive keep their entries as written and
say plainly that pre-port entries describe the upstream product.
2026-08-13 17:29:50 -07:00

213 lines
10 KiB
Plaintext
Raw 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
hanzo frame auth login # one-time sign-in
hanzo frame 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 [`hanzo frame 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
hanzo frame 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
`hanzo frame 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 `hanzo frame 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
hanzo frame cloud render . --dry-run
hanzo frame 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.
## 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.
hanzo frame cloud render . \
--composition compositions/intro.html \
--output ./renders/intro.mp4
# Higher quality at 60fps.
hanzo frame 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
hanzo frame cloud render --variables '{"title":"Q4 Recap","theme":"dark"}'
# From a file
hanzo frame cloud render --variables-file ./vars.json
# Fail fast on undeclared keys or wrong types
hanzo frame 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.
hanzo frame 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"}'
```
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
hanzo frame cloud render --callback-url https://example.com/hf-hook --no-wait
# ✓ Submitted hfr_def456
# Poll with: hanzo frame 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
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)
```
`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
hanzo frame 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).
## 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>