Skip to content

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

Proprietary software. All rights reserved.