一张静帧,然后整部影片——以及两个角色怎样共用一棵目录树
这些准则是做 MECHANICAL LEPIDOPTERA 时挣来的,它就是 example/ 里那个完整示例。下面每一条规则都在那部影片上付过学费;哪里的错误是导演自己犯的,这里就照实说,因为带着伤疤的规则,人们才守得住。
错误,而且是我的。 我的 spec 第 3 版有八道闸门。第 4 版有七道,静帧优先,每一张审完才开始下一张:一张花毛茛设定页、六张蜕变静帧、三张设定页静帧、对目的地画面的再次审批。感觉很严谨。它实际做的事,是让客户一轮又一轮地审批一部她还看不到的影片的碎片,而她真正想要的东西——一部影片——始终停在零帧。她叫停了这道闸门,要求看完成的影片。她是对的。交回来的影片有一些任何静帧都显示不出来的问题(节奏、流畅度、那次拉远有没有动机),而静帧一直在争论的那些问题一个都没有。
为什么一张静帧值得,七张不值得。 一张静帧恰好回答一个问题:是不是这个样子。线条、填色、调色板、密度、写实程度、媒介。这个问题问起来便宜(一张静帧不到一分钟就渲染完),问晚了却是灾难(我们前一部影片的第一版角色阵容,是在场景已经搭在它上面之后才被否决的;我们的第一只蝴蝶,是在已经放进两个场景之后才被否决的)。所以这个问题你只问一次,并且好好问。其他一切——故事、节奏、摄像机、连贯性、音乐——只存在于运动之中,而从一个粗糙的整体里学得最快。
规则。
- 一张样子静帧,影片里最难的那一帧:主角题材画得大,处在它的世界里,用最终的媒介、最终的光。如果题材是现实世界里的东西,再加一张标本样张(realism-and-craft.md)。只有确实存在另一种截然不同的样子时,才再加一张静帧(我们有两种媒介,所以是两张)。这就是上限:三张图。
- 先自己批评它,写成文字,对照手艺及格线的对照表,并且在拿给人看的时候说清还有哪里不对。
- ✋ 一次审批。
- 然后不停顿地从头做到尾。 第一天就有一部粗糙的完整影片,胜过一个完美的第一幕。机械检查持续运行,不需要任何人审批:类型检查、网格、契约扫描、绘制预算、确定性探针、冷场。
- 整体只审一次。 从渲染出来的文件本身审:每拍一格的联系表(contact sheet),每个切点做成前后一对并附上差异度量,冷场数值,联系表引起怀疑的地方再抽几帧全分辨率看。一份编号的修改清单,排好优先级。一次重建。这一次审查怎么跑(四种读法、一张记分卡、闸门):workflows/review.md。
- 审批是一笔预算。 每道闸门都要花掉客户的注意力和你的 token。把它们花在出错代价高的地方,也就是样子、音乐小样和最终影片。三次,不是三十次。
好的审查是什么样子(过度设闸的流程里,这一部分值得保留):看之前先冻结文件的一份副本并记下它的哈希,因为构建者可能正在你底下重新渲染(它确实这样做了,两次)。先报告哪些地方好,好让它们在修改中保留下来。给出原因,而不是印象:不是「身体是绿的」,而是「太阳圆盘叠印在胸部上,蓝乘黄」。错在你自己的 spec 时,同一口气就把它改正过来(我规定的 5 帧翅膀滞后,放在 10 帧一拍上就成了反相:一只翅膀合上时,另一只正张开)。
两个角色、书面交接,以及重置
为什么要分开。 构建一个镜头的人无法用新鲜的眼光看它,而审查自己作品的人是在给自己付出的努力打分。把导演(故事、spec、样子、审查)和构建者(引擎、确定性、契约、渲染)分开,给了我们一个从没见过代码那些借口的审查者,和一个从不被要求在截止期限前拿出品味的构建者。客户仍然是审批者和传话人。
行之有效的模式。
- spec 是意图的唯一来源,故事一变就整份重写,绝不一层层打补丁打成一张重写本。我们的 spec 一天里改了四版;第 2 版是一个「第 12 节取代第 5 节和第 9 节」的补丁,所有人——包括我——都读错了。把每一行属于导演自己拍板的内容都标出来(我们用的是 FABLE),这样客户一行字就能否决,不用到处找。
- 构建者在项目里维护一份持续更新的决策日志:设计决策、偏离、取舍、悬而未决的问题,每批做完后追加,附上数字和哈希。导演靠它了解实际造出来的是什么,本文里最好的教训也都是在那里发现的。
- 审查就是文件:
reviews/<thing>-r<N>.md,条目编号、排好优先级,内容自足到可以一字不改地转达。 - 两个 agent、同一棵工作树,一定会撞车。 构建者在我正在审的文件上重新渲染;我改了一个它正打开着的源文件。终结这件事的协议:导演审的是一份冻结的副本(记下哈希),只写审查文件,构建者活跃期间绝不碰共享的源文件或输出。导演的小补丁只有在构建者空闲时才允许,并且每一处都带一行注释,说明是谁、为什么。
- 一个绿色对勾是一项声明。 重新跑一遍。构建者报的「G-AIR PASS」是真的,而那一秒近乎静止的画面也是真的。
重置。 长会话会腐坏。我们的会话把这一点表现得很清楚:客户的消息开始到达时前半截被截掉了,上下文在我底下被摘要,我发现自己差点就在半句话上重建一个计划。征兆是下面任意一条:你在猜对方问的是什么;你在重新推导早已决定了的东西;你的回答越来越长、越来越不确定;运行框架(harness)本身报告上下文质量低。
不要硬撑。重置:
- 先把状态写到磁盘上。 spec 是最新的,决策日志是最新的,未结的审查已归档,再加一份简短的记忆笔记:角色分工、三句话讲完的故事、硬性规则、东西都放在哪里、已知的环境陷阱。
- 清空会话。
- 用一条消息重新交代,附一份「先读」(READ-FIRST)清单:spec、契约那一节、已经构建好的模块、记忆笔记。第一行写明角色分工。任务放在最后。
- 新会话先核实,再信任。 读文件、查磁盘、说出哪里和交代的内容对不上。(我们的新会话在头五分钟里就发现,那个「已经构建好」的摄像机并不在源码里。)
一次重置花了我们大约十分钟,因为状态都在文件里。如果状态只在对话里,它会让整个项目付出代价。还有,一条消息被截断到达时,先去会话记录里找完整原文,再去猜;有两次,缺掉的那一半改变了整个任务。
把 token 和时间花在买得到东西的地方
发布片花了 1.88 亿个 token,其中大约 99% 是对同一个 75 万 token 上下文的缓存重读。没有一个花在画画上。下面这些习惯把它砍掉了一个数量级:
- 每一版剪辑一个会话,配一份交接文件。 一版剪辑完成时,把状态写下来(有什么东西、对方给出的规则、还有什么没解决、文件放在哪里),然后在一个读取这份文件的新会话里开始下一版剪辑。长会话每一轮都要把它的整个历史重读一遍。
- 帮手只拿写好的 brief,绝不用继承上下文的分叉(fork)。 帮手拿到一份简短的书面 brief 和它需要的那几个文件。分叉会继承整段对话,并在每一次调用时为此付费。
- 审查用 0.3-0.5 倍的联系表(
ffmpeg -vf "fps=1,scale=576:-1,tile=4x4"),只有联系表引起怀疑的那块裁切才看全尺寸。已经判断过的大图,绝不要再读一遍。 - 任何完整渲染之前,先出一张选项页。 转场、文字样式、调色板:一张静帧页上并排放三到六个变体,一条消息里挑定。
- 时间线即数据。 场景放在同一条内容时间线上,剪辑是一份片段列表(
launchCut.ts)。调整时间只改这份列表;场景代码和针对它的审查依然有效。 - 区间渲染。
render.mjs <film> --from F --to T只渲染[F, T)这些帧,无声(配乐会对不上),写入out/<film>.<F>-<T>.mp4;--out指向完成的影片时它会拒绝。用于审查,不用于交付。 - 多张静帧,一个浏览器。
still.mjs <film> --frames 0,700,1500在一个页面里画出列出的每一帧(一次构建、一次启动、样张只烘焙一次);区间也行,--frames 0-300:50是从 0 到 300 每隔 50 帧取一帧。加上--sheet out/sheet.jpg,就以--sheet-scale(默认 0.4)把它们拼成一张联系表。--out out/dir/或--out out/x-{frame}.png指定 PNG 的命名。 - 样张缓存。 画完的样张帧保存在
engine/.cache/bakes/<browser version>-<binary>/里,以样张整个导入闭包的哈希为键,所以一面 32 个活样张的墙不会在每一张静帧上都重新烘焙一遍(约 60 秒),而改过的样张只是缓存未命中、重新画一遍。缓存从来不是必需的:随时可以删掉.cache/。--no-bake-cache(或ANIDOODLE_BAKE_CACHE=0)让每个样张都冷启动重画,怀疑缓存有问题时就这么做。 - 逐帧精确的比对。
render.mjs --hashes out/x.md5在编码器碰到每一帧之前写下它的 md5;对比两份这样的文件,就能证明一次引擎改动让影片逐字节不变,或者找出它改动的第一帧。 - 定格要声明,绝不悄悄吞下。 一个正在被读的词、一张片尾卡、一个正在被观看的循环动画:把这段区间写进
meta.holds,并在注释里写明理由。这样闸门的冷场检查就知道这段静止是有意的。其他任何静止不动的东西都是干等:剪掉。审查在一部已经审批过的影片里发现的等待,连同理由写进meta.locked:闸门把它打印出来并持续不通过,于是这个决定始终摆在眼前。如果负责人接受它按原样交付,它就变成一个以那条理由为第三个字段的定格([from, to, "approved as shipped: ..."]),闸门打印它并放行(launch3.ts)。 npm test(在engine/里)不开浏览器,运行engine/test/*.test.ts里的单元测试套件(目前测的是摄像机运动)。任何引擎改动之后,都和闸门一起跑。