Record + narrate web app demos in one config file.
A tiny Node CLI that drives Playwright through a sequence of shots, generates voice narration with local TTS (no cloud, no API keys), and muxes it into an MP4 ready to drop into Twitter.
Recording a polished demo for every project means screen-capture software, narration takes, an editor for timing, and re-doing it every time the UI changes. democast collapses that to a democast.config.js file:
shots: [
async (page) => { await page.click('.daily-focus-name'); await page.waitForTimeout(2400); },
async (page) => { await page.fill('#ask-input', 'investors I should reach out to'); ... },
// ...
],
narration: {
lines: [
{ at: 0.4, text: "Minty. Your network, unified." },
{ at: 2.5, text: "WhatsApp, Gmail, LinkedIn — one timeline." },
// ...
],
},Then democast all writes:
out/demo.webm— silent recordingout/demo.mp4— same, mp4-encodedout/demo-narrated.mp4— with the voice over
Re-record any time the UI changes; same script, same timing.
git clone https://github.com/<you>/democast.git
cd democast
npm install
npx playwright install chromium
npm link # gives you the `democast` command globallyFor narration (optional — democast record works without it):
pip install --user --break-system-packages piper-tts
mkdir -p ~/.democast/voices
curl -L -o ~/.democast/voices/amy.onnx \
https://huggingface.co/rhasspy/piper-voices/resolve/main/en/en_US/amy/medium/en_US-amy-medium.onnx
curl -L -o ~/.democast/voices/amy.onnx.json \
https://huggingface.co/rhasspy/piper-voices/resolve/main/en/en_US/amy/medium/en_US-amy-medium.onnx.json
export PIPER_VOICE=~/.democast/voices/amy.onnxffmpeg + ffprobe must also be on PATH for narration. Most package managers ship them together (brew install ffmpeg, apt install ffmpeg).
In any project that has a running web app:
democast init # scaffolds democast.config.js
# edit the config to match your app's selectors and views
democast all # records the demo + adds narrationOr call the steps separately:
democast record # just the silent recording
democast narrate # add voice (requires piper)| Field | Default | Description |
|---|---|---|
url |
required | Where your app is running. |
output |
./out |
Output directory. |
viewport |
1280×800@2x | Browser viewport for recording. 1280×800 is a good Twitter ratio. |
bootWait |
0 | Extra ms to wait after first navigation. |
shots[] |
required | Async functions taking a Playwright page. Each one is one beat of the demo. |
narration.voice |
$PIPER_VOICE |
Path to a piper voice .onnx file. |
narration.gap |
0.25 |
Minimum seconds between two narration lines. |
narration.volume |
0.85 |
Voice mix volume (0–1). |
narration.lines[] |
required | Each { at: 1.5, text: "..." }. at is the EARLIEST start; lines auto-shift back if they'd overlap. |
- The recorder is silent — Twitter autoplay-mutes anyway.
- Viewport stays in browser-pixels;
deviceScaleFactor: 2produces retina-quality output without ballooning the file size. - democast doesn't boot your app. Start it however you usually do (
npm run dev, docker, etc.) before runningdemocast. - Voice files live wherever you want. Multiple voices? Drop them in one folder and
PIPER_VOICE=path/to/other.onnx democast narrate.
AGPL-3.0-only. Same license as the Minty project this tool was extracted from. Build whatever you want with it; if you run a modified version on a public network service, share the source.