Skip to content

45ck/demo-machine

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

28 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

demo-machine

demo-machine banner

Demo as code — turn YAML specs into polished product demo videos.

License: MIT Node.js TypeScript Tests Playwright FFmpeg

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 StartSpec FormatCLI ReferenceContributing


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.

View the YAML spec that produced this video
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: 500

Demo Gallery (GIF Previews)

These are compressed GIF previews generated from real rendered MP4s. For the full acceptance matrix, see docs/demo-anything.md.

TaskFlow demo preview (GIF) FlowForm demo preview (GIF) AuthFlow OTP demo preview (GIF) OverlayKit demo preview (GIF) RouteLab SPA demo preview (GIF) ScrollForge demo preview (GIF) DashLite table demo preview (GIF) ControlRoom inputs demo preview (GIF) ChartLab tooltips demo preview (GIF) GridV virtualized table demo preview (GIF) SelectorGym demo preview (GIF) DragSort reorder demo preview (GIF) FileUploader preview demo (GIF) AsyncSkeleton dashboard demo (GIF) SeededAPI notes demo (GIF)

To regenerate the gallery assets (GIFs + 5 screenshots per demo): pnpm demo:gallery.

For the frame-by-frame review output, see docs/demo-gallery.md.

Why 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

  • Node.js >= 22
  • pnpm
  • FFmpeg on your PATH
  • Playwright browsers: pnpm exec playwright install chromium

Install

git clone https://github.com/45ck/demo-machine.git
cd demo-machine
pnpm install
pnpm build

Run the Example

node dist/cli.js run examples/todo-app.demo.yaml \
  --output ./output \
  --no-headless

This will:

  1. Start the included todo-app dev server
  2. Launch a browser with smooth cursor and natural typing
  3. Record the session via Playwright
  4. 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>

Example Suite

The repo includes multiple example apps and .demo.yaml specs under examples/.

# Validate all example specs
pnpm examples:validate

# Smoke-capture raw videos for all example specs (no narration, no post-processing)
pnpm examples:capture

# Filter to a subset (note the `--` for pnpm passthrough)
pnpm examples:capture -- --filter spa-router

capture and run write these artifacts into --output:

  • video.webm (raw recording)
  • events.json (event log)
  • metadata.json (capture timing info used for accurate timelines)
  • trace.zip (Playwright trace)

edit expects video.webm to be in the same directory as the events.json you pass. If metadata.json exists, it will be used automatically.

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"

navigate.url can be absolute (https://...) or relative (/). Relative URLs are resolved against runner.url.

Action Types

Action Required Fields Description
navigate url Go to a URL
click selector or target Click an element
check selector or target Check a checkbox/toggle
uncheck selector or target Uncheck a checkbox/toggle
type selector or target, text Type text character-by-character
select selector or target, option Select an option in a <select>
upload selector or target, file or files Upload files into an <input type="file">
hover selector or target Hover over an element
scroll Scroll the page or a container (selector or target, x, y optional)
wait timeout Pause for milliseconds
press key Press a keyboard key
back Go back in browser history
forward Go forward in browser history
assert selector or target Assert visibility or text content
screenshot Take a screenshot (name optional)
dragAndDrop from, to Drag from one target to another

Every action supports an optional narration field for TTS and most support delay to override the default post-action pause.

Targeting (Selector-Free)

For click, type, hover, scroll (container scroll), and assert, you can use a structured target instead of a raw CSS selector:

- action: click
  target:
    by: role
    role: button
    name: "Next"

Supported strategies:

  • css: { by: css, selector: ".my-class" }
  • testId: { by: testId, testId: "save-button" } (uses data-testid)
  • role: { by: role, role: "button", name: "Save", exact: true }
  • text: { by: text, text: "Settings", exact: true }
  • label: { by: label, text: "Email", exact: true }
  • placeholder: { by: placeholder, text: "Search", exact: true }
  • altText: { by: altText, text: "Company logo", exact: true }
  • title: { by: title, text: "Open menu", exact: true }

This makes specs more resilient across UI refactors (class name changes, DOM reshuffles) and aligns with accessibility.

Disambiguation (nth)

When a selector/target matches multiple elements, you can pick the Nth match (0-based):

- action: click
  selector: "button"
  nth: 1

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 action

Redaction

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 apps

Development

pnpm build          # Compile TypeScript
pnpm test           # Run 172 tests
pnpm lint           # ESLint
pnpm format         # Prettier check
pnpm typecheck      # tsc --noEmit
pnpm validate       # Run everything

See CONTRIBUTING.md for setup instructions and development workflow.

License

MIT — use it however you want.

About

Demo as code — turn YAML specs into polished product demo videos with smooth cursor animation, natural typing, and professional overlays

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors