# Entity Component System

Entity Component System (ECS) is a data-oriented architecture pattern where objects are decomposed into three pieces: entities (identity), components (data), and systems (behavior). It replaces class hierarchies with composition — instead of `class Player extends Character extends Entity`, you have an entity with `Position`, `Health`, `Sprite`, and `PlayerInput` components attached, and systems that iterate over specific component combinations.

The three pieces:

**Entities** are just IDs. An entity is a `uint64` or a generation-indexed handle — it has no data and no behavior of its own. It's a tag that components hang off of.

**Components** are plain data structs. `Position{X, Y float64}`, `Velocity{DX, DY float64}`, `Health{Current, Max int}`. No methods, no inheritance, no polymorphism. Components are attached to entities at runtime and can be added or removed dynamically, changing what the entity "is" without changing its type in the language's type system.

**Systems** are functions that query for entities matching a component filter and iterate over them. A physics system queries all entities with both `Position` and `Velocity`, reads the velocity, and updates the position. A render system queries all entities with `Position` and `Sprite` and draws them. Systems don't know about each other and don't hold references to specific entities — they operate over the *set* of entities matching their filter.

## Why it works

The real payoff is memory layout. In a traditional OOP game, a `Player` object holds all its fields in one heap allocation — position, velocity, health, AI state, render data, inventory. Iterating over all positions means chasing pointers through heterogeneous objects, which is cache-hostile.

In an archetype-based ECS, all entities with the same set of components (the "archetype") are stored in contiguous arrays, one per component type. Iterating over all `Position` components is a linear scan through a dense array. The CPU cache prefetcher loves this. For systems that touch thousands of entities per frame (physics, collision, rendering), the difference can be an order of magnitude.

## Archetype-based vs sparse-set

Two dominant storage strategies:

**Archetype-based** (used by Unity DOTS, Bevy, [[ark-ecs|Ark]]): entities are grouped by their component combination. Adding or removing a component moves the entity to a different archetype table. Iteration is maximally cache-friendly; component mutation (add/remove) is more expensive because it involves a table move.

**Sparse-set** (used by EnTT, flecs pre-v4): each component type has its own sparse set mapping entity IDs to dense storage. Iteration is fast within a single component but cross-component queries require intersection. Add/remove is cheap — just insert or delete from the set.

Most modern ECS frameworks lean archetype-based because the iteration-heavy workload (game loop, simulation tick) dominates the add/remove workload in practice.

## Beyond games

ECS is native to game engines but the pattern applies anywhere you have a large collection of heterogeneous entities processed in bulk. Simulations (agent-based modeling, particle systems), robotics (sensor data flowing through processing pipelines), and data processing workflows all fit. The key question is whether your workload is "iterate over many entities doing the same operation" (ECS wins) or "do complex operations on individual objects" (OOP is fine).

[[behavior-tree]] is a complementary pattern — it handles per-entity decision logic while ECS handles the data layout and bulk processing. [[go-bt]] and [[ark-ecs|Ark]] are both Go libraries that could be combined in a game or simulation.
