变更日志 → 品牌化视频
输入:一份变更日志 .md 文件(包含主题和项目,如每周 HyperFrames 摘要)。
输出:一个经过 lint 检查和 seam-gate-green 验证的 HyperFrames 项目,位于
projects/active/weekly-changelog-<range>/ 目录。仅在用户要求时进行渲染。
首要且不可协商的加载项: motion-doctrine(以及 cut-the-curve(如果出现光标)、oversized-cursor、seam-craft)和 captions-overlay。本技能提供变更日志专用管线;运动基础法则提供运动规则。
首要原则:可视化,而非列举
每个主题都必须通过实际 UI 的动画模拟或一个忠实类比来展示,该模拟需演绎出体验中的变化——绝不能使用文本项目符号。在编写脚本之前,务必将每个主题/项目通过 references/visualization-registry.md 进行处理;该注册表将决定采用 UI-recreate(UI 重建)/ UI-analog(UI 类比)/ terminal(终端)/ checklist(清单)中的哪一种。文本清单是最后的手段,仅保留给确实无法视觉化的项目(如可靠性修复清单)。
管线
0 · 从本技能的资产引导项目——不可协商
在编写任何组合 HTML 之前完成此步骤。跳过它总会生成一个看起来像你之前构建过的类似项目的视频,而不是本技能的品牌——这是该技能偏离品牌最常见的方式。 本技能的资产、字体和骨架模板就是技能本身;SKILL.md 提示是一个路由器。
mkdir -p project/assets/fonts
cp <SKILL_DIR>/assets/fonts/*.woff2 project/assets/fonts/
cp <SKILL_DIR>/assets/bgm.mp3 project/bgm.mp3
ffmpeg -y -stream_loop 15 -i <SKILL_DIR>/assets/bg-pattern.mp4 -t <TOTAL> \
-vf "scale=1080:1080,fps=30,eq=saturation=0.72,[email protected]:t=fill" \
-an -c:v libx264 -crf 20 -pix_fmt yuv420p project/assets/bg-pattern-<TOTAL>s.mp4
cp <SKILL_DIR>/examples/master-skeleton.html project/index.html
然后从头到尾阅读 references/build-spec.md(不要略读)——它定义了品牌令牌(TT Norms Pro + ABC Solar Display + TT Norms Mono,奶油色 #f5f6f4,定量使用的绿色 #5ef17c,带有绿色边框的玻璃卡片,kicker/sec-chip 药丸形状,位于 top: 990 的 32px 字幕轨道),每个场景都从骨架模板继承这些参数。
然后才开始下面的步骤 1-6。步骤 1-4(解析、路由、脚本、VO)规划要放入骨架模板的内容;步骤 5 填充已复制好的 project/index.html 中的占位符(<RANGE>、<TOTAL>、<CUT_N>、<DUR_N>、场景主体)——你不要重写骨架模板的 chrome、字体、调色板或布局外壳。
如果你发现自己正在使用 cp 命令复制先前视频的 index.html,或者正在编写自己的 @font-face 声明,或者正在设计 WebGL 着色器背景而不是使用上面编码的 bg-pattern MP4:立即停止。删除当前的 index.html 并从 cp master-skeleton 骨架模板开始重新构建。在正确的骨架模板上重建场景内容比试图将品牌改造到错误的骨架模板上要便宜得多。
1 · 解析和编辑剪辑
- 提取:周范围、标题统计(发布次数、提交次数)、主题、项目。
- 预算:总计 45-60 秒。 标题 ≤2s,片尾 ≤3.5s,4 个主题每个约 9-12s。
- 每个主题保留一个主要的视觉化场景,以及最多 3 个配音项目。其他所有内容仅作为片尾中“完整摘要”的指针存在。剪辑就是工作:一个包含 30 个项目的变更日志仍应产生 ≤14 个配音节拍。
- 按故事顺序排列主题:重磅功能 → 产品界面 → 性能 → 可靠性(摘要通常已经按此方式组织)。
2 · 视觉化路由
对于每个主题,从 references/visualization-registry.md 中选择一个界面,并写一行:theme → surface → 模拟执行的 2-4 个有序动作,每个动作对应脚本中的一个短语。如果没有合适的注册表界面且没有忠实的类比,则它是一个清单场景——不要为无法诚实表示的内容发明虚假的 UI。
3 · 双层脚本(口语与显示)
根据 references/script-voice.md 将脚本编写为令牌行:对话式语气,每个技术术语在 references/lexicon.json 中携带一个 spoken 语音形式,而 display 保持标准拼写。字幕显示 display 层;配音朗读 spoken 层。任何不在词汇表中的术语:停止并询问用户如何发音,然后将其添加到词汇表中。
将脚本保存为项目中的 script-tokens.json。
4 · VO——Annie (HeyGen, 固定)
# 仅口语层文本;words JSON = 口语文本的 ground-truth 时间戳
# 仓库原生路径:changelog-video 技能从 hyperframes 仓库根目录运行,
# 因此它直接使用跟踪的 hyperframes-media TTS 助手(无需 `npx hyperframes`
# skills 安装步骤)。如果你已将技能复制到另一个仓库,请将路径替换为你自己的
# media-use / hyperframes-media heygen-tts.mjs 路径。
node skills/hyperframes-media/scripts/heygen-tts.mjs ./vo-spoken.txt \
-o voiceover.mp3 --words vo-words.json \
--voice 330290724a1b470fb63153f34d4c0183 # Annie — 逼真语音 (请勿替换)
需要已认证的 heygen CLI ≥0.3.0 版本 (heygen auth login --oauth)。
然后将口语时间戳与显示令牌对齐:
node <SKILL_DIR>/scripts/align-captions.mjs \
--tokens script-tokens.json --words vo-words.json --out captions.json
captions.json 是字幕轨道的输入(显示拼写,口语时间)。
对齐器会打印 MISMATCH 警告——在构建之前解决每一个(通常是词汇表拼写导致 TTS 渲染为多个单词)。音频是时钟:所有节拍时间都来自 vo-words.json;重新生成 VO 会重新打开每个 seam。
单词时间戳是一个硬性关卡。 在进入步骤 5 之前,验证 vo-words.json 非空,并且包含一个带有每个单词 start/end 的 words: [...] 数组。如果它为空(0 字节)或缺少该数组——这是 TTS 提供者返回音频但没有时间戳载荷的一种已知失败模式——在没有它们的情况下请勿继续。回退:使用本地 whisper 对生成的音频进行强制对齐:
uvx --from openai-whisper whisper voiceover.mp3 \
--model base.en --language en --word_timestamps True \
--output_format json --output_dir .
# 然后使用 --words voiceover.json (相同结构) 运行 align-captions.mjs
Whisper 可能会误听 TTS 渲染的内容(如 "gee-sap" → "gsap", "heyjen" → "hey Jen" 等)——字幕仍使用 script-tokens.json 中的 DISPLAY 拼写;whisper 仅提供时间戳。align-captions.mjs 负责合并处理。这个回退方案是有字幕版本和无字幕无声版本的差别。
5 · 构建
严格遵循 references/build-spec.md:品牌令牌 + 字体(打包在 <SKILL_DIR>/assets/ 中)、动画背景编码、场景骨架模板、chrome、字幕轨道、每个场景一个定量使用的绿色时刻。然后按照 doctrine 顺序:ledger.json(所有普通 seam 使用 cut-the-curve LEFT)→ seam-stamp → VO 单词上的内部节拍 → seam-gate 验证。
字幕是不可选的。 master-skeleton 骨架模板附带了一个读取 LINES 数组的字幕轨道 IIFE——让该数组为空是一个已发布的 bug,而不是一种风格选择。在进入步骤 6 之前,从 captions.json 填充它:
// 粘贴以替换 caption-rail IIFE 中的 "const LINES = /* … */ []":
const LINES = /* captions.json 的内容 */ [
{ id: 0, end: 2.74, w: [["This", 0.0], ["week,", 0.30], …] },
…
];
如果跳过了 align-captions.mjs 或 LINES 为 [],步骤 6 中的帧检查将失败——不要通过从骨架模板中移除 #cap-line 来掩盖它。
6 · 门控(在呈现前全部为绿色)
node packages/cli/bin/hyperframes.mjs check --caption-zone "x0=0;y0=.90;x1=1;y1=1;severity=error;seek=.02,.06,.10,.14,.18,.22,.26,.30,.34,.38,.42,.46,.50,.54,.58,.62,.66,.70,.74,.78,.82,.86,.90,.94,.98"(或仓库本地skills/hyperframes-cli/技能中已安装的hyperframesCLI)——0 个错误(对比度:暗淡文本 ≥ .66 alpha;场景内容保持在字幕轨道上方)。不要使用npx hyperframes@latest;被跟踪的仓库本地 CLI 是本技能生成的合成合约的真实来源。seam-gate.mjs verify——0 个失败。- 重启预览服务器(它会缓存 bundle),通过原始合成页面上的
__player.seek抽查 3-4 个节拍。 - 除非用户要求,否则不要渲染。在请求渲染后,从 MP4 中验证帧(
ffmpeg -ss <t> … -frames:v 1):字幕存在,背景视频不是黑色,没有微小/冻结的帧。 - 字幕存在性门控——硬性失败。 抽样分布在 VO 口语窗口内的 3-4 个帧(例如,对于一个 48 秒的 VO,使用
t=3、t=15、t=30、t=42),并确认位于top: 990的字幕轨道在每个帧上都渲染了可见文本。如果在口语间隔内的任何帧缺少字幕,则构建发布的是无字幕版本——将其视为红色门控并重新检查步骤 5 的LINES填充。这正是 7 月 13-20 日 v4 构建中出错的问题。
项目布局
projects/active/weekly-changelog-<range>/
├── index.html # 单文档主文件(场景作为幻灯片,带有 seam 标记)
├── ledger.json # vector ledger(seam-stamp 输入)
├── script-tokens.json # 双层脚本(VO + 字幕的真实来源)
├── vo-spoken.txt # 生成:口语层,每行
├── voiceover.mp3 + vo-words.json + captions.json
├── bgm.mp3 # 从 <SKILL_DIR>/assets/bgm.mp3 复制(官方背景音乐)除非用户提供
└── assets/fonts/ + assets/bg-pattern-<dur>s.mp4
反模式
| 不要这样做 | 应这样做 |
|---|---|
| 对 UI 变化使用项目符号幻灯片 | 模拟界面演绎变化 |
| 为不可表示的项目使用虚假 UI | 诚实的清单场景 |
| 在 TTS 文本中使用纯文本 "JSON"/"CLI" | 使用词汇表的口语形式;显示层保持标准形式 |
| 在字幕中使用语音拼写 | 字幕始终渲染显示层 |
| 猜测未知术语的发音 | 询问,然后扩充词汇表 |
| 朗读每个变更日志项目 | 每个主题最多 3 个;摘要链接包含其余内容 |
| 绿色强调色到处都是 | 每个场景一个绿色时刻 (#5ef17c) |
| 从先前视频的 index.html 开始 | 步骤 0 —— 始终从本技能的 examples/master-skeleton.html 复制到 project/index.html |
手写的 @font-face / WebGL 着色器 / 自定义 BGM | 步骤 0 —— 逐字复制本技能的 assets/ 目录;本技能的资产就是品牌 |
| 在没有 CloudFront 失效清理的情况下交付 | 在任何 S3 替换后,对分发的精确路径运行 aws cloudfront create-invalidation——否则 CDN 会缓存旧文件 |
骨架模板中的 LINES 数组为空时发布 | 步骤 4 必须生成填充的 captions.json;步骤 5 必须将其粘贴到 IIFE 中;步骤 6 门控 5 必须在渲染帧上确认字幕存在。空的 LINES = 无字幕发布 = 重新运行 |
没有 vo-words.json → 跳过字幕并直接发布 | 回退到对生成的音频使用 whisper 强制对齐;字幕不可选 |