Skip to content
←返回开源项目

OPEN SOURCE DEEP DIVE

Video RenderingHTML-Native VideoDeterministic Rendering

HyperFrames:写 HTML 就能渲染视频、为 Agent 而生的开源确定性视频引擎

HeyGen 开源的 HyperFrames 把视频定义成带 data-* 时间属性的 HTML:无构建步骤、index.html 直接可播可预览;渲染时无头 Chrome 逐帧 seek 抓取、FFmpeg 编码,同一输入永远得到同一支 MP4。它自带 21 个 agent 技能、frame.md 设计系统转译层与 Catalog 组件库,Claude Code / Codex / Cursor 等编码代理可以跑完 plan—write—lint—preview—render 的整条生产循环;AWS Lambda 路径支持分布式渲染。Apache-2.0,无按次渲染费用。

heygen-com/hyperframes63kTypeScriptApache-2.05 min read

一句话定位

HyperFrames 是 HeyGen 开源的HTML 原生视频渲染框架:把一支视频写成一个带时间属性的 HTML 文件,由无头 Chrome 逐帧 seek 抓取、FFmpeg 编码成 MP4。它的口号只有三句话——写 HTML、渲视频、为 Agent 而生。仓库 heygen-com/hyperframes,Apache-2.0 许可,无按次渲染费用、无商用门槛;HeyGen 自己在生产环境用它,tldraw、TanStack 等团队列在 ADOPTERS.md 里。

它要解决的不是「再做一个剪辑器」,而是视频生产的交接问题:React 时间线、专有工程格式都是人类工具的方言,AI 编码代理写不好也改不动。HyperFrames 的赌注是——代理本来就会写 HTML,那就让视频的源码就是 HTML:无构建步骤、index.html 直接在浏览器里播、CLI 全程非交互,于是「plan → 写 HTML → 接动画 → 加媒体 → lint → preview → render」整条生产循环可以完全交给代理跑。

下面这张是官方 Studio 的主视觉:编辑器长在浏览器里,画布上那句「Anything a browser can render can be a frame」就是整个项目的世界观。

HyperFrames Studio:为 Agent 而生的视频编辑器

数据面

项值
仓库heygen-com/hyperframes(Apache-2.0,主语言 TypeScript)
Stars / Forks / Watchers(采集时快照)62,903 / 5,643 / 166
建仓 / 最近推送2026-03-10 / 2026-10-14
运行依赖Node.js 22+、FFmpeg;分布式渲染走 AWS Lambda
官网 / 文档hyperframes.dev(playground 与 frame.md 画廊)/ hyperframes.heygen.com(文档、Catalog、Showcase)
包结构hyperframes(CLI)、@hyperframes/core、engine、producer、studio、player、shader-transitions、aws-lambda
Agent 面21 个发布技能 + /hyperframes 路由技能、Claude Code 插件市场、MCP、Figma 导入
回归基线Git LFS 金样视频约 240MB(packages/producer/tests/**/output.mp4),逐帧比对守确定性

合成契约:时间写在属性里,不写在脚本里

一支视频就是一个合成(composition)。根元素声明 data-composition-id 与输出尺寸,每个 timed 元素加 class="clip" 和三个时间属性:data-start 何时入场、data-duration 占多久、data-track-index 落在 Studio 的哪一条道。运行时按 data-start 控制可见性,.clip 只负责给场景一个满幅盒子;轨道不是图层——前后遮挡永远由 CSS z-index 决定,轨道只是 Studio 画出来的行,渲染器根本不看它。

<div id="stage" data-composition-id="launch" data-start="0" data-width="1920" data-height="1080">
  <video class="clip" data-start="0" data-duration="6" data-track-index="0"
         src="intro.mp4" muted playsinline></video>
  <h1 id="title" class="clip" data-start="1" data-duration="4" data-track-index="1">Launch day</h1>
  <audio data-start="0" data-duration="6" data-track-index="2" data-volume="0.5" src="music.wav"></audio>
</div>

