演示视频
生成全高清 MP4 视频,展示项目网站或应用的实际运行效果:真实的屏幕录制、用户语言的配音、烧录的字幕、背景音乐以及可分享链接。所有工作都在容器内完成,使用 agent-browser、ffmpeg 和项目的 AI 代理(费用计入项目 credits)。典型成果:1-3 分钟、10-20 MB、约 1-2 小时代理工作时间。所有文件位于 video/ 目录(build/ 和 out/ 不会加入 git)。
何时使用
- “制作一个展示系统如何运作的视频”,宣传片、广告、客户演示
- 为某个方案、发布说明或落地页制作实操导览
- 不适用于用户自行录制的情况:此时应为他们编写拍摄脚本到
docs/demo/script.md(场景、动作、台词)
流水线(每一步都可恢复:重新运行时跳过已完成的输出)
| 步骤 | 命令 | 输出 |
|---|---|---|
| 0. 设置 | bash .claude/skills/demo-video/setup.sh | ffmpeg、字幕字体、video/ 目录 |
| 1. 脚本 | 编写 video/vo/narrator.json 和 video/scenes.mjs(从 examples/ 开始) | 计划 |
| 2. 配音 | node .claude/skills/demo-video/tts.mjs video/vo/narrator.json video/build/vo | s01.wav… + s01.txt(所念内容) |
| 3. 录制 | source .claude/skills/demo-video/rec-lib.sh 然后执行 take_start、mark、take_stop | video/build/rec/<take>.mp4 + .marks |
| 4. 卡片 | card_take <name> "file://$PWD/video/cards/<name>.html?…" <seconds> | video/build/rec/card-<name>.mp4 |
| 5. 音效 | node .claude/skills/demo-video/sfx.mjs | video/build/sfx/chime.wav、click.wav |
| 6. 剪辑 | node .claude/skills/demo-video/compose.mjs video/scenes.mjs | video/out/<name>.mp4(若无指定则自动生成音乐) |
| 7. 质量检查 | node .claude/skills/demo-video/listen.mjs video/out/<name>.mp4 "<问题>" 以及逐帧截图 | 修复后重复步骤 6 |
| 8. 发布 | node .claude/skills/demo-video/publish.mjs video/out/<name>.mp4 --cover 16 | 项目存储中的 key + 封面 JPG |
(若通过 npx skills add 安装,路径为 .agents/skills/demo-video/。)
如何制作优质视频
先写脚本。 10-15 行旁白,每行一个想法,8-15 个词,使用用户的语言。只陈述事实:切勿声称项目自身数据无法验证的数字、客户或奖项。将品牌名称和缩写放入 pronounce 中以确保正确发音。每行对应一个场景。
配音。 代理没有 TTS 模型;tts.mjs 使用 Live 模型(gemini-3.8-live)逐行朗读,通过将模型自身转录与脚本对比(词匹配率 80%)保留三次尝试中最佳的一次,每行输出一个 WAV 文件。可用音色:Kore、Charon、Puck、Fenrir、Aoede。旁白使用一种音色;“客户”角色使用另一种。运行后检查 s*.txt 文件,对存在差异的行重新生成(删除其 wav 文件后重新运行)。
录制。 从干净状态开始:全新的浏览器上下文、空的购物车、无已保存的表单草稿(agent-browser eval 'sessionStorage.clear()' 并对应用使用的 localStorage 键执行相同操作)、录制前已登录以避免密码出现在镜头中。使用 typeslow 输入文字,在每个剪辑点之前的点击前调用 mark <label>,等待 AI 回复使用 wait_gone "<搜索文本>",切勿将正在展示的元素滚动到屏幕外。通过元素引用(snapshot 中的 @e12)而非标签文本进行点击。take_start 将视口设置为 1600×900(默认 1280×720 对 1080p 太小);每个场景录制一段。当产品包含语音代理时,通过其自身 API 录制真实对话(examples/voice-exchange.mjs),并在卡片上播放而非伪造。
卡片。 examples/cards/ 中包含开场(动画数字、Logo、标签)、通话卡片和结尾。复制到 video/cards/,将颜色、Logo 和文字改为品牌样式。在 URL 中传递时间参数(?t1=<s>)以使动画对应配音。
剪辑(scenes.mjs)。 每个场景由一段录制的片段 [take, in, out, speed, zoom?] 加上音频 ['vo:s01', at] 组成。将等待部分加速 2-5 倍、对小字面板使用 zoom 放大、每个新部分添加 chapter 标志、当底部字幕会遮挡 UI 时使用 cap: 'left'、在成功时刻(如加入购物车、下单)使用 sfx 音效。剪辑按场景缓存;仅重新渲染有变化的场景。
音频。 背景音乐由 compose.mjs 合成(无版权风险),并在配音时自动降低音量;在 scenes.mjs 中设置 music: 'path/to/track.mp3' 可使用用户自己的音轨。输出标准化至 -16 LUFS。
交付前进行质量检查。 listen.mjs 将混音发送给 Gemini:询问发音清晰度、误读词汇、音乐与配音的平衡、卡顿和长时间静音。然后以全分辨率每场景截取一帧(ffmpeg -ss <t> -i out.mp4 -frames:v 1 f.png)并检查:字幕是否遮挡 UI、文字是否被截断、屏幕状态是否正确。修复后重复步骤 6。
交付。 删除录制过程中创建的测试订单/数据,运行 agent-browser close --all,提交 video/ 目录下的工具和脚本(不提交 build/、out/)。提供链接、本地路径、视频内容简要说明,以及录制期间修复的产品问题(完整录制流程通常会暴露出实际 bug;修复它们,这些 bug 会影响真实用户)。
发布
publish.mjs 将视频上传到项目存储,并设置正确的内容类型(普通存储上传会将视频作为下载文件提供),然后输出公共 URL:若 openkbs.json 中包含 "storage": { "cloudfront": "media" },则文件可通过 <site>/media/<key> 访问(需先执行 openkbs deploy 设置该路径)。若未使用 CDN 存储,可将文件放入 site/ 并部署,或分享 openkbs storage download 命令。--cover <seconds> 参数还会上传一帧 JPG 作为缩略图。
要求
- Studio 容器:
ffmpeg(setup 会安装)、agent-browser、代理 JWT 存放于~/.openkbs/projectJWT。在 Studio 外部需设置OPENKBS_API_KEY。 - 字幕字体由
setup.sh下载到video/build/fonts(Golos Text、Fira Sans Extra Condensed:支持拉丁字母和西里尔字母,OFL 许可)。