fix(blog): correct read-along alignment and clear stale highlights #16

Merged
Phil merged 1 commit from fix/audiobook-highlight-sync into main 2026-06-23 17:41:07 +00:00
Owner

Fixes two bugs Phil spotted on the live read-along:

  1. Desync from paragraph 2 on — the difflib longest-match port merged the j2len run-length map across rows instead of replacing it, leaking stale run lengths and producing wrong narration→body matches. Fixed to difflib semantics (j2len = newj2len per row). Verified: assigned word times are now strictly monotonic in DOM order (0 backward steps across 2549 timed words).

  2. Words stayed highlighted after a seek — the seeked handler reset the tracking index but never cleared the orphaned .is-active span, so every seek left a stuck highlight. The highlighter now tracks the active element directly and reconciles read-state via a moving boundary → at most one active word at any time (verified across click/±15s/drag seeks).

🤖 Generated with Claude Code

Fixes two bugs Phil spotted on the live read-along: 1. **Desync from paragraph 2 on** — the difflib longest-match port merged the `j2len` run-length map across rows instead of replacing it, leaking stale run lengths and producing wrong narration→body matches. Fixed to difflib semantics (`j2len = newj2len` per row). Verified: assigned word times are now strictly monotonic in DOM order (0 backward steps across 2549 timed words). 2. **Words stayed highlighted after a seek** — the `seeked` handler reset the tracking index but never cleared the orphaned `.is-active` span, so every seek left a stuck highlight. The highlighter now tracks the active element directly and reconciles read-state via a moving boundary → at most one active word at any time (verified across click/±15s/drag seeks). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Two bugs in the audiobook read-along:

1. Desync from the 2nd paragraph on: the difflib longest-match port
   merged the j2len run-length map across rows instead of replacing it,
   so stale run lengths leaked between iterations and produced wrong
   narration→body matches. Replacing j2len each row (difflib semantics)
   makes the assigned word times strictly monotonic in DOM order
   (verified: 0 backward steps across 2549 timed words).

2. Words stayed highlighted after a seek: the `seeked` handler reset the
   tracking index but never cleared the orphaned `.is-active` span, so
   every seek (click-to-word, ±15s, drag) left a stuck highlight. The
   highlighter now tracks the active element directly and reconciles read
   state via a moving boundary, so at most one word is ever active.

Exposes data-s on timed spans for inspection.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Phil merged commit 2a20427ca3 into main 2026-06-23 17:41:07 +00:00
Phil deleted branch fix/audiobook-highlight-sync 2026-06-23 17:41:07 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Phil/philflow.io!16
No description provided.