Skip to content

Version 1.3.19 - #642

Merged
maboa merged 13 commits into
mainfrom
release/1.3.19
Sep 17, 2026
Merged

maboa merged 13 commits into
mainfrom
release/1.3.19

Conversation

@maboa

@maboa maboa commented Sep 17, 2026

Copy link
Copy Markdown
Member

Caption reading rates, a warning when one runs too fast, and Settings split into tabs.

  • Show each caption's reading rate in the caption editor, in WPM or CPS #639 — every caption shows its reading rate. Top right of each caption in the caption editor, in characters per second or words per minute, recalculated on every edit: typing, a time change, a merge, an insert, a delete. Clicking a rate switches the measure for all of them. Settings carries the choice, including None, which hides them. Characters per second is the streaming convention and words per minute the broadcast one, which is why both are offered rather than one.
  • Show each caption's reading rate in the caption editor, in WPM or CPS #639 — characters per line is a setting, and feeds generation. Defaulting to 32, passed to caption generation in all three places that call it, so it applies to the next generation and leaves existing captions alone. The minimum line length follows the maximum down, so a break stays possible at any setting.
  • Warn when a caption's reading rate goes over the limit #641 — a caption over the limit is flagged. A limit per measure in Settings, 17 characters per second and 180 words per minute by default. The flag is judged on the number as shown, so a caption displaying 17.0 against a limit of 17 is not flagged. Advisory only, and a limit of zero keeps the number without the judgement.
  • A settings page: what belongs in it, and where it goes #615 follow-up — Settings is tabbed. Three collapsible sections had become a long scroll. Application, Captions and Playback are tabs now, using the lifted tabs the Transcribe modal already uses for its engines, at a fixed height so the modal does not resize as tabs change.
  • Regenerate captions reads as a button. It was a transparent word sitting over the caption rows. It is now a solid icon button with a tooltip, and it confirms before discarding caption edits.

Fixes #639
Fixes #641

Gate: 122 unit; 391 e2e passed, 1 skipped (the known WebKit OPFS skip).

Editing captions well means knowing whether a cue can be read in the time
it is on screen, and the caption editor said nothing. Each caption now
carries its rate at the top right of its first row, beside the play
button: characters per second, the streaming convention and the stricter
of the two, or words per minute, what broadcast works in. The choice is
the user's rather than the project's, so it sits in Settings, defaulting
to CPS.

It reads the INPUTS rather than any cached model, so a re-worded line or a
retimed cue shows up at once, and it recomputes from two places only:
when the editor is populated — generation, regeneration, VTT/SRT import,
returning to the caption view — and on makeCaptionEditorActive, the one
door typing, insert, merge and delete already pass through.

Nothing is shown for an empty caption, a zero or negative duration, or a
timecode still being typed, rather than a division by zero.
It is DaisyUI's outline button, so its fill was transparent, and it
floats over the caption rows that scroll underneath it — caption text
showed through the button. White matches the card it sits on, and hover
keeps the filled-primary inversion so the affordance is unchanged.
The floating button carried the word "Regenerate" across the top right of
the caption editor, over rows it floats above. It is an icon now, square,
with "Regenerate captions from transcript" in a tooltip and the same text
as its accessible name, so a screen reader and a pointer get the same
sentence. The tooltip is right-anchored, the mirror of the left-edge rule
the player controls use (#546), since a centred bubble at that width
would run off-screen.

The confirmation it opens is unchanged and was already there: it warns
that caption edits will be lost, and confirming resumes transcript sync
before rebuilding.
The measure was only changeable in Settings, which is a long way from the
captions you are reading it against. Clicking a rate switches it now,
between characters per second and words per minute, for every caption at
once: it is one editorial standard, and two scales down the same column
would tell you nothing. The tooltip says which measure a click brings.

Settings gains None as a third choice, for anyone who does not want the
number at all. It lives there rather than in the click cycle, because a
hidden rate leaves nothing to click back with.

The rate reads as a label and behaves as a control: no button chrome, the
affordance on hover, and a focus ring for the keyboard.
caption.js took a hard-coded 37 from three separate call sites. It takes
the user's choice now, defaulting to 32, which reads more comfortably
than what shipped.

The generator wants a maximum AND a minimum — the minimum is where a
mid-sentence break becomes allowed, so a minimum at or above the maximum
makes a break impossible. One helper derives the pair: the shipped 21 is
kept wherever there is room for it and follows the maximum down when
there is not, so 16 characters a line is still a working setting rather
than a jam.

The field clamps between 16 and 80, and an emptied one gives the default
back rather than the tightest wrap available. The setting applies to the
next generation, not retrospectively, so hand-edited captions are left
alone — which is the rule the caption editor already works by.
The modal had grown past a screenful, with Application — the version,
storage, the escape hatches — last, under two groups of preferences. It
leads now, open, and all three sections are <details>, with Playback and
Captions collapsed until asked for. <details> brings the marker, the
keyboard and the semantics with it, so there is nothing to wire.

The reading-rate hint drops its last sentence: the click is discoverable
from the rate's own tooltip, and the hint was explaining one control in
the margin of another.
The rate had nothing to judge it against, so the standard had to be held
in the reader's head on every cue. Settings gains a limit per measure —
17 characters per second, Netflix's figure for English, and 180 words per
minute, the upper end of broadcast practice — because the two numbers do
not convert cleanly into one another.

A caption over its limit turns red and bold, and its tooltip says which
limit it passed, so the warning survives a colour-blind reader and a
monochrome screenshot. Advisory only: nothing is blocked and nothing is
rewritten. A limit of zero keeps the number and drops the judgement, and
turning rates off takes the flag with them.

Judged on the number as SHOWN rather than the one behind it: a caption
reading 17.0 flagged against a limit of 17 looks like a bug, and arguing
that it was really 17.04 helps nobody.

Expect it to fire: ten of the intro's nineteen cues are over 17 CPS. That
is not the warning misfiring — our cues last exactly as long as the
speech, while the standards assume a cue padded into the silence after
it. #640 is where that padding is proposed.
Three collapsible sections had grown long enough that Settings opened as a
scroll rather than a page. Application, Playback and Captions are now tabs,
using the CSS-only radio idiom the Transcribe modal already uses: hidden but
focusable radios, labels as the tab strip, panels shown by a :checked sibling
selector. No script, and arrow-key movement comes free with the radio group.

Application stays first and selected — version, storage and the escape
hatches are what someone opening Settings is usually after.

The dead <details> styling goes with it; the first row of a panel now loses
its top border by position rather than by following a summary.
The pill switch was a second tab style in an app that already has one, so
Settings now uses the lifted tabs the Transcribe modal uses for its engines:
the radio inputs are the tabs, DaisyUI shows the checked tab's panel, and the
keyboard comes with the radio group.

Captions moves ahead of Playback, which holds one setting.

The panel is a fixed 24rem and scrolls inside, so the modal stays exactly
where it is as tabs change rather than growing and shrinking under the
pointer. The box widens to 32rem, which stops the caption rows wrapping into
three lines and is what lets every tab fit that height.
@maboa
maboa merged commit 4a92728 into main Sep 17, 2026
1 check failed
@maboa
maboa deleted the release/1.3.19 branch September 17, 2026 14:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Warn when a caption's reading rate goes over the limit Show each caption's reading rate in the caption editor, in WPM or CPS

1 participant