从 0 到 1:我如何用 WorkBuddy 一键制作拼贴动画
最近,WorkBuddy 的模型列表里把 Hy3 标成了限时免费。
活动通知写得很直接,0 积分替你把活干完。

看到活动以后,第一反应不是拿它测一道题,也不是让它多写几段文案。我在想,能不能趁这个机会多跑几次,把 WorkBuddy 和 CodeBuddy 接进自己的工作流,替掉一部分原来反复放在 Codex 里做的工作。
前段时间,我刷到一条用 Codex 制作拼贴动画的视频。
那种效果并不复杂。背景像一本摊开的绘本,人物、动物和道具是单独的纸片,配合旁白在画面里移动。但真要自己做,后面是一长串零碎工作。
写故事,拆分镜,列素材,逐张生图,抠图,统一尺寸,配音,切字幕,写 Remotion 动画,渲染后再抽帧检查。
每一步单独拿出来都不难。
难的是每次换一个故事,这些事又要从头做一遍。
所以这次我没有急着生成某一条具体视频。我先想做一个 WorkBuddy 版的通用 Skill。
以后只需要给它一个故事、主题或文章,WorkBuddy 就在同一个任务里自己完成脚本、分镜、素材生成、rembg 抠图、VoxCPM 配音、Remotion 动画和成片 QA。
Skill 不是一条更长的提示词
我以前也容易把 Skill 看成一份很长的 Prompt。
真正开始写这套 Skill 后,我更愿意把它叫作一份可以执行的制作规范。提示词只是其中一层,真正让结果稳定下来的,是规则、数据协议、脚本和工程模板一起工作。
这套纸质拼贴动画 Skill 的主体结构大致如下。
paper-collage-video/
├── SKILL.md
├── references/
│ ├── video-script-template.md
│ ├── prompt-library.md
│ ├── storyboard-schema.md
│ ├── background-aware-motion.md
│ ├── subtitles.md
│ └── voiceover.md
├── scripts/
│ ├── check_environment.py
│ ├── remove_background.py
│ ├── normalize_asset.py
│ ├── scaffold_remotion.py
│ ├── validate_background_motion.py
│ └── validate_subtitles.py
└── assets/remotion-template/
├── src/
├── storyboard.json
├── path-editor.mjs
├── path-editor.html
└── path-editor.js

SKILL.md 负责规定执行顺序,也写清楚哪些事情不能省。
例如,图片必须由 WorkBuddy 在同一个任务里逐张生成,不能只输出一份素材提示词就停下。背景和可移动主体必须分开生成。每一个需要独立运动的角色,都要有自己的一张绿幕素材。
references 里放的是会被重复读取的专业规则。脚本模板告诉 WorkBuddy 怎么拆镜头,提示词库负责约束写实微缩绘本、剪纸拼贴、水彩绘本等不同画风,分镜协议规定 Remotion 到底要读取什么数据。
scripts 解决的是靠提醒很难稳定完成的动作。
检查 rembg 是否存在,确认模型有没有缓存,裁掉透明图片四周不一致的空白,验证字幕里有没有标点,检查角色路线是否穿过石头或树干,这些都不适合只写一句请仔细检查。
Remotion 模板负责把前面的规则落到画面上。故事换了,素材换了,分镜数据换了,底层的逐帧运动、图层合成和渲染方式不需要重写。
这样拆开以后,Skill 才不再是一段只能祈祷模型听懂的文字。
它开始有了可以验证的输入和输出。
把一次生成拆成可以恢复的生产线
我给 WorkBuddy 规定的完整流程是这样的。
用户主题
↓
video-script.md
↓
assets-manifest.md
↓
WorkBuddy 逐张生成素材
↓
rembg 抠图和尺寸统一
↓
VoxCPM2 生成旁白
↓
storyboard.json
↓
Remotion 渲染
↓
ffprobe 和抽帧检查

