ADR-0025 — A portable core: any JavaScript engine, transcribable to another language
Status: Accepted
Context
The Product Owner wants the library's mathematics to be its own (never delegated to the SVG or DOM APIs), runnable in any JavaScript engine — a browser, Node.js or another server runtime, so that heavy computation can move to a server — and simple to transcribe into another language (for instance Rust compiled to WebAssembly) if speed requires it. ADR-0005 and ADR-0014 already keep the DOM out of the core; host APIs of Node.js and language-specific behaviors were not addressed.
Decision
- The functional core (
math,geometry,model,routing,io) uses ECMAScript only: no DOM, no Node.js API, no host API (fetch,structuredClone,Intl, timers,console). Enforced byno-restricted-globalsineslint/scopes/pure-layers.ts; its tests already run in Node.js without a DOM. - Plain data in, plain data out: read-only records and arrays of numbers, strings and booleans; no class, no prototype, no closure returned, no exception (already ADR-0014 and the lint).
- Mathematical intent over JavaScript behavior: the TSDoc formula and the derivation state the mathematics; where JavaScript semantics differ from other languages (remainder sign of
%, negative indexes ofArray.prototype.at,-0,NaNpropagation), the TSDoc says which result is meant, so that a transcription reproduces the intent. - Numbers are IEEE 754 binary64 (
number), thef64of most languages;EPSILONandSVG_DECIMALSare part of the specification, not of the implementation. - One function = one formula with its source: the library can be transcribed function by function, with its tests as the acceptance suite.
Consequences
- The shell (
render,interaction,playground) stays the only place tied to a browser. - A server or worker can run the core unchanged.
- Existing functions are checked against point 3 by AUD-001 (e.g.
cyclicVertexrelies on%and.atwith negative indexes).
References
ADR-0003, ADR-0005, ADR-0014