# 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](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](per-snippet-flow.md) — 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 deps** — `edge-tts` / `adom-cli` / `adom-video-post` / `ffmpeg` versions / required env vars
- **Voice + rate** — `en-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

```markdown
# <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/`

```bash
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](../tts-pronunciation/SKILL.md) (data file: [`pronunciations.json`](../tts-pronunciation/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-tsci` → `adom t s c i`
- `JLCPCB` / `FPGA` / `PCB` / `SPI` → spell letters with spaces
- `1.3.7` → `one point three point seven`
- `KiCad` → `kai cad`
- `BOM` → `bill 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:**

```bash
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:

```bash
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:

```text
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`.

```text
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:

```text
[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

- [SKILL.md](SKILL.md) — parent: orchestration, the ten failure modes, the "real demo" 10-step shape
- [recording-mechanics.md](recording-mechanics.md) — capture path, surfaces, frame-rate sanity, NEVER stitch screenshots
- [per-snippet-flow.md](per-snippet-flow.md) — manifest, storyboard review, mux + concat, hero, upload
- [tts-pronunciation](../tts-pronunciation/SKILL.md) — Adom-specific phoneme table
