Summary
(As of v0.8.1.) When a word has no data-d, its duration is derived from the next span's data-m with only a positive cap applied (caption.js:132-141):
thisDuration = (parseInt(words[i + 1].getAttribute('data-m') - 1, 10) / 1000) - thisStart;
if (thisDuration > maxWordDuration) { thisDuration = maxWordDuration; }
If the next span's data-m is ≤ its own — duplicate timestamps on split/glued tokens (cf. the space:false convention) or out-of-order times after manual edits — thisDuration goes negative. Then segmentStop = lastWord.start + lastWord.duration (:198) < segment.start → a cue with stop < start. applyTimingSafeguards deliberately steps over exactly these (:380: if (isNaN(start) || isNaN(stop) || stop <= start) continue;), so the inverted cue is serialized — browsers drop it from the VTT track, and several SRT consumers reject the whole file. If the arithmetic goes below zero, formatSeconds (:11, Date-based) wraps the negative to "23:59:59.xxx" — a cue apparently ending at 24 h.
Fix
Clamp thisDuration = Math.max(0, ...) at :134, and make the safeguard repair stop <= start cues (set stop = start + minCaptionDuration, capped at next start) instead of skipping them.
Found reviewing the vendored copy in the GliderMac app (2026-07-11).
Summary
(As of v0.8.1.) When a word has no
data-d, its duration is derived from the next span'sdata-mwith only a positive cap applied (caption.js:132-141):If the next span's
data-mis ≤ its own — duplicate timestamps on split/glued tokens (cf. thespace:falseconvention) or out-of-order times after manual edits —thisDurationgoes negative. ThensegmentStop = lastWord.start + lastWord.duration(:198) <segment.start→ a cue withstop < start.applyTimingSafeguardsdeliberately steps over exactly these (:380: if (isNaN(start) || isNaN(stop) || stop <= start) continue;), so the inverted cue is serialized — browsers drop it from the VTT track, and several SRT consumers reject the whole file. If the arithmetic goes below zero,formatSeconds(:11, Date-based) wraps the negative to"23:59:59.xxx"— a cue apparently ending at 24 h.Fix
Clamp
thisDuration = Math.max(0, ...)at:134, and make the safeguard repairstop <= startcues (setstop = start + minCaptionDuration, capped at next start) instead of skipping them.Found reviewing the vendored copy in the GliderMac app (2026-07-11).