plugins/narrated-demo/skills/narrated-demo/SKILL.md
Generate narrated demo videos with synchronized audio using ElevenLabs TTS and Playwright
npx skillsauth add roaming-panda-llc/claude-plugins narrated-demoInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Generate narrated demo videos with synchronized audio using ElevenLabs TTS and Playwright browser automation.
Use this skill when you need to:
Before using this skill, ensure:
export ELEVENLABS_API_KEY="your-key"# macOS
brew install ffmpeg
# Ubuntu/Debian
sudo apt install ffmpeg
The demos-not-memos library must be installed from GitHub:
# Clone the repository
git clone https://github.com/markng/demos-not-memos.git
cd demos-not-memos
# Install dependencies
npm install
# (Optional) Install Playwright browsers if not already installed
npx playwright install chromium
Node.js 18.0.0 or higher is required.
cd /path/to/demos-not-memos
# Create a demo script
cat > demos/my-demo.ts << 'EOF'
import { NarratedDemo } from '../src/demo-builder';
async function run() {
const demo = new NarratedDemo({
baseUrl: 'http://localhost:8000',
output: './output/my-demo.mp4'
});
await demo.start();
await demo.narrate("Welcome to the demo.");
await demo.page.click('#button');
await demo.narrate("The demo is complete.");
await demo.finish();
}
run().catch(console.error);
EOF
# Run the demo
npm run dev narrate --script demos/my-demo.ts
const demo = new NarratedDemo({
baseUrl: string; // Required: Base URL for the demo
output: string; // Required: Output file path (.mp4)
viewport?: { width, height }; // Default: 1280x720
voice?: string; // Default: 'Rachel'
model?: string; // Default: 'eleven_v3'
sounds?: boolean; // Default: false - enable UI sounds
});
await demo.start(); // Launch browser and start recording
demo.page // Playwright Page for browser actions
await demo.narrate(text); // Generate TTS and wait for completion
await demo.finish(); // Merge audio/video and save
demo.getElapsedTime(); // Milliseconds since start
When sounds: true, demo.page returns a SoundEnabledPage wrapper that records click and keystroke sounds automatically.
await demo.page.goto('/products');
await demo.page.click('#submit'); // Records click sound
await demo.page.type('#email', '[email protected]'); // Records keystrokes
await demo.page.fill('#password', 'secret'); // No keystroke sounds
await demo.page.locator('.card').first().click();
await demo.page.waitForSelector('.loaded');
The narrate() method returns a Narration object:
const narration = await demo.narrate("Welcome to our product.");
narration.getDuration(); // Duration in milliseconds
For "watch as I..." scenarios, use concurrent narration:
// Method 1: doWhileNarrating convenience method
await demo.doWhileNarrating(
"Watch as I fill in the form and submit",
async () => {
await demo.page.type('#email', '[email protected]');
await demo.page.click('#submit');
}
);
// Method 2: narrateAsync with whileDoing
const narration = await demo.narrateAsync("Watch as I click the button...");
await narration.whileDoing(async () => {
await demo.page.click('#button');
});
Use bracket-enclosed audio tags for expressive narration:
await demo.narrate("[excited] Check out this amazing feature!");
await demo.narrate("[whispers] Here's a secret tip.");
await demo.narrate("[curious] What happens if we click here? [laughs] Perfect!");
Supported Tags:
| Category | Tags |
|----------|------|
| Emotions | [excited], [curious], [sarcastic], [mischievously] |
| Voice | [whispers], [sighs], [laughs], [crying] |
| Sounds | [applause], [gunshot], [gulps] |
| Accents | [strong French accent], [strong British accent] |
Built-in voice mappings:
You can also use any ElevenLabs voice ID directly:
const demo = new NarratedDemo({
voice: 'pNInz6obpgDQGcFmaJgB', // Voice ID
// ...
});
See ElevenLabs Voice Library for more options.
import { NarratedDemo } from '../src/demo-builder';
async function run() {
const demo = new NarratedDemo({
baseUrl: 'https://your-product.com',
voice: 'Rachel',
model: 'eleven_v3',
sounds: true,
output: './output/product-tour.mp4'
});
await demo.start();
// Homepage
await demo.narrate("[excited] Welcome to our product!");
// Navigate to features
await demo.page.click('a[href="/features"]');
await demo.page.waitForLoadState('networkidle');
await demo.narrate("[curious] Let me show you what makes us special...");
// Scroll through features
await demo.page.locator('#key-features').scrollIntoViewIfNeeded();
await demo.narrate("These features save our customers hours every week.");
// Call to action
await demo.page.click('.cta-button');
await demo.narrate("[whispers] Getting started takes just a minute.");
// Form demo
await demo.page.type('#email', '[email protected]');
await demo.narrate("[excited] Thanks for watching!");
await demo.finish();
}
run().catch(console.error);
Ensure you call await demo.start() before accessing demo.page or calling demo.narrate().
Install ffmpeg and ensure it's in your PATH:
which ffmpeg # Should output a path
echo $ELEVENLABS_API_KEYThe DSL uses real-time timing. If sync issues occur:
See the demos-not-memos README for complete API reference and examples.
tools
Calculate Real Revenue for Profit First allocations. Determines if a business should use Real Revenue (vs Total Revenue) and calculates it.
development
Calculate quarterly profit distribution options including standard distribution, debt destruction, and vault building strategies.
tools
Plan the quarterly transition from Current Allocation Percentages (CAPs) to Target Allocation Percentages (TAPs) using the 3% rule.
tools
Calculate exact dollar amounts for Profit First allocations based on income and percentages. Use on allocation days (10th and 25th).