API reference

Every public class, method, and event in @codexo/exojs. Generated from source.

C

classSystemRegistry

@codexo/exojs / core / stable

Phase-dispatching registry of Systems, shared by `Scene` (as `scene.systems`) and `Application` (as `app.systems`). Each system participates only in the scheduler phases it implements (`preFrame`/`fixedUpdate`/`update`/`draw`); within a phase, systems run in ascending `order` (ties keep registration order) and are destroyed in reverse registration order when the registry is destroyed. SystemRegistrationOptions.before/SystemRegistrationOptions.after layer a dependency graph on top of `order`, additive rather than a replacement: `order`/registration sequence still decide ties among registrations the graph doesn't relate to each other. A `before`/`after` reference to a system outside the current phase - a different phase, or never registered - is silently a no-op there, not an error. A cycle throws once the affected phase list is next sorted. Structural mutations are frame-scoped: a system added during a frame - whether from outside or from another system's own callback - does not participate in any phase until the *next* frame, in any phase. Removing a system during a callback marks it inactive immediately, so it is skipped by every later phase and every later fixed step in the *same* frame; the structural delete and the single SystemRegistry.onRemove dispatch are finalized at the frame boundary, or at once if the same system is added again before that boundary. Outside a frame - before the first SystemRegistry._beginFrame or after its matching SystemRegistry._endFrame - `add()`/`remove()` apply immediately.

1
props
4
methods
2
events
Import
import { SystemRegistry } from '@codexo/exojs'

Phase-dispatching registry of Systems, shared by `Scene` (as `scene.systems`) and `Application` (as `app.systems`). Each system participates only in the scheduler phases it implements (`preFrame`/`fixedUpdate`/`update`/`draw`); within a phase, systems run in ascending `order` (ties keep registration order) and are destroyed in reverse registration order when the registry is destroyed.

SystemRegistrationOptions.before/SystemRegistrationOptions.after layer a dependency graph on top of `order`, additive rather than a replacement: `order`/registration sequence still decide ties among registrations the graph doesn't relate to each other. A `before`/`after` reference to a system outside the current phase - a different phase, or never registered - is silently a no-op there, not an error. A cycle throws once the affected phase list is next sorted.

Structural mutations are frame-scoped: a system added during a frame - whether from outside or from another system's own callback - does not participate in any phase until the *next* frame, in any phase. Removing a system during a callback marks it inactive immediately, so it is skipped by every later phase and every later fixed step in the *same* frame; the structural delete and the single SystemRegistry.onRemove dispatch are finalized at the frame boundary, or at once if the same system is added again before that boundary. Outside a frame - before the first SystemRegistry._beginFrame or after its matching SystemRegistry._endFrame - `add()`/`remove()` apply immediately.

Constructors1
new(): SystemRegistry
Methods4
Register system, returning it unchanged for fluent capture (const world = app.systems.add(new PhysicsWorld())). Adding the same object twice is a no-op. See the class docs for buffering timing. Takes ownership: the registry calls system.destroy?.() when it is removed by the registry's own SystemRegistry.destroy, in reverse registration order. remove() does not destroy - see its own docs - so a system meant to outlive this registry (e.g. an application-lifetime PhysicsWorld registered on a scene) must be remove()d before the registry that would otherwise destroy it tears down. Re-adding a system removed earlier in the same frame is not that no-op: it cancels the pending removal and registers the system again with this call's options, which is how a system changes its own order or phase selection from inside a callback. The re-registration is buffered like any other, so the system runs again from the next frame on.
destroy(): void
Destroy every remaining registered system exactly once, in reverse registration order, then clear the registry. A system already removed via SystemRegistry.remove - even if not yet structurally finalized - is not destroyed: remove() never destroys. Each system is destroyed under its own guard and the clear-and-reset tail always runs, so one throwing system can neither skip the systems after it nor leave the registry live. Systems are the extension seam, which makes a throwing destroy() the case to expect rather than a remote one. Failures are logged, never propagated - including in development, where DestroyScope.destroy rethrows an AggregateError instead. The difference is the caller: Application._disposeManagedResources invokes this method unguarded, part-way through an ordered teardown, so a throw here would strand the rendering context, audio, input, backend, platform and clocks that come after it - reinstating the very leak this guard closes.
Whether system is currently registered and eligible to run - false for a not-yet-eligible buffered add or an already-removed system.
Remove system without destroying it - never destroys. Returns true if the system was registered and eligible to run, matching SystemRegistry.has; a buffered add made earlier in the same frame is cancelled but reports false, since it never became a registration. See the class docs for the exact timing of structural cleanup and SystemRegistry.onRemove.
Properties1
size: number
Number of systems currently registered and eligible to run.
Events2
Dispatched when a system structurally enters the registry (immediately, or at the frame boundary for a buffered add).
Dispatched when a system structurally leaves the registry (immediately, or at the frame boundary for a buffered remove).
Source