demo-machine
v0.1.0
Published
Demo as code — automate polished product demo videos from YAML specs
Maintainers
Readme
demo-machine
Demo as code — turn YAML specs into polished product demo videos.
Write a simple YAML file describing what to click, type, and navigate. demo-machine launches your app, drives a real browser with human-like interactions, records everything, and renders a production-ready MP4.
Quick Start • Spec Format • CLI Reference • Contributing
Demo
A task manager app demo with voice narration — generated entirely from a YAML spec.
https://github.com/45ck/demo-machine/raw/master/examples/todo-app-demo.mp4
Notice the smooth cursor movement to each target, character-by-character typing, voice narration that leads into each action, and polished overlays with fades. This is not a screen recording — it's generated from code.
meta:
title: "TaskFlow - Task Manager Demo"
resolution:
width: 1920
height: 1080
runner:
command: "node examples/todo-app/serve.mjs"
url: "http://localhost:4567"
timeout: 10000
chapters:
- title: "Welcome to TaskFlow"
steps:
- action: navigate
url: "http://localhost:4567"
narration: "Welcome to TaskFlow, a simple and elegant task manager."
- action: wait
timeout: 1000
- title: "Getting Started"
steps:
- action: click
selector: "#get-started"
narration: "Let's click Get Started to begin managing our tasks."
- action: wait
timeout: 800
- title: "Adding Tasks"
steps:
- action: click
selector: "#task-input"
- action: type
selector: "#task-input"
text: "Design new landing page"
narration: "We'll type in our first task — designing a new landing page."
- action: click
selector: "#add-btn"
- action: wait
timeout: 500
- action: type
selector: "#task-input"
text: "Review pull requests"
narration: "Next, let's add a task to review pull requests."
- action: click
selector: "#add-btn"
- action: wait
timeout: 500
- action: type
selector: "#task-input"
text: "Write unit tests"
narration: "And one more — writing unit tests."
- action: click
selector: "#add-btn"
- action: wait
timeout: 500
- title: "Completing a Task"
steps:
- action: click
selector: ".task-checkbox"
narration: "To mark a task as done, just click the checkbox."
- action: wait
timeout: 800
- title: "Filtering Tasks"
steps:
- action: click
selector: "[data-filter='completed']"
narration: "We can filter to see only completed tasks."
- action: wait
timeout: 800
- action: click
selector: "[data-filter='all']"
narration: "Or switch back to view all tasks at once."
- action: wait
timeout: 500Why demo-machine?
Tools like Screen Studio and Arcade require manual recording sessions. Every time your UI changes, you re-record. demo-machine takes a different approach:
- Reproducible — same YAML, same video, every time
- Version-controlled — specs live in your repo, reviewable in PRs
- CI-friendly — generate demo videos in your pipeline on every release
- No manual work — no clicking through your app, no editing in a video tool
Features
| Feature | Description | | ------------------------- | --------------------------------------------------------------------------- | | Smooth cursor | Cubic-bezier eased movement with click pulse feedback | | Natural typing | Character-by-character keystroke simulation | | Configurable pacing | Global + per-step delays for clicks, typing, navigation | | Polished overlays | Intro/outro cards, chapter titles with fades and backgrounds | | Auto app lifecycle | Spawns your dev server, healthchecks, tears down after | | Redaction | Blur sensitive selectors, scan for secret patterns | | Narration | Local TTS via Kokoro, or cloud via OpenAI/ElevenLabs with VTT/SRT subtitles | | Dead-time compression | Long pauses automatically sped up | | Callout zoom | Click targets highlighted with zoom regions |
Quick Start
Prerequisites
Install
git clone https://github.com/45ck/demo-machine.git
cd demo-machine
pnpm install
pnpm buildRun the Example
node dist/cli.js run examples/todo-app.demo.yaml \
--output ./output \
--no-headlessThis will:
- Start the included todo-app dev server
- Launch a browser with smooth cursor and natural typing
- Record the session via Playwright
- Render a polished MP4 with overlays to
./output/output.mp4
Usage
CLI Commands
# Full pipeline: capture + edit + render
demo-machine run <spec.yaml>
# Validate a spec file without running
demo-machine validate <spec.yaml>
# Capture only (raw video, no post-processing)
demo-machine capture <spec.yaml>
# Re-render from an existing event log
demo-machine edit <events.json>Options
| Flag | Default | Description |
| ----------------------- | ---------- | ---------------------------------------------- |
| -o, --output <dir> | ./output | Output directory |
| --no-narration | — | Skip TTS narration |
| --no-edit | — | Raw capture only, skip rendering |
| --no-headless | — | Show the browser window |
| --renderer <name> | ffmpeg | Video renderer |
| --tts-provider <name> | kokoro | TTS: kokoro (local), openai, elevenlabs, piper |
| --verbose | — | Debug logging |
Spec Format
Minimal Spec
meta:
title: "My Demo"
runner:
url: "http://localhost:3000"
chapters:
- title: "Getting Started"
steps:
- action: navigate
url: "/"
- action: click
selector: "#btn"Action Types
| Action | Required Fields | Description |
| ------------ | ------------------ | ----------------------------------------------- |
| navigate | url | Go to a URL |
| click | selector | Click an element |
| type | selector, text | Type text character-by-character |
| hover | selector | Hover over an element |
| scroll | — | Scroll the page (selector, x, y optional) |
| wait | timeout | Pause for milliseconds |
| press | key | Press a keyboard key |
| assert | selector | Assert visibility or text content |
| screenshot | — | Take a screenshot (name optional) |
Every action supports an optional narration field for TTS and most support delay to override the default post-action pause.
Pacing
Control the feel of the demo globally. All fields are optional with sensible defaults:
pacing:
cursorDurationMs: 600 # cursor travel time
typeDelayMs: 50 # ms between keystrokes
postClickDelayMs: 500 # pause after clicks
postTypeDelayMs: 300 # pause after typing
postNavigateDelayMs: 1000 # pause after navigation
settleDelayMs: 200 # micro-pause after every actionRedaction
Blur sensitive content and scan for secret patterns:
redaction:
selectors:
- ".user-email"
- "[data-sensitive]"
secrets:
- "\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Z]{2,}\\b"Branding
meta:
branding:
logo: "./assets/logo.png"
colors:
primary: "#3B82F6"
background: "#000000"Architecture
┌──────────────┐
│ YAML Spec │
└──────┬───────┘
│
┌──────▼───────┐
│ Spec Loader │ Zod validation + defaults
└──────┬───────┘
│
┌──────▼───────┐
│ Runner │ Spawn dev server, healthcheck
└──────┬───────┘
│
┌──────▼───────┐
│ Playback │ Cursor animation, typing, pacing
│ Engine │ Playwright browser automation
└──────┬───────┘
│
┌──────▼───────┐
│ Capture │ Video recording + event log
└──────┬───────┘
│
┌──────▼───────┐
│ Timeline │ Intro/outro, chapters, callouts
│ Builder │ Dead-time compression
└──────┬───────┘
│
┌──────▼───────┐
│ FFmpeg │ Overlays, fades, final MP4
│ Renderer │
└──────┬───────┘
│
┌──────▼───────┐
│ Narration │ TTS + VTT/SRT subtitles
│ (optional) │
└──────────────┘Project Structure
src/
cli.ts # CLI entry point
index.ts # Public API exports
spec/ # YAML parsing + Zod validation
runner/ # Dev server lifecycle
playback/ # Cursor, typing, pacing engine
capture/ # Playwright video recording
editor/ # Timeline + ffmpeg renderer
narration/ # TTS providers + subtitles
redaction/ # Blur + secret scanning
utils/ # Logger, process helpers
tests/ # 172 tests across 13 suites
examples/ # Example specs + demo appsDevelopment
pnpm build # Compile TypeScript
pnpm test # Run 172 tests
pnpm lint # ESLint
pnpm format # Prettier check
pnpm typecheck # tsc --noEmit
pnpm validate # Run everythingSee CONTRIBUTING.md for setup instructions and development workflow.
License
MIT — use it however you want.
