产品广告视频,用代码制作
一个 15-20 秒产品广告的制作流水线,无需视频编辑器:每一帧、每一个声音和每一句旁白都由脚本生成,因此整个作品可复现且可编辑为文本。
project facts ─► brief + storyboard ─► visuals ─────────────► Remotion render ─► MP4
├ 2D: React (Remotion) ▲
└ 3D: Blender (headless) ─► JPG frames
sound: scripts/score.py ─► WAV ┘
voice: scripts/kokoro_tts.py ─┘
工作示例 (GhostCommits,真实文件): examples/ghostcommits/。
步骤 1 — 了解产品,撰写简报
阅读 README、登陆页和代码。提取:一句话宣传语、3-4 个具体证据点(数字优于形容词:“1 个文件”、“0 次登录”)、CSS 中的品牌颜色、Logo SVG、URL。写下哪些内容绝对不能宣称(例如“仅测试网”、“不匿名”、没有用户数)。每一条屏幕文字和旁白都要对照此列表进行检查。仅在品牌未定义配色/风格时,让用户选择一种配色/风格。
步骤 2 — 故事板(在构建之前先写入 .md 文件)
18 秒,30 fps = 540 帧。5-6 个镜头,每个约 2.5 秒(75 帧,相当于是 96 BPM 下的一小节,因此剪辑点正好落在节拍上)。每个镜头包含:帧数、摄像机/运动、屏幕文字、音效。以 3-4 秒的结束卡(名称、标语、URL)收尾。模板:references/storyboard.md。
步骤 3a — 2D 风格 (Remotion)
动态文字 + 扁平形状,具有“Spotify Wrapped”的活力感。参见 references/remotion-2d.md。
npx create-video@latest --yes --blank --no-tailwind video 然后为每个广告创建一个组件,仅由 useCurrentFrame() + 带缓动的 interpolate 驱动。不使用 CSS 过渡。
步骤 3b — 3D 风格 (Blender,无头模式)
黑色空间中的光洁主角对象、微距特写、物体表面的光条纹、硬切、左下角的大号统计文字和小号标题。参见 references/blender-3d.md。
一个 Python 脚本构建场景,为每个镜头设置关键帧,并渲染帧:
blender -b --factory-startup -P scene.py -- anim ../public/frames。Remotion 在帧上叠加文字(examples/ghostcommits/GhostAdV2.tsx)。先渲染 2-3 张静帧并审视,然后再进行完整动画。
步骤 4 — 音效 (scripts/score.py)
编写 JSON 提示表:每个视觉事件一个条目,键为动画代码中的帧号(剪切 → cut_hit,物体飞入 → whoosh,着陆 → click/lock,光条纹 → glint,结束卡 → impact,渐强 → riser)。然后运行 python scripts/score.py cues.json。它会合成所有音效(无样本,无许可),添加一个 96 BPM 的背景音乐,并在 break_frame 处降低音量,在 end_frame 处结束,并输出每秒响度以供快速审查(无需实际试听)。详情和增益建议:references/sound.md。
步骤 5 — 旁白 (可选)
短句,≤ 6 个单词,每个镜头一句,与屏幕文字匹配。最佳免费选项:
python scripts/kokoro_tts.py lines.txt vo/(托管的 Kokoro,比较 3 种声音)。将文件添加到提示表的 voiceover 列表中,起始时间设为该镜头文字出现的时间;score.py 会修剪静音并在旁白下降低音乐音量。测量每句的长度,确保其在前一句结束后才结束。选项和经验教训:references/voiceover.md。
步骤 6 — 渲染并交付
在合成中使用 <Html5Audio src={staticFile("audio/soundtrack.wav")} />,然后
npx remotion render <CompositionId> out/ad.mp4。将 MP4 发送给用户。明确说明你无法听到音频:电平和时序已经过数值检查,而非人耳监听。
重要的规则
- 诚实的文案:不宣称产品无法支撑的内容;保持警告语(beta、testnet)在屏幕上显示。
- 不要复刻特定品牌的广告(Logo、音乐、角色)——仅借鉴其风格。
- 文字在 1080p 下 ≥ 48 px,在屏幕上停留 ≥ 1.2 秒,位于左下角或居中,切勿覆盖主角的脸部。
- 在完整渲染前先渲染静帧;检查每个镜头的一帧。
- 将生成的帧/音频排除在 git 之外(
.gitignore);仅提交脚本 + 故事板。