关于 vscode-playwright
用于捕获 VS Code 编辑器截图,并将独立的浏览器动画录制为无声 WebM 视频。提供适用于 CI 的可重复脚本流程,也支持通过 Playwright MCP 进行交互式的单次捕获。
主要功能
- 01脚本化捕获 VS Code 截图
- 02通过 Playwright MCP 交互捕获
- 03验证截图并测量字体
- 04将浏览器动画录制为 WebM
- 05配置视口并整理编辑器界面
适用场景
- 01制作演示文稿或文档用的 VS Code 截图
- 02在 CI 中运行可重复的截图捕获
- 03将 HTML 动画录制为无声 WebM 视频
MCP 相关
交互式 VS Code 捕获会使用 Playwright MCP 服务提供的浏览器工具。脚本化截图和浏览器动画录制流程不需要 MCP。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ microsoft/ hve-core --skill vscode-playwright安装后在 Claude Code 中输入/vscode-playwright确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
pyproject.tomluv.lockscripts/capture_vscode.pyrecord_browser_video.pytests/fuzz_harness.pytest_capture_vscode.pytest_record_browser_video.pytests/corpus/not-a-mapping.ymltraversal-plan.ymlvalid-plan.yml详细介绍
VS Code 和浏览器录制技能
捕获 VS Code 编辑器视图、代码讲解和 Copilot Chat 示例,并将独立的浏览器动画场景录制为无声 WebM 片段。
概述
此技能提供完整的工作流,用于捕获高质量的 VS Code 截图,适合嵌入幻灯片、文档和其他视觉媒体。它可处理服务生命周期管理、视口配置、界面清理和截图验证。
两种方式遵循相同的限制。对于任何可重复或无人值守的捕获(包括 CI),优先使用脚本方式。对于探索性或一次性捕获,请使用交互式 Playwright MCP 方式。
脚本捕获
scripts/capture_vscode.py 以无头模式运行 YAML 捕获计划:启动 serve-web、应用捕获设置、在 Monaco 中打开每个文件、测量渲染字体,并为每次捕获写入一张截图。它直接驱动 Playwright,因此无需 MCP 服务,可在 CI 运行器上运行。
uv sync
uv run playwright install --with-deps chromium
uv run python scripts/capture_vscode.py --plan capture-plan.yml --workspace /path/to/repo
计划会为每次捕获指定 id、相对于工作区的 file,以及相对于计划目录的 output 路径;如果指定了 --output-root,则 output 路径相对于该目录。id 必须是由字母、数字、.、_ 或 - 组成的单个文件名安全标记。output 必须是使用 / 分隔符且不含 .. 的相对 .png 路径;脚本会拒绝写入输出根目录之外或通过符号链接写入:
resolution: 1920x1080
min_font_pt: 18
font_size: 26
theme: Default Dark Modern
captures:
- id: marketplace-catalog
file: .github/plugin/marketplace.json
output: frames/marketplace-catalog.png
只有在所有捕获均已写入且满足 min_font_pt 时,脚本才会以 0 退出;并在最后一行标准输出中打印一条 JSON 结果,其中包含每次捕获的测量值 rendered_font_size_pt、zoom 和 source_resolution。捕获失败时也会写入 debug-<id>.png。脚本会在计划验证时拒绝 Markdown 目标;如果深色主题未生效,也会运行失败,因此与之冲突的浅色捕获无法通过验证。在 CI 中通过管道传输其输出时,请在 shell: bash 下运行该步骤,以便 pipefail 保留退出代码。
浏览器动画录制
scripts/record_browser_video.py 会从就绪场景帧中录制一个独立的 HTML 动画,并生成无声 WebM 片段。场景必须在本地资源和动画状态就绪后,将 data-animation-ready="true" 设为其 body 上的属性,并定义 window.startAnimation(),以重置叙事动画和计时器。录制从这一握手信号开始,而不是从页面导航开始。
浏览器上下文处于离线状态,Service Worker 会被拦截,WebSocket 流量会被截获但不会转发,弹出窗口会被关闭。合成来源只会提供获准资源根目录下的文件;路径遍历和逃逸的符号链接都会被拒绝。默认根目录为场景目录;如需使用包含该场景且经调用方批准的共享资源目录,请使用 --asset-root。请勿将工作区或主目录设为资源根目录。
uv run python scripts/record_browser_video.py \
--scene animation/scene-001/index.html \
--output clips/scene-001.webm \
--duration 8 \
--resolution 1920x1080
录制器会写入无声片段。请将其与匹配的旁白 WAV 配对,放入 demo-video 片段中;该组装器会将浏览器片段裁剪或循环到指定的旁白时长,并提供最终音频。帧以 24 fps 的帧率按虚拟场景时间采样,然后使用 FFmpeg 编码。浏览器启动和关闭时的帧会被排除;时长精确到视频帧边界。
前置条件
脚本截图需要 VS Code 或 VS Code Insiders CLI(code 或 code-insiders)。交互式 VS Code 捕获还需要真实的 Playwright MCP 浏览器工具和 curl。浏览器动画录制需要 uv、包含 Playwright 1.48 或更高版本的技能环境、Chromium,以及带有 libvpx-vp9 的 FFmpeg;不需要 VS Code 或 MCP。
此技能中的工具名称使用 mcp_microsoft_pla_browser_* 前缀。实际前缀取决于你的宿主中 MCP 服务的注册名称,因此可能有所不同,例如 mcp_playwright_browser_*。请使用宿主提供的前缀。
已验证的约束
以下三项约束已通过运行中的 serve-web 实例确认。每一项都否定了一种看似合理但实际行不通的做法。
- 用户设置保存在浏览器的 IndexedDB 中,而不是磁盘上。将设置写入
--server-data-dir/data/User/settings.json对 VS Code Web 没有影响。通过触发粘贴事件,在Preferences: Open User Settings (JSON)中写入设置,因为粘贴可以避开 EditContext 按键处理和括号自动补全,然后保存并重新加载页面。重新加载会关闭设置编辑器;Insiders 会将其作为模态窗口打开并占据焦点。重新加载还会应用工作区信任等窗口级设置。持久化的浏览器上下文会在重新加载后保留这些设置。 - Markdown 文件会作为跨源预览 Webview 打开,而不是 Monaco 编辑器。页面无法访问 Webview 的 DOM,因此无法检查或测量其中渲染的文本。如果截图需要可测量的编辑器文本,请截取代码文件或配置文件。
- 应通过尝试导航来确认浏览器工具,而不是匹配工具名称,因为 MCP 工具前缀会因服务器注册方式而异。VS Code 内置的浏览器工具就是一个已知案例:它能加载页面,却无法向 VS Code Web 工作台发送键盘或鼠标事件,因此使用这些工具会在第一步命令面板操作时失败。
架构
serve-web CLI 是一个基于 Rust 的代理(“服务器的服务器”),用于下载 VS Code Server 发行版,并将连接代理到内部 Node.js 服务。外层 CLI 接受的标志有限;--server-data-dir 是关键标志,用于控制服务器端数据的存储位置,例如下载的服务器构建版本、扩展和计算机状态。它不控制用户设置;用户设置由浏览器保存在 IndexedDB 中。
快速开始
- 检测 VS Code CLI 变体并启动 Web 服务。
- 使用 Playwright 导航到 VS Code Web 实例。
- 清理界面(关闭面板、标签页和通知)。
- 打开文件并截取屏幕截图。
- 停止服务并进行清理。
工作流步骤
步骤 1:检测 VS Code CLI 变体
首先检查 VSCODE_QUALITY 环境变量;如果其中包含 insider,则使用 code-insiders。否则,使用 command -v code-insiders 检查是否可用,不可用时则回退到 code。保存结果以便重复使用:
if [[ "${VSCODE_QUALITY:-}" == *insider* ]] || command -v code-insiders &>/dev/null; then
VSCODE_CLI="code-insiders"
else
VSCODE_CLI="code"
fi
步骤 2:启动 VS Code Web 服务
创建临时服务数据目录并启动 serve-web。--server-data-dir 标志必须接收字面路径,因为其他终端会话中的 shell 变量在后台终端中不可用:
VSCODE_SERVE_DIR=$(mktemp -d)
$VSCODE_CLI serve-web --port 8765 --without-connection-token \
--accept-server-license-terms --server-data-dir "$VSCODE_SERVE_DIR"
不要在该目录下写入 data/User/settings.json 文件。VS Code Web 会将用户设置保存在浏览器的 IndexedDB 中,因此预置设置文件不会产生任何变化。工作台加载后,通过命令面板命令设置主题、关闭恢复的编辑器并隐藏界面元素(步骤 5);使用 document.body.style.zoom 增大渲染文本的尺寸。
也不要尝试通过 textarea 选择器输入来编辑设置 JSON 编辑器。VS Code Insiders 使用 EditContext API 而非 textarea,因此不存在该元素。
serve-web 命令和 mktemp 必须在同一终端会话中执行,这样 $VSCODE_SERVE_DIR 变量才能正确解析。如果使用后台终端(isBackground: true),请将整个代码块内联,不要引用在其他终端中设置的变量。
继续操作前,请确认服务已就绪:curl -s -o /dev/null -w "%{http_code}" http://localhost:8765/ 必须返回 200。
如果服务日志中包含 Ignoring option 'server-data-dir': Value must not be empty,说明变量为空——服务正在使用默认数据目录,而非临时目录。请终止进程,并使用字面路径重新启动。
第 3 步:导航并等待
- 导航到工作区:使用
mcp_microsoft_pla_browser_navigate前往http://localhost:8765/?folder=/path/to/workspace。 - 等待 VS Code 加载:使用
mcp_microsoft_pla_browser_wait_for,设置time: 5,让编辑器界面完全呈现。
第 4 步:调整视口大小
调整视口大小,使其符合目标放置区域的宽高比:使用 mcp_microsoft_pla_browser_resize,将分辨率设为与要插入截图的 PPTX 占位符宽高比一致。
使用 width_px = 1200 和 height_px = int(1200 / (target_width_inches / target_height_inches)) 计算尺寸。例如,5.5" x 4.2" 的占位符对应 1200 x 916 的视口。
如果截图要填满 16:9 的幻灯片,请将视口设为 1920x1080,而不要根据 1200 px 宽度规则计算。其他所有情况均使用宽度规则,不要在这些情况下使用 1920x1080。请在清理界面前调整视口大小,以便界面元素按目标分辨率呈现。
第 5 步:清理界面
使用 mcp_microsoft_pla_browser_run_code 和命令面板操作模式,为清晰截图做好编辑器准备:
- 如果存在工作区信任对话框,请将其关闭:使用
mcp_microsoft_pla_browser_snapshot检查是否有信任对话框;如果可见,则通过mcp_microsoft_pla_browser_click点击 “Yes, I trust the authors”。 - 关闭所有编辑器和标签页:命令面板 ->
View: Close All Editors。 - 清除通知:命令面板 ->
Notifications: Clear All Notifications。 - 启用“请勿打扰”模式:命令面板 ->
Notifications: Toggle Do Not Disturb Mode。 - 关闭主侧边栏:命令面板 ->
View: Close Primary Side Bar。 - 关闭底部面板:先使用
mcp_microsoft_pla_browser_snapshot。如果面板(Terminal、Problems、Output)可见,则运行命令面板 ->View: Close Panel。不要盲目运行此命令——它会切换显示状态,并打开隐藏的面板。 - 关闭辅助侧边栏:先使用
mcp_microsoft_pla_browser_snapshot。如果辅助侧边栏(Chat)可见,则运行命令面板 ->View: Close Secondary Side Bar。 - 放大以提高可读性:使用
mcp_microsoft_pla_browser_run_code,执行await page.evaluate(() => { document.body.style.zoom = '1.75'; }),以放大整个 UI。不要认为任何单一缩放比例都足够:请提高缩放比例并重新测量渲染后的文字大小,直到达到调用方要求的可读性下限。若编辑器的基础字体大小为 14 px,则 18 pt 相当于 24 CSS 像素,因此约 1.75 倍只是起始值,并非保证值,因为基础字体大小会有所不同。截图缩小以适应幻灯片占位符时,默认字体大小会变得无法辨认(约 7 pt)。
第 6 步:打开文件并截图
使用 mcp_microsoft_pla_browser_run_code 和命令面板操作模式打开文件:Go to File 命令会打开 Quick Open,然后输入文件名并按 Enter:
async (page) => {
await page.keyboard.press('F1');
await page.waitForTimeout(400);
await page.keyboard.type('Go to File');
await page.waitForTimeout(300);
await page.keyboard.press('Enter');
await page.waitForTimeout(500);
await page.keyboard.type('doc-ops-update.prompt.md');
await page.waitForTimeout(500);
await page.keyboard.press('Enter');
await page.waitForTimeout(1000);
return 'File opened';
}
设置视图:通过点击导航,有选择地只打开此截图所需的面板(拆分视图、Copilot Chat、Explorer)。使用 mcp_microsoft_pla_browser_snapshot 查找引用,然后使用 mcp_microsoft_pla_browser_click 点击。让视图聚焦于主题内容。
截图:使用 mcp_microsoft_pla_browser_take_screenshot,设置 type: "png" 和描述性 filename。
验证截图是否适合目标放置区域。比较截取图像的宽高比与目标占位符的宽高比。如果偏差超过 5%,请调整视口尺寸后重新截图。如果测得的渲染文字大小低于调用方要求的可读性下限,请提高缩放比例后重新截图。反复调整视口和缩放比例,直到截图符合放置尺寸且不失真。
其他截图也重复上述操作。打开下一个文件前,请关闭当前文件的标签页(命令面板 -> View: Close All Editors)。
第 7 步:Copilot Chat 截图
对于 Copilot Chat 截图:Activity Bar 默认可见,设置初始化无法更改这一点,因此清理时请保留它。通过点击 Activity Bar 打开 Chat 面板,使用 mcp_microsoft_pla_browser_snapshot -> mcp_microsoft_pla_browser_click;使用 mcp_microsoft_pla_browser_run_code 和 page.keyboard.type() 输入提示词,然后使用 mcp_microsoft_pla_browser_wait_for 等待响应,再进行截图。
第 8 步:清理
停止 VS Code Web 服务器并清理临时环境:
pkill -f "serve-web.*8765" 2>/dev/null || true
rm -rf "$VSCODE_SERVE_DIR"
同时关闭 Playwright 浏览器:mcp_microsoft_pla_browser_close。
Playwright MCP 命令面板操作模式
单个 MCP 工具调用会异步执行,因此在不同的 press_key、type 和 press_key 调用之间,命令面板会关闭。所有命令面板操作都必须使用 mcp_microsoft_pla_browser_run_code,在单次 Playwright 执行中原子地串联操作:
async (page) => {
const runCommand = async (command) => {
await page.keyboard.press('F1');
await page.waitForTimeout(400);
await page.keyboard.type(command);
await page.waitForTimeout(300);
await page.keyboard.press('Enter');
await page.waitForTimeout(500);
};
await runCommand('View: Close All Editors');
await runCommand('View: Close Primary Side Bar');
// Chain additional commands as needed
return 'Commands executed';
}
命令面板操作时,切勿分别调用 mcp_microsoft_pla_browser_press_key -> mcp_microsoft_pla_browser_type -> mcp_microsoft_pla_browser_press_key,否则面板会在调用之间失去焦点。
故障排除
| 问题 | 原因 | 解决方案 |
|---|---|---|
Ignoring option 'server-data-dir': Value must not be empty | 后台终端中的 Shell 变量解析为空 | 将完整命令内联,并使用临时目录的字面路径;或者在同一会话中运行 mktemp 和 serve-web |
| 颜色主题跳转到 Marketplace 主题 | 尚未选择主题,且设置填充未生效 | 工作台加载后,运行命令面板 -> Preferences: Color Theme |
| 切换面板会打开隐藏的面板 | View: Toggle Panel Visibility 是切换操作 | 通过快照确认面板可见后,才使用 View: Close Panel |
?file= 参数不会自动打开文件 | VS Code Web 仅支持 ?folder= | 导航后,通过命令面板中的 Go to File 命令打开文件 |
| 截图中的文字太小 | 默认约 14px 的字体缩小后会变成约 7pt | 调高 document.body.style.zoom 并重新测量,直到达到可读性下限 |
| 截图宽高比失真 | 视口比例与占位图比例不匹配 | 根据占位图计算视口:width_px = 1200,height_px = int(1200 / (target_w / target_h)) |
| 幻灯片嵌入尺寸下 UI 杂乱 | 资源管理器、缩略图、标签页和通知提示均可见 | 每次截取前关闭所有不必要的 UI 元素 |
workbench.action.zoomIn 不起作用 | 仅适用于 Electron 的命令 | 使用 editor.action.fontZoomIn,或通过 page.evaluate() 设置 CSS 缩放 |
| 浏览器状态恢复 | IndexedDB/localStorage 恢复了之前的文件 | 加载后通过命令面板关闭编辑器;如果可用,请使用全新的浏览器上下文或隐身模式 |
Meta+P 触发浏览器操作 | 浏览器拦截了键盘快捷键 | 使用 page.keyboard.press('F1') 打开命令面板 |
| 截图保存到了错误的目录 | take_screenshot 按相对于 Playwright 工作目录的路径保存 | 截取后将截图复制到目标目录 |
| Copilot Chat 回复不确定 | 输出按 token 逐个流式传输 | 使用 mcp_microsoft_pla_browser_wait_for 等待预期文本,或设置时间延迟 |