Demo script + TTS narration + captions

This is the content reference — what to write down before recording. The demo script is a first-class artifact (checked into the repo, published to the wiki); narration text is approved by the user BEFORE TTS rendering; captions are rendered live in the workspace during capture.

Parent skill: SKILL.md. Read the "Ten failure modes" and "What a real demo means" sections first.

Write the demo script — self-contained, reproducible, checked into the repo

The demo script is a first-class artifact of the repo, not scratch work. It must be checked into the project git repo at <repo>/demo/<name>-demo-script.md (not just /tmp/) and — at the end of per-snippet-flow's wiki publish step — published to the wiki so other Adom users can run, review, or tweak the demo without digging through chat history. Treat it the way you'd treat a Makefile: if another person (or another Claude) can't reproduce the demo from this file alone, the file is incomplete.

Repo location. <repo>/demo/<name>-demo-script.md is the canonical home. Put companion files (record.py, mux.py, generated manifest, any custom TTS overrides) in the same demo/ directory. /tmp/ paths are fine during execution but the source of truth lives in the repo so git history tracks every demo revision.

The script MUST be self-sufficient — every piece, one file

The script is a runnable spec. A fresh Claude thread (or a teammate) reading it should be able to re-render the entire demo without asking any questions. That means every setting that affects the output goes in the file, not in the assistant's head:

  • Metadata header — version being demoed, target duration, recording date, hero frame timestamp, final output path
  • Tooling depsedge-tts / adom-cli / adom-video-post / ffmpeg versions / required env vars
  • Voice + rateen-US-AndrewMultilingualNeural / +5% / any per-scene overrides
  • Workspace setup — canonical split ratio (default 0.30 AI / 0.70 feature), which panels, which apps pre-opened
  • Scene list — numbered, with captions, interactions, commands, panel choreography, speedup markers, and narration text (see table below)
  • Manifest path — canonical /tmp/<name>-manifest.json location + <repo>/demo/manifest.json checked-in copy
  • Reproduction block — the exact commands another user runs to regenerate the demo end-to-end (see template below)
  • Wiki page target — where this demo publishes (apps/<page>)

Omitting any of the above means the next person who tries to regenerate the demo has to reverse-engineer your choices from the muxed output. Don't do that to them.

Template — start every demo script from this shape

# <Product Name> <version> — Feature Tour

**Target duration:** 4:30–5:00
**Recorded:** 2026-04-23
**Final output:** `~/project/recordings/<name>-<version>-tour.webm`
**Wiki target:** `apps/<page>`
**Hero frame:** `00:12` of scene 1 (BME680 first iso shot)

## Dependencies

- `edge-tts` — `pip install edge-tts` (tested with 6.1.x)
- `adom-cli` — container-provided
- `adom-video-post` — built from `/home/adom/project/adom-video-post/` (`cargo build --release`)
- `ffmpeg 6+` — container-provided
- Env vars: none required beyond the container defaults

## Recording config

- **Voice:** `en-US-AndrewMultilingualNeural`
- **Rate:** `+5%`
- **Workspace split:** 0.30 (VS Code / AI left, feature pane right)
- **Captions:** on, via `adom-cli hydrogen caption show`
- **Resolution:** native (1280×…)

## Scenes

| # | id | Caption (on-screen) | Narration (TTS, phonetics applied) | Target length | Commands + choreography |
|---|---|---|---|---|---|
| 1 | intro | `adom-tsci 1.3.7` | `This is adom t s c i version one point three point seven — the interactive t s circuit preview.` | 8s | `adom-tsci view isometric --port 8853` — cinematic slow orbit |
| 2 | examples | `8 example molecules` | `Adom ships eight example molecules — let's open a BME680 breakout.` | 10s | switch to example folder, `adom-tsci start <dir>` |
| … | … | … | … | … | … |

(13 scenes for the adom-tsci 1.3.7 tour; ~5:00 total)

## Reproduction

Another user regenerates this demo end-to-end with:

