Rebuild the Studio as a single-voice Liquid Glass app - #3
Open
MattModeCode wants to merge 2 commits into
Open
Conversation
The Studio was a two-column web page in bundled mono type on a flat dark field — functional, but it read as a local dev tool rather than a Mac app, and it made you pick a voice every time despite there only ever being one that mattered. Interface - Single column built around one voice. It is resolved at boot and never appears as a choice on the composing surface; enrolment, switching and the environment report moved into a Settings sheet. - Progressive disclosure: script and Generate at rest, delivery controls and prosody marks behind panes that summarize themselves when closed. - Apple Liquid Glass material — layered translucency with backdrop blur and saturation, specular top lip, depth shadows — over an ambient colour field that gives the glass something to refract. - Light and dark are both first class, each with its own glass and ink values rather than one palette dimmed. Increased contrast drops the translucency entirely and has its own dark variant. - System UI type for prose, mono kept only for numerics. The bundled JetBrains Mono files are gone; nothing referenced them any more. - ⌘↵ generates. Reduced motion, focus rings and labelled controls throughout. Structure - static/ split into tokens.css (design system), style.css (components), and ES modules api.js / format.js / app.js. - The eight /api/* routes are untouched; this is a front-end change. Desktop shell - The window painted pywebview's white default before the page loaded, which flashed on the way into a dark interface. It now launches on the interface's own canvas colour, chosen from the macOS appearance, with a test asserting the two files cannot drift apart. Verified in the browser, in the pywebview window, and in a rebuilt dist/Double Chin.app; 110 tests pass. Claude-Session: https://claude.ai/code/session_01FdWprv4TKfVzapYFJnRffz
…ve field The first pass wore Liquid Glass without earning it. Every panel was translucent, and behind them sat an animated four-pool radial gradient with a noise overlay — a synthetic backdrop invented so the blur would have something to show. That is the tell: Apple's materials blur the app's own content, and a gradient placed behind glass to make it look like glass is decoration pretending to be a material. Backgrounds - The ambient field, the grain overlay and the drift animation are gone. - Apple's grouped-content system instead: a recessed page (#F2F2F7 / #1C1C1E) with opaque cards on top (#FFFFFF / #2C2C2E), divided by .5px separators and carrying no shadow, because grouped cards in AppKit don't have one. Materials - Glass now appears in exactly the two places Apple puts it: the toolbar, which the page genuinely scrolls beneath, and the settings sheet, which sits over the page. Both blur real content. Colour and type - Semantic AppKit/UIKit values throughout — label, secondaryLabel, tertiaryLabel, separator, the fill ramp, controlAccentColor, systemGreen / Orange / Red — rather than invented ones. Two documented departures: the secondary label alpha is raised because Apple's own value measures 3.5:1 on white and fails AA, and the accent has a defined pressed shade instead of a brightness filter. - macOS type scale: 13px body, 11px secondary, 15/17px titles. Controls - AppKit metrics: 36px prominent button, 24px secondary, 8px control radius, 12px card radius, the three-point accent focus halo, a real disclosure triangle that rotates 90 degrees, and a slider whose track is a two-stop fill rather than a gradient. - History is one inset grouped list with hairline dividers, not eight floating cards. - The primary button lost its coloured glow; nothing pulses or drifts. Window - The toolbar was repeating the window title. It now shows the voice, which is information the title bar doesn't already carry. - Default size follows the content column: 820x860. - Launch colour tracks --bg-grouped; the drift test follows the rename. Claude-Session: https://claude.ai/code/session_01FdWprv4TKfVzapYFJnRffz
6 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.
The Studio worked, but it looked like a local dev tool: two columns, bundled
mono type everywhere, a flat dark background, and a voice picker you had to
answer every time despite there only ever being one voice that mattered.
This rebuilds the interior. The desktop shell, the engine, and all eight
/api/*routes are untouched — nothing here changes what Double Chin does,only what it is like to use.
The interface
Single voice. The app opens straight into composing. The voice is resolved
at boot and never appears as a choice on the main surface; enrolment, switching
between enrolled voices, and the environment report all live in a Settings
sheet. The choice persists in
localStorage, so it stops depending onwhichever voice happens to sort first. The toolbar shows the voice rather than
repeating the window title.
Progressive disclosure. At rest: a script editor and a Generate button.
Delivery controls and the prosody reference sit behind panes that summarize
their own state when closed — "Default", or "Expression 0.70 · fixed seed".
Apple's design system, not an impression of it. The first pass wore Liquid
Glass without earning it: every panel was translucent, and behind them sat an
animated four-pool radial gradient with a noise overlay — a synthetic backdrop
invented so the blur would have something to show. That is exactly the tell.
Apple's materials blur the app's own content; a gradient placed behind glass to
make it look like glass is decoration pretending to be a material.
So the ambient field, the grain and the drift animation are gone, and what is
left is Apple's grouped-content system: a recessed page (
#F2F2F7/#1C1C1E)with opaque cards on top (
#FFFFFF/#2C2C2E), divided by.5pxseparatorsand carrying no shadow, because grouped cards in AppKit don't have one.
Glass now appears in the two places Apple puts it, and only there:
Both blur real content.
Colour and type are semantic AppKit/UIKit values — label, secondaryLabel,
tertiaryLabel, separator, the fill ramp, controlAccentColor, systemGreen /
Orange / Red — at the macOS scale (13px body, 11px secondary, 15/17px titles).
Two departures, documented in the file: the secondary label alpha is raised
because Apple's own value measures 3.5:1 on white and fails WCAG AA, and the
accent has a defined pressed shade instead of a brightness filter.
Controls use AppKit metrics: 36px prominent button, 24px secondary, 8px
control radius, 12px card radius, the three-point accent focus halo, a
disclosure triangle that rotates 90°, and a slider whose track is a two-stop
fill. History is one inset grouped list with hairline dividers rather than
eight floating cards. Nothing pulses, glows or drifts.
I also tried real window vibrancy — pywebview 6.2.1 does give a genuine
NSVisualEffectViewbehind the WebView withtransparent=True, vibrancy=True— and did not ship it: it costs the window shadow, which is a bigger Mac
regression than desktop-sampling translucency is a win.
Details. ⌘↵ generates (scoped so it does not fire behind the Settings
sheet). Reduced motion, increased contrast with its own dark variant, visible
focus rings, labelled controls,
aria-liveon status regions, and nohorizontal scroll down to 520px.
Structure
static/was three files and is now six:tokens.css(design system),style.css(components), and ES modulesapi.js(endpoint wrapper),format.js(pure presentation helpers),app.js(state and wiring). Thebundled JetBrains Mono files are deleted — system type for prose,
ui-monospacefor numerics.
Desktop shell
The native window painted pywebview's white default before the page loaded — a
bright flash on the way into a dark interface. It now launches on the
interface's own background colour, read from the macOS appearance, and the
default size follows the content column (820×860). Since that colour lives in
two files, a test asserts
desktop.pyandtokens.csscannot drift apart.Fixes found while building
.scorecarried an explicitgrid-row,which took it out of auto-flow and let it claim column 1.
"chunks finished", which is zero until the only chunk lands.
<dialog>lost its centring to the global* { margin: 0 }reset.overwritefield even though the API has always accepted one.--ink, so darkmode plus increased contrast was white-on-white. (Found by
/code-review.)Test plan
pytest— 110 passed, 2 skipped (3 new tests for the launch colour)dist/Double Chin.app— styling survives PyInstaller, and thewhole
static/directory is already in the spec'sdatas, so nopackaging change was needed
strong match), plus replay from history
Not included
The README prose is updated, but
demo/studio/double-chin-studio-demo.gifandthe linked session video still show the old interface. Re-recording them is a
separate pass.
https://claude.ai/code/session_01FdWprv4TKfVzapYFJnRffz