这九步其实可以分成四段。
用户主题、video-script.md 和 assets-manifest.md 负责把故事想清楚。前者确定横竖版、时长和画风,中间那份脚本把内容拆成镜头,素材清单再把每个镜头需要什么图片写成明确合同。
WorkBuddy 生图、rembg 和 VoxCPM2 负责准备可以进入时间线的素材。图片需要经过生成、抠图和尺寸统一,旁白则要先得到真实音频时长,镜头帧数才有可靠依据。
storyboard.json 是交接点。前面的故事、图片、声音和路径,到这里全部变成帧、图层和关键帧数据。Remotion 不再临场猜故事,只读取这份数据逐帧渲染。
ffprobe 和抽帧检查负责决定任务是否真的结束。分辨率、音轨、字幕、绿边和路径接触点有任何一项不对,就返回对应阶段修改,不推倒整条生产线。
步骤多并不可怕。每一步都会留下可以检查的文件,这才让它成为一条能恢复的生产线。
如果 WorkBuddy 已经生成了十张合格素材,第十一张出了问题,下次运行时应该继续补第十一张,而不是把前面十张全部重做。
如果只是角色路线不对,也不该重新生图、重新抠图、重新配音。修改 storyboard.json 后,从路线校验和 Remotion 渲染继续就够了。
这也是我后来越来越在意的一点。
一键生成不等于把所有动作塞进一个黑盒里。真正好用的一键流程,应该知道自己执行到了哪里,也允许人从中间接手。
生产线开始前还有一道环境闸门。
check_environment.py 只检查,不会擅自安装。它会确认 Node.js、npm、FFmpeg 和 rembg 是否可用,也会检查 rembg 模型是否已经缓存。环境闸门还会按照 voiceover.md 的规则检查本地 VoxCPM2。
如果 rembg 不存在,Skill 必须停下来询问是否安装。模型需要首次下载时,也要先取得同意。Remotion 依赖优先复用本机已有目录,找不到时才询问是否执行 npm install。
这看起来比直接自动安装多了一步,却避免了工作流为了生成一条视频,悄悄改掉整台电脑的环境。
素材尺寸不是小问题
前景素材统一生成绿幕版本,再交给 rembg 抠成透明 PNG。
抠完以后还要做一次 normalize。
脚本先裁掉透明空边,再把主体按指定占比放回 1024×1024 的透明画布。人物和陆行动物默认底部对齐,主体占画布大约 72% 到 82%。
我一开始也觉得这是后期细节。
真正做动画时才发现,同样是两张 1024×1024 的角色图片,如果一张周围留白很多,另一张贴近边缘,在 Remotion 里给它们相同的 width,画面里的实际大小仍然不同。
角色忽大忽小,有时与缩放曲线无关,问题出在素材边界不一致。
所以在这套 Skill 里,生成尺寸、主体占比和 Remotion 显示宽度被当成三个不同的数据。不能靠临时改一个 width,把前面的素材问题盖过去。

