# Narrator

A dubbing-style teleprompter for voice-over essays.

A **Villaine** experiment. Single HTML file, no build, no server, no dependencies. Drop a Markdown script in the defined format and the app turns it into a synced reading environment with a chapter timeline, visual-cue sidebar, and built-in mic recorder.

---

## What it does

Most teleprompters are reader-paced: the script scrolls to match how fast you talk. Narrator is **script-paced**: the script advances on its embedded `[MM:SS]` markers regardless of how fast or slow you read. If you finish a line early, you sit in silence until the next mark. If you take longer, a pace readout flags you. That's the dubbing model — the script sets the cadence, the reader matches it — and it's what makes voice-over work cut cleanly to a pre-imagined edit.

## When to use it

- You're writing a voice-over essay and the timing matters for the visual edit.
- You want to rehearse a narration until the cadence is locked.
- You want a fast, clean rec environment with a level meter and per-take .webm download.
- You want a script format simple enough that AI can generate it (see [`prompts/generate-narration.md`](prompts/generate-narration.md)).

## When NOT to use it

- You want a freeform teleprompter that scrolls at your pace. Use one of the dozens of free ones online.
- You're doing live-to-camera presentations. Narrator is for pre-edited voice-over delivery.
- You need multi-language synced subtitles. Narrator only handles the source script.

---

## Run it

Three ways:

1. **Double-click `index.html`** — opens in your default browser. Loading the example scripts via "try an example" requires the browser to fetch sibling files; some browsers block this under `file://`. If it fails, use the file picker or paste instead.

2. **Serve the folder** — for full functionality including example loading:
   ```bash
   cd villaine-experiments/narrator
   python -m http.server 8080
   # open http://localhost:8080
   ```

3. **Host it** — drop the whole `narrator/` folder on any static host (Netlify, GitHub Pages, Vercel, Cloudflare Pages). No build step.

## Load a script

- **File picker:** click "pick file" and choose a `.md`.
- **Drag and drop:** drop a `.md` file onto the import card on the empty state.
- **Paste:** click "paste markdown", paste, click "load pasted".
- **Examples:** "try an example" links in the empty state (requires serving via HTTP).

The last loaded script is remembered in `localStorage` and auto-loads on next visit. Click the wordmark (top-left of the app) to go back to the import screen.

## Read the script

- `space` — play / pause
- `esc` — stop (reset to 0:00)
- `←` / `→` — seek ±5 s
- `r` — toggle recording
- `m` — mirror flip (for teleprompter rigs that bounce off a mirror)
- Click the timeline to seek.
- Click any chapter block to jump to its start.

## Record

Click the red `⚫ rec` button (or press `r`). Grant mic permission on first use. Recording is independent of playback — you can start the script, hit record halfway through, etc. Stop recording to get a download link in the footer; the file is `.webm` (Opus codec), browser-native.

Convert to `.wav` for editing:
```bash
ffmpeg -i narration-XYZ.webm narration-XYZ.wav
```

---

## The script format

See [`FORMAT.md`](FORMAT.md) for the full spec. The short version:

```markdown
---
title: Soustraction
lang: fr
target_duration: 4:32
---

## OUVERTURE (0:00 - 0:12)
`[00:00]` // visual: black, hold 3 s

## CHAPITRE I — UN COCKPIT (0:12 - 1:12)
`[00:15]` // visual: wide symmetric shot of basement office
`[00:18]` Je travaille dans le sous-sol d'une maison a Montreal.
`[00:22]` Les tuiles du plafond sont blanches.
```

Three things matter: chapters (`## TITLE (MM:SS - MM:SS)`), timestamped events (`` `[MM:SS]` content ``), and content type (visual cues start with `//`, spoken lines are plain text). Everything else is ignored.

## Generating scripts with AI

See [`prompts/generate-narration.md`](prompts/generate-narration.md) for a paste-ready prompt template. Fill in subject, voice, length, anchors, off-limits — get a valid `.md` back.

## Examples

- [`examples/minimal.md`](examples/minimal.md) — 30-second three-chapter demo, useful for testing the parser.
- [`examples/soustraction.md`](examples/soustraction.md) — full 4:32 French essay, the original use case.

---

## Files

```
narrator/
├── index.html              ← the app (open this)
├── README.md               ← you are here
├── FORMAT.md               ← narration script format spec
├── examples/
│   ├── minimal.md          ← 30-second demo
│   └── soustraction.md     ← 4:32 French essay
└── prompts/
    └── generate-narration.md  ← AI prompt template for generating scripts
```

## Provenance

Built 2026-05-22 under the Villaine maison numerique label. Second experiment after `win-sanity`. Standalone, MIT-licensed (when published). The original use case was a 4:32 French voice-over essay; the format and tool were generalized for reuse.

## Roadmap (not promises)

- v0 (shipped): single-file app, file/paste/drag import, dubbing-style teleprompter, browser mic recording, chapter timeline.
- v0.1 ideas: keyboard shortcut to "mark take" in the recording timeline; SRT export of the script; multi-language switching; tone-of-voice presets that scale font/cadence; teleprompter rig fullscreen mode.
- v1 idea: a tiny editor mode for in-browser script edits with live re-parse and undo.

No commitments on the roadmap — it ships when it ships, in line with the Villaine experiments posture.
