手工分镜头影片
万圣节夜晚,没什么可看:一个黑色波波头的女孩坐在一个手绘纸板沙发上,手拿粉色饮料,点击纸板遥控器。纸板电视打开,屏幕出现雪花,一个小幽灵在屏幕上跳舞,然后从屏幕上剥离并飘走。它盘旋在她的杯子旁("它想喝一口。"),降落在格子桌上,一把巨大的叉子戳着盘中的手绘浆果("栀子花。浆果。酸奶。"),喝了一口后,她坐在一顶巨大的女巫帽上,星星在她周围闪烁("……满满的魔法。")。杯子特写,画着涂鸦的"神奇漂亮水"和箭头,最后一张卡片上有品牌标志、杯子、幽灵、"万圣节限量版"及购买信息。每一帧都来自品牌自己的七张活动照片。
它由四个部分组成:
scripts/generate.mjs将静帧转化为素材:9:16关键帧(Nano Banana 2绘制额外场景,原始像素覆盖在上面),Kling剪辑片段,抠出的道具,重新放置的标签和品牌标志。scripts/reel.mjs将剪辑片段按影片时间线合并为一个文件。scripts/sfx.mjs合成音效:一首原创音乐盒华尔兹和每个事件对应的音效。scripts/render.mjs将全部内容作为舞台剧播放:12帧/秒的步进运动、手持抖动、动态颗粒、纸偶、撕纸字幕、带箭头的标签、开关电视屏幕以及最后一张卡片。它使用headless Chrome和FFmpeg在本地渲染。
设置(每台机器一次)
在该技能文件夹内运行:
npm install
这将安装puppeteer-core和ffmpeg-static。必须安装Google Chrome,或设置CHROME_PATH指向一个Chrome/Chromium可执行文件(npx @puppeteer/browsers install chrome-headless-shell@stable会打印一个路径)。
素材需要Nano Banana 2和Kling 2.5 Turbo的API密钥;脚本通过模型API网关调用它们,密钥在这个页面创建(https://fal.ai/dashboard/keys)。用户在自己的终端中设置`FAL_KEY`(例如在shell配置文件中)。永远不要要求他们将密钥粘贴到聊天中,也不要打印它。
费用
模型使用费用,计入你自己的API密钥:每张扩展到9:16的静帧(以及每次edit)0.08美元,每段5秒剪辑片段0.35美元,每个抠图不到0.01美分(2026年10月价格)。7张静帧、5个剪辑片段的短片大约2.30美元。合成文件、纸偶、字幕、音效和最终MP4文件在本地免费处理。在生成前告知用户费用。
成功要点
- 他们自己的照片,关键部分原封不动。 扩展和每个剪辑片段都从品牌的真实静帧开始;
extend将原始像素覆盖回AI生成的版本,relabel将清晰的标签覆盖回任何剪辑片段模糊了标签的帧。 - 一个故事,而不是幻灯片。 在几张照片之间规划一个小情节,有一个东西贯穿其中(这里是一个从电视里逃出来的幽灵纸偶)。字幕是简短的情节节拍,而不是口号。
- 刻意笨拙。 所有动作都以1/12秒的步进运动,并带有轻微抖动,纸偶在关键帧上摇晃,字幕分三步弹出,箭头分三笔画完。不要平滑它。
- 一半产品,一半品牌。 产品出现在大多数镜头中,并有一个带标签的特写;最后一张卡片是品牌标志、产品、名称和购买方式。
工作流程
- 收集 来自同一拍摄的4-8张静帧(3:4、4:5或9:16),产品名称,一行描述(口味、材质),一个注释("万圣节限量版")和行动号召。询问静帧底部是否印有品牌标志或徽章(它会被从画面中清除,并作为最后一张卡片的背景素材)。
- 剧本(生成前展示):镜头顺序、情节、每个剪辑片段中的动作(一个或两个小动作,产品保持静止)、哪些道具需要抠图成为纸偶及其动作、字幕和标签,以及费用。保持15-20秒。
- 关键帧:对于每个不是9:16的静帧,运行
node scripts/generate.mjs extend --in still.jpg --out keys/<shot>.png --cover <rows>(--cover= 原始照片底部印刷标志条带的高度,以像素为单位,如果有的话)。以全尺寸查看每个关键帧:如果模型在新扩展的区域留下了镜像或重复的物体,用同一张照片中的纯色纹理覆盖它。 - 试拍:一个剪辑片段,选择有情节钩子的镜头:
node scripts/generate.mjs clip --start keys/<shot>.png --prompt "…" --out clips/<shot>.mp4。提示词只描述动作("她用一个手指按下遥控器上的一个按钮;杯子保持直立且静止");一个固定的后缀保持镜头锁定,场景、面部和产品不变。展示它,然后继续其余部分。 - 剪辑片段:其他需要动作的镜头。逐帧观看每个片段:记录动作落点(以便放置音效和纸偶),以及产品上的小文字模糊的地方。使用
relabel --clip … --key keys/<shot>.png --box x,y,w,h(标签在关键帧中的矩形框)修复标签,或者只使用产品移动前的帧。并非每个镜头都需要剪辑片段:产品特写静帧配合缓慢推进(still、box、boxTo)通常效果更好。 - 道具:对于每个纸偶(角色、星星、花朵、浆果、手中的产品),运行
cutout --in keys/<shot>.png --box x,y,w,h --out props/<name>.png;对于去除某些元素的盘子(如没有幽灵的电视屏幕),运行edit。品牌标志:wordmark --in still.jpg --box x,y,w,h --out props/wordmark.png。最后一张卡片的背景是从一个关键帧中裁剪出的手绘墙区域。 - 构建
effect.json参考examples/example.json(参见“镜头”和“最后卡片”部分),然后运行node scripts/reel.mjs effect.json --out reel.mp4并设置"reel": "reel.mp4"。 - 音效:运行
node scripts/sfx.mjs effect.json --out stage.m4a,然后设置"music": "stage.m4a"。在时间线有任何更改后重新运行。--no-bed --music track.mp3将华尔兹替换为用户拥有使用许可的音轨。 - 验证:运行
node scripts/validate.mjs effect.json— 修复所有错误并向用户解释警告。 - 草稿:运行
node scripts/render.mjs effect.json --quality draft --width 540 --out draft.mp4,并检查每个镜头的一帧:确保没有字幕、标签或纸偶遮挡面部或产品,所有内容避开右侧14%的区域(平台按钮所在位置)。 - 最终版:运行
node scripts/render.mjs effect.json --out film.mp4 --poster poster.png。对于小红书,裁剪出3:4版本:ffmpeg -i film.mp4 -vf crop=720:960:0:160 -c:a copy film-3x4.mp4(在默认720宽度下;确保无重要内容位于顶部或底部的160像素内)。
镜头
所有位置单位为1080×1920像素帧。每个镜头是以下类型之一:
- 剪辑镜头:
clip(reel.mjs使用的文件),from和to(在剪辑中的秒数),speed(0.5=半速,与12步播放一起使用短但好的动作片段的每一帧),hold(第一帧在移动前保持的秒数)。 - 静帧镜头:
still(一张图片),len,box和boxTo([x, y, width]9:16窗口在图片像素中的位置;视图从一个窗口移动到另一个窗口)。
每个镜头可以包含:
captions:{ "text", "at", "out", "x", "y", "rot", "size" }— 撕纸碎片上的手写字幕;\n换行。tags:{ "text", "at", "x", "y", "to": [x, y], "ink": "dark" | "light", "rot", "size" }— 带箭头的标签,箭头自动绘制指向to。puppets:{ "image", "path": [[t, x, y, width, rotation], …], "sound", "exit", "flip", "wobble" }— 一个抠图纸偶,在其关键帧之间移动(t为镜头内的秒数,x、y为其中心点)。一个宽度为0的关键帧紧接着一个全宽度关键帧表示弹入。它保持其最后一个关键帧,除非设置"exit": true。sound在第一个关键帧时播放。screen:{ "rect": [x, y, w, h], "off", "static", "plate", "plateAt" }— 电视或手机屏幕,在off之前为黑色,static之前为雪花,从plateAt开始显示plate(同一关键帧但屏幕内容被清空),因此纸偶可以从里面爬出来。sounds:[[t, "kind"], …]—click、tvon、static、ghost、boing、tap、pop、whoosh、land、stab、sip、sparkle、chime、paper、scribble、cut。剪辑、字幕、标签、屏幕和带有sound设置的纸偶会自动获得对应的音效。
最后卡片
end:len、bg(一个9:16的手绘墙)、wordmark(wordmarkY、wordmarkWidth)、name(nameY、nameSize)、line(lineY)、note在碎纸片上(noteX、noteY)、cta在药丸形按钮上(ctaY),以及puppets(与镜头类似,例如产品从边缘滑入手中的纸偶、角色、星星)。每个都有对应的…At时间。
字段
| 字段 | 必需 | 说明 |
|---|---|---|
reel | 是 | 视频文件路径,相对于JSON文件——由scripts/reel.mjs将所有剪辑镜头合并成一个无声的9:16合成文件(reel.mp4) |
shots | 是 | 2-10个条目列表:clip、from、to、speed、hold、still、len —— 按顺序的影片镜头:剪辑镜头(你的一张静帧的AI剪辑片段)和静帧镜头(带有缓慢移动的静帧);见SKILL.md的“镜头”部分 |
end.bg | 否 | 图片路径,相对于JSON文件 —— 最后卡片的背景:来自你照片的手绘墙或背景,9:16 |
end.wordmark | 否 | 图片路径,相对于JSON文件 —— 透明背景上的品牌标志(由scripts/generate.mjs wordmark生成) |
end.name | 否 | 文本,少于4个单词 —— 产品名称,在最后卡片上手写字体 |
end.line | 否 | 文本,少于6个单词 —— 名称下方的一行短文字,例如口味 |
end.note | 否 | 文本,少于4个单词 —— 在撕纸碎片上,例如“万圣节限量版” |
end.cta | 否 | 文本,少于12个单词 |
music | 否 | 音频文件路径,相对于JSON文件 —— 来自scripts/sfx.mjs的原声音乐(stage.m4a) |
palette | 否 | 颜色值为#RRGGBB;键值:ink(字幕和深色标签)、paper(纸片和浅色标签)和accent(CTA按钮) |
提示
- 写好剪辑提示词:一个或两个小动作,面无表情,“杯子保持直立且静止,标签面向镜头”。大动作会模糊面部和标签。
- Kling自己控制时机:观察动作落点,并将点击、切换和纸偶放在那一帧,而不是整数值。
- 给故事一个贯穿物:从一张照片中抠出的纸偶出现在后续镜头中,将七张静帧连成一个影片。
- 纸偶从照片本身中抠出,而不是新创作的艺术:相同的颜料、纸张和光线使它们融为一体。
- 字幕保持三到四个单词;图片能讲述大部分内容。
输出
H.264 MP4,1080×1920,30fps(画面以每秒12步运动),15-20秒含音效,外加一个封面帧(PNG)。