配音和字幕也分开处理。
旁白由本机 VoxCPM2 生成,沿用已经准备好的参考音频。配音原文保留正常标点,因为停顿和语气需要它。
屏幕字幕则按语义切成 2 到 14 个汉字的短句,一次只出现一条,不带标点,太长会显得比较拥挤,占据更多的屏幕空间。
渲染前,validate_subtitles.py 会检查长度、标点、换行、时间重叠和停留时长。这样一句字幕不要有标点,才从偏好变成了可以执行的规则。
storyboard.json 是整个 Skill 的数据协议
素材准备好以后,画面怎么动,不再由 WorkBuddy 临场发挥。
所有镜头都写入 storyboard.json。视频尺寸、帧率、场景时长、背景、角色图层、字幕、相机运动和配音时间,都以这份文件为准。
我没有让 Remotion 去理解故事。
Remotion 只负责按照数据一帧一帧地画。
下面是一段经过简化的角色路线数据。
{
"durationInFrames": 120,
"background": "assets/river-bank.jpg",
"backgroundMap": {
"horizonY": 0.34,
"blockedZones": [
{"id": "deep-water", "x": 0.42, "y": 0.56, "width": 0.22, "height": 0.18}
],
"paths": [{
"id": "main-route",
"points": [
{"x": 0.12, "y": 0.82, "scale": 1.06},
{"x": 0.34, "y": 0.72, "scale": 0.98},
{"x": 0.58, "y": 0.61, "scale": 0.88},
{"x": 0.82, "y": 0.48, "scale": 0.76}
]
}]
},
"layers": [{
"source": "assets/character.png",
"motion": {
"preset": "follow-path",
"pathRef": "main-route",
"pathAnchor": {"x": 0.5, "y": 0.94},
"depthScale": true,
"pathProgress": [
{"frame": 0, "progress": 0},
{"frame": 48, "progress": 0.46},
{"frame": 66, "progress": 0.46},
{"frame": 119, "progress": 1}
]
}
}]
}
backgroundMap 是对背景图的结构化描述。
horizonY 记录地平线。blockedZones 标出深水、树干、石头等不能直接穿过的区域。paths 保存道路、河流或轨道的真实走向。坐标都在 0 到 1 之间,所以预览窗口变大变小,路径仍能贴在同一个位置。
角色图层用 pathRef 引用路线。
pathAnchor 决定路线应该贴在素材的哪个部位。人物和动物取脚底,汽车取轮胎接地点,船取水线。只有飞行物才适合用图片中心。
pathProgress 负责节奏。
它描述某一帧走到了路线的哪个位置。两个关键帧的 progress 相同,就表示角色在这里停了一会儿。再配合起步、回弹、轻微步态和镜头推拉,一条路线里就能做出加速、减速、停顿和再次出发。
这些字段没有多高级。
但它们把脚要踩在地上这句话,翻译成了 Remotion 可以执行的数据。

路线不能按控制点数量平均
路线运动里还有一个很容易忽略的问题。
假设直线路段只有两个点,转弯处为了贴合背景放了六个点。如果把进度平均分给每一段,角色到了弯道就会突然变慢,因为它要花同样的时间走过许多很短的线段。
Skill 模板里的 samplePath 不按点数分配进度,而是先把归一化坐标还原成屏幕像素,计算每一段的实际长度。
length[i] = hypot(
deltaX * canvasWidth,
deltaY * canvasHeight
)
target = progress * totalLength
找到 target 所在的线段
在线段起点和终点之间插值
这样一来,控制点只负责描述形状,不会偷偷改变速度。
角色的缩放也跟路线一起走。
路径点可以显式记录 scale。如果没有写,Remotion 就根据路径纵坐标和地平线估算景深。角色靠近画面下方时变大,走向地平线时缩小。
路线切线还可以提供一个受限的旋转角度。走上坡或转弯时,角色会轻微倾斜,但不会整张图片跟着道路大幅翻转。
做到这里我才意识到,角色看起来像贴纸一样滑,通常不是少写了几个 translateX。
真正缺的是背景、路线、角色接触点和时间进度之间的关系。
自动规划不够时,让人直接画路线
Skill 会先分析处理后的背景图,再尝试自动提取道路边界、弯道、消失点和禁入区。
普通道路可以自动规划。遇到河岸、踏石、山路和遮挡,模型仍然可能判断错。继续在提示词里描述先走近一点再向右绕过去,成本很高,结果也不稳定。
所以这套 Skill 里还装了一个本地路线控制台。

