录制自动演示视频(Playwright)
模式(先决定)
收到的参数:$ARGUMENTS
| 参数 | 模式 | 模板 |
|---|---|---|
包含 audio(或请求要求声音/语音旁白/口头叙述) | 旁白模式 — TTS语音 + 字幕 | record-demo-narrated-template.mjs + narrate.py |
| 空/其他情况 | 无声模式 — 仅字幕(默认) | record-demo-template.mjs |
旁白模式:语言 en(默认)或 pt(巴西葡萄牙语);引擎 auto(默认:英语→kokoro离线;葡萄牙语→edge,离线时回退到kokoro),或强制使用 kokoro / edge。示例:audio、audio pt、audio pt kokoro、audio en edge。同时请遵循下方的旁白模式说明。
字幕和旁白使用所选语言编写(en,除非给出了pt或用户用葡萄牙语书写)。
概述
演示视频是代码,而非手动录制:一个Playwright脚本驱动浏览器,使用原生录制功能,并叠加字幕和视觉高亮。当产品变更时,可随时重新录制(npm run demo:record),且节奏和故事内容可控。
核心原则:视频是一次推销,而非E2E测试。 每个场景都是为了证明一个论点——而只有在逐帧验证生成的视频后,工作才算完成。
何时使用/不使用
- ✅ Web产品POC/面向投资者、客户、利益相关者、新员工入职的演示
- ✅ 记录不断演进的端到端流程(可重新录制)
- ✅ 带语音:旁白模式(本地/离线TTS)—— 见上文
- ❌ 自动化测试(请使用Playwright Test)· ❌ 非Web应用 · ❌ 录制应用自身声音(Playwright不录制浏览器音频)
流程
- 首先确保确定性状态。 视频执行真实操作(登录、点击、数据库写入)。在录制前,确保幂等的种子/演示数据和专用账户可用。以生产模式运行服务器(
build && start),或在开发模式下预热路由——懒编译会在视频中显示为白屏。 - 先写剧本,再写代码。 一个4幕推销结构:愿景(开场)→ 运作方式(差异化因素,内部)→ 最终用户体验 → 证明/结果(以愿景收尾)。每个场景 = 1个论点 + 1条字幕(有力的标题+解释性副文本)。目标:总时长60–120秒,每个关键画面停留3–5秒。
- 适配模板 — 提供现成的辅助函数,用于字幕、高亮、登录、节奏控制和转换。使用项目品牌颜色设置字幕样式。
- 录制,将选择器失败视为脚本错误(修复它,不要绕开问题)。
- 验证视频——必须执行。 时长和场景:
在检查完所有帧之后才能交付。如果有场景失败,则重新录制。ffprobe -v error -show_entries format=duration -of csv=p=0 demo.mp4 # 每个场景截取一帧,并逐一检查(字幕正确?画面正确?无破损?) ffmpeg -y -ss <t> -i demo.mp4 -frames:v 1 -vf scale=800:-1 frame_<t>.png - 交付
.mp4(可在PowerPoint/Slack/WhatsApp中使用),同时保留.webm。创建一个npm脚本(demo:record)并将输出文件加入gitignore(因其可重新生成)。
旁白模式(audio)
与上述流程相同,但有如下差异:
- 前置条件: 确保
uv和ffmpeg在PATH中(uv --version、ffmpeg -version)。将narrate.py复制到与录制脚本相同的文件夹中。首次运行会下载Kokoro模型(约120 MB,缓存于~/.cache/recording-demo-videos)。 - 节奏由音频主导。 每个场景的
SCRIPT中包含caption(画面字幕)和say(语音文本,1–2句话,推介语气)。await narrate(page, "id")会显示字幕、播放语音并等待其完成——有语音的场景不要使用固定的pause()。在交互过程中播放语音:narrate(page, id, { wait: false });下一个narrate()会等待前一段语音结束(不会重叠)。 - 语言/语音通过环境变量设置:
DEMO_LANG=en|pt、DEMO_TTS=auto|kokoro|edge、DEMO_VOICE=<voice>(Kokoro:af_heart、am_michael、bf_emma、pf_dora、pm_alex;Edge:en-US-AvaMultilingualNeural、pt-BR-FranciscaNeural……)。kokoro= 离线,Apache-2.0许可证,英语默认引擎;其葡萄牙语语音明显不够自然。edge= 葡萄牙语默认引擎,音质最佳,但通过非官方的微软端点在线运行——适用于内部演示;商业用途建议优先使用kokoro或官方TTS。 - 同步自动完成: 模板以品红色闪烁(
syncMarker)开始,测量实际视频启动延迟并修剪该闪烁。务必让syncMarker作为第一个动作;如果日志显示“Sync marker not found”,则语音会不同步——检查syncMarker是否为第一个动作,且前1秒内没有内容遮挡屏幕,然后重新录制。 - 输出:
demo.mp4(旁白版——可交付文件)、demo.srt、timeline.json、demo.raw.webm(原始无声版)、audio/(缓存:重新录制仅重新合成已变更的行)。 - 额外验证(必须执行): 除帧检查外,还需确认语音位置正确:
ffprobe -v error -show_entries stream=codec_type,duration -of csv=p=0 demo.mp4 # 必须包含视频和音频流 ffmpeg -i demo.mp4 -af silencedetect=n=-45dB:d=0.6 -f null - 2>&1 | grep silence_end # 每个silence_end ≈ timeline.json中对应场景的atVideo时间(误差±0.2秒);截取该时间点的帧并检查字幕
常见陷阱(经验教训)
| 陷阱 | 解决方法 |
|---|---|
| 视频文件名随机 | 在关闭页面之前获取page.video();context.close()之后使用await video.path();然后重命名 |
| 导航后字幕消失 | 每次goto后重新注入字幕(caption()辅助函数),或使用addInitScript + sessionStorage |
| 视频对观众来说太快 | 设置slowMo: 100–150 + 每个场景显式暂停3–5秒 + pressSequentially({ delay: 40–60 })模拟可见的输入 |
| mp4无法在PowerPoint/播放器中打开 | 使用ffmpeg -c:v libx264 -pix_fmt yuv420p |
| 视频尺寸偏小/被裁剪 | recordVideo.size必须等于viewport |
| 视频中出现白屏/加载中画面 | 操作后使用waitUntil: "networkidle" + waitForURL;在开发模式下预热路由 |
| 观众不知该看哪里 | 在点击前对元素使用琥珀色高亮(box-shadow),或注入一个假的鼠标光标 |
| 重新录制导致数据重复 | 使用幂等操作,或能容忍重复运行的种子数据(后缀slug、upsert操作) |
| 不同角色间登录信息泄漏 | 切换用户之间调用context.clearCookies() |
| (旁白模式)语音与画面不同步 | Playwright视频启动比页面迟0.2–1.5秒(因运行/版本而异)——使用模板的syncMarker,切勿使用固定偏移 |
| (旁白模式)语音被截断或场景仓促 | 在有语音的场景中使用固定的pause()——应替换为narrate(),它会等待语音结束 |
| (旁白模式)缩写/品牌名发音错误 | 在say中按音拼写(例如“S Q L”或“sequel”);字幕保持正确 |
常见错误
- 跳过帧验证(“运行没有报错” ≠ “视频没问题”)—— 务必亲自查看。
- 字幕描述UI(“登录界面”)而不是讲述论点(“团队登录——细粒度角色控制”)。
- 没有写好脚本就录制:结果是一个冗长无故事的屏幕录像。
- 硬编码真实凭据——使用演示/测试账户,敏感信息通过环境变量注入。