Koder Design — Numeric spacing scale
themes specs/themes/spacing-scale.kmd
A numeric spacing scale (`--kds-space-<n>`) on a 2px base unit — the single density-aware source the KDS t-shirt spacing tokens (xs/sm/md/lg/xl), the semantic tokens (--pad-x, --gap-*), and gov.br's spacing-scale all map onto. Closes the KDS×gov.br gap (govbr-ds-parity, stack#401): KDS had a density-aware t-shirt scale but no numeric one, while gov.br publishes an explicit numeric scale.
Corpo da especificação
Numeric spacing scale
Context
KDS spacing already had a density-aware t-shirt scale
(--kds-space-{xs,sm,md,lg,xl} = calc(<px> × var(--kds-density-scale)), in the
density :root of assets/css/base.css), and the semantic tokens (--pad-x,
--gap-field, …) are integer multiples of a 2px base unit
(internal/tokens/noncolour.go). What was missing — and what gov.br's Padrão
Digital publishes explicitly — is a numeric scale (spacing-scale-*). This
spec adds the numeric scale as the single source, re-expresses the t-shirt
names as aliases of it, and documents the semantic + gov.br mappings.
R1 — The scale
--kds-space-<n> = n × --kds-space-unit, where --kds-space-unit is 2px.
The index is the multiple, so the scale faithfully names the geometry KDS
spacing already used — no value is invented. Contiguous n ∈ 0..12 (0–24px at
default density) is published in the density :root (assets/css/base.css,
served in the KDS dist tokens at https://kds.koder.dev). Larger steps extend
the SAME rule (--kds-space-16 = calc(16 × unit × scale)); the rule, not an
enumerated ceiling, is normative.
R2 — Density relation
Each step n ≥ 1 reads the density multiplier:
--kds-space-<n>: calc(<n> * var(--kds-space-unit) * var(--kds-density-scale, 1)).
--kds-density-scale is 1 default, 0.8 compact, 1.2 comfortable
(specs/themes/density.kmd R2). A surface rescales all scale-sourced spacing by
setting data-density alone. --kds-space-0 is a literal 0 (density-invariant).
R3 — T-shirt aliases (single source)
The pre-existing t-shirt tokens are aliases of numeric steps — same computed value, one source of truth (no parallel definitions to drift):
| T-shirt | Numeric | px @ default |
|---|---|---|
--kds-space-xs | --kds-space-2 | 4 |
--kds-space-sm | --kds-space-4 | 8 |
--kds-space-md | --kds-space-6 | 12 |
--kds-space-lg | --kds-space-8 | 16 |
--kds-space-xl | --kds-space-12 | 24 |
R4 — Semantic-token mapping
The semantic spacing tokens (internal/tokens/noncolour.go) are exact scale steps:
| Semantic | Scale step | px |
|---|---|---|
--pad-y | --kds-space-4 | 8 |
--gap-field | --kds-space-5 | 10 |
--pad-x | --kds-space-6 | 12 |
--gap-title | --kds-space-7 | 14 |
--pad-form | --kds-space-9 | 18 |
Migrating the semantic tokens to literal var(--kds-space-<n>) (so they too
become density-aware) is a follow-up — it changes their behavior under non-default
density, so it is deliberately separate. Until then the semantic tokens keep their
raw px (density-invariant).
R5 — gov.br cross-map
gov.br's spacing-scale maps onto even indices (its base is 8px = 4 units):
| gov.br | KDS step | t-shirt | px |
|---|---|---|---|
spacing-scale-half | --kds-space-2 | xs | 4 |
spacing-scale-base | --kds-space-4 | sm | 8 |
spacing-scale-2x | --kds-space-8 | lg | 16 |
spacing-scale-3x | --kds-space-12 | xl | 24 |
Higher gov.br steps (4x…10x) resolve through R1's extension rule
(--kds-space-16…--kds-space-40), giving the govbr DS a spacing foundation in
the KDS scale with no parallel vocabulary.
Não-escopo
- Component minimum dimensions and per-mode padding deltas —
specs/themes/density.kmdR2/R3, not here. - The semantic-token alias migration (R4) — its own slice.
- Rust/non-CSS token mirrors — the scale's canonical dist surface is the KDS CSS custom properties; a Rust mirror follows design-RFC-006 if a native consumer needs it.