部署

Lambda 上的模板

在 AWS Lambda 上使用 --variables 和 lambda render-batch 命令大规模渲染个性化模板视频。

HyperFrames 模板是接受类型化变量(名称、颜色、图表数据、CTA URL)并生成由这些值参数化的成品渲染的 composition。将模板与已部署的 Lambda 栈和 lambda render-batch 配合使用,只需一条 CLI 命令即可实现大规模个性化视频生成:

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

本指南涵盖完整流程:在 composition 上声明变量、使用 hyperframes render 进行本地迭代、一次性部署到 Lambda,然后从批量文件中展开 N 次渲染。同样的流程也适用于通过 lambda render --variables 进行的单次个性化渲染,以及通过 renderToLambda({ variables }) 进行的编程式批量渲染。

flowchart LR
A["本地迭代<br/>hyperframes render --variables"] --> B["部署栈<br/>hyperframes lambda deploy"]
B --> C["一次性上传站点<br/>hyperframes lambda sites create"]
C --> D["展开批量渲染<br/>hyperframes lambda render-batch"]
D --> E["N 个个性化视频<br/>在 S3 中"]

什么是模板

模板就是一个 HyperFrames composition,其顶层 HTML 元素声明了 data-composition-variables 属性,列出了它接受的变量。composition 通过 window.__hyperframes.getVariables() 读取运行时值。

<!doctype html>
<html
data-composition-variables='[
{"id":"title","type":"string","label":"Headline","default":"Welcome"},
{"id":"accentColor","type":"string","label":"Accent","default":"#0a0a0a"},
{"id":"avatarUrl","type":"string","label":"Avatar image","default":"/avatars/default.png"}
]'
>
<head><meta charset="utf-8"><title>Welcome template</title></head>
<body style="margin:0;background:#f6f5f1">
<div data-composition-id="root" data-width="1920" data-height="1080" data-duration="5">
<h1 id="title" style="font:80px Inter,sans-serif">Welcome</h1>
<div id="accent" style="width:100%;height:8px"></div>
<img id="avatar" alt="" style="width:240px;height:240px;border-radius:50%" />
</div>
<script>
(function () {
var v = window.__hyperframes.getVariables();
document.getElementById("title").textContent = v.title;
document.getElementById("accent").style.background = v.accentColor;
document.getElementById("avatar").src = v.avatarUrl;
})();
</script>
</body>
</html>

运行时辅助函数以全局变量的形式暴露——window.__hyperframes.getVariables()——而不是可导入的模块。使用普通 <script>(而非 <script type="module">),确保脚本执行时运行时已初始化。

声明变量

data-composition-variables 数组中的每个条目描述一个变量。支持的字段:

字段必填示例
id"title"
type"string""number""color""boolean""enum"
label推荐"Headline"
default推荐"Welcome"

详见 Variables 了解每种类型的编辑器组件和仅用于 "enum"options 字段。

getVariables() 返回声明的默认值与调用者覆盖值的合并结果,因此具有合理默认值的 composition 在预览模式和生产环境中无需更改即可渲染。渲染时的覆盖来自 CLI 上的 --variables '{...}' 或 SDK 的 renderToLambda 调用中的 variables 字段。

变量是类型化的原始值;对于结构化数据(项目列表、嵌套记录),请在调用者侧序列化,在 composition 内部解析:

<html data-composition-variables='[
{"id":"heroJson","type":"string","label":"Hero copy (JSON)","default":"{\"title\":\"Hi\"}"}
]'>

运行时不会接受声明中的 type: "object"——解析器会拒绝五种规范类型之外的任何内容并静默丢弃该声明,因此 --strict-variables 会将每个未声明的键标记出来。

本地迭代循环

快速迭代是模板的全部意义——你不需要部署到 Lambda 就能看到效果。在本地使用 hyperframes render 配合 --variables(或 --variables-file)来针对任意负载渲染模板:

hyperframes render --variables '{"title":"Hello Alice","accentColor":"#ff0000"}' \
--output renders/alice-preview.mp4

