An entity is an opaque ID with at most one component of each type. spawn
creates one component-bearing entity; add attaches another component. A
system selects component types and gives its callback typed, mutable bindings
for each match. This is the step from value to type to ECS: the type owns
state and behavior, while the system owns the update schedule.
Schedule a component
Compile the counter fixture, then use Step and Finish. init prints
init once for the matching counter, the first step appends 1, and done
prints once when Finish completes. Reset starts a new run at tick zero.
Results
No output.
- Executed source spans appear here.
system Tick of Counter selects one component and addresses it as self.
system Rotate of (spinner: Spinner, pose: Transform) selects entities with
both distinct concrete types and names the bindings. A successful callback
writes every changed binding back together. Misspelled fields and wrong method
arguments fail compilation; there is no string lookup or cast. A single
selector may name a trait, but trait joins and optional components are not
implemented.
Lifecycle and world access
frame(dt) is required. init() runs before the first frame for each matching
tuple, and done() runs when an initialized tuple is removed or the host
finishes the run. entity, time, and tick identify the current match and
simulation clock. despawn is deferred to the callback or action boundary, so
teardown sees committed values and a removed entity receives no later frame.
Outside a system, use get[T](entity) to copy a statically selected component,
edit the copy, and set(entity, copy) to persist it. query[T]() returns
stable entity IDs, while has[T](entity) tests membership. add attaches a
missing component. Invalid world operations remain runtime checks.
Systems run in linked source order, imported modules before their importers. Each system snapshots its matches at the start of its visit and traverses them by entity ID. Later systems see accepted changes from earlier systems; no systems run in parallel.
Edit exercise
Change the increment in Counter.advance from 1 to 2. After two steps,
the inspected counter value should be 4; Finish should still invoke done
once. Replace the frame callback’s dt: Number with dt: Bool and compilation
should report the required lifecycle signature.
Initialization, actions, ticks, and finish are transactions. A failed operation rolls back component edits, globals, logs, entity IDs, and lifecycle membership. The language reference has the exact ordering and runtime rules; the built-in catalog documents ECS operations.