Playwright CLI 视频录制指南:用 playwright-cli 与 Screencast API 生成带章节与标注的 WebM 演示视频
Playwright 的视频录制能力用于把浏览器自动化会话捕获为 WebM(VP8/VP9 编码)视频,服务于调试复盘、交付演示与文档化场景。本指南以 video-recording.md 为主线,讲解 playwright-cli 三条录制命令的交互式用法,以及通过 run-code + page.screencast API 编写“脚本化录屏”,在视频中插入章节卡片、悬浮标注与元素高亮,产出专业级操作演示。
背景:video 命令在 playwright-cli 中的位置
playwright-cli 是一套供 Agent 与自动化程序驱动浏览器的命令行界面,其全部命令在 SKILL.md 中登记,其中视频相关命令归类于 devtools 能力组:
# record user actions in the browser, print them as Playwright code on stop
playwright-cli video-start video.webm
playwright-cli video-chapter "Chapter Title" --description="Details" --duration=2000
playwright-cli video-stop
这些命令的命令行参数定义位于 cli-daemon/commands.ts,每个命令映射到底层工具(tool),真正执行录制、章节与标注逻辑的是 tools/backend/video.ts 中导出的五个工具:browser_start_video、browser_stop_video、browser_video_chapter、browser_video_show_actions、browser_video_hide_actions。
基础录制流程
视频录制在已打开的浏览器会话上进行。核心命令如下:
| 命令 | 作用 | 关键参数 |
|---|---|---|
video-start |
开始录制 | filename(保存文件名,可选);--size=WxH(视频帧尺寸,如 800x600) |
video-chapter |
在录制流中加入章节卡片 | title(标题,必填);--description(描述);--duration(卡片展示毫秒数) |
video-stop |
停止录制并保存视频 | 无 |
一段最小可用的交互式录制流程:
# 先打开浏览器
playwright-cli open
# 开始录制
playwright-cli video-start demo.webm
# 为章节切换插入章节标记
playwright-cli video-chapter "Getting Started" --description="Opening the homepage" --duration=2000
# 导航并执行操作
playwright-cli goto https://example.com
playwright-cli snapshot
playwright-cli click e1
# 添加另一个章节
playwright-cli video-chapter "Filling Form" --description="Entering test data" --duration=2000
playwright-cli fill e2 "test input"
# 停止并保存
playwright-cli video-stop
几点参数细节可从命令定义中确认:
- 文件名可省略:
video-start的filename是可选参数。底层browser_start_video工具会在未提供文件名时按video-{timestamp}.webm规则命名,并把相对路径解析到工作区根目录(见 tools/backend/video.ts)。若给不出更贴切的名字,省略它让系统自动命名即可。 - 尺寸参数:
video-start --size支持"800x600"这样的宽x高字符串,命令层会把它解析为{ width, height }结构后透传给底层(见 commands.ts)。未指定时,服务端会以当前页面视口为基准做缩放:默认在 800×800 的边界内按比例取整尺寸(见 server/screencast.ts)。 - 章节标记:
video-chapter在当前标签页的页面上调用page.screencast.showChapter(title, { description, duration }),会在页面正中显示一张带模糊背景的全屏章节卡片,duration为 0/省略时该卡片不会自动消失(见 tools/backend/video.ts)。 - 停止即保存:
video-stop对应browser_stop_video,会返回录制到的全部视频文件并解析为最终产物(见 tools/backend/video.ts)。
录制一旦开始,页面上的真实操作(goto、click、fill 等)都会被连续帧捕获,因此流程中自然的 snapshot 停顿或 waitForTimeout 就是视频中的“留白”,可以用来控制节奏。
录制自动标注:video-show-actions 与 video-hide-actions
除章节卡片外,CLI 还提供一对动作标注命令(同样属于 devtools 能力组,见 SKILL.md):
# 为后续每个动作(click、type…)在页面上叠加“动作名 + 目标高亮”标注
playwright-cli video-show-actions --duration=600 --position=top-right
playwright-cli video-hide-actions
参数说明(定义见 commands.ts):
| 参数 | 含义 | 默认值 |
|---|---|---|
--duration |
每个动作标注停留的毫秒数 | 500 |
--position |
动作标题位置:top-left/top/top-right/bottom-left/bottom/bottom-right |
top-right |
--cursor |
光标装饰:pointer 会在动作点之间动画一个鼠标指针;none 关闭 |
pointer |
底层实现上,browser_video_show_actions 会调用 tab.page.screencast.showActions(...),随后每当真实输入动作(点击、键入等)发生前,服务端都会在页面上短暂渲染一次标注:渲染动作标题、定位目标边界框并叠加指针动画,再在 duration 毫秒后移除(见 server/screencast.ts)。这非常适合“边执行边录制”的场景——无需任何脚本即可让最终视频里的每一步操作都有视觉说明。
最佳实践:用 run-code 录制完整脚本
文档特别强调:当录制给用户观看的“成品视频”或用作工作交付证明时,不要逐条敲 CLI 命令,而是把整个场景写成一段代码,交给 run-code 执行。这样可以在动作之间插入恰到好处的停顿,并为视频逐段添加旁白与标注。
推荐的完整流程分三步:
- 先用 CLI 走一遍场景,用
snapshot记录下所有关键元素的 ref 与 locator,随后利用 locator 去请求对应的边界框(bounding box)以便做高亮。 - 把目标视频写成脚本文件:使用
pressSequentially配合delay模拟自然的打字节奏,并在动作之间加入合理的等待。 - 用
playwright-cli run-code --filename your-script.js执行,一次跑完整个场景并自动产出视频。
run-code 命令本身接受 --filename 从文件加载代码,也可以直接用 --code 传入内联函数(定义见 commands.ts),代码以 async page => { ... } 形式编写。
完整示例脚本(改编自原文档):
async page => {
await page.screencast.start({ path: 'video.webm', size: { width: 1280, height: 800 } });
await page.goto('https://demo.playwright.dev/todomvc');
// 章节卡片:模糊页面并弹出对话框,duration 到期后自动移除。
// 简单场景用 showChapter 即可;如需更漂亮的叠加层,
// 随时可以用 await page.screencast.showOverlay() 手工定制。
await page.screencast.showChapter('Adding Todo Items', {
description: 'We will add several items to the todo list.',
duration: 2000,
});
// 执行动作
await page.getByRole('textbox', { name: 'What needs to be done?' }).pressSequentially('Walk the dog', { delay: 60 });
await page.getByRole('textbox', { name: 'What needs to be done?' }).press('Enter');
await page.waitForTimeout(1000);
// 展示下一章节
await page.screencast.showChapter('Verifying Results', {
description: 'Checking the item appeared in the list.',
duration: 2000,
});
// 添加一个“粘性”标注,标注保持显示的同时仍可继续操作页面。
// 叠加层是 pointer-events: none,不会挡住点击。
const annotation = await page.screencast.showOverlay(`
<div style="position: absolute; top: 8px; right: 8px;
padding: 6px 12px; background: rgba(0,0,0,0.7);
border-radius: 8px; font-size: 13px; color: white;">
✓ Item added successfully
</div>
`);
// 标注显示期间继续执行动作
await page.getByRole('textbox', { name: 'What needs to be done?' }).pressSequentially('Buy groceries', { delay: 60 });
await page.getByRole('textbox', { name: 'What needs to be done?' }).press('Enter');
await page.waitForTimeout(1500);
// 移除标注
await annotation.dispose();
// 也可以高亮相关 locator 并提供上下文标注:
const bounds = await page.getByText('Walk the dog').boundingBox();
await page.screencast.showOverlay(`
<div style="position: absolute;
top: ${bounds.y}px;
left: ${bounds.x}px;
width: ${bounds.width}px;
height: ${bounds.height}px;
border: 1px solid red;">
</div>
<div style="position: absolute;
top: ${bounds.y + bounds.height + 5}px;
left: ${bounds.x + bounds.width / 2}px;
transform: translateX(-50%);
padding: 6px;
background: #808080;
border-radius: 10px;
font-size: 14px;
color: white;">Check it out, it is right above this text
</div>
`, { duration: 2000 });
await page.screencast.stop();
}
脚本中的关键约定:
- screencast 生命周期:
page.screencast.start(...)开始录屏并返回一个DisposableStub,path指定视频保存位置、size指定画面尺寸;page.screencast.stop()结束录制并落盘。客户端侧实现见 client/screencast.ts。 - 叠加层不拦截事件:所有 overlay 都带
pointer-events: none,因此即使把粘性标注一直显示在页面上,后续的click、fill等操作也完全不受影响(原文档特别提醒这一点)。 showChapter会阻塞:章节卡片持续到duration耗尽后自动移除,才继续执行后续代码,因此它天然充当了“暂停—解说—继续”的节奏控制点。boundingBox()配合 overlay:先取目标元素的边界框,再据此生成一个绝对定位的高亮矩形与说明气泡,是制作“注视某个元素”效果的标准手法。- 创造力不受限:overlay 就是注入到页面的任意 HTML,你可以按需定制任意样式,做出远比内置卡片更丰富的视觉效果。
Overlay API 汇总
原文档给出如下 API 对照表,可直接用于脚本:
| 方法 | 适用场景 |
|---|---|
page.screencast.showChapter(title, { description?, duration?, styleSheet? }) |
全屏章节卡片 + 模糊背景 —— 适合章节切换 |
page.screencast.showOverlay(html, { duration? }) |
自定义 HTML 叠加层 —— 用于提示框、标签、高亮 |
disposable.dispose() |
移除未带 duration 的粘性叠加层 |
page.screencast.hideOverlays() / page.screencast.showOverlays() |
临时隐藏 / 恢复显示所有叠加层 |
这些方法都由 Screencast 客户端类实现并逐一通过协议通道下发(见 client/screencast.ts):showOverlay 会获得一个 overlay id,返回的 DisposableStub 在 dispose 时触发 screencastRemoveOverlay;hideOverlays/showOverlays 则通过 screencastSetOverlayVisible 统一控制全部叠加层的显隐,方便在需要展示“干净页面”的时刻临时收拢标注。
最佳实践:文件名与目录组织
视频文件会堆积在输出目录中,建议在文件名中携带足够的上下文,方便日后检索:
# 在文件名中包含上下文
playwright-cli video-start recordings/login-flow-2024-01-15.webm
playwright-cli video-start recordings/checkout-test-run-42.webm
录制多个场景时,按 场景-日期 或 流程-运行号 的命名习惯(如 login-flow-2024-01-15.webm)能显著提升可追溯性。也可以省略 filename,让系统以 video-{timestamp}.webm 自动命名并写入输出目录。
Tracing vs Video:如何选择
录制浏览器会话还有另一条途径——Tracing(可配合 playwright-cli tracing-start / tracing-stop 使用)。两者的能力边界如下:
| 特性 | Video | Tracing |
|---|---|---|
| 输出 | WebM 文件 | Trace 文件(可在 Trace Viewer 中查看) |
| 展示内容 | 视觉录制画面 | DOM 快照、网络、控制台、动作序列 |
| 适用场景 | 演示、文档 | 调试、分析 |
| 体积 | 较大 | 较小 |
选择依据:当你需要“给人看”的画面(产品演示、交付证明、教学视频),选 Video;当你需要“给程序分析”的结构化数据(复现 bug、审查请求与状态),选 Tracing。二者并不互斥,同一场景可以同时开启。
底层实现与已知限制
从服务端实现可以佐证视频产出的几个工程细节:
- 输出编码为 VP8 的 WebM:服务端
_startScreencast在未指定尺寸时会依据视口等比例缩放进 800×800 的盒子,并把宽高强制转换为偶数——注释明确说明“两个维度都必须为奇数……vp8 需要”(实际代码width & ~1/height & ~1向下取偶,见 server/screencast.ts),同时 JPEG 帧质量默认 90。 - 客户端 API 与类型:
page.screencast对应的公开类型位于 client/screencast.ts,Screencast实例通过监听页面的screencastFrame通道事件接收帧,并在stop()时把产物Artifact保存到path。 - 一个录制会话可被多方消费:服务端维护多个 client,帧会同时分发给视频录制与 tracing 等消费者,且按“任一 consumer 完成即 ack”的 OR 逻辑保证帧流不被最慢的一方阻塞(见 server/screencast.ts)。
需要留意的局限(原文档明确列出):
- 录制会带来轻微自动化开销:帧捕获与编码占用 CPU,长场景下可能使操作略有延迟。
- 大录制会消耗显著磁盘空间:分辨率越高、时长越长,产物越大。建议明确指定
--size或size以控制体积,录完即检查磁盘占用。
延伸阅读
- 视频录制命令的完整清单与语法示例见 SKILL.md;
- CLI 命令参数定义与默认值见 cli-daemon/commands.ts;
- 底层视频工具的协议 schema 见 tools/backend/video.ts;
- 客户端 Screencast API 见 client/screencast.ts,服务端实现见 server/screencast.ts;
- 需要结构化调试信息时,可参考配套的 Tracing 能力文档 tracing.md。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00