ADR-032 — Font and script strategy (Wave 1)
Status · Accepted Date · 2026-05-04 RFC anchor ·
docs/rfc/RFC-010.md(closed by ADR-031 + this ADR + ADR-033) Scope · Wave 1 baseline; CJK + RTL now resolved by follow-up ADRs
Context
RFC-010 OQ-2 raised three distinct script-handling concerns: CJK fonts (Wave 2), RTL layout (Wave 3 — Arabic), and Devanagari fonts (Wave 3 — Hindi). ADR-031 grouped these into waves but didn't decide the technical approach. This ADR closes the Wave 1 question and explicitly defers Wave 2 + Wave 3 to follow-up ADRs scheduled with their respective waves.
Decision
Wave 1 (Latin script — es, fr, de, pt-BR, it): no new font work.
The existing font stack — Bebas Neue (titles), Space Mono (data / HUD), Crimson Pro (editorial) — already covers the Latin-extended characters required for all five Wave 1 languages, including Spanish accented vowels (á / é / í / ó / ú / ñ / ¿ / ¡), French accents and ligatures (à / â / ç / é / è / ê / ë / î / ï / ô / œ / ù / û / ü), German umlauts and eszett (ä / ö / ü / ß / ẞ), Portuguese-BR accents (ã / õ / ç + Spanish + French overlap), and Italian accents (à / è / é / ì / í / ò / ù).
Coverage was verified against the Google Fonts canonical glyph table for each font family.
Wave 2 (CJK — zh-CN, ja, ko): resolved by ADR-044.
See docs/adr/ADR-044.md for the accepted Wave 2 decision.
Wave 3 (Devanagari — hi; Cyrillic — ru; Arabic RTL — ar): deferred.
Three separate decisions; one follow-up ADR per concern when Wave 3 is scheduled:
- Devanagari font (likely Noto Sans Devanagari, ~400 KB)
- Cyrillic glyph coverage audit of existing fonts; add Noto Sans Cyrillic if incomplete
- Arabic RTL: resolved by
docs/adr/ADR-045.md.
Rationale
Wave 1 ships zero font bytes and zero new infrastructure — translation is a content-only operation per ADR-017's locale-overlay architecture. Deferring Wave 2 / 3 decisions until they're actually scheduled avoids speculative work and keeps the surface area of this ADR honest: it documents the Wave 1 reality, not a fiction about all eleven languages.
The "deferred to follow-up ADR" language is intentional — it makes the decision-debt visible in the ADR registry and prevents Wave 2 / 3 from silently inheriting a default that wasn't actually chosen.
Alternatives considered
- Decide CJK + RTL strategy now, before Wave 2 / 3 are scheduled — premature; the trade-offs (bundle-size budget, browser support for
font-display: swap, prevalence of CSS logical properties in our tree) shift over time and benefit from being decided in context. - Pre-load Noto Sans CJK in v0.3.x to save Wave 2 work — adds ~2 MB to every user's first paint regardless of locale; rejected on bundle-cost grounds.
- Single global font stack with all scripts (e.g. Noto Sans variable family) — covers everything but loses the typographic identity of
Bebas Neue+Crimson Pro; rejected on design grounds.
Consequences
Positive: Wave 1 ships immediately with no font work; Wave 2 / 3 decision points are explicit and registry-tracked; bundle-cost stays at current baseline until a Wave 2 / 3 language is actually scheduled.
Negative: this ADR will be superseded (or extended) twice as Wave 2 + Wave 3 follow-up ADRs land; the supersession chain needs to be kept current in CLAUDE.md.
Implementation notes
- No file changes required for Wave 1 font strategy.
scripts/fetch-assets.tsalready pulls the three Wave-1-sufficient font families.- Wave 2 CJK strategy is now tracked in
docs/adr/ADR-044.md. - Wave 3 Arabic RTL strategy is now tracked in
docs/adr/ADR-045.md. sr-Cyrlgate was later documented indocs/adr/ADR-043.md.