| name | ecs-guide |
| description | Use when designing or implementing a data-oriented Entity-Component-System: archetype/bitmask storage, contiguous per-type component arrays, filter-and-batch systems, change tracking, and syncing ECS state into stateful external systems (renderer, physics). Triggers on entities, components, archetypes, systems, world iteration, component bitmasks, mirroring transforms to physics, even when the user doesn't say 'ECS'. |
Entity-Component-System Guidelines (Data-Oriented)
Architecture for a data-oriented ECS: how entities and components are stored, how systems iterate them, and how to bridge the ECS to stateful external systems (renderer, physics) without losing parallelism or cache locality. For the underlying cache/layout reasoning see data-oriented-design-guide; for the renderer the ECS feeds, see gpu-rendering-guide; for the allocators behind component storage see memory-management-guide.
Requirements
- A component is plain data (POD-ish struct); behavior lives in systems, not components.
- Storage groups entities by their set of components, so a system can walk matching components linearly.
Essentials
Gotchas
- Mirroring ECS state to an external system in a batch pass leaves a one-frame out-of-sync window: a 100 km/h car moves a full meter at 30 Hz, so a raycast fired before the mirror pass misses it. Order dependent passes accordingly.
- Adding or removing a component moves the entity's data to a different type bucket — cheap per entity, but doing it every frame (e.g. a "Changing" tag component) churns memory and shrinks batches.
- Cross-component lookups by id in a hot loop defeat the whole point; co-locate the data instead so the match needs no indirection.
- The render graph can only be extended before execution; extra viewers (shadows, reflections) are generated during execution and fold into the viewer array — don't try to register them up front.
Example
void velocity_system(tm_transform_t *td, const tm_velocity_t *vd, uint32_t n, float dt) {
while (n--) {
td->pos = vec3_mul_add(td->pos, vd->vel, dt);
++td, ++vd;
}
}
Progressive Disclosure