fix(desktop): restore true zoom by scaling the root rem - #6514
Conversation
PR #5644 introduced a virtual typography rem so the Font size preference could change text without moving layout, but it also routed Cmd +/- zoom through that same px-valued token while pinning the real root at 16px. Zoom became text-only: type grew while rem-based padding, gaps, widths, and controls stayed frozen, producing cramped layouts. Give each dial one owner and let CSS compose them: - Cmd +/- once again scales the real root font-size, so every rem in the app zooms together. - The Font size preference only sets `data-font-size`; typography.css maps it to a unitless `--buzz-type-scale`, mirroring how density works. - `--buzz-type-rem` is now `calc(1rem * var(--buzz-type-scale))` — rem- relative, so it rides on top of zoom automatically. The 13 / 14 / 15px conversation contract is unchanged at default zoom. The preference module no longer does px math or knows about zoom, and the zoom hook no longer imports the preference module. Tests now assert root font-size scales and measure the composed type rem through a rendered probe instead of reading a px literal off the custom property. The inbox spec's zoomed row padding expectation moves from the frozen 4px to the correct 4.4px. Signed-off-by: morgmart <98432065+morgmart@users.noreply.github.com>
|
Same channel, same 1280×720 window, Cmd+ to 140%. Note avatars, buttons, search field, sidebar row height, composer padding. Before (main) — text-only zoomType grew; everything around it stayed at 100% geometry. After — true zoomText and layout scale together. The sidebar is scrolled to keep 100% reference (before / after are pixel-identical in layout) |
Blocking finding
That is the deterministic The production behavior I exercised looks sound: 5,308 desktop unit tests, typecheck/check, the two focused zoom/storage integration tests, and all three top-chrome zoom tests pass at this head. I found no second material issue in the changed code. |
… smoke test
The appearance smoke test read `--conversation-*` custom properties straight
off <html> and asserted on their raw strings (`calc(16px * .875)`,
`parseFloat("0.125rem")`). That only worked while `--buzz-type-rem` was a
px literal. Now that the type rem is `calc(1rem * --buzz-type-scale)` so
Cmd +/- zooms layout and text together, the raw strings are unresolved
calc text and the assertions fail deterministically in CI.
Resolve every token to px through a probe element (assign the token to the
probe's font-size, read the computed value) and assert the 13 / 14 / 15px
type contract and comfy / compact / spacious spacing as numbers, independent
of each other. This is the same approach profile.spec.ts already uses.
Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: morgmart <98432065+morgmart@users.noreply.github.com>
jedwards27
left a comment
There was a problem hiding this comment.
:bot: Jude’s code review agent — approved at head 8555bafa3ef9247ccfbfe6e42c7ab69358e2e0a3 (base 025425591ed67518a63870316f1473ffd02dd520).
The ownership split is coherent and appropriately small:
- keyboard zoom alone owns the real root
remscale and persistedbuzz:text-scale, while pinning native webview zoom to 1; - the Font size preference owns only
data-font-sizeand its separate persisted key; - CSS composes the unitless 13/14, 1, and 15/14 type scale with root zoom, preserving the default 13/14/15 px conversation contract while scaling rem-based layout geometry;
- storage-event handling covers peer-window updates and clears, with listener cleanup intact. No competing production root-font-size writer was found in the searched Desktop source.
Validation on this exact head:
just desktop-check— pass (pre-existing unrelated Biome warnings only)just desktop-typecheck— passjust desktop-test— 5,308/5,308 passjust desktop-build— pass- focused changed-spec E2E after
pnpm build:e2e— 31/31 pass - full
pnpm test,pnpm check,pnpm typecheck, andpnpm build— pass in an independent clean checkout - applicable Desktop CI, smoke/integration shards, macOS build, and DCO — green
The regression evidence is causal rather than ornamental: restoring the old frozen-root behavior makes the inbox zoom assertion fail on root size, row padding, and gap (16px/4px/2px instead of 17.6px/4.4px/2.2px). Supplied screenshots also distinguish text-only scaling from whole-layout zoom across controls, avatars, row geometry, and spacing while retaining fixed native-chrome clearance.
Residual evidence limit: no fresh interactive real-Tauri keyboard run or fresh narrow-window screenshot was produced during review; confidence there rests on source tracing, focused E2E contracts, supplied visual evidence, and exact-head CI. No contrary evidence found. Any head change invalidates this approval pending delta review.
* origin/main: (65 commits) fix(composer): preserve caret when inserting mentions mid-message (#6531) chore(deps): update rust crate async-trait to v0.1.92 (#6094) chore(deps): update dependency sonner to v2.0.8 (#6093) chore(deps): update rust crate http-body-util to v0.1.4 (#5452) chore(deps): update rust crate http to v1.4.2 (#5451) chore(deps): update rust crate futures-util to v0.3.33 (#5448) chore(deps): update rust crate futures to v0.3.33 (#5445) chore(deps): update dependency @tauri-apps/api to v2.11.1 (#5444) chore(deps): update ubuntu:24.04 docker digest to 561618e (#5442) chore(deps): update swatinem/rust-cache digest to 6323deb (#5441) fix(desktop): restore true zoom by scaling the root rem (#6514) chore(desktop): drop unused ORIGINAL_CONTENT from empty-edit-delete spec (#6517) feat(workflows): clarify workflow setup and activation (#6470) perf(desktop): stop the Projects fan refetching on re-entry and running after leave (#6458) perf(desktop): keep the member roster off the channel-switch path (#6456) fix(deletion): allow IRSA S3 credentials (#6495) docs(nips): comprehensive NIP-FI — core + claimable profiles (EDGE/LIFECYCLE/DELEG/CONF) (#5946) fix(benchmarks): wait for scripted event delivery (#6487) Polish mobile channel navigation and message sends (#6488) Clarify huddle message destination (#6496) ... Signed-off-by: leader <71e9f2c44a6932b6772caaaccda1911d010463c3e2c6c40410b8329956046801@buzz.block.builderlab.xyz> Co-authored-by: Tom Brow <tomb@block.xyz> Signed-off-by: Tom Brow <tomb@block.xyz>
…ifications-pr * origin/main: (38 commits) fix(composer): preserve caret when inserting mentions mid-message (#6531) chore(deps): update rust crate async-trait to v0.1.92 (#6094) chore(deps): update dependency sonner to v2.0.8 (#6093) chore(deps): update rust crate http-body-util to v0.1.4 (#5452) chore(deps): update rust crate http to v1.4.2 (#5451) chore(deps): update rust crate futures-util to v0.3.33 (#5448) chore(deps): update rust crate futures to v0.3.33 (#5445) chore(deps): update dependency @tauri-apps/api to v2.11.1 (#5444) chore(deps): update ubuntu:24.04 docker digest to 561618e (#5442) chore(deps): update swatinem/rust-cache digest to 6323deb (#5441) fix(desktop): restore true zoom by scaling the root rem (#6514) chore(desktop): drop unused ORIGINAL_CONTENT from empty-edit-delete spec (#6517) feat(workflows): clarify workflow setup and activation (#6470) perf(desktop): stop the Projects fan refetching on re-entry and running after leave (#6458) perf(desktop): keep the member roster off the channel-switch path (#6456) fix(deletion): allow IRSA S3 credentials (#6495) docs(nips): comprehensive NIP-FI — core + claimable profiles (EDGE/LIFECYCLE/DELEG/CONF) (#5946) fix(benchmarks): wait for scripted event delivery (#6487) Polish mobile channel navigation and message sends (#6488) Clarify huddle message destination (#6496) ... Signed-off-by: Tom Brow <tomb@block.xyz>
…ake-fix * origin/main: (33 commits) perf(desktop): make the Projects surface render-cheap (#6460) refactor(acp): clarify agent prompt sections (#6501) Add mobile Huddles voice MVP (#6056) feat(desktop-messages): keep agents addressed across messages (#6315) fix(desktop): remove Buzz entity link previews (#6512) fix(composer): preserve caret when inserting mentions mid-message (#6531) chore(deps): update rust crate async-trait to v0.1.92 (#6094) chore(deps): update dependency sonner to v2.0.8 (#6093) chore(deps): update rust crate http-body-util to v0.1.4 (#5452) chore(deps): update rust crate http to v1.4.2 (#5451) chore(deps): update rust crate futures-util to v0.3.33 (#5448) chore(deps): update rust crate futures to v0.3.33 (#5445) chore(deps): update dependency @tauri-apps/api to v2.11.1 (#5444) chore(deps): update ubuntu:24.04 docker digest to 561618e (#5442) chore(deps): update swatinem/rust-cache digest to 6323deb (#5441) fix(desktop): restore true zoom by scaling the root rem (#6514) chore(desktop): drop unused ORIGINAL_CONTENT from empty-edit-delete spec (#6517) feat(workflows): clarify workflow setup and activation (#6470) perf(desktop): stop the Projects fan refetching on re-entry and running after leave (#6458) perf(desktop): keep the member roster off the channel-switch path (#6456) ... Signed-off-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
…ions-sync-fixes * origin/main: (22 commits) Downgrade mobile Huddles to audio protocol v2 (#6558) perf(desktop): make the Projects surface render-cheap (#6460) refactor(acp): clarify agent prompt sections (#6501) Add mobile Huddles voice MVP (#6056) feat(desktop-messages): keep agents addressed across messages (#6315) fix(desktop): remove Buzz entity link previews (#6512) fix(composer): preserve caret when inserting mentions mid-message (#6531) chore(deps): update rust crate async-trait to v0.1.92 (#6094) chore(deps): update dependency sonner to v2.0.8 (#6093) chore(deps): update rust crate http-body-util to v0.1.4 (#5452) chore(deps): update rust crate http to v1.4.2 (#5451) chore(deps): update rust crate futures-util to v0.3.33 (#5448) chore(deps): update rust crate futures to v0.3.33 (#5445) chore(deps): update dependency @tauri-apps/api to v2.11.1 (#5444) chore(deps): update ubuntu:24.04 docker digest to 561618e (#5442) chore(deps): update swatinem/rust-cache digest to 6323deb (#5441) fix(desktop): restore true zoom by scaling the root rem (#6514) chore(desktop): drop unused ORIGINAL_CONTENT from empty-edit-delete spec (#6517) feat(workflows): clarify workflow setup and activation (#6470) perf(desktop): stop the Projects fan refetching on re-entry and running after leave (#6458) ... Signed-off-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
## Summary Follow-up to block#5644. Cmd +/- had become a text-only zoom: type scaled while rem-based padding, gaps, widths, avatars, and controls stayed frozen, which produced cramped layouts (see [#buzz-frontend thread](buzz://message?channel=a410ffde-c61f-416a-96e0-c296b5f5ecc9&id=1a758115cf07b00c097f6e988553908c045165325a57637519cfa7ed9c9accec)). Root cause: block#5644 introduced a virtual typography rem so the **Font size** preference could change text without moving layout — a good decoupling — but it also routed **Cmd +/- zoom** through that same px-valued token and pinned the real root at 16px. One decision ("freeze layout") was applied to two dials that shouldn't share it. This PR gives each dial one owner and lets CSS compose them: | Control | Changes | How | |---|---|---| | **Cmd +/- zoom** | Everything — true zoom | Scales the real `<html>` font-size again (`useWebviewZoomShortcuts`) | | **Font size preference** | Text only | Sets `data-font-size`; `typography.css` maps it to a unitless `--buzz-type-scale`, mirroring how density already works | `--buzz-type-rem` becomes `calc(1rem * var(--buzz-type-scale))` — rem-relative, so it rides on zoom automatically. Resulting text px = `16 × zoom × scale × token-ratio`. The 13 / 14 / 15px conversation contract is unchanged at default zoom. Density and the type ramp from block#5644 are untouched. The preference module no longer does px math or knows about zoom; the zoom hook no longer imports the preference module. Net deletion in production code. ## Validation - `pnpm test` — 5,308 desktop unit tests - `pnpm check:px-text`, `tsc --noEmit`, biome - Playwright: `top-chrome-zoom-clearance.spec.ts` (native-chrome clearance stays fixed under root zoom), `inbox-refactor-screenshots.spec.ts` (zoomed row padding now asserts `4.4px` instead of the frozen `4px`), and both `profile.spec.ts` zoom tests (composed zoom × preference, cross-window storage reset) - Before/after screenshots at 140% zoom in the comment below --------- Signed-off-by: morgmart <98432065+morgmart@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com>



Summary
Follow-up to #5644. Cmd +/- had become a text-only zoom: type scaled while rem-based padding, gaps, widths, avatars, and controls stayed frozen, which produced cramped layouts (see #buzz-frontend thread).
Root cause: #5644 introduced a virtual typography rem so the Font size preference could change text without moving layout — a good decoupling — but it also routed Cmd +/- zoom through that same px-valued token and pinned the real root at 16px. One decision ("freeze layout") was applied to two dials that shouldn't share it.
This PR gives each dial one owner and lets CSS compose them:
<html>font-size again (useWebviewZoomShortcuts)data-font-size;typography.cssmaps it to a unitless--buzz-type-scale, mirroring how density already works--buzz-type-rembecomescalc(1rem * var(--buzz-type-scale))— rem-relative, so it rides on zoom automatically. Resulting text px =16 × zoom × scale × token-ratio. The 13 / 14 / 15px conversation contract is unchanged at default zoom. Density and the type ramp from #5644 are untouched.The preference module no longer does px math or knows about zoom; the zoom hook no longer imports the preference module. Net deletion in production code.
Validation
pnpm test— 5,308 desktop unit testspnpm check:px-text,tsc --noEmit, biometop-chrome-zoom-clearance.spec.ts(native-chrome clearance stays fixed under root zoom),inbox-refactor-screenshots.spec.ts(zoomed row padding now asserts4.4pxinstead of the frozen4px), and bothprofile.spec.tszoom tests (composed zoom × preference, cross-window storage reset)