browser-video

v2026.09.25

Records demo and verification videos of web pages using playwright-cli's screencast, and checks the result by inspecting extracted frames. Use when asked to record a video, screen recording, demo, or walkthrough of a web app or page; to show a flow working end to end; or to capture visual proof that a UI change behaves correctly. Not for making a thumbnail from an existing video (video-thumbnails), or for terminal recordings (terminal-control, terminal-fabricate).

GitHub
安装命令
npx skhub add connorads/browser-video
Markdown
SKILL.md

Browser Video

You cannot see what you recorded. Every rule here exists because a script succeeded and the video was still wrong: the run returned "done", exited 0, and shipped a take with the click 200px off target and no pointer in frame. A green run is evidence the script ran, not evidence the video is right.

Assumes playwright-cli is on PATH. Begins where its references/video-recording.md ends - that reference has the screencast and overlay API; this skill has what it takes to get a correct take.

One take per browser session

Overlays leak. An overlay with duration: 3400 outlived its duration, survived page.goto, survived screencast.stop(), and reappeared in two later recordings as a stale pill nobody put there. Start every take in a fresh named session and close it after:

playwright-cli -s=take1 open https://example.com/
playwright-cli -s=take1 video-show-actions
playwright-cli -s=take1 run-code --filename hero.js
playwright-cli -s=take1 close

page.screencast.hideOverlays() clears leaked overlays and is worth calling before stop(), but only a fresh session is deterministic.

Make actions visible

The screencast records no cursor. Not the OS pointer, not a synthetic one - page.mouse.move() moves an invisible thing. Run video-show-actions on the session before the scripted run and the recording gains both an animated pointer and a callout naming each action:

playwright-cli -s=take1 video-show-actions --duration=600 --position=top-right

--cursor pointer is the default; --cursor none disables the pointer and keeps the callouts. It annotates run-code actions, not just CLI-driven ones, so it replaces any hand-rolled cursor overlay entirely.

Work in two phases

  1. Explore with CLI commands. Drive the real flow with playwright-cli goto/snapshot/click/fill, recording nothing. This is where you learn the locators, what the app actually anchors to, and where the flow surprises you. Skipping it means discovering the surprise inside a take.
  2. Script the take with run-code. One file, run once, so pauses and pacing are deliberate. Copy assets/hero-template.js and adapt it - it carries the coordinate mapping, the glide helper, and the chapter brackets.

Coordinates inside a scaled iframe

boundingBox() does not correct for a CSS transform scaling an iframe. It reported (766, 538) for an element rendering at (442, 350) inside an iframe at Fit 55%; the click landed 200px low and pinned a comment to the wrong thing. Map through the iframe box instead:

const ib = await page.locator(FRAME).boundingBox();          // iframe in the page
const r = await locator.evaluate(el => {                     // element in the frame
  const b = el.getBoundingClientRect();
  return { x: b.x, y: b.y, w: b.width, h: b.height, vw: innerWidth };
});
const s = ib.width / r.vw;                                   // the real scale
const point = { x: ib.x + r.x * s, y: ib.y + r.y * s };

Outside a scaled frame boundingBox() is correct and needs none of this. The tell that you need it: the app renders a page inside a page, or shows a zoom control such as "Fit 55%".

Verify before delivering

Extract frames and look at them. This is the only step that has ever caught any of the above.

scripts/video.sh probe take.webm                  # duration, size, codec
scripts/video.sh sheet take.webm                  # 6 frames tiled into one PNG
scripts/video.sh sheet take.webm -n 6 --around 5 --window 2   # hunt a short overlay

Read the sheet, not the frames one at a time. Check four things:

  • the pointer is visible and near what is being clicked
  • the intended target was hit, and the app responded to it
  • no overlay from an earlier take is on screen
  • text is legible at the delivered size

A short annotation can hide entirely between evenly spaced frames; --around with a narrow --window is how you confirm a 900ms callout rendered.

Deliver .mp4 unless asked otherwise - .webm will not play in several places a reviewer might open it:

scripts/video.sh mp4 take.webm     # H.264, yuv420p, faststart

Record against a disposable fixture

A flow that mutates state burns its target on every take, and you will need more than one take. Recording a comment flow consumed three real canvases before a clean run. Create the fixture you can recreate before recording - a fresh account, board, document or seeded row - rather than after the first take has dirtied the real one. Where the flow is read-only, none of this applies.

Craft

For a video a human watches, as opposed to a verification artefact:

  • Type with pressSequentially(text, { delay: 55 }). Instant fills read as a glitch; 50-60ms reads as a person.
  • Move with page.mouse.move(x, y, { steps: 28 }), then wait ~500ms before clicking. The settle pause is what makes the action legible.
  • Bracket sections with page.screencast.showChapter(title, { description, duration: 2400 }). Open on one, close on one.
  • Highlight the outcome with showOverlay for ~3s at the end, so the viewer knows which part was the point.
  • Aim for 20-40s. Under 20s a viewer misses the setup; over 40s they scrub.

Boundaries

  • playwright-cli - the screencast, overlay and chapter API itself.
  • video-thumbnails - a still image composed from a video that already exists.
  • terminal-control, terminal-fabricate - recordings of a terminal, not a browser.
  • prove-it - whether evidence supports a claim; this skill is how the evidence gets captured.

tests/video.bats covers scripts/video.sh's CLI contract; run it after changing the script. evals/ holds this skill's own test prompts and rubric; neither is part of the procedure.

发现
标签

此技能尚未发布标签。

版本
最新版本元数据

版本

v2026.09.25

发布时间

2026年9月25日

分类

未分类

许可证

未指定

源路径

skills/browser-video

默认分支

master

最新提交

aee98d2

Tree SHA

d5838aa