demo-recorder
Skill0 starsChanged 2 months agoApache-2.0View on GitHub
Drives a web app in a headless browser with a visible cursor and slow-motion delays, records a real demo video (WebM and mp4), then reviews it. Use to make a watchable UI demo or check a flow.
5 other projects use a version of this.
Adopted by
Most recently taken up by
- milad-ahmd/agent-skillstheir own version, first seen Nov 1, 2026
- sammcj/agentic-codingtheir own version, first seen Oct 17, 2026
- dot-skill/skillerr-browsertheir own version, first seen Sep 30, 2026
- savagemanage/claude-skillsword for word, first seen Sep 4, 2026
- mozdowski/claude-skillstheir own version, first seen Aug 4, 2026
Other versions5 projects use a version of this.
Word for word · 1
- savagemanage/claude-skills★ 0100% same
Edited · 0
None found.
Wrote their own version · 4
- sammcj/agentic-coding★ 169same name
- milad-ahmd/agent-skills★ 5same name
- dot-skill/skillerr-browser★ 2same name
- mozdowski/claude-skills★ 0same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository6 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- exec-one-pagerSkill
- gov-one-pagerSkill
- spoonSkill
- voiceSkill
- template-skillSkill
The file
We split this skill into the rules it gives an agent
4 rules. 0 are common, 0 are distinctive, and 4 are very specific to this project.
0
Common
Most of the 4 edited versions we read keep these.
0
Distinctive
This author's own choices. Worth a look.
4
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 20
Set
PLAYWRIGHT_BROWSERS_PATH: if your environment keeps browsers in a shared, pre-provisioned directory (for example export … - Very specific: line 26
Run these steps from the skill directory (the one containing scripts/), or point --config at any config path.
- Very specific: line 128
Then actually look at the evidence: READ review-report.md, open video/demo.mp4, and open the failure screenshot(s) for any failing step.
- Very specific: line 136
Always surface video/demo.mp4 (the H.264 transcode of the real recording) as the deliverable, since mp4 is broadly playable and embeddable.
“Common” is measured: kept by at least 6 in 10 of the 4 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
demo-recorder
demo-recorder turns "does this product actually work when you click through it?" into an automated, reviewable loop that also produces a watchable demo video. It launches the app, drives it in a headless Chromium browser, records a real video of the run, and captures per-step screenshots, accessibility snapshots, and a structured action log. You then review those artifacts to judge PASS/FAIL, find the failing step, fix the product code, and re-run until it passes.
To make the recording easy for a human to follow it (1) inserts a configurable pause between steps, (2) runs Playwright in slow motion so each action is visibly slower, and (3) injects a visible mouse cursor that glides to each control before clicking (headless Chromium has no OS cursor).
Playwright records the session natively as a genuine WebM screen recording (its context video recording), not a slideshow of screenshots. After the run, demo-recorder transcodes that WebM to an H.264 .mp4 with ffmpeg. The .mp4 is the primary deliverable video to show and report to the user; the WebM is kept as the source recording.
Prerequisites
- Node.js 22+.
- Install the skill's dependencies once from the skill directory:
npm install(this installsplaywrightandffmpeg-static). - Install a Chromium browser for Playwright once:
npx playwright install chromium. - Set
PLAYWRIGHT_BROWSERS_PATHif your environment keeps browsers in a shared, pre-provisioned directory (for exampleexport PLAYWRIGHT_BROWSERS_PATH=/opt/playwright). Point it at the directory that already contains the matching Chromium build so Playwright reuses it instead of re-downloading. - Headless only (no display server): the engine forces
headless: truewith--no-sandbox. The visible-cursor overlay is how the pointer is made visible under headless. - ffmpeg is required to produce the
.mp4. The skill depends on theffmpeg-staticnpm package (installed bynpm install), which bundles an H.264-capable ffmpeg, so no system ffmpeg is needed. To use a different binary, setDEMO_RECORDER_FFMPEGto its absolute path; the resolver then falls back toffmpeg-static, then Playwright's bundled ffmpeg, thenffmpegonPATH. If no ffmpeg is found (or the transcode fails), the run is not aborted: the real WebM is kept and the report notes that mp4 was skipped.
The loop
Run these steps from the skill directory (the one containing scripts/), or point --config at any config path.
1. Write (or point to) a demo.config.json
The config describes how to launch the target, where it lives, and the click-through scenario.
{
"name": "calculator",
"launch": {
"command": "node server.mjs 4600",
"cwd": ".",
"readyLog": "listening on",
"timeoutMs": 15000
},
"baseUrl": "http://127.0.0.1:4600",
"viewport": { "width": 1280, "height": 720 },
"stepDelayMs": 800,
"slowMo": 300,
"showCursor": true,
"scenario": [
{ "action": "goto", "url": "/" },
{ "action": "click", "selector": "#key-7" },
{ "action": "click", "selector": "#op-add" },
{ "action": "click", "selector": "#key-8" },
{ "action": "click", "selector": "#key-equals" },
{ "action": "expectText", "selector": "#display", "text": "15" }
]
}Top-level fields
name(required): human name; used to slug the run's artifact directory.baseUrl(required): the URL the app is served at (e.g.http://127.0.0.1:4600). ScenariogotoURLs can be relative to this.launch(optional): how to start the app. Omit it if the app is already running / external.command(required): shell command to start the app (e.g.node server.mjs 4600).cwd(optional): working directory, resolved relative to the config file.- readiness signal (one required):
readyUrl(any HTTP response means up),readyPort(TCP connect succeeds), orreadyLog(substring appears in stdout/stderr). timeoutMs(optional, default 30000): how long to wait for readiness.
viewport(optional, default{ "width": 1280, "height": 720 }): browser + video size.stepDelayMs(optional, default700): milliseconds to pause between scenario steps so the video is not too fast to follow. Overridden by--slow <ms>.slowMo(optional, default250): PlaywrightslowMo, milliseconds added inside each browser action (clicks, typing) so individual actions are visibly slower. Overridden by--slow-mo <ms>.showCursor(optional, defaulttrue): inject a synthetic mouse cursor overlay that glides to each control before clicking and shows a click ripple. Setfalse(or pass--no-cursor) to disable.review(optional): declare incidental console/network noise that should NOT fail the run.ignoreConsole(optional, array of case-insensitive regex strings): matched against each console error's text.ignoreNetwork(optional, array of case-insensitive regex strings): matched against"<STATUS> <METHOD> <URL>"for each failed (>= 400) response (e.g."404 GET .*/favicon\\.ico").- Omit the block (or use empty arrays) to keep the strict "any error fails" behavior.
scenario(required, non-empty array): the steps to run in order.
launch.command runs through a shell, so a shared demo.config.json is executable code; treat it as trusted the same way you would a checked-in npm script, and only run configs you trust.
Scenario actions
goto—{ "url": "/path" }: navigate (relative tobaseUrl).click—{ "selector": "#id" }or{ "text": "Save" }or{ "role": "button", "name": "Save" }. When the cursor is on, it glides to the target first.fill—{ "selector": "#id", "value": "text" }: set an input's value.type—{ "selector": "#id", "value": "text" }: type key-by-key.press—{ "key": "Enter" }: press a keyboard key.waitFor— one of{ "selector" },{ "text" },{ "url" }, or{ "ms": 500 }.expectText—{ "text": "15", "selector": "#display" }(selector optional; defaults to body). Assertion.expectVisible—{ "selector": "#el" }: assertion that the element is visible.screenshot—{ "label": "name" }: capture an extra labeled screenshot.snapshot—{ "label": "name" }: capture an accessibility snapshot.
expect* failures are recorded as failed steps but the run continues so the video captures the failure state.
2. Record the run
node scripts/demo-run.mjs --config examples/calculator/demo.config.jsonOptional flags:
--base-url <url>— overridebaseUrl.--slow <ms>(alias--step-delay <ms>) — pause between steps; overridesstepDelayMs.--slow-mo <ms>(alias--slowmo <ms>) — Playwright slowMo; overridesslowMo.--no-cursor/--cursor— turn the visible cursor off / on; overridesshowCursor.--headedis accepted but ignored (always headless).
Artifacts are written to <ARTIFACTS_ROOT>/<runId>/, where the artifacts root defaults to <cwd>/.demo-recorder/artifacts and is overridable via the DEMO_RECORDER_ARTIFACTS_ROOT env var (set it if you want runs to land somewhere specific; review.mjs honors the same variable):
video/demo.mp4— the deliverable H.264 video (transcoded from the WebM). This is what you show the user.video/demo.webm— the real recorded video Playwright captured; retained as the source recording (and used if the mp4 transcode was skipped).screenshots/— one PNG per step (failure screenshots are suffixed-FAIL).snapshots/— accessibility snapshots forsnapshotsteps.action-log.json— structured log:meta(including thewatchabilitysettings and thevideotranscode result),summary,steps[], plus captured console errors and failed network responses (HTTP >= 400) keyed to the step that was running.
demo-run.mjs exits non-zero if any step failed or errored.
3. Review
node scripts/review.mjs # reviews the latest run
node scripts/review.mjs --run <runId | run dir>This writes review-report.md into the run directory with an overall verdict (PASS only if every scenario step passed and there were no console/network errors that were not explicitly ignored), a per-step table, captured console/network errors keyed to the step they occurred in, the absolute path to the deliverable video/demo.mp4 (with video/demo.webm as the source), the list of key/failure screenshots, and, for each failed step, a "likely cause / where to look" hint.
review.mjs exits non-zero on FAIL.
Then actually look at the evidence: READ review-report.md, open video/demo.mp4, and open the failure screenshot(s) for any failing step.
4. Fix and repeat
Use the failure analysis to fix the product code (the app under test), not the scenario, unless the scenario itself is wrong. Then re-run steps 2 and 3 until the review verdict is PASS. When it passes, report the video/demo.mp4 to the user as the proof the flow works.
Reporting to the user
Always surface video/demo.mp4 (the H.264 transcode of the real recording) as the deliverable, since mp4 is broadly playable and embeddable. video/demo.webm is the source recording and a fine fallback if the mp4 transcode was skipped (no ffmpeg). Screenshots and review-report.md are supporting evidence.
Installing into a tool
The same SKILL.md works in all three tools; only the discovery directory differs. Use the installer:
node scripts/install-skill.mjs # symlink into ./.kiro, ./.claude, ./.opencode
node scripts/install-skill.mjs --copy # copy instead of symlink
node scripts/install-skill.mjs --global # into ~/.kiro, ~/.claude, ~/.config/opencode
node scripts/install-skill.mjs --tools kiro,claude # a subset
node scripts/install-skill.mjs --dry-run # print planned actions onlyDiscovery locations: Kiro .kiro/skills/demo-recorder, Claude Code .claude/skills/demo-recorder, opencode .opencode/skills/demo-recorder (opencode also reads .claude/skills and .agents/skills).
Install dependencies in the canonical dir first. The engine needs playwright (and ffmpeg-static) in the canonical dir's node_modules. A symlink install shares it and a --copy install omits it, so the installed skill only runs after npm install has been run once in the canonical skills/demo-recorder dir. The installer prints this reminder.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

