Opus 5.5 当导演,Sonnet 5.5 当画师:纯 JS 画出一部蜡笔水彩风《奥德赛》短片

这次想试一件事:让大模型分工拍一部短片。

需求就一句话:

生成一个关于奥德修斯的故事的短片,风格使用手绘蜡笔水彩风格,先由你确定创意构思,再使用 sonnet 完成落地。

分工很明确:

  • Claude Opus 5.5(主代理):导演 + 美术指导。负责创意、写设计规格、拆任务、审稿、给修改意见。它自己一行业务代码都不写。
  • Claude Sonnet 5.5(子代理) :执行团队。拿着规格写代码、出图、跑测试,遇到规格外的审美问题不许自己拍板,只能在报告里提出来。

最后的成片:2 分 40 秒、16 个镜头、1080p,所有画面都是 JavaScript 程序画出来的,旁白、配乐也是代码合成的。

先看成品(每个镜头抽一帧):


一、任务:一个关于"回家"的故事

Opus 拿到需求后,先定了创意,而不是马上动手:

  • 主题不是打怪,是回家。 十年战争、十年漂泊,独眼巨人、塞壬、斯库拉都只是回家路上的阻碍。情绪落点放在老狗认主和橄榄树床相认。
  • 贯穿符号:一条红围巾。 佩涅洛佩在织布机上织的红线,就是奥德修斯脖子上的红围巾。全片只有这条围巾是高饱和的红色,大海再大,那一点红就是"家"的牵挂。结尾围巾挂在自家窗台上随风飘------回到了。
  • 首尾呼应。 从织布机开始,到织布机窗口结束。
  • 16 个镜头:片头 → 织机 → 木马 → 独眼巨人 → 波塞冬 → 风袋 → 喀耳刻 → 塞壬 → 斯库拉与卡律布狄斯 → 孤舟夜海 → 卡吕普索 → 老狗阿尔戈斯 → 拉弓穿斧 → 橄榄树床 → 黎明 → 片尾。

这些全部写进了两份文件:brief.md(创意说明)和 shots.json(每个镜头的旁白、画面描述、运镜参数)。后面所有 Sonnet 都以这两份文件为唯一依据。

二、画面路线:用 JS 把它们画出来

这次的画面全部用 JavaScript(Node + @napi-rs/canvas)程序化绘制。

难度不低:程序画"蜡笔水彩",质感全靠算法;人物、怪物、船、海全要用代码构造。但这也恰好是验证"Opus 设计 + Sonnet 执行"这套分工最好的场景------设计含量极高,执行量也极大。

三、分工方式:Opus 写规格,Sonnet 照规格干活

Opus 先写了一份约 400 行的绘制规格 js_art_spec.md,这是整个项目的核心产物。它不是"画一个好看的海"这种模糊描述,而是可以直接执行的设计:

规格章节 写清楚了什么
色板 30 个颜色的 hex 与用途;scarfRed 只允许红围巾使用
纸 纸齿、斑驳两张噪声场怎么生成,最终怎么乘到画面上
水彩 叠层变形算法的每一步参数:递归深度、方差衰减、层数、alpha、边缘加深、颗粒沉积
蜡笔 线条怎么重采样、抖动、压力、两端收尖、每个采样点戳几个小矩形
分层合成 每个"平面"= 遮盖层 + 水彩层(multiply) + 蜡笔层(纸齿蒙版),从后往前合成
人物骨架 以身高 h 为单位的比例(头半径 0.09h......),关节角约定,14 种姿态的动作含义
分镜构图 15 个场景每个元素的坐标(2560×1440 基准),并保证关键人物在运镜起止窗口内
审查流程 先出半尺寸预览 → 自查技术问题 → 全尺寸出图;审美问题只报告,不自改

然后按依赖关系拆成 4 个阶段,能并行的都并行:

markdown 复制代码
阶段 1  笔刷核心库(1 个 Sonnet)
          │  Opus 审测试页 → 调参意见 → 通过
阶段 2  人物骨架与角色(1 个 Sonnet) ∥ 环境道具库(1 个 Sonnet) ∥ 渲染管线改造(1 个 Sonnet)
          │  Opus 审角色页/道具页 → 各 1 轮修改 → 通过
阶段 3  场景 S00--S04 ∥ S05--S09 ∥ S10--S14(3 个 Sonnet 并行)
          │  Opus 逐张审 15 个场景 → 8 个场景返修 1 轮 → 通过
阶段 4  最终渲染与验证(1 个 Sonnet)

