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

101 lines
5.1 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

---
title: RFC — The `scaling` axis (global zoom), separate from density
type: rfc
audience: human + agent
status: implemented
source: 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`](../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`):
```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.