第 3 课
渲染 MP4、用变量出第二版,从 Catalog 装一个字幕条组件
渲染 1920×1080 30fps 7 秒 MP4 并用 ffprobe 核对;用 variables 与 strict-variables 参数换文案和配色出第二版,并看到拼错变量名会被拦下;用 catalog 搜索、add 安装 lt-clean-bar 字幕条,以子合成方式挂上时间轴;同机两次渲染 MD5 一致,最后用 clean 预览清理。
课程目录第 3 / 3 课
学习位置仅保存在当前浏览器,有效期 180 天。
渲染 MP4、用变量出第二版,从 Catalog 装一个字幕条组件
本课对照的官方页面:CLI 参考中的 render / catalog / add / clean 、变量 、合成与子合成 、确定性渲染 。测试环境同课时 1:Node.js v22.21.1、FFmpeg 7.1.5、
hyperframes0.9.26,8 核 CPU、无独立显卡。所有「对照结果」均为真实输出节选,超长行已折行。
上一课的片头已经通过 check。这一课把它真正渲染成 MP4 并核对参数,再用同一份模板换文案和配色出第二版,最后从官方组件库(Catalog)搜一个字幕条组件,挂进片头再渲染一次。
第 1 步:渲染成 MP4
在 kun-intro 目录里运行:
hyperframes render --output renders/kun-intro.mp4
对照结果(节选):
◆ Rendering kun-intro → …/kun-intro/renders/kun-intro.mp4
30fps · standard · auto workers (8 cores detected)
GPU: browser GPU (auto-detect)
Checking browser...
Browser: cache
◇ …/kun-intro/renders/kun-intro.mp4
210.0 KB · 7.0s video · rendered in 3.9s
beginframe capture · software gpu · compile 0.2s · setup 1.0s · capture 2.6s · encode
(during capture) 2.6s · assemble 0.1s
7 秒视频 3.9 秒渲完。Browser: cache 表示用的是已经下载好的 chrome-headless-shell;你第一次渲染时这里会显示 Browser: download,要多等一会儿。不写 --output 时文件会落在 renders/项目名_日期_时间.mp4。
用 FFmpeg 自带的 ffprobe 核对参数:
ffprobe -v error -select_streams v:0 \
-show_entries stream=codec_name,width,height,r_frame_rate,nb_frames:format=duration \
-of default=nw=1 renders/kun-intro.mp4
对照结果:
codec_name=h264
width=1920
height=1080
r_frame_rate=30/1
nb_frames=210
duration=7.000000
H.264、1920×1080、30fps、正好 210 帧 7 秒,和根元素上写的尺寸与时长一致。想要别的规格,常用参数有 --fps 60、--quality draft(快速出样片)或 --quality high、--format webm(带透明通道,适合叠加层)、--format gif。
第 2 步:用变量换文案和配色,出第二版
上一课已经在 <html> 上声明了 title、subtitle、accent 三个变量,并用 data-var-text 与 var(--accent) 绑定。渲染时用 --variables 传一个 JSON 覆盖默认值,加上 --strict-variables 让拼错的变量名直接报错:
hyperframes render \
--variables '{"title":"HyperFrames","subtitle":"写 HTML,渲染成视频","accent":"#f97316"}' \
--strict-variables --quality draft \
--output renders/kun-intro-orange.mp4
对照结果(节选):
◆ Rendering kun-intro → …/kun-intro/renders/kun-intro-orange.mp4
30fps · draft · auto workers (8 cores detected)
◇ …/kun-intro/renders/kun-intro-orange.mp4
285.4 KB · 7.0s video · rendered in 3.4s
截第 2 秒对比:默认版是「昆仑学堂 / 用 HTML 写一段视频」配绿色进度条,新版变成「HyperFrames / 写 HTML,渲染成视频」配橙色进度条,版式和动画完全不变。
再故意把 title 拼成 titel 试试严格模式:
hyperframes render --variables '{"titel":"typo"}' --strict-variables --output renders/bad.mp4
echo "exit=$?"
对照结果:
Variable issue (1) — values may not render as expected:
Variable "titel" is not declared in data-composition-variables.
✗ Variable validation failed
Aborting render due to variable issues (--strict-variables mode).
exit=1
渲染被拦下,退出码为 1,renders/ 里不会多出 bad.mp4。批量出片时一定要加 --strict-variables。要一次出很多版,官方还提供 --variables-file(从文件读)和 --batch(JSON 数组每行出一个文件),用法见 CLI 参考的 render 一节。
第 3 步:从 Catalog 搜一个字幕条组件并装进项目
官方组件库有约 450 个现成的转场、标题、图表、字幕条等组件。先按描述搜:
hyperframes catalog --query "lower third name title"
对照结果(节选):
40 of 448 moves · local word match
Name Type Description
lt-kicker-name block Cardless lower third with an accent eyebrow/kicker
tag, heavy name, and a drawn baseline; for footage
lt-stack-bars block Two stacked bars: a dark name bar wipes from the
left, an accent role bar wipes from the right
lt-soft-pill block Rounded white pill lower third for
podcasts/interviews: status dot, name + role, scale-pop entrance
…
不带 --query 会列出全部;--type block、--tag social 可以过滤;加 --on-device 会改成语义搜索,但需要先下载一个 33 MB 的本地模型。本课选 lt-clean-bar(白色卡片、左侧强调色竖条的姓名条):
hyperframes add lt-clean-bar --no-clipboard
对照结果:
✓ Added lt-clean-bar (hyperframes:block)
compositions/lt-clean-bar.html
Include snippet:
<div data-composition-id="lt-clean-bar"
data-composition-src="compositions/lt-clean-bar.html" data-duration="4.8"
data-width="1920" data-height="1080"></div>
Paste the snippet above into your host composition.
组件以源码形式落在 compositions/lt-clean-bar.html,可以随便改。--no-clipboard 表示不把片段写进剪贴板,在服务器和 CI 上要加。
第 4 步:改组件文字,挂进片头
组件里的示例文字是 Dr. Maya Chen 与 Host · Neuroscientist。用编辑器改成你自己的,或者用 sed(macOS 上写成 sed -i ''):
sed -i 's#>Dr. Maya Chen<#>HyperFrames<#; s#>Host · Neuroscientist<#>Write HTML. Render video.<#' \
compositions/lt-clean-bar.html
然后在 index.html 里网址那一段 <p id="outro" …> 的上面,加上刚才的挂载片段,并补上开始时间和轨道号:
<div id="lower-third"
data-composition-id="lt-clean-bar"
data-composition-src="compositions/lt-clean-bar.html"
data-start="1.5" data-duration="4.8" data-track-index="3"
data-width="1920" data-height="1080"></div>
data-composition-src 的路径从项目根目录算。子合成自带自己的时间线,父级只决定它何时出现:这里从第 1.5 秒开始,持续 4.8 秒。
hyperframes lint
hyperframes timeline
对照结果:
◆ Linting kun-intro/2 files
◇ 0 errors, 0 warnings
timeline 7s
graphics (6: 5 top-level, 1 nested)
|███████████████████████ | #title title 0-4s
|███████████████████████ | #subtitle subtitle 0-4s
|███████████████████████ | #bar bar 0-4s
| ████████████████████████████ | #lower-third lower-third 1.5-6.3s
src=compositions/lt-clean-bar.html
| ████████████████████████████ | #lt-clip lt-clip 1.5-6.3s (local 0-4.8s) nested
in lower-third compositions/lt-clean-bar.html
| ██████████████████| #outro outro 4-7s
lint 这次检查了 2 个文件,时间轴上字幕条落在 1.5 到 6.3 秒,组件内部的本地时间 0 到 4.8 秒被映射过去。先抽第 3 秒确认位置:
hyperframes snapshot --at 3 --no-end --output snaps
对照结果(节选):
◆ Capturing 1 frames at [3s] from kun-intro
Fonts: 10 loaded
[hyperframes] snapshot: frame 1/1 at 3s
◇ 1 snapshots saved to …/kun-intro/snaps
Fonts: 10 loaded 比上一课的 2 个多,多出来的是组件用的 Montserrat 字体:测试机第一次检查带这个组件的项目时,日志显示从 Google Fonts 拉取了 Montserrat 并缓存到 ~/.cache/hyperframes/fonts/montserrat。打开 snaps/frame-00-at-3s.png,左下角出现白色卡片「HyperFrames / Write HTML. Render video.」,中间仍是「昆仑学堂」标题。
第 5 步:最终渲染,并验证可复现
hyperframes render --output renders/kun-intro-lt.mp4
hyperframes render --output renders/kun-intro-lt-2.mp4
md5sum renders/kun-intro-lt.mp4 renders/kun-intro-lt-2.mp4
对照结果(第二次渲染输出略):
◇ …/kun-intro/renders/kun-intro-lt.mp4
313.9 KB · 7.0s video · rendered in 5.4s
e47b1390fdf733408ee61f19c55c0e6c renders/kun-intro-lt.mp4
e47b1390fdf733408ee61f19c55c0e6c renders/kun-intro-lt-2.mp4
同一台机器连续渲染两次,文件逐字节相同。这就是「逐帧跳转再截图」带来的好处:不受渲染时机器忙不忙的影响。官方确定性渲染文档也提醒,不同电脑的字体和 Chrome 版本不同,本机渲染换一台机器可能差一个像素,需要跨机器逐字节一致时用 hyperframes render --docker(需本机装 Docker,本课测试机未装,未实测)。
最后清理一下渲染留下的临时文件,先看会删什么:
hyperframes clean --dry-run
本课测试机的结果是 Nothing to clean,只列出了可以用 --snapshots 额外回收的快照与 check 报告(约 200 KB)。渲染出的 MP4、源码、浏览器和模型永远不会被 clean 删除。
常见坑
- 字幕条整块不见:多半是你给通用的
.clip类写了定位样式,组件内部也用.clip,被一起改了位置。把布局样式写到具体 id 上 - 组件的 Montserrat 来自 Google Fonts,网络不通时会退回默认字体;可以像上一课那样把字体文件放进项目并在组件里写
@font-face --variables的 JSON 在 Windows PowerShell 里要注意引号转义,最稳的是写进文件后用--variables-file- 想让每次渲染都一样,动画里不要用
Date.now()、requestAnimationFrame和不带种子的Math.random(),也不要在渲染中途再去请求网络资源(官方确定性渲染文档列出的规则) --quality draft只适合看样片;交付用默认的 standard 或--quality high- 内存 8 GB 及以下的机器会自动进入低内存模式(单进程、较慢),属正常现象;也可以用
--workers 1手动限制
小结
你把片头渲染成了 1920×1080、30fps、7 秒的 H.264 视频,并用 ffprobe 核对;用 --variables 与 --strict-variables 一份模板出了第二版,并看到拼错变量名会被拦下;用 catalog 与 add 把官方字幕条组件装进项目,以子合成的方式挂上时间轴;最后验证了同机两次渲染 MD5 一致。接下来可以运行 npx hyperframes skills update,让 Claude Code、Codex 或 Cursor 在同一个项目里按 AGENTS.md 的约定继续帮你改。
