Toon reel
你正使用 toon-reel-engine 来执导并制作一部短动画故事。所有内容都是 Python 代码:角色、场景、灯光和摄像机都是代码,每一帧都是时间 T 的纯函数。没有时间轴编辑器,也没有关键帧 UI。你编写数据(关键帧、镜头表),然后 查看每一帧。
引擎布局(请保持此结构,其相对导入依赖于此):
tools/toon/ 引擎:toon.py(渲染器)、rig.py(角色)、anim.py(时间)、cast/、props/、sets/(组件库)
tools/ sound.py(依据提示生成音轨)、mix_check.py(语音清晰度检查)、finish.py(-14 LUFS 导出)、
thumb.py(封面图)、find_phrases.py(解说录音中各短语的时间位置)
episodes/starter/toon 模板:"The Lamp",12.5 秒,四个镜头,一个房间,一个人物。拷贝此文件夹开始制作。
episodes/window/toon 完整示例:"The Man at the Window",50 秒,13 个镜头,两个世界,一个反转。
episodes/jeff、episodes/smilingman 完整示例和组件库的支持模块(不可作为独立剧集运行)
命令。 下面的 python 指已安装 requirements.txt 中依赖的解释器(Windows 上是 py)。剧集本身的脚本(reel.py、build_tl.py、finalize.py)在剧集文件夹 episodes/<name>/toon 中运行。工具从项目根目录运行:python tools/sound.py episodes/<name>/toon。
第一步:查找或设置引擎
在用户自己的项目文件夹中工作,绝不能进入插件的安装文件夹(更新时会被替换)。
- 如果工作文件夹中已有
tools/toon/toon.py,直接使用。 - 否则,引擎随此技能一起提供。其根目录位于此技能基础目录向上两级(
<skill dir>/../..):包含tools/、episodes/、requirements.txt和.gitignore。将这 4 项复制到工作文件夹中,保持目录结构,并告知用户已完成复制。如果该文件夹没有tools/(说明技能被单独复制),则克隆https://github.com/wlr2/toon-reel-engine。 pip install -r requirements.txt,并检查ffmpeg -version是否能正常工作(需版本 5.1 或更高)。字幕需要 Arial Black 字体,或设置TOON_FONT为一个粗体无衬线.ttf文件。- 在构建任何内容之前,先验证设置是否成功:从
episodes/starter/toon运行python build_tl.py,然后python reel.py --frame 5.0必须生成文件review/_f5.00.png。
流程是固定的
脚本 -> 时间线 -> 角色造型表 + 场景帧 -> 封锁表演 -> 检查(两轮) -> 预览 -> 主渲染 -> 音效 -> 混音 -> 导出 -> 后期处理。
在检查通过并记录日志之前,绝不要开始主渲染。在开始动画之前,先向用户展示角色造型表和一张场景帧;在全分辨率预览之前,展示一张带标注的关键帧图。在需要花钱的地方(付费 TTS、付费音效、云渲染)之前先征求用户同意。
1. 脚本(references/script.md)
十步法:从最具体的矛盾开始,一个主要问题,一系列后果,每隔几秒就有一个变化,内容适合朗读和动画,有一个动态的中段,一个有意义且包含标志性台词的结尾,诚实的框架(例如,对于 creepypasta 风格使用“AN INTERNET HORROR STORY”),一个带时间的镜头表,然后进行保留编辑。如果用户提供了脚本或节拍表,以他们的文字和规格为准,而不是这里的内置规则:永远不要重写他们的台词,可以提出修改建议并引用你要修改的内容。
交付物:SCRIPT.md(三个钩子 + 选择,完整旁白,带时间的镜头表,字数统计)和 script.py。
2. 时间线,然后是声音
script.py包含PHRASES(每句台词的放置位置、文本、字幕块,其中红色关键词用[word]标记)和MARKS(以秒为单位的故事节拍,将成为镜头边界)。python build_tl.py会生成timeline.json(包含total、marks、lines)。短片只读取timeline.json。 在模板示例中,它在任何音频存在之前就能工作:短语时长根据字数估算,因此你可以先规划画面。- 声音需要每个说话者一个录音文件,48kHz 单声道,可以来自任何 TTS 或麦克风(本仓库不包含任何 TTS;ElevenLabs 是付费的,Kokoro 是免费的本地库)。永远不要为了适配时长而加速录音:而是应剪掉一个节拍。在发送给 TTS 的文本中,将数字拼写为单词。
python tools/find_phrases.py take.wav会打印录音中每个短语的(start, end)时间。将它们填入PHRASES并重新运行build_tl.py:它会切出短语、放置它们并生成audio/narration.wav。然后重新检查每个镜头:实际短语长度与估计值不同。- 技能附带的
build_tl.py文件处理单个旁白者。若有多个说话者,则每个说话者保留一个录音文件,并将说话者添加到每个短语中(这需要对build_tl.py做一点小改动)。 - 针对 TikTok 的脏话处理:在单独的音轨中进行哔声处理,并在字幕中用星号代替(
f***ing)。
3. 剧集文件(references/engine.md)
| 文件 | 职责 |
|---|---|
script.py | 台词、字幕块、标记 |
build_tl.py | 生成 timeline.json(以及 audio/narration.wav) |
looks.py | 角色:每个造型是 rig.LOOK 中的一个字典 |
scenes.py | 世界:场景几何体、灯光、谁在时间 T 在哪里、表演轨道 |
reel.py | 镜头(SHOTS)、字幕、render(T)、检查命令和渲染命令 |
cues.py | tools/sound.py 使用的声音事件 |
finalize.py | 混音各音轨,合并到渲染视频,运行 tools/finish.py |
通过复制 episodes/starter/toon 到 episodes/<name>/toon 来开始一个新剧集。 其 reel.py、build_tl.py 和 finalize.py 是通用的,可以保持原样;你需要替换 script.py、looks.py、scenes.py、SHOTS 表和 cues.py。不要从 episodes/window/toon 开始,它的 reel.py、cues.py 和检查逻辑是针对该故事定制的(两个镜像世界、命名标记、自定义反转镜头)。可以阅读它学习技巧:纹理、景深、每个世界的脸部关键帧、玻璃上的手、跨世界淡入淡出。较大的剧集应将表演逻辑从 scenes.py 移到单独的 acting.py 中。
一个世界需要两个方法:draw(fr, cam, T),绘制所有内容并返回 {pid: rig.draw 的结果};以及 cast(T),返回 [(pid, look, pose)]。pid 是剧集中的角色 ID(例如 "nora")。每个地点一个世界和一个时间线;镜头只选择摄像机。
4. 造型(references/look.md)
圆润简单的形状,头部稍大,大眼睛富有表现力,哑光材质,带柔和的 3 级渐变阴影,以及比底色更深的外轮廓线。每个角色根据剧本拥有自己的剪影、面部和配色设计(绝不能对另一个短片的角色进行换皮);重复出现的角色保持造型一致。在动画制作前,从 tools/toon 运行 python -m cast.sheet ../../episodes/<name>/toon/looks.py <look> 制作造型表(它会在项目根目录生成 assets/kit/cast/<look>.png,或者你指定的第三个参数路径)。
5. 布光(references/lighting.md)
每个场景都有三层:冷色环境光(蓝紫色夜晚能保留细节),每个面部的柔光主光(从上前方来,由台灯或窗户激发),以及暖色实用光源(分布在几个距离上,照亮它们附近的东西)。面部是画面中最清晰的部分;背景在面部周围稍暗且对比度稍低。脚底、家具和接触的手部有接触阴影。每个地点一个灯光方案:方向、颜色和曝光在剪辑间保持一致。没有发光效果、没有发光轮廓、没有纯黑区域。当故事中有天气时,在安静时刻动画化天气(雨、雪、风)。
6. 摄像机(references/camera.md)
- 每 2-3 秒一个切。每个镜头服务于一个动作、一个表情或一个揭示。
- 钩子(0-3 秒)是短片中最漂亮的运动镜头:从第一帧起摄像机和角色就开始运动。
- 先全景双人镜头,然后匹配的单人特写。特写镜头保持在视线方向约 35 度范围内。
track(a, b, ease)在两个关键帧(position, target, focal px, horizon)之间进行一次干净的运动。摄像机会转向面对目标,但不能倾斜:目标的纵轴高度会被忽略。通过调节摄像机高度和horizon值(较小的值使视线在画面中更高,看起来像是向下看)来上下构图。- 保持摄像机与画面中任何人的距离 >= 0.45 米:
rig.draw不会绘制比这更近的人。 - 字幕(Arial Black 66px,白色,黑色描边,关键词 #FF4D4D)绝不能出现在脸部或手上。使用
cap=(y, size)为每个镜头移动字幕位置。
7. 表演与舞台调度(references/acting-staging.md)
每个动作都是带有偏移量的链条:眼睛 -> 头部 -> 肩膀 -> 身体 -> 手,按照预备 -> 动作 -> 稳定结束的顺序。反应使用缓出/突然停止,稳定结束使用缓回。抓取动作在手掌合拢之前先行靠近。一个只转动头部和肩膀的角色可以站在默认脚位上;一个需要行走或转动身体的角色,其双脚必须固定在世界空间坐标中(使用来自 rig.replant 或 rig.gait 的 ankle_R/ankle_L),一次迈出一步。在封锁任何表演之前,请阅读舞台调度故障清单:每一个都是已经发生过的错误。
8. 检查:每次主渲染之前的关口(references/checks.md)
python reel.py --check-> 读取整个review/reel_checks.txt。在模板示例中,每个问题都是ANOMALY行:伸臂问题、脚部陷入地面、肘部过度弯曲、肘部和膝盖翻转、抖动、人物离镜头太近、字幕遮挡脸或手。python reel.py --stills-> 每个镜头的第一/中/最后一帧(第一轮检查)。python reel.py --sheet <SHOTS>-> 每一帧 的接触镜头、行走、转身和遮挡变化,以分帧图形式输出(第二轮检查)。检查分离、肢体弹出、头部穿过物体、物体消失等问题。- 在数据中修复后重新运行,并在
review/LOG.md中记录每条异常(只追加写入):时间、镜头、原因、修复方式、验证方式;以及接受标记(附理由)和无法检查的部分。 - 绝不能仅凭代码就声明“无异常”。代码检查的是关节而不是画面:它无法看到人物穿过家具或彼此、道具没有握在手中、错误的绘制顺序、或一个 0.8 米的侧向步幅看起来像劈叉。这些需要你在分帧图上自己发现。
9. 渲染(从剧集文件夹)
python reel.py --preview --full->review/reel_preview.mp4(1080x1920,无声)。python finalize.py preview添加混音 ->review/preview.mp4。展示给用户,获得批准。python reel.py --master-par 12->video/reel_silent.mp4:使用 12 个进程的主渲染(根据你的核心数调整)。
10. 音效、混音、导出、后期处理(references/sound-finish.md)
cues.py,然后从项目根目录运行python tools/sound.py episodes/<name>/toon-> 生成音乐、音效和氛围音轨。真实物体使用真实录音(将 CC0 或已授权样本放入assets/sfx/);只有抽象的嗡嗡声、上升音和爆音才使用合成音。模板示例的提示音全部是合成的以便流程运行:请替换它们。python tools/mix_check.py episodes/<name>/toon:人声在任何一句台词上必须比背景音高 >= 10dB(在有人声录音之前每一句都会失败)。python finalize.py final(在剧集文件夹中运行) ->tools/finish.py-> -14 LUFS,<= -2 dBTP,H.264 High,+faststart。- 封面图,从项目根目录运行:
python tools/thumb.py frame.png cover.jpg --line "TITLE:#F2EFE6:120"。 POST.md:各平台的字幕、话题标签,以及提醒在应用中开启高清上传。
本文使用的术语
- mark:一个以秒为单位命名的故事节拍(在
MARKS中),用作镜头边界和动作的计时依据。 - station:角色站立的位置(x, z,朝向)以及他们走到该位置的时间。
- planted foot:在世界坐标中固定了一个脚踝位置(
ankle_R/ankle_L),使脚不会滑动。 - clip zone:屏幕空间裁剪区域,用于隐藏身体的一部分(如树篱、墙边)。
- wall-flat item:挂在墙上的平面布景(窗帘、海报);将其排序到墙的最远层。
- practical:场景中可见的光源(台灯、亮着的窗户)。
工作习惯
- 先看再断言。渲染画面,读取分帧图,然后说出你看到的。
- 一次更改,一次受影响镜头的重新渲染,一次重新检查,并附上分帧图。
- 当某个舞台调度反复失败时,简化它或选择一个更清晰的角度。绝不能依靠模糊、黑暗、剪辑或字幕来掩盖问题。
- 将用户的每一条修正意见写入剧集的
review/LOG.md中;如果是通用性的,写入项目根目录的STAGING_NOTES.md(在每集开始时阅读)。绝不能写入插件自己的文件夹中。