Skip to content

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.ts already 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-Cyrl gate was later documented in docs/adr/ADR-043.md.

Orrery — architecture documentation · MIT · No tracking