传入 --strict-variables 可以在类型与 data-composition-variables 声明不匹配时报错。不带该标志时,不匹配会显示为警告,渲染继续进行。

hyperframes render --variables-file ./alice.json --strict-variables \
--output renders/alice-preview.mp4

部署到 Lambda

模板在标准的 hyperframes lambda 栈上渲染——没有专门的模板部署模式。运行:

hyperframes lambda deploy

每个 AWS 账户/区域只需运行一次。aws-lambda 部署指南 涵盖了 SAM 栈、IAM 策略和 CloudFormation 输出。

当同一模板需要生成多次渲染时,先用 lambda sites create 一次性上传项目,然后在后续每次渲染或批量中引用其内容寻址的 siteId

hyperframes lambda sites create ./my-template
# → Site ID: abc1234deadbeef0

单次个性化渲染

对于一次性渲染,传入 --site-id 加上每次渲染的 --variables。CLI 从 siteId 合成最小的站点句柄(无需重新打包)并调用 renderToLambda

hyperframes lambda render ./my-template \
--site-id abc1234deadbeef0 \
--width 1920 --height 1080 \
--variables '{"title":"Hello Alice","accentColor":"#ff0000"}' \
--output-key renders/alice.mp4 \
--wait

--wait 会流式输出进度行直到渲染完成;不带该标志时 CLI 立即返回,你可以通过 hyperframes lambda progress <renderId> 轮询。

批量流水线(核心功能)

lambda render-batch 是核心的便捷功能:一条 CLI 命令即可调度 N 次个性化渲染。编写一个 JSONL 文件,每个接收者一行:

{"outputKey": "renders/alice.mp4", "variables": {"title": "Hi Alice", "accentColor": "#ff0000"}}
{"outputKey": "renders/bob.mp4",   "variables": {"title": "Hi Bob",   "accentColor": "#00aa00"}}
{"outputKey": "renders/carol.mp4", "variables": {"title": "Hi Carol", "accentColor": "#0000ff"}}
{"outputKey": "renders/dave.mp4",  "variables": {"title": "Hi Dave",  "accentColor": "#ff00aa"}}
{"outputKey": "renders/erin.mp4",  "variables": {"title": "Hi Erin",  "accentColor": "#aa00ff"}}

运行批量任务:

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

该命令会一次性部署站点(或使用 --site-id 跳过),然后对每一行调用 renderToLambda。变量内联在每个 JSONL 条目中——render-batch 不接受 --variables-file,因为按条目传入负载正是其设计目的。并发的 Step Functions 启动数量受限于 --max-concurrent(默认 50),这样 10,000 条的批量任务不会尝试同时启动 10,000 个执行并触发 AWS 账户的并发执行限制。

清单输出对每个输入行给出一行结果:

Batch dispatched: 5 started, 0 failed-to-start.

✓ line 1  renders/alice.mp4  arn:aws:states:us-east-1:1234:execution:hf:hf-render-...
✓ line 2  renders/bob.mp4    arn:aws:states:us-east-1:1234:execution:hf:hf-render-...
✓ line 3  renders/carol.mp4  arn:aws:states:us-east-1:1234:execution:hf:hf-render-...
✓ line 4  renders/dave.mp4   arn:aws:states:us-east-1:1234:execution:hf:hf-render-...
✓ line 5  renders/erin.mp4   arn:aws:states:us-east-1:1234:execution:hf:hf-render-...

添加 --json 获取机器可读的格式,你的批量协调器可以管道传给 jq

hyperframes lambda render-batch ./my-template --batch ./users.jsonl \
--width 1920 --height 1080 --json \
| jq -r '.[] | select(.status == "started") | .executionArn'

使用 lambda progress 轮询每个 executionArn(或 renderId)以跟踪完成状态:

hyperframes lambda progress arn:aws:states:us-east-1:1234:execution:hf:hf-render-abcd

使用 --dry-run 在产生任何执行费用之前检查批量文件。每个条目的状态变为 would-invoke

