home-modules/shared/skills/demo-recording/SKILL.md
Record a demo of a web application or terminal session. Uses Playwright for browser recordings and VHS for terminal recordings. Offers to attach the resulting GIF/video as a PR comment.
npx skillsauth add mccurdyc/nixos-config demo-recordingInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Record a demo of a running application or terminal session.
Determine the type of demo.
Ask if the local dev environment is already running (for browser demos).
http://localhost:3000).Ask what flow/steps to demonstrate. Get a clear description of the interactions to script (pages to visit, buttons to click, text to type, etc.).
Record the demo.
Install Playwright and Chromium to a temp directory:
npm install --prefix /tmp/pw playwright
npx --prefix /tmp/pw playwright install chromium
Create a script (e.g., /tmp/pw/demo-record.mjs) that performs the
described interactions with video recording enabled:
import { chromium } from '/tmp/pw/node_modules/playwright/index.mjs';
const url = process.argv[2] || 'http://localhost:3000';
const browser = await chromium.launch();
const context = await browser.newContext({
recordVideo: { dir: '/tmp/pw/', size: { width: 1600, height: 900 } },
viewport: { width: 1600, height: 900 }
});
const page = await context.newPage();
await page.goto(url, { waitUntil: 'networkidle' });
await page.waitForTimeout(3000);
// Scripted interactions here
// await page.click('button#start');
// await page.waitForTimeout(2000);
// await page.fill('input#search', 'demo query');
// ...
await context.close(); // saves the video
await browser.close();
Run with:
node /tmp/pw/demo-record.mjs "<URL>"
Tips:
page.waitForTimeout(2000–3000) pauses between actions so the
recording is easy to follow.waitUntil: 'networkidle' for every page.goto() call.Create a .tape file describing the session:
Output demo.gif
Set FontSize 14
Set Width 1200
Set Height 600
Type "command here"
Enter
Sleep 2s
Run with:
vhs demo.tape
If VHS is not available, fall back to asciinema + agg:
asciinema rec demo.cast
agg demo.cast demo.gif
Convert to GIF if needed (for browser recordings that output .webm):
ffmpeg -i /tmp/pw/*.webm -vf "fps=15,scale=1280:-1:flags=lanczos" -loop 0 demo.gif
If the GIF is too large (>10MB), reduce fps or scale:
ffmpeg -i /tmp/pw/*.webm -vf "fps=10,scale=800:-1:flags=lanczos" -loop 0 demo.gif
Show the result to the user using the read tool on the resulting GIF/video file so they can verify it looks correct.
Ask if the user wants the recording added as a comment on the current pull request.
gh pr view --json number -q .number
# Upload the GIF as a GitHub comment attachment (returns markdown image URL)
# GitHub renders attached images hosted on user-attachments CDN
gh pr comment <number> --body "## Demo" --edit-last 2>/dev/null || true
# Use gh api to upload the file as a comment attachment:
REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner)
ASSET_URL=$(curl -sS \
-H "Authorization: token $(gh auth token)" \
-H "Accept: application/json" \
-F "[email protected];type=image/gif" \
"https://uploads.github.com/repos/${REPO}/issues/${PR_NUMBER}/comments/assets" \
| jq -r '.[0].href // .[0].url')
# If the upload endpoint above fails, fall back to creating a gist:
# ASSET_URL=$(gh gist create demo.gif --public | tail -1)/raw/demo.gif
gh pr comment <number> --body "## Demo
"
git add, git commit, or git push for demo GIFs.
They bloat the repository and are not source code./tmp/pw/node_modules/playwright/index.mjs./tmp/pw to avoid polluting the project directory..webm, scripts) after the final GIF is produced,
unless the user says otherwise.pkgs.vhs or pkgs.asciinema).development
Goal-driven execution. Breaks a task into phases with verification, parallelizes via subagents, and iterates until the outcome is achieved. Triggers: 'go-do', 'goal-driven', 'achieve this', 'make it so'.
tools
Do work in an isolated git worktree instead of switching branches. Use when creating a branch and opening a PR so the user's working directory is never disturbed. Triggers: 'create a branch', 'open a PR', 'make a change on a new branch'.
development
Search the web, fetch web page content, or search GitHub issues/PRs/repos. Use when you need current information not available locally.
tools
Start an interactive questionnaire when there are more than 5 options or bullet points that need to be addressed. Uses the ask_user tool to walk through selections interactively instead of dumping a wall of text.