--- title: RFC — Reference-grade typography engine (eidos) type: rfc audience: human + agent status: implemented — phases 1-5 closed source: migrated from src/uix/eidos/TYPOGRAPHY_ENGINE_RFC.md (2026-07-02, docs-book F7.4) --- # RFC — Reference-grade typography engine (eidos) > **Status: PROPOSAL (2026-06-05), since implemented — see §10.** Plan to raise > eidos typography to par with or above the reference frameworks, replicating > the color approach ([`rfc-color-engine.md`](./rfc-color-engine.md)): audit → > compare → extend ADDITIVELY behind the frozen token contract, in phases. ## 1. Current state (audit) `TypographyPrimitiveSet` (`lib/primitives/typography.ts` + `config-types.ts`) → emission in `render-css.ts` → tokens → the `` / `` / `` components. - **4 families** (primary Instrument Sans · secondary/display Lora · mono Azeret Mono). - **8 sizes** `xxs 10px … xxxl 80px`, each with **fixed px** `size` / `lineHeight` / `letterSpacing`. - **4 weights** (400/500/600/700). - **13 named styles** (hero, h1–h6, body, prose, label, caption, code), some with per-breakpoint responsive size (`{ base, md }`). - **`--scaling` axis** (global zoom 90–110%) multiplying the px. - Tokens: `--font-family-*`, `--font-size-*` (`calc(px * --scaling)`), `--font-line-height-*`, `--font-letter-spacing-*`, `--font-weight-*`, `--style-{name}-*`. - **Measurement arm**: the `canvas-text` engine (``) counts exact lines replicating the browser (productionized — see `lib/canvas-text/fix-stext.md`). **Good today**: named semantic styles, responsive sizes, the scaling axis (uncommon), token contract + theming, exact line measurement. ## 2. Comparison against the reference (the gap) | Capability | Reference | Eidos today | | --------------------------------------------------- | -------------------------------- | ----------------------------------- | | **Fluid** typography (viewport `clamp()`) | Utopia, Carbon, Tailwind(opt) | ❌ fixed px + manual breakpoints | | **Variable fonts** (1 file, wght + opsz) | Material 3, Apple | ❌ static TTF per weight | | **WOFF2 + subsetting + metric fallback** (anti-CLS) | Next/Fontaine | ❌ TTF, no subset, no `size-adjust` | | **Optical sizing** (`opsz`) | Apple, Material | ❌ | | **Per-size tracking** (optical) | Material, Apple, Radix | ❌ all `0` | | **`text-wrap: balance`/`pretty`** | Tailwind, Chakra | ❌ | | **Measure** (line width ~65ch) | classic, Tailwind prose | ❌ | | **`font-feature-settings`** (tabular-nums…) | Tailwind, Radix | ❌ | | Named styles · scaling axis | Chakra/Material · Apple(partial) | ✅ | ## 3. Inclusion model: extend, don't replace **Guiding principle (identical to color)**: everything new is **ADDITIVE** over `TypographyPrimitiveSet`, behind the **frozen token contract**. The old (fixed px) keeps working; the new activates via config. Token names (`--font-size-X`, `--style-Y-*`) **do not change** — only the _value formula_ changes (just as in color the `--scale-*` token went from hex to `oklch()` without renaming). Implementation layers, parallel to color: | Piece | Where | Color analog | | ------------------------------ | ------------------------------------------------ | -------------------------------- | | Pure math (Utopia fluid scale) | `eidos/lib/type-scale.ts` (pure) | `arts/color` / `build-scheme.ts` | | Type + config | `config-types.ts` (`TypographyPrimitiveSet`) | `EidosConfig` | | CSS emission | `render-css.ts` (`appendTypographyDeclarations`) | `appendColorScaleDeclarations` | | Fonts | `themes/fonts.css` (woff2/variable) | `themes/base` (palette) | | Components | `` / `` (new props) | `