hyperframes lambda render-batch ./my-template --batch ./users.jsonl \
--width 1920 --height 1080 --dry-run --json

通过 SDK 编程式调用

同样的功能可以通过 @hyperframes/aws-lambda/sdk 从 TypeScript 调用。一次性部署站点,然后并行渲染批量任务:

import { deploySite, renderToLambda } from "@hyperframes/aws-lambda/sdk";

const users = [
{ name: "Alice", accentColor: "#ff0000" },
{ name: "Bob",   accentColor: "#00aa00" },
// … 1 000 more rows …
];

const siteHandle = await deploySite({
projectDir: "./my-template",
bucketName: process.env.HYPERFRAMES_BUCKET!,
});

const handles = await Promise.all(
users.map((user) =>
renderToLambda({
siteHandle,
bucketName: process.env.HYPERFRAMES_BUCKET!,
stateMachineArn: process.env.HYPERFRAMES_SFN_ARN!,
config: {
fps: 30,
width: 1920,
height: 1080,
format: "mp4",
variables: { title: `Hello ${user.name}`, accentColor: user.accentColor },
},
outputKey: `renders/${user.name.toLowerCase()}.mp4`,
}),
),
);

console.log(`Started ${handles.length} renders`);

HYPERFRAMES_BUCKETHYPERFRAMES_SFN_ARN 来自部署栈。hyperframes lambda deploy 会将它们打印为 RenderBucketNameRenderStateMachineArn,也可以通过 aws cloudformation describe-stacks --query "Stacks[0].Outputs" 获取。完整的 CloudFormation 输出表请参阅 aws-lambda 部署指南

当批量任务足够大,无限制的突发可能会触发你的 AWS Lambda 并发执行配额时,请用信号量包装 Promise.all(或使用 CLI 的 runWithConcurrencyLimit 模式)。

处理大变量

变量在 Step Functions 标准执行输入中传输,AWS 对整个输入(不仅仅是变量——限制是针对完整序列化载荷的)限制为 256 KiB。Express 工作流限制为 32 KiB;我们使用 Standard 是为了执行历史可见性,因此适用 256 KiB 的限制。

SDK 在客户端验证大小,在任何 AWS 调用之前拒绝超大输入并给出清晰的错误信息:

[validateConfig] config: Step Functions execution input is 287422 bytes,
which exceeds the 262144-byte (256 KiB) limit for Standard workflows.
Variables are for typed data (strings, numbers, structured records);
media assets (images, audio, video) should be passed as URL references
he composition resolves at render time, not inlined as base64. See
https://hyperframes.heygen.com/deploy/templates-on-lambda#working-with-large-variables
for the URL-your-assets convention.

规范:变量用于类型化数据;媒体资源是 composition 在渲染时解析的 URL 引用。

正确做法:

{
"title": "Hello Alice",
"accentColor": "#ff0000",
"avatarUrl": "https://cdn.example.com/avatars/alice.png"
}

错误做法(任何稍大的图片都会超出限制):

{
"title": "Hello Alice",
"avatarBase64": "data:image/png;base64,iVBORw0KGgoAAAANSUh..."
}

在 composition 中,将变量绑定到 DOM 的脚本直接使用 URL——Lambda chunk worker 在捕获期间通过文件服务器获取资源,与本地渲染器的方式相同:

<script>
(function () {
var v = window.__hyperframes.getVariables();
document.getElementById("avatar").src = v.avatarUrl;
})();
</script>

同样的限制适用于 Remotion 的 inputProps——如果你从 @remotion/lambda 迁移过来,你的载荷应该已经是这种结构。

如果你的类型化数据载荷确实超过 256 KiB(例如每次渲染有很长的结构化记录且没有媒体资源),请提交 issue——通过 S3 托管变量文件有一个清晰的路径,但我们希望在设计 API 之前看到真实的需求。

费用与规模

