capture
Film a real web app, logged in or public, SPA or multi-page, as clean re-recordable product footage.
Skill by stevengonsalvez
Install
Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.
npx agentmarket install skill/stevengonsalvez-capture
Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.
Get the weekly diff
The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.
About
Use cases: design, frontend, testing
Reviews
Write a reviewNo reviews yet. Installed it? Reviews come from verified installers only. How reviews work
Permissions
What this skill can do and what it asks for, from its SKILL.md. Checked Oct 25, 2026.
- Tools
- No tools found
- Secrets
- None asked for
- Install scripts
- None found
- Runs as
- Node.js package
Network hosts it talks to 1
codeload.github.com· found in install command
Files it touches
~/.claude/skills/capture
What's inside
- Skill name
capture- Description
- Film a real web app, logged in or public, SPA or multi-page, as clean re-recordable product footage. Drives real clicks through Playwright and films it deterministically (every frame rendered on demand, 2560x1440 lossless at exactly 60fps, with a screencast fallback that says when it is used), with spring-physics camera zooms and cursor, real motion blur, and emits per-chapter mp4 plus an events.json (timed marks with element rects and camera box) for a compositor. Use when asked to "record a product demo", "film the app", "capture a walkthrough", "screen-record a user flow", "make demo footage", "record the feature in the browser", or to re-shoot a demo chapter after the UI changed. Capture only; for spotlights, callouts, chapter cards, transitions and final assembly hand the output to demo:compose, which renders it through HyperFrames.
- License
- MIT
- Instructions
- 562 lines in SKILL.md · view on GitHub
Before installing
- Ships executable scripts
Agent Skills spec issues
- body: 562 lines (spec recommends under 500)
Files (14)
- SKILL.md
- beats.mjs · examples/ferry-draft/
- draft.config.json · examples/ferry-draft/
- package-lock.json
- package.json
- capture.mjs · scripts/
- encode.sh · scripts/
- inventory.mjs · scripts/
- locate.mjs · scripts/
- montage.sh · scripts/
- motion.mjs · scripts/
- narrative.mjs · scripts/
- run.mjs · scripts/
- selfcheck.mjs · scripts/
SKILL.md (first lines)
# demo:capture
Capture real product footage from a live app. Compose it elsewhere.
Pairs with **demo:compose** (the sibling skill in this plugin): it takes the take directory this
skill writes, plus one config carrying the brand and copy, and produces the finished cut.
```
beats.mjs ──▶ run.mjs ──▶ capture.mjs ──▶ <out>/<chapter>/ cfr/ + events.json
│ ▲ │
mintState (login) motion.mjs encode.sh ──▶ <chapter>.mp4
(springs)
│
montage.sh (grade the take) ──▶ demo:compose
```
## Use / do not use
- USE for: authenticated SPA flows, public multi-page apps, feature walkthroughs, re-shooting one chapter after a UI change.
- DO NOT use for annotation, spotlight, labels, chapter cards, transitions, music, final cut. That is `demo:compose`, which renders through HyperFrames (`hyperframes`, `hyperframes-core`, `hyperframes-keyframes`, `hyperframes-animation`). HyperFrames renders video FROM HTML and cannot drive an authenticated SPA, which is why capture is a separate step.
- Keep footage free of annotations. Annotations then stay re-timeable without re-recording. The only things burned in are the synthetic cursor and click ripple.
## Run
Skill dir: this skill's own directory, referred to below as `$SKILL_DIR`. It pins `@playwright/test@1.62.0`.
First run only, from that directory: `npm ci`, then
`PLAYWRIGHT_BROWSERS_PATH="$PW" npx playwright install chromium`, where `$PW` is a writable directory you keep
(for example `~/.local/pw-browsers`). Neither `node_modules` nor the browsers ship with the plugin.
```bash
cd "$SKILL_DIR"
npm run check # self-check, ~9 min, no app needed
node scripts/run.mjs /path/to/beats.mjs --dry-run # every target resolved, no frames: seconds
node scripts/run.mjs /path/to/beats.mjs [chapter ...] # dry run, then capture + encode each chapter
scripts/montage.sh <out>/<chapter>.mp4 # 4x3 contact sheet; LOOK at it
node scripts/inventory.mjs <url> # what a beat can target on a page (see Drafting beats)
```
- Browsers: Playwright reads `PLAYWRIGHT_BROWSERS_PATH` when it is set and otherwise uses its own default (`~/.cache/ms-playwright` on Linux). Export `PLAYWRIGHT_BROWSERS_PATH="$PW"` in the shell that runs the rig and keep that directory stable; the scripts never set it for you. The installed revision must match `node_modules/playwright-core/browsers.json` (1.62.0 wants chromium 1234). On mismatch: `PLAYWRIGHT_BROWSERS_PATH="$PW" npx playwright install chromium`. Prefer a directory you control over `~/.cache/ms-playwright`, which other tooling clears: measured wiped twice on one machine with 34G free, so not disk pressure.
- Write beats files and `out` under a scratch dir, never in a project repo.
- Narration (composing a demo whose config has `narration`) runs `hyperframes tts`, which reads
`HYPERFRAMES_PYTHON`: point it at a venv with `kokoro-onnx` and `soundfile` installed.
- After every take: open the montage. Check head is not blank/black, tail is not a splash, zoom frames are sharp.
- `run.mjs` prints each chapter's mode, fps, density and wall time, e.g.
`fares: deterministic 60fps x2, 659 frames, 11.0s, 2 marks, filmed in 210s`. A chapter that fell back
says `screencast 30fps x1` and the line above it gives the cause.
## Capture modes
```
capture.mode
deterministic (default) ──▶ beginFrame + virtual time ──▶ PNG 2560x1440 @ exactly 60fps
│ a request holds page time: network 'auto' forces it on (see below)
│ no beginFrame / page time stuck even when forced / hard timeout / wrong frame size
▼ (one warning naming the cause, chapter re-filmed from scratch)
screencast ──────────────▶ CDP screencast ──▶ JPEG 1280x720, resampled to 30fps
```
- **deterministic**: chrome-headless-shell runs under `HeadlessExperimental.beginFrame` with
virtual time (`pauseIfNetworkFetchesPending`). The rig renders every frame on demand at exactly
`n / fps` of page time, so CSS animations, `requestAnimationFrame` and timers all step on the
footage clock. Frames come back at `--force-device-scale-factor`: 2560x1440 lossless PNG for a
1280x720 viewport. Network latency is edited out (page time stands still while a fetch is in
flight). Camera and cursor are posed every frame by the spring solver (`motion.mjs`). Costs
several times real time: see the measured facts.
- **Requests that hold page time.** `pauseIfNetworkFetchesPending` waits for every request in
flight, and two kinds never let it go: a stream that stays open (SSE), and, measured, any
dynamic `import()` of a module, even an instant one, so every code-split route. With
`network: 'auto'` (the default) a frame that waits `unstickMs` (1.5s of wall time) is forced
through with policy `advance`; a lazy route then costs 1.5s once and the take stays fully
deterministic. Chrome does not say which request holds page time, so a stream is recognised by
behaviour: a request still in flight at two stalls, or stalls on three frames running (which
also catches a holder no request event shows). Then the rest of the chapter runs under `advance` (page time moves on regardless of the network, so a
load shows for its wall time, roughly a tenth of its real length), the rig says so once, and
`capture.network` / `capture.networkNote` in events.json record it. `network: 'pause'` never
forces and falls back to screencast after `stallMs` instead; `'advance'` forces from the start.
- **Why `auto` is the default.** Almost every modern SPA lazy-loads its routes, and under strict
`pause` each of those loads freezes page time for good: a real app's first deterministic take
fell back to screencast on its first route change. `auto` keeps those apps deterministic, edits
network latency out everywhere else, and only gives that up (saying so) when a stream really
holds page time. Use `pause` when the footage must never show a load at anything but its edited
length, and accept a screencast fallback on apps that need it.
- **screencast**: the real-time path. It is used when deterministic capture cannot proceed: the
browser has no beginFrame, page time stops even when forced, the chapter passes `timeoutMs` of
wall time, frames come back at the wrong size, or `network: 'pause'` meets a request that never
finishes. The rig prints one line naming the cause, re-films the
chapter in screencast mode and records both in `events.json` (`capture.mode`,
`capture.requested`, `capture.fallback`). With a `login`, it checks the session again first
(and re-mints it): the failed take ran its beats, and one that signs out revoked it. It never
hands over a broken take. Set
`capture: { mode: 'screencast' }` to choose it outright.
- **Websockets do not stall it** (measured: a page receiving a frame every 200ms of wall time
filmed a 2s hold deterministically, and a real SPA holding a Supabase realtime websocket and a
Vite HMR socket filmed a home, click, lazy route, zoom chapter deterministically: 7.5s in 164s,
network still `pause`). Their messages arrive on the wall clock, which runs several times slower
than page time here, so live pushes land sooner in the footage than they would for a real viewer.
```js
capture: {
mode: 'deterministic', // or 'screencast'
dpr: 2, fps: 60, // pixel density and frame rate (deterministic only)
blur: { samples: 4, max: 64, spacing: 1.5, shutter: 0.5, threshold: 2 }, // on by default; false for drafts, spacing 4 in between
network: 'auto', // or 'pause' / 'advance': requests that hold page time, see above
unstickMs: 1500, // wall ms a frame waits on the network before 'auto' forces it
stallMs: 10000, // wall ms before falling back: page time stuck, or any wait under 'pause'
timeoutMs: 600000, // wall ms a chapter may take before falling back; by default 120x its estimated footage when that is longer
}
```
**Motion blur** (deterministic only, ON by default). Pick the setting by how final the take is.
Measured on the ferry example (8 cores, no GPU, one take at a time):
| setting | capture time | a 5-minute demo films in | fast moves look |
|---|---|---|---|
| `capture: { blur: false }` (drafts) | about 6.5x real time | about 33 minutes | sharp, stepping frame to frame |
| `capture: { blur: { spacing: 4 } }` (middle ground) | about 17x | about 1 hour 25 minutes | smeared, faint steps up close |
| default (final takes) | about 35x | about 2 hours 55 minutes | smooth smear |
Screencast mode films at 1x. Set the option file-wide or per chapter: the footage is the same 2x,From stevengonsalvez/ainb-toolkit, MIT.
More from stevengonsalvez/ainb-toolkit
- 0.592score
export
stevengonsalvez
Turn a finished demo into what people see outside a video player - a README bundle (a looping GIF, an animated WebP and a poster PNG plus a ready `<picture>`…
SkillAFreshness: A★ 1Claude Code +9 - 0.587score
brag
stevengonsalvez
Turn the project in the current directory into a short, shareable launch video, by delegating to the upstream brag skill.
SkillAFreshness: A★ 1Claude Code +9 - 0.584score
illustration:popa
stevengonsalvez
Generate intricate hand-drawn sketchnote illustrations starring Popa, a cute pink blob with a green sprout and a notepad, on soft pastel scenes.
SkillAFreshness: A★ 1Claude Code +9 - 0.582score
illustration
stevengonsalvez
Generate intricate hand-drawn sketchnote illustrations starring Popa (a pink blob with a green sprout and a notepad).
SkillAFreshness: A★ 1Claude Code +9 - 0.581score
agytoggle
stevengonsalvez
Multi-account credential manager and profile switcher for the Antigravity CLI (agy).
SkillAFreshness: A★ 1Claude Code +9 - 0.579score
compose
stevengonsalvez
Turn captured product footage into a finished demo video - a 1440p60 master with the app in a framed window on a themed backdrop, a feathered spotlight that…
SkillAFreshness: A★ 1Claude Code +9 - 0.557score
test-writer-fixer
stevengonsalvez
Write tests for code that has none, and repair tests that broke, without weakening what they check.
SkillAFreshness: A★ 1Claude Code +9 - 0.552score
godmode
stevengonsalvez
Autonomous product factory.
SkillBFreshness: B★ 1Claude Code +9 - 0.547score
adopt
stevengonsalvez
Index the agent lanes that already exist into a programme's lanes.jsonl, reading each terminal to classify it and its context use.
SkillBFreshness: B★ 1Claude Code +9 - 0.547score
discover
stevengonsalvez
List the Orca environments, hosts, worktrees and terminals a programme could use, and say which environments are unreachable.
SkillBFreshness: B★ 1Claude Code +9 - 0.547score
retire
stevengonsalvez
Remove a finished lane's worktree through Orca, only once it is merged, clean and idle.
SkillBFreshness: B★ 1Claude Code +9 - 0.547score
handover
stevengonsalvez
Generate HANDOVER.md from a programme's index files and release the owner lock so another session, on any harness, can pick the programme up.
SkillBFreshness: B★ 1Claude Code +9
Signals
- Stars
- 1
- Forks
- 1
- Open issues
- 4
- Last commit (this folder)
- Oct 3, 2026 (26 days ago)
From GitHub (fetched Oct 24, 2026).
Details
- License
- MIT
- Repository
- github.com/stevengonsalvez/ainb-toolkit
- First seen
- Oct 24, 2026
- Last checked
- Oct 24, 2026
- Source
- GitHubgithub-graphql
More from stevengonsalvez
- 0.592score
export
stevengonsalvez
Turn a finished demo into what people see outside a video player - a README bundle (a looping GIF, an animated WebP and a poster PNG plus a ready `<picture>`…
SkillAFreshness: A★ 1Claude Code +9 - 0.587score
brag
stevengonsalvez
Turn the project in the current directory into a short, shareable launch video, by delegating to the upstream brag skill.
SkillAFreshness: A★ 1Claude Code +9 - 0.584score
illustration:popa
stevengonsalvez
Generate intricate hand-drawn sketchnote illustrations starring Popa, a cute pink blob with a green sprout and a notepad, on soft pastel scenes.
SkillAFreshness: A★ 1Claude Code +9 - 0.582score
illustration
stevengonsalvez
Generate intricate hand-drawn sketchnote illustrations starring Popa (a pink blob with a green sprout and a notepad).
SkillAFreshness: A★ 1Claude Code +9 - 0.581score
agytoggle
stevengonsalvez
Multi-account credential manager and profile switcher for the Antigravity CLI (agy).
SkillAFreshness: A★ 1Claude Code +9 - 0.579score
compose
stevengonsalvez
Turn captured product footage into a finished demo video - a 1440p60 master with the app in a framed window on a themed backdrop, a feathered spotlight that…
SkillAFreshness: A★ 1Claude Code +9
Cite this page
capture skill. Agent Mart. https://agentmart.dev/skills/stevengonsalvez-capture (last updated 2026-10-24)