GameComponents in action
site/media/lessons/foundations-components.lesson.ts (5 steps) The whole engine rests on one idea: the Three.js Object3D is the entity, and behavior is
attached to it with a GameComponent. This lesson makes that concrete — first the shape of
a component, then seeing components tick live.
A GameComponent
Section titled “A GameComponent”A GameComponent (packages/engine/src/ecs/game-component.ts) is a small class with a
lifecycle:
// A minimal component: spin an object every frame.import { GameComponent } from '@engine/ecs/game-component';import { z } from 'zod';
export class Spin extends GameComponent { static phase = 'gameLogic' as const; // when update() runs static schema = z.object({ speed: z.number().default(1) }); // authored field speed = 1;
init(ctx) { /* runs once, after the entity + physics exist */ } update(dt, ctx) { this.object3D.rotation.y += this.speed * dt; } dispose(ctx) { /* clean up anything you created */ }}this.object3Dis the entity — there is no separate handle.static phasepicks which phaseupdate()runs in (defaultgameLogic).static schema(Zod) declares fields an author can set in the scene; they’re validated and assigned on load.init/update/disposeare the lifecycle; sensor overlaps also callonTriggerEnter/onTriggerExit.
Register the class by name in the component registry, then reference it from a scene’s
components — the loader validates the data through schema.parse() and attaches an instance
(the ComponentManager ticks it each frame in its phase).
See it run
Section titled “See it run”-
Open a scene whose entities have GameComponents. Load
examples/scenes/editor-tutorial.vscn.json.
A scene whose entities carry components. -
Enter play mode — each component’s
update()runs every tick. Press Play; the ComponentManager begins ticking every attached component in its phase.
Components tick once play starts. -
Watch component-driven animation and physics. The motion you see is components mutating their
object3Deach frame.
Per-frame update() in action. -
Components keep ticking in their phase. Each runs in the fixed phase order — input → … → gameLogic → … → render.
-
Stop play mode. Press Stop (or
Escape) —dispose()runs and the runtime tears down.
Recap
New functionality
- Saw a component-rich scene run
- Read the GameComponent lifecycle
New concepts & skills
- The Object3D IS the entity (no separate ECS)
- update() runs each fixed tick in the component's phase
- Static schema authors fields; the registry + ComponentManager wire and tick instances
- State on the instance survives hot reload
Next lesson → Manual: Entities & GameComponents