Motion Ad Studio(自我优化版)
制作一段 20-40 秒的竖屏动态图形广告,达到资深动态设计师认可的标准:第 0 帧即开始运动,整体有一条贯穿的载体对象,转场在运动中途发生并速度匹配,每一次点击、着落、坠落和呼啸声都与旁白词语或音乐节拍锁定。影片为单一 HTML 页面(GSAP 时间线 + 纯时间函数),可逐帧渲染为 MP4,并在任何人观看前由脚本进行校验。音效源自影片自身的事件列表,因此音频同步由设计保证,而非靠耳朵调节。
每次运行:先阅读 references/lessons.md 和 references/runs.md。结束时执行回顾(第 13 步)。
技能会持续改进,但前提是你将经验教训写回文件中。
0. 预检(始终执行)
python scripts/preflight.py [--elevenlabs-mcp yes] # 如果你已连接 ElevenLabs 工具,则传 yes
以下路径相对于本技能文件夹($SKILLS/motion-ad-studio):scripts/...、references/... 和 templates/...。$MOTIONMAXXING 是引擎文件夹($SKILLS/motionmaxxing;预检脚本会打印它),$SEAM_GATE 是可选的转缝门控脚本,预检脚本会找到它(或通过 --seam-gate FILE 指定)。
| 需求 | 原因 | 缺失时处理 |
|---|---|---|
| motionmaxxing 引擎 (Apache-2.0) | render.mjs(帧→MP4)、look.py 门控、lint.mjs 设计检查、runtime/vendor/gsap.min.js | 在本技能旁执行 git clone https://github.com/Tejashmakwana/motionmaxxing,或设置 MOTIONMAXXING |
| ffmpeg + ffprobe、Node 18+、Chrome/Chromium/Edge | 渲染、探测、混音 | 安装;如果 Chrome 未自动找到,设置 CHROME_PATH |
| Python 3.9+ 及 numpy + Pillow | 节拍、合成背景音乐、混音、拼版 | pip install numpy pillow |
| faster-whisper(可选) | 为词语锁定时序提供词语时间戳 | pip install faster-whisper,或任何能输出词语起始/结束时间的对齐工具 |
| 转缝门控(可选) | 证明每个转场速度匹配 | HyperFrames motion-doctrine + patches/seam-gate-camera-overlap.patch |
| ElevenLabs(可选,推荐) | 富有表现力的语音、合成音乐、自定义音效 | 请参阅下一节 |
ElevenLabs 是可选的:通知用户一次,绝不阻塞
如果预检脚本打印了通知(无 API 密钥且你未连接 ElevenLabs 工具),请用用户语言在音频步骤之前一次性简短告知,并让他们选择:
- 连接:用户添加
ELEVENLABS_API_KEY或连接 ElevenLabs MCP 服务器,然后重新运行预检。 - 继续:使用下方无密钥路径构建完整影片。在交付说明中提一次,如果使用 ElevenLabs 能提升语音和音乐质量。同一项目中不再询问。 如果你无法询问(批处理或非交互式运行),则跳过,并将建议写入 NOTE.md。
| 层级 | 使用 ElevenLabs | 不使用(仍可交付) |
|---|---|---|
| 旁白 | 带情感标签的 TTS,录制两次,选择其一 | 用户自己的录音(最佳),或本地/操作系统 TTS 引导语音;或者无旁白的音乐主导影片 |
| 音乐 | 根据影片长度、BPM 和“高潮点秒”生成音乐 | scripts/synth_bed.py(程序化生成,精确节拍网格),或用户拥有版权的曲目 |
| 音效 | 1-3 个主样本(鞭子声、呼啸声、打字声) | scripts/mix_events.py 本地合成所有音效 |
| 词语时间 | 带时间戳的语音转文字(或 TTS 时间戳) | scripts/words.py(本地 faster-whisper) |
细节、提示、信用费用和许可规则:references/audio-providers.md。
流程
-
工作区。
python scripts/new_film.py <project>复制单次拍摄工具包、GSAP 运行时和本地字体。渲染未改动 demo 的一帧以验证工具链:node $MOTIONMAXXING/scripts/render.mjs <project>/film/index.html --still 1.2,16.4 <project>/stills。 -
品牌工具包。 从用户处获取官方标志文件,并裁剪到其 alpha 包围盒。如果载体将停靠到标志中,则测量子字形矩形。通过统计网站 CSS 中的
#hex获取颜色,并将字体作为本地 woff2 获取(scripts/fetch_fonts.py)。使用品牌实际使用的 CTA 渠道。绝不重绘或近似标志:必须向用户索取。 -
一个创意 + 一种新风格。 只写一个只有该品牌能拍的创意。覆盖标志测试:隐藏标志后,影片仍应指向该品牌。写出三个方向,删掉两个,选择一个与
references/runs.md最后一行不同的风格。 -
钩子。 写 3 个 12 字以内的变体(问题、否定、具体性、故事),选一个。第 0 帧已活跃且运动,钩子在帧 1 前出现在屏幕上,没有从黑色淡入。
-
旁白。 约 2.5 词/秒(30 秒 ≈ 70-75 个词)。如果 TTS 支持情感标签,为每行标注([好奇] [自信] [有力] [俏皮] [温暖])。生成或录制,修剪长停顿,用
atempo≤ 1.1 调整至合适长度,然后获取词时间:python scripts/words.py audio audio/vo.wav --lang <code>。Whisper 只给出时间。字幕文本始终来自已批准的脚本。 -
音乐。 生成(长度 + BPM + “高潮点在 处”)、授权曲目,或运行
python scripts/synth_bed.py --bpm 120 --dur 32 --drop 15.8 --out audio/bed.wav。用python scripts/beats.py audio/music.mp3 audio/beats.json获取节拍网格(synth_bed会写入精确的.beats.json)。修剪音乐头部,使高潮点落在旁白的高潮词上:影片节拍 k = first_beat - trim + k·period。 -
STORYBOARD.md + ledger.json(
templates/one-take/有填充的示例)。包括:- 页面规格、创意和三个方向;
- 节奏表(时长段 / t / 能量 0-10 / 路线 / 音乐);
- 时序映射:每个事件及其锁定的词
w(i)或节拍beat(k); - 旁白和示例数据列表;
- ledger:每行一个转缝(退出/进入轴 + 方向、切割时间)。
-
构建。 从工具包中复制模式(
references/one-take-kit.md):- 时钟
w(i)/we(i)/beat(k); - 每帧顺序
tl.seek → PRE(相机、移动锚点)→ cursors(读取实时 DOM 矩形)→ UP(跟随的 UI); - 关键帧 3D 相机和针对实时 DOM 矩形的光标引擎;
- 纯 t 函数的打字/文本/类更新器;
sfx()事件和源自相机的呼啸声。
渲染器需要满足的约定:
#main带有data-composition-id="main" data-width data-height data-duration。window.__seek / __duration / __timelines / __events / __player / __ready / __playerReady / __renderReady。蒙太奇风格影片(分层场景、扁平 UI、标志载体):references/montage-kit.md。 - 时钟
-
查看。 渲染 15-20 帧(
node $MOTIONMAXXING/scripts/render.mjs ... --still t1,t2,... stills),拼成缩略图(python scripts/sheet.py stills sheet.jpg 6 220),进行一次视觉检查:每帧一行,然后是缺陷列表。修复并重复 2-3 次。- 几何真相(内容位置、可见性、透明度)来自
node scripts/probe.mjs index.html "t1,t2" "#a,#b"。 - 文本真相来自全分辨率裁剪:视觉检查会误将缩小后的阿拉伯语和 CJK 文本读作“错别字”,但实际上并不存在。
- 几何真相(内容位置、可见性、透明度)来自
-
转缝门控(推荐)。在 localhost 上提供影片文件夹,然后运行
node "$SEAM_GATE" verify --ledger ledger.json --url http://127.0.0.1:<port> --comp-url http://127.0.0.1:<port>/index.html。目标是 0 FAIL。如果单次拍摄相机甩动使两个窗口都在屏幕上,则需要在"overlap": "camera"及patches/中的补丁。之后停止服务器。参见references/qa-gates.md。 -
混音。 每个音效位于
window.__events({t, type:'sfx', name, gain, dur?, speed?})。- 使用
node $MOTIONMAXXING/scripts/render.mjs index.html --still <t> ev导出,这会写入ev/events.json。 - 混音:
python scripts/mix_events.py --events ev/events.json [--vo vo.wav --vo-at 0.10] [--music bed.wav --music-trim s] --dur <s> --out audio/mix.wav [--music-db -24] [--tp -2.5] [--whip/--whoosh/--typing samples] [--lift t0:t1:dB] [--fade t]。 - 电平:VO 在 -18 dBFS RMS,音乐在 -30,在 VO 下进行闪避,呼啸声峰值与相机最快帧对齐,两次 loudnorm 处理到 -14 LUFS / TP ≤ -1。
- 使用
-
渲染 + 门控 + 交付。
- 渲染:
node $MOTIONMAXXING/scripts/render.mjs index.html <新名称>.mp4 --audio ../audio/mix.wav --crf 17 --grain 0.03。每次尝试使用新输出名称:两次渲染到同一文件会导致损坏。 ffmpeg -v error -i x.mp4 -f null -必须无输出。然后运行python $MOTIONMAXXING/scripts/look.py x.mp4 --out look --expect <dur> --expect-audio(G0/G2/G3/G5 PASS)和node $MOTIONMAXXING/scripts/lint.mjs index.html。- 交付:9:16 主版本、4:5 裁剪版本(布局确认后
crop=1080:1350:0:200)、2-3 个封面 PNG、NOTE.md(创意、时序映射、真实 vs 示例数据、音频来源 + 许可、门控编号、改进方向)及一个project/文件夹(影片 + 音频 + 脚本)。 - 清理:停止服务器和孤立的 headless Chrome。
- 渲染:
-
回顾(必须执行,在最终回复之前)。 将带有日期的规则+经验教训追加到
references/lessons.md。在references/runs.md中添加一行(日期、产品类型、风格、长度、门控编号、已知后的结论)。如果有步骤变更,修补此文件、某个脚本或工具包。当用户稍后反馈时,记录结论。经验教训只包含方法,不包含客户名称或私有数据。
质量标准
- 钩子: 真实客户用语或好奇心缺口。第 0 帧即运动,钩子在第 1 帧前可读,无黑色淡入。
- 连续性: 整部影片有一条载体(光标、芯片、标志标记),无交叉淡入淡出,2-3 种转场类型重复使用。剪接在运动中途发生且速度匹配。保持一个当前方向:对于“下一个”,RTL 影片内容从左向右运动,LTR 影片从右向左。保留的向量用于表达含义。
- 时序锁定: 每一个点击、坠落和着落都落在
w(i)或beat(k)上,音乐高潮点落在旁白词上。呼啸声源自相机速度。时序映射列出每个事件及其锁定的内容。 - 无无聊晃动: 每个停顿时都有带有意图的相机运动、阶段性揭示或实时 UI。静止只属于高潮前的时刻。
- 安全区域 (1080×1920):
- Meta 付费投放:可读文本在 y 270-1250 和 x 60-960(右侧 120 px 为按钮);
- 自然 Reels/TikTok:保持底部 320-370 px 清晰;
- 将字幕导轨放在 UI 面板下方,绝不覆盖构图器;
- 字幕导轨显示图片已有的内容。
- 结尾: 品牌标志加上一个品牌实际使用的 CTA。结尾持续 0.6-1.4 秒,最终镜头不超过影片长度的 25%。
- 诚实: 在 NOTE.md 中声明示例数据。绝不捏造性能声明、价格或推荐语。
- 目标: look.py G0/G2/G3/G5 PASS,运动能量 ≥ 5/255 平均亮度变化(深色 UI 影片接近 2),剪辑同步 ≥ 35%(实测专业基准),-14 LUFS ± 0.5,真峰值 ≤ -1 dBTP,0 个解码错误。
平台注意事项
- Windows git-bash 上的后台任务:调用
node.exe,而不是nodewinpty 别名(“stdin is not a tty”)。 - 绝对 Windows 路径的 ESM 导入需要
file:///C:/...。 - Headless Chrome 在中断运行后会泄漏。在最后,列出使用
--headless=new和--remote-debugging-port=0启动且父进程已消失的浏览器,并杀死其根进程及其树。 - 渲染速度:扁平 UI 在 1080×1920 下约 4 分钟每 35 秒。3D 世界约 4-5 分钟,约 4 fps,但前提是 3D 层数保持较少。
文件
scripts/:preflight.py:依赖项和 ElevenLabs 通知;new_film.py:创建项目脚手架;fetch_fonts.py:本地 woff2;words.py:词语时间;beats.py:节拍网格和高潮点;synth_bed.py:无密钥音乐;mix_events.py:事件驱动混音;sheet.py:缩略图拼版;probe.mjs:实时几何探测。
templates/one-take/:完整的单次拍摄 3D 相机影片,作为可运行示例(虚构产品,阿拉伯语 RTL 文字),包含 STORYBOARD.md 和 ledger.json。references/:research.md:领域调查、上游技能、安全说明、平台规格;lessons.md、runs.md:自学习记忆;audio-providers.md、one-take-kit.md、montage-kit.md、qa-gates.md。
patches/seam-gate-camera-overlap.patch:用于单次拍摄相机影片的可选用转缝门控规则。