每次个性化渲染是一次 Step Functions 执行 + N 次 chunk Lambda 调用。按默认设置(chunkSize: 240maxParallelChunks: 16),一个 5 秒 30fps 的 composition 为 1 个 chunk;一个 60 秒的 composition 约为 8 个 chunk。

费用调节参数:

  • --max-parallel-chunks:每次渲染,默认 16。较小的 composition 不会展开超过 ceil(totalFrames / chunkSize)。更高的值会增加 Lambda 调用费用但完成更快。
  • Lambda 预留并发lambda deploy --concurrency=<N>):限制渲染函数可以并行运行的 Lambda 调用数量。同一 AWS 账户中的其他工作负载共享相同的账户级并发池(大多数区域默认约 1,000),因此预留并发可以防止渲染函数饿死其他工作负载,反之亦然。
  • render-batch --max-concurrent:编排器侧。限制同时运行的 StartExecution 调用数量——与 Lambda 并发限制不同,后者位于更低一层的 chunk 调用层。CLI 无法强制执行 Lambda 的账户限制;它只能避免创建过多排队的 Step Functions 执行。
  • Lambda 内存lambda deploy --memory):默认 10,240 MB(最大值)。更高的内存意味着更快的 Chrome 捕获 + 每个 chunk 更多的 vCPU;更低的内存节省费用但可能在重型 composition 上触发 15 分钟超时。

每次 Step Functions 执行会展开到约 maxParallelChunks 个 Lambda 调用。因此,如果部署的预留并发为 8 而 maxParallelChunks 保持默认的 16,即使单次渲染也会被限流——在运行大批量任务之前请提高部署并发数。

对于小批量(< 100 条),默认的 --max-concurrent 50 即可。对于大批量(> 1,000),一个有用的起点是 --max-concurrent ≈ floor(reservedConcurrency / maxParallelChunks),使每个运行中的渲染获得完整的 chunk fan-out 预算;批量命令不会强制执行此值,这只是选择该标志值的参考。

进程内 vs 分布式交叉点:对于约 30 秒以下的单次渲染,进程内渲染器(hyperframes render)在延迟上更优,因为没有每个 chunk 的 S3 往返。分布式渲染在超过约 60 秒的渲染或需要个性化批量时更优——这就是该功能存在的全部原因。(Phase 7 的小型渲染快捷方式在上线后将缩小短渲染的差距。)

从 @remotion/lambda inputProps 迁移

Remotion 的 inputProps API 和 HyperFrames 的 variables 是同构的——两者都是在声明的 composition 默认值之上注入的渲染时覆盖的 JSON 对象。映射是机械化的:

RemotionHyperFrames
Composition.defaultProps根 HTML 元素上的 data-composition-variables 声明
useCurrentFrame() + props.<x>window.__hyperframes.getVariables().<x>(在 DOMContentLoaded 时读取一次)
renderMediaOnLambda({ inputProps })renderToLambda({ config: { variables } })
Lambda inputProps 256 KiB 限制Step Functions 执行输入 256 KiB 限制
inputProps URL 化大媒体模式相同规范——URL 引用,而非内联字节

Remotion 的 inputProps 有相同的 256 KiB 限制和相同的"URL 化你的资源"规范,因此迁移一个正常工作的 inputProps 流程是直接的 CLI/SDK 替换,而非载荷重构。

下一步

  • 更小的批量原语:除 JSONL 外支持 HTML 格式输入。如果你觉得有用请提交 issue。
  • data-composition-variables 生成 TypeScript 类型hyperframes types generate <projectDir> 已有设计,可能在 v1.5 中实现;它将允许 SDK 调用者 import type { Variables } from "./template/variables" 以获得自动补全和类型检查。
  • HDR 模板支持:HDR mp4 目前在分布式模式下被拒绝(仅支持进程内)。v1.5 的下一个目标是为分布式渲染解锁 HDR,使模板可以生成广色域输出。

如果你的模板流水线遇到了文档未覆盖的问题,请在 GitHub 上提交 issue——批量功能是新的,反馈循环很短。