Skip to content

Archetype Storage

An archetype entity component system groups entities by their exact set of components. Every distinct component set identifies a table, and every component stored by that table has a contiguous column.

SIECS uses this model to turn an ECS query into iteration over matching tables instead of repeated lookups across unrelated component stores.

Consider three entities:

Entity Components Archetype
Player Position, Velocity, Health Moving actor
Enemy Position, Velocity, Health Moving actor
Tree Position, Health Static actor

The player and enemy share one table because they have the same component set. The tree belongs to another table because it does not have Velocity.

An entity handle identifies a row in one of these tables. The handle is stable while its storage location may change.

Conceptually, the moving-actor table is laid out as separate arrays:

entities: [player, enemy, ...]
Position: [p0, p1, ...]
Velocity: [v0, v1, ...]
Health: [h0, h1, ...]

A query for Position and Velocity can process those columns sequentially. It does not need to visit unrelated entities or perform one component lookup for every row.

Tags are zero-sized components. They participate in the archetype identity and query matching without adding a data column.

A persistent SIECS query records the table identifiers that satisfy its terms. Iteration then returns one matching table batch at a time:

ecs_query_id_t moving = ecs_query({
.components = {
ecs_inout(Position),
ecs_in(Velocity),
ecs_filter(Visible),
},
});

Position and Velocity produce fields. Visible only constrains matching, so it does not consume a field index.

When a compatible table is created later, the query index can associate that table with the persistent query. This keeps repeated iteration focused on matching storage.

Changing an existing component value writes into the current column. Changing the component set is different:

  1. SIECS finds or creates the destination archetype table.
  2. Shared component values move to the destination row.
  3. Added component storage is initialized.
  4. Removed component storage is discarded according to its lifecycle.
  5. The entity handle is updated to its new row.

Operations such as ecs_add(), ecs_remove(), and setting a previously absent component are structural changes. They are valid operations, but they should not dominate a hot iteration loop.

Both models can implement a capable ECS, but they optimize different work:

Concern Archetype storage Sparse-set storage
Grouping Exact component sets Usually one store per component
Query iteration Matching tables and contiguous columns Drive one component store and test membership in others
Adding/removing components May migrate a row between tables Usually updates independent component stores
Stable component sets Strong fit Also supported
Frequent structural churn More migration work Often less coupled
Batch processing Natural table batches Depends on store alignment and query strategy

This is a design tradeoff, not a universal ranking. Archetypes are a strong fit when many entities keep stable component sets and systems repeatedly process large matching batches. A sparse-set design can be attractive when independent component insertion and removal dominates the workload.

  • Keep persistent queries for repeated work.
  • Resolve query fields once per batch.
  • Update existing component values in place.
  • Apply structural changes outside tight loops when practical.
  • Use filter terms for components that affect matching but are not read.
  • Model stable state with tags without expecting tag toggles to be free.

Continue with ECS theory for the user-facing model and queries for query terms and hot-path rules.