cmux NEXT: Inter, bundled, is the UI font everywhere, with its calculated tracking
Leo asked for Inter as the UI font with its calculated tracking and the fonts bundled in. None of it was on feat-cmux-next or main: --font-ui was never defined, pages hard-coded system-ui / -apple-system, and native chrome drew SF. This makes Inter, bundled, the UI font of cmux NEXT on both sides, with per-size tracking, and adds a check that keeps it that way.
Leo-ask: ask-52da478628
Leo-ask: ask-00b6f86024
Leo's words (ask-00b6f86024, as written): "WE ALREADY FUCKING HAD THE FUCKING FONTS WE SAID INTER WITH SOME AMOUNT AND WE FUCKING BUUNDLED SOME SHIT IN WHERE THE FUCK IS EVERYBODY WHERE THE FUCK IS THE FUCKING CI AND EFFICIENCY AND OPTIMIZATION"
What changes
-
Bundled font. Inter 4.1 from the official release (
Inter-4.1.zip, sha2569883fdd4…6b11e), unmodified:InterVariable.ttf(CoreText),InterVariable.woff2(pages) and the OFL license inCmuxNextDesign/Resources/Fonts/, with each file's sha256 inFONTS.md. The italic isn't bundled, to keep the app lean. -
One source.
schemas/type-scale/type-scale.jsongetsfont(familyInter, the TTF's own familyInter Variable, the files, the system fallback) andtracking, Inter's dynamic metrics:a + b * e^(c * size)em witha = -0.0223, b = 0.185, c = -0.1745.gen-type-scale.pywrites each step'strackinginto the JSON (4 decimals), so the table is never typed by hand:step size tracking (em) caption 11 0.0048 detail 12 0.0005 body 13 -0.0032 field 14 -0.0062 title 15 -0.0088 heading 20 -0.0167 The other recorded value is the 2026-10-19 study's flat -0.011em against SF Pro. Leo can switch to it by setting
a = -0.011, b = 0(with aLeo-order:trailer, see below). -
Web. The generator writes
--font-ui("Inter", then the system stack) and--text-<step>--letter-spacingintodesktop.css, and Tailwind'stext-*utilities carry the letter-spacing. Every cmux web view installsWebTheme.userScripts: the theme bootstrap, thenBundledFonts.pageScript, which declares Inter's@font-facefrom adata:URL (every page CSP already allowsdata:fonts). Every webviews stylesheet that named the system font now usesvar(--font-ui), and every rule sized by a type-scale step also sets that step's letter-spacing (rules with a monospace family are skipped). The chat's "system" font preset and the Markdown viewer's default body font follow--font-ui. A font the person picked (#22762's settings: chat, code, Markdown and terminal fonts) still wins. The gallery frame declares the same face. -
Native.
CheckedFontdraws the default design in Inter (BundledFonts.uiFont, with itswghtaxis set from the AppKit weight). If the font is missing it falls back to the system font.ChromeTextLayerandLabelTextadd the tracking as kern at each font's own size (em * sizepoints; 0 for any face other than Inter). The theme store's launch init registers the font and builds the page script off the main thread. -
Leo's bans.
scripts/cmux-next/check-leo-bans.py, with the pinschemas/type-scale/leo-bans.json, fails when:- the UI family, the tracking constants or the tracking table drift from the pin
--font-uidoesn't start with Inter- the Swift
TypeScalefamily or tracking, or theCheckedFontpath, isn't the bundled Inter - the bundled TTF's family isn't
Inter Variable - any webviews stylesheet names
system-ui/-apple-system/BlinkMacSystemFont - the pin changes in a range where no commit touching it has a
Leo-order: <Leo's words>trailer
It runs in
prepush-gate.pyon every push, whereCMUX_NEXT_CHECKS_SKIP_REASONdoesn't skip it, and as its own step, "Leo's bans (Inter UI font and tracking)", in thecmux-next checksjob.tests/test_leo_bans.pycovers each case and is registered intests/test-execution.toml(linux-guard) and in the checks job's script tests.
Verification
Test-first: 9251507fc143 commits tests/test_leo_bans.py before the check exists. At that commit scripts/cmux-next/check-leo-bans.py doesn't exist, so every case gets exit 2 and fails, and the pass case can't pass. The head runs it in CI: python3 tests/test_leo_bans.py (checks job, "Script tests").
Observed / Not run
Observed:
python3 -I scripts/cmux-next/check-leo-bans.py: ok on the head. At the base it reports the missing pin (and, before the stylesheet changes, 68 system-font findings).python3 -I scripts/cmux-next/check-leo-bans.py --rev HEAD --base <base>: ok, because the pin-adding commit carriesLeo-order:.python3 -I scripts/cmux-next/gen-type-scale.py --check: clean.python3 scripts/cmux-next/prepush-gate.py: no new violations.scripts/web-lint.sh(Oxfmt, Oxlint, type check and style checks on the changed webviews files): passed.cmux-ci compile-check --ref <sha> --appon the fleet passed at2c9f292920d8and again at the head,e7023990fb76.- PR CI at the head
e7023990fb76: success (glaeda-gh wait pr). That coverstests/test_leo_bans.pyand the new "Leo's bans" step in thecmux-next checksjob. - Independent review subagent: SHIP at
2c9f292920d8and again ate7023990fb76. Its should-fix items are fixed ine7023990fb76:.kernis set only for Inter, so other faces keep their own kerning, and an Inter the person already installed counts as available.
Not run here (CI runs them, since this Mac takes no test runs):
- The red run of
tests/test_leo_bans.pyat9251507fc143. Green ran in CI at the head. - The webviews bun tests I updated:
agent-pane-chat-display(the chat's measure font is now"Inter", system-ui, sans-serif) andinternal-pages-app-font(the body's font stack now starts with Inter). - The Swift suites.
- I didn't watch Inter render in a live app. The tracking values come from the formula, not from a visual check.
- Known costs, left for follow-ups:
- The page script inlines the 352 KB WOFF2 as base64 (about 470 KB of script per web view). Serving it from each page scheme would cut that.
- Native text set outside
ChromeTextLayerandLabelText(SwiftUIText,NSTextField) gets Inter without the tracking. - The native font sits at optical size 14 at every size, while the web picks the optical size per size.
Capture
Web before/after (gallery, merge-base vs this branch): https://cmux-lawrences-mac-mini.tail137216.ts.net:18796/compare/cmux-inter-ui-font/
No capture: cmux-ci capture <head> --state scene:main-showcase --pr 24100 can't build a DEV app at any current feat-cmux-next head. The fleet's web step stops on a base red: "the agent pane imports webviews/src/agent-session/acpmux/inspector/ContextSection.css but build-agent-pane-web.sh does not add it to the page's styles". That comes from #23789, and build-agent-pane-web.sh at base ca686c9badab still doesn't list the file (fleet build jobs e40b2086… and c8bb618a…). The web before/after above shows the font and tracking on every gallery state. The native chrome change shows up once the base builds again.
Changelog
- Changed: the UI font is Inter, bundled with the app, with tracking tuned per text size, in native chrome and every web page.
Agent session: cosmic-gray
🤖 Generated with Claude Code