hyperframes 实测:写 HTML 渲染出 MP4 视频,HeyGen 开源的确定性视频引擎
hyperframes 实测:写 HTML 渲染出 MP4 视频,HeyGen 开源的确定性视频引擎
用代码生成视频,过去两年 Remotion 是默认答案,但它要求你写 React 组件。最近 GitHub 趋势榜上另一个项目走了相反的路:HeyGen 开源的 hyperframes(6.2 万星,Apache-2.0,当天仍有提交),主张视频的源文件就是纯 HTML:写一个 HTML 文件,跑一条命令,出来一个 MP4。没有构建步骤,没有按次渲染收费,人和 AI coding agent 都能写。
我在本机完整跑通了全链路:从 init 到渲出 6 秒 720p 的 H.264 视频。这篇是实测记录。
一、它到底是什么
hyperframes 是一个 monorepo:CLI(hyperframes)、引擎(Puppeteer + FFmpeg)、Studio(本地可视化编辑器)、player、21 个 agent skills、Claude Code 插件,以及 AWS Lambda 渲染分包。用法有三路:本机 CLI、agent skills(让 Claude Code 之类的 agent 代写视频)、托管渲染。
和 Remotion 的核心差异:Remotion 用 React 组件描述视频,hyperframes 用 HTML + data-* 时间属性。渲染时引擎在 headless Chrome 里按帧 seek,FFmpeg 编码。官方宣称同一输入恒定输出(确定性),这对"视频也要能回归测试"的团队是个关键属性。
二、上手:三条命令
官方 quickstart 就三条:
npx hyperframes init my-video
cd my-video
npx hyperframes preview # Studio 实时预览(本地 :3002)
npx hyperframes render # 渲染 MP4
前提条件:Node.js 22+、Chrome(puppeteer cache)、FFmpeg。装完先跑 npx hyperframes doctor 自检,它会逐项打勾/打叉。
三、时间线写在 HTML 属性里
hyperframes 的"编程模型"全在 HTML 属性里。根节点的写法:
<div id="root" data-composition-id="main" data-start="0" data-duration="6"
data-width="1280" data-height="720">
<h1 id="title" class="clip" data-start="0" data-duration="6" data-track-index="0">Hello HyperFrames</h1>
...
</div>
- 根节点上的一组属性声明这条"组合"的元信息:
data-composition-id(组合名)、data-duration(总时长)、data-width / data-height(画布尺寸); - 每个动画元素挂
class="clip"+data-start / data-duration / data-track-index,声明自己在哪条轨道、何时出现; - 动画本体还是熟悉的 GSAP/CSS/Lottie,但 timeline 必须
paused: true并注册到window.__timelines。seek 由引擎驱动,浏览器不自己播,同一份 HTML 每次渲染结果一致。
我实测用的完整 index.html(86 行,GSAP 本地化到 vendor/,可复现):
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=1280, height=720" />
<script src="./vendor/gsap.min.js"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html,
body {
margin: 0;
width: 1280px;
height: 720px;
overflow: hidden;
background: #0b1020;
}
#root {
width: 100%;
height: 100%;
position: relative;
font-family: ui-sans-serif, system-ui, sans-serif;
}
#title {
position: absolute;
top: 200px;
left: 0;
width: 100%;
text-align: center;
color: #f4f4f5;
font-size: 84px;
font-weight: 700;
letter-spacing: -0.03em;
}
#subtitle {
position: absolute;
top: 330px;
left: 0;
width: 100%;
text-align: center;
color: #7dd3fc;
font-size: 32px;
}
#dot {
position: absolute;
top: 480px;
left: 540px;
width: 200px;
height: 200px;
border-radius: 100px;
background: linear-gradient(135deg, #38bdf8, #a78bfa);
}
</style>
</head>
<body>
<div
id="root"
data-composition-id="main"
data-start="0"
data-duration="6"
data-width="1280"
data-height="720"
>
<h1 id="title" class="clip" data-start="0" data-duration="6" data-track-index="0">Hello HyperFrames</h1>
<p id="subtitle" class="clip" data-start="0" data-duration="6" data-track-index="0">HTML in. MP4 out.</p>
<div id="dot" class="clip" data-start="0" data-duration="6" data-track-index="0"></div>
</div>
<script>
const tl = gsap.timeline({ paused: true });
tl.from("#title", { opacity: 0, y: 60, duration: 1, ease: "power3.out" }, 0.2);
tl.from("#subtitle", { opacity: 0, duration: 1, ease: "power2.out" }, 1.0);
tl.fromTo(
"#dot",
{ x: -320, scale: 0.4, rotation: 0 },
{ x: 320, scale: 1, rotation: 180, duration: 2.4, ease: "back.inOut(1.4)" },
1.4
);
window.__timelines = window.__timelines || {};
window.__timelines.main = tl;
tl.seek(0);
</script>
</body>
</html>
四、我的实测:6 秒 720p
渲染产物(真实文件,ffprobe 实测参数):
- 142,277 字节 · 6.000s · 1280×720 · H.264 High/yuv420p · 30fps · 180 帧 · ~187kbps · bt709,容器 metadata 里带
hyperframes_version=0.8.151; - 渲染耗时两次实测,条件不同:首次 1m33.4s(含首次环境准备:setup 36.5s + capture 43.3s + assemble 0.5s);环境就绪后重跑 14.9s(compile 0.3s + setup 5.3s + capture 9.1s + assemble 0.1s)。两次日志均标注 encode 与 capture 并行(encode during capture),不另计耗时。静态帧复用 65/245(27%,省约 585ms),抽取 4 个基准帧(第 45/90/135/171 帧)做 PSNR 自校验(50.6~56.2dB);
snapshot命令出 5 个关键帧 + contact-sheet 拼图(给 AI review 用的,细节到位);- Studio(localhost:3002)是完整本地编辑器:Compositions / Preview / Timeline / Inspector / Lint 五个面板,不渲染也能逐帧检查。
180 帧 = 6s × 30fps,与 data-duration="6" 精确一致。同一份输入重跑两次,产物 md5 一致。
五、踩坑记录(六个)
1. git clone 在我的网络环境必失败(代理 502 / handshake 错,连试 10+ 次)。对策:npm pack hyperframes 拿官方 tarball(6.9MB),README/提交历史用 GitHub API 补;
2. npm install 报 EUNSUPPORTEDPROTOCOL workspace:。npm 包是 monorepo 裁剪版,devDependencies 里 23 个 workspace:* npm 解析不了,删掉 devDependencies 走 npm install --omit=dev;
3. esbuild 安装脚本 EBUSY(Windows 通病)。用 npm install --ignore-scripts,esbuild/sharp 都带预编译 optional 包,跳脚本无碍;
4. 缺 FFmpeg 直接没法编码(doctor 明确报错)。省事的路径是 npm 二进制包 @ffmpeg-installer/win32-x64 + ffprobe-static,再设 HYPERFRAMES_FFMPEG_PATH / HYPERFRAMES_FFPROBE_PATH 两个环境变量(dist 代码实测认这两个变量);
5. init 时会顺带去 GitHub clone skills。网络不通会失败,但项目文件已完整生成,render 不受影响;
6. 模板默认引 CDN 的 gsap。离线环境把 gsap.min.js 下到 ./vendor/ 改本地引用即可。
(另两个小坑:validate 已 deprecated 推荐用 check;preview 的 daemon 在某些环境要加 --foreground 才存活。)
六、适合谁用
适合:只会 HTML/CSS/JS 不想碰 React 的人;要求确定性、可回归、CI 批量出片的团队;想让 agent 代写视频的 agent 工作流(21 个 skills + 插件开箱即用)。
边界:渲染时长与帧数近似线性(首次 720p/180 帧约 1.5 分钟,环境就绪后 15 秒;1080p 预计数倍);npm 包是 monorepo 裁剪版( workspace 协议要手动处理);纯本地渲染不需要 API key,但 cloud render / lambda / publish / TTS 配乐这些需要 HeyGen 账号或外部服务(本次未验证)。
参考与署名:本文实测项目为 heygen-com/hyperframes(Apache License 2.0,实测版本 npm hyperframes@0.8.151);文中示例代码、渲染产物参数均为本次实跑记录;运行环境 Node.js 22.22.2 / Windows。
- 点赞
- 收藏
- 关注作者
评论(0)