@toineapps/demoux
v0.4.1
Published
Turn HTML prototypes into high-quality demo videos
Downloads
943
Maintainers
Readme
@toineapps/demoux
Turn HTML prototypes into high-quality demo videos using AI agent workflows.
How it works
- You have raw HTML files — a UI prototype, a landing page, an app mockup
- An agent builds a demo-ready prototype (phone frame, screen transitions, dark stage)
- demoux stages the final presentation context (viewport, frame fit, screenshot, metadata)
- An agent writes a recording script against that staged context
- demoux records the script in a headless browser and encodes it to MP4
Setup
npm install @toineapps/demoux
npx @toineapps/demouxCreates:
prototypes/ ← demo-ready prototypes land here (agent output)
demos/ ← recorded MP4s land here
demoux.config.js ← configuration
.claude/skills/ ← Claude Code agent skills
AGENTS.md ← Codex agent entry point
AGENTS.demoux.md ← demoux Codex workflowsAgent commands
Three skills, one per step. Each one asks if you want to continue to the next.
/demoux-prototype
| Agent | Command |
|-------|---------|
| Claude Code | /demoux-prototype |
| Codex | "run demoux-prototype" |
Scans the project for raw HTML files, asks which one to use, asks mobile or desktop, then builds a polished self-contained prototype:
- Dark stage background
- Phone frame mockup (or fullscreen for desktop)
- Smooth CSS screen transitions
- All CDN assets (Tailwind, Inter, FontAwesome)
- Every button wired to
showScreen()
Saves to prototypes/<name>/prototype.html.
Ends by asking: "Should I stage the presentation context now?"
/demoux-script
| Agent | Command |
|-------|---------|
| Claude Code | /demoux-script |
| Codex | "run demoux-script" |
Reads the staged screenshot/metadata and the prototype HTML, maps all screens and interactive elements, plans a compelling demo flow, and writes a complete recording script:
- Scene comments for every section
- Natural cursor hover before every click
- Realistic typing delays
- Scroll reveals for content below the fold
- Movement authored against the final framed viewport
- Verified selectors — every
tap()checked against the HTML
Saves to prototypes/<name>/demo.script.js.
Ends by asking: "Ready to record? Which format — phone (9:16), desktop (16:9), or square (1:1)?"
demo stage
Use demo stage before writing the script whenever framing matters, especially for mobile portrait demos. It loads the prototype in the same viewport the final recording will use, applies the same presentation prep as the recorder, and writes:
recording/stage-<width>x<height>.pngrecording/stage-<width>x<height>.json
This gives the agent a concrete visual context to author movement and pacing against instead of guessing from raw HTML structure alone.
/demoux-record
| Agent | Command |
|-------|---------|
| Claude Code | /demoux-record |
| Codex | "run demoux-record" |
Asks for the output format, then runs the recorder non-interactively:
1. Phone portrait (9:16) — Reels, Stories, TikTok
2. Desktop landscape (16:9) — YouTube, presentations
3. Square (1:1) — Instagram, LinkedIn
4. Classic (4:3)Runs npx @toineapps/demoux demo create --prototype ... --ratio ... and handles any failures automatically (broken selectors, blank frames, unstyled content).
CLI
You can also stage or record directly without the agent:
npx @toineapps/demoux demo stage
npx @toineapps/demoux demo createOr with flags (skips interactive prompts — same flags the agent uses):
npx @toineapps/demoux demo stage --prototype prototypes/myapp/prototype.html --ratio 9:16
npx @toineapps/demoux demo create --prototype prototypes/myapp/prototype.html --ratio 9:16
npx @toineapps/demoux demo create --prototype prototypes/dashboard/prototype.html --ratio 16:9Flags:
| Flag | Values | Description |
|------|--------|-------------|
| --prototype | relative path | Path to the prototype HTML |
| --ratio | 9:16 16:9 1:1 4:3 | Output aspect ratio |
| --device | phone desktop desktop-wide square | Viewport preset (if no ratio) |
How the script drives the recording
The recommended flow is: stage first, script second, record last. demo stage captures the final framed presentation context, and the agent should write demo.script.js against that artifact rather than against raw prototype structure alone.
The agent writes demo.script.js — a plain JS file with interaction calls. When demo create runs, it loads this file and executes it inside a real headless Chromium. Every call drives the actual browser. Playwright records the screen the whole time. ffmpeg trims and encodes to MP4.
/** @type {import('@toineapps/demoux').SceneScript} */
module.exports = async (ctx) => {
const { tap, scroll, sleep, move, type, phoneCX, phoneCY, frame } = ctx;
// ── Scene 1: Dashboard ────────────────────────────────────────────────────
await move(phoneCX, frame.y + 100, 25); // drift cursor toward CTA
await sleep(800);
await tap('#screen-dashboard button:has-text("Betalingen")', { delayAfterMs: 1000 });
// ── Scene 2: Payments ─────────────────────────────────────────────────────
await sleep(2000);
await scroll('screen-payments', 300);
await sleep(1000);
await scroll('screen-payments', -300);
await tap('#screen-payments .back-button', { delayAfterMs: 1000 });
// ── Scene 3: Clean ending ─────────────────────────────────────────────────
await sleep(2000);
};Context API
| | Signature | Description |
|-|-----------|-------------|
| tap | (selector, { delayAfterMs? }) | Smooth cursor move + click |
| scroll | (screenId, deltaY) | Scroll inside .screen-main |
| move | (x, y, steps?) | Raw cursor movement |
| type | (text, delayMs?) | Keyboard input |
| sleep | (ms) | Pause |
| frame | BoundingBox | Phone frame position and size |
| phoneCX/CY | number | Center of phone frame |
| page | Playwright Page | Escape hatch |
Configuration
demoux.config.js:
module.exports = {
prototype: {
dirs: ['.', 'prototypes'], // where to scan for prototypes
output: 'prototypes',
},
demo: {
output: 'demos',
format: 'mp4',
viewport: { width: 1440, height: 940 },
startTrimMs: 800, // trim blank frames from start
renderWaitMs: 800, // wait after load before recording
},
cursor: {
enabled: true,
style: 'touch', // 'touch' (circle + ripple) | 'dot'
ripple: true,
movement: { steps: 30 },
timing: { beforeClickMs: 160, afterClickMs: 700, hoverMs: 300 },
},
}Requirements
- Node.js ≥ 18
- Playwright:
npm install playwright && npx playwright install chromium - ffmpeg:
winget install ffmpeg/brew install ffmpeg
Full flow
raw HTML files (anywhere in the project)
│
▼
/demoux-prototype scan → ask mobile/desktop → build prototype
│ "Should I write the script?"
▼
/demoux-script read HTML → plan scenes → write + verify script
│ "Ready to record? Which format?"
▼
/demoux-record ask format → run CLI with flags → handle failures
│
▼
demos/<name>-<timestamp>.mp4In the recommended workflow, run demo stage between /demoux-prototype and /demoux-script so the script is authored against the final framed recording context.
