Skip to content

docs(deploy): templates-on-lambda guide for personalised video at scale#968

Merged
jrusso1020 merged 3 commits into
mainfrom
05-19-docs_deploy_templates-on-lambda_guide
May 19, 2026
Merged

docs(deploy): templates-on-lambda guide for personalised video at scale#968
jrusso1020 merged 3 commits into
mainfrom
05-19-docs_deploy_templates-on-lambda_guide

Conversation

@jrusso1020
Copy link
Copy Markdown
Collaborator

@jrusso1020 jrusso1020 commented May 19, 2026

What

Phase 9 PR 9.5 of the distributed rendering plan — the user-facing templates-on-lambda guide. Documents the personalised-video-at-scale flow now shippable end-to-end after PRs 9.1–9.4.

Why

PRs 9.1–9.4 plumb variables through every layer (producer plan/renderChunk, aws-lambda SDK, single-render CLI, batch CLI). Without a guide, users have to reverse-engineer the flow from --help output and source comments. The docs ARE the deliverable that makes "easy template pipelines" real — that's why this PR exists separate from the code changes.

How

docs/deploy/templates-on-lambda.mdx walks all 11 sections required by the Phase 9 plan:

  • (a) What's a template (composition + data-composition-variables)
  • (b) Declaring variables (syntax, types, defaults, getVariables())
  • (c) Local iteration loop (hyperframes render --variables / --variables-file / --strict-variables)
  • (d) Deploying to Lambda (pointer to deploy guide + sites create)
  • (e) Single personalised render (lambda render --variables)
  • (f) Batch pipeline — the headline (lambda render-batch --batch users.jsonl, with a worked 5-row example, manifest output, progress polling, --dry-run)
  • (g) Programmatic via SDK (TypeScript example with deploySite + Promise.all(renderToLambda))
  • (h) Working with large variables (the 256 KiB Step Functions Standard ceiling, URL-your-assets convention, one-line escape note for genuine > 256 KiB cases)
  • (i) Cost + scale considerations (Lambda concurrency, --max-parallel-chunks vs --max-concurrent, in-process vs distributed crossover)
  • (j) Migrating from @remotion/lambda inputProps (side-by-side table; same 256 KiB cap + same URL-your-assets convention, so migration is mechanical)

Plus a Mermaid architecture diagram for the site-upload-once + N-execution fan-out flow at the top.

docs/docs.json adds the page to the Deploy navigation group between the existing aws-lambda and migrating-to-hyperframes-lambda pages.