时间还可以引用别的片段:data-start="intro" 表示「intro 结束时我开始」,data-start="intro - 0.5" 就是提前半秒叠进来做交叉淡入;引用只在同一合成内解析、被引片段必须有确定时长、引用链不许成环。嵌套合成用 data-composition-src 指向另一个 HTML 文件,被引文件把内容包在 <template> 里,路径一律从项目根解析——嵌套两层也写 compositions/foo.html,不写 ../。媒体元素另有一组精确契约:源偏移、播放速率、音量。文档里连 CSS 的坑都写成了规则:负 z-index 的背景层可能被不创建层叠上下文的祖先背景盖住,补一句 isolation: isolate 才在浏览器、snapshot 与 render 三处都可见;hyperframes lint 会把 negative_z_index 报成警告而不是错误。

能做什么:从发布片到图表竞赛

官方把适用面列得很具体:产品发布与功能宣告片;带代码 diff 动画、旁白与字幕的 PR walkthrough;数据可视化、图表竞赛(chart race)与地图动画;带动能字幕、叠层与音乐的社交视频;docs-to-video、PDF-to-video 与站点导览讲解片;以及内容流水线里可复用的动效件。共性是:这些视频的每一帧都可以被代码描述、被版本控制、被 CI 重放。桌面端也已就位——README 的头图动图展示的就是原生 Mac / Linux 应用从 Dock 打开、在提示框里写一句「这支视频讲什么」即可开工的流程,@ 可以引用项目或媒体素材。

HyperFrames 桌面应用的提示入口:说一句视频讲什么即可开工

确定性渲染:帧号是唯一的变量

「同一输入永远得到同一支视频」是其余一切的地基——自动化流水线、CI 回归、AI 改稿敢不敢信它,全看这一条。实现方式很硬:渲染从不「播放」视频,它一帧一帧地问「第 90 帧长什么样」,而答案只依赖一个会变的量:数字 90。帧时钟用整数算术算时间 t = floor(frame) / fps,全程不查真实时钟;每个动画被 seek 到恰好 t,而不是播放到 t;Chrome 的 HeadlessExperimental.beginFrame 把像素一次性原子抓走,不留半画完的帧;FFmpeg 再把抓到的帧编成 MP4,并把 <audio> 与 <video> 里的声音混进去。

