Files
gui-video-clipper/chat-summaries/2026-09-22_07-10-paged-teleprompter-subtitles-summary.md
cottongin 8ad2f1c800 chore: stage all pending work — caption styling, media server, processing modal, docs, summaries
Includes:
- Extended caption styling (font, shadow, dimmed color, bg toggle)
- Media server, subtitle downloader, VTT parser, processing modal
- Waveform tiers, thumbnail/timeline improvements, transport controls
- Hybrid download model, dependency management, clip export enhancements
- 21 chat summaries, 2 implementation plans, 2 design specs

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-22 10:48:16 -04:00

63 lines
3.3 KiB
Markdown

# Paged Teleprompter Burn-In Subtitles
**Date:** 2026-09-22
**Task:** Replace rolling per-line ASS subtitle generation with a paged teleprompter model for burn-in captions.
## Problem
The previous rolling subtitle implementation generated 3 independent ASS Dialogue events per spoken line (`Active → Context → Disappear`) with `\move` animations. When a new line arrived, both the new and previous lines scrolled simultaneously, creating a "2-line block jump" rather than a natural top-to-bottom reading flow. The active line always reset to the bottom position.
## Solution
Rewrote the ASS generation to use **2-line paged blocks**:
- **Paged model:** Spoken lines are grouped into consecutive pairs. Each page is a single ASS Dialogue event with `\N` (hard line break) between lines.
- **Continuous karaoke:** `\k` tags flow from line 1 through line 2 within the same Dialogue, creating a natural top-to-bottom reading experience (teleprompter style).
- **Cross-fade transitions:** Pages transition via 300ms cross-dissolve using `\fad` tags — no `\move` or `\clip` tags needed.
- **Static positioning:** `\an2\pos(960, 1040)` anchors each page at bottom-center. No animation on position.
- **Gap-based splitting:** If two consecutive lines are >2s apart, they're split into separate single-line pages.
## Changes Made
| File | Change |
|------|--------|
| `src-tauri/src/services/clip_exporter.rs` | Added `group_into_pages()`, `build_page_karaoke_text()`. Rewrote `vtt_to_ass_with_karaoke()`. Removed `RollingLayout` struct and dead `build_karaoke_text()`. Fixed stale comments. |
| `docs/superpowers/specs/2026-09-22-paged-teleprompter-subtitles-design.md` | Design spec |
| `docs/superpowers/plans/2026-09-22-paged-teleprompter-subtitles.md` | Implementation plan |
## Key Implementation Details
### Karaoke Stitching Across Lines
The `build_page_karaoke_text()` function collects word timings from both lines into a flat sequence. The last word of line 1 gets a `\k` duration that extends to line 2's first word start time, naturally covering any gap (silence) between lines. The `\N` is purely visual and doesn't interrupt the karaoke timeline.
### Cross-Fade Timing
| Page Position | `\fad` value |
|---|---|
| First page | `\fad(0, 300)` |
| Middle pages | `\fad(300, 300)` |
| Last page | `\fad(300, 0)` |
Display times are extended/preponed by 300ms to create overlap.
## Commits
- `934c270` — feat(subtitles): add page grouping and cross-line karaoke stitching
- `d13ba27` — feat(subtitles): rewrite ASS generation to paged teleprompter model
- `2b95d8a` — chore: remove dead build_karaoke_text, fix stale comments
## Tests
23 tests passing (8 new + 15 existing).
## Lessons Learned
1. **ASS `\N` doesn't interrupt `\k` flow** — Hard line breaks within a single Dialogue event are purely visual; karaoke timing continues seamlessly across them.
2. **`\fad` > `\move` for transitions** — Static positioning with opacity-only transitions (`\fad`) is much simpler and cleaner than coordinate-based animations, especially for avoiding background-box artifacts.
3. **Trailing `\N` bug recurrence** — The trailing `\\N` in Dialogue format strings was a recurring bug from previous iterations. Must always check for this when writing ASS output.
## Follow-Up
- Manual smoke test needed: export a clip with burn-in captions and verify the teleprompter reading flow.