Appearance
Recording a walkthrough
From an installed server and skill, the request is ordinary English — "record a two-minute walkthrough of the projects page for someone who has never seen the site" — and the agent does the rest. This page covers the setup behind that, the method the skill follows, and the two cases that need more than a sentence: rendering from a storyboard, and recording a site that needs a login.
Install
The server is a Node process an MCP client starts on demand. Chromium is Playwright's, installed once; FFmpeg ships with the package.
bash
cd server
npm ci
npx playwright install chromium
npm run buildRegister the built entry point with an MCP client. In Claude Code that is a project's .mcp.json, or ~/.claude.json for every project:
json
{
"mcpServers": {
"videostroll": {
"command": "node",
"args": ["C:/path/to/evo.videostroll/server/dist/index.js"]
}
}
}Then install the skill, which is a single Markdown file:
powershell
New-Item -ItemType Directory -Force "$HOME\.claude\skills\videostroll" | Out-Null
Copy-Item skill\SKILL.md "$HOME\.claude\skills\videostroll\SKILL.md"bash
mkdir -p ~/.claude/skills/videostroll
cp skill/SKILL.md ~/.claude/skills/videostroll/SKILL.mdThe tools
| Tool | When | Records? |
|---|---|---|
videostroll_start | Once, to open the site | No |
videostroll_observe | As often as you like | No |
videostroll_step | Once per storyboard step | Yes |
videostroll_finish | Once, at the end | Assembles the video |
videostroll_abort | If the walkthrough is wrong | Discards it |
videostroll_render | Batch, from a storyboard file | The whole thing |
start, observe and step each return the page's accessibility snapshot, which is where selectors come from. Actions available to a step are goto, move, hover, click, type, press, scroll, highlight, wait and waitFor.
The method
The skill puts the agent through four beats, and the order is the point.
1. Reconnoitre. Open the site and read the snapshot before deciding a single step. Observing records nothing, so looking first costs only time. Never narrate a page that has not been read.
2. Storyboard. Four to ten steps, one idea each, all drafted before any of them is recorded. For each: what the viewer should be looking at, and the action on screen that demonstrates the sentence. If nothing on screen demonstrates the sentence, the sentence does not belong in a video. If the goal will not fit on one line, there is no walkthrough yet.
3. Record. One videostroll_step per storyboard step — the narration, and its actions. Narration is at most two sentences, present tense, presenter voice: "The projects page lists every product", not "I'll open the projects page". Spell for the ear, because the voice reads what is written: "evo dot e h s", not "evo.ehs".
4. Verify. Read the manifest back and check what was said against what was shown. A narration naming something the viewer cannot see is exactly the defect this catches, and it is invisible to anyone who only watches the render once.
Pacing is handled for you — the recorder holds each step until the speech finishes — but the step lengths still want a look. Under about 2.5 seconds a step reads as a cut and belongs merged into its neighbour; past about 15 seconds the viewer's attention wanders and it wants splitting.
Rendering from a storyboard
An interactive run emits the storyboard it just recorded, and that file re-renders to the same walkthrough from the command line:
bash
cd server
npm run render -- ../examples/storyboards/www-evomedia.json ./output/wwwThat is what makes a walkthrough maintainable: when one sentence is wrong or one page has moved, edit that step and render again instead of re-recording the whole tour. A step is small enough to write by hand:
json
{
"id": "projects",
"chapter": "Projects",
"narration": "The projects page lists every product in the fleet, each with a stage label.",
"actions": [
{ "type": "goto", "url": "https://evomedia.net/projects.html" },
{ "type": "move", "target": { "selector": "role=heading" } },
{ "type": "scroll", "deltaY": 500, "durationMs": 1200 }
]
}Steps carrying a chapter become the video's chapter list — give one to the first step and to each change of subject.
Sites behind a login
The recorder never types a password and a storyboard never holds one. You sign in yourself, once, and the session is reused:
bash
npm run login -- https://app.example.comA real browser window opens. Sign in however the site asks — password manager, second factor, SSO redirect — then press Enter in the terminal. The cookies and local storage are written to auth/<host>.storage-state.json, and a storyboard points at it:
json
{
"url": "https://app.example.com/dashboard",
"storageState": "auth/app.example.com.storage-state.json"
}videostroll_start takes the same path, so an agent can record behind a login having been given a file path and nothing else.
That file is a live session — treat it like a password. The helper only writes it where git already ignores it and refuses anywhere else; it prints hostnames and counts but never a cookie value; and it refuses to save a file that captured nothing, which is what a half-finished sign-in produces.
Sessions expire, and finding that out halfway through a render is expensive. Check first — it exits non-zero if anything has lapsed:
bash
npm run login -- --check auth/app.example.com.storage-state.json