← 工作室

03 · 程序化视频

程序化视频:两个例子

画面里没有任何生成的像素。画面就是代码:HyperFrames 里一条暂停的 GSAP 时间线,每个元素的位置与时间都来自一份实测文件,逐帧渲染,再从交付的 MP4 里读回来。

例子 A · Coco da Vinci Apple 的“Intention”短片,双语版 中文逐帧配合英文的文字编排动效 例子 B · Cody 图灵 Toastmasters Table Topic「五」,一条招募短片 生成图像 + HyperFrames + Fish Audio,为手机做的竖屏

例子 A · Apple · Intention · 中英双语版

把中文做成第二语言母版,出自同一个动效团队之手

Apple 这部 91 秒的短片,就是动起来的文字排版。Coco 的版本保持英文画面和音频原封不动,把简体中文作为一行安静的伴随文字加入进去,它是原有编排的一部分,而不是叠在上面的字幕。要求:忠实的双语本地化;检验标准:中文读者应当觉得这一行是与原片一起创作出来的。

91.05 秒 1920×1080 · 24000/1001 fps
29 已映射的提示点,英文到中文
93 已检查的关键补间
2,183 / 2,183 已解码的交付帧
0 运行时、版式、动效或对比度错误
A1

两份母版,两种权威,白纸黑字写明

英文母版(1920×1080,画面与音频原封不动)决定动效、特效、方向和时间。Apple 官方的中文版(848×480,仅作为时间与措辞的参照,绝不作为交付素材)决定确切措辞和断句。早先一轮曾让中文文件同时决定两者,结果压平了四个功能性特效;这条规则已被纠正并记录下来,使它不会再漂回去。

BRIEF.md · OFFICIAL-CHINESE-REVIEW.md "Authority correction" · source: Apple - Intention 1080p.mp4 · reference: Designed by Apple in California - Original Chinese.MP4

A2

按影片的原生节奏,测量每一个提示点

英文母版按 24000/1001 帧/秒解码,对每个逐步出现的字,从首次可见的对比度量到完全亮起。结果是一份含 29 行的提示点图,每行附有大致的原片时间窗和对应的双语处理方式,从“如果 紧随 If,从首次可见到完全亮起”到“Apple 标语保持英文,与官方中文版一致”。

LOCALIZATION.md (cue map) · index.motion.json · snapshots/ (78 sampled frames)

A3

配对的是意思,不是语序,也绝不逐字配对

中文被分成有意义的单元,每个单元与它的英文对应部分同时开始、同时完全不透明,即使中文语法会调换句子顺序。在“perfect”那个问句里,做到好? 紧随“perfect”,哪一件事 紧随“anything”。在忙碌那一句里,三个短语单元恰好分别覆盖“is busy”“making”和“everything”。

If everyone is busy making everything 如果 · 所有的人 · 都忙着 · 做 · 所有的事
delight · surprise · love · connection 开心 · 惊奇 · 喜爱 · 相联

MOTION-MAP.md "Semantic Pairing Revision" · motion references: discrete-text-sequence, scale-swap-transition (flat-opacity variation)

A4

承接功能性动效;不添加任何装饰

英文那一行做了什么,中文就做同样的事:丰富|等于选择。 在顺时针圆弧之前,沿中间的关节弯折的铰链;设计东西需要 上低幅度的水面漂浮;焦点 清晰、“focus”模糊、随后两者同时清晰的交替模糊;围绕固定的 主旨 画出的基线测量线;便利那一行里向内的圆点塌缩;这需要时间······ 中间六个圆点一个接一个地出现;由英文母版自带的圆圈揭开的最后两行。凡没有英文对应物的,一概不加:没有方框,没有阴影,没有光晕,没有渐变。

MOTION-MAP.md "Removed-effect audit" · frame.md "Do Not"

A5

字体作为伴随行,用从原片取样的中性色

PingFang SC Regular,28 像素(当有移动的圆圈或紧凑形状造成拥挤时用 24 像素),行高 1.2,字距 0,使用自然的简体中文标点,放在对应英文短语正下方 24 像素处。颜色取自影片本身——墨色与纸色——所以画面里不会出现任何凭空发明的东西。

