smithery/roaming-panda-llc

narrated-demo

Generate narrated demo videos with synchronized audio using ElevenLabs TTS and Playwright

Installation

$ npx skills add smithery/roaming-panda-llc --skill narrated-demo

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 6,828 B
  • docs SUMMARY.md 110 B

History

  1. First recorded snapshot · 0 installs

SKILL.md

narrated-demo

Generate narrated demo videos with synchronized audio using ElevenLabs TTS and Playwright browser automation.

When to Use

Use this skill when you need to:

  • Create product demo videos with voice narration
  • Record feature walkthroughs with synchronized audio
  • Generate marketing videos showing UI interactions
  • Create tutorial content with explanations

Requirements

Before using this skill, ensure:

  1. demos-not-memos is installed (see Installation below)
  2. ElevenLabs API key is set: export ELEVENLABSAPIKEY="your-key"
  3. ffmpeg and ffprobe are installed:

```bash # macOS brew install ffmpeg

# Ubuntu/Debian sudo apt install ffmpeg ```

Installation

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.

Quick Start

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

DSL API Reference

NarratedDemo

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

Page Interactions

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');

Narration

The narrate() method returns a Narration object:

const narration = await demo.narrate("Welcome to our product.");
narration.getDuration();  // Duration in milliseconds

Concurrent Narration with Actions

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');
});

Emotional Expression (Eleven v3 Audio Tags)

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]

Voice Options

Built-in voice mappings:

  • Rachel (default) - Clear, professional female voice
  • Domi - Professional female voice
  • Josh - Friendly male voice
  • Antoni - Professional male voice
  • Adam - Professional male voice

You can also use any ElevenLabs voice ID directly:

const demo = new NarratedDemo({
  voice: 'pNInz6obpgDQGcFmaJgB',  // Voice ID
  // ...
});

See ElevenLabs Voice Library for more options.

Full Example: Product Tour

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);

Troubleshooting

"Demo not started" error

Ensure you call await demo.start() before accessing demo.page or calling demo.narrate().

ffmpeg not found

Install ffmpeg and ensure it's in your PATH:

which ffmpeg  # Should output a path

ElevenLabs API errors

  • Verify your API key is set: echo $ELEVENLABSAPIKEY
  • Check your ElevenLabs account has available credits
  • Ensure you're using a valid voice name or ID

Audio/video sync issues

The DSL uses real-time timing. If sync issues occur:

  • Ensure your system clock is stable
  • Try shorter narration segments
  • Check that no background processes are causing timing delays

Full Documentation

See the demos-not-memos README for complete API reference and examples.