Skill Tracer
Skills › HyperFrames › hyperframes-cli › lambda.md

lambda.md

189 lines · skills/hyperframes-cli/references/lambda.md at a595755

Open on GitHub

Most marks come from matching words in the file, so treat them as pointers.

1# Lambda rendering on AWS
2
3Use `hyperframes lambda` when the user explicitly wants self-managed AWS infrastructure or needs distributed rendering. It wraps `@hyperframes/aws-lambda` and AWS SAM.
4

Lambda rendering on AWS

Use hyperframes lambda when the user explicitly wants self-managed AWS infrastructure or needs distributed rendering. It wraps @hyperframes/aws-lambda and AWS SAM.

Raw lines 1 to 4
5## Contents
6
7- [Choose Lambda or local rendering](#choose-lambda-or-local-rendering)
8- [Prerequisites](#prerequisites)
9- [Deploy](#deploy)
10- [Upload a reusable site](#upload-a-reusable-site)
11- [Render one composition](#render-one-composition)
12- [Render a JSONL batch](#render-a-jsonl-batch)
13- [Inspect progress](#inspect-progress)
14- [Destroy the stack](#destroy-the-stack)
15- [IAM policies](#iam-policies)
16- [State, cost, and cleanup](#state-cost-and-cleanup)
18The basic lifecycle is:
20```bash
21npx hyperframes lambda deploy
22npx hyperframes lambda render ./my-project --width 1920 --height 1080 --wait
23npx hyperframes lambda destroy
24```

Contents

  • Choose Lambda or local rendering
  • Prerequisites
  • Deploy
  • Upload a reusable site
  • Render one composition
  • Render a JSONL batch
  • Inspect progress
  • Destroy the stack
  • IAM policies
  • State, cost, and cleanup

The basic lifecycle is:

npx hyperframes lambda deploy
npx hyperframes lambda render ./my-project --width 1920 --height 1080 --wait
npx hyperframes lambda destroy
Raw lines 5 to 25
26## Choose Lambda or local rendering
28- **Local `render`** — dev-loop iteration, single host, anything under a few minutes at 1080p.
29- **`lambda render`** — long videos, 4K, large parallel batches, or anything where local Chrome would time out / exhaust RAM. Pay-per-invocation, no idle cost.
31For one-off short renders Lambda is not worth the deploy overhead.

Choose Lambda or local rendering

  • **Local render** — dev-loop iteration, single host, anything under a few minutes at 1080p.
  • **lambda render** — long videos, 4K, large parallel batches, or anything where local Chrome would time out / exhaust RAM. Pay-per-invocation, no idle cost.

For one-off short renders Lambda is not worth the deploy overhead.

Raw lines 26 to 32
33## Prerequisites
35- AWS credentials configured (env vars, `~/.aws/credentials`, SSO, or IMDS).
36- AWS SAM CLI on `PATH`.
37- `bun` on `PATH` (builds the Lambda handler ZIP).

Prerequisites

  • AWS credentials configured (env vars, ~/.aws/credentials, SSO, or IMDS).
  • AWS SAM CLI on PATH.
  • bun on PATH (builds the Lambda handler ZIP).
Raw lines 33 to 38
39## Deploy
41```bash
42npx hyperframes lambda deploy \
43 --stack-name=hyperframes-prod \
44 --region=us-east-1 \
45 --concurrency=8 \
46 --memory=10240
47```
49Builds `packages/aws-lambda/dist/handler.zip` and SAM-deploys the stack (Lambda + Step Functions + S3 + IAM). Idempotent — re-running on the same `--stack-name` is a no-op when nothing changed. Writes `<cwd>/.hyperframes/lambda-stack-<name>.json` so later subcommands don't need to call `describe-stacks`.
51| Flag | Default | Description |
52| ----------------- | ------------------------------- | -------------------------------------- |
53| `--stack-name` | `hyperframes-default` | CloudFormation stack name |
54| `--region` | `AWS_REGION` env or `us-east-1` | AWS region |
55| `--profile` | `AWS_PROFILE` env | Named AWS credentials profile |
56| `--concurrency` | `8` | Lambda reserved concurrency |
57| `--chrome-source` | `sparticuz` | `sparticuz` or `chrome-headless-shell` |
58| `--memory` | `10240` | Lambda memory in MB |
59| `--skip-build` | off | Reuse existing `handler.zip` |
60| `--no-warm` | warm | Skip the warm-up call after deploy |

Deploy

npx hyperframes lambda deploy \
  --stack-name=hyperframes-prod \
  --region=us-east-1 \
  --concurrency=8 \
  --memory=10240

Builds packages/aws-lambda/dist/handler.zip and SAM-deploys the stack (Lambda + Step Functions + S3 + IAM). Idempotent — re-running on the same --stack-name is a no-op when nothing changed. Writes <cwd>/.hyperframes/lambda-stack-<name>.json so later subcommands don't need to call describe-stacks.

FlagDefaultDescription
--stack-namehyperframes-defaultCloudFormation stack name
--regionAWS_REGION env or us-east-1AWS region
--profileAWS_PROFILE envNamed AWS credentials profile
--concurrency8Lambda reserved concurrency
--chrome-sourcesparticuzsparticuz or chrome-headless-shell
--memory10240Lambda memory in MB
--skip-buildoffReuse existing handler.zip
--no-warmwarmSkip the warm-up call after deploy
Raw lines 39 to 61
62## Upload a reusable site
64```bash
65npx hyperframes lambda sites create ./my-project
66# → siteId: abc1234deadbeef0 (stable across re-runs of the same tree)
68npx hyperframes lambda render ./my-project --site-id=abc1234deadbeef0 ...
69```
71Tars + uploads `<projectDir>` to S3 with a content-addressed key. Returns a stable `siteId` you can reuse — re-renders of the same tree skip the upload.

Upload a reusable site

npx hyperframes lambda sites create ./my-project
# → siteId: abc1234deadbeef0  (stable across re-runs of the same tree)

npx hyperframes lambda render ./my-project --site-id=abc1234deadbeef0 ...

Tars + uploads <projectDir> to S3 with a content-addressed key. Returns a stable siteId you can reuse — re-renders of the same tree skip the upload.

Raw lines 62 to 72
73## Render one composition
75```bash
76npx hyperframes lambda render ./my-project \
77 --width 1920 --height 1080 --fps 30 --format mp4 \
78 --chunk-size 240 --max-parallel-chunks 16 \
79 --wait
80```
82Starts a Step Functions execution. Returns immediately with a `renderId` unless `--wait` is set, in which case the CLI blocks until completion and streams per-chunk progress lines. Add `--json` for machine-parseable output.
84| Flag | Description |
85| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
86| `--width` / `--height` | Output dimensions in pixels |
87| `--output-resolution` | Supersampling preset (engages Chrome `deviceScaleFactor`) — `landscape` / `landscape-4k` / `portrait` / `portrait-4k` / `square` / `square-4k`, plus aliases (`1080p`, `4k`, `uhd`, `hd`, `1080p-portrait`, `4k-portrait`, `1080p-square`, `4k-square`). Use this to render an authored-at-1080p composition at 4K without re-laying-out — see footgun below. |
88| `--fps` | `24` / `25` / `30` / `60` |
89| `--format` | `mp4` / `mov` / `png-sequence` / `webm` (default `mp4`) |
90| `--codec` | `h264` / `h265` (mp4 only) |
91| `--quality` | `draft` / `standard` / `high` |
92| `--chunk-size` | Frames per chunk (default `240`) |
93| `--max-parallel-chunks` | Max concurrent chunks (default `16`) |
94| `--target-chunk-frames` | Cap frames per chunk and let the planner add chunks up to the parallel limit |
95| `--keyframe-interval` | MP4 only: a keyframe at least every N seconds (a maximum: chunk joins add keyframes) |
96| `--max-bitrate` | MP4 only: peak bitrate cap, held per chunk (a join can burst up to one buffer) |
97| `--buffer-size` | MP4 only: buffer for `--max-bitrate` (default twice it) |
98| `--site-id` | Reuse an existing site (skip upload) |
99| `--execution-name` | Explicit Step Functions execution name |
100| `--output-key` | Explicit final S3 object key |
101| `--variables` | Inline JSON object with composition variable values |
102| `--variables-file` | JSON file containing one composition variable object |
103| `--strict-variables` | Fail when supplied variables are undeclared or have the wrong type |
104| `--wait` | Block until completion, stream progress |
105| `--wait-interval-ms` | Poll cadence while waiting (default `5000`) |
106| `--json` | Machine-parseable progress snapshot |
108**`--width` / `--height` footgun.** Setting `--width 3840 --height 2160` against a composition whose `data-width="1920"` silently produces 1080p — the runtime lays out the page at the composition's authored dimensions and the CLI flags are ignored for layout. To actually output at 4K, use `--output-resolution 4k` (supersamples via `deviceScaleFactor`). The CLI now prints a warning when CLI dimensions disagree with the composition's `data-width` / `data-height` and `--output-resolution` is not set; the warning is suppressed when `--json` is on or `index.html` isn't on disk (`--site-id` flows).
110For variable-driven templates, declare the schema in the composition and pass either `--variables` or `--variables-file`, never both. `--strict-variables` checks local project input before any render starts. Also read [Variables](../../hyperframes/references/format.md#variables).

Render one composition

npx hyperframes lambda render ./my-project \
  --width 1920 --height 1080 --fps 30 --format mp4 \
  --chunk-size 240 --max-parallel-chunks 16 \
  --wait

Starts a Step Functions execution. Returns immediately with a renderId unless --wait is set, in which case the CLI blocks until completion and streams per-chunk progress lines. Add --json for machine-parseable output.

FlagDescription
--width / --heightOutput dimensions in pixels
--output-resolutionSupersampling preset (engages Chrome deviceScaleFactor) — landscape / landscape-4k / portrait / portrait-4k / square / square-4k, plus aliases (1080p, 4k, uhd, hd, 1080p-portrait, 4k-portrait, 1080p-square, 4k-square). Use this to render an authored-at-1080p composition at 4K without re-laying-out — see footgun below.
--fps24 / 25 / 30 / 60
--formatmp4 / mov / png-sequence / webm (default mp4)
--codech264 / h265 (mp4 only)
--qualitydraft / standard / high
--chunk-sizeFrames per chunk (default 240)
--max-parallel-chunksMax concurrent chunks (default 16)
--target-chunk-framesCap frames per chunk and let the planner add chunks up to the parallel limit
--keyframe-intervalMP4 only: a keyframe at least every N seconds (a maximum: chunk joins add keyframes)
--max-bitrateMP4 only: peak bitrate cap, held per chunk (a join can burst up to one buffer)
--buffer-sizeMP4 only: buffer for --max-bitrate (default twice it)
--site-idReuse an existing site (skip upload)
--execution-nameExplicit Step Functions execution name
--output-keyExplicit final S3 object key
--variablesInline JSON object with composition variable values
--variables-fileJSON file containing one composition variable object
--strict-variablesFail when supplied variables are undeclared or have the wrong type
--waitBlock until completion, stream progress
--wait-interval-msPoll cadence while waiting (default 5000)
--jsonMachine-parseable progress snapshot

**--width / --height footgun.** Setting --width 3840 --height 2160 against a composition whose data-width="1920" silently produces 1080p — the runtime lays out the page at the composition's authored dimensions and the CLI flags are ignored for layout. To actually output at 4K, use --output-resolution 4k (supersamples via deviceScaleFactor). The CLI now prints a warning when CLI dimensions disagree with the composition's data-width / data-height and --output-resolution is not set; the warning is suppressed when --json is on or index.html isn't on disk (--site-id flows).

For variable-driven templates, declare the schema in the composition and pass either --variables or --variables-file, never both. --strict-variables checks local project input before any render starts. Also read Variables.

Raw lines 73 to 111
112## Render a JSONL batch
114Use `render-batch` to upload one template once and start one Step Functions execution per nonblank JSONL line:
116```bash
117npx hyperframes lambda render-batch ./template \
118 --batch ./users.jsonl \
119 --width 1920 --height 1080 \
120 --max-concurrent 10 \
121 --strict-variables \
122 --json
123```
125Each line must be an object with a non-empty `outputKey`. Choose unique keys to prevent outputs from overwriting one another. `variables` and `executionName` are optional:
127```json
129 "outputKey": "renders/alice.mp4",
130 "variables": { "name": "Alice" },
131 "executionName": "alice-video"
133```
135Batch rules:
137- The project is uploaded once unless `--site-id` reuses an earlier upload.
138- `--max-concurrent` defaults to `50` and limits in-flight render executions. `--max-parallel-chunks` separately limits chunks inside each render.
139- `--strict-variables` checks every entry, reports all variable issues, and aborts before AWS calls.
140- `--dry-run` performs no upload or AWS render call. Every manifest row becomes `would-invoke`.
141- The emitted manifest preserves input order and records `inputLine`, `outputKey`, `executionArn`, and `status` (`started`, `would-invoke`, or `failed-to-start`), plus an error when applicable.
142- A per-entry start failure does not hide other rows. Human-output mode exits nonzero when a row fails to start. In `--json` mode the current CLI prints the manifest and exits zero, so gate on every row's `status`, not the process code alone. Dispatch success is not render completion; inspect each execution with `progress`.

Render a JSONL batch

Use render-batch to upload one template once and start one Step Functions execution per nonblank JSONL line:

npx hyperframes lambda render-batch ./template \
  --batch ./users.jsonl \
  --width 1920 --height 1080 \
  --max-concurrent 10 \
  --strict-variables \
  --json

Each line must be an object with a non-empty outputKey. Choose unique keys to prevent outputs from overwriting one another. variables and executionName are optional:

{
  "outputKey": "renders/alice.mp4",
  "variables": { "name": "Alice" },
  "executionName": "alice-video"
}

Batch rules:

  • The project is uploaded once unless --site-id reuses an earlier upload.
  • --max-concurrent defaults to 50 and limits in-flight render executions. --max-parallel-chunks separately limits chunks inside each render.
  • --strict-variables checks every entry, reports all variable issues, and aborts before AWS calls.
  • --dry-run performs no upload or AWS render call. Every manifest row becomes would-invoke.
  • The emitted manifest preserves input order and records inputLine, outputKey, executionArn, and status (started, would-invoke, or failed-to-start), plus an error when applicable.
  • A per-entry start failure does not hide other rows. Human-output mode exits nonzero when a row fails to start. In --json mode the current CLI prints the manifest and exits zero, so gate on every row's status, not the process code alone. Dispatch success is not render completion; inspect each execution with progress.
Raw lines 112 to 143
Starts an agent Dispatch :142
144## Inspect progress
146```bash
147npx hyperframes lambda progress hf-render-abcd1234
148npx hyperframes lambda progress arn:aws:states:us-east-1:...:execution:...
149```
151Prints one snapshot — overall percent, frames rendered, Lambda invocations, accrued cost, and any errors. Accepts a bare `renderId` (resolved against the stack's state-machine ARN) or a full SFN execution ARN.

Inspect progress

npx hyperframes lambda progress hf-render-abcd1234
npx hyperframes lambda progress arn:aws:states:us-east-1:...:execution:...

Prints one snapshot — overall percent, frames rendered, Lambda invocations, accrued cost, and any errors. Accepts a bare renderId (resolved against the stack's state-machine ARN) or a full SFN execution ARN.

Raw lines 144 to 152
153## Destroy the stack
155```bash
156npx hyperframes lambda destroy
157```
159Calls `sam delete --no-prompts` and drops the local state file. **The render S3 bucket is configured `Retain`** so it survives stack destruction — empty + delete it via the AWS console / CLI if you want the storage back.

Destroy the stack

npx hyperframes lambda destroy

Calls sam delete --no-prompts and drops the local state file. **The render S3 bucket is configured Retain** so it survives stack destruction — empty + delete it via the AWS console / CLI if you want the storage back.

Raw lines 153 to 160
161### Non-retryable errors
163A subset of failures the Step Functions state machine short-circuits instead of running through its 4× 15-min retry budget. `progress` surfaces these immediately with the error class name; do not re-issue `lambda render` blindly when you see one.
165- **`ChromeBinaryUnavailableError`** — `@sparticuz/chromium` returned an empty/missing executable path. A prior chunk hit `Sandbox.Timedout` mid-extraction and the warm instance is wedged until the execution environment recycles. Remedy: bump a Lambda env var (forces a new exec env) or `lambda deploy` again. Not a transient render failure; retries will burn budget on the same wedged instance.
166- **`FFMPEG_VERSION_MISMATCH`** / **`PLAN_HASH_MISMATCH`** — planner / executor version drift. Re-deploy.

Non-retryable errors

A subset of failures the Step Functions state machine short-circuits instead of running through its 4× 15-min retry budget. progress surfaces these immediately with the error class name; do not re-issue lambda render blindly when you see one.

  • **ChromeBinaryUnavailableError** — @sparticuz/chromium returned an empty/missing executable path. A prior chunk hit Sandbox.Timedout mid-extraction and the warm instance is wedged until the execution environment recycles. Remedy: bump a Lambda env var (forces a new exec env) or lambda deploy again. Not a transient render failure; retries will burn budget on the same wedged instance.
  • **FFMPEG_VERSION_MISMATCH / PLAN_HASH_MISMATCH** — planner / executor version drift. Re-deploy.
Raw lines 161 to 167
168## IAM policies
170Print or validate the minimum IAM permissions the CLI needs.
172```bash
173npx hyperframes lambda policies user # inline policy for an IAM user
174npx hyperframes lambda policies role # { TrustRelationship, InlinePolicy }
175npx hyperframes lambda policies validate ./infra/iam/hf-deploy.json # CI gate
176```
178`validate` reads a JSON policy doc and checks the union of its `Effect: Allow` actions (expanding `s3:*` / `s3:Get*` / `*` wildcards) against the CLI's required action set. Missing actions print to stderr; the command exits non-zero. Wire it into CI to catch policy drift before the next deploy fails.
180The default action set is deliberately broad (`Resource: "*"`) because CloudFormation creates new ARNs on every adopter's first deploy. Tighten `Resource` after that first run if security posture requires it.

IAM policies

Print or validate the minimum IAM permissions the CLI needs.

npx hyperframes lambda policies user                                  # inline policy for an IAM user
npx hyperframes lambda policies role                                  # { TrustRelationship, InlinePolicy }
npx hyperframes lambda policies validate ./infra/iam/hf-deploy.json   # CI gate

validate reads a JSON policy doc and checks the union of its Effect: Allow actions (expanding s3:* / s3:Get* / * wildcards) against the CLI's required action set. Missing actions print to stderr; the command exits non-zero. Wire it into CI to catch policy drift before the next deploy fails.

The default action set is deliberately broad (Resource: "*") because CloudFormation creates new ARNs on every adopter's first deploy. Tighten Resource after that first run if security posture requires it.

Raw lines 168 to 181
182## State, cost, and cleanup
184`hyperframes lambda` stores per-stack metadata under `<cwd>/.hyperframes/lambda-stack-<name>.json` (bucket name, state-machine ARN, region). Not secret, but AWS-account-identifying. Commit it to a repo or `.gitignore` it per your workflow.
186- `lambda destroy` removes the SAM stack but **leaves the S3 bucket** (`Retain`). Delete it manually if you want the storage back.
187- Lambda billing is per-invocation + duration. `progress` reports the accrued cost.
188- `--concurrency` caps parallel Lambda invocations — keep it aligned with your account quota.
189- `--chunk-size` and `--max-parallel-chunks` trade off per-chunk overhead against parallelism; larger chunks reduce coordinator overhead, smaller chunks parallelize more aggressively.

State, cost, and cleanup

hyperframes lambda stores per-stack metadata under <cwd>/.hyperframes/lambda-stack-<name>.json (bucket name, state-machine ARN, region). Not secret, but AWS-account-identifying. Commit it to a repo or .gitignore it per your workflow.

  • lambda destroy removes the SAM stack but leaves the S3 bucket (Retain). Delete it manually if you want the storage back.
  • Lambda billing is per-invocation + duration. progress reports the accrued cost.
  • --concurrency caps parallel Lambda invocations — keep it aligned with your account quota.
  • --chunk-size and --max-parallel-chunks trade off per-chunk overhead against parallelism; larger chunks reduce coordinator overhead, smaller chunks parallelize more aggressively.
Raw lines 182 to 189