product-demos
Use when creating narrated product demo videos from terminal recordings. Triggers on: asciinema, screen recording, product video, demo video, narrated walkthrough, voiceover, TTS, cast-to-video, product announcement with video
What this skill does
# Product Demo Videos
Produce narrated product demo videos from asciinema terminal recordings. Pipeline: `.cast` → MP4 → ElevenLabs voiceover → synced narrated video.
## Pipeline Overview
```
.cast files (asciinema recordings)
↓
agg → GIF → ffmpeg → MP4 clips (per section)
↓
Trim clips to interesting parts (thumbnail-guided)
↓
ElevenLabs API → per-section MP3 narration
↓
ffmpeg sync (speed-adjust video to match audio)
↓
Normalize + concatenate → final MP4
Normalize + concatenate → final MP4
```
## Setup
```bash
# Install agg (asciinema gif generator) — MUST use --git, not crate name
cargo install --git https://github.com/asciinema/agg
# Python deps in a venv
uv venv /tmp/demo/venv
source /tmp/demo/venv/bin/activate
uv pip install elevenlabs
# Verify
which agg ffmpeg ffprobe
```
**Gotcha:** `cargo install agg` installs a DIFFERENT crate (a library). Must use `--git`.
## Recording with asciinema
```bash
asciinema rec /tmp/demo/recordings/section-name.cast
# Terminal size: 120x35 recommended for consistency
# Theme: set your terminal to a dark theme before recording
```
**Key principles:**
- Record one logical section per file
- Keep a script of what to type, but don't over-rehearse
- Comments (`# Section: ...`) typed into terminal help with trim-point discovery later
- If a command errors on camera, that's usually fine — re-record only if the error is misleading
## Cast → MP4 Conversion
```bash
# Step 1: Cast → GIF (agg compresses idle time automatically)
agg --font-size 24 --theme monokai input.cast output.gif
# Step 2: GIF → MP4 (terminal-optimized encoding)
ffmpeg -y -i output.gif \
-movflags faststart -pix_fmt yuv420p \
-vf "scale=trunc(iw/2)*2:trunc(ih/2)*2" \
-c:v libx264 -preset slow -crf 15 -tune stillimage \
output.mp4
```
**Critical settings:**
- `-crf 15` (not 18 or 23) — terminal text needs near-lossless quality
- `-tune stillimage` — optimizes for low-motion content (terminal = mostly static)
- `scale=trunc(iw/2)*2:trunc(ih/2)*2` — ensures even dimensions for h264
**Gotcha:** agg compresses idle time, so .cast timestamps ≠ MP4 timestamps. Find trim points via thumbnails, not math.
## Finding Trim Points
```bash
# Generate thumbnails at intervals
for t in 0 5 10 15 20 30 40 50 60; do
ffmpeg -y -ss $t -i full.mp4 -frames:v 1 -q:v 5 thumb_${t}s.jpg 2>/dev/null
done
```
Then use `look_at` or manual inspection to identify section boundaries. Trim with:
```bash
ffmpeg -y -i full.mp4 -ss $START -to $END \
-c:v libx264 -crf 15 -tune stillimage -pix_fmt yuv420p -an \
trimmed.mp4
```
## Narration Script Structure
Write narration as a Python data structure for programmatic generation:
```python
SECTIONS = [
{
"id": "1a_feature_intro",
"title": "Feature Name", # → title card
"narration": "Script text here. Use <break time=\"0.8s\" /> for pauses.",
"video": {
"source": "recording-full.mp4",
"trim": (start_sec, end_sec),
},
},
]
```
**Script-to-screen audit (MANDATORY before final render):**
After all recordings are finalized, compare every narration line to what's actually visible on screen. Pre-written scripts WILL diverge from actual recordings. Common mismatches:
- Command output differs from what narration describes
- Specific numbers/stats don't match (e.g., "resisted" vs "ignored")
- Feature names differ (e.g., "slash run-inspect" vs "running-tasks")
- Described workflow doesn't match what the recording shows
## ElevenLabs Voice Generation
### Voice Selection (DO THIS FIRST)
Generate comparison samples before committing to a voice:
```python
from elevenlabs import ElevenLabs, VoiceSettings, save
SAMPLE_TEXT = "Your representative 2-3 sentence sample."
for voice_id, name in [
("CwhRBWXzGAHq8TQ4Fs17", "Roger"),
("iP95p4xoKVk53GoZ742B", "Chris"),
("cjVigY5qzO86Huf0OWal", "Eric"),
("onwK4e9ZLuTAKqWW03F9", "Daniel"),
]:
audio = client.text_to_speech.convert(
voice_id=voice_id, text=SAMPLE_TEXT,
model_id="eleven_turbo_v2_5",
output_format="mp3_44100_192",
voice_settings=VoiceSettings(
stability=0.75, similarity_boost=0.85,
style=0.0, speed=0.92, use_speaker_boost=True,
),
)
save(audio, f"sample_{name}.mp3")
```
Build a comparison video with labels so the user can A/B in one file:
```bash
ffmpeg -y \
-f lavfi -i "color=c=0x1a1a2e:size=1280x720:duration=${dur}:rate=24" \
-i sample.mp3 \
-filter_complex "[1:a]volume=2.0,aformat=channel_layouts=stereo[a];
[0:v]drawtext=fontfile=${FONT}:text='${NAME}':fontsize=48:
fontcolor=white:x=(w-text_w)/2:y=(h-text_h)/2,format=yuv420p[v]" \
-map "[v]" -map "[a]" \
-c:v libx264 -crf 18 -c:a aac -b:a 192k -ar 44100 -ac 2 \
-shortest labeled_sample.mp4
```
### Generating Narration
```python
audio = client.text_to_speech.convert(
voice_id=VOICE_ID,
text=section_text,
model_id="eleven_turbo_v2_5", # Best for English narration
output_format="mp3_44100_192", # 192kbps — 128 sounds bad
voice_settings=VoiceSettings(
stability=0.75, # 0.6-0.8 for narration
similarity_boost=0.85,
style=0.0, # Keep at 0 — reduces artifacts
speed=0.92, # Slightly slower for clarity
use_speaker_boost=True,
),
previous_text=prev[-200:], # Cross-section continuity
next_text=nxt[:200],
)
save(audio, output_path)
```
**Critical audio settings:**
- `mp3_44100_192` minimum — 128kbps sounds tinny/compressed
- `eleven_turbo_v2_5` model — more natural than `multilingual_v2` for English
- `pcm_44100` (lossless) requires Pro plan
- Mono output from API — must convert to stereo + boost volume for video
### Pronunciation
ElevenLabs handles most acronyms. For problem terms, use alias substitution in text:
- `"jj"` → `"jay-jay"`, `"CLI"` → `"C L I"`, `"OAuth"` → `"Oh-Auth"`
- `"uv sync"` → `"you-vee sync"`, `"tl run"` → `"T L run"`
### Fallback: gTTS
If no ElevenLabs key, `pip install gTTS` provides free Google TTS. Lower quality but unblocks the pipeline. Strip `<break>` tags (unsupported) and replace with periods.
## Video Assembly
### Syncing Video + Audio
Speed-adjust video to match audio duration. Terminal recordings tolerate wide speed ranges:
```python
video_dur = get_duration(video_path)
audio_dur = get_duration(audio_path)
pts = max(0.25, min(4.0, video_dur / audio_dur))
inv_pts = 1.0 / pts
ffmpeg ... -filter_complex
"[0:v]setpts={inv_pts}*PTS,...[v];[1:a]volume=2.0,aformat=channel_layouts=stereo[a]"
-map "[v]" -map "[a]"
-c:a aac -b:a 192k -ar 44100 -ac 2
```
**Acceptable speed ranges:**
- 0.5x–2.0x: imperceptible for terminal recordings
- 0.3x–0.5x: fine for "reading the screen" moments (diagnostics output)
- >3x: video becomes unwatchably fast — trim the narration instead
### Normalization for Concat
**ALL clips MUST be normalized before concatenation.** ffmpeg concat demuxer requires identical:
- Resolution (scale + pad to target)
- FPS (`fps=10` is fine for terminal)
- Pixel format (`format=yuv420p`)
- Audio: stereo, 44100Hz, AAC
```bash
ffmpeg -y -i clip.mp4 \
-vf "scale=${W}:${H}:force_original_aspect_ratio=decrease,
pad=${W}:${H}:(ow-iw)/2:(oh-ih)/2:color=0x1a1a2e,
fps=10,format=yuv420p" \
-c:v libx264 -crf 15 \
-c:a aac -b:a 192k -ar 44100 -ac 2 \
normalized.mp4
```
**Gotcha:** ffmpeg `scale` filter uses `:` separator, NOT `x`. `scale=1756:1208` ✅, `scale=1756x1208` ❌.
### Title Cards
```bash
ffmpeg -y -f lavfi \
-i "color=c=0x1a1a2e:size=${W}x${H}:duration=3:rate=10" \
-f lavfi -i "anullsrc=r=44100:cl=stereo" \
-vf "drawtext=fontfile=${FONT}:text='Section Title':
fontsize=52:fontcolor=white:x=(w-text_w)/2:y=(h-text_h)/2,
format=yuv420p" \
-c:v libx264 -crf 15 -c:a aac -b:a 192k -t 3 title.mp4
```
### Concatenation
```bash
# Build concat list
for clip in normalized_*.Related in Image & Video
watch
IncludedWatch a video (URL or local path). Downloads with yt-dlp, extracts auto-scaled frames with ffmpeg, pulls the transcript from captions (or Whisper API fallback), and hands the result to Claude so it can answer questions about what's in the video.
physical-ai-defect-image-generation
IncludedUse when the user wants to orchestrate defect image generation, run associated setup, or handle outputs on OSMO. The Day 0 path handles cold-start with USD-to-ROI, image-edit augmentation, and AnomalyGen to create initial PCBA datasets. The Day 1 path performs inference and labeling on real images. This skill helps with first-time asset setup, creation of finetuning checkpoints, and configuring deployment. Trigger keywords: defect image generation, dig workflow, dig pipeline, defect image detection workflow, aoi pipeline, aoi anomalygen, usd2roi anomalygen, day 0 pcba, day 1 pcba, day 1 real-photo alignment, day 1 manual roi, metal surface anomaly, glass defect, anomalygen finetune, setup_pcb, setup_metal, setup_glass, setup_pretrained, dig setup, dig datasets, dig pretrained checkpoint, dig image-edit endpoint.
accelint-react-best-practices
IncludedReact performance optimization and best practices. ALWAYS use this skill when working with any React code - writing components, hooks, JSX; refactoring; optimizing re-renders, memoization, state management; reviewing for performance; fixing hydration mismatches; debugging infinite re-renders, stale closures, input focus loss, animations restarting; preventing remounting; implementing transitions, lazy initialization, effect dependencies. Even simple React tasks benefit from these patterns. Covers React 19+ (useEffectEvent, Activity, ref props). Triggers - useEffect, useState, useMemo, useCallback, memo, inline components, nested components, components inside components, re-render, performance, hydration, SSR, Next.js, useDeferredValue, combined hooks.
elevenlabs-agents
IncludedBuild conversational AI voice agents with ElevenLabs Platform using React, JavaScript, React Native, or Swift SDKs. Configure agents, tools (client/server/MCP), RAG knowledge bases, multi-voice, and Scribe real-time STT. Use when: building voice chat interfaces, implementing AI phone agents with Twilio, configuring agent workflows or tools, adding RAG knowledge bases, testing with CLI "agents as code", or troubleshooting deprecated @11labs packages, Android audio cutoff, CSP violations, dynamic variables, or WebRTC config. Keywords: ElevenLabs Agents, ElevenLabs voice agents, AI voice agents, conversational AI, @elevenlabs/react, @elevenlabs/client, @elevenlabs/react-native, @elevenlabs/elevenlabs-js, @elevenlabs/agents-cli, elevenlabs SDK, voice AI, TTS, text-to-speech, ASR, speech recognition, turn-taking model, WebRTC voice, WebSocket voice, ElevenLabs conversation, agent system prompt, agent tools, agent knowledge base, RAG voice agents, multi-voice agents, pronunciation dictionary, voice speed control, elevenlabs scribe, @11labs deprecated, Android audio cutoff, CSP violation elevenlabs, dynamic variables elevenlabs, case-sensitive tool names, webhook authentication
humanizer
IncludedHumanize AI-generated text by detecting and removing patterns typical of LLM output. Rewrites text to sound natural, specific, and human. Uses 28 pattern detectors, 560+ AI vocabulary terms across 3 tiers, and statistical analysis (burstiness, type-token ratio, readability) for comprehensive detection. Use when asked to humanize text, de-AI writing, make content sound more natural/human, review writing for AI patterns, score text for AI detection, or improve AI-generated drafts. Covers content, language, style, communication, and filler categories.
generating-mermaid-diagrams
IncludedSalesforce architecture diagrams using Mermaid with ASCII fallback. Use this skill when generating text-based diagrams for Salesforce architecture, OAuth flows, ERDs, integration sequences, or Agentforce structure. TRIGGER when: user says "diagram", "visualize", "ERD", or asks for sequence diagrams, flowcharts, class diagrams, or architecture visualizations in Mermaid. DO NOT TRIGGER when: user wants PNG/SVG image output (use generating-visual-diagrams), or asks about non-Salesforce systems.