卡通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 words/s,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: 使用 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 写入静音音轨)。 - QA:
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,太阳相对于相机固定并冻结在每个镜头中):- 白天:方位角 75 / 仰角 48,受光面 [1.58,1.5,1.33],阴影面 [.30,.29,.36],提升 [.05,.06,.11](仅在阴影中有冷色调),天空顶部 #3e7fd2 → 地平线 #b8d0ec,雾 = 地平线颜色,25→300 m,uSat 1.08,超过 60 m 约 15% 蓝色雾霾。
- 金色:方位角 6 / 仰角 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 像素 → 远处(90 m)3.3 像素,在 1080x1920 下,折痕从 35° 开始 ×0.8,深度跳跃 1%,仅远处雾色调 0.3;角色卡片在NOINK层(它们自带李子色墨线)。 - 镜头 (
lensblur.ts+story.ts中的dofAt):在 1080 下 cInf 像素:钩子/河流特写 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 秒;紧贴脚底的接触阴影约 .5,白天有太阳方向尾迹;金色光线时仅内边缘发光(永远不是偏移的外部副本)。 - 相机 (
story.ts):大跳跃时硬切,18-40 帧平滑步进滑动,每次停顿都有微推(无超过 4 帧的静止停顿),撞击时衰减 7 帧的翻转抖动,4-4.6°的转动,约 1/3 的镜头有前景道具 (FOREGROUND)。
外观目标(根据参考测量;参见 references/reports/)
- 墨线:
- 世界线条:在 1080 宽时约 3 像素,接近黑色 #0b0a0c,几乎不随距离变化。仅轮廓、深度跳跃和法线折痕。墙壁/地板接缝或地平线上没有线条。角色卡片从不由世界墨线勾勒。
- 角色墨线:深李子色 #201628-#2f1d28,在底部/阴影侧更粗。
- 色彩:
- 白天中值亮度 ~.57。非墨线第 5 百分位 ~.23(无黑色被裁切)。受光面彩度 C* 第 90 百分位 ~55。白天天空顶部 ~#5e93d9,地平线亮度 1.28 倍。
- 金色:桃色地平线 #ffd08a,紫蓝色阴影(从不棕色),逆光太阳。
- 深度:
- 大约 1/3 的屏幕时间有景深(特写、中景、插入镜头),在 1080 下 cInf 10-16 像素,对焦在眼睛上。定场镜头和广角镜头保持清晰。
- 雾 = 地平线颜色,白天 25→420 m,金色 20→360 m。
- 泛光仅作用于 HDR 自发光物体:阈值 1.0。
- 相机:
- 大跳跃时硬切。其他所有镜头都是 18-40 帧的平滑步进滑动,在 720p 下峰值 ≤ 25 像素/帧。
- 每次停顿推近速度为 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),对每个区域按 10 分制打分(色彩白天/金色、光照、墨线、纹理、角色、深度、构图),并附带有帧编号的编号修复列表。将每个修复映射到文件所有者,并用 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 中的视线剔除器会移除任何遮挡相机光线的物体。
- 如果与 DOF 在同一合并效果通道中,墨线会被覆盖。墨线必须在模糊之前有自己的通道。
- 像素级的后期参数必须随分辨率缩放:静帧为 0.5 倍,最终为 1.333 倍。R3F 将 dpr 钳制到 ≥ 1,因此
--scale 0.5的静帧仍然渲染 1080x1920 的缓冲区。 - 磁盘: 每个 Remotion bundle 都会将
public/(~1.3 GB) 复制到临时文件夹\remotion-webpack-bundle-*中,并且从不删除。在桥短片迭代过程中,60+ GB 填满了系统盘,导致渲染因 ENOSPC 而失败。始终使用export TEMP='<大驱动器>/remotion-tmp' TMP='<大驱动器>/remotion-tmp'进行渲染(bridge-stills.mjs 会自行设置),并在删除临时文件夹中的旧 bundle 文件夹之前询问用户(自动模式会阻止清理)。<大驱动器>/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 秒 bundle 后每帧需要 3-8 秒。
- 2.5% 的胶片颗粒会使 2K 文件达到 910 MB 而不是约 250 MB,并且在 YouTube 上会变得模糊;参考素材中没有颗粒。请保持关闭。
验证器发现的易读性问题(检查每个新道具/镜头是否存在这些问题)
- 如果秋千只画了一根绳子,并且消失在孩子身后,看起来像是上吊。 始终使用两根绳子连接一块宽木板,孩子坐在中间(toon.ts 中的
swingKid),并且框架的腿要避开摆动弧线(两端各一个 A 形框架)。 - 距离镜头约 2 米以内的道具或漂浮物会变成巨大的、被裁切掉的模糊块。 当相机移动时,重新检查其新位置附近的每个道具(河流相机就移动到了漂浮的帽子中)。
- 被画面边缘裁切的前景灌木看起来像一个“绿色球体”;前景道具必须可识别,否则就不放。
- 旗帜: 红色 + 黄色星星/菱形看起来像越南国旗。请使用符合历史时期的旗帜(1831 年英格兰使用圣乔治十字旗)。