Test plan

  • Guide structure matches the 10-section spec from the Phase 9 plan (verified via grep "^## ").
  • Mermaid diagram renders (Mintlify's preview will catch syntax errors).
  • Internal links resolve: /deploy/aws-lambda (existing), https://github.com/heygen-com/hyperframes/issues/new (anchor), the working-with-large-variables anchor referenced by the SDK's oversize-input error message.
  • Code samples use the exact flag names from PRs 9.3 + 9.4 (--variables, --variables-file, --strict-variables, --max-concurrent, --dry-run, --json).
  • No backticks / shell-meta in --variables JSON examples that would mis-render in Mintlify's monospace blocks.

This is the load-bearing artifact for the user-facing pitch on Phase 9. After this lands, the user goal "make automated template pipelines on Lambda as easy as possible" is shippable.

This is part of a stack of 5 (+1 optional) PRs (9.1–9.6); this is PR 9.5.

🤖 Generated with Claude Code

Copy link
Copy Markdown
Collaborator Author

jrusso1020 commented May 19, 2026

Copy link
Copy Markdown
Collaborator

@miguel-heygen miguel-heygen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thorough, accurate guide. Cross-referenced every CLI flag, SDK signature, runtime API, and constraint against the actual code in #962-#967 — all correct:

  • Flag names (--variables, --variables-file, --strict-variables, --max-concurrent, --dry-run, --batch, --site-id, --wait) match lambda.ts definitions
  • SDK import path (@hyperframes/aws-lambda/sdk) matches actual exports
  • window.__hyperframes.getVariables() correctly documents the public API (not the internal window.__hfVariables injection point)
  • 256 KiB cap, default concurrency of 50, JSONL batch format, data-composition-variables schema all verified

Guide structure covers the complete user journey from template authoring through batch rendering at scale. This also unblocks PR #970's cross-links.

CI green. Ship it.

Copy link
Copy Markdown
Collaborator

@vanceingalls vanceingalls left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the templates-on-lambda guide end-to-end against the downstack code (#962-#967) and the canonical concept docs (docs/concepts/variables.mdx, docs/concepts/data-attributes.mdx, runtime in packages/core/src/runtime/getVariables.ts).

Calibrated strengths

  • Section structure mirrors the Phase 9 plan cleanly; the headline batch surface lands with worked JSONL example, manifest output, --dry-run, and --json (docs/deploy/templates-on-lambda.mdx:79-128).
  • "Working with large variables" pins the 256 KiB Step Functions Standard cap correctly against MAX_STEP_FUNCTIONS_INPUT_BYTES in packages/aws-lambda/src/sdk/validateConfig.ts and reproduces the SDK error verbatim (docs/deploy/templates-on-lambda.mdx:175-185).
  • Mermaid diagram captures the deploy-once / fan-out-N flow that's the actual point of render-batch; matches the deploySite + Promise.all(renderToLambda) shape in packages/aws-lambda/src/sdk/.

Findings

blockerInvented "object" variable type that the runtime will silently drop.
docs/deploy/templates-on-lambda.mdx:54 advertises supported types as "string", "number", "boolean", "object", and docs/deploy/templates-on-lambda.mdx:65-69 shows a worked type: "object" declaration. The canonical validator in packages/core/src/parsers/htmlParser.ts rejects anything outside ["string", "number", "color", "boolean", "enum"]:

if (!["string", "number", "color", "boolean", "enum"].includes(v.type)) return false;

A user copy-pasting that hero block will get a declaration that fails the parser and readDeclaredDefaults will drop it — no defaults, Studio won't render an editor, and --strict-variables will report every key as undeclared. Two bugs in one: (1) "object" doesn't exist, (2) color and enum (which do exist) are missing. This is the load-bearing artifact for the user-facing pitch; the type table is the first thing they'll read. Fix: align the table to the canonical five types and drop the type: "object" "nested data" example, OR add "object" to the validator's whitelist if that's actually the intent of this stack (no evidence of that in #962-#967).

blockerCross-reference URLs use the wrong path.
docs/deploy/templates-on-lambda.mdx:99 links to /deploy/aws-lambda, which is correct. But the upstream PRs reference this same guide as /docs/deploy/templates-on-lambda (e.g. docs/packages/cli.mdx:920 in #964, and again in #967). Mintlify routes are repo-relative without the /docs prefix — one set of references will 404. The SDK's oversize-input error message that this guide quotes verbatim (docs/deploy/templates-on-lambda.mdx:182) points to github.com/.../docs/deploy/templates-on-lambda.mdx#working-with-large-variables — that's a GH source-blob anchor, not the rendered docs site, so it's the wrong destination from a production CLI error. Decide on one canonical URL across the stack and fix every reference (this PR's links + #964/#967 incoming references + the SDK error message).

importantSDK example uses an API shape that won't compile.
docs/deploy/templates-on-lambda.mdx:139-155 shows renderToLambda({ siteHandle, bucketName, stateMachineArn, config: {...}, outputKey }). Verified RenderToLambdaOptions in packages/aws-lambda/src/sdk/renderToLambda.ts — that signature is right. BUT the deploySite call above it passes { projectDir, bucketName } only; DeploySiteOptions is correct on that. What's missing: renderToLambda requires a region only when AWS env isn't configured, and the doc never names where HYPERFRAMES_BUCKET / HYPERFRAMES_SFN_ARN come from. The aws-lambda deploy guide names the SAM outputs as RenderBucketName / RenderStateMachineArn. Add one line linking to the deploy guide's CloudFormation outputs section so readers know how to source the env vars. Cost of skipping: every reader copy-pastes a snippet that fails at runtime with an unhelpful "missing bucket" error.

importantrender-batch doesn't accept --variables-file, but the guide implies a parallel UX with lambda render.
docs/deploy/templates-on-lambda.mdx:74 talks up --variables / --variables-file / --strict-variables as the local iteration loop, then docs/deploy/templates-on-lambda.mdx:90-95 introduces batch and quietly switches to --batch ./users.jsonl. The flag listing in #967's lambda.ts confirms render-batch has no --variables-file — variables are inline in the JSONL only. A reader who internalized "variables-file is the long-form variant" will look for an analog on batch and not find one. Either add an explicit "variables travel in the JSONL — no top-level --variables-file on render-batch" callout, or surface the asymmetry in the batch section header.

importantCost section makes a claim that doesn't match the code.
docs/deploy/templates-on-lambda.mdx:218-219: "pick --max-concurrent to match the reserved concurrency divided by maxParallelChunks" and later "explicitly set --max-concurrent to floor(reservedConcurrency / maxParallelChunks)". --max-concurrent caps StartExecution calls — Step Functions starts — not Lambda invocations. Each started execution then itself fans out to up to maxParallelChunks Lambda calls. The formula buried in the doc is right (concurrency_budget = reserved / fan_out), but the way it's framed in the first paragraph reads like --max-concurrent IS the Lambda cap, which contradicts the explicit clarification in #967's CLI reference: "--max-concurrent is orchestrator-side only: it caps how many StartExecution calls run simultaneously, not how many Lambda invocations the account can run." Tighten the framing so the two paragraphs don't contradict each other.

importantMintlify nav placement.
docs/docs.json:248 inserts deploy/templates-on-lambda between deploy/aws-lambda and deploy/migrating-to-hyperframes-lambda. The "migrating from Remotion inputProps" section at the bottom of THIS guide overlaps with the existing migration guide's scope. Either cross-link them so readers don't get duplicated guidance, or move the inputProps-mapping table into the existing migration guide and trim it here. Currently they're two adjacent pages each making a partial claim about the migration story.

nitCost transparency.
The cost section names the knobs (concurrency, memory, parallel chunks) but never gives a ballpark $ figure per personalised render at default settings. The aws-lambda guide cites ~$1.20 worst-case for a runaway render with --concurrency=8; pull the same shape of estimate in here for "one personalised 5-second template render at defaults" so the reader can size a 10 000-row batch upfront.

nitLong-bash example missing a comment marker on the manifest output.
docs/deploy/templates-on-lambda.mdx:107-115: the manifest block uses Unicode characters — fine in Mintlify, but if anyone pipes the example through grep they'll be confused. Worth a single-line note that the leading symbol is presentational and not in the --json output.

Verdict: REQUEST CHANGES
Reasoning: Two blockers — the invented "object" variable type would silently break any reader who copies the hero example, and at least one of the cross-reference URLs across this stack will 404 once Mintlify deploys. The rest is reconcilable, but those two go to the heart of "the docs ARE the deliverable."

— Vai

@jrusso1020 jrusso1020 force-pushed the 05-19-feat_cli_hyperframes_lambda_render-batch_verb branch from e2a2722 to 3d056a5 Compare May 19, 2026 21:13
@jrusso1020 jrusso1020 force-pushed the 05-19-docs_deploy_templates-on-lambda_guide branch from 0dbb53e to 4b10697 Compare May 19, 2026 21:13
@jrusso1020
Copy link
Copy Markdown
Collaborator Author

Addressed both blockers + the importants in the latest force-push:

Blockers:

  • invented type: "object" — fixed. Variable types table now matches the canonical [string, number, color, boolean, enum] whitelist enforced by packages/core/src/parsers/htmlParser.ts:813. Dropped the nested-object example (would have been silently rejected at parse time) and replaced it with the JSON-string escape-hatch pattern. Added a paragraph naming the failure mode explicitly so readers don't try type: "object" again.
  • URL paths inconsistency — settled on hyperframes.heygen.com as the canonical docs origin. Fixed:
    • docs/packages/cli.mdx cross-link: /docs/deploy/templates-on-lambda/deploy/templates-on-lambda
    • SDK error message (packages/aws-lambda/src/sdk/validateConfig.ts): GitHub blob URL → https://hyperframes.heygen.com/deploy/templates-on-lambda#working-with-large-variables
    • This guide's quoted error message updated to match
    • Plus the config/input field rename from feat(aws-lambda): validate variables + 256 KiB Step Functions input cap #964 reflected in the quoted error

Importants:

  • SDK env vars sourcing — added a paragraph after the SDK example pointing at hyperframes lambda deploy's RenderBucketName / RenderStateMachineArn outputs, with a cross-link to the aws-lambda deploy guide.
  • render-batch flag asymmetry — added a one-line callout: Variables travel inline in each JSONL entry — render-batch does not accept --variables-file because per-entry payloads are the whole point.
  • --max-concurrent framing — cost-and-scale section reworked. The three concurrency layers are now spelled out explicitly: Lambda reserved concurrency, account-level Lambda limit, and orchestrator-side --max-concurrent. The "pick --max-concurrent to match reserved / max-parallel-chunks" framing is now framed as guidance for picking the flag value, not enforcement. The interaction between layers is explicit.
  • site-id placeholder consistent with the CLI examples (abc1234deadbeef0).

Skipping for follow-up:

  • Cost ballpark per render at defaults — agreed valuable; needs a real measurement on a representative composition to be honest about the number.
  • Mintlify nav placement / overlap with migrating-to-hyperframes-lambda — agreed there's some duplication, but the inputProps mapping table works in either location. Defer to the docs-restructure PR rather than juggling content here.
  • Unicode callout in manifest example — minor; leaving.

CI green at 4b106974. Re-review when you have a minute, Vai.

miguel-heygen
miguel-heygen previously approved these changes May 19, 2026
Copy link
Copy Markdown
Collaborator

@miguel-heygen miguel-heygen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed. Both blockers from previous round are addressed:

  1. Invented "object" type — fixed. Type table now lists the correct five canonical types (string/number/color/boolean/enum). Explicit warning paragraph explains why type: "object" is rejected by the parser. Structured data workaround correctly uses type: "string" with JSON serialization.

  2. URL path inconsistency — fixed within this PR. Internal links use correct Mintlify paths (/deploy/aws-lambda). SDK error message uses the full production URL. Cross-stack references in #964/#967 are out of scope for this diff.

All three "important" items also addressed:

  • render-batch lacking --variables-file explicitly documented as intentional
  • SDK example now includes CloudFormation output sourcing guidance
  • Cost section disambiguates --max-concurrent (orchestrator) vs Lambda concurrency (chunk-invoke layer)

CI green. Ready to merge.

vanceingalls
vanceingalls previously approved these changes May 19, 2026
Copy link
Copy Markdown
Collaborator

@vanceingalls vanceingalls left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review post-force-push. Per Magi's verification + James's per-PR response, both prior blockers addressed:

  • Invented "object" variable type removed; the doc's type list now matches the canonical 5 (string / number / color / boolean / enum) per packages/core/src/parsers/htmlParser.ts.
  • URL paths converged on hyperframes.heygen.com format across the stack.

All 3 prior importants also addressed:

  • render-batch --variables-file asymmetry documented.
  • SDK example sources HYPERFRAMES_BUCKET / HYPERFRAMES_SFN_ARN from CloudFormation outputs.
  • Cost section reconciled with --max-concurrent clarification.

Verdict: APPROVE — flipping CHANGES_REQUESTED → APPROVE.

Re-review by Vai

… --strict-variables

Mirror the local hyperframes render variables UX on the Lambda CLI:

- --variables '<json>'       inline JSON object of variable values
- --variables-file <path>    path to a JSON file with variable values
- --strict-variables          fail on type/declared-mismatch (warn by default)

Resolution + validation logic is hoisted to packages/cli/src/utils/variables.ts
so both surfaces share one parser. The new reportVariableIssues helper formats
the warning block + handles --strict-variables exit, deduping the per-CLI
issue-handling block.

Variables flow into SerializableDistributedRenderConfig.variables and reach
every chunk worker via the path PR 9.1 + 9.2 wired up (plan() →
meta/encoder.json → renderChunk() → window.__hfVariables). Pre-validation
against the composition's data-composition-variables declaration runs only
when the project's index.html is on disk — --site-id pointing at a
pre-uploaded site that was packaged elsewhere skips the check, matching how
the local CLI treats unreadable index files.

The render.ts re-exports of parseVariablesArg / resolveVariablesArg /
validateVariablesAgainstProject are dropped; the matching tests move to
packages/cli/src/utils/variables.test.ts where the implementations now live.

Docs: docs/packages/cli.mdx adds a section on --variables / --variables-file /
--strict-variables for lambda render, including the 256 KiB Step Functions
execution-input cap and a pointer to the upcoming templates-on-lambda guide
(PR 9.5).

Phase 9 PR 9.3 of the distributed rendering plan.
New subcommand for automated template-rendering pipelines. Given a
project dir + a JSONL batch file, fans out N personalised renders by
calling renderToLambda once per batch row with per-entry variables and
outputKey:

  hyperframes lambda render-batch ./my-template \
    --batch ./users.jsonl \
    --width 1920 --height 1080 \
    --max-concurrent 10

JSONL format (one JSON object per line):

  {"outputKey": "renders/alice.mp4", "variables": {"name": "Alice"}}
  {"outputKey": "renders/bob.mp4",   "variables": {"name": "Bob"}}

The verb deploys the site once and reuses it across renders (--site-id
skips the deploy when the project was pre-uploaded). Concurrent Step
Functions starts are capped at --max-concurrent (default 50) via a
semaphore so a 10 000-entry batch doesn't try to spawn 10 000
executions simultaneously and trip the AWS account's concurrent-
execution quota.

Per-entry results land in a manifest (one row per input line) with
executionArn + status. --json emits the manifest as machine-readable
JSON. --dry-run prints the manifest with status: "would-invoke" for
every entry without calling AWS, so callers can lint their batch file
before paying for N executions.

Variables in each batch entry pre-validate against the composition's
data-composition-variables declaration (mirroring the local
hyperframes render UX). --strict-variables aborts the run on the first
failing entry before any AWS call. The reportVariableIssues helper from
PR 9.3 is reused so the warning format matches the single-render path
exactly.

Distinction from --max-parallel-chunks: --max-concurrent caps
ORCHESTRATOR-side fan-out (how many StartExecution calls run at once);
--max-parallel-chunks caps chunks PER render. AWS account-level Lambda
concurrent-execution limits live one level up and render-batch can't
enforce those; pick --max-concurrent based on your account quota +
the reserved concurrency you provisioned via lambda deploy.

Tests cover the concurrency-cap semaphore (preserve-order,
peak-in-flight, empty-input, limit > inputs.length, propagate
rejection) and the JSONL parser (blank-line handling, malformed JSON,
missing outputKey, non-object variables).

Phase 9 PR 9.4 of the distributed rendering plan.
User-facing guide for the automated template-rendering pipeline now
shippable end-to-end after PRs 9.1-9.4:

  - What a template is (composition + data-composition-variables)
  - Declaring variables (syntax, types, defaults, getVariables())
  - Local iteration loop (hyperframes render --variables / --variables-file
    / --strict-variables)
  - Deploying to Lambda (pointers to deploy guide + sites create)
  - Single personalised render (lambda render --variables)
  - Batch pipeline (lambda render-batch --batch users.jsonl, with a worked
    5-row example, manifest output, progress polling, --dry-run)
  - Programmatic via SDK (TypeScript example with deploySite +
    Promise.all(renderToLambda))
  - Working with large variables (the 256 KiB Step Functions ceiling,
    URL-your-assets convention, the one-line escape note for genuine
    >256 KiB cases)
  - Cost + scale considerations (Lambda concurrency, max-parallel-chunks
    vs max-concurrent, in-process vs distributed crossover)
  - Migrating from @remotion/lambda inputProps (side-by-side table; same
    256 KiB cap and same URL-your-assets convention, so migration is
    mechanical)

Includes a Mermaid architecture diagram for the site-upload-once +
N-execution fan-out flow at the top.

Adds the guide to the Deploy navigation group in docs.json (between
the existing aws-lambda and migrating-to-hyperframes-lambda pages).

Phase 9 PR 9.5 of the distributed rendering plan — the load-bearing
artifact for the user-facing pitch.
@jrusso1020 jrusso1020 force-pushed the 05-19-feat_cli_hyperframes_lambda_render-batch_verb branch from 3d056a5 to 3b3a955 Compare May 19, 2026 22:51
@jrusso1020 jrusso1020 changed the base branch from 05-19-feat_cli_hyperframes_lambda_render-batch_verb to main May 19, 2026 22:51
@jrusso1020 jrusso1020 dismissed stale reviews from vanceingalls and miguel-heygen May 19, 2026 22:51

The base branch was changed.

@jrusso1020 jrusso1020 force-pushed the 05-19-docs_deploy_templates-on-lambda_guide branch from 4b10697 to a22f5ed Compare May 19, 2026 22:51
Copy link
Copy Markdown
Collaborator

@miguel-heygen miguel-heygen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-approved — same diff, rebased onto main.

Copy link
Copy Markdown
Collaborator

@vanceingalls vanceingalls left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-stamp at the new HEAD after rebase onto main. Same content as my prior approve (4323426136); both blockers + all 3 importants addressed (variable-type list matches canonical 5, URL paths converged, render-batch flag asymmetry documented, SDK CFN env-sourcing added, cost section reconciled). Base now main.

Re-stamp by Vai (post-rebase)

@jrusso1020 jrusso1020 merged commit 480d0cf into main May 19, 2026
44 of 68 checks passed
@jrusso1020 jrusso1020 deleted the 05-19-docs_deploy_templates-on-lambda_guide branch May 19, 2026 23:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants