教学短片
教学短片旨在讲解一个机制,让新手观看一遍后就能向他人复述。每一帧画面均由代码绘制,叙述者的声音充当节拍器,音乐在语音间隙间播放。它基于 code-film 构建:后者负责外观、画廊、品味和缺陷检查。本技能则负责教学、词句、语音、节奏、结尾以及YouTube相关的一切。
示例作品位于 examples/parcel42-lesson/,是一段关于Apache Pinot的upsert如何隐藏旧行的130秒教学视频。该技能的作者Kartik在八个版本后称其为“完美”,过程中的所有笔记都记录在对应的参考文件中。阅读其README以了解方法论,而非外观。
核心:追踪观众
教学短片是一场对话的一半,观众在沉默中提供另一半。每一秒,他们都掌握三样东西:
- 他们已知的。 仅限于影片到目前为止展示和讲述的内容,加上日常知识。不包括源代码,也不包括你为了制作而阅读的内容。
- 他们正在追问的。 每一幅画面和每一个主张都会引发下一个问题:“那么旧的那个会怎样?”、“如果它来晚了呢?”、“那不会浪费空间吗?”
- 他们相信的。 一个仅从影片中构建的机制模型。一个错误的词语就会植入错误的模型。“Pinot从不推倒旧房子”传达了没有任何东西被移除,而后续影片却展示了合并将其移除。
制作影片就是在每一秒运行这个模型,同时兼顾语音和画面:
- 在观众产生疑问的地方回答问题。 迟到的信件紧跟在规则之后,“那暗色的房子呢?”紧跟在查询之后。
- 在宣布之前,让他们自己先到达。 画面在语音命名之前一个节拍展示证据。标题、标签或章节名称从不先于问题给出答案。
- 绝不切断线索。 一句承诺了什么的台词,必须拥有下一幅画面。在“两个开关翻转”之后,屏幕上接下来必须是开关。
- 在使用每个词语之前,先将其交给观众。 屏幕上的每个术语都至少在画面展示它时被大声说出来一次,并且没有一个术语会出现在第一行。现实世界中的事物先出现,术语随后被命名。除了那行命名语句外,一句话应保持在同一个世界:一朵花已经停止生长,它永远不会“关闭”。一整段影片在路牌上显示了“segment 7”,却从未说出segment这个词。
- 教授机制,而非代码。 只有当观众会去搜索该名称时才展示真实名称(如
validDocIds),永远不要展示仅用于标记机制的函数名。
参考文件中的所有规则都是这五条法则的应用。当一条规则似乎与另一条冲突,或者没有覆盖某种情况时,运行观众模型,由它来决定。
一条笔记从不针对单个实例。 当你为之制作影片的人指出某一时刻时,他们是指出了模型崩溃的一个地方。找到所有以相同方式崩溃的其他地方,全部修复,并报告数量。Kartik的“痛苦节拍”既包括填充音,也包括叮当和咔嗒声。他缺失的字母是任何从固定帧计时的现象,这就是 shiftcheck.py 存在的原因。他的“错误短语”是每一个绝对化的词语,这就是 scriptcheck.py 列出它们的原因。
设置
本技能需要 code-film 安装在其旁边,位于同一技能文件夹内。其构建、门控、捕获、接缝和声音检查以及手写体均来自那里,每个脚本都会在那里或 $CODE_FILM 环境变量指向的位置找到它。
运行 bash assets/setup.sh 一次。它会检查 code-film 的doctor,然后在 ~/.cache/lesson-film/venv 构建一个包含Kokoro、soundfile、faster-whisper和spaCy英文模型的Python 3.12虚拟环境,并检查ffmpeg是否包含 loudnorm 功能。
良好效果的标准
- 新手能够复述。 他们所说的两句话与意图卡上的要点一致,且真实术语放在正确的位置。
- 听起来像是一个人在向你解释。 每个句子都自然引出下一个,每次场景切换都承载着当前的问题。不看画面朗读脚本。如果听起来像是一个标签列表,说明还没完成(
reference/words.md)。 - 节奏有呼吸感。 观众在下一个变化发生前有时间看清每个变化。Kartik发现一段64秒、每秒0.36个剪辑的片段“节奏太快”。通过剪辑的版本时长130秒,每秒0.16个剪辑,语音速度正常且带有真实的呼吸(
reference/pace-and-ending.md)。 - 每个主张都是真实的,且经过核实。 在任何绘制之前,将主张写入
facts.md并与源材料进行核对。画面精确展示该状态。 - 画面随词语变化。 每样东西都在语音提及它的那一刻出现。运动和颜色仅位于正在被解释的部分上(
reference/teaching.md)。 - 开篇柔和,结尾舒缓。 第一行简单易懂,同时画面和音乐已经开始,一个冷开场以问题结束,接着是一个大约五秒的标题冲击,就像Kurzgesagt的做法。Kartik对一部从一个观众尚未见过的角色开始的影片评价是“开头感觉很突兀”(
reference/pace-and-ending.md)。 - 影片是结束,而非停止。 一个回顾,一个回报,一句与开场呼应的结束语,一个主和弦,然后画面和声音在数秒内一起淡出。“结尾很突兀”是绝不能再收到的评价。
- 缺陷为零。 无闪烁,无爆音,无削波,响度在-14 LUFS,每个词都听得清。
这些是判断,而非规则。当意图卡说明了原因时,可以打破它们。
工作流程
将此流程复制到你的笔记中,并在完成每一项后报告。一项不能在被勾选时不说明是如何完成的。
[ ] 0 参考 仅当他们分享了一个参考资料时。一个片段、一张静态图片或一个HTML页面。报告其形式、作用、哪些差距可以弥合,以及你采取和舍弃了什么。
[ ] 1 事实 根据源材料编写 facts.md。报告主张及其核实位置。
[ ] 2 意图 将 assets/intent.md 复制为 <piece>.intent.md,包括要点、感觉、问题、猜测。报告它们。
[ ] 3 画廊 code-film 的 reference/gallery.md,找到两到三部最相似的影片。报告你借鉴了什么以及你不会复制什么。
[ ] 4 草图 三个新的故事,每个都是用工具包(sketch.py)绘制出的看起来很完整的静态图,其中一个是你愿意生活其中的世界,不能从示例或共享参考资料中选取。sketchcheck.py 没有 BLOCK 错误,然后根据评分表进行评判。展示它们。报告每个故事的核心思想、三个评判答案以及最终选择。
[ ] 5 词句 首先将整个脚本作为一段写在 <piece>.chain.txt 中,然后根据“术语”、“事物”和“技术”将其切分成行。在段落之前,为每个术语写出其对应的事物,并为每个真实状态写出世界的动词。scriptcheck.py 没有 BLOCK 错误。报告该映射、朗读一遍脚本、每个关键转折点,以及对每个 REVIEW 项的决定。
[ ] 6 语音 <piece>.lines.json -> voice.py -> heard.py --write。报告时长,以及每个被听到的词或未听到的原因。
[ ] 7 计划 场景,每个场景都与改变它的词句以及它们共享的世界状态相关联。报告计划,包括展示每个术语的世界中的事物和每个真实状态的世界的动词。
[ ] 8 构建 从 assets/template/ 创建页面。先在草稿中单独检查场景。报告你在查看后重绘了什么。
[ ] 9 声音 从 assets/score_template.py 创建 <piece>.score.py。报告和弦、间隙中的曲调以及世界中的声音。
[ ] 10 渲染 assets/build.sh。先使用 DRAFT=1。报告数字。
[ ] 11 验证 以下所有三个层面。报告每一个。
[ ] 12 交付 每次构建都创建新文件,绝不覆盖。用于YouTube的母版,以及一个小于30MB的预览版用于发送。
步骤1到5是决定教学效果的关键。特别是步骤5:先以散文形式写稿,然后再切分成行。先切分行是导致脚本变成一叠字幕的原因。
验证
在交付说明中分别报告所有三个层面。
- 缺陷检查块。
build.sh运行scriptcheck.py(每个术语都被说出来,没有一个在第一行,检查关联是否存在)以及 code-film 的check.py和seamcheck.py,母版处理至-14 LUFS集成功,真实峰值为-1.5 dBTP,并按照YouTube规范编码(reference/youtube.md)。 - 教学效果被量化。
verify.py检查意图卡中的时长、节奏和声音。heard.py转录语音并报告哪些词未被听清以及声音相对于提示时间的滞后程度。wordsync.py检查画面绑定词上的运动是否出现。shiftcheck.py渲染语音延迟两秒后的影片,并标记出任何发生变化的场景,这是如何发现从固定帧计时的事件。captions.py根据相同的提示编写精确的SRT字幕文件。 - 观看测试先是你的,然后才是他人的。 像新手一样复述它。命名联系表中的每一个片段。关闭声音观看。不带画面朗读脚本。独立评判最后十秒。然后坦白说明你没有检查什么,比如是否凭耳朵听了语音。
何时阅读什么
每次完整阅读一个文件,一次调用一个文件。如果读取时报告了分词截断,则需单独重新读取该文件。code-film 的“何时阅读什么”说明了批量读取的代价。
- 当他们分享了一个参考资料时,阅读 code-film 的
reference/references.md。它涵盖了所有三种形式。一个片段和一张静态图片需要用 ffmpeg 进行拆解。一个HTML页面,无论是我们的还是他们的,都要通过 code-film 的assets/refpage.mjs处理,它会观察页面绘制并报告其调色板、标记、图层和音频工具包,并写一个MP4文件,以便片段检查也能在其上运行。 - 在编写事实和意图卡之前,阅读
reference/teaching.md。 - 在绘制草图之前,阅读本技能的
reference/sketches.md及其reference/traps.md中的“故事”部分。然后阅读 code-film 的reference/story.md了解“先选择一个形状”和“什么持续存在”,以及 code-film 的reference/traps-story.md。 - 在编写脚本的任何一个字之前,阅读
reference/words.md。 - 当规划开头或结尾,以及设置语音速度、呼吸和停顿时,阅读
reference/pace-and-ending.md。 - 当制作或修复语音时,阅读
reference/voice.md。 - 当规划场景、将其拆分给辅助函数,或构建页面时,阅读
reference/film.md,以及 code-film 的reference/moves.md(它负责两张图片之间的转换)。 - 当制作声音时,阅读
reference/sound.md,以及 code-film 的reference/sound.md了解乐器及其reference/traps-sound.md。 - 在首次渲染之前以及收到任何关于渲染的反馈之后,阅读
reference/traps.md。 - 在发布之前,阅读
reference/youtube.md。 - 当需要规则的来源,或有人询问技能为何如此运作时,阅读
reference/research.md:证据、效应大小和链接。 - 了解外观、品味和印刷效果,阅读 code-film 的
gallery.md、taste.md和press.md,以及在调优最终效果之前阅读其traps-print.md。
文件列表
| 文件 | 说明 |
|---|---|
assets/setup.sh | 一次性设置:语音和聆听的虚拟环境,以及各种检查程序 |
assets/intent.md | 教学意图卡,在 code-film 的卡片基础上增加了教学要点 |
assets/voice.py | 使用 Kokoro 朗读 <piece>.lines.json,将词行置于节拍网格上,生成语音和提示 |
assets/heard.py | 使用 Whisper 转录语音,报告缺失的单词和延迟,--write 将延迟信息存储到提示中 |
assets/saytest.py | 尝试 Kokoro 发音错误单词的不同拼写,并判断 Whisper 能正确识别哪个 |
assets/captions.py, assets/wordsync.py | 从提示生成 SRT 字幕,以及检查每个绑定词上是否出现运动的程序 |
assets/shiftcheck.py | 检查每个场景是否以语音为时序依据,而非固定帧 |
assets/scriptcheck.py | 脚本检查:术语是否被说出、是否出现在第一行、每个术语所指的事物是否在术语前被说出、关联是否存在,以及列出绝对化的词语、未说出的屏幕词语和混淆世界与现实系统的句子以供阅读 |
assets/sketchcheck.py, assets/barsheet.py | code-film 的草图检查,使用本技能认可的帧、示例中的场景和模板的存根运行。以及重建评判表的脚本 |
assets/score_template.py | 每行一个背景音轨,间隙中的曲调,状态变化时的世界中声音,语音下16 dB的闪避,渐弱结尾 |
assets/build.sh | 页面、门控、并行捕获、接缝、配乐、-14 LUFS母版处理、编码、字幕、联系表、所有检查 |
assets/template/ | 要复制的页面:assemble.py、film/kit.js(不含世界内容的工艺:墨水、点、边缘、光、手写体、印刷效果)、film/core.js(语音时钟、层、相机、俯冲和虹膜移动)、film/main.js、film/SCENES.md、一个构建单个待用对象的示例场景,以及带有 sketches/sketch.js的sketch.py 用于三个故事静态图 |
reference/stills/ | 来自已验证教学视频的带字幕帧,用于说明仅靠散文无法传达的两条规则:开头和结尾节拍,以及画面随词变化。还有草图评判表 sketch-bar.jpg(仅在你完成自己的三个草图后打开)和 sent-back.jpg |
examples/parcel42-lesson/ | 已验证教学视频的完整源代码、语音轨道、供观看的视频预览链接、其README、联系表和缩略图 |
并行捕获功能位于 code-film(assets/capture-range.mjs、assets/capture-par.sh),因为任何长片都需要它。
修改本技能
说明意图和判断,并根据意图检查结果。一个得到认可的新教学视频将作为第二个示例出现,并在本文件中说明其工作原理。学到的一课将被记录到拥有它的一个参考文件中,所有其他文件都将在一行中指向那里。