flowchart TD F["第 90 帧"] --> T["t = floor(90 / fps)
整数算术,不查墙钟"] L["第 0 帧前已锁定:
fps / 宽 / 高 / 变量"] --> T T --> S["所有动画 seek 到恰好 t
GSAP 时间线 paused+seek,从不 play"] S --> P["beginFrame 原子抓取 → FFmpeg 编码
每次运行同一批像素"] S -.-> X["会破坏确定性的写法:
Date.now / 未播种的 Math.random / 渲染中途 fetch"]

于是规则短得可以背:不用墙钟(Date.now()、requestAnimationFrame、系统定时器全禁)、不用未播种随机、渲染中途不 fetch(所有资产在第 0 帧前加载完)、输出尺寸固定、长度有限。跨机器还有一层:字体与 Chrome 版本不同会让本地渲染差出一个像素,需要逐像素复现时 npx hyperframes render --docker 把 Chromium 版本、字体集、FFmpeg 编码器一起钉死,平台就不再是输入。预览与渲染之所以长得一样,是因为两边跑同一个 hyperframe.runtime,producer 的 seek 行为是唯一事实来源,__playerReady 与 __renderReady 两道门把抓取按住直到合成完全加载。速度则相反:预览是实时播放、吃你的硬件;渲染是 seek 驱动、一帧一帧要,再贵的帧也不丢——预览里卡顿的合成,渲染出来依然完美。

运行时与 seek 协议:预览、Studio、producer 说同一种话

运行时把稳定面收敛成几个全局量:window.__player、window.__playerReady、window.__renderReady、window.__timelines、window.__clipManifest;父子通信走 postMessage——父侧以 source: "hf-parent" 发 play / pause / seek / set-muted / set-playback-rate / 拾取模式开关,运行时以 source: "hf-preview" 回 state(整帧状态 + 精确秒数 + ended,父侧靠 ended 收尾而不是比时间)、timeline(媒体/图片/字体是否 settle)、assets-ready 与 ready(控制桥注册完成,父侧借此重放此前发出的控制消息,iframe 每次重载都会再发一次)。协议版本化:RUNTIME_PROTOCOL_VERSION = 1,能力清单写着 seconds-time、rational-fps、seek-keep-playing、composition-manifest-v1、runtime-data、play-range,fps 用分子/分母的有理数表达而不是浮点;producer 在渲染前会校验 manifest 里钉死的运行时 checksum,运行时 bootstrap URL 必须版本钉死 + 主机白名单,iframe 桥 payload 要过 schema 校验,javascript: 与未批准的 data: 一律拒掉,握手不健康就 fail closed。

帧适配器:任何动画库都能被 seek

动画层是插件化的:GSAP、CSS 动画、Lottie、Three.js、Anime.js、WAAPI,或者你自己写的帧适配器。契约只有四条:seekFrame(frame) 对同一帧号永远给同一结果;seek 可以任意顺序来(渲染器会跳着要帧);帧提交之后不许再有异步决议;生命周期固定 init → seekFrame(多次) → destroy。GSAP 的用法被拧成一条纪律:时间线 paused: true 创建、挂到 window.__timelines[compositionId],由运行时按帧 seek——库时钟的动画在这里是帧精确的,这正是它与墙钟动画模式的根本差别。仓库里还有配套的诊断命令 hyperframes keyframes,把渲染出来的运动反过来检查一遍。

渲染管线:从抓取到编码的工程纵深

engine 包是这套确定性的执行体,代码体量本身就说明了问题:frameCapture.ts 约 218KB,管逐帧抓取、warmup、静态帧去重、motion blur、子时间线 memo;videoFrameExtractor.ts 约 102KB,把输入视频按区间解成帧并带下载缓存与错误分类;audioMixer.ts 约 64KB 负责混音与淡入淡出分组;chunkEncoder.ts / streamingEncoder.ts 走分块与流式编码;parallelCoordinator.ts 加 browserLeasePool.ts 把多工作浏览器租出去并行抓帧;screenshotService / drawElementService 两条抓取路径按 GPU 能力切换;另有 hdrCapture、threeDProjection、chromeMemorySampler 与 systemMemory(低内存主机自动降档)、extractionCache、fileServer。错误约定也写成了制度:编排类服务失败就抛;FFmpeg 进程包装永远返回 { success, error? } 不 reject;清理函数吞掉一切异常,绝不掩盖原始失败。

确定性的另一道闸是金样回归:packages/producer/tests/**/output.mp4 下约 240MB 的基线视频走 Git LFS,改管线就要过逐帧比对;测试体量同样夸张(init.test.ts 约 248KB、videoFrameExtractor.test.ts 约 141KB)。分布式渲染有两条现成路径:本地多浏览器并行,以及 @hyperframes/aws-lambda 把渲染栈部署到 Lambda、从笔记本或 CI 驱动——文档直说 Remotion Lambda 更成熟,这是它承认的差距。

抓取路径上还有几处值得点名的工程:静态帧去重——时间线上没动的区间不重复抓,直接复用已提交的帧;motion blur 走子帧采样而不是事后滤镜;HDR 与色彩管理单独立了 hdrCapture 与一套 152KB 的 colorGrading(曲线、LUT、媒体级调色分析),SDR 抓到带标签的 BT.709 有专用滤镜串;4K 渲染与性能指南把「预览卡不等于渲染卡」讲透:渲染按帧要画面,丢帧在数学上不存在。并行侧,parallelCoordinator 负责把工作帧分给租约池里的多个无头浏览器,peer 中止要能单独失败而不拖垮整批;内存侧,cgroup 限额与主机总内存会被采样,低内存机器自动收敛并发——这些都不是文档口号,是带测试文件的实现。

音频不是事后补的:carve、效果链与子混音总线

声音在合成里是一等公民:<audio> 与 <video> 的音轨由 producer 混进成片。技能 /hyperframes-audio 覆盖三层:voiceover carve——只在人声实际占据的频段把音乐床让开(静态或动态),顺带做电平匹配;效果链——EQ、压缩、限制、门、饱和、延迟、混响、合唱、镶边、bitcrush;自动化包络——音量或任何效果参数都能画曲线;<hf-audio-group> 子混音总线让多条轨共用一条效果链、一个推子和一个自动化时钟。预览侧由 webAudioTransport 保证「听到的」与「渲出来的」是同一套算法。取素材则是 /media-use 这个「媒体操作系统」:BGM、音效、图、图标、logo、配音、调色、LUT 一律解析成冻住的本地文件或可粘贴块 + 台账记录,目录里没有就调 TTS/音乐/图像模型生成,顺带转写、上字幕、抠背景、跨项目复用。

工程文化:把确定性写进测试与契约

读源码时最扎眼的不是功能,而是测试与实现的体量比:audioMixer.ts 64KB 配 56KB 测试,screenshotService.ts 40KB 配 39KB 测试,videoFrameExtractor.ts 102KB 配 141KB 测试,init.ts 226KB 配 248KB 测试——几乎每个模块都带一个同量级的 .test.ts 兄弟文件,命名细到 frameCapture-staticDedupBoundary、clock-drift、clock-stall、pausedTransportInvariant 这种「一个失败模式一个文件」的粒度。契约也不散落在注释里:docs/contracts/ 下是带日期的契约fixture(如 2026-10-07 的合成探针与 document-idle 就绪页),运行时的错误约定、清理语义、可空查询的返回值策略写在 engine 的包级文档头里;canary 与 canaryRegistry 把「哪条路径一旦回归就要立刻红」登记成册;写文件走 atomicFile(先临时后替换),路径解析走 safePath 并配 9KB 的穿越攻击测试。一个把视频当产物交付的框架,先把自己当成了需要被回归的系统。

Agent 原生:21 个技能与一个路由

HyperFrames 把「教代理做视频」做成了产品面:发布 21 个技能,入口是 /hyperframes 路由技能——它是一张能力地图,对任何「给我做一支……」的请求先选工作流(视频 / 幻灯片 / 移植 Remotion 工程),再按需装领域技能。创建类工作流包括 /motion-graphics(十秒内无旁白的设计向动效)、/music-to-video(beat 对齐的歌词片/幻灯/动能promo)、/talking-head-recut(给访谈素材加设计感图形叠层)、/embedded-captions(字幕嵌入)、/slideshow(可导航演示稿)、/general-video(兜底与共创模式)与 /remotion-to-hyperframes(单向移植);领域技能覆盖合成契约、动画知识、seek-safe 关键帧、创意方向、媒体、CLI、音频、注册表与 Figma。安装面也分得很细:Claude Code 走版本化插件市场(claude plugin marketplace add heygen-com/hyperframes),独立技能走 npx skills add heygen-com/hyperframes,而非交互与代理场景应该用 npx hyperframes skills update——它从当前 main 装恰好核心集,而 skills.sh 的注册表 blob 可能滞后 main 几个小时。CLI 默认非交互,init / lint / check / snapshot / preview / render / publish / doctor 加云渲染与 Lambda 子命令,Codex、Cursor、Gemini CLI、IBM Bob 等支持技能的代理都能直接跑这条生产循环。

创建类工作流与领域技能的分工如下表:路由技能只负责选路,工作流技能负责「做一支什么片」,领域技能负责某一层原子能力,按需拉取、用完即走。

技能覆盖的创作任务
/motion-graphics十秒内、无旁白的设计向动效:动能字体、数据/图表hit、logo sting、动态推文标题,可出透明叠层
/music-to-video一条音乐(音频文件、从视频抽的音轨、或按情绪brief生成)→ beat 对齐的歌词片/幻灯/动能promo
/talking-head-recut给访谈/播客素材加设计感图形叠层:lower-thirds、数据callout、动能标题、pull-quote、侧栏、PiP
/embedded-captions给已有口播视频嵌字幕(素材不动):逐字轨、主体身后嵌入式高潮、纯电影感嵌入
/slideshow演示稿/路演稿:离散幻灯片、fragment 揭示、分支与热点导航、讲者模式,产出可导航deck而非视频
/general-video其余一切:多场景长片、品牌sizzle、标题卡、静态loop;共创模式(全工具箱协同)的家
/remotion-to-hyperframes把既有 Remotion(React)合成源码单向移植为 HyperFrames HTML

frame.md:把设计系统翻译给镜头

每个品牌都有 design.md,但没有人是为镜头写的。frame.md 是 HyperFrames 补的那层翻译:同一批 token、同一套规则,按「镜头」反写一遍——比例、出血、字幕安全区、动效节奏,让代理不必猜尺度、也不会把网页的 chrome 搬进画面。产出是 DESIGN.md 的超集,整条工具链都能读;原则是「原子神圣、合成自由、数字来自脚本」。画廊在 hyperframes.dev/design,Biennale Yellow、Blockframe、Blue Professional、Bold Poster、Broadside、Capsule、Cartesian、Cobalt Grid 等模板可以直接 remix;设计交接另有 Claude Design 与 Open Design 两份指南,Figma 侧能把资产、token、组件与故事板段导入并重建为运动(帧被读成状态而不是幻灯片),Motion 动画与 shader 走 MCP。

生态位:与 Remotion 正面相认

HyperFrames 不避讳自己受 Remotion 启发——两者都用无头 Chrome 抓帧、FFmpeg 编码。真正的分歧在创作模型:Remotion 押 React 组件,HyperFrames 押「人和代理都写得动的纯 HTML」。

维度HyperFramesRemotion
创作载体HTML + CSS + 可 seek 动画React 组件
构建步骤无;index.html 直接可播需要打包器
交给代理的形式纯 HTML 文件JSX / React 工程
库时钟动画适配器 seek,帧精确墙钟动画模式需小心
分布式渲染本地并行 + AWS LambdaRemotion Lambda,更成熟
许可Apache-2.0source-available 的 Remotion License

围绕引擎的外圈也在长:Catalog 用 npx hyperframes add flash-through-white / instagram-follow / data-chart 装现成的转场、叠层、字幕、图表、地图与特效块;Studio 是浏览器里的合成编辑器;@hyperframes/player 是可嵌入的 <hyperframes-player> web component;@hyperframes/shader-transitions 给合成加 WebGL 转场;hyperframes.dev 是社区 playground,Showcase 里的成片可以看、可以读源码、可以跑、可以 remix。

产品面的另外三块拼图:Studio 是浏览器里的合成编辑器,主交互是「prompt + 元素拾取」,手工精确控制是第二模式,官方明确不把时间线优先的手工剪辑当主路径;@hyperframes/player 把合成封装成可嵌入的 web component,站里嵌一支「活的」HTML 视频不需要先渲成文件;遥测默认脱敏(telemetryRedaction 单独立模块),把「代理会写进 HTML 的东西」当作不可信输入处理。安全模型与运行时同源:桥 payload 过 schema、URL 方案白名单、握手失败即 fail closed。

边界与局限

一是成本模型:逐帧 seek 意味着渲染耗时随帧数线性增长,重帧(Three.js、shader、4K/HDR)会把无头 Chrome 与内存吃满,低内存主机要靠自动降档与并行租约缓解,真正的大活仍得搬去 Lambda 或 Docker 农场。二是确定性的纪律成本:墙钟、未播种随机、渲染中途 fetch 任何一条都会 silently 毁掉复现,金样基线能兜住管线却兜不住作者写坏的场景,lint 与 check 只是护栏不是保险。三是生态年龄:Lambda 渲染路径相对 Remotion Lambda 仍年轻,Studio 标注为「Available, evolving」,手工时间线编辑不是产品主路径(主路径是 prompt + 元素拾取),习惯传统剪辑器的人会需要换脑。四是运行门槛:Node 22+ 与 FFmpeg 是硬依赖,完整 clone 还要 Git LFS 拉约 240MB 金样。

总结:谁该现在上手

如果你的视频是被生产出来的而不是被剪出来的——产品发布片、带代码 diff 动画的 PR walkthrough、图表竞赛与地图动画、带动能字幕的社交片、docs-to-video 与站点导览、内容流水线里可复用的动效件——HyperFrames 给了这条流水线一个可版本化、可回归、可交给代理的源码形态。它最锋利的地方不是某个特效,而是把「同一输入、同一支视频」从口号做成了有金样基线、有协议版本、有 checksum 门禁的工程契约;再叠上 frame.md 把设计系统翻译成镜头语言,HTML 这条所有人都会的方言,第一次成了视频的生产格式。

社区面也值得记一笔:Discord 是主阵地,维护团队甚至挂了一个「约 30 分钟随便聊聊」的用户研究日历——不做销售话术、只要真实工作流;安全报告走 SECURITY.md,贡献走 CONTRIBUTING.md,周更与产品更新各有独立文档流。对一个 2026 年 3 月才建仓的项目来说,半年做到六万星、并把文档、技能、契约、金样回归同时铺开,这个节奏本身就是证据:HTML 原生视频这条赛道,等一个开放标准已经很久了。

「浏览器能渲染的一切,都可以是一帧。」—— Anything a browser can render can be a frame.

作为亚马逊联盟会员,我们可能从符合条件的购买中获得佣金。