Skip to content

Word-level .active class suppressed while paused, breaks default CSS on scrub-while-paused #220

@maboa

Description

@maboa

Report

When the player is paused, Hyperaudio Lite applies the active class to the paragraph element but not to the word <span> inside it. This breaks the project's own default CSS, which uses .active > .active to style the currently-active word.

Result: if a user scrubs the media (drags the playhead, clicks on the timeline, navigates via keyboard, etc.) while the player is paused, the active paragraph gets highlighted but the active word does not. The visual indicator effectively disappears on scrub-while-paused — a common interaction.

Where

js/hyperaudio-lite.js lines 767–772 (on main, version 2.4.0):

if (index > 0) {
  if (!this.myPlayer.paused) {
    this.wordArr[index - 1].n.classList.add('active');
  }
  this.wordArr[index - 1].n.parentNode.classList.add('active');
}

The word-level active class is gated on !this.myPlayer.paused. The paragraph-level one isn't.

The default CSS in active.html (and recommended in the README) does:

.hyperaudio-transcript .active{
  background-color: #efefef;            /* paragraph */
}

.hyperaudio-transcript .active > .active {
  background-color: #ccf;               /* word inside active paragraph */
  text-decoration:  #00f underline;
  text-decoration-thickness: 3px;
}

The second rule needs .active on both the parent and the child to match. With the word-level class suppressed while paused, the child rule matches nothing.

Reproduction

  1. Open active.html in a browser
  2. Start playback, then pause
  3. Click on a word elsewhere in the transcript (or scrub the media element)
  4. Observe: the paragraph gets the highlight, but no word does

Why it's a footgun

This shows up most often for downstream consumers who adopt the project's recommended CSS verbatim and then build an "interactive transcript editor" or "scrubbing UI" on top. The behavior is invisible during normal play (because the paused check is true only briefly) and only manifests when the user pauses and interacts — a common pattern in editing/review workflows.

Possible fixes

  1. Just drop the conditional. Always apply word-level active. Risk: there's presumably a reason it was added — would need to check git blame and confirm no regression to whatever was being protected against (possibly there was a flicker issue mid-play that this guarded).

  2. Make it a flag. Add an option like keepActiveWordWhilePaused: true (default could be either way), so consumers can opt out of the suppression.

  3. Hook native seek events. Listen for the seeked event on the media element and re-apply the word-level class on that path. This narrowly fixes the scrub case without changing pause behavior.

  4. Suppress in CSS, not JS. Move the "no word highlight while paused" decision into a class on the transcript element (e.g. .is-paused on the container) and let CSS author choose to apply it or not. Cleanest separation of concerns but biggest API change.

(1) or (3) likely resolve the report without breaking anyone. (2) is more conservative if intent of the original conditional matters and can't be re-derived.

Context

Reported by a downstream consumer working with HLE in a separate project.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions