ADR-007: Data-Oriented Design
Status: Accepted Date: 2026-01-25
Context
Web game engines traditionally use object-oriented patterns: class hierarchies for game objects, scattered heap allocations, and per-object update loops. This causes poor cache utilization, limits entity capacity to ~1,000-5,000 objects in JavaScript, and makes network serialization expensive.
The engine needed a foundational design philosophy that would enable:
- 50,000+ entities in a browser
- Sub-millisecond serialization for multiplayer
- Efficient GPU batch uploads
- Parallel system execution across workers
Decision
Adopt Data-Oriented Design (DOD) as the core architectural principle:
1. Structure of Arrays Over Array of Structures
Components are stored in contiguous typed arrays grouped by archetype, not as properties on individual objects.
- Cache-friendly iteration: sequential memory access for hot-path systems
- ~104 bytes/entity vs ~500+ bytes/object in OOP patterns
- Typed arrays enable zero-copy transfers to GPU and Web Workers
2. Systems Operate on Data, Not Objects
Systems are pure functions that iterate over component arrays. No inheritance hierarchies, no virtual dispatch.
- Parallelizable: systems with non-overlapping component access run concurrently
- Testable: pure input/output, no hidden state
- Composable: systems combine freely without class coupling
3. ECS as Central Coordinator
All game state lives in the ECS World. No parallel state stores, no shadow copies.
- Single source of truth for game state
- Delta encoding for network: diff component arrays directly
- Deterministic replay: replay command stream against ECS state
4. Batch-Oriented GPU Integration
Rendering reads component arrays directly for batch GPU uploads, avoiding per-object draw calls.
Consequences
Positive
- 50,000+ entities achievable in browser (vs ~5,000 with OOP)
- Network bandwidth reduced to 20-40% of baseline (delta encoding on typed arrays)
- Serialization 10-100x faster (0.1-0.5ms vs 5-20ms per 1,000 entities)
- Parallel system execution via work-stealing scheduler
- Uniform architecture: all packages integrate through ECS
Negative
- Steeper learning curve for developers familiar with OOP game engines
- Less intuitive debugging (data in arrays, not named object properties)
- Dynamic component addition is more expensive in archetype-based DOD
- Third-party library integration requires facade/adapter layers (ADR-004)
Alternatives Considered
- Object-Oriented with Three.js-style scene graph -- Rejected: cache-unfriendly, limits entity count
- Sparse set ECS (bitECS-style) -- Rejected in favor of archetype-based (ADR-001): sparse sets add indirection
- Hybrid OOP+ECS -- Rejected: mixing paradigms creates synchronization bugs
- WASM-first engine -- Rejected: adds compilation step, limits TypeScript ecosystem integration
Related
- ADR-001: Archetype-Based ECS -- Specific storage implementation choice
- Data-Oriented Design -- Detailed architectural explanation