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

3.3 KiB

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.