ADR-0002 · accepted
A genre's root entry has no DOM or Three.js
Amended by ADR-0010 on 2026-11-04: a genre's root entry also holds its
GameSimulation, the runtime has a DOM-free root of its own, and a Worker or server steps a run withGameLoop, so the #25 consequence below is resolved.
Amended on 2026-11-06:
GameDriveris gone;makeGameEngine'sattachis therequestAnimationFrameadapter, see the note on ADR-0010.
A genre's simulation must run where there is no DOM: in a Web Worker, on a game server, in a test. So a genre package's root entry (content schema, content service, simulation) uses no DOM and no Three.js, and only its ./browser entry (the GameDefinition, view, input and engine) may use them. @gamekit/content follows the same rule: fetchJsonSource needs fetch, so it lives in @gamekit/content/browser (#20, finding 6).
Consequences
content,survivorsandpush-puzzleeach have atsconfig.root.jsonthat typechecks the root entry with no DOM types, andpnpm typecheckruns it. Adocumentorfetchin a root entry fails the check.corehas no DOM types anywhere. Before #20 the rule was a convention: survivors' tsconfig gave the whole package DOM types.- The check misses a Three.js import that uses no DOM type, such as
Vector3, becauseskipLibCheckhides the DOM names inside Three.js's own types. Keeping Three.js out is a convention. - #24: sound and asset loading (Web Audio,
fetch, Three.js loaders) go in./browserentries or in browser-only packages. A root entry can still hold the ids that name a sound or a model, since those are plain content. - #25: stepping a run in a Worker or on a server needs only the root entry. The runtime's
GameDriveris browser code today: it loops onrequestAnimationFrameand attaches to an element. - #26: published packages keep their
./browserexports, and root entries stay checked with no DOM types.