Skip to content

System ​

Systems implement behavior. They declare queries (entity sets) and optional config schema (reactive signals).

createSystem(queries, schema) receives only query descriptors and optional configuration fields. Define lifecycle methods such as init(), update(), and destroy() in the subclass body, not inside the queries object.

Mental Model: Behavior that reacts to data ​

Systems are functions over sets of entities. Think of them as database stored procedures that run every frame:

text
Traditional Game Loop:           ECS System Approach:
──────────────────────           ───────────────────
for each object:                 for each relevant entity set:
  object.update(dt)                system.update(dt, entities)

Problems:                        Benefits:
- Tight coupling                 - Data/behavior separation
- Hard to optimize               - Cache-friendly iteration
- Difficult to disable          - Easy to enable/disable
- Hard to test                   - Systems are pure functions

Queries pick the rows (entities) to process; systems implement the logic of what to do with that data each frame.

Anatomy ​

ts
import { Types, createSystem } from '@iwsdk/core';

export class MySystem extends createSystem(
  {
    groupA: { required: [CompA], excluded: [CompB] },
    groupB: { required: [CompC] },
  },
  {
    speed: { type: Types.Float32, default: 1 },
  },
) {
  init() {
    this.queries.groupA.subscribe('qualify', (e) => {
      /*…*/
    });
  }
  update(dt: number) {
    for (const e of this.queries.groupB.entities) {
      /*…*/
    }
  }
  destroy() {
    /* cleanup */
  }
}

Config Signals ​

System config values are reactive signals powered by @preact/signals. Each config key is a Signal<T> at this.config.key.

ts
export class CameraShake extends createSystem(
  {},
  {
    intensity: { type: Types.Float32, default: 0 },
    decayPerSecond: { type: Types.Float32, default: 1 },
  },
) {
  update(dt: number) {
    const i = this.config.intensity.peek();
    if (i <= 0) return;
    // apply random offset scaled by i
    this.camera.position.x += (Math.random() - 0.5) * 0.01 * i;
    this.config.intensity.value = Math.max(
      0,
      i - this.config.decayPerSecond.peek() * dt,
    );
  }
}

Reading vs Tracking ​

  • .value — set and track.
  • .peek() — read without tracking to avoid incidental subscriptions.
  • .subscribe(fn) — run when the value changes.
ts
const unsubscribe = this.config.intensity.subscribe((v) => console.log(v));
// later
unsubscribe();

UI ↔ ECS Wiring ​

Config signals are ideal for developer tools and UI controls:

ts
// debugging slider
document.getElementById('intensity')!.addEventListener('input', (e) => {
  this.config.intensity.value = Number((e.target as HTMLInputElement).value);
});

Creating/Destroying Entities in Systems ​

ts
const e = this.createEntity();
e.addComponent(CompA);
e.destroy(); // remove when done

Priorities ​

Systems run each frame in ascending priority (more negative runs earlier). IWSDK registers some priorities by default when you enable features in World.create:

  • Locomotion: −5 (if enabled)
  • Input: −4 (always)
  • Grabbing: −3 (if enabled)

You control your system’s order via { priority } when registering:

ts
world.registerSystem(MySystem, { priority: -2 });

Query events and resource management ​

Use qualify/disqualify to perform one‑time setup/teardown per entity. Cache handles on the entity (e.g., via a component or a symbol) instead of recomputing every frame.

Batching and allocations ​

  • Avoid creating objects in update loops; reuse vectors/arrays.
  • Keep derived numbers in components if they are consumed by multiple systems.

Debugging patterns ​

  • Log query sizes: console.debug('N panels', this.queries.panels.entities.size).
  • Temporarily increase verbosity of specific systems with a debug config signal.

Sharing data via globals ​

this.globals is a reference to world.globals — a simple shared object store. Use sparingly for cross‑system coordination.

ts
this.globals.navMesh = myNavMesh;

Privacy | Terms