World¶
Purpose¶
World is the central authority of the ECS.
It owns and coordinates:
- entity lifecycle
- archetypes and component storage
- queries
- deferred structural commands
- system execution
There is exactly one World instance per ECS context.
Construction¶
Side effects¶
- Initializes an empty entity pool
- Initializes archetype storage
- Initializes command buffer
- Initializes system list
Entity Lifecycle API¶
spawn(): Entity¶
Creates a new entity immediately.
- Allocates a new entity id
- Marks entity as alive
- Places entity in the empty archetype
spawnMany(...items: ComponentCtorBundleItem[]): Entity¶
Creates a new entity along with its initial components immediately.
...items: ComponentCtorBundleItem[]is the list of components to add to the newly created entity.- Internally, it iterates over the items and calls
addfor each component.
despawn(e: Entity): void¶
Immediately removes an entity.
- Invalidates the entity handle (
genmismatch) - Removes the entity from its archetype
- Frees the slot for reuse
Throws if:
- entity is stale or not alive
despawnMany(entities: Entity[]): void¶
Immediately removes multiple entities.
entities: Entity[]is the list of entities to despawn.- Internally, it iterates over the array and calls
despawn(e)for each entity.
isAlive(e: Entity): boolean¶
Checks whether an entity handle is still valid.
Component API¶
All component types are identified by constructor identity.
has<T>(e: Entity, ctor: ComponentCtor<T>): boolean¶
Checks if an entity has a component.
get<T>(e: Entity, ctor: ComponentCtor<T>): T | undefined¶
Returns the component value or undefined.
- Does not throw if missing
- Returns
undefinedfor stale entities
add<T>(e: Entity, ctor: ComponentCtor<T>, value: T): void¶
Adds a component to an entity.
- Structural change
- Moves the entity to a different archetype
Throws if:
- entity is stale
- component already exists
- structural changes are forbidden (see iteration rules)
addMany(e: Entity, ...items: ComponentCtorBundleItem[]): void¶
Adding multiple components to an existing entity.
e: Entityis the target entity....items: ComponentCtorBundleItem[]is the list of components to add.- Internally, it loops through the items and calls
addfor each component.
remove<T>(e: Entity, ctor: ComponentCtor<T>): void¶
Removes a component.
- Structural change
- Moves the entity to a different archetype
Throws if:
- entity is stale
- component does not exist
- structural changes are forbidden
removeMany(e: Entity, ...ctors: ComponentCtor<any>[]): void¶
Removes multiple component types from an entity.
e: Entityis the target entity....ctors: ComponentCtor<any>[]is the list of component constructors (types) to remove.- Internally, it loops through the ctors and calls
removefor each one.
set<T>(e: Entity, ctor: ComponentCtor<T>, value: T): void¶
Updates an existing component value.
- Non-structural
- Does not change archetypes
Throws if:
- entity is stale
- component does not exist
Query API¶
query(...ctors): Iterable<QueryRow>¶
Iterates entities that contain all requested components.
Properties¶
- Iterates archetypes, not entities
- Components are returned as
c1,c2, … in argument order - Query iteration locks structural changes
Structural Change Rules¶
While iterating a query or running systems:
- ❌
spawn,despawn,add,removeare forbidden - ✔️
get,set,hasare allowed
Violations throw a runtime error.
Command Buffer API¶
cmd(): Commands¶
Returns a command buffer for deferred structural changes.
Commands are queued, not applied immediately.
flush(): void¶
Applies all queued commands.
- Safe to call after queries
- Automatically called by
update()andSchedule
System API¶
addSystem(fn: SystemFn): this¶
Registers a system.
Systems are executed in insertion order.
update(dt: number): void¶
Runs one ECS frame.
Execution order:
- Run all systems
- Flush deferred commands
Events API¶
emit<T>(key: ComponentCtor<T>, ev: T): void¶
Emits an event of type T into the current phase write buffer.
events<T>(key: ComponentCtor<T>): EventChannel<T>¶
Returns the event channel for key, creating it if missing.
drainEvents<T>(key: ComponentCtor<T>, fn: (ev: T) => void): void¶
Drains readable events for the given type.
Behavior
- If the channel doesn’t exist yet, it’s a no-op (does not allocate/create)
clearEvents<T>(key?: ComponentCtor<T>): void¶
Clears readable events.
- If
keyis provided: clears that event type’s read buffer - If omitted: clears the read buffers of all event types
swapEvents(): void (internal / schedule boundary)¶
Swaps all event channels’ buffers. Called by Schedule at phase boundaries.
Required schedule behavior At each phase boundary:
Internal Guarantees¶
- Archetypes use Structure of Arrays (SoA)
- Entity handles are generation-safe
- Component lookups are O(1) per archetype row
- Queries are archetype-filtered, not entity-scanned
Error Conditions (Summary)¶
| Operation | Error Condition |
|---|---|
| add / remove | during query iteration |
| add | component already exists |
| remove | component missing |
| set | component missing |
| any | stale entity |
Design Constraints¶
- Single-threaded
- No automatic conflict detection
- No parallel systems
- No borrowing model
These are intentional for simplicity and predictability.