深入浅出(Under the Hood)
将一个主题(或用户的代码)变成带有旁白和动画的解说视频。视觉风格温暖且为手绘效果:
- 米色点阵“纸张”背景,配以墨水线条画
- 蓝色用于请求,橙色用于响应,绿色用于加密或成功状态
- 顶部有步骤跟踪器,底部有大号字幕
- 数据包在方框之间飞行,镜头在不同“世界”之间平移
参考结果位于 ${CLAUDE_SKILL_DIR}/assets/example-cookie/,展示了在 Google 搜索 "cookie" 时发生的过程。打开它的 scenes.js 便能找到处理复杂场景的模式。
一切由代码驱动。画布页面以确定方式渲染帧,旁白剪辑设定每个场景的长度,音乐和音效从同一时间线合成。修改脚本会重新同步所有内容,一个 60 秒的视频大约在 30 秒内完成渲染。
请求的主题:$ARGUMENTS
文件位置
- 脚本:
${CLAUDE_SKILL_DIR}/scripts/(简称SCRIPTS)。 - 运行时:
UTH_HOME(默认~/.local/share/under-the-hood)存放 node 模块、TTS 虚拟环境和已保存的语音文件。运行doctor.sh可打印确切的路径,包括PY(TTS 的 Python 路径)。 - 项目: 当前工作目录下的
./explainers/<slug>/,除非用户指定了其他位置。如果工作目录是 home 文件夹,请询问存放位置,避免弄乱~。
一个项目文件夹的结构如下:
index.html engine.js scenes.js script.json timeline.js
narration/ (语音剪辑:<id>.wav, <id>_take2.wav 以及预览文件)
audio/ (音轨分轨和 mix.wav)
.shots/ (截图,每次运行生成一个新文件夹)
<slug>.mp4
工作流程
0. 检查环境(准备就绪时执行一行命令)
bash ${CLAUDE_SKILL_DIR}/scripts/doctor.sh # 如果视频没有旁白,添加 --no-tts
如果输出 READY,记下 PY 和 VOICES 并继续。如果输出 MISSING 行,请加载 under-the-hood-setup 技能并按照说明操作,然后重新运行 doctor。
1. 简短需求采集
如果 $ARGUMENTS 为空,请询问主题。然后只询问你无法合理决定的内容,一次消息内,提供合理默认值:
-
角度: 仅当主题宽泛时询问。例如“互联网如何工作”需要确定焦点,而“当你执行 git push 时发生了什么”则不需要。
-
语音: 始终询问此选项,因为用户可能不知道还可以使用自己的语音。按以下方式展示:
- 内置语音(默认,立即可用)
- 已保存的语音(如果
VOICES中列出) - 你自己的语音:用手机录制大约 20 到 30 秒,然后发送文件。你的语音只保留在你的机器上。
- 无旁白(仅音乐和音效)
如果用户选择自己的语音,请先阅读
${CLAUDE_SKILL_DIR}/references/voice.md,并向他们提供录音提示和示例段落,再开始其他操作。你可以在编写故事板的同时让他们录音。 -
时长: 默认 30 到 60 秒,16:9。
不要把这变成一个问卷。最多两三个简短的问题。
2. 理解主题并确保事实准确
如果用户提供了代码,请阅读代码并追踪真实流程。技术观众会发现错误。所以:
- 确定事件顺序正确。例如:在已经加载的页面上,DNS 和 TLS 握手已经发生,因此在首次接触时放置它们,或标注为“首次访问”。
- 优先使用现代系统实际采用的方式。例如:Chrome 通过 QUIC 和 TLS 1.3 与 Google 通信,而不是教科书式的 TCP 三次握手。
- 在简化时,在副字幕中注明“简化演示”。
- 使用示例值(示例 IP 地址、
.example域名、虚构的分数),避免像确切的毫秒计数这样的虚假精确度。 - 不要重现真实产品的 logo 或像素级精确的 UI。线条画风格的替代品更符合整体风格。
3. 故事板和脚本,在构建前获得批准
规划 4 到 8 个编号步骤,大约 30 到 60 秒,加上开头的 title 场景和结尾的 end 场景。为每个场景编写:
- 旁白(
script.json):{"id", "text", "gap"}。gap是台词之后的停顿,0.25 到 0.45 秒。 - 字幕(
cap):不超过 8 个单词,静音时可读。副字幕(sub):一行简短文字。 - 视觉节奏: 出现和移动的元素,以及每个音效是什么。
在编写旁白之前,请阅读 ${CLAUDE_SKILL_DIR}/references/narration.md。文章式的旁白听起来像是 AI 在读文章。请以朋友间讲解的方式写作。
以简短表格的形式向用户展示脚本和故事板,等待确认。现在修改文字是免费的。生成语音后,修改将需要重新运行。
旁白和屏幕文字中不要使用长破折号和分号。TTS 读起来很奇怪,短句子听起来也更自然。
4. 搭建项目脚手架
bash SCRIPTS/new_project.sh ./explainers/<slug> "<页面标题>"
这会复制 engine.js、一个起始 scenes.js(一个可运行的“点击发送”小示例)和 script.json。它拒绝覆盖非空文件夹。将起始内容替换为真实的故事板。
5. 构建 scenes.js
首先阅读 ${CLAUDE_SKILL_DIR}/references/engine-api.md。它涵盖了时间模型、所有辅助函数、布局区域、音效名称和启动配置。关键概念:
- 使用
defineScenes([...])并设定设计时长。在设计时间内使用prog(t, S.id + a, S.id + b)进行动画。引擎会拉伸每个场景以匹配其语音剪辑,因此永远不要根据剪辑长度手动调整。 - 保持画面区域在 y 坐标 150 到 800 之间。跟踪器位于上方,字幕位于下方。
- 需要持续存在的物体(如浏览器、服务器)在一个场景中出现,并在后续场景中保持绘制状态。
- 对于第二个“地点”,比如数据中心内部,请在 x + 1920 处绘制,并使用
camera(t)平移。在平移过程中开始显示其内容,以确保屏幕在移动过程中不会出现空白。 - 每个可见事件都会在
sfx(add)中添加音效。按键使用key,飞行的数据包使用whoosh*,到达时使用thunk或pop,成功时使用chime或success。这是让视频显得完整的重要部分。
6. 无需语音预览,检查帧画面
node SCRIPTS/shots.js <project> # 每个场景的中间帧,保存到新的 .shots/<时间>/ 文件夹
查看每张截图。在阅读之前先缩小尺寸(macOS 上使用 sips -Z 960,其他平台使用 ffmpeg -i in.png -vf scale=960:-1 out.png)。检查:
- 文本重叠或溢出边缘
- 平移过程中出现空白帧
- 元素绘制在应该位于其后方的物体之上
修复并重新截图。如果页面无法启动,脚本会打印页面错误。
7. 语音
内置语音(不带 --voice 参数):
$PY SCRIPTS/narrate.py --script <project>/script.json --out <project>/narration --takes 2
已保存的语音:添加 --voice <UTH_HOME>/voices/<name>.wav。
来自录音的新语音:请按照 ${CLAUDE_SKILL_DIR}/references/voice.md 操作。它涵盖了 prep_voice.sh、快速测试行和同意声明。只克隆用户自己的语音,或者他们确认已获得授权的语音。
然后请用户收听:<project>/narration/narration-preview_take1.wav(macOS 使用 open,Linux 使用 xdg-open)。
- 第一次运行会下载大约 1 GB 的模型权重。之后在 Apple Silicon 或 GPU 上大约实时运行,在 CPU 上较慢。
- 你无法听到音频。 告诉用户这一点,请他们用耳朵判断各次录音的效果。他们可以逐行混合不同的录音。使用
--only <id>重新录制单行。 - Turbo 支持标签
[chuckle]、[laugh]、[sigh]、[gasp]和[surprised]。每个视频最多使用一两个。
无旁白:跳过此步骤和 build_timeline.py。场景保持设计时长,视频仅包含音乐和音效。
8. 时间线、渲染、验证
python3 SCRIPTS/build_timeline.py <project> [--pick dns=2,enter=2]
node SCRIPTS/render.js <project> [--music-db -12] [--sfx-db 1] [--silent] [--audio-only]
render.js 构建语音、音乐和音效分轨并进行混音,在语音下方降低音乐音量(避让),并将响度标准化至 -16 LUFS。它渲染为 <slug>.partial.mp4,只有在 ffprobe 确认完整时长后,才将其重命名为 <slug>.mp4。
在告知用户完成之前,验证实际文件:
- ffprobe 显示预期的时长以及视频和音频流
ffmpeg -ss <后期时间> -frames:v 1显示正确的场景- 响度约为 -16 LUFS
然后打开 MP4 和 index.html 预览。预览会同步播放混音,并支持章节和进度条拖动。
简明报告验证了哪些内容、你无法检查的内容(音频效果如何)以及哪些部分经过了简化。
工作规则
- 禁止全局删除。 不要对项目文件夹运行带有通配符的
rm或rm -rf。新输出应放入新文件夹,文件按名称覆盖。 - 已停止的命令可能已部分执行。 如果用户停止了一个多步骤命令,请检查磁盘上的变化,然后继续下一步,并向用户说明任何部分影响。一组被部分替换的剪辑可能会留下一个看似完整的短视频。
- 不要根据偏好暗示自动切换。 如果用户说“我喜欢第 2 次录音”但仍在考虑,请在重新渲染前确认。
- 提供选项,但不主动构建: 9:16 竖版、裁剪至 30 秒、或更多润色。每个选项用一行提及。
故障排除
'NoneType' object is not callable出现在PerthImplicitWatermarker:运行uv pip install --python $PY "setuptools<81"。Chatterbox 的水印库需要pkg_resources。- 首次 TTS 运行缓慢:这是预热和模型下载。后续运行会更快。
- 音乐太响或太轻:使用
--music-db参数(默认 -12)。效果:--sfx-db(默认 1)。使用--audio-only可以快速迭代混音。 - 找不到 Chrome:设置
CHROME_PATH,或加载under-the-hood-setup技能。 - Chrome 的离线音频每次运行不是完全位相同的,因此分轨在不同渲染之间略有差异。时序是精确的,帧画面是像素级相同的。