You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte-kit-vice/docs/rfcs/rfc-scaling.md

5.1 KiB

title type audience status source
RFC — The `scaling` axis (global zoom), separate from density rfc human + agent implemented migrated from src/uix/eidos/SCALING_RFC.md (2026-07-02, docs-book F7.4)

RFC — The scaling axis (global zoom), separate from density

Status: ✅ IMPLEMENTED. (designed 2026-06-01 · implemented 2026-06-02) Born from P1-2: density-driven typography (content-scale) was wrongly framed. Density and zoom are different things; this RFC introduces zoom as its own axis.

Code: lib/config-types.ts (SCALING_KEYS / ScalingKey / DEFAULT_SCALING), lib/primitives/static.ts (STATIC_SCALING), lib/render-css.ts (appendScalingDeclarations / appendScaledMetricDeclarations / renderScalingBlocks), active-eidos.svelte.ts (scaling / scalingSource / getScaling() / data-scaling). Doc consolidated in theming/reference.md §23. --density-scale and --density-content-scale were removed in this sprint.

0. Motivation

scaling in Radix Themes (90/95/100/105/110%) is a global zoom that scales space, typography, heights and line-box with ONE factor — accessibility/zoom, not density. Eidos had a dead --density-content-scale (±4%) that tried to scale typography under the density axis, which conflates density with zoom:

  • Density (compact / comfortable / spacious): tightens layout (space + control height), text stays stable (legibility — Material/Carbon). Already done.
  • Scaling (this RFC): zoom — scales the px metrics including typography.

The two axes are orthogonal and compose (you can have compact + 110%).

1. Decisions

  • Discrete, Radix parity: 90 / 95 / 100 / 105 / 110 (%). Default 100. Projected as [data-scaling='90'] (blocks, cacheable) + --scaling.
  • Scales (px): font-size, space, control-height, icon-size.
  • Does NOT scale:
    • line-height → it is a unitless ratio (1.45…); it already scales via the scaled font-size. Multiplying it would double the effect (bug). Exclude.
    • border-width (crisp 1px), radius (independent — as in Radix), shadow, z-index, opacity, motion. Exclude.
  • Composition with density (multiplicative) on the 2 shared metrics: --space-N: calc(base × var(--density-space-scale) × var(--scaling)), --control-height-N: calc(base × var(--density-control-scale) × var(--scaling)).
  • Prune --density-scale (master) + --density-content-scale: they were the half-baked attempt at what this axis does properly. Reconciles §20.1 (density = stable text; scaling = zoom includes text).

2. Design

Primitive (lib/primitives/static.ts):

export const STATIC_SCALING = { '90': 0.9, '95': 0.95, '100': 1, '105': 1.05, '110': 1.1 }

Active default: 100.

Types (config-types.ts): SCALING_KEYS = ['90','95','100','105','110'], ScalingKey. The density primitive loses scale + contentScale.

Emission (render-css.ts):

  • :root declares --scaling-90: 0.9 … --scaling-110: 1.1 (constants) and --scaling: var(--scaling-100) (active).
  • Blocks [data-scaling='90'] { --scaling: var(--scaling-90); } … (the ≠100 ones).
  • font-size + icon-size move from verbatim to calc(value × var(--scaling)).
  • space + control-height add × var(--scaling) to the calc they already have.
  • line-height, radius, border, shadow, etc.: unchanged.

Runtime (active-eidos.svelte.ts): new scalingSource (get/onChange, mirror of densitySource); apply() writes data-scaling on the host (next to data-mode / data-density); dispose() cleans it up. EIDOS_SCALING_ATTR.

Contract (contract.ts): emits --scaling + the constants as knobs.

3. Conflicts (resolved)

Point Resolution
Density × scaling on space/control-height Multiplicative composition in the calc. Orthogonal in intent.
line-height (ratio) Do NOT scale — scales via font-size.
radius/border/shadow/z/opacity/motion Do NOT scale (Radix parity + correctness).
Dead --density-scale + content-scale Pruned — superseded by this axis.
size prop Orthogonal — size picks the tier, scaling multiplies the tier's value. Composes.
Browser zoom Composes multiplicatively (both px). App-level, distinct.
§20.1 (typography doesn't scale with density) Still true — density doesn't scale it; scaling does. Two axes.

4. Implementation plan

  1. STATIC_SCALING + remove scale/contentScale from STATIC_DENSITY.
  2. Types (SCALING_KEYS/ScalingKey; adjust DensityPrimitiveSet).
  3. render-css: scaling emission + blocks + × var(--scaling) on the 4 families; prune density scale/content-scale emission.
  4. ActiveEidos: scalingSource + data-scaling + cleanup.
  5. contract: scaling tokens; remove density scale/content-scale.
  6. Regenerate generated/base.css.
  7. Tests: update the shape of --space-4/--control-height (× scaling); scaled font-size test; [data-scaling] block; scalingSource test.
  8. Verify (check + vitest src/uix/eidos + browser) + doc in theming reference.

Powered by TurnKey Linux.