frame.md · ink #1C181B · paper #D0CCCF · english_to_chinese 24 px (12 px compact)

A6

一条确定性时间线,一处新增

所有关乎渲染的动效,都在一条暂停的 GSAP 时间线里,只用确定性的数值,所以每一帧渲染两次结果都一样。感觉? 的粒子崩散用的是同样的字形,画在一块确定性的画布上。唯一加进 Apple 影片里的,是版本署名;结尾的“Designed by Apple in California”落版保持英文,与 Apple 自己的中文版一致。

index.html (33 KB composition) · HyperFrames 0.7.102 · window.__timelines, paused

A7

从交付文件里抽帧做质检

提示点的进入、完全不透明状态、退出和高动态的中点,现场检查了 64 个精确的提示点边界帧,外加 17 个针对性微调帧;然后从渲染好的 MP4 里重新抽出 61 帧,覆盖每一段修订过的渐变、消失、圆圈节拍和结尾转场。这次逐帧审计抓到了两个没人问起的回退:“时间”那一行退出的方向反了,以及一次塌缩裁掉了 1920 像素的行框,而不是文字的宽度。两处都已修好,并在交付之前重新取样。

在交付文件上的实测 H.264 High,1920×1080,BT.709,24000/1001 帧/秒,2,183 帧中 2,183 帧可读。音频 AAC 48 kHz 立体声,91.049 秒;峰值 −7.952 dB、RMS −25.209 dB,对比原片的 −7.944 和 −25.194。容器 91.049 秒,18,180,970 字节,已记录 SHA-256。

PAIRED-MOTION-QA.md · renders/Apple-Intention-Bilingual-ZH-EN-Official-Frame-Synced-Final.mp4 (8 August 2026)

例子 B · Toastmasters · Table Topic「五」· 招募短片

这条视频本身就是一次 Table Topic

Tony 的构想:展示一次世界级的 Table Topic 可以是什么样。抽到的题卡只给了 Abby 一个字,「五」,她用大约九十秒,在绿灯和红灯之间,把它变成俱乐部的招募信息:15 位创始会员已加入,还差 5 位,9 月 30 日前正式立会。观众一边看着俱乐部所训练的这项技能,一边被邀请加入。竖屏,为手机而做,附一个通往报名页面的二维码。

1080×1920 竖屏 · 分享副本 12.5 MB
23 脚本行,停顿已写入
90.9 秒 声音 · 结束在黄灯与红灯之间
108 HeyGen 积分用于口型同步,约 4 分钟
3 生成的形象做了对比;选定 v2
B1

一份点明自己所展示技艺的脚本,每个事实都有来源

二十三行中文旁白。旁白之上,是一次出色的即兴回答所做的八个动作:开口之前的停顿、复述题目、把抽象变成可见的东西(一只手、五根手指、一个拳头)、从题目到信息的桥接、平实地讲一个事实、用三段式发出邀请、点出这项技能一次、回扣式结尾。每个事实都有来源行:会员人数来自 Tony,场地与双语说明来自俱乐部网站,计时灯来自 Toastmasters 的标准。停顿以 (停 N) 写进脚本。

SCRIPT.zh.md · Abby 代表俱乐部发言(“我们”);不把个人履历塞进她的口中 · “Apex Learn 演讲俱乐部”,品牌不翻译

B2

Fish Audio,每行一条录音,按脚本自带的停顿拼接

旁白工具用 Abby 获批的声音,一行一行地配音,用请求的哈希缓存每一条录音,所以重录时只重新录制改动过的部分;然后按脚本写下的停顿拼接:行与行之间 0.45 秒,段落之间 0.9 秒,外加明确写出的 (停 N) 停顿。它写出的时间线记录了每一行的开始与结束。在发出任何一个请求之前,工具会再次确认免费模型仍然不收费。

孤零零的「五」 单音节的五,每一次录音都被转写成了嗯、我或一,一个干净的系统语音念出的五也被听错,所以一个孤立的音节,无法靠听一次来判断。开头的“五”是从一段更长的录音里剪出来的,“题目只有一个字:五。”,之所以选它,是因为转写器连续三次都听成了五。十四条变体录音和一条对照,放在脚本旁边。

narrate.py · voice 大曼007 · s2.1-pro-free · clips/NN.wav + NN.json · variants/x1-cut.wav · voice.wav 90.9 s · timeline.json

B3

生成图像:Abby 站在讲台后

第一版剪辑,是把一张讲台照片贴在一个半身数字人片段前面,Tony 一眼就看出她的双手应该放在讲台上。贴上去的讲台没法承载双手,所以在 HeyGen 里用两张参考图生成了一个新形象:Abby 的身份数字人,以及 Toastmasters 的讲台照片。结果是一张 1536×2752 的竖版画面,双掌都放在讲台台面上,徽标朝向镜头。生成了三个变体:v1 偏年轻,耳环也不对;v3 在台沿下多出了指尖;v2 守住了脸、西装外套、四叶草耳环和项链,被选中。让身份稳定下来的那条提示词,把每一个特征都一一写明,而不是只相信参考图。

heygen avatar create · type prompt · avatar_id = Abby + reference_images = lectern asset · heygen/look/request-v2.json · abby-looks-compare.jpg · 1 credit per look

B4

对我们的 WAV 对口型,再拿片段与它对照测量

HeyGen Avatar V,1080p,由拼接好的人声文件加上 0.8 秒的垫片驱动,大约四分钟完成。返回片段的音频与上传的音频做了互相关:第一个形象提前 13 毫秒,讲台形象滞后 23 毫秒。偏移被写入构建会读取的文件,所以观众听到的声音和嘴唇所跟随的音频,在最终文件里的误差在 0 到 5 毫秒之内。

heygen/request.json · engine avatar_v · audio_asset_id · 91.7 s = 108 credits (582 → 474) · film/assets/abby.offset.json

B5

从配音时间线生成 HyperFrames:每个图形都绑定它所属的那一行

构建脚本依据配音时间线写出 1080×1920 的合成。先是开场卡,然后从 4.2 秒起是 Abby 和声音。在下方区域里,每个图形从它所说明的那一行开始,到下一行结束:五根手指攥成拳头、场地、俱乐部名称、二十个座位被填到十五个、三段式的三个标签、9 月 30 日这个日期、再次出现的拳头、带报名地址的二维码。每一行一个字幕片段,保持到下一行开始。因为每个起始时间都读自时间线,重新配音的脚本,会让整部影片自动重排时间,无需任何手工修改。字体被裁剪到只含所用的字符。

构建里写死的两条框架事实 视频不能嵌套在一个带时间的片段里,所以数字人放在一个不带时间的包装层里,它的子元素各自带时间。把 16:9 形象裁成 9:16 画幅,是围绕 Abby 的原生 1080×1080 窗口,绝不是放大两倍;讲台形象后来改成竖版生成,所以带框的卡片是 907×1361,上方有一条带,下方是紧凑的区域。

film/build.py → index.html · assets/voice-timeline.json · build.py --fonts · build-square-v1.py kept as the earlier layout · npx hyperframes check

B6

在有磁盘空间的机器上渲染,核对分享副本

笔记本只剩 403 MB 可用空间,所以渲染在工作室的渲染机上进行。母版 83.6 MB;供微信分享的副本 12.5 MB。检查是对交付的分享文件做的,而不是对母版:人声在时间线所说的位置开始,二维码能从文件自己的画面里解码出报名地址,缩小到一半后依然能解码。最终的 v2 在 9 月 29 日发出,也就是俱乐部立会截止日的前一天。

film/renders/apexlearn-table-topic-wu-lectern-share.mp4 · master on the render machine · QR → toastmasters.apexlearn.org/#join

两个例子的共同点

  • 时间以一份实测文件为准:一个是逐帧解码出的提示点图,另一个是配音时间线。
  • 合成由这份文件生成或映射而来,所以时间从不靠手工微调。
  • 验证读回交付的 MP4:抽出的帧、解码的音频、从画面里扫出的二维码。

版权与关卡

  • Apple 版本是对 Apple 自己影片的一次本地化研究。这里展示的是方法;影片本身不再分发。
  • Toastmasters 短片用免费的 Fish 模型配音,该模型仅授权非商业使用;俱乐部的推广,经 Tony 判断属于这个范围之内。
  • Abby 的讲台形象只存在于 Tony 的 HeyGen 账号里。