← A Voice Reader for Simply Broken
v8 · the buttonThe corner button, four ways
Amit, on the shipped dock: it is not visible enough, and it is too intrusive. Those sound like opposite complaints. They are the same complaint, and this round fixes the cause rather than splitting the difference.
Open the live previewOne fault, not two
The shipped button is a 48 px disc filled with #0E0F11. That is the
heaviest value anywhere on the page. It is darker than the body text, and it is the
only solid mass on a white sheet, so the eye goes to it whether or not the reader
wants to listen. That is the intrusive half.
When the eye arrives, the button says nothing. It carries a bare ▶
character and no word, no duration, no name. A small dark circle in a corner is the
shape of a close button, a chat bubble, a cookie notice. So the reader looks, does not
learn that the article can be heard, and looks away. That is the invisible half.
The button spends mass where it should spend meaning. Every version below makes the same trade in a different currency: it gives back the black fill and buys visibility with a word, a colour, a shape that reads as sound, or a duration. None of them is louder than the shipped one. All of them say more.
What all four keep
- The corner. Bottom-left, at
bottom:14px, level with the Notes and Edit text buttons, exactly as it is now. Nothing moves. - The behaviour of ยง21. The capsule grows into a control panel when sound starts, and it does not collapse on pause — someone who pauses is reaching for the controls.
- One audio element. The top player and the corner are two shells on the same sound. They cannot disagree about position, speed or state.
- Drawn icons. The shipped dock used the text characters
▶and×, which land at a different size, weight and baseline on every platform. That is part of why it read as chrome. These are authored SVG on one stroke.
The player at the top, and the handoff
The full player mounts in normal flow, under the date and category line and above the first paragraph. That is where the reader is already looking, and it is before they have committed to reading — which is the only moment the offer to listen is worth anything.
It does not hide itself by watching the scroll position. The corner dock watches the top player instead: while the player is on screen the dock stays down and out of the way, and the dock rises only once the player has genuinely left. One control is visible at any moment, never two, and the reader never sees the same offer twice. Scroll back up and the dock sinks again.
A scroll-offset threshold is a guess about where the player ends. It goes wrong at every width, at every font size, and on any page with a longer title. Watching the element itself is right at all of them, and it is fewer lines.
The four
Each row shows the resting corner state at its real size. The first row is what is live today, for comparison. Open any version to see its top player, scroll it away, and hear the handoff.
How to choose
The corner treatment and the top player are separate decisions. They are paired above so each version reads as one idea, but any corner can take any top bar. If B's top bar recruits best and A's corner is the quietest, that combination is one line of CSS.
| Says "listen" without a word | Weight on the page | Shows progress at rest | Footprint | |
|---|---|---|---|---|
| Now | no | heaviest | no | 56 px |
| A Byline | no, it uses the word | lightest | no | ~112 px wide |
| B Ring | partly | light | yes, the ring | 56 px, unchanged |
| C Glass | no, it uses the word | lightest, see-through | no | ~112 px wide |
| D Waveform | yes | light | no, but it moves | ~112 px wide |
What was measured
- All four were driven in a real browser at 1280 px and at 390 px, not a headless one — headless Chrome does not reflow below about 500 px and its phone screenshots are a lie.
- Sound actually plays in all four: a real mouse press on the top player starts the
file and
currentTimeis advancing a second later. A player that loads and sits at zero is the failure this check exists to catch. - No horizontal overflow at either width:
scrollWidthequals the viewport in all eight runs. - The handoff was checked in the same runs — after scrolling past the top player, the dock reports itself armed and open in all four.
- Two faults found this way and fixed: the fifteen-second icons were drawn with the numeral at a size that rendered as a smudge, and the top player was pinned to a guessed width that came up about 200 px short of the paragraphs.
Amit picked A, Byline, and asked for it everywhere the player runs.
Shipped as the one shared reader.js: the corner is the white pill with
the word on it, and the top player is the ruled byline line.
Reach, without touching any page by hand: 37 blog posts and pages, where
build.py now writes the mount under the meta line instead of after
</main>; and 33 /explore version pages, where the
reader relocates its own legacy end-of-body element to just under the lede. Four
explore pages have no lede and fall back to the h1, which is also right for them.
The other three stay on this page as the record of the round. B, C and D are each one CSS block away if the corner ever wants revisiting.