卡通3D故事短片 (three.js + Remotion)
已验证的示例:为歌而倾倒的桥。这是一部原创67秒短片,讲述1831年布劳顿桥和74名士兵齐步走的故事。
- 代码:Remotion项目的
src/videos/bridge/(合成BridgeShort,1080x1920,30 fps)。 - 脚本、配音和声音:
~/bridge-short/。 - 风格研究:
references/。
风格参考是私下研究的频道(references/:STYLE_BIBLE.md,reports/*.md,frames/)。
- 这些视频是私人学习资料。绝不上传、发布或发送它们。
- 绝不抄袭他们的脚本、角色或镜头。故事、角色和配音始终是我们自己的。
- 绝不在旁白或描述中提及该频道的名称。
适用的用户规则:
- 视频中无字幕或标签。
- 仅限英语。
- 配音:单一稳定语调。
- 笑话基于研究过的真实事实。
- 标准混音:音乐 +3 dB,音效 -6 dB,人声不变。
- 最终导出为2K竖屏:1440x2560,
--scale 1.3333。 - Opus max 验证每一步。
- 每一步后保存。
- 脚本批准后“只管去做”。
流程
- 主题和事实。 选取一个令人惊讶的真实故事,具有物理因果关系(应具视觉性),并附带一个解释它的简单日常类比。
- 将事实及其来源写在
SCRIPT.md顶部。
- 将事实及其来源写在
- 脚本 (~3.7 词/秒,55-70 秒)。源自桥短片的节拍公式:
- 钩子: 一行荒诞的事实(“74名士兵只是在上面走,就把一座铁桥震塌了。”)。
- 设定: 年份、地点、荣耀。
- 行动: 三个或四个节拍的升级,每个都稍大一些。
- 断裂: 崩溃的那一刻。
- 冷面双行: “幸运的是……/不幸的是……”。
- 解释: 通过一个日常类比(荡秋千的孩子)解释一个物理概念。
- 后果: 它创造的规则。
- 回调转折: 结尾。
- 绝不描述观众已经看到的画面内容。
- 配音。 录制或生成
voice.wav,然后制作其单词时间戳words.json(任何带单词时间的语音转文字)。- 将它们放在项目文件夹中,例如
~/bridge-short/voice/。 - 手动修正单词时间戳。所有内容都根据 words.json 进行时间同步。
- 将它们放在项目文件夹中,例如
- 镜头计划 在
story.ts中:复制templates/bridge/(最终的桥源代码,与 Remotion 项目的src/videos/bridge/相同)到src/videos/<name>/,在src/Root.tsx中BridgeShort旁边注册一个新的合成组件,并重命名它。SHOTS:id,a/b 帧,光照(白天/金色),人群模式,tau故事时间。XFADE:地点/时间变化时的交叉淡入淡出。FLASH_AT:钩子后的白色闪光。CAMS:每个镜头的关键帧{f, dur?, cut?, s: f => {pos, look, fov, roll}}。KICKS:冲击翻转震动。DOF/dofAt:每个节拍的镜头模糊。FOREGROUND:近景构图道具。- 每个视觉反应在其对应单词前 0-3 帧落地。
- 世界。
lights.ts:灯光以及每个光照对应的 LOOK 天空/河流/云彩调色板。shade.ts:双色着色和untone()。build.ts:城镇、房屋和 Kenney CC0 套件道具,重新着色,并具有视线剔除功能,移除任何遮挡摄像机的物体。paint.ts:HD Canvas2D 绘制的纹理,接缝处用深色调绘制。world.ts:天空着色器、雾(= 地平线颜色)、河流、逐帧姿态、每个镜头冻结的太阳(相对于摄像机)。
- 角色。
toon.ts:Canvas2DPen绘制 API,600x1000 设计画布,脚底位于 y=975,豆形头,棍状四肢,李子色可变宽度轮廓,面部库。cast.ts:面向摄像机的广告牌、人群、效果卡、眨眼、行走循环。所有广告牌都在NOINK层上。cardshade.ts:由场景光照亮的卡片,无自发光。
- 后期 (
Bridge.tsx+ink.ts+lensblur.ts+grade.ts)。- 合成器顺序:墨线 → 镜头预模糊 → 镜头主模糊 → 泛光 → NEUTRAL 色调映射 → 校色(MSAA 4)。
- 每个像素参数随输出高度 / 1920 缩放。
- 声音 (
~/bridge-short/audio/:timeline.py,sfx_gen.py,sfx.py,music.py,instruments.py,dsp.py,mix.py)。- 事件表 → 合成音效加上在配音下闪避的原创配乐。
- 输出:mix.wav(48 kHz,精确长度),分轨文件和 cues.md。
- 在声音制作前锁定画面的时间常数。任何后续的时间变化都需要重新运行声音。
- 外观检查。 运行
node scripts/bridge-stills.mjs out/<name>/x_ 100,400 0.5。- 设置
BRIDGE_ENTRY=src/sandboxes/<n>/index.tsx以渲染沙箱副本。 - 使用
python scripts/sbs_sheet.py out.jpg --ours ... --ref ...制作与参考帧的并排对比图。 - 将它们发送给 Opus max 验证器:1-3 张图片,一份 ≤200 词的裁决。
- 设置
- 最终渲染。
npx remotion render src/index.ts <Comp> out/<name>/video.mp4 --codec h264 --crf 16 --scale 1.3333- 使用
-map 0:v:0 -map 1:a:0进行多路复用(Remotion 写入静音音轨)。 - 质量检查:
python scripts/short_qa.py final.mp4 out/<name>/qa shots.json检查每一帧的黑帧、白帧、冻结帧和弹出帧,以及响度和表格。 - 修复它发现的任何问题,然后运行一次深入的 Opus 审计。
- 交付。 将最终的 mp4 文件发送给用户,更新记忆,写下笔记。
最终外观值(桥版经过 4 轮验证器;全部位于 templates/bridge/)
从 templates/bridge/ 开始每个新短片(复制到 src/videos/<name>/):外观存在于这些值中,故事存在于 story.ts / build.ts 布局 / cast.ts 角色中。最终 Opus max 评分:颜色白天 7,金色 5-6,光照 5-6,墨线 6,纹理 5-6,角色 7,深度 6-7,构图 6-7(起始于 5/3/4/5/4/7/4/6)。
- 光照预设 (
lights.ts,太阳相对于摄像机并逐镜头冻结):- 白天:az 75 / el 48,亮部 [1.58,1.5,1.33],暗部 [.30,.29,.36],提亮 [.05,.06,.11](仅在暗部使用冷色调),天空顶部 #3e7fd2 → 地平线 #b8d0ec,雾 = 地平线颜色,25→300 m,uSat 1.08,超过 60 m 大约 15% 蓝色雾霾。
- 金色:az 6 / el 7(背光低角度太阳),主光源朝向 #FFB36B ×1.5,紫蓝色暗部(立面 ≈ #444380),天空 #ffc47c → #8a6f8a,仅超过 50 m 有桃色雾,太阳光盘 #ffcf9e + 泛光,接触光斑 + 真实卡片阴影。
- 反照率 (
paint.ts/build.ts):柔和的砖红/奶油/赭石/陶土色房屋,带有基座、檐口、窗台、雨棚、门阶、烟囱 + 烟囱帽,高度 7 / 8.4 / 9.8 m;暖灰/米色石材(饱和度从“故事书”风格降低 35%);赭色木甲板 C* ~51-58 带有近黑色接缝;铁质深色且低饱和度。绝不用柠檬色、薰衣草色照亮的面孔。 - 墨线 (
ink.ts):#030303,近处(6 m)5.1 px → 远处(90 m)3.3 px(1080x1920 下),折痕从 35° 起 ×0.8,深度跳跃 1%,仅远处雾色调 0.3;角色卡片位于NOINK层(它们自带李子色墨线)。 - 镜头 (
lensblur.ts+ story.ts 中的dofAt):1080 下的 cInf px:钩子/河流特写 15-16,近景镜头 12-14,中景 10-12,公园 7,金色摇摆 5,广角/航拍 0。聚焦于前排角色的眼睛。 - 后期 (
Bridge.tsx):墨线 → 镜头预模糊 → 镜头主模糊 → 泛光(阈值 1.0,强度 .5,6 级,半径 .6)→ NEUTRAL 色调映射 → 校色;MSAA 4。存在胶片颗粒但已关闭(参考测量无颗粒;它会使文件大小增加四倍)。 - 角色 (
toon.ts/cast.ts/cardshade.ts):豆形头高/宽 .94,李子色墨线 #241726,眼睛相距 .26 倍头宽,无腮红,14 种表情;成年人 3.5 头高;行走弹跳 5%,倾斜 1-7°,着地步幅 0.8 m;眨眼 0.5-2.3 s;白天脚底紧贴接触阴影约 .5 + 太阳方向拖尾;金色时刻仅内边缘高光(绝不使用偏移的外部副本)。 - 摄像机 (
story.ts):大跳跃时硬切,较平滑步进滑行 18-40 帧,每个静态镜头有缓慢推拉(无 ≥4 帧的完全静态),冲击时翻转震动持续 7 帧并衰减,4-4.6° 倾斜,约 1/3 镜头使用前景道具(FOREGROUND)。
外观目标(参考测量得出;参见 references/reports/)
- 墨线:
- 世界线条:1080 宽度下大约 3 px,近黑色 #0b0a0c,随距离几乎不变。仅用于轮廓、深度跳跃和法线折痕。墙壁/地板接缝或地平线上无线条。角色卡片从未被世界墨线勾勒。
- 角色墨线:深李子色 #201628-#2f1d28,底部/阴影侧更粗。
- 颜色:
- 白天中位亮度约 .57。非墨线区域第 5 百分位约 .23(无死黑)。亮部色度 C* 第 90 百分位约 55。白天天空顶部约 #5e93d9,地平线亮 1.28 倍。
- 金色时刻:桃色地平线 #ffd08a,紫蓝色阴影(绝非棕色),背光太阳。
- 深度:
- 约 1/3 屏幕时间使用景深(特写、中景、插入镜头),1080 下 cInf 10-16 px,聚焦于眼睛。定场镜头和广角镜头保持清晰。
- 雾 = 地平线颜色,白天 25→420 m,金色 20→360 m。
- 仅对 HDR 自发光物体使用泛光:阈值 1.0。
- 摄像机:
- 大跳跃时硬切。其余为 18-40 帧的较平滑步进滑行,720p 下峰值 ≤ 25 px/帧。
- 每个静态镜头每帧推拉 0.15-0.35%,在重读词上为 0.6%/帧。
- 倾斜 4-5°。
- 无手持晃动。冲击震动每帧翻转符号并持续 7 帧衰减。
- 角色:
- 约 3.5 头高,腿长 1.4 倍头高。
- 棍状四肢约 0.055 倍头宽,墨点手。
- 豆形头(高/宽 ~0.93,更窄的下巴,更尖的头顶)。
- 无腮红或眼睛高光。面部亮度约 .93。
- 行走弹跳 3-7%,倾斜 1-7°,着地脚。
- 每 0.5-2.3 秒眨眼一次,持续 4 帧。
外观匹配循环(桥版外观的达成方式;可用于任何“让它看起来像 X”的迭代)
- 首先测量参考。 每个主题(运动、深度、纹理、角色、光照、轮廓、校色)一个分析代理,每个代理将数字(而非形容词)写入
references/reports/<topic>.md。共享简报:compare/CONTEXT.md。报告是后续每个代理的事实来源。 - 沙箱,每个文件一个所有者。 将项目文件夹复制到
src/videos/<name>_{cam,world,mat,char,post},入口文件为src/sandboxes/<n>/index.tsx(与主项目相同的index.tsx,仅更改导入路径)。桥版的所有权分配:- cam:story.ts(摄像机关键帧、硬切、震动、景深表、前景道具)
- world:world.ts,lights.ts,shade.ts,grade.ts(太阳、天空、雾、河流、颜色、校色)
- mat:paint.ts,build.ts(绘画纹理、建筑、道具)
- char:toon.ts,cast.ts,cardshade.ts(角色绘制、姿态、卡片光照、效果卡)
- post:ink.ts,Bridge.tsx,lensblur.ts(轮廓通道、合成器、镜头模糊、泛光)
代理只能在其自己的沙箱中编辑自己的文件,并使用
BRIDGE_ENTRY=src/sandboxes/<n>/index.tsx node scripts/bridge-stills.mjs out/<name>/<n>/x_ <frames> 0.5渲染静态帧。
- 合并 使用
python scripts/bridge_merge.py [cam,world,mat,char,post](将主项目备份到backup/bridge_<time>/,仅复制拥有的文件)。然后npx tsc --noEmit(过滤到项目文件夹),然后在下一轮之前从主项目重新同步每个沙箱(cp -f src/videos/<name>/* src/videos/<name>_<n>/)。 - 验证 使用新的 Opus max 代理:并排对比图(
python scripts/sbs_sheet.py out.jpg --ours a b --ref r1 r2),对每个区域进行十分制评分(颜色白天/金色评分、光照、墨线、纹理、角色、深度、构图)并附带有帧编号的编号修复列表。将每个修复映射到文件所有者,并使用 SendMessage 恢复该所有者的代理(保持其上下文)。桥版评分:第1轮 5/3/4/5/4/7/4/6 → 第2轮 5/4/5/6/4/7/6/6 → 第3轮见笔记。 - 所有者之间的契约存在于导出的常量中(例如来自 ink.ts 的
NOINK层,来自 story.ts 的dofAt/FOREGROUND,来自 lights.ts 的LIGHTS/LOOK)。更改契约意味着告知读取它的每个所有者。
注意事项
- Kenney 自然套件材质是青绿色的:在 build.ts 中按材质名称重新着色。
- 摄像机最终会进入房屋内部:build.ts/world.ts 中的视线剔除器会移除任何遮挡摄像机光线的物体。
- 墨线与景深在同一合并效果通道中时会被覆盖。墨线必须在模糊之前作为自己的通道处理。
- 像素级后期参数必须随分辨率缩放:静态帧为 0.5,最终为 1.333。R3F 将 dpr 限制为 ≥ 1,因此
--scale 0.5的静态帧仍会渲染 1080x1920 的缓冲区。 - 磁盘: 每个 Remotion 包将
public/(~1.3 GB)复制到临时文件夹\remotion-webpack-bundle-*中并且从不删除。在桥版迭代过程中,60+ GB 填满了系统驱动器,渲染因 ENOSPC 失败。始终使用export TEMP='<大驱动器>/remotion-tmp' TMP='<大驱动器>/remotion-tmp'进行渲染(bridge-stills.mjs 会自行设置),并在删除共享临时文件夹中的旧包文件夹前询问用户(自动模式会阻止清理)。<大驱动器>/remotion-tmp 也会被填满(经过 4 轮桥版迭代后约有 ~500 个文件夹 / 110 GB):当一个项目完成且没有进行渲染时,删除其中的remotion-webpack-bundle-*和puppeteer_dev_chrome_profile-*文件夹。 - 在 JS 字符串中写入
"<大驱动器>/remotion-tmp",绝不使用"<大驱动器>\remotion-tmp"(\r会成为回车符)。 - Remotion 写入静音音轨:使用
-map 0:v:0 -map 1:a:0进行多路复用。 - 在这个框架中,子代理无法写入报告文件:要求它们发送一份 ≤150 词的最终消息,然后您自己将其保存到
out/<name>/<n>/REPORT.md。 out/中的临时.ts文件会破坏tsc:将它们命名为.txt。- 2K 渲染运行约 4 fps(67 秒大约需要 10 分钟)。0.5 比例静态帧在约 40 秒打包后每帧需要 3-8 秒。
- 2.5% 的胶片颗粒使 2K 文件达到 910 MB 而不是约 250 MB,并且在 YouTube 上会变得模糊;参考视频中无颗粒。保持关闭状态。
验证器发现的易读性陷阱(检查每个新道具/镜头是否包含这些)
- 画成一根绳子消失在孩子后面的秋千看起来像上吊。 始终使用两根绳子连接宽木板,孩子位于两者之间(toon.ts 中的
swingKid),以及一个腿部能避开弧线的框架(每端一个 A 型框架)。 - 距离镜头小于约 2 m 的道具或漂浮物会变成巨大的截断斑点出现在画面边缘。 当摄像机移动时,重新检查其新位置附近的每个道具(河流摄像机移入了漂浮的帽子中)。
- 被画面边缘切断的前景灌木看起来像一个“绿色球体”;前景道具必须是可识别的或移除。
- 旗帜: 红色 + 黄色星形/菱形看起来像越南国旗。使用符合历史时期的正确旗帜(1831 年英格兰使用圣乔治十字旗)。
- 痛苦
…
[为翻译截断]