Skip to content

World

Reference documentation for the ECS World lifecycle, plugins, scenes, and resources.

import { World } from '@shell/ecs';
const world = new World();

Set the world’s immutable fixed timestep at construction. The value is in milliseconds and defaults to 1000 / 60:

const world = new World({ fixedTimestepMs: 1000 / 120 });

The root world owns the timestep for its complete lifetime. Child worlds inherit it; attempting to construct a child with a conflicting value throws.

// Register components and plugins
world.registerComponent(Transform, Velocity);
world.addPlugin(MyPlugin);
// Mount starts the lifecycle: startup systems run, ticker starts
await world.mount();
// Pause/resume
await world.pause();
await world.continue();
// Unmount
await world.unmount(); // reloadable unload
await world.unmount(false); // just stop (no unload)
// Permanently release world-owned state
await world.dispose();
MethodDescription
mount(mountToParent?)Prepare systems, start ticker, and run lifecycle. Returns Promise<void>. For child scenes, mountToParent attaches to parent lifecycle.
pause()Sleep the lifecycle. Returns Promise<void>.
continue()Resume the lifecycle. Returns Promise<void>.
unmount(reset?)true (default) = full unload; false = just stop. Returns Promise<void>.
isMounted()Returns whether the world is currently mounted.
clear()Remove all entities, destroy systems and observers, and reset prepared state. Returns Promise<void>.
dispose()Permanently unload and release world-owned registrations and resources. Returns Promise<void>.

Lifecycle calls execute in invocation order and cannot interleave phases. Adjacent identical transitions share one promise while in flight. Lifecycle state advances only after every callback for the current phase succeeds, so a failed startup leaves the world unmounted and a failed unload retains the previous successful step. Both operations can be retried. Callback side effects that completed before a failure are not rolled back.

The root world’s pause() stops its ticker. Child scenes share that ticker, so pausing a child instead deactivates only the child’s scheduler owner. Its systems and observers stop executing while root and sibling execution continues. continue() reactivates the owner. unmount(false) similarly deactivates child execution without discarding definitions.

unmount() is reloadable; dispose() is permanent. Disposal unregisters the world’s systems and observers, removes scheduler hooks and owner activation, releases lifecycle subscriptions, disposes its entity registry, and disposes only resources owned by that world. A child never disposes inherited parent resources. Repeated disposal is safe, but a disposed world cannot be mounted or configured again.

// Pre-register components (useful for editors or deserialization)
world.registerComponent(Transform, Velocity);
// Use each system's builder schedule (or Update by default)
world.registerSystem(MoveSystem);
world.registerSystem(SystemA, SystemB);
// Explicit schedules override builder schedules
world.registerSystem(Schedule.Update, [SystemA, SystemB]);
// Unregister a system
world.unregisterSystem(MoveSystem);
// Register runtime-required components
world.registerRequiredComponents(Transform, Position, PreviousPosition);

Scenes are child worlds that inherit resources from a parent.

// Define a scene
const BattleScene = Define.scene('battle').build((world) => {
world.registerSystem(Schedule.Update, BattleSystem);
});
// Create from parent world
const sceneWorld = world.createScene(BattleScene);
const sceneWorld2 = world.createScene('empty-scene');
// Access via scene manager
const scenes = world.get('scenes');
const battle = scenes.getScene('battle');
// Mount (registers lifecycle with parent)
await sceneWorld.mount();

Scene manager transitions are also asynchronous and resolve after teardown or startup completes:

MethodReturn type
scenes.mount(name)Promise<void>
scenes.unmount(name)Promise<boolean> (false when missing or inactive)
scenes.goto(name)Promise<void>
scenes.deactivateAll()Promise<void>
scenes.clear()Promise<void>

Scene-manager transitions are serialized. A pending mount can be cancelled with either scene.unmount() or scenes.unmount(name). Failed and unvisited pending scenes remain available for retry. goto() unmounts the previous active set and attempts to restore it if the target mount fails; an AggregateError reports a transition whose rollback also failed.

scenes.deactivateAll() performs reloadable unmounts. scenes.clear() permanently disposes every child scene and releases its scheduler, observer, lifecycle, entity-registry, and resource ownership.

  • Inherited (shared): components, scheduler, ticker, queries, archetypes, events, mutationHooks
  • Isolated (per-scene): entities, systems, commands, lifecycle, observer registrations
  • Startup systems stay with their owning world by default. A .forEachWorld() builder clone registered on a startup schedule creates a fresh instance for its owner and every descendant lifecycle.
  • Observer dispatch is shared, but each observer runs with and is destroyed by its owning world.
  • Optional isolated (manually bound): serializer

The World uses dependency injection for resource management.

// Class binding (lazy singleton — instantiated on first .get())
world.bindResource('myService', MyServiceClass);
// Factory binding
world.bindResource('factory', (container) => new X(container.get('dep')));
// Instance binding (immediate)
world.bindResource('config', { debug: true });
world.get('myService'); // from World
resources.get('scheduler'); // from system update params
declare module '@shell/ecs' {
interface IocRegistry {
myService: MyServiceClass;
}
}
KeyTypeDescription
schedulerSchedulerTick loop, system execution
commandsCommandsEntity operations
eventsEventsEvent system
entitiesEntitiesEntity count, iteration
componentsComponentsComponent registry
queriesQueryRegistryQuery creation
archetypesArchetypesArchetype management
scenesSceneManagerChild world registry
tickerTickerFrame loop (root world only)
lifecycleLifeCycleMount/start/stop/unload
mutationHooksMutationHooksEntity/component change callbacks

Optional (manually bound, from @shell/serialization):

KeyTypeDescription
serializerSceneSerializerSave/load/apply
MethodDescription
world.toString()Returns Shell ECS - version <VERSION>
world.uidUnique identifier for the world instance
world.isRoot()Returns true if this world has no parent
world.inherit()Creates a new child world inheriting from this one