几个让并行不打架的约定:

  • 文件所有权 :每个 Sonnet 只能写自己名下的文件,场景代理禁止修改 lib/,私有辅助函数放各自的 _helpers_A/B/C.js。
  • 接口先行:阶段 1 结束时让 Sonnet 在报告里写清 API 签名,阶段 2/3 的任务说明直接引用。
  • 遇到规格没覆盖的情况停下来问,而不是自己发挥。

四、笔刷:程序怎么画出"蜡笔 + 水彩"

水彩用的是 Tyler Hobbs 的叠层变形法:一个多边形反复做"边中点沿法线随机偏移",派生出几十个略有不同的形状,每层只填 4.5% 的不透明度,叠起来就有了水彩那种不规则边缘和内部浓淡:

js 复制代码
// 每条边取中点,沿法线偏移 gauss(0, variance*v*边长);递归 depth 次
function deform(verts, depth, variance, rng) {
  let cur = verts;
  for (let d = 0; d < depth; d++) {
    const out = [];
    for (let i = 0; i < cur.length; i++) {
      const a = cur[i], b = cur[(i + 1) % cur.length];
      out.push(a);
      const dx = b.x - a.x, dy = b.y - a.y, len = Math.hypot(dx, dy);
      const vv = (a.v + b.v) * 0.5;
      const off = rng.gauss(0, variance * vv * len);
      out.push({ x: (a.x + b.x) / 2 - dy / len * off, y: (a.y + b.y) / 2 + dx / len * off, v: vv });
    }
    for (const q of out) q.v *= 0.65;   // 越细的层级偏移越小
    cur = out;
  }
  return cur;
}

蜡笔是在路径的每个采样点上"戳"一把 1~2.4px 的小矩形,位置在法线方向三角分布(中间密两边稀),再叠加低频抖动、压力变化、两端收尖。

真正让它"像蜡笔"的是纸齿蒙版 :蜡笔层合成前逐像素乘上 smoothstep(0.22, 0.62, tooth),蜡只挂在纸的凸起上,笔触自然断续、有颗粒:

js 复制代码
// 纸齿蒙版:a *= smoothstep(0.22,0.62,tooth)(蜡笔只挂在纸的凸起上)
for (let i = 0, p = 3, N = Wp * Hp; i < N; i++, p += 4) {
  const a = d[p];
  if (a) d[p] = (a * mask[i] + 127) / 255;
}

第一版测试页 Opus 并不满意,给 Sonnet 的意见是这样的(节选):

wash 默认值:spread 0.9→0.55(边缘要像湿水彩边,不是撕纸);granulate 0.35→0.15;tone 0.45→0.22,且浓淡噪声尺度至少是形状尺寸的 2 倍(色块内部是宽缓的明暗过渡,不是云团斑块);edge 0.6→1.1(边缘有可见的深色水线,这是水彩最重要的特征)。

gradientWash 重写(横带不能再被看出来):......

意见里是具体的参数和判断标准,不是"再好看一点"。 这是 Sonnet 能一次改到位的关键。

五、人物与道具

人物是一个简单的 2D 骨架:以身高 h 为单位定比例(绘本式大头,头半径 0.09h),关节角驱动四肢,服装、头发、胡子、红围巾都是参数化部件。14 种姿态覆盖了所有镜头的动作:拉弓、被绑在桅杆上、背影坐在石头上、单膝跪地伸手、相拥......

道具库包括希腊船(高翘船头、船眼、方帆、一排桨,船身拆成前后两部分,好让水手"站在船里")、双刃斧、木马、城墙、织布机、羊、猪、老狗、橄榄树......

这一轮 Opus 的意见同样很具体,比如:

斧头改成古希腊双刃斧(labrys),不能再像雨伞或镐头;皮袋改成软皮囊,不能再像陶罐;红围巾现在像一串锁链,改成连续的布带:先整条铺 scarfRed 水彩,再叠垂直于布带方向的密排线,两侧用同色相更深的红描边......

六、场景:15 张画,三个 Sonnet 并行

场景阶段三个 Sonnet 同时开工,每人 5 个场景。每个代理都会用脚本把运镜的起止窗口框画到预览图上,确认主角全程在镜头里。

独眼巨人是返修最多的一张。第一版鼻子画成了猪鼻子、四肢像散落的香肠、洞壁像蜂巢。Opus 的返修意见把每个部位的形状、朝向、连接关系都写了出来,第二版就对了:

塞壬:奥德修斯被绑在桅杆上,围巾飘向歌声;水手耳朵里塞着蜡:

老狗阿尔戈斯:二十年后,只有它认出了扮成乞丐的主人。第一版里红围巾掉在地上像一条红腿、狗又小又和草堆一个颜色,返修后变成了现在这样:

橄榄树床:床是围着一棵活着的橄榄树做的,这是只有他们两人知道的秘密:

七、让画"动"起来:线条抖动

每个镜头用不同的蜡笔随机种子渲染 3 个变体,只有蜡笔线条不同,水彩与构图完全一致(这要求代码里构图随机数和线条随机数严格分成两条流,混用就是 bug)。视频里每 3 帧切换一次变体,就得到了手绘动画那种"线条在呼吸"的效果:

再配合缓慢的推拉摇(Ken Burns,亚像素插值避免抖动)、1 秒叠化、纸纹和暗角,整片就有了绘本翻页的感觉。

声音部分:旁白用 edge-tts(zh-CN-YunxiNeural),配乐是 numpy 合成的 Karplus-Strong 拨弦里拉琴(D 多利亚调式)+ 海浪噪声,旁白出现时音乐自动压低,最终响度归一到 -16 LUFS。字幕用 PIL 逐帧绘制(本机 ffmpeg 没有 drawtext)。

八、数据

项 数值
成片 2 分 40 秒,1920×1080,24fps,16 个镜头
绘图核心库(笔刷/骨架/道具/环境) 约 3700 行 JS
15 个场景 约 3450 行 JS
音频与合成管线 约 650 行 Python
插画 15 个场景 × 3 个抖动变体 = 45 张 2560×1440
Sonnet 子代理 10 个任务(最多 3 个同时跑)
Opus 审查 笔刷 1 轮、角色 1 轮、道具 1 轮、场景 8 张返修 1 轮
最终渲染 约 4 分钟

九、几点体会

1. 规格写到"可执行",Sonnet 的产出就很稳。 坐标、比例、参数、验收标准都写死之后,Sonnet 几乎不需要猜,返工基本只来自"规格本身没想到"的地方。

2. 审美决策必须收回到 Opus。 明确要求 Sonnet"审美问题只报告不自改"之后,它的报告里会列出"需要主代理判断的点"(比如"S12 求婚者被斧子挡得比较碎,是否接受"),由 Opus 统一拍板,风格才不会在 15 个场景里各自漂移。

3. 审查意见要像规格一样具体。 "猪鼻子改成蒜头鼻:圆润的水滴形,比脸略深的肤色,鼻尖有阴影,鼻孔只是底边两道短弧"这样的意见,Sonnet 一轮就能改对;"再好看一点"只会换来随机的变化。

4. 并行靠边界清晰。 文件所有权、接口先行、随机数分流、"不许改 lib"------这些工程约定比模型能力更决定并行能不能顺利进行。

5. 自查要可验证,而不是"我看过了"。 每个任务都写明了用脚本自证的方法:把运镜起止窗口框画到预览图上、用 numpy 对比三个抖动变体只有蜡笔区域不同、把四条边各裁 60px 拼起来检查有没有漏出纸白。Sonnet 交上来的是证据,Opus 的审查就能集中在审美上。


如果你也在用多模型协作,不妨试试这种"强模型定方向和标准、快模型大量执行"的分工:贵的模型花在判断上,便宜的模型花在体力上。

相关推荐
ZzT3 小时前
用 Claude 设计 eval,再一轮轮把分数提上去
ai编程·claude
虫无涯5 小时前
Claude Code 频繁卡住?一文搞懂Spinner状态标识、卡顿根源与排查方案
人工智能·claude
CS_Zero5 小时前
Claude code使用DeepSeek的API
ai编程·claude·deepseek
乘风gg7 小时前
花了 100 亿 Token 后,我发现 Code is cheap 是最大的谎言
前端·ai编程·claude
三水写代码21 小时前
手写一个 Claude Code(1):从 Agent Loop 到工具、权限、Hooks 与任务规划
python·ai编程·claude·ai agent·claudecode
AI砖家1 天前
Claude Code Skill 质量检查实战:用 /skill-doctor + Plugin Evals 找出“看似能用、实际没被调用“的问题
人工智能·ai编程·claude·codex·skill
ZzT1 天前
effort 调到 max,Claude 并没有变聪明
人工智能·程序员·claude
乘风gg1 天前
别跟风 AI 副业,工程师最该学的是 AI Coding
前端·ai编程·claude