录制演示视频(免费、脚本化) 是做什么的?
通过脚本驱动浏览器,为真实应用制作无声的产品演示视频,并渲染为mp4。 免费且完全本地化:Playwright驱动应用,ffmpeg生成视频。无需付费SaaS、无需旁白、无需人工点击。同一个脚本同时可作为UX冒烟测试,当UI变化时可重新渲染——这正是可持续性地制作大量功能演示的关键。
何时使用
- 用户希望获得一个或多个功能演示/导览视频,但不想为工具付费。
- 面临“每次新功能都需要有人手动录屏”的重复性问题。
- 需要快速提供功能端到端工作的可视化证明,且基于真实UI。
不适用于:含有大量动画且带画外音的市场营销视频(应使用专业剪辑工具),或需要真人在镜头前互动的场景。
工作流程
获取登录会话 → 使用Playwright驱动应用(录制为.webm) → ffmpeg转换为.mp4
在目标仓库的demo/目录下会生成三个文件(从resources/复制而来):
record.mjs— 引擎核心。包含一个CONFIG块(仓库特定配置)和一个FLOWS映射(每个视频对应一个条目)。polish.sh— 将.webm转换为.mp4,修剪登录引导部分,可选添加烧录字幕。run.sh— 一步到位:将开发环境指向staging、录制、后期处理、清理。README.md— 每个仓库的使用说明。
要制作新视频:复制一个FLOWS条目,修改url和steps。这就是完整的操作循环。
设置清单(每个仓库只需执行一次)
- 安装工具(一次性):
npm install -D @playwright/test && npx playwright install chromium。需要ffmpeg(使用Homebrew安装)。对于烧录字幕,需要安装包含libfreetype的ffmpeg版本;否则字幕会自动跳过,其余功能仍正常工作。 - 了解仓库的具体情况,并在
record.mjs的CONFIG块中填写:- 开发命令 — 应用本地启动方式(通常为
npm run dev,有时在子目录如congrats/中)。 - Supabase客户端模块路径 — 通常为
src/integrations/supabase/client.ts。录制器会在页面内导入它以实现登录(参见陷阱1)。 - 录制所用的数据库 — 使用staging环境,切勿使用生产环境(避免真实用户PII)。需找到其URL、匿名/公开密钥、服务密钥和直接数据库URL。在此组织内,这些信息位于audition仓库的
.env.local文件中(VETTED_SUPABASE_*对应VettedAI的staging环境,STAGING_CONGRATS_SUPABASE_*对应Congrats的staging环境)。 - 登录邮箱 — 一个合成/测试账号,拥有可演示的数据。在获取会话之前始终询问用户使用哪个账号(项目守则:未经允许不得使用真实用户进行测试)。
- 路由 — 要录制的流程对应的深层链接路径。
- 开发命令 — 应用本地启动方式(通常为
- 将本地开发服务器指向staging环境(参见陷阱2)。
- 编写流程,运行
bash demo/run.sh <flow>,并通过提取帧进行验证(陷阱8)。
陷阱(来之不易的经验——调试前请先阅读)
1. 通过应用自身的Supabase客户端登录,而非伪造localStorage
Supabase-js会在浏览器中以其非标准键/信封格式写入会话;直接注入localStorage['sb-<ref>-auth-token'] = JSON.stringify(session)看似正确,但客户端实际上不会读取它——应用会跳转到/login。解决方案:在服务端mint一个会话(使用admin.generateLink → verifyOtp获取access_token和refresh_token,无需密码),然后在页面内import应用的Supabase客户端并调用supabase.auth.setSession({access_token, refresh_token})。这会将正确的数据写入存储,且会话在页面导航期间保持有效。这是最重要的一步。
2. --mode staging可能被静默忽略 → 使用.env.development.local
vite-react-ssg dev(以及某些其他配置)会在加载环境变量文件时忽略--mode,因此.env.staging永远不会被加载,应用仍会指向生产环境(你会看到请求发往生产Supabase主机)。Vite始终会自动加载开发模式下优先级高于.env/.env.local的.env.development.local。因此,run.sh会在录制时将你的staging配置复制到.env.development.local中,并在退出时删除它(否则每次运行npm run dev都将静默指向staging——这是一个真正的隐患)。普通的vite仓库可能会遵循--mode;可通过观察应用调用哪个Supabase主机来测试。
3. Staging schema可能滞后于前端 → 进行针对性的增量修改
Staging分支可能缺少前端需要查询的新列→数据查询返回400错误(“column X does not exist”),导致屏幕渲染为空。不要重放整个数据库迁移。对比前端读取的少数几个表的字段(通过information_schema.columns比较staging和production),然后仅应用缺失的字段作为增量的、可为空的ALTER TABLE ... ADD COLUMN IF NOT EXISTS。需获得用户同意——这是一次staging数据库更改。
4. 种子数据的量级可能不匹配
合成种子数据的分值/值可能与UI格式化器期望的范围不一致(例如,种子数据存储为0-100,而UI使用value/5*100→显示“1392%”)。检查格式化器对应的预期范围与production的真实值对比;必要时重新调整种子数据(需先询问用户——这是一次数据修改)。
5. Playwright录制的视频不显示鼠标光标
通过addInitScript注入一个虚拟光标叠加层(一个跟随鼠标移动并在按下鼠标时放大的圆点)。模板中已包含此功能。在点击前将鼠标移动到真实坐标,以便光标正确跟踪。
6. ffmpeg可能缺少drawtext功能
没有libfreetype支持的ffmpeg在添加烧录字幕时会报错。polish.sh会检测drawtext,如果缺失则跳过字幕——不要让字幕故障阻塞mp4的生成。
7. 自动修剪登录/启动引导部分
录制会捕获登录和应用启动的等待时间(数秒的空白)。record.mjs会测量引导时间并写入一个.trim附属文件;polish.sh会据此进行裁剪(ffmpeg -ss)。
8. 通过帧进行验证,不要仅凭“已录制”来判断
使用ffmpeg -ss <t> -i out.mp4 -frames:v 1 frame.png在几个时间点提取帧并实际查看。最初的几次录制可能会停留在/login页面、骨架屏或错误的标签页——帧是检测这些问题的方法。
9. 数据与认证安全性
在staging环境使用合成数据(例如seed_…@test.vetted.com)进行录制,切勿使用真实客户的项目(避免PII)。始终询问用户要登录哪个账号。创建认证会话是一项实际的操作——需先获得确认。
编写流程
在record.mjs中,FLOWS是一个包含{ label, url, steps(page, ui) }的映射。ui辅助方法涵盖大多数需求:
ui.settle(what, [words])— 等待内容加载完成(networkidle + 一个证明屏幕已加载的关键词)ui.scrollThrough(fraction, steps)— 平滑向下滚动再返回ui.clickFirstCandidate()/ 通用形式ui.clickFirst(selectors)— 尽力点击,绝不硬性失败ui.beat(ms)— 有意的暂停,使视频观看体验更流畅
保持流程中selector的使用轻量化和尽力而为(使用try/catch包裹点击操作),以便某个selector匹配失败时降级为“仍然是好看的滚动演示”而非崩溃。节奏要宽松(800–1800ms的停顿);一个好的无声演示时长通常为15–35秒。
输出与交付
mp4文件位于demo/output/目录中(已加入gitignore)。使用open demo/output/<flow>.mp4播放(相对markdown链接无法在IDE中播放——它会在编辑器中打开文件)。共享路径或为用户执行open命令。
传播此技能(它位于skill-master中)
此技能的规范版本位于submodules/skill-master/.agent/skills/recording-demo-videos/,并通过符号链接到每个仓库的.agent/skills/目录。编辑后,先提交并推送子模块,再更新父仓库的指针,然后运行/distribute-skill以更新同级仓库(在推送前需询问用户)。详见skill-master-submodule-sync规则。