executing-plans
executing-plans
Use when executing an implementation plan in the current session as the implementer yourself — your human partner chose inline execution, or no subagent tool is available
ecs-architectureExpert ECS (Entity Component System) architecture patterns - storage models, system scheduling, archetypes, cache-friendliness, and real-world engine comparisons.
Independent GitHub snapshot · Automated classification · Original documentation governs
ECS is a data-driven design pattern for game engines that separates entities (IDs), components (pure data), and systems (logic operating on component sets). Its core win: cache-friendly iteration over contiguous component arrays plus implicit parallelism.
struct Transform { Vec3 pos; Quat rot; Vec3 scale; };
struct Velocity { Vec3 linear; Vec3 angular; };
void moveSystem(Slice<Transform> t, Slice<Velocity> v, float dt) {
for (i) t[i].pos += v[i].linear * dt; // two contiguous arrays
}
Traditional OOP (GameObject with Actor::Update() virtual call per object) has:
ECS wins:
for loops over slices → auto-vectorizable (SIMD).dense[]: component data in entity order, tightly packed
sparse[]: entity id -> index into dense
Entities grouped by exact component signature (archetype). Each archetype owns a column array per component:
Archetype "Transform+Velocity":
entityIDs: [12, 17, 9]
Transform: [t12, t17, t9] contiguous
Velocity: [v12, v17, v9] contiguous
Many engines allow per-entity "prefab-like" dynamic storage. Choose based on:
| Factor | Sparse-set | Archetype |
|---|---|---|
| Add/remove component cost | O(1) | move entity (memcpy) |
| Iteration locality | dense per component | perfect array per archetype |
| Fragmentation | none | many archetypes = sparse |
| Simplicity | simpler | needs archetype registry |
A system declares required components: Query<Transform, Velocity>(All).
storage.contains(entity).Entity IDs filtering: any/maybe-style optional components need a "present bitset" check; optional components can iterate a second storage.
Systems schedule in a DAG respecting read/write on component storages:
TransformSystem <-> PlayerMovement <-> CameraSystem
(Velocity RW) (Transform RW) (Transform R)
After(system), Before(system) ordering; or "this system writes X so those that read X run next".ParForEach, Unity ScheduleParallel).Adding/removing components mid-iteration invalidates iterators. Rule: queue structural changes in a command buffer / deferred list applied after iteration. (Unity EntityCommandBuffer, Bevy Commands.)
Added<T>, Changed<T> filters; Unity SystemAPI.GetComponentLookup.Parent/child: store optional Parent + Children components. World-space recompute only on dirty leaf.
ECS events (collision events, input) as transient entity/component pools — event systems read then delete. Avoid per-frame entity spam; use component-versioned event queues for perf.
| Engine | Storage | Strengths |
|---|---|---|
| Unity DOTS | Archetype (Burst/Jobs) | SIMD burst, editor tooling, ECS + jobs |
| Bevy | Archetype (Rust) | safe parallelism, great ergonomics, GPU-driven |
| EnTT | Sparse-set (C++) | no-reflection, header-only, fastest add/remove |
| Flecs | Archetype+C (C/... plugins) | fast, relations, prefab support, single include |
| Machina/Garnet | sparse / arche | niche |
| Anti-pattern | Consequence |
|---|---|
| Components with pointers/references | breaks array continuity, serialization / cache |
Systems calling GetComponent<T> in a loop | pointer chase kills the approach |
| Structural changes mid-iteration | iterator invalidation / undefined |
| One giant "Stats" component | hot/cold mix, cache waste |
| Over-strict ECS religion (all kinds, even trivial) | boilerplate bloat |
| Global mutable state in systems | breaks parallel schedule / determinism |
flowchart TD
A{Per-frame hot? Many entities?} -->|Yes| B{Change component set often?}
A -->|No| C[Classic OOP ok]
B -->|Yes| D[Sparse-set storage]
B -->|No| E[Archetype storage]
E --> F{SIMD + safety via language?}
F -->|Rust| G[Bevy]
F -->|C#| H[Unity DOTS]
F -->|C++| I[EnTT / Flecs]
D --> J{Simplicity? Language?}
J -->|C++| I
Deep storage internals, scheduling, and engine-specific patterns live in:
skills/game/game-engine/ecs-pattern/SKILL.md (full deep dive: archetypes, scheduling, SIMD, benchmarks)skills/game/game-engine/ecs-pattern/references/archetype-storage-deep-dive.mdskills/game/game-engine/ecs-pattern/references/system-scheduling-pipelines.mdskills/game/game-engine/ecs-pattern/references/unity-dots-in-practice.mdskills/game/game-engine/ecs-pattern/references/bevy-ecs-patterns.mdskills/game/game-engine/ecs-pattern/references/entt-and-flecs.md