demo
Skill8 starsChanged 3 months agoMITView on GitHub
Record a product demo video by reading the product's own code and the craft of demo-making, not by guessing at either. Use when the user asks to record a demo, make a demo video, film the product, show the product working, or produce a launch clip. Also use when a demo already recorded is wrong, boring, or missed the point of the product. Needs the repo and a running instance.
26 other projects use a version of this.
Adopted by
Most recently taken up by
- serhiileniv/skillstheir own version, first seen Nov 8, 2026
- serhiileniv/ccstheir own version, first seen Nov 8, 2026
- NahumLitvin/prismantistheir own version, first seen Nov 8, 2026
- zedarvates/frugal-skillstheir own version, first seen Nov 8, 2026
- mehboobali98/rmine-skillstheir own version, first seen Nov 1, 2026
- ozerova152-lab/youtube-producertheir own version, first seen Nov 1, 2026
Used with
Projects with it also use spec, implement and 3 more.
Other files people use alongside this one.
Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
SentrySkillspec
Produce a verified spec — problem, desired outcome, and acceptance criteria — before building. Use when given a GitHub/Linear issue link, when starting from a fuzzy in-conversation idea, or asked to "figure out what to do" / "scope this" / "what should I build" — whenever the *what* isn't yet pinned down. Grills the ambiguities, checks the premise against the code, and produces acceptance criteria you sign off on — then hands to design-first.
Also in 4 projects that use this
Hugging FaceSkillimplement
Make tests pass. Invoke after /write-tests produces failing tests.
Also in 4 projects that use this
SentrySkillreview
Fixture review skill.
Also in 4 projects that use this
AWSSkillship
Finalize dev work on an issue branch — update docs, push, and open a PR.
Also in 3 projects that use this
NVIDIASkillresearch
Before designing a feature, research how comparable libraries solve the problem, check best practices, known pitfalls, and upstream changes. Use when starting a new feature, investigating an unfamiliar area, or the user asks to research something.
Also in 3 projects that use this
Other versions26 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 26
- NahumLitvin/prismantis★ 324same name
- iamrohithrnair/merman★ 42same name
- eliasstravik/skills★ 22same name
- yarikleto/claude-teacher-plugin★ 9same name
- malinskibeniamin/skills★ 4same name
- nivoset/skills★ 4same name
- pcode-xyz/simple-skills★ 4same name
- developzone5/sanad★ 3same name
- raphaelDkhn/worldbuilder★ 3same name
- fxmartin/claude-code-config★ 2same name
16 more not listed
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 repository46 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- hud/CLAUDE.mdCLAUDE.md
- agent-setupSkill
- asaSkill
- audio-briefSkill
- call-coachSkill
- clone-siteSkill
- courseworkSkill
- creative-videoSkill
- debuggingSkill
- deep-researchSkill
- graph-engineeringSkill
- gtm-engineeringSkill
- hudSkill
- interfaceSkill
- jev-browseSkill
- kit-builderSkill
- life-contextSkill
- life-opsSkill
- list-auditSkill
- mac-actSkill
- mac-appsSkill
- mac-briefSkill
- mac-controlSkill
- mac-debugSkill
- mac-followupsSkill
- mac-permissionsSkill
- mac-runtimeSkill
- mac-seeSkill
- peopleSkill
- prospect-briefSkill
- repo-healthSkill
- reviewing-changesSkill
- second-brainSkill
- setupSkill
- shippingSkill
- site-specSkill
- skill-forgeSkill
- skill-trainingSkill
- stack-rulesSkill
- study-guideSkill
- study-systemSkill
- textsSkill
- what-can-this-doSkill
- your-dataSkill
The file
We split this skill into the rules it gives an agent
8 rules. 0 are common, 7 are distinctive, and 1 is very specific to this project.
0
Common
Most of the 24 edited versions we read keep these.
7
Distinctive
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 15
Run against a real site it produced this:
- Distinctive: line 22
No CTA found, so it scrolled.
- Distinctive: line 116
What is the single moment that shows it?: Not the homepage. The moment the thing pays off: the search returning cooks, the file becoming a …
- Distinctive: line 119
What is the shortest path from load to that moment?: Every beat that is not on that path is cut.
- Very specific: line 180
After the export, pull four beat frames and look again.
- Distinctive: line 196
A camera cut must be a content cut: Never cut mid-idle.
- Distinctive: line 197
Cut on the action, resume on the loaded page: No spinners, no blur-up.
- Distinctive: line 212
When the thing to show is a web page that already plays on its own (a WebGL scene, a scripted demo, a scroll-synced story), a screen …
“Common” is measured: kept by at least 6 in 10 of the 24 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
Record a demo of the product, from its own source
The failure this exists to fix
Cap's bundled cap-demo skill scouts the page at runtime and scores every
anchor and button to pick a "CTA": +3 if the text matches
/features|pricing|docs/, +2 for a background colour, -5 for "sign up". Nothing in
that scoring has any knowledge of the product it is pointed at.
Run against a real site it produced this:
STORY=scroll cta=none accent=null
cursor track synthesized: 182 moves, 0 clicksNo CTA found, so it scrolled. Zero clicks in a product demo. Nothing was demonstrated, because nothing in that pipeline knows what the product does.
You are not in that position. You have the repo. Read it, decide what the demo should show, and write the storyboard yourself. That is the whole skill.
Before any of that: you do not know how to make a demo video
You know how to drive a UI and run an encoder. Those are the mechanics. A demo video is a craft with its own rules, and the first version of this skill had none of them, so the first demo it produced was four taps on a tab bar. That is a screen recording. Caleb's response was "there's more to UX than just the nav bar lol", and he was right.
Research the craft before producing the artifact. For a demo that means watching people who make them for a living, not reasoning from first principles about what a demo probably is. The rules below came from doing that once, and they are here so the research does not have to be repeated. If the work drifts outside them, go watch two more and add what you learn.
The rules, from practitioners who have made hundreds
One to three features. Never more. Stated as the biggest mistake people make: "include way too many features... otherwise people will just switch off." This is the rule most likely to be overridden by the person asking, who will say "show everything". Showing everything is the failure mode with a name.
A storyline, not a tour. The demos that work have "a clear narrative... not jumping around between different aspects of the product." Ask what one job the viewer watches somebody complete. Most products already have this written down in their own onboarding copy; Silo's how-it-works screen says "Three taps to dinner", which is the storyboard, pre-written by the founder.
Cut the login. "I often see people record their login process, but it's not really something that people find that interesting."
Show it with data in it. A populated product is the whole advantage a demo has over a free trial. Empty states are not a feature.
Do not over-zoom. "It can actually be a little bit dizzying... most people really want to see the context about what you're interacting with." Zoom for one specific thing, then pull back out.
Describe the benefit, not the action. Not "now we click the filter": "you see only what is still open near you."
Increase complexity over time. Open on the simplest possible beat and build.
End on a CTA. Somebody who reached the end is the most engaged viewer the product will get that week.
When the brief and the craft disagree
"Show me all the screens" is a reasonable thing to ask for and a bad demo. Say so in one line, make the narrative version, and offer the full screen tour as a separate artifact if it is still wanted. Do not silently deliver either one.
What to read, in order of how much it is worth
1. The e2e specs, which are where you should always start. e2e/, tests/, cypress/,
playwright/, *.spec.ts, *.cy.ts. These are the single best source in any
repo and almost nobody thinks to use them: a passing e2e test is a recorded
script of the exact journey the team already decided is the product, written
with the real selectors, in the real order, with the real fixture data. A demo
plan is an e2e spec with dwell times.
rg -l "test\(|it\(|describe\(" --glob "**/*.{spec,cy,e2e}.{ts,tsx,js}" .
rg "getByTestId|data-testid|getByRole" -N --glob "**/*.spec.ts" . | head -402. data-testid attributes. Stable by contract, which is exactly what a
storyboard needs. A class name is a refactor away from breaking the demo.
rg -o 'data-testid="[^"]+"' -N . | sort -u3. The routes. app/**/page.tsx, pages/, the router config. They are the
product's own table of contents, and the order they were built in usually is
the order they should be shown in.
4. The landing copy and the README. What the product claims to do is what the demo has to deliver. If the hero says "find a home cook near you" and the demo never finds a cook, the demo is wrong no matter how good it looks.
5. Recent commits. git log --oneline -30. For a launch clip, the feature
that just shipped is usually the point.
Then decide the story, out loud, before writing any JSON
Answer these three in one line each. If you cannot, read more:
- What does this product do for someone? One sentence, their words.
- What is the single moment that shows it? Not the homepage. The moment the thing pays off: the search returning cooks, the file becoming a chart, the message arriving.
- What is the shortest path from load to that moment? Every beat that is not on that path is cut. You have 12 seconds.
Write the plan
{
"url": "http://localhost:3000",
"beats": [
{ "do": "aim", "selector": "h1", "label": "hero" },
{ "do": "dwell", "ms": 1200, "label": "settle" },
{
"do": "type",
"selector": "[data-testid=search]",
"text": "tacos",
"label": "search"
},
{
"do": "click",
"selector": "[data-testid=search-submit]",
"label": "run_search"
},
{ "do": "scroll", "selector": "[data-testid=results]", "label": "results" },
{ "do": "idle", "ms": 1800, "label": "land" }
]
}Beats: aim (mark a landmark for the 3D shot, moves nothing), dwell, move,
click, type, scroll (by selector or by pixels), idle.
Common keys: label names the beat in the timeline, ms is the glide or dwell
duration, settle is the pause after, text on a click disambiguates by
visible text, waitFor: false on a click that does not navigate.
A missing selector is a hard error, on purpose. A demo that silently skips its own climax is worse than one that stops and tells you the selector moved.
Run it
demo-shoot plan.json <outDir> <slug>
python3 ~/.claude/skills/cap-demo/lib/treat.py <outDir> <slug> [--bg-gradient FROM,TO]demo-shoot.mjs writes <slug>.cap and <slug>.timeline.json in Cap's own
format, so Cap's treat.py does the 3D camera, gradient, cursor and music
unchanged. That stage is Cap's work and is good; only the scouting was the
problem.
Frame-QA between the stages. Do not skip this.
ffmpeg -y -ss <t> -i <outDir>/<slug>.cap/content/segments/segment-0/display.mp4 \
-frames:v 1 /tmp/raw-<t>.pngThen look at the frames. Check the right content is captured, no cookie banner leaked, the click landed somewhere that proves the product works, and the tail is clean. Reshoot before spending an export.
After the export, pull four beat frames and look again. Check the fps first,
because cap record --detach engages late and the true rate is often ~58, not 60. Passing --quality hd on a 58fps capture buys judder:
ffprobe -v error -select_streams v:0 -show_entries stream=nb_frames,duration \
-of csv=p=0 <outDir>/<slug>.cap/content/segments/segment-0/display.mp4Set the brand gradient by eye. getComputedStyle lies on pastel and
gradient-heavy sites: one that reads white with lavender accents samples as
black. Look at the raw frame and pass --bg-gradient.
The editorial rules, which are Cap's and are right
- 12 seconds, hard. Past that the tail is shaved evenly and the ending is
lost.
demo-shoot.mjsrefuses a plan that budgets over it. - A camera cut must be a content cut. Never cut mid-idle.
- Cut on the action, resume on the loaded page. No spinners, no blur-up.
- One motion system. The 3D shot carries the emphasis. Never stack 2D zoom segments on top.
- Aim at content, not the container. Point at the hero, the clicked thing, the destination header.
Requirements
macOS on Apple Silicon. cap on PATH with Screen Recording granted, node,
python3, ffmpeg. npm install once in ~/.claude/skills/cap-demo for
playwright-core. The product must be running and reachable at the plan's
url, which is usually a local dev server you start first.
Web scenes that animate themselves: render, do not record
When the thing to show is a web page that already plays on its own (a WebGL
scene, a scripted demo, a scroll-synced story), a screen recording is the wrong
tool: it drops frames whenever the laptop is busy and captures real time.
page-render runs the page on a fake clock and screenshots it one subframe at
a time, so a 60fps render of a heavy shader comes out at 60fps anyway, with
real motion blur (4 subframes per frame, blended by ffmpeg).
# one frame per second, tiled: check this before every full render
page-render http://127.0.0.1:4173/ sheet.png --preview 1 --duration 12 \
--setup "document.querySelector('#scene').scrollIntoView()"
# then the clip, cropped to one element, at 2x
page-render http://127.0.0.1:4173/ clip.mp4 --duration 12 --scale 2 --clip "#stage"It holds timers, performance.now, requestAnimationFrame and every CSS
animation on the same virtual clock; tests/page_render.sh proves two renders
match byte for byte. Cost: about 25 s of wall time per second of 2x video.
The method is @twoclipping's code-only motion template (in the brain at
research/motion-template); the story rules above still decide what to show.
Native apps: iOS Simulator, not a browser
demo-shoot.mjs drives Playwright, so it only works on something a browser can
open. An Expo or React Native app is not that. Check app.json first: Silo lists
platforms: ["ios","android"], so expo start --web refuses outright.
The path that works, learned by doing it badly first:
Boot a simulator that already has the app. A native build is minutes and can fail. Look before building:
find ~/Library/Developer/CoreSimulator/Devices -name "*.app" -path "*Bundle*" | grep -i <app>
xcrun simctl boot <udid> && open -a Simulator
xcrun simctl launch <udid> <bundle.id>Deep links are a trap. xcrun simctl openurl booted myapp://feed raises an
"Open in App?" system dialog every single time, so it cannot be used to jump
between screens in a recording. Navigate by tapping.
Wheel scroll does nothing. peekaboo scroll sends wheel events and a
simulator wants a touch drag. Use a swipe, and note the flags are
--from-coords / --to-coords, not --from:
peekaboo swipe --from-coords 233,720 --to-coords 233,400 --duration 420 --steps 22 --app SimulatorClicking by element label is unreliable here. peekaboo see reads the whole
accessibility tree inside the simulator, which is genuinely useful for
discovering labels, but clicking --on elem_N landed one element low every
time. Calibrate coordinates instead, from the window bounds in
peekaboo list windows --app Simulator:
screen_x = win.x + device_pt_x * (win.width / device_pt_width)VERIFY THE WINDOW EXISTS BEFORE EVERY COORDINATE CLICK. This is the one that
did damage. Mid-session the simulator shut down, its window vanished, and the
next clicks at y=885 landed on the Dock and launched applications on the
user's real machine. A coordinate click is a click on the desktop when the thing
you meant to hit is gone.
cap record windows --json | grep -q '"id": *<winid>' || { echo "window gone"; exit 1; }Never send keystrokes with System Events. osascript -e 'tell application
"System Events" to keystroke "..."' goes to the frontmost macOS app, not the
device, and it shut the simulator down mid-run. Text entry into a React
Native field is the one unsolved piece: taps and swipes work, typing does not.
xcrun simctl pbcopy fails with "Unable to connect to device pasteboard".
idb-companion is installed and is the next thing to try (idb ui text).
Record and export without treat.py, since its 12s ceiling and its editorial cut are built for the browser storyboard:
cap record start --detach --window <winid> --fps 60 --path out.cap
cap record stop --path out.cap
cap export out.cap --output out.mp4
ffmpeg -y -i out.mp4 -vf "crop=500:1008:0:72" -c:v libx264 -crf 18 final.mp4That crop removes the Simulator's macOS title bar and keeps the phone bezel, which reads as a product shot rather than a screen grab.
Demoing Chewbacca itself: driving another Claude tab
A demo of this kit is usually a demo of an agent doing something, which means
the footage needs a second Claude visibly working. claude-tab drives one.
claude-tab new open a fresh tab, verified
claude-tab ask "<prompt>" --timeout 300 send, then block until it finishes
claude-tab status idle | busy | absentask is the piece that makes a back-and-forth possible. Before it existed every
attempt used a fixed sleep, and the recording made that way stopped while the
other Claude was still thinking, so the clip had no payoff in it. A real turn on
this machine took 29.4s; guessing that number is how you lose the ending.
How it knows. The message input's placeholder is the run state: it reads
"Queue another message…" while a turn is in flight and "⌘ Esc to focus or unfocus
Claude" the moment it finishes. The field is exposed to the accessibility tree
with description: "Message input", so it is found by description and clicked by
element id rather than by coordinate.
Opening a tab is a keybinding, not a click. It used to be a derived click at
a measured offset from the window's top-right corner. That broke the first time
the VS Code toolbar gained an icon: every button shifted left, the click landed
on a neighbour, and new reported "the tab did not change". claude-tab new
now presses ctrl+alt+cmd+n, bound to claude-vscode.editor.open (the command
the icon itself runs), and writes that binding into VS Code's
keybindings.json if it is missing. It still verifies a tab appeared instead of
trusting it.
Two constraints worth knowing before planning a shot:
- Only the frontmost tab's state is published.
statusreports whichever Claude tab is on top, never one hidden behind it. Drive one at a time. - FILM A SEPARATE WINDOW, NOT A SIBLING TAB. Caleb's rule, 2026-09-16:
"When making a video interacting with chewbacca, ALWAYS operate with it in a
different tab." A sibling tab is not enough on its own, because VS Code raises
whichever tab is producing output: every tool call the recording session
makes pulls focus off the tab being filmed and onto itself. Open the demo in
its own window with
ctrl+alt+cmd+w(claude-vscode.window.open) and record that window id. Then the camera and the performance cannot steal focus from each other. window()picks the largest window, which is the wrong one once a second window exists. With a demo window open, pass the id explicitly rather than letting it guess.sendrefuses a tab that is mid-turn. The session running the tool is itself a Claude tab in the same window and is busy for as long as it runs, so without that guard asendissued beforenewsucceeded types the prompt into its own input box.--forcequeues deliberately.
Record the VS Code window the same way as any other: cap record start --detach
--window <id>, and resolve the id with claude-tab window, which picks the
largest window because VS Code also publishes 1512x37 menu-bar strips.
When there is no repo
Fall back to cap-demo <url>, Cap's deterministic pipeline, and say plainly
that it is the ~70% version. Do not pretend a scouted demo read the product.
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.

