Communitygithub.com

vishalvana-belwo/belwo-claude-skills

Records a narrated walkthrough video (MP4 with voice-over and captions) of a web app by driving a real browser. Use when someone asks for a demo video, product walkthrough, feature tour or screen recording to show a reviewer, client or team. Works on Windows and macOS.

What is belwo-claude-skills?

belwo-claude-skills is a Claude Code agent skill that records a narrated walkthrough video (MP4 with voice-over and captions) of a web app by driving a real browser. Use when someone asks for a demo video, product walkthrough, feature tour or screen recording to show a reviewer, client or team. Works on Windows and macOS.

Works with✓Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/vishalvana-belwo/belwo-claude-skills/tree/HEAD/plugins/demo-video/skills/make-demo-video

Ask in your favorite AI

Open a new chat with this agent skill pre-loaded.

Documentation

Make a narrated demo video

You write a scenes file: each scene is a piece of narration plus the clicks that happen while it plays. The scripts turn the narration into speech, drive the app in a headless Chromium at a fixed 1600×900 while capturing the screen, and build an MP4 with the voice-over and burned-in captions. A visible cursor, click ripples, highlight rings and title cards are added on top of the page.

All commands below use PY, which means python on Windows and python3 on macOS, and DV, which means "${CLAUDE_SKILL_DIR}/scripts/demo_video.py". Every command prints plain status lines (SCENE …, RECORDED …, CHECK OK, ERROR …); read them rather than guessing.

1. Set up (once per machine)

PY "${CLAUDE_SKILL_DIR}/scripts/setup_env.py"

It creates a private environment in ~/.claude-demo-video with Playwright, Chromium and edge-tts, then checks ffmpeg. It ends with READY, or with exactly what is missing. ffmpeg is a system tool: ask the user before installing it (winget install --id Gyan.FFmpeg -e on Windows, brew install ffmpeg on macOS). The scripts also look in the usual install folders (WinGet, Chocolatey, Scoop, Homebrew). If ffmpeg is somewhere else, set DEMO_VIDEO_FFMPEG_DIR to its folder for every command.

2. Agree the video with the user before writing anything

Ask, or confirm from context:

  • Who will watch it and why (a reviewer approving a feature, a client, new staff). That sets the tone and what to explain.
  • What to show, in what order. Propose a scene list with one line each and get a yes. Aim for 3 to 8 minutes.
  • Voice. The default is a natural English neural voice (edge-tts). Tell the user the narration text is sent to Microsoft's speech service to generate the audio. It should contain feature explanations only, never data. The alternative is the offline system voice (--offline): nothing leaves the machine, but it sounds robotic.
  • Data. Record only demo data: fictional people, @example.com emails, clearly fake projects. Never record real client or employee records, and never point the recorder at production.

3. Prepare the app

  • The app must be running and reachable from this machine, usually a local build.
  • If screens need data, write a seed script and a matching cleanup script for the demo data, and run the seed. Tag demo rows (for example IDs starting DEMO-) so cleanup can't touch anything else.
  • Make sure outgoing email and notifications are off, or go only to fake addresses, because the walkthrough clicks real buttons (submit, approve…).
  • Scenes that change data (approve, delete) can only be recorded once per seed. Re-seed before every retake.

4. Write the scenes file

Create it in the user's project, for example demo-videos/<name>.py, never inside the skill folder. Start from ${CLAUDE_SKILL_DIR}/reference/scenes-template.py. For a full real example, see ${CLAUDE_SKILL_DIR}/reference/zentrio-timesheet-example.py, which made a 6-minute approval video.

CONFIG = {'url': 'https://localhost:7101/MyTimesheet', 'ready': '#tsCards .tsw-card', 'sign_in': True}

async def week(r):
    await r.click('.tsw-row:has-text("Approval screen")')
    await r.spot('.tsw-panel', 3)

SCENES = [
    ('week', "Click a task row and the log panel opens right under it.", week),
]
  • CONFIG['url'] is the first page. ready is a selector that is only visible once that page is loaded and signed in. It's how the recorder knows sign-in worked.
  • Narration: one to three short spoken sentences per scene. Explain why something matters, not just what is on screen. Write numbers and symbols the way they should be said ("two point three zero"). Don't put data in narration.
  • Actions run while their narration plays. Keep them shorter than the narration; the recorder waits for the narration to finish before starting the next scene.

Scene helpers (r is the recorder; anything else is available as r.page, the Playwright page):

HelperDoes
await r.goto('/path', wait_for=sel)open a page (relative to CONFIG['url'])
await r.click(target, dx=.5, dy=.5)move the visible cursor there and click; dx/dy pick the point inside the element
await r.move_to(target)move the cursor without clicking
await r.type(target, 'text')click a field and type into it visibly
await r.select(target, value)choose a dropdown option
await r.press('ControlOrMeta+K')keyboard shortcut (Ctrl on Windows, Cmd on macOS)
await r.spot(target, seconds, pad)orange highlight ring
await r.card(kicker, title, lines, bullets) / await r.uncard()full-screen title card (intro, summary, outro)
await r.confirm_click(target, show=4)for buttons that call confirm(): shows a look-alike dialog, then accepts
await r.download(target)click a download and return the saved file's path
await r.show_file(path)show a local file, for example an HTML preview you made of a downloaded report
await r.scroll_top(), await r.scroll_x(selector, px)smooth scrolling
await r.clear_toasts(selector)remove notification toasts that cover buttons
await r.wait(seconds)pause

target is a CSS or Playwright selector string ('button:has-text("Approve")') or a Locator (r.page.locator('tr', has_text='Aarav').first).

5. Make the narration, record, and review

PY DV voice  demo-videos/<name>.py     # audio per scene; prints each scene's length
PY DV record demo-videos/<name>.py     # drives the app and captures frames
PY DV stills demo-videos/<name>.py     # two stills per scene in <name>-video/stills/

Sign-in. With 'sign_in': True, if the app isn't signed in, a browser window opens and the recorder prints SIGN_IN_NEEDED. Tell the user to sign in in that window. Never type credentials or ask for passwords. The session is saved in <name>-video/.profile so retakes don't need another sign-in.

Review every still before building, by reading the images:

  • right page, panel open, cursor where the narration says;
  • nothing covering the action (toasts, cookie banners, a profile menu);
  • the picture isn't stretched or cut off;
  • no real personal data on screen.

A SCENE_ERROR line or a wrong still means fixing that scene function and recording again (re-seed first if the scenes changed data). reference/lessons.md lists the failures seen so far and their fixes. Read it when something looks off.

6. Build, check and hand over

PY DV build demo-videos/<name>.py [--out "path/Name.mp4"]
PY DV check "path/Name.mp4" --size 1600x900

run does voice, record, stills, build and check in one go, once the scenes are known to work. Tell the user the video's path and length, and what it shows. Don't upload or share it anywhere unless they ask.

7. Clean up

  • PY DV clean demo-videos/<name>.py deletes the saved sign-in. Always do this when finished, because it holds a real session. --all also removes frames, stills and audio.
  • Run the demo-data cleanup script, and stop any app processes you started.

Platform notes

  • macOS: use python3. Captions are drawn by Chromium and laid over the video, so they look the same everywhere and don't need an ffmpeg built with libass (Homebrew's isn't). Recording is headless, so Retina screens don't change the video size.
  • --headed records in a visible window. Only use it when an app refuses headless browsers, and ask the user not to touch or resize the window while it records.
  • DEMO_VIDEO_HOME moves the private environment; DEMO_VIDEO_FFMPEG_DIR points at an ffmpeg folder.

Related Skills