@relu-interactives/spatial-ecs 0.2.11 → 0.2.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{System-KTHuWc-i.d.cts → System-CTTwEGn1.d.cts} +312 -3
- package/dist/{System-KTHuWc-i.d.ts → System-CTTwEGn1.d.ts} +312 -3
- package/dist/{Video-Ds_0Aj66.d.ts → Video-BMWPYc3q.d.cts} +2 -241
- package/dist/{Video-BnrYbbzu.d.cts → Video-CV1-u6hL.d.ts} +2 -241
- package/dist/{chunk-OIOUWDOS.js → chunk-27RBPOVO.js} +40 -4
- package/dist/chunk-27RBPOVO.js.map +1 -0
- package/dist/{chunk-YLRCC4EK.js → chunk-7QBONTBW.js} +4 -4
- package/dist/{chunk-YLRCC4EK.js.map → chunk-7QBONTBW.js.map} +1 -1
- package/dist/{chunk-XPCVEXMY.js → chunk-FTIQQK62.js} +2 -2
- package/dist/chunk-FTIQQK62.js.map +1 -0
- package/dist/{chunk-UU6VYCIO.js → chunk-KDZ6VBRO.js} +4 -4
- package/dist/{chunk-UU6VYCIO.js.map → chunk-KDZ6VBRO.js.map} +1 -1
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.d.cts +2 -2
- package/dist/components/index.d.ts +2 -2
- package/dist/components/index.js +1 -1
- package/dist/docs/api/Behaviour/classes/Behaviour.md +29 -29
- package/dist/docs/api/Component/classes/Component.md +1 -1
- package/dist/docs/api/components/classes/AnimationComponent.md +26 -26
- package/dist/docs/api/components/classes/AudioComponent.md +19 -19
- package/dist/docs/api/components/classes/CameraComponent.md +14 -14
- package/dist/docs/api/components/classes/EntityType.md +3 -3
- package/dist/docs/api/components/classes/Environment.md +7 -3
- package/dist/docs/api/components/classes/ImageComponent.md +7 -7
- package/dist/docs/api/components/classes/ImageTarget.md +7 -7
- package/dist/docs/api/components/classes/ImageTargetAnchor.md +4 -4
- package/dist/docs/api/components/classes/InstanceSlotComponent.md +4 -4
- package/dist/docs/api/components/classes/InstancedMeshComponent.md +10 -10
- package/dist/docs/api/components/classes/LightComponent.md +6 -6
- package/dist/docs/api/components/classes/MaterialComponent.md +11 -11
- package/dist/docs/api/components/classes/MeshComponent.md +3 -3
- package/dist/docs/api/components/classes/MeshGeometryComponent.md +9 -9
- package/dist/docs/api/components/classes/ModelComponent.md +4 -4
- package/dist/docs/api/components/classes/Name.md +3 -3
- package/dist/docs/api/components/classes/Object3DRef.md +4 -4
- package/dist/docs/api/components/classes/ParentId.md +3 -3
- package/dist/docs/api/components/classes/PhysicsComponent.md +6 -6
- package/dist/docs/api/components/classes/Postprocessing.md +7 -3
- package/dist/docs/api/components/classes/ScriptComponent.md +5 -5
- package/dist/docs/api/components/classes/Selectable.md +3 -3
- package/dist/docs/api/components/classes/SelectionTransformState.md +5 -5
- package/dist/docs/api/components/classes/SpriteComponent.md +7 -7
- package/dist/docs/api/components/classes/TransformComponent.md +12 -12
- package/dist/docs/api/components/classes/VideoComponent.md +28 -28
- package/dist/docs/api/components/functions/normalizePhysicsState.md +1 -1
- package/dist/docs/api/components/index.md +1 -1
- package/dist/docs/api/components/type-aliases/AnimationComponentOptions.md +9 -9
- package/dist/docs/api/components/type-aliases/CameraComponentOptions.md +13 -13
- package/dist/docs/api/components/type-aliases/CameraProjection.md +1 -1
- package/dist/docs/api/components/type-aliases/CameraRuntimeType.md +1 -1
- package/dist/docs/api/components/type-aliases/ColliderShape.md +1 -1
- package/dist/docs/api/components/type-aliases/ColliderState.md +20 -20
- package/dist/docs/api/components/type-aliases/CubeMeshParameters.md +4 -4
- package/dist/docs/api/components/type-aliases/EditableMeshObjectKind.md +1 -1
- package/dist/docs/api/components/type-aliases/EnvironmentFogState.md +8 -8
- package/dist/docs/api/components/type-aliases/EnvironmentFogType.md +1 -1
- package/dist/docs/api/components/type-aliases/EnvironmentGradientEffect.md +1 -1
- package/dist/docs/api/components/type-aliases/EnvironmentSkyboxState.md +7 -7
- package/dist/docs/api/components/type-aliases/EnvironmentSkyboxType.md +1 -1
- package/dist/docs/api/components/type-aliases/EnvironmentState.md +5 -5
- package/dist/docs/api/components/type-aliases/ImageTargetAnchorOptions.md +3 -3
- package/dist/docs/api/components/type-aliases/ImageTargetReference.md +7 -7
- package/dist/docs/api/components/type-aliases/InstanceTransform.md +13 -13
- package/dist/docs/api/components/type-aliases/InstancedMeshKind.md +1 -1
- package/dist/docs/api/components/type-aliases/LightValueState.md +11 -11
- package/dist/docs/api/components/type-aliases/MaterialTypeValue.md +1 -1
- package/dist/docs/api/components/type-aliases/MaterialValueState.md +28 -28
- package/dist/docs/api/components/type-aliases/MeshGeometryParameters.md +1 -1
- package/dist/docs/api/components/type-aliases/MeshGeometryParametersByKind.md +7 -7
- package/dist/docs/api/components/type-aliases/PhysicsState.md +3 -3
- package/dist/docs/api/components/type-aliases/PlaneMeshParameters.md +3 -3
- package/dist/docs/api/components/type-aliases/PostprocessingState.md +62 -62
- package/dist/docs/api/components/type-aliases/RadiusHeightMeshParameters.md +3 -3
- package/dist/docs/api/components/type-aliases/RadiusMeshParameters.md +2 -2
- package/dist/docs/api/components/type-aliases/RigidbodyState.md +17 -17
- package/dist/docs/api/components/type-aliases/RigidbodyType.md +1 -1
- package/dist/docs/api/components/type-aliases/ScriptEntry.md +9 -9
- package/dist/docs/api/components/type-aliases/TextureFilteringValue.md +1 -1
- package/dist/docs/api/components/type-aliases/TransformData.md +4 -4
- package/dist/docs/api/components/type-aliases/TransformModeValue.md +1 -1
- package/dist/docs/api/components/type-aliases/TransformSpaceValue.md +1 -1
- package/dist/docs/api/components/type-aliases/Vec3.md +4 -4
- package/dist/docs/api/components/variables/DEFAULT_COLLIDER_STATE.md +1 -1
- package/dist/docs/api/components/variables/DEFAULT_ENVIRONMENT_STATE.md +1 -1
- package/dist/docs/api/components/variables/DEFAULT_INSTANCED_MESH_PARAMETERS.md +1 -1
- package/dist/docs/api/components/variables/DEFAULT_INSTANCE_TRANSFORM.md +1 -1
- package/dist/docs/api/components/variables/DEFAULT_MESH_GEOMETRY_PARAMETERS.md +1 -1
- package/dist/docs/api/components/variables/DEFAULT_PHYSICS_STATE.md +1 -1
- package/dist/docs/api/components/variables/DEFAULT_POSTPROCESSING_STATE.md +1 -1
- package/dist/docs/api/components/variables/DEFAULT_RIGIDBODY_STATE.md +1 -1
- package/dist/docs/api/index/classes/AnimationStateMachine.md +16 -16
- package/dist/docs/api/index/classes/AnimationStateManager.md +13 -13
- package/dist/docs/api/index/classes/AnimationSystem.md +3 -3
- package/dist/docs/api/index/classes/AudioSystem.md +4 -4
- package/dist/docs/api/index/classes/CameraSyncSystem.md +2 -2
- package/dist/docs/api/index/classes/EnvironmentSyncSystem.md +4 -4
- package/dist/docs/api/index/classes/InputSystem.md +33 -33
- package/dist/docs/api/index/classes/InstancedMeshSystem.md +2 -2
- package/dist/docs/api/index/classes/LightSyncSystem.md +2 -2
- package/dist/docs/api/index/classes/MaterialSyncSystem.md +3 -3
- package/dist/docs/api/index/classes/MeshGeometrySystem.md +2 -2
- package/dist/docs/api/index/classes/ObjectManagementSystem.md +39 -19
- package/dist/docs/api/index/classes/ObjectVisibilitySystem.md +2 -2
- package/dist/docs/api/index/classes/PhysicsSyncSystem.md +4 -4
- package/dist/docs/api/index/classes/PostprocessingSyncSystem.md +4 -4
- package/dist/docs/api/index/classes/RenderSystem.md +3 -3
- package/dist/docs/api/index/classes/ScriptBehaviourSystem.md +4 -4
- package/dist/docs/api/index/classes/TransformSyncSystem.md +2 -2
- package/dist/docs/api/index/classes/VideoSystem.md +4 -4
- package/dist/docs/api/index/classes/World.md +146 -82
- package/dist/docs/api/index/functions/createAnimationComponent.md +1 -1
- package/dist/docs/api/index/functions/createAudioComponent.md +1 -1
- package/dist/docs/api/index/functions/createCameraComponent.md +1 -1
- package/dist/docs/api/index/functions/createEntityTypeComponent.md +1 -1
- package/dist/docs/api/index/functions/createEnvironmentComponent.md +1 -1
- package/dist/docs/api/index/functions/createImageComponent.md +1 -1
- package/dist/docs/api/index/functions/createImageTargetAnchorComponent.md +1 -1
- package/dist/docs/api/index/functions/createImageTargetComponent.md +1 -1
- package/dist/docs/api/index/functions/createInstanceSlotComponent.md +1 -1
- package/dist/docs/api/index/functions/createInstancedMeshComponent.md +1 -1
- package/dist/docs/api/index/functions/createLightComponent.md +1 -1
- package/dist/docs/api/index/functions/createMaterialComponent.md +1 -1
- package/dist/docs/api/index/functions/createMeshComponent.md +1 -1
- package/dist/docs/api/index/functions/createMeshGeometryComponent.md +1 -1
- package/dist/docs/api/index/functions/createModelComponent.md +1 -1
- package/dist/docs/api/index/functions/createNameComponent.md +1 -1
- package/dist/docs/api/index/functions/createObject3DRefComponent.md +1 -1
- package/dist/docs/api/index/functions/createParentIdComponent.md +1 -1
- package/dist/docs/api/index/functions/createPhysicsComponent.md +1 -1
- package/dist/docs/api/index/functions/createPostprocessingComponent.md +1 -1
- package/dist/docs/api/index/functions/createScriptComponent.md +1 -1
- package/dist/docs/api/index/functions/createSelectableComponent.md +1 -1
- package/dist/docs/api/index/functions/createSelectionTransformStateComponent.md +1 -1
- package/dist/docs/api/index/functions/createSpriteComponent.md +1 -1
- package/dist/docs/api/index/functions/createTransformComponent.md +1 -1
- package/dist/docs/api/index/functions/createVideoComponent.md +1 -1
- package/dist/docs/api/index/functions/hydrateWorldFromSnapshot.md +1 -1
- package/dist/docs/api/index/functions/hydrateWorldFromSnapshotDetailed.md +1 -1
- package/dist/docs/api/index/functions/registerDefaultComponentFactories.md +1 -1
- package/dist/docs/api/index/functions/registerDefaultFactories.md +1 -1
- package/dist/docs/api/index/interfaces/EcsSystem.md +3 -3
- package/dist/docs/api/index/interfaces/StateMachine.md +13 -13
- package/dist/docs/api/index/type-aliases/AnimationStateCallbacks.md +4 -4
- package/dist/docs/api/index/type-aliases/ComponentFactory.md +1 -1
- package/dist/docs/api/index/type-aliases/EcsComponentFactoryKind.md +1 -1
- package/dist/docs/api/index/type-aliases/EcsWorldComponentSnapshot.md +3 -3
- package/dist/docs/api/index/type-aliases/EcsWorldStateSnapshotLike.md +4 -4
- package/dist/docs/api/index/type-aliases/HydrateWorldFromSnapshotResult.md +3 -3
- package/dist/docs/api/index/type-aliases/KeyboardKey.md +1 -1
- package/dist/docs/api/index/type-aliases/MouseButton.md +1 -1
- package/dist/docs/api/index/type-aliases/SelectionContext.md +4 -4
- package/dist/docs/api/index/variables/HYDRATABLE_ENTITY_KINDS.md +1 -1
- package/dist/docs/api/index/variables/KeyboardKeys.md +89 -89
- package/dist/docs/api/types/type-aliases/AssetInput.md +3 -3
- package/dist/docs/api/types/type-aliases/CheckboxInput.md +12 -2
- package/dist/docs/api/types/type-aliases/ColorInput.md +1 -1
- package/dist/docs/api/types/type-aliases/ComponentInput.md +4 -4
- package/dist/docs/api/types/type-aliases/ComponentKind.md +1 -1
- package/dist/docs/api/types/type-aliases/DropdownInput.md +3 -3
- package/dist/docs/api/types/type-aliases/DropdownOption.md +3 -3
- package/dist/docs/api/types/type-aliases/EcsEntityEditorKind.md +1 -1
- package/dist/docs/api/types/type-aliases/EcsEntityKind.md +1 -1
- package/dist/docs/api/types/type-aliases/EntityId.md +1 -1
- package/dist/docs/api/types/type-aliases/EntityInput.md +3 -3
- package/dist/docs/api/types/type-aliases/FloatInput.md +1 -1
- package/dist/docs/api/types/type-aliases/IntersectionResult.md +3 -3
- package/dist/docs/api/types/type-aliases/ParentLookup.md +3 -3
- package/dist/docs/api/types/type-aliases/SelectionListener.md +1 -1
- package/dist/docs/api/types/type-aliases/SliderInput.md +5 -5
- package/dist/docs/api/types/type-aliases/TextInput.md +1 -1
- package/dist/docs/api/types/type-aliases/ToggleInput.md +1 -1
- package/dist/docs/api/types/type-aliases/Vec3.md +1 -1
- package/dist/docs/api/types/type-aliases/Vector2Input.md +3 -3
- package/dist/docs/api/types/type-aliases/Vector3Input.md +4 -4
- package/dist/docs/api/types/type-aliases/WorldEntityView.md +1 -1
- package/dist/docs/guide/accessing-components.md +135 -1
- package/dist/docs/guide/authoring-a-behaviour.md +1 -1
- package/dist/docs/guide/behaviour-data-binding/asset-input.md +54 -0
- package/dist/docs/guide/behaviour-data-binding/checkbox-input.md +38 -0
- package/dist/docs/guide/behaviour-data-binding/color-input.md +38 -0
- package/dist/docs/guide/behaviour-data-binding/component-input.md +79 -0
- package/dist/docs/guide/behaviour-data-binding/dropdown-input.md +53 -0
- package/dist/docs/guide/behaviour-data-binding/entity-input.md +100 -0
- package/dist/docs/guide/behaviour-data-binding/float-input.md +35 -0
- package/dist/docs/guide/behaviour-data-binding/index.md +158 -0
- package/dist/docs/guide/behaviour-data-binding/slider-input.md +37 -0
- package/dist/docs/guide/behaviour-data-binding/text-input.md +35 -0
- package/dist/docs/guide/behaviour-data-binding/toggle-input.md +36 -0
- package/dist/docs/guide/behaviour-data-binding/vector2-input.md +36 -0
- package/dist/docs/guide/behaviour-data-binding/vector3-input.md +41 -0
- package/dist/docs/guide/component-catalog.md +2 -0
- package/dist/docs/guide/components/animation.md +40 -1
- package/dist/docs/guide/components/instanced-mesh.md +1 -4
- package/dist/docs/guide/runtime-entity-management.md +302 -0
- package/dist/docs/guide/scene/environment.md +5 -6
- package/dist/docs/guide/scene/index.md +5 -10
- package/dist/docs/guide/scene/postprocessing.md +5 -6
- package/dist/docs/guide/spawning/audio.md +29 -7
- package/dist/docs/guide/systems/object-management-system.md +70 -0
- package/dist/docs/guide/world-api.md +3 -1
- package/dist/factories/index.cjs.map +1 -1
- package/dist/factories/index.d.cts +2 -2
- package/dist/factories/index.d.ts +2 -2
- package/dist/factories/index.js +3 -3
- package/dist/{index-D-gUELQS.d.ts → index-ByX7502C.d.ts} +2 -2
- package/dist/{index-ComEYKYI.d.cts → index-D7q4SRCp.d.cts} +2 -2
- package/dist/index.cjs +84 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +55 -8
- package/dist/index.js.map +1 -1
- package/dist/systems/index.cjs +37 -1
- package/dist/systems/index.cjs.map +1 -1
- package/dist/systems/index.d.cts +2 -2
- package/dist/systems/index.d.ts +2 -2
- package/dist/systems/index.js +3 -3
- package/dist/types.d.cts +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/worldSnapshotUtils.d.cts +1 -1
- package/dist/worldSnapshotUtils.d.ts +1 -1
- package/package.json +1 -1
- package/dist/chunk-OIOUWDOS.js.map +0 -1
- package/dist/chunk-XPCVEXMY.js.map +0 -1
- package/dist/docs/guide/inspector-data-binding.md +0 -367
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
# Runtime Entity Management
|
|
2
|
+
|
|
3
|
+
From a `Behaviour` script you have full control over the entity lifecycle: spawning new objects, adding or removing components on existing ones, re-parenting entities in the hierarchy, and deleting with proper resource cleanup.
|
|
4
|
+
|
|
5
|
+
## The ObjectManagementSystem
|
|
6
|
+
|
|
7
|
+
Every world exposes `ObjectManagementSystem` via `this.world.getObjectManagementSystem()`. It is the hub for all runtime entity and component creation:
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
const oms = this.world.getObjectManagementSystem();
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Always null-check — `oms` returns `null` if the world has not been set up yet.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## 1. Spawning new objects
|
|
18
|
+
|
|
19
|
+
Use `requestCreate` to queue a new entity from a built-in kind. The factory runs on the next frame and the optional `onCreated` callback fires with the new `entityId`:
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
import { Behaviour } from "@relu-interactives/spatial-ecs";
|
|
23
|
+
|
|
24
|
+
export default class Spawner extends Behaviour {
|
|
25
|
+
private spawnedId: number | null = null;
|
|
26
|
+
|
|
27
|
+
protected init() {
|
|
28
|
+
const oms = this.world.getObjectManagementSystem();
|
|
29
|
+
|
|
30
|
+
oms?.requestCreate("cube", {
|
|
31
|
+
name: "RuntimeCube",
|
|
32
|
+
transform: { position: { x: 0, y: 1, z: 0 } },
|
|
33
|
+
}, (entityId) => {
|
|
34
|
+
this.spawnedId = entityId;
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
dispose(world: any) {
|
|
39
|
+
if (this.spawnedId !== null) {
|
|
40
|
+
this.world.getObjectManagementSystem()?.deleteEntity(this.world, this.spawnedId, true);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Supported kinds: `"cube"`, `"sphere"`, `"plane"`, `"capsule"`, `"cylinder"`, `"empty"`, `"model"`, `"image"`, `"sprite"`, `"video"`, `"audio"`, `"camera"`, `"ambient-light"`, `"directional-light"`, `"point-light"`, `"spot-light"`, `"area-light"`, `"instanced-mesh"`.
|
|
47
|
+
|
|
48
|
+
See the [Spawning reference](./spawning/) for per-kind payload schemas.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## 2. Adding components to existing entities
|
|
53
|
+
|
|
54
|
+
### `world.addComponent` — simple data components
|
|
55
|
+
|
|
56
|
+
Use `world.addComponent` to attach data-only components that carry no runtime handles:
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
import { Behaviour } from "@relu-interactives/spatial-ecs";
|
|
60
|
+
import { Name } from "@relu-interactives/spatial-ecs/components";
|
|
61
|
+
|
|
62
|
+
export default class Tagger extends Behaviour {
|
|
63
|
+
protected init() {
|
|
64
|
+
const entity = this.world.getEntityByName("Target");
|
|
65
|
+
if (!entity) return;
|
|
66
|
+
|
|
67
|
+
this.world.addComponent(entity.entityId, new Name({ value: "Tagged" }));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### `oms.createComponentNow` — factory-initialized components
|
|
73
|
+
|
|
74
|
+
For components that need runtime setup (Rapier physics bodies, Web Audio nodes, Three.js material instances, AnimationMixers) use `createComponentNow`. It calls the same registered factory used during scene construction, so all runtime handles are correctly wired up:
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
import { Behaviour } from "@relu-interactives/spatial-ecs";
|
|
78
|
+
|
|
79
|
+
export default class AddPhysics extends Behaviour {
|
|
80
|
+
protected init() {
|
|
81
|
+
const oms = this.world.getObjectManagementSystem();
|
|
82
|
+
if (!oms) return;
|
|
83
|
+
|
|
84
|
+
oms.createComponentNow("physics", this.world, this.entityId, {
|
|
85
|
+
rigidbody: { type: "dynamic", mass: 1, gravityScale: 1 },
|
|
86
|
+
collider: { shape: "box" },
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
**When to use which:**
|
|
93
|
+
|
|
94
|
+
| Scenario | Method |
|
|
95
|
+
|----------|--------|
|
|
96
|
+
| Name, EntityType, Transform (data only) | `world.addComponent(id, new ComponentClass(...))` |
|
|
97
|
+
| Physics with Rapier body/collider | `oms.createComponentNow("physics", world, id, config)` |
|
|
98
|
+
| Audio with Web Audio node | `oms.createComponentNow("audio", world, id, path, options, ctx)` |
|
|
99
|
+
| Material with Three.js material instance | `oms.createComponentNow("material", world, id, values)` |
|
|
100
|
+
| Animation with clip catalog | `oms.createComponentNow("animation", world, id)` |
|
|
101
|
+
|
|
102
|
+
**Registered factory kinds:**
|
|
103
|
+
|
|
104
|
+
`"animation"`, `"audio"`, `"camera"`, `"physics"`, `"environment"`, `"entityType"`, `"image"`, `"imageTarget"`, `"imageTargetAnchor"`, `"light"`, `"material"`, `"mesh"`, `"meshGeometry"`, `"model"`, `"name"`, `"object3DRef"`, `"parentId"`, `"postprocessing"`, `"script"`, `"sprite"`, `"transform"`, `"video"`, `"instancedMesh"`.
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## 3. Removing components
|
|
109
|
+
|
|
110
|
+
Remove a component by passing its class to `world.removeComponent`. The associated runtime handles are not disposed — call system-specific cleanup first if needed:
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
import { Behaviour } from "@relu-interactives/spatial-ecs";
|
|
114
|
+
import { PhysicsComponent } from "@relu-interactives/spatial-ecs/components";
|
|
115
|
+
|
|
116
|
+
export default class Freezer extends Behaviour {
|
|
117
|
+
protected init() {
|
|
118
|
+
// Remove physics from this entity to freeze it in place
|
|
119
|
+
this.world.removeComponent(this.entityId, PhysicsComponent);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## 4. Re-parenting at runtime
|
|
127
|
+
|
|
128
|
+
`oms.setParent(world, entityId, parentId, options?)` updates the `ParentId` component and reconciles the Three.js scene graph in the same frame. By default (`preserveWorldTransform: true`) the entity's world-space position and rotation are preserved by adjusting the local transform:
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
import { Behaviour } from "@relu-interactives/spatial-ecs";
|
|
132
|
+
|
|
133
|
+
export default class Attach extends Behaviour {
|
|
134
|
+
protected init() {
|
|
135
|
+
const oms = this.world.getObjectManagementSystem();
|
|
136
|
+
if (!oms) return;
|
|
137
|
+
|
|
138
|
+
const anchor = this.world.getEntityByName("Anchor");
|
|
139
|
+
if (!anchor) return;
|
|
140
|
+
|
|
141
|
+
// Attach this entity under Anchor, preserving world position
|
|
142
|
+
oms.setParent(this.world, this.entityId, anchor.entityId);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Detach from parent (become a direct child of the scene root):
|
|
148
|
+
|
|
149
|
+
```ts
|
|
150
|
+
oms.setParent(this.world, this.entityId, null);
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
`setParent` guards against cycles and returns `false` if the operation would create a loop or if either entity does not exist.
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## 5. Deleting entities and freeing GPU memory
|
|
158
|
+
|
|
159
|
+
`oms.deleteEntity(world, entityId, dispose?)` removes the entity from the ECS world and its `Object3D` from the Three.js scene graph:
|
|
160
|
+
|
|
161
|
+
- Pass `dispose = false` (default) when geometry or materials are shared — GPU resources stay allocated.
|
|
162
|
+
- Pass `dispose = true` for dynamically spawned, one-off objects to immediately free `BufferGeometry` and `Material` GPU memory.
|
|
163
|
+
|
|
164
|
+
```ts
|
|
165
|
+
// Safe remove (shared geometry/materials stay on GPU)
|
|
166
|
+
oms.deleteEntity(this.world, entityId);
|
|
167
|
+
|
|
168
|
+
// Full cleanup (frees GPU memory — use for unique spawned objects)
|
|
169
|
+
oms.deleteEntity(this.world, entityId, true);
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Always delete spawned entities in `dispose()` to prevent leaks when the script is removed:
|
|
173
|
+
|
|
174
|
+
```ts
|
|
175
|
+
dispose(world: any) {
|
|
176
|
+
if (this.spawnedId !== null) {
|
|
177
|
+
this.world.getObjectManagementSystem()?.deleteEntity(this.world, this.spawnedId, true);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## 6. Async loading patterns
|
|
185
|
+
|
|
186
|
+
Models and audio load asynchronously. The entity is created immediately but the asset is not available until the loader fires. Use the `onCreated` callback for setup that doesn't need the asset, and poll component state in `onUpdate` for setup that does:
|
|
187
|
+
|
|
188
|
+
```ts
|
|
189
|
+
import { Behaviour } from "@relu-interactives/spatial-ecs";
|
|
190
|
+
import { AnimationComponent } from "@relu-interactives/spatial-ecs/components";
|
|
191
|
+
|
|
192
|
+
export default class ModelSpawner extends Behaviour {
|
|
193
|
+
private modelId: number | null = null;
|
|
194
|
+
private animSetup = false;
|
|
195
|
+
|
|
196
|
+
protected init() {
|
|
197
|
+
const oms = this.world.getObjectManagementSystem();
|
|
198
|
+
|
|
199
|
+
oms?.requestCreate("model", {
|
|
200
|
+
name: "Character",
|
|
201
|
+
path: "localasset://assets/character.glb",
|
|
202
|
+
transform: { position: { x: 0, y: 0, z: 0 } },
|
|
203
|
+
}, (entityId) => {
|
|
204
|
+
this.modelId = entityId;
|
|
205
|
+
|
|
206
|
+
// Safe immediately — entity exists, physics factory is synchronous
|
|
207
|
+
oms.createComponentNow("physics", this.world, entityId, {
|
|
208
|
+
rigidbody: { type: "dynamic", mass: 1 },
|
|
209
|
+
collider: { shape: "capsule" },
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
protected onUpdate() {
|
|
215
|
+
if (this.modelId === null || this.animSetup) return;
|
|
216
|
+
|
|
217
|
+
// availableClips populates after the GLB finishes loading
|
|
218
|
+
const anim = this.world.getComponent(this.modelId, AnimationComponent);
|
|
219
|
+
if (anim && anim.availableClips.length > 0) {
|
|
220
|
+
anim.addState("Idle", anim.availableClips[0], true);
|
|
221
|
+
anim.switchState("Idle");
|
|
222
|
+
this.animSetup = true;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
dispose(world: any) {
|
|
227
|
+
if (this.modelId !== null) {
|
|
228
|
+
this.world.getObjectManagementSystem()?.deleteEntity(this.world, this.modelId, true);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
## 7. Complete worked example
|
|
237
|
+
|
|
238
|
+
Spawn a model, add physics, parent it under an AR anchor, set up animation once clips are ready, and clean everything up on dispose:
|
|
239
|
+
|
|
240
|
+
```ts
|
|
241
|
+
import { Behaviour } from "@relu-interactives/spatial-ecs";
|
|
242
|
+
import { AnimationComponent } from "@relu-interactives/spatial-ecs/components";
|
|
243
|
+
|
|
244
|
+
export default class ARCharacter extends Behaviour {
|
|
245
|
+
private characterId: number | null = null;
|
|
246
|
+
private animReady = false;
|
|
247
|
+
|
|
248
|
+
protected init() {
|
|
249
|
+
const oms = this.world.getObjectManagementSystem();
|
|
250
|
+
if (!oms) return;
|
|
251
|
+
|
|
252
|
+
const anchor = this.world.getEntityByName("ImageTargetAnchor");
|
|
253
|
+
|
|
254
|
+
oms.requestCreate("model", {
|
|
255
|
+
name: "ARCharacter",
|
|
256
|
+
path: "localasset://assets/character.glb",
|
|
257
|
+
transform: { position: { x: 0, y: 0, z: 0 } },
|
|
258
|
+
}, (entityId) => {
|
|
259
|
+
this.characterId = entityId;
|
|
260
|
+
|
|
261
|
+
// Parent under AR anchor so it tracks with the target
|
|
262
|
+
if (anchor) {
|
|
263
|
+
oms.setParent(this.world, entityId, anchor.entityId);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Add physics (Rapier body wired immediately by the factory)
|
|
267
|
+
oms.createComponentNow("physics", this.world, entityId, {
|
|
268
|
+
rigidbody: { type: "kinematic-position" },
|
|
269
|
+
collider: { shape: "capsule" },
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
protected onUpdate() {
|
|
275
|
+
if (this.characterId === null || this.animReady) return;
|
|
276
|
+
|
|
277
|
+
const anim = this.world.getComponent(this.characterId, AnimationComponent);
|
|
278
|
+
if (anim && anim.availableClips.length > 0) {
|
|
279
|
+
if (anim.availableClips.includes("Idle")) anim.addState("Idle", "Idle", true);
|
|
280
|
+
if (anim.availableClips.includes("Walk")) anim.addState("Walk", "Walk", true);
|
|
281
|
+
anim.crossFadeDuration = 0.3;
|
|
282
|
+
anim.switchState("Idle");
|
|
283
|
+
this.animReady = true;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
dispose(world: any) {
|
|
288
|
+
if (this.characterId !== null) {
|
|
289
|
+
this.world.getObjectManagementSystem()?.deleteEntity(this.world, this.characterId, true);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
---
|
|
296
|
+
|
|
297
|
+
## See also
|
|
298
|
+
|
|
299
|
+
- [Spawning reference](./spawning/) — per-kind payload schemas for `requestCreate`
|
|
300
|
+
- [ObjectManagementSystem](./systems/object-management-system) — system internals and API reference
|
|
301
|
+
- [Accessing Components](./accessing-components) — reading and writing component state
|
|
302
|
+
- [World API](./world-api) — entity queries, input, raycasting, scene access
|
|
@@ -12,15 +12,14 @@ It is a **singleton** there is exactly one `Environment` entity per scene, owned
|
|
|
12
12
|
|
|
13
13
|
## Get the component from the world
|
|
14
14
|
|
|
15
|
+
Use `world.getEnvironmentComponent()` — a convenience method that handles the entity lookup for you:
|
|
16
|
+
|
|
15
17
|
```ts
|
|
16
|
-
import { Behaviour
|
|
18
|
+
import { Behaviour } from "@relu-interactives/spatial-ecs";
|
|
17
19
|
|
|
18
20
|
export default class ReadEnvironment extends Behaviour {
|
|
19
21
|
init() {
|
|
20
|
-
const
|
|
21
|
-
if (entityId === undefined) return;
|
|
22
|
-
|
|
23
|
-
const env = this.world.getComponent(entityId, Environment);
|
|
22
|
+
const env = this.world.getEnvironmentComponent();
|
|
24
23
|
if (!env) return;
|
|
25
24
|
|
|
26
25
|
console.log("skybox type", env.values.skybox.type);
|
|
@@ -29,7 +28,7 @@ export default class ReadEnvironment extends Behaviour {
|
|
|
29
28
|
}
|
|
30
29
|
```
|
|
31
30
|
|
|
32
|
-
`env.values` is the live state object. Mutating fields on it is enough
|
|
31
|
+
`env.values` is the live state object. Mutating fields on it is enough — `EnvironmentSyncSystem` reads it every frame and pushes changes into the three.js scene.
|
|
33
32
|
|
|
34
33
|
## Change values at runtime
|
|
35
34
|
|
|
@@ -9,22 +9,17 @@ Some settings live on the **scene** rather than on a single object the skybox, f
|
|
|
9
9
|
|
|
10
10
|
## Pattern
|
|
11
11
|
|
|
12
|
-
Both components
|
|
12
|
+
Both components expose a convenience method on `world` — no manual entity lookup needed:
|
|
13
13
|
|
|
14
14
|
```ts
|
|
15
|
-
import { Behaviour
|
|
15
|
+
import { Behaviour } from "@relu-interactives/spatial-ecs";
|
|
16
16
|
|
|
17
17
|
export default class TweakScene extends Behaviour {
|
|
18
18
|
init() {
|
|
19
|
-
|
|
20
|
-
const [entityId] = this.world.query(Environment);
|
|
21
|
-
if (entityId === undefined) return;
|
|
22
|
-
|
|
23
|
-
// 2. Read the component instance.
|
|
24
|
-
const env = this.world.getComponent(entityId, Environment);
|
|
19
|
+
const env = this.world.getEnvironmentComponent();
|
|
25
20
|
if (!env) return;
|
|
26
21
|
|
|
27
|
-
//
|
|
22
|
+
// Mutate `env.values` — sync systems pick the change up next frame.
|
|
28
23
|
env.values.fog.type = "linear";
|
|
29
24
|
env.values.fog.color = "#88aaff";
|
|
30
25
|
env.values.fog.linear.near = 5;
|
|
@@ -33,4 +28,4 @@ export default class TweakScene extends Behaviour {
|
|
|
33
28
|
}
|
|
34
29
|
```
|
|
35
30
|
|
|
36
|
-
The same
|
|
31
|
+
The same pattern works for `Postprocessing` via `this.world.getPostprocessingComponent()` — see each page for the full set of authorable values.
|
|
@@ -11,15 +11,14 @@ It is a **singleton** there is exactly one `Postprocessing` entity per scene, ow
|
|
|
11
11
|
|
|
12
12
|
## Get the component from the world
|
|
13
13
|
|
|
14
|
+
Use `world.getPostprocessingComponent()` — a convenience method that handles the entity lookup for you:
|
|
15
|
+
|
|
14
16
|
```ts
|
|
15
|
-
import { Behaviour
|
|
17
|
+
import { Behaviour } from "@relu-interactives/spatial-ecs";
|
|
16
18
|
|
|
17
19
|
export default class ReadPostprocessing extends Behaviour {
|
|
18
20
|
init() {
|
|
19
|
-
const
|
|
20
|
-
if (entityId === undefined) return;
|
|
21
|
-
|
|
22
|
-
const post = this.world.getComponent(entityId, Postprocessing);
|
|
21
|
+
const post = this.world.getPostprocessingComponent();
|
|
23
22
|
if (!post) return;
|
|
24
23
|
|
|
25
24
|
console.log("post enabled?", post.values.postEnabled);
|
|
@@ -27,7 +26,7 @@ export default class ReadPostprocessing extends Behaviour {
|
|
|
27
26
|
}
|
|
28
27
|
```
|
|
29
28
|
|
|
30
|
-
`post.values` is the live state object mutate fields on it directly. The `PostprocessingSyncSystem` reads it every frame and rebuilds the composer pipeline as effects are toggled.
|
|
29
|
+
`post.values` is the live state object — mutate fields on it directly. The `PostprocessingSyncSystem` reads it every frame and rebuilds the composer pipeline as effects are toggled.
|
|
31
30
|
|
|
32
31
|
## Change values at runtime
|
|
33
32
|
|
|
@@ -40,13 +40,35 @@ export default class SpawnSound extends Behaviour {
|
|
|
40
40
|
|
|
41
41
|
### `options`
|
|
42
42
|
|
|
43
|
-
| Option | Type
|
|
44
|
-
| --------------- |
|
|
45
|
-
| `autoplay` | `boolean`
|
|
46
|
-
| `loop` | `boolean`
|
|
47
|
-
| `volume` | `number` (0–1)
|
|
48
|
-
| `
|
|
49
|
-
| `
|
|
43
|
+
| Option | Type | Default | Description |
|
|
44
|
+
| --------------- | ---------------------------------------- | ----------- | ----------------------------------------------------------------- |
|
|
45
|
+
| `autoplay` | `boolean` | `false` | Start playback as soon as the clip is loaded. |
|
|
46
|
+
| `loop` | `boolean` | `false` | Loop playback indefinitely. |
|
|
47
|
+
| `volume` | `number` (0–1) | `1` | Linear gain. |
|
|
48
|
+
| `pitch` | `number` | `1` | Playback rate multiplier (`1` = normal speed/pitch). |
|
|
49
|
+
| `positional` | `boolean` | `false` | When `true`, audio is spatialized using the entity's transform. |
|
|
50
|
+
| `refDistance` | `number` | `1` | Distance at which volume is unattenuated (positional only). |
|
|
51
|
+
| `distanceModel` | `"linear" \| "inverse" \| "exponential"` | `"inverse"` | WebAudio distance model (positional only). |
|
|
52
|
+
| `rolloffFactor` | `number` | `1` | How quickly volume falls off past `refDistance`. |
|
|
53
|
+
|
|
54
|
+
## ⚠️ Common mistake — wrong payload shape
|
|
55
|
+
|
|
56
|
+
`path` and `options` must be **top-level** keys on the payload. Never nest them inside an `audio:` sub-object.
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
// ✅ Correct
|
|
60
|
+
objects?.requestCreate("audio", {
|
|
61
|
+
name: "SFX",
|
|
62
|
+
path: "localasset://assets/sfx/hit.mp3",
|
|
63
|
+
options: { autoplay: true, volume: 0.8 },
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// ❌ Wrong — do NOT wrap inside audio:{}
|
|
67
|
+
objects?.requestCreate("audio", {
|
|
68
|
+
name: "SFX",
|
|
69
|
+
audio: { path: "...", options: { autoplay: true } }, // ← this will be ignored
|
|
70
|
+
});
|
|
71
|
+
```
|
|
50
72
|
|
|
51
73
|
## Components attached
|
|
52
74
|
|
|
@@ -32,7 +32,77 @@ Component kinds (e.g. `"animation"`, `"physics"`) are registered with `registerC
|
|
|
32
32
|
- **Parent reconciliation** — if a `ParentId` refers to an entity that does not yet have an `Object3DRef` (e.g. the parent is still loading), reparenting is deferred to the next frame.
|
|
33
33
|
- **Scene root** — entities without a `ParentId` (or with `ParentId.parentId === null`) are kept as direct children of the THREE.js scene root.
|
|
34
34
|
- **Audio listener** — `getOrCreateAudioListener()` lazily creates a single `THREE.AudioListener` on the world camera and is used by audio object factories.
|
|
35
|
+
- **Entity deletion** — `deleteEntity(world, entityId)` removes the entity from the ECS world and its `Object3D` from the THREE.js scene graph. Pass `dispose = true` as the third argument to also call `.dispose()` on all `BufferGeometry` and `Material` instances in the subtree, freeing GPU memory. Use this for dynamically spawned objects that will not be reused. Avoid it when geometry or materials are shared with other entities.
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
// Remove from scene only (geometry/materials are kept on the GPU — safe if shared)
|
|
39
|
+
objects.deleteEntity(world, entityId);
|
|
40
|
+
|
|
41
|
+
// Remove from scene and free GPU memory
|
|
42
|
+
objects.deleteEntity(world, entityId, true);
|
|
43
|
+
```
|
|
35
44
|
|
|
36
45
|
## API reference
|
|
37
46
|
|
|
47
|
+
### `requestCreate(kind, payload?, onCreated?)`
|
|
48
|
+
|
|
49
|
+
Queue a new entity creation request. The factory for the given `kind` runs on the next frame; the optional `onCreated` callback fires with the new `entityId`:
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
const oms = this.world.getObjectManagementSystem();
|
|
53
|
+
|
|
54
|
+
oms?.requestCreate("cube", {
|
|
55
|
+
name: "DynamicCube",
|
|
56
|
+
transform: { position: { x: 0, y: 2, z: 0 } },
|
|
57
|
+
}, (entityId) => {
|
|
58
|
+
// entityId is ready — add more components here
|
|
59
|
+
});
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### `createComponentNow(kind, world, entityId, ...args)`
|
|
63
|
+
|
|
64
|
+
Synchronously call the registered component factory for `kind` on an existing entity. Use this instead of `world.addComponent` when the component needs runtime setup (Rapier bodies, Web Audio nodes, Three.js material instances):
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
// Add physics with full Rapier body + collider setup
|
|
68
|
+
oms.createComponentNow("physics", world, entityId, {
|
|
69
|
+
rigidbody: { type: "dynamic", mass: 1, gravityScale: 1 },
|
|
70
|
+
collider: { shape: "box" },
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// Add a material with a Three.js material instance
|
|
74
|
+
oms.createComponentNow("material", world, entityId, { color: "#ff0000" });
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Registered factory kinds: `"animation"`, `"audio"`, `"camera"`, `"physics"`, `"environment"`, `"entityType"`, `"image"`, `"imageTarget"`, `"imageTargetAnchor"`, `"light"`, `"material"`, `"mesh"`, `"meshGeometry"`, `"model"`, `"name"`, `"object3DRef"`, `"parentId"`, `"postprocessing"`, `"script"`, `"sprite"`, `"transform"`, `"video"`, `"instancedMesh"`.
|
|
78
|
+
|
|
79
|
+
### `deleteEntity(world, entityId, dispose?)`
|
|
80
|
+
|
|
81
|
+
Remove an entity from the ECS world and its `Object3D` from the Three.js scene graph. Pass `dispose = true` to also free GPU memory by calling `.dispose()` on all `BufferGeometry` and `Material` instances in the subtree:
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
// Remove from scene, keep GPU resources (safe if geometry is shared)
|
|
85
|
+
oms.deleteEntity(world, entityId);
|
|
86
|
+
|
|
87
|
+
// Remove from scene and free GPU memory (use for dynamically spawned objects)
|
|
88
|
+
oms.deleteEntity(world, entityId, true);
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### `setParent(world, entityId, parentId, options?)`
|
|
92
|
+
|
|
93
|
+
Re-parent an entity at runtime. Updates the `ParentId` component and reconciles the Three.js scene graph on the same frame. By default (`preserveWorldTransform: true`), world-space position and rotation are preserved by adjusting the local transform:
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
// Attach child to a parent entity (preserves world position)
|
|
97
|
+
oms.setParent(world, childEntityId, parentEntityId);
|
|
98
|
+
|
|
99
|
+
// Detach from parent — make direct child of scene root
|
|
100
|
+
oms.setParent(world, childEntityId, null);
|
|
101
|
+
|
|
102
|
+
// Reparent without preserving world position (local transform reset)
|
|
103
|
+
oms.setParent(world, childEntityId, parentEntityId, { preserveWorldTransform: false });
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
`setParent` guards against cycles and returns `false` if the operation would create a loop or if either entity does not exist.
|
|
107
|
+
|
|
38
108
|
- Source: [`core/systems/ObjectManagementSystem.ts`](https://github.com/Relu-Interactives/relu-spatial-ecs-engine/blob/main/core/systems/ObjectManagementSystem.ts)
|
|
@@ -102,6 +102,8 @@ Both methods accept `Vec3` (`THREE.Vector3` or `{ x, y, z }`) and return `Inters
|
|
|
102
102
|
| `getSystem(SystemClass)` | Resolve a registered system instance. |
|
|
103
103
|
| `hasSystem(SystemClass)` | `true` if the system is registered. |
|
|
104
104
|
| `getObjectManagementSystem()` | Shorthand for the built-in `ObjectManagementSystem`. Use this to spawn or destroy entities at runtime (`requestCreate`, `createNow`, `deleteEntity`). |
|
|
105
|
+
| `getEnvironmentComponent()` | Returns the singleton [`Environment`](./scene/environment) component, or `undefined` if not yet initialized. Mutate `values` to change skybox, fog, or gravity at runtime. |
|
|
106
|
+
| `getPostprocessingComponent()` | Returns the singleton [`Postprocessing`](./scene/postprocessing) component, or `undefined` if not yet initialized. Mutate `values` to toggle effects or adjust parameters at runtime. |
|
|
105
107
|
|
|
106
108
|
### World lifecycle
|
|
107
109
|
|
|
@@ -398,6 +400,6 @@ export default class PauseOnHit extends Behaviour {
|
|
|
398
400
|
## See also
|
|
399
401
|
|
|
400
402
|
- [Custom Behaviours](./authoring-a-behaviour) — `init`, `onUpdate`, `dispose`, `data`, lifecycle.
|
|
401
|
-
- [
|
|
403
|
+
- [Behaviour Data Binding](./behaviour-data-binding/) — exposing fields to the inspector through `data`.
|
|
402
404
|
- [Behaviour Lifecycle & Events](./behaviour-lifecycle) — when each hook fires.
|
|
403
405
|
- [Component Catalog](./component-catalog) — the components you'll read and mutate from scripts.
|