ADR-002: Worker-First Execution Model
Status: Accepted Date: 2026-01-15
Context
Browser games that run on the main thread compete with DOM updates, input handling, and browser UI for CPU time. Heavy game logic or rendering work causes frame drops and unresponsive UI. We need an execution model that keeps the main thread light and allows the engine to run at full performance.
Options Considered
1. Worker thread with OffscreenCanvas (chosen)
- Game logic and rendering run in a Web Worker
- Canvas rendering is transferred to the worker via
OffscreenCanvas - Main thread handles only input capture and lightweight UI overlays
- wgpu can render directly on the OffscreenCanvas from the worker
2. Main thread only
- Simplest approach
- All rendering and logic compete with DOM
- No way to avoid jank from long frames
- No path to multithreading
3. Worker for logic only, main thread renders
- Logic offloaded but rendering still blocks main thread
- Requires serializing render commands across threads
- Adds latency between state computation and display
Decision
Adopt a worker-first execution model where the WASM game module runs entirely in a Web Worker. The HTML page transfers an OffscreenCanvas to the worker at startup. Input events are forwarded from the main thread to the worker via postMessage.
Consequences
Positive
- Main thread stays responsive — no jank from game logic
- Full CPU core dedicated to the game loop
- Path to SharedArrayBuffer threading when cross-origin isolation is enabled
- Clean separation between browser shell (HTML/CSS) and engine runtime
Negative
- OffscreenCanvas is not supported in all browsers (Safari added support in 16.4)
- postMessage has serialization overhead for input events
- Debugging is more complex — DevTools worker support varies
- Initial setup is more complex than direct canvas rendering
Mitigations
- Fall back to main-thread rendering when OffscreenCanvas is unavailable
- Input events are small and infrequent — postMessage overhead is negligible
- Provide dev mode that runs on main thread for easier debugging
- Document debugging workflow for worker-based execution
Architecture
Main Thread Worker Thread
┌──────────────────────┐ ┌──────────────────────┐
│ HTML Shell │ transfer │ WASM Module │
│ ├─ <canvas> ──────────────────→ │ ├─ sg_app │
│ ├─ Input capture │ postMsg │ ├─ sg_scene │
│ │ keydown/up ──────────────────→│ ├─ sg_render │
│ │ mouse/touch ──────────────────→│ └─ OffscreenCanvas │
│ └─ Overlay UI │ │ └─ wgpu surface │
└──────────────────────┘ └──────────────────────┘