控制台本身很简单。
服务端只用了 Node.js 自带的 http、fs 和 child_process,没有再引入 Web 框架。前端是一页原生 HTML、CSS 和 Canvas。打开以后选择场景,再选择场景里的某个主体,就能在背景图上点击绘制路线。
每个主体有自己的独立路线。
控制点可以拖动、删除或清空,时间滑杆会让角色沿路线预览。编辑器保存的是归一化坐标,所以浏览器里的显示尺寸不会污染正式视频数据。
真正需要小心的是保存。
如果网页直接覆盖 storyboard.json,只要写入一份坐标越界或字段缺失的数据,原来的可渲染工程就可能被破坏。
现在的保存过程分成四步。
浏览器 PUT 新 storyboard
↓
服务端写入随机命名的临时 JSON
↓
Python 校验器检查临时文件
↓
通过后原子替换正式 storyboard.json
validate_background_motion.py 会检查路径是否至少有四个点,坐标是否处于 0 到 1,路径 id 是否重复,pathRef 是否真实存在,pathProgress 是否按帧递增,以及路线有没有穿过未获允许的禁入区。
校验失败时,临时文件会被删除,原 storyboard.json 保持不动。
这部分代码并不多,却是我认为整个路线编辑器里最值得保留的设计。
可以让人改,但不能让一次误操作毁掉已经能跑的工程。
我是怎么一轮轮把它改出来的
这套 Skill 并不是先画好一张完整架构图,再一次写完。
第一轮只解决一件事,让 WorkBuddy 真正一键跑到底。它不能写完素材提示词就停下,也不能把逐张生图重新交给我。已经生成的文件还要能够续用。
第二轮处理的是素材边界。绿幕和 rembg 解决了透明背景,normalize 再把角色放进统一画布,Remotion 才能得到稳定的视觉尺寸。
第三轮补上声音、字幕和画风控制。我把配音切到本地 VoxCPM2,显示字幕变成 2 到 14 字的无标点短语,默认画风也从单一剪纸改成可以选择。
第四轮开始处理主体和背景的关系。backgroundMap、pathRef、pathAnchor、pathProgress 和 depthScale 被写进分镜协议,路线校验器负责挡住坐标越界和穿过禁入区的数据。
第五轮没有继续追求全自动。我加了路线控制台、保存前校验、原子替换和成片后的路线确认,让人可以只改判断错误的那一小段。

Skill 做完以后,我让它生成了《小马过河》
前面的脚本、数据协议、Remotion 模板和路线控制台都装进 WorkBuddy 以后,我才开始跑具体故事。
我给它的主题是《小马过河》。
这次我没有再逐步告诉它先写什么、下一张图片画什么。WorkBuddy 按照 Skill 自己拆成六个场景,生成小马、母马、老牛、松鼠和河岸素材,完成抠图、尺寸统一、配音、字幕和 Remotion 渲染。
第一次成片已经能完整播放。小马走到河边、听完老牛和松鼠的意见,再试着过河,故事和镜头都跑通了。
但其中一段路线没有贴住河岸。
这时我没有修改素材,也没有让 WorkBuddy 从头再做一遍。我打开 Skill 自带的路线控制台,把走歪的那一段重新画好。
保存后,WorkBuddy 继续运行路线校验、Remotion 渲染和 ffprobe 检查。
得到的成片是 1080×1920、30 帧、32.04 秒,带完整音轨的 MP4。

这条实测也验证了 Skill 末尾的一条规则。
初版视频完成渲染和抽帧检查后,WorkBuddy 要主动问一句。
是否有需要更新的路线。

如果我说没有,它就交付视频和 Remotion 工程。如果我说有,它就打开路线控制台,等我保存,再从校验、渲染和 QA 接着执行。
字幕的样式还是差点意思,大家有喜欢的字幕样式可以通过控制 remotion 来进行优化。
Workbuddy 生成的图片会有水印,rembg 还是会把水印给抠出来,大家可以在 skill 中加一层去水印的功能或者使用自定义的生图 api。
目前暂时还是做不出来特别惊艳的效果,可能是没有 bgm 以及 remotion 控制等等的问题,但感觉逗一逗小孩子还是可以的。
最后附上 rembg 和 voxcpm 的链接:
- rembg:https://github.com/danielgatis/rembg
- VoxCPM / VoxCPM2:https://github.com/OpenBMB/VoxCPM
更多推荐


所有评论(0)