UI overhaul: labels instead of essays, and a deck you can read - #29
Merged
MyNamesEMurray merged 7 commits intoSep 7, 2026
Merged
Conversation
Every page had grown its own version of the same handful of patterns, and the settings page had grown something worse: controls whose entire explanation was crammed into the <label>, five to seven lines each. That is documentation wearing a UI's clothes, and it buries the one control a streamer opened the page for. theme.css gains `.setting` + `.why` (a short label with the paragraph folded into a closed disclosure), `.section`, `.card-head`, `.seg`, `.empty-state`, `.toolbar`/`.spacer` and `.kbd`. Buttons no longer wrap their labels, which is what turned "Say something" into two lines on the deck. DESIGN.md gains the two principles these encode: labels, not essays -- depth on demand rather than depth by default; and nothing in the app is only a colour, since the deck's status orbs currently drop their labels on a narrow window and leave four unreadable dots behind. Groundwork for the page-level overhaul that follows. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LWa54BF5RjHWC5GFaENZMM
The wizard is the first thing a new user sees, and it was asking them to
walk six anonymous dashes with no idea how many were left or what "Next"
was about to commit to. The progress bar is now a named rail (Goal ·
Ghost · Brain · Stream · Energy · Extras) with ticks behind and a step
counter, and the button says where it goes ("Next: your stream",
"Finish setup") next to a note that nothing is saved until the end.
The choice cards were only ever a faint tint when selected, which is a
colour carrying meaning on its own. They are radios now, with a check
mark, arrow-key movement between them, and the aria roles to match.
Failures used to be a scrap of red text under a button, sometimes raw
provider JSON: `connect ECONNREFUSED 127.0.0.1:4455` is not something to
show a streamer. Errors are callouts that say what to do about it, and a
refused connection reads as a sentence.
The overlay's compact theme was genuinely illegible over a bright scene
-- two soft shadows under white text on white video. It has a real halo
now. That halo then bled into the AI badge and filled in its letters, so
the badge opts out of it: the badge carries its own contrast and stays
pixel-identical to the deck's, as the ethics guarantee requires. The
watermark was strengthened only -- full white on a bordered plate that
can never be squeezed -- and the card theme, which was fine over every
backdrop tested, was left alone.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LWa54BF5RjHWC5GFaENZMM
Most controls on this page carried their entire explanation inside the <label> -- five to seven lines each, four stacked in a row on the Voice tab. Everything was equally loud, so the one control you opened the page for was the hardest thing to find. All 16 paragraph-labels become a short label, a one-line hint, and the control, with the original prose kept verbatim behind a "why?" disclosure. Nothing was deleted: that writing is the only documentation some users will read, it just isn't what they need while a stream is live. Tabs are now sections with real headings, and Voice in particular went from one five-part scroll to Where speech comes from → How the cast handles what you say → Accuracy → Second channel, with the channel a streamer sets up once sitting last instead of level with the mode they change often. Fixes along the way: the save bar was fixed-position over the content and hid the bottom of long tabs, and is now sticky in flow; the shell was a narrow column in a wide window, so hints wrapped in a 30-character gutter; the level toggle floated in the header far from the nav it changes, and now sits at the top of that nav saying what it hides. The Simple/Advanced split was also wrong in a way that mattered: the Twitch channel name was Advanced-only while "pull game + title from Twitch" was Simple, so the Simple setting depended on a field you could not see. Machinery (cadence seconds, ports, thresholds, backoffs) moved out; the channel name moved in. The "why?" summaries were styled at --faint, where they read as leftover markup rather than an affordance, so they sit at --dim now. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LWa54BF5RjHWC5GFaENZMM
At 1440 the ghosts' messages hugged the far left and yours the far right, so reading your own chat meant sweeping across the whole monitor. The conversation is a contained, centred column now, with the speaker sides kept inside it. Consecutive messages from one author group under a single header, so three lines of chrome no longer carry one line of chat. The 🤖 AI badge does not group: it moved onto the bubble itself, trailing the message text, so every cast message still carries it exactly as before. That is the product's ethic and it does not bend for layout. The cast rail dropped the four-times-repeated "watching" and the heavy ring around every tile; a ghost's hue is still unmistakably theirs, and the loud treatment is saved for the one that is actually doing something. Rail status is one line that cannot reflow the tiles beneath it. Also fixed: "Say something" wrapped onto two lines next to Pause; the status orbs dropped their labels below 1180px and left four unreadable coloured dots behind, which is status carrying meaning in colour alone; cost printed three decimals, and rounded anything under a cent to $0.00; and the empty state was a small mark floating in a large void. Moments lead with ✨ as the icon table says they should. The page's private copies of .seg and .kbd are gone in favour of the shared ones. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LWa54BF5RjHWC5GFaENZMM
The copy explains too much of the wrong thing. Not the app-specific parts -- that speech-to-text invents filler during silence, or that image cost scales with resolution, are things a smart user cannot guess -- but the sentences that explain nothing: "fill in the one that matches your mode", "paste the path -- either works", "read these out loud at your normal streaming volume", and "applies live on save" repeated down a dozen rows until it reads as noise. Principle 11 makes the rule explicit rather than fixing the instances and letting them grow back: explain what is specific to this app or genuinely surprising, and nothing else; say it once; treat reassurance as padding. The copy passes that follow are held to it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LWa54BF5RjHWC5GFaENZMM
The wizard told a new user the price of the Claude API three times on one screen -- in the provider dropdown, in the hint under the key field, and again in "what does this cost me?" -- and promised that everything is changeable later four separate times. The deck's tooltip on a transcribed line stated one fact twice and then reassured them about it. 32 strings tightened, 5 deleted. Gone: "Just looking?", "Good pick --", "100% locally", "Entirely optional, and read-only either way", a title="Command palette" on a button labelled Commands, and a note explaining that "Finish setup" finishes setup. What stayed is what a smart user cannot guess: that an outdated LocalVocal can crash OBS, that screenshots go to the brain provider and nowhere else, that Twitch access never touches their chat or metrics. The local-model note actually got a fact it was missing while getting shorter -- nothing leaves your PC, but the model shares your GPU with the game -- because that trade-off is the whole decision and the wizard wasn't saying it. The pitch under the title now shows on step one only. It is there to sell the doorway; from step two the rail says where you are, and the line is one the reader has already read five times. The overlay needed nothing: its only prose is the watermark, which is fixed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LWa54BF5RjHWC5GFaENZMM
41 strings tightened, 5 deleted. The deletions are all the same shape: a hint that restated the label above it or the two field labels below it, and "fill in the one that matches your mode", which tells a reader nothing they cannot see. "Applies live on save" appeared three times plus its own section heading. It survives once, on the Behavior card where cadence tuning makes it the point, and Word fixes gets the better fact instead -- live from the next line you speak, which is when it actually bites. The text-to-speech "why?" repeated the SAPI-versus-browser distinction verbatim from the hint two rows below it; it now carries only what is unique to it. The game screen guide opened by re-explaining its own label and then said the same thing twice more; it opens on the concrete list now and keeps every real fact. Two things were kept against the brief, deliberately. "Either way they read it: unanswered speech is still in the transcript" stays, compressed to a clause -- without it a reader concludes that ticking the box makes the cast deaf, which is wrong and changes the setting they pick. And the engine-mode why stays long because every clause in it is behaviour you cannot infer from two fields. The About tab is untouched, as is every line about where the API key lives, audio never leaving the machine, and Twitch being read-only. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LWa54BF5RjHWC5GFaENZMM
MyNamesEMurray
deleted the
claude/live-mic-transcription-accuracy-x5ptio
branch
September 7, 2026 02:01
5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A full pass over all four pages for distribution polish, driven by screenshots of the running app rather than by reading markup. The theme was already coherent; what was wrong was density, hierarchy, and a handful of things that were simply broken at sizes nobody had looked at.
Changes
Shared components first (
theme.css,DESIGN.md). Each page had grown its own copy of the same patterns, so the pass starts by settling them:.setting+.why(a short label with its explanation folded into a disclosure),.section,.card-head,.seg,.empty-state,.toolbar,.kbd. DESIGN.md gains the two principles these encode — labels, not essays (depth on demand, not depth by default) and nothing in the app is only a colour.Settings: documentation turned back into a UI. Most controls carried their whole explanation inside the
<label>, five to seven lines each, four stacked in a row on the Voice tab. All 16 paragraph-labels became a short label, a one-line hint, and the control, with the prose kept verbatim behind 24 "why?" disclosures — nothing deleted, just not shouted while a stream is live. Tabs became sections with real headings; Voice went from one five-part scroll to Where speech comes from → How the cast handles what you say → Accuracy → Second channel. The Simple/Advanced split was also wrong in a way that mattered: the Twitch channel name was Advanced-only while "pull game + title from Twitch" was Simple, so a Simple setting depended on a field you could not see.The deck: a conversation instead of a wall. The column is contained and centred instead of spanning the monitor, consecutive messages group under one header, and the cast rail dropped the four-times-repeated "watching" and the ring around every tile. The 🤖 AI badge deliberately does not group — it moved onto the bubble, trailing the text, so every cast message still carries it.
The wizard got a map. Six anonymous dashes became a named rail with ticks and a step counter; "Next" says where it goes; choice cards became real radios with a check mark (they were previously selected by a faint tint alone); and errors became callouts that say what to do instead of showing raw provider JSON like
connect ECONNREFUSED 127.0.0.1:4455.Real defects fixed along the way: the settings save bar was fixed-position over the content and hid the bottom of long tabs; the deck's status orbs dropped their labels below 1180px, leaving four unreadable coloured dots; "Say something" wrapped onto two lines; cost printed three decimals and rounded anything under a cent to
$0.00; and the overlay's compact theme was genuinely illegible over a bright scene (white text, two soft shadows, white video) and now has a proper halo.Verification
node --checkover every JS file,config.example.jsonparse,npm test(161 pass, 0 fail, 1 pre-existing Windows-only SAPI skip),npm run smoke→ SMOKE OK.data-pathset is byte-identical to the previous revision, every pre-existing id still resolves, and a save round-trip was verified for one control per tab..badge-ai(11/11 and 9/9 in two runs), plus 3× zooms proving the badge is legible against all four ghost colours at both font scales. Send, energy drag, room switch, pause/resume and the command palette all still work.GET /favicon.ico404.Risk & rollout
src/is untouched by this PR..badge-aicomponent at the same size and contrast on every surface — it moved position on the deck and opted out of the overlay's new text halo, both so it stays more legible, never less. The "simulated viewers, not real people" watermark was strengthened only: full white on a bordered plate that can never be squeezed, same size, same position, same copy, still unconditional.data-pathcheck and the per-tab round-trip, but a second pair of eyes on that file is worth it./favicon.ico404s on every page load, and/api/configserves stale in-memory config after a non-hot save undernpm run serve(the Electron host relaunches, so this only bites headless).Checklist
npm run smokepasses locally (or CI is green)main🤖 Generated with Claude Code
https://claude.ai/code/session_01LWa54BF5RjHWC5GFaENZMM
Generated by Claude Code