ADR-034 — Math rendering: KaTeX server-rendered at build
Status · Accepted Date · 2026-05-07 Closes · RFC-011 (with ADR-035, ADR-036) TA anchor · §components / primary-route-pages Related · PRD-008, ADR-014 (CI + GitHub Pages), ADR-016 (build-time assets), ADR-017 (i18n)
Context
PRD-008 / GitHub #39 introduce /science: an in-app encyclopedia covering ~40 physics concepts with formulas, diagrams, and prose. RFC-011 OQ-1 asked how to render math in section bodies. Four candidates: KaTeX server-rendered, KaTeX client-side, MathJax v3, hand-rolled SVG per formula. The trade-off pivots on bundle weight vs. authoring ergonomics.
Decision
Render path (RFC OQ-1 — Option A)
Use KaTeX to compile every formula_latex field into HTML at SvelteKit prerender time. The client receives static HTML + KaTeX's CSS only; the JavaScript library never ships to the browser.
Implementation:
- Add
katex@^0.16as a runtime dependency and@types/katexas devDependency. src/lib/katex.tsexposesrenderKatex(latex: string): string— server-only helper called from+page.server.tsloadfunctions during prerender.- KaTeX's CSS imported once at the science layout level (
src/routes/science/+layout.svelte) so the fonts + glyphs are available offline. - LaTeX source authored in section JSON:
{ "formula_latex": "v = \\sqrt{\\mu \\cdot (2/r - 1/a)}" }. - The SvelteKit
prerender = truedirective on/science/[tab]/[section]ensures every section is a static HTML file — KaTeX never runs in the browser.
Edge cases (RFC OQ-1 — Option D fallback)
For any formula that KaTeX cannot render (e.g. macros KaTeX rejects, custom layout), inline an SVG into the section's formula_svg field instead. Schema treats formula_latex and formula_svg as mutually exclusive optional fields.
Budget
- KaTeX CSS: ~30 KB minified gzipped, loaded once for the entire
/sciencetree. - KaTeX JS: 0 KB at runtime (server-rendered).
- Authored formulas: LaTeX strings in JSON; ~10–20 across all 40 sections.
Consequences
Positive: Authoring ergonomics of LaTeX without runtime cost. The encyclopedia can include rigorous formulas (vis-viva, Tsiolkovsky, orbital period) without inflating the JS bundle. Offline-capable per ADR-029 (PWA).
Negative: Build time grows by the cost of running KaTeX over every formula_latex field — negligible at 40 sections, observable at 400+. Edge-case formulas need a separate SVG fallback path, which costs authoring time. KaTeX's CSS adds 30 KB to first paint of /science; trivially cached after.
Implementation notes
- Renderer entry point:
src/lib/katex.ts. - Component wrapper:
src/lib/components/ScienceFormula.svelteaccepts pre-rendered HTML + caption. - Validation:
scripts/validate-data.tsensures every section with aformula_latexfield produces valid HTML at build time (compile + assert non-empty output). - Deferred: client-side render path (RFC-011 OQ-1 Option B) — kept available as a fallback if SvelteKit's prerender ever can't statically resolve a section, but never invoked in steady state.