\`\`\`bash
cd <repo>
python3 demo/gen_tts.py           # renders TTS from this script's narration column
python3 demo/record.py            # drives scene-by-scene recording
python3 demo/mux.py               # muxes TTS onto clips, concatenates final
adom-video-post storyboard /tmp/<name>-manifest.json   # review
# after review:
adom-video-post concat /tmp/<name>-manifest.json --kind raw --output ~/project/recordings/<name>-<version>-tour.webm
adom-wiki asset upload apps/<page> --asset-type video --file ~/project/recordings/<name>-<version>-tour.webm
\`\`\`

## Known issues from this rev

- Clip 02 originally recorded as one 2:17 mega-clip; split into 8 × 12s clips in revision 2 for surgical re-shoot support.
- TTS in rev 1 mispronounced `adom-tsci` as one word; fixed in rev 2 by spelling as `adom t s c i` in narration column.

Why the repo + wiki double-home

  • In the repo: git history tracks every demo revision. If someone files an issue "the demo is out of date after v1.4.0 ships" you can diff the script.
  • On the wiki: other Adom users find it when browsing apps/<page>. They can click "reproduce" and a Claude thread says "I see a demo-script for this app — want me to re-record against the current version?"
  • Both: git is the source of truth (atomic with code changes); wiki is the discoverable surface.

Copy this script file during recording, don't write straight to /tmp/

mkdir -p <repo>/demo
cp /tmp/<name>-demo-script.md <repo>/demo/<name>-demo-script.md    # if you drafted in /tmp
# ...or write directly to the repo path in the first place (preferred).

Before touching the record button, show the script to the user for approval. Save to <repo>/demo/<name>-demo-script.md.

🗣️ TTS pronunciation — consult the tts-pronunciation skill

Neural TTS engines mispronounce many Adom product names, acronyms, and hyphenated terms. The canonical table lives in the tts-pronunciation skill (data file: pronunciations.json). For every narration scene, look up each proper-noun / acronym / version-number in that table and substitute its narration spelling into the narration column. Captions and on-screen text keep the real spelling; only the narration-column text gets phoneticized.

Most common fixes (the full table is in the tts-pronunciation skill):

  • adom-tsciadom t s c i
  • JLCPCB / FPGA / PCB / SPI → spell letters with spaces
  • 1.3.7one point three point seven
  • KiCadkai cad
  • BOMbill of materials (TTS engines read "BOM" as the word "bomb")

If a term you need isn't in the table, add it. The contribution flow is in tts-pronunciation/SKILL.md — verify the mispronunciation with a one-shot edge-tts, find a spelling that fixes it, append to pronunciations.json, commit. Every user benefits.

Verify before rendering the full tour:

edge-tts --voice en-US-AndrewMultilingualNeural \
  --text "adom t s c i version one point three point seven" \
  --write-media /tmp/_test.mp3
# Listen with ffplay /tmp/_test.mp3 — it should spell out T S C I, not say "sci" as a word.

Fixing narrations at script time costs seconds. Fixing them after you've muxed 13 clips means re-running TTS, re-muxing, re-concat, re-storyboarding.

📏 Clip duration ≈ narration duration, ±15%

Don't let a clip's video length drift too far from its narration length. A 2:17 video with 0:30 of narration is broken either way:

  • Either the narration is too thin — tighten the video ("cycle through 8 example molecules" is one scene if narrated in 30s, but only if you can render all 8 in 30s).
  • Or the video is genuinely 2:17 — then split it into multiple clips, each with its own matched-length narration.

Split-before-speedup heuristic. When a single clip concept spans distinct sub-actions (open / click / close, or cycle-through-N-things), the correct path is N clips with N narrations, not one mega-clip with a speedup pass. Reasons:

  • Surgical re-shoots — if one of 8 examples fails to render, a single split clip rerecord fixes it. A mega-clip has to be fully rerecorded.
  • Pacing control — app-side lag (e.g. loading a new example molecule) bakes into a mega-clip. Smaller clips let you cut-on-ready.
  • Narration clarity — "now we see the BME680... and the BHI360... and the SN65HVD230..." is unnatural. "This is the BME680." [clip break] "The BHI360." is tight.

Scene list

Numbered scenes with:

  • What's on screen
  • Commands to run
  • Expected duration (real time + after speedup)

🎙️ Narration text for every scene — the TTS that will be rendered

The full spoken narration for every scene goes in the demo script, visible to the user for approval BEFORE any recording or TTS rendering happens. This is the single most important line-item in the script. Everything else (captions, interactions, commands) is cheaper to change than narration once rendered — if you skip the script-time review and discover the wrong pronunciation / wrong wording / wrong length at mux time, you're re-rendering N clips to fix it.

The script table should have a dedicated Narration column next to each scene:

Scene Caption (seen) Narration (heard) — TTS-safe phonetics applied Target length
1 adom-tsci 1.3.7 This is adom t s c i version one point three point seven — the interactive t s circuit preview. 8s
2 BME680 breakout Let's open a BME680 breakout molecule. Four in one sensor: temperature, humidity, pressure, gas. 10s

Rules for the narration column:

  1. Apply the TTS pronunciation table (above) — the user approves the phonetic spelling, so what they read in the script is exactly what the TTS will say. adom-tsci never appears literally in narration column; it's always adom t s c i.
  2. Target length per scene must be consistent with the planned video length (±15%, per the section above). If a scene is planned for 15 s of video, narration is ~80–120 words. Count words as a sanity check; at 160 wpm spoken pace that's ~13–17 s.
  3. User-approved narration text is the only source of truth for edge-tts --text "…" later. No paraphrasing at record time. If you need to change narration during recording, stop and update the script (and re-get approval).
  4. Narration ≠ caption. Caption is short, on-screen, SEO-ish ("BME680 breakout"). Narration is conversational, spoken ("Let's look at the BME680 breakout molecule…"). Both are required. Don't reuse one for the other.

Why narration lives in the script (approved) not at render time: Fixing a typo or a pronunciation issue in the approved script costs seconds. Finding it after mux costs 13 × (TTS render + ffmpeg mux + concat) minutes + another storyboard-review round. The script-approval step is where all cheap-to-fix-now mistakes get caught.

Captions for every scene

Always generate a caption for every scene. Captions are rendered live in the workspace during recording via adom-cli hydrogen caption show. They serve two purposes:

  1. Make the video self-explanatory — viewers understand each scene on mute
  2. Narrator cues — during the voiceover pass, the user sees the captions in the video and knows exactly when and what to say for each scene

Display captions at the START of each scene:

adom-cli hydrogen caption show "Isometric view — full board layout" -d 5

Hide when transitioning: adom-cli hydrogen caption hide

Do NOT use adom-video-post --label for captions. Those are ugly ffmpeg text overlays. Use adom-cli hydrogen caption show for clean, rendered captions that appear natively in the workspace.

Do NOT use Adom Viewer (AV) for captions or narration — ever. No html_interactive caption panels, no av_display narration overlays, no custom AV widgets that exist just to show status text. The Hydrogen caption overlay is the only supported captioning path for demos and for any live narration of a multi-step task ("show me what's happening as you go"). AV is for visual content (3D models, schematics, gerbers, scope screenshots) — never for captions about that content. This applies to every demo skill, including tours and any ad-hoc "narrate while you work" requests.

Show the full caption table to the user as part of the script:

Scene Caption
1 shotlog health — server running
2a Isometric view — full board layout
2b Top-down — trace routing and pad layout
3 Timeline — 4 screenshots with descriptions

Panel choreography

If the demo involves multiple panels (e.g. a 3D viewer AND a log viewer), script explicit panel switches between each action so the viewer sees both sides. Don't run 4 CLI commands with one panel visible — alternate:

1. Show 3D viewer → rotate to isometric
2. Switch to shotlog → screenshot appeared in timeline
3. Switch to 3D viewer → rotate to top-down
4. Switch to shotlog → 2 entries now

This makes the demo visually interesting instead of staring at one panel while CLI commands run off-screen.

Speedup markers

Mark slow operations (exports, searches, AI latency, screenshot capture) with their speedup factor. Do NOT use --label for captions — speedup labels are only for internal tracking. Visual captions come from adom-cli hydrogen caption.

Speedup: 10x — screenshot capture + inject
Speedup: 20x — exporting gerbers

Voiceover draft

Write a short narration script the user can read during the voiceover pass. The live captions displayed during recording serve as narrator cues — when the user watches the sped-up video during voiceover, they see each caption appear and know exactly what to say at that moment. Structure the voiceover script as caption-keyed paragraphs:

[Caption: "Isometric view — full board layout"]
"Here's our CAN transceiver molecule from the isometric angle, showing the
full board with standoffs and the SN65HVD230 IC in the center."

[Caption: "Top-down — trace routing"]
"From the top, you can see the trace routing and pad layout clearly."

Keep total narration under 60 seconds for most demos.

Target final duration

Aim for 30-60s. Nobody watches a 5-minute demo.

See also