Skip to content

Desktop: add a macOS-style display scale chooser so smaller screens fit more #2311

Description

@jaylfc

What

A display scale chooser in Settings, like macOS Displays > Scaled, so smaller screens can fit more on screen. Discrete steps rather than a free slider, previewed the way macOS does it ("Larger Text ... More Space").

Requested by Jay.

Why it fits cleanly

theme-store.ts already establishes the exact pattern this needs: localStorage persistence plus document.documentElement.style.setProperty for CSS custom properties, applied at the root. A scale setting is the same shape, so it should mirror that store rather than invent a mechanism.

There is currently no UI scale handling anywhere in desktop/src (no zoom, no root font-size scaling, no density setting), so this is greenfield rather than a refactor.

Proposed approach

Root-level CSS zoom on :root, driven by a persisted uiScale value, with discrete steps (for example 0.8 / 0.9 / 1.0 / 1.1 / 1.25) surfaced in Settings next to Themes.

zoom is preferred over transform: scale() because transform breaks fixed positioning and pointer hit-testing, which a windowing UI depends on heavily.

The real risks, all found by reading the code

These are the reason this is not a one-line change.

1. 27 viewport reads across 18 files would desync. window.innerWidth / window.innerHeight are the layout viewport and are NOT affected by CSS zoom, while layout and CSS media queries ARE. Window.tsx:50-51 derives its bounds from exactly these. Every one of those reads needs to go through a single useEffectiveViewport() helper that divides by the active scale, or window clamping, maximize and snap maths will be wrong at any scale other than 1.0.

2. JS breakpoints and CSS breakpoints would diverge. use-is-mobile.ts and use-device-mode.ts decide mobile vs desktop from window.innerWidth in JS, while CSS media queries evaluate against the zoomed viewport. Under zoom those two disagree, so the OS could style itself as mobile while behaving as desktop, or scaling down could trip the mobile breakpoint and switch the whole shell unexpectedly. This needs one deliberate decision, recorded: does scaling affect the device-mode breakpoint or not? My view is it should NOT (scale is an appearance preference, device mode is a form-factor fact), which means device-mode reads must stay on the true viewport while layout reads use the effective one.

3. Agent desktop control reads bounds. use-desktop-control.ts is how an agent reads screen geometry and drives windows. If it reports unscaled bounds while windows are laid out scaled, agent-driven window placement lands in the wrong place. Whatever coordinate space is chosen has to be the one the control API reports, and the agent manual needs updating to say which.

Acceptance

  • Discrete scale steps in Settings, persisted, applied at root, surviving reload
  • Single source of truth for the effective viewport; the 27 raw reads go through it
  • Device-mode detection explicitly decided and tested at the smallest and largest scale
  • use-desktop-control.ts reports coordinates in the documented space, agent manual updated
  • Keyboard accessible with proper labels, and the current value announced (per the project accessibility rule)
  • Verified by booting the real desktop and screenshotting at the smallest and largest scale, not by unit tests alone

Not in scope

Per-display scaling, fractional/free slider, and remembering scale per device.

Metadata

Metadata

Assignees

No one assigned

    Labels

    agentsAgent frameworks and deploymentdocumentationImprovements or additions to documentationenhancementNew feature or requestfeatureNew featurejavascriptPull requests that update javascript codekilo-auto-fixAuto-generated label by Kilokilo-triagedAuto-generated label by KiloplatformPlatform core featurestestingTesting and QA

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions