@relu-interactives/spatial-ecs 0.2.17 → 0.2.21
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-BeuJ1xt5.d.cts → System-me3iAcMF.d.cts} +150 -1
- package/dist/{System-BeuJ1xt5.d.ts → System-me3iAcMF.d.ts} +150 -1
- package/dist/{Video-Cym2C52L.d.ts → Video-DHnxjGhW.d.ts} +17 -3
- package/dist/{Video-D4B-z74P.d.cts → Video-U9hAnf9y.d.cts} +17 -3
- package/dist/{chunk-EPK6MA7X.js → chunk-5U3YS4JD.js} +1809 -8
- package/dist/chunk-5U3YS4JD.js.map +1 -0
- package/dist/{chunk-GRUK5TNL.js → chunk-AXRCGF63.js} +3 -3
- package/dist/{chunk-GRUK5TNL.js.map → chunk-AXRCGF63.js.map} +1 -1
- package/dist/{chunk-CJW6K3CL.js → chunk-K6KMKKJ6.js} +62 -5
- package/dist/chunk-K6KMKKJ6.js.map +1 -0
- package/dist/{chunk-FTIQQK62.js → chunk-V7BNVTJW.js} +50 -3
- package/dist/chunk-V7BNVTJW.js.map +1 -0
- package/dist/{chunk-R2WMVXZZ.js → chunk-ZXGHKX7N.js} +5 -3
- package/dist/chunk-ZXGHKX7N.js.map +1 -0
- package/dist/components/index.cjs +47 -0
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.d.cts +3 -2
- package/dist/components/index.d.ts +3 -2
- package/dist/components/index.js +1 -1
- package/dist/docs/guide/components/material.md +4 -0
- package/dist/docs/guide/components/physics.md +10 -0
- package/dist/docs/guide/getting-started/editor/assets-browser.md +1 -1
- package/dist/docs/guide/prefabs.md +152 -0
- package/dist/docs/guide/world-api.md +1 -1
- package/dist/factories/index.cjs +136 -64
- package/dist/factories/index.cjs.map +1 -1
- package/dist/factories/index.d.cts +5 -4
- package/dist/factories/index.d.ts +5 -4
- package/dist/factories/index.js +3 -3
- package/dist/{index-BfoOC2CG.d.cts → index-CZo5I5Gs.d.cts} +76 -4
- package/dist/{index-BoJ3_6a3.d.ts → index-D7FSg0Au.d.ts} +76 -4
- package/dist/index.cjs +6386 -4962
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +313 -7
- package/dist/index.d.ts +313 -7
- package/dist/index.js +407 -926
- package/dist/index.js.map +1 -1
- package/dist/systems/index.cjs +1386 -0
- 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.cjs +3 -1
- package/dist/worldSnapshotUtils.cjs.map +1 -1
- package/dist/worldSnapshotUtils.d.cts +1 -1
- package/dist/worldSnapshotUtils.d.ts +1 -1
- package/dist/worldSnapshotUtils.js +1 -1
- package/package.json +4 -2
- package/dist/chunk-CJW6K3CL.js.map +0 -1
- package/dist/chunk-EPK6MA7X.js.map +0 -1
- package/dist/chunk-FTIQQK62.js.map +0 -1
- package/dist/chunk-R2WMVXZZ.js.map +0 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export { A as AnimationComponent, a as AnimationComponentOptions, b as AudioComponent, C as CameraComponent, c as CameraComponentOptions, d as CameraProjection, e as CameraRuntimeType, f as ColliderShape, g as ColliderState, h as CubeMeshParameters, D as DEFAULT_COLLIDER_STATE, i as DEFAULT_INSTANCED_MESH_PARAMETERS, j as DEFAULT_INSTANCE_TRANSFORM, k as DEFAULT_MESH_GEOMETRY_PARAMETERS, l as DEFAULT_PHYSICS_STATE, m as DEFAULT_RIGIDBODY_STATE, E as EditableMeshObjectKind, n as EntityType, I as ImageComponent, o as ImageTarget, p as ImageTargetAnchor, q as ImageTargetAnchorOptions, r as ImageTargetReference, s as InstanceSlotComponent, t as InstanceTransform, u as InstancedMeshComponent, v as InstancedMeshKind, L as LightComponent, w as LightValueState, M as MaterialComponent, x as MaterialTypeValue, y as MaterialValueState, z as MeshComponent, B as MeshGeometryComponent, F as MeshGeometryParameters, G as MeshGeometryParametersByKind, H as ModelComponent, N as Name, O as Object3DRef, P as PhysicsComponent, J as PhysicsState, K as PlaneMeshParameters, R as RadiusHeightMeshParameters, Q as RadiusMeshParameters, S as RigidbodyState, T as RigidbodyType, U as ScriptComponent, V as ScriptEntry, W as Selectable, X as SelectionTransformState, Y as SpriteComponent, Z as TextureFilteringValue, _ as TransformModeValue, $ as TransformSpaceValue, a0 as VideoComponent, a1 as normalizePhysicsState } from '../Video-
|
|
2
|
-
export { D as DEFAULT_ENVIRONMENT_STATE, a as DEFAULT_POSTPROCESSING_STATE, E as Environment, b as EnvironmentFogState, c as EnvironmentFogType, d as EnvironmentGradientEffect, e as EnvironmentSkyboxState, f as EnvironmentSkyboxType, g as EnvironmentState, P as ParentId, h as Postprocessing, i as PostprocessingState, T as TransformComponent, j as TransformData, V as Vec3 } from '../System-
|
|
1
|
+
export { A as AnimationComponent, a as AnimationComponentOptions, b as AudioComponent, C as CameraComponent, c as CameraComponentOptions, d as CameraProjection, e as CameraRuntimeType, f as ColliderShape, g as ColliderState, h as CubeMeshParameters, D as DEFAULT_COLLIDER_STATE, i as DEFAULT_INSTANCED_MESH_PARAMETERS, j as DEFAULT_INSTANCE_TRANSFORM, k as DEFAULT_MESH_GEOMETRY_PARAMETERS, l as DEFAULT_PHYSICS_STATE, m as DEFAULT_RIGIDBODY_STATE, E as EditableMeshObjectKind, n as EntityType, I as ImageComponent, o as ImageTarget, p as ImageTargetAnchor, q as ImageTargetAnchorOptions, r as ImageTargetReference, s as InstanceSlotComponent, t as InstanceTransform, u as InstancedMeshComponent, v as InstancedMeshKind, L as LightComponent, w as LightValueState, M as MaterialComponent, x as MaterialTypeValue, y as MaterialValueState, z as MeshComponent, B as MeshGeometryComponent, F as MeshGeometryParameters, G as MeshGeometryParametersByKind, H as ModelComponent, N as Name, O as Object3DRef, P as PhysicsComponent, J as PhysicsState, K as PlaneMeshParameters, R as RadiusHeightMeshParameters, Q as RadiusMeshParameters, S as RigidbodyState, T as RigidbodyType, U as ScriptComponent, V as ScriptEntry, W as Selectable, X as SelectionTransformState, Y as SpriteComponent, Z as TextureFilteringValue, _ as TransformModeValue, $ as TransformSpaceValue, a0 as VideoComponent, a1 as defaultMaterialValue, a2 as normalizePhysicsState } from '../Video-U9hAnf9y.cjs';
|
|
2
|
+
export { D as DEFAULT_ENVIRONMENT_STATE, a as DEFAULT_POSTPROCESSING_STATE, E as Environment, b as EnvironmentFogState, c as EnvironmentFogType, d as EnvironmentGradientEffect, e as EnvironmentSkyboxState, f as EnvironmentSkyboxType, g as EnvironmentState, P as ParentId, h as Postprocessing, i as PostprocessingState, T as TransformComponent, j as TransformData, V as Vec3 } from '../System-me3iAcMF.cjs';
|
|
3
|
+
export { P as PrefabInstance, a as PrefabNode } from '../index-CZo5I5Gs.cjs';
|
|
3
4
|
import 'three';
|
|
4
5
|
import '@dimforge/rapier3d-compat';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export { A as AnimationComponent, a as AnimationComponentOptions, b as AudioComponent, C as CameraComponent, c as CameraComponentOptions, d as CameraProjection, e as CameraRuntimeType, f as ColliderShape, g as ColliderState, h as CubeMeshParameters, D as DEFAULT_COLLIDER_STATE, i as DEFAULT_INSTANCED_MESH_PARAMETERS, j as DEFAULT_INSTANCE_TRANSFORM, k as DEFAULT_MESH_GEOMETRY_PARAMETERS, l as DEFAULT_PHYSICS_STATE, m as DEFAULT_RIGIDBODY_STATE, E as EditableMeshObjectKind, n as EntityType, I as ImageComponent, o as ImageTarget, p as ImageTargetAnchor, q as ImageTargetAnchorOptions, r as ImageTargetReference, s as InstanceSlotComponent, t as InstanceTransform, u as InstancedMeshComponent, v as InstancedMeshKind, L as LightComponent, w as LightValueState, M as MaterialComponent, x as MaterialTypeValue, y as MaterialValueState, z as MeshComponent, B as MeshGeometryComponent, F as MeshGeometryParameters, G as MeshGeometryParametersByKind, H as ModelComponent, N as Name, O as Object3DRef, P as PhysicsComponent, J as PhysicsState, K as PlaneMeshParameters, R as RadiusHeightMeshParameters, Q as RadiusMeshParameters, S as RigidbodyState, T as RigidbodyType, U as ScriptComponent, V as ScriptEntry, W as Selectable, X as SelectionTransformState, Y as SpriteComponent, Z as TextureFilteringValue, _ as TransformModeValue, $ as TransformSpaceValue, a0 as VideoComponent, a1 as normalizePhysicsState } from '../Video-
|
|
2
|
-
export { D as DEFAULT_ENVIRONMENT_STATE, a as DEFAULT_POSTPROCESSING_STATE, E as Environment, b as EnvironmentFogState, c as EnvironmentFogType, d as EnvironmentGradientEffect, e as EnvironmentSkyboxState, f as EnvironmentSkyboxType, g as EnvironmentState, P as ParentId, h as Postprocessing, i as PostprocessingState, T as TransformComponent, j as TransformData, V as Vec3 } from '../System-
|
|
1
|
+
export { A as AnimationComponent, a as AnimationComponentOptions, b as AudioComponent, C as CameraComponent, c as CameraComponentOptions, d as CameraProjection, e as CameraRuntimeType, f as ColliderShape, g as ColliderState, h as CubeMeshParameters, D as DEFAULT_COLLIDER_STATE, i as DEFAULT_INSTANCED_MESH_PARAMETERS, j as DEFAULT_INSTANCE_TRANSFORM, k as DEFAULT_MESH_GEOMETRY_PARAMETERS, l as DEFAULT_PHYSICS_STATE, m as DEFAULT_RIGIDBODY_STATE, E as EditableMeshObjectKind, n as EntityType, I as ImageComponent, o as ImageTarget, p as ImageTargetAnchor, q as ImageTargetAnchorOptions, r as ImageTargetReference, s as InstanceSlotComponent, t as InstanceTransform, u as InstancedMeshComponent, v as InstancedMeshKind, L as LightComponent, w as LightValueState, M as MaterialComponent, x as MaterialTypeValue, y as MaterialValueState, z as MeshComponent, B as MeshGeometryComponent, F as MeshGeometryParameters, G as MeshGeometryParametersByKind, H as ModelComponent, N as Name, O as Object3DRef, P as PhysicsComponent, J as PhysicsState, K as PlaneMeshParameters, R as RadiusHeightMeshParameters, Q as RadiusMeshParameters, S as RigidbodyState, T as RigidbodyType, U as ScriptComponent, V as ScriptEntry, W as Selectable, X as SelectionTransformState, Y as SpriteComponent, Z as TextureFilteringValue, _ as TransformModeValue, $ as TransformSpaceValue, a0 as VideoComponent, a1 as defaultMaterialValue, a2 as normalizePhysicsState } from '../Video-DHnxjGhW.js';
|
|
2
|
+
export { D as DEFAULT_ENVIRONMENT_STATE, a as DEFAULT_POSTPROCESSING_STATE, E as Environment, b as EnvironmentFogState, c as EnvironmentFogType, d as EnvironmentGradientEffect, e as EnvironmentSkyboxState, f as EnvironmentSkyboxType, g as EnvironmentState, P as ParentId, h as Postprocessing, i as PostprocessingState, T as TransformComponent, j as TransformData, V as Vec3 } from '../System-me3iAcMF.js';
|
|
3
|
+
export { P as PrefabInstance, a as PrefabNode } from '../index-D7FSg0Au.js';
|
|
3
4
|
import 'three';
|
|
4
5
|
import '@dimforge/rapier3d-compat';
|
package/dist/components/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { AnimationComponent, AudioComponent, CameraComponent, DEFAULT_COLLIDER_STATE, DEFAULT_ENVIRONMENT_STATE, DEFAULT_INSTANCED_MESH_PARAMETERS, DEFAULT_INSTANCE_TRANSFORM, DEFAULT_MESH_GEOMETRY_PARAMETERS, DEFAULT_PHYSICS_STATE, DEFAULT_POSTPROCESSING_STATE, DEFAULT_RIGIDBODY_STATE, EntityType, Environment, ImageComponent, ImageTarget, ImageTargetAnchor, InstanceSlotComponent, InstancedMeshComponent, LightComponent, MaterialComponent, MeshComponent, MeshGeometryComponent, ModelComponent, Name, Object3DRef, ParentId, PhysicsComponent, Postprocessing, ScriptComponent, Selectable, SelectionTransformState, SpriteComponent, TransformComponent, VideoComponent, normalizePhysicsState } from '../chunk-
|
|
1
|
+
export { AnimationComponent, AudioComponent, CameraComponent, DEFAULT_COLLIDER_STATE, DEFAULT_ENVIRONMENT_STATE, DEFAULT_INSTANCED_MESH_PARAMETERS, DEFAULT_INSTANCE_TRANSFORM, DEFAULT_MESH_GEOMETRY_PARAMETERS, DEFAULT_PHYSICS_STATE, DEFAULT_POSTPROCESSING_STATE, DEFAULT_RIGIDBODY_STATE, EntityType, Environment, ImageComponent, ImageTarget, ImageTargetAnchor, InstanceSlotComponent, InstancedMeshComponent, LightComponent, MaterialComponent, MeshComponent, MeshGeometryComponent, ModelComponent, Name, Object3DRef, ParentId, PhysicsComponent, Postprocessing, PrefabInstance, PrefabNode, ScriptComponent, Selectable, SelectionTransformState, SpriteComponent, TransformComponent, VideoComponent, defaultMaterialValue, normalizePhysicsState } from '../chunk-V7BNVTJW.js';
|
|
2
2
|
import '../chunk-OY7ZODZP.js';
|
|
3
3
|
//# sourceMappingURL=index.js.map
|
|
4
4
|
//# sourceMappingURL=index.js.map
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
Material catalog for an entity. Tracks the live three.js materials (`materials`, `material`) plus serialized authoring state (`values[]`) mirrored from the inspector. Supports `standard`, `basic`, `phong`, and `physical` PBR types with optional texture map slots. Use `setMaterials`, `updateValue`, `setMaterialType`, `setTextureFiltering`, and `setUseMipmaps` to mutate state — these keep `values[]` and the live three.js materials in sync. Texture URLs use the `localasset://` protocol inside the editor.
|
|
4
4
|
|
|
5
|
+
## Shared material assets (editor)
|
|
6
|
+
|
|
7
|
+
The editor can link a material slot to a **material asset** (a `.material` file in the project's asset browser) via the `assetRefs` field — one entry per slot, holding the asset's `localasset://` URL or `null` for a local material. The editor materializes the asset's values into `values[]` and re-applies them to every linked entity whenever the asset is edited. Rendering and the published runtime read only `values[]`; `assetRefs` is editor bookkeeping that persists with the project.
|
|
8
|
+
|
|
5
9
|
> **Managed by:** [`MaterialSyncSystem`](../systems/material-sync-system)
|
|
6
10
|
|
|
7
11
|
## Editor inspector
|
|
@@ -4,6 +4,16 @@ Combined rigid body and collider component backed by Rapier. `values.rigidbody.t
|
|
|
4
4
|
|
|
5
5
|
> **Managed by:** [`PhysicsSyncSystem`](../systems/physics-sync-system)
|
|
6
6
|
|
|
7
|
+
## Collider sizing rules (read before authoring colliders)
|
|
8
|
+
|
|
9
|
+
- **Primitives auto-fit on add** (v0.2.18+): adding a `PhysicsComponent` to a `plane`, `cube`, `sphere`, `capsule`, or `cylinder` derives the collider from the mesh-geometry parameters automatically — a plane gets a thin local-Z slab and a `fixed` body, a cube gets its exact box, and so on. Models and entities without mesh geometry keep the generic 1 m cuboid default and must be sized explicitly. Auto-fit runs only when no explicit values are passed; saved/duplicated components are never altered. If you resize the mesh geometry AFTER adding physics, re-author the collider — it does not track later geometry edits.
|
|
10
|
+
|
|
11
|
+
- `values.collider.size` holds the cuboid's **FULL edge lengths** in meters — NOT half-extents. A 1 m cube is `size: { x: 1, y: 1, z: 1 }`.
|
|
12
|
+
- Collider dimensions (`size`, `radius`, `height`) are authored in **unscaled local units**: `PhysicsSyncSystem` multiplies them by the entity's world scale when building the collider. Author the dimensions of the *unscaled* mesh; scaling the entity keeps mesh and collider matched.
|
|
13
|
+
- `offsetPosition` is **not** multiplied by scale — it is applied in raw units. On a scaled entity, compute the offset in final world units.
|
|
14
|
+
- The collider is axis-aligned to the entity and follows the entity's `TransformComponent` rotation (plus `offsetRotation`). A `plane` primitive is a vertical quad pre-rotated `rotation.x = -π/2` to lie flat — keep that rotation, and put a plane floor's thin cuboid axis on **local Z** (geometry is 100×100 → `size: { x: 100, y: 100, z: 0.05 }`). A flattened `cube` is usually a more robust ground.
|
|
15
|
+
- Model (GLB) colliders are never auto-fitted from geometry — measure the mesh bounds and author dimensions explicitly, or use `trimesh` for complex static geometry.
|
|
16
|
+
|
|
7
17
|
## Editor inspector
|
|
8
18
|
|
|
9
19
|

|
|
@@ -46,7 +46,7 @@ Folders are real directories under `assets/`. You can:
|
|
|
46
46
|
|
|
47
47
|
## Scripts
|
|
48
48
|
|
|
49
|
-
Right-click in the asset browser and pick **New
|
|
49
|
+
Right-click in the asset browser and pick **New Script** to create a `Behaviour` script in place. The editor compiles it and exposes it for attachment via the inspector's **Script** panel. See [Custom Behaviours](../../authoring-a-behaviour).
|
|
50
50
|
|
|
51
51
|
## Related
|
|
52
52
|
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# Prefabs
|
|
2
|
+
|
|
3
|
+
A prefab packages a fully configured entity — its children, components,
|
|
4
|
+
materials, physics, animations, and scripts — into a reusable `.prefab`
|
|
5
|
+
asset. Configure something once (a third-person character, a pickup, an
|
|
6
|
+
enemy), save it as a prefab, then reuse it everywhere: drag copies into the
|
|
7
|
+
scene, or spawn them from scripts at runtime.
|
|
8
|
+
|
|
9
|
+
## File anatomy
|
|
10
|
+
|
|
11
|
+
A `.prefab` file is JSON:
|
|
12
|
+
|
|
13
|
+
```jsonc
|
|
14
|
+
{
|
|
15
|
+
"version": 1,
|
|
16
|
+
"name": "Enemy",
|
|
17
|
+
"snapshot": {
|
|
18
|
+
"entities": [1, 2, 3], // ids renumbered 1..N, root first
|
|
19
|
+
"components": [ // same columnar shape as a world snapshot
|
|
20
|
+
{ "component": "PrefabNode", "entries": [ /* stable per-node uuids */ ] },
|
|
21
|
+
{ "component": "TransformComponent", "entries": [ /* … */ ] }
|
|
22
|
+
// …every other serialized component
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
- Every entity carries a `PrefabNode { nodeId }` — a stable uuid used to
|
|
29
|
+
match instance entities back to the file across sessions and machines.
|
|
30
|
+
- The root's `ParentId` is always `null`; entity references inside the
|
|
31
|
+
subtree (script `EntityInput`/`ComponentInput` fields, instanced-mesh
|
|
32
|
+
slots) are remapped on instantiation. References that pointed *outside*
|
|
33
|
+
the subtree are nulled when the prefab is created.
|
|
34
|
+
- Scene singletons (`Environment`, `Postprocessing`) never serialize into a
|
|
35
|
+
prefab. Cameras and image targets cannot be turned into prefabs.
|
|
36
|
+
|
|
37
|
+
## Creating and editing (editor)
|
|
38
|
+
|
|
39
|
+
- **Create**: drag an entity from the Hierarchy into the Asset Browser. The
|
|
40
|
+
dragged entity automatically becomes the first linked *instance*.
|
|
41
|
+
- **Edit**: double-click the `.prefab` tile — the editor enters **Prefab
|
|
42
|
+
Mode**, showing only the prefab's contents with the full inspector.
|
|
43
|
+
Saving writes the file; closing returns to the scene and applies the
|
|
44
|
+
changes to every instance.
|
|
45
|
+
- **Instantiate**: drag the `.prefab` from the Asset Browser into the
|
|
46
|
+
viewport or onto a Hierarchy row.
|
|
47
|
+
|
|
48
|
+
## Instances and per-property overrides
|
|
49
|
+
|
|
50
|
+
Scene instances stay fully editable. Any property you change on an instance
|
|
51
|
+
(a material color, a script field, a child's transform) becomes an
|
|
52
|
+
**override**: when the prefab asset is edited later, overridden properties
|
|
53
|
+
keep their per-instance values while everything else syncs from the file.
|
|
54
|
+
|
|
55
|
+
Always per-instance (never synced): the instance **root's** position /
|
|
56
|
+
rotation / scale, name, and place in the scene hierarchy.
|
|
57
|
+
|
|
58
|
+
Rules of thumb:
|
|
59
|
+
|
|
60
|
+
- Components or children you *add* to an instance are yours — prefab
|
|
61
|
+
updates never remove them.
|
|
62
|
+
- Components or children you *delete* from an instance come back on the
|
|
63
|
+
next prefab apply (deletion tracking is not supported).
|
|
64
|
+
- "Unpack" in the inspector detaches ONE level — the objects lose their
|
|
65
|
+
link but any nested instances inside survive as standalone instances.
|
|
66
|
+
|
|
67
|
+
## Nested prefabs
|
|
68
|
+
|
|
69
|
+
Prefabs can contain other prefab instances: drag a prefab into an open
|
|
70
|
+
prefab (Prefab Mode), or create a prefab from a subtree that contains whole
|
|
71
|
+
instances. Node identity is scoped per placement, so a prefab may nest two
|
|
72
|
+
copies of the same child prefab and each keeps independent overrides.
|
|
73
|
+
|
|
74
|
+
- Editing a child prefab **cascades**: every prefab file that nests it is
|
|
75
|
+
patched (overrides preserved), and every scene instance updates when you
|
|
76
|
+
close the editor — transitively through any depth of nesting.
|
|
77
|
+
- A prefab can never contain itself, directly or through another prefab
|
|
78
|
+
(the editor rejects the drop).
|
|
79
|
+
- Only *whole* instances nest — a partial slice of an instance can't become
|
|
80
|
+
a prefab.
|
|
81
|
+
- In the scene, content can't be re-parented across a nested instance
|
|
82
|
+
boundary (its identity would change); open the host prefab to
|
|
83
|
+
restructure.
|
|
84
|
+
- Runtime spawning is unaffected: files are fully materialized, so
|
|
85
|
+
`spawnPrefab` needs no resolution regardless of nesting depth.
|
|
86
|
+
|
|
87
|
+
## Spawning at runtime
|
|
88
|
+
|
|
89
|
+
Scripts spawn prefabs with `this.spawnPrefab(source, options?)`. Declare an
|
|
90
|
+
`AssetInput` field and drag the `.prefab` onto it in the editor:
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
import { Behaviour } from "@relu-interactives/spatial-ecs";
|
|
94
|
+
|
|
95
|
+
export default class EnemySpawner extends Behaviour {
|
|
96
|
+
data = {
|
|
97
|
+
// AssetInput — drag Enemy.prefab onto this field in the inspector
|
|
98
|
+
enemyPrefab: { path: "", type: "prefab" },
|
|
99
|
+
spawned: [] as number[],
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
private async spawnWave() {
|
|
103
|
+
for (let i = 0; i < 3; i++) {
|
|
104
|
+
const rootId = await this.spawnPrefab(this.data.enemyPrefab, {
|
|
105
|
+
position: { x: i * 2 - 2, y: 0, z: -6 },
|
|
106
|
+
});
|
|
107
|
+
this.data.spawned.push(rootId);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
private despawnWave() {
|
|
112
|
+
for (const id of this.data.spawned) {
|
|
113
|
+
this.despawn(id); // removes the root and all of its children
|
|
114
|
+
}
|
|
115
|
+
this.data.spawned = [];
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Details:
|
|
121
|
+
|
|
122
|
+
- `spawnPrefab` resolves once the entities exist. Heavy assets inside
|
|
123
|
+
(models, textures, audio) stream in reactively — repeated spawns of the
|
|
124
|
+
same prefab share geometry through the model cache, so waves are cheap.
|
|
125
|
+
- `source` can be an `AssetInput` (`{ path, type }`), a URL string, or a
|
|
126
|
+
pre-loaded `PrefabAsset`.
|
|
127
|
+
- Options: `{ parentId, position, rotation, scale }` — the transform applies
|
|
128
|
+
to the spawned root in its parent's local space.
|
|
129
|
+
- `world.spawnPrefab(...)` / `world.despawnPrefab(id)` expose the same calls
|
|
130
|
+
outside of behaviours.
|
|
131
|
+
|
|
132
|
+
## Preloading and caching
|
|
133
|
+
|
|
134
|
+
Each prefab URL is fetched and parsed once per session (`loadPrefab` caches
|
|
135
|
+
the parsed file; failed loads retry). Published experiences preload prefab
|
|
136
|
+
files referenced by script `AssetInput` fields — plus the models and
|
|
137
|
+
textures inside them — before the experience starts, so the first spawn
|
|
138
|
+
does not hitch.
|
|
139
|
+
|
|
140
|
+
## Custom hosts
|
|
141
|
+
|
|
142
|
+
Prefab files store editor-space asset URLs. Published and preview builds
|
|
143
|
+
register a resolver that maps them onto the deployed `assets/` folder:
|
|
144
|
+
|
|
145
|
+
```ts
|
|
146
|
+
import { setPrefabAssetUrlResolver } from "@relu-interactives/spatial-ecs";
|
|
147
|
+
|
|
148
|
+
setPrefabAssetUrlResolver((url) => rewriteToMyCdn(url));
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
The standard project templates already do this — you only need it when
|
|
152
|
+
embedding the runtime in a custom host.
|
|
@@ -430,7 +430,7 @@ export default class PauseOnHit extends Behaviour {
|
|
|
430
430
|
> [!TIP]
|
|
431
431
|
> `pause()` and `resume()` affect the **entire world**. If you only want to
|
|
432
432
|
> stop a subset of entities (for example, freeze enemies while a menu is open)
|
|
433
|
-
> use a flag
|
|
433
|
+
> use a flag in a custom script (`Behaviour`) instead and guard your `onUpdate` logic.
|
|
434
434
|
|
|
435
435
|
## See also
|
|
436
436
|
|
package/dist/factories/index.cjs
CHANGED
|
@@ -929,10 +929,130 @@ var _PhysicsComponent = class _PhysicsComponent extends Component {
|
|
|
929
929
|
};
|
|
930
930
|
__name(_PhysicsComponent, "PhysicsComponent");
|
|
931
931
|
var PhysicsComponent = _PhysicsComponent;
|
|
932
|
+
var DEFAULT_MESH_GEOMETRY_PARAMETERS = {
|
|
933
|
+
capsule: { radius: 0.5, height: 1 },
|
|
934
|
+
cube: { width: 1, height: 1, depth: 1 },
|
|
935
|
+
cylinder: { radius: 0.5, height: 1 },
|
|
936
|
+
plane: { width: 100, height: 100 },
|
|
937
|
+
sphere: { radius: 0.5 }
|
|
938
|
+
};
|
|
939
|
+
var GEOMETRY_TYPE_BY_KIND = {
|
|
940
|
+
capsule: "CapsuleGeometry",
|
|
941
|
+
cube: "BoxGeometry",
|
|
942
|
+
cylinder: "CylinderGeometry",
|
|
943
|
+
model: "Model",
|
|
944
|
+
plane: "PlaneGeometry",
|
|
945
|
+
sphere: "SphereGeometry"
|
|
946
|
+
};
|
|
947
|
+
var _MeshGeometryComponent = class _MeshGeometryComponent extends Component {
|
|
948
|
+
constructor(kind, object, parameters, options) {
|
|
949
|
+
super();
|
|
950
|
+
this.kind = kind;
|
|
951
|
+
this.geometryType = GEOMETRY_TYPE_BY_KIND[kind];
|
|
952
|
+
this.object = object;
|
|
953
|
+
this.modelName = options?.modelName ?? "";
|
|
954
|
+
this.castShadow = options?.castShadow ?? false;
|
|
955
|
+
this.receiveShadow = options?.receiveShadow ?? false;
|
|
956
|
+
switch (kind) {
|
|
957
|
+
case "cube":
|
|
958
|
+
this.parameters = {
|
|
959
|
+
...DEFAULT_MESH_GEOMETRY_PARAMETERS.cube,
|
|
960
|
+
...parameters
|
|
961
|
+
};
|
|
962
|
+
break;
|
|
963
|
+
case "plane":
|
|
964
|
+
this.parameters = {
|
|
965
|
+
...DEFAULT_MESH_GEOMETRY_PARAMETERS.plane,
|
|
966
|
+
...parameters
|
|
967
|
+
};
|
|
968
|
+
break;
|
|
969
|
+
case "sphere":
|
|
970
|
+
this.parameters = {
|
|
971
|
+
...DEFAULT_MESH_GEOMETRY_PARAMETERS.sphere,
|
|
972
|
+
...parameters
|
|
973
|
+
};
|
|
974
|
+
break;
|
|
975
|
+
case "cylinder":
|
|
976
|
+
this.parameters = {
|
|
977
|
+
...DEFAULT_MESH_GEOMETRY_PARAMETERS.cylinder,
|
|
978
|
+
...parameters
|
|
979
|
+
};
|
|
980
|
+
break;
|
|
981
|
+
case "capsule":
|
|
982
|
+
this.parameters = {
|
|
983
|
+
...DEFAULT_MESH_GEOMETRY_PARAMETERS.capsule,
|
|
984
|
+
...parameters
|
|
985
|
+
};
|
|
986
|
+
break;
|
|
987
|
+
case "model":
|
|
988
|
+
this.parameters = {};
|
|
989
|
+
break;
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
};
|
|
993
|
+
__name(_MeshGeometryComponent, "MeshGeometryComponent");
|
|
994
|
+
var MeshGeometryComponent = _MeshGeometryComponent;
|
|
932
995
|
|
|
933
996
|
// core/factories/components/PhysicsFactory.ts
|
|
997
|
+
function deriveColliderFromGeometry(world, entityId) {
|
|
998
|
+
const meshGeometry = world.getComponent(entityId, MeshGeometryComponent);
|
|
999
|
+
if (!meshGeometry) {
|
|
1000
|
+
return null;
|
|
1001
|
+
}
|
|
1002
|
+
switch (meshGeometry.kind) {
|
|
1003
|
+
case "plane": {
|
|
1004
|
+
const params = meshGeometry.parameters;
|
|
1005
|
+
return {
|
|
1006
|
+
collider: {
|
|
1007
|
+
shape: "cuboid",
|
|
1008
|
+
size: { x: params.width, y: params.height, z: 0.05 }
|
|
1009
|
+
},
|
|
1010
|
+
// An (effectively) zero-thickness sheet is only physically meaningful
|
|
1011
|
+
// as static geometry — planes are floors/walls, not dynamic bodies.
|
|
1012
|
+
rigidbody: { type: "fixed" }
|
|
1013
|
+
};
|
|
1014
|
+
}
|
|
1015
|
+
case "cube": {
|
|
1016
|
+
const params = meshGeometry.parameters;
|
|
1017
|
+
return {
|
|
1018
|
+
collider: {
|
|
1019
|
+
shape: "cuboid",
|
|
1020
|
+
size: { x: params.width, y: params.height, z: params.depth }
|
|
1021
|
+
}
|
|
1022
|
+
};
|
|
1023
|
+
}
|
|
1024
|
+
case "sphere": {
|
|
1025
|
+
const params = meshGeometry.parameters;
|
|
1026
|
+
return { collider: { shape: "ball", radius: params.radius } };
|
|
1027
|
+
}
|
|
1028
|
+
case "capsule": {
|
|
1029
|
+
const params = meshGeometry.parameters;
|
|
1030
|
+
return {
|
|
1031
|
+
collider: {
|
|
1032
|
+
shape: "capsule",
|
|
1033
|
+
radius: params.radius,
|
|
1034
|
+
height: params.height
|
|
1035
|
+
}
|
|
1036
|
+
};
|
|
1037
|
+
}
|
|
1038
|
+
case "cylinder": {
|
|
1039
|
+
const params = meshGeometry.parameters;
|
|
1040
|
+
return {
|
|
1041
|
+
collider: {
|
|
1042
|
+
shape: "cylinder",
|
|
1043
|
+
radius: params.radius,
|
|
1044
|
+
height: params.height
|
|
1045
|
+
}
|
|
1046
|
+
};
|
|
1047
|
+
}
|
|
1048
|
+
default:
|
|
1049
|
+
return null;
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
__name(deriveColliderFromGeometry, "deriveColliderFromGeometry");
|
|
934
1053
|
function createPhysicsComponent(world, entityId, values) {
|
|
935
|
-
const
|
|
1054
|
+
const initial = values ?? deriveColliderFromGeometry(world, entityId) ?? void 0;
|
|
1055
|
+
const component = new PhysicsComponent(initial);
|
|
936
1056
|
world.addComponent(entityId, component);
|
|
937
1057
|
return component;
|
|
938
1058
|
}
|
|
@@ -1286,8 +1406,23 @@ var _MaterialComponent = class _MaterialComponent extends Component {
|
|
|
1286
1406
|
this.materials = [];
|
|
1287
1407
|
this.material = null;
|
|
1288
1408
|
this.values = [];
|
|
1409
|
+
this.assetRefs = [];
|
|
1289
1410
|
this.setMaterials(materialOrMaterials);
|
|
1290
1411
|
}
|
|
1412
|
+
/** Link/unlink a slot to a material asset URL (editor bookkeeping only). */
|
|
1413
|
+
setAssetRef(index, url) {
|
|
1414
|
+
if (index < 0) {
|
|
1415
|
+
return;
|
|
1416
|
+
}
|
|
1417
|
+
while (this.assetRefs.length <= index) {
|
|
1418
|
+
this.assetRefs.push(null);
|
|
1419
|
+
}
|
|
1420
|
+
this.assetRefs[index] = url;
|
|
1421
|
+
}
|
|
1422
|
+
/** The material-asset URL a slot is linked to, or null when local. */
|
|
1423
|
+
getAssetRef(index) {
|
|
1424
|
+
return this.assetRefs[index] ?? null;
|
|
1425
|
+
}
|
|
1291
1426
|
setMaterials(materialOrMaterials = []) {
|
|
1292
1427
|
this.materials = Array.isArray(materialOrMaterials) ? materialOrMaterials.filter(Boolean) : materialOrMaterials ? [materialOrMaterials] : [];
|
|
1293
1428
|
this.material = this.materials[0] ?? null;
|
|
@@ -1356,69 +1491,6 @@ function createMeshComponent(world, entityId, ...args) {
|
|
|
1356
1491
|
return component;
|
|
1357
1492
|
}
|
|
1358
1493
|
__name(createMeshComponent, "createMeshComponent");
|
|
1359
|
-
var DEFAULT_MESH_GEOMETRY_PARAMETERS = {
|
|
1360
|
-
capsule: { radius: 0.5, height: 1 },
|
|
1361
|
-
cube: { width: 1, height: 1, depth: 1 },
|
|
1362
|
-
cylinder: { radius: 0.5, height: 1 },
|
|
1363
|
-
plane: { width: 100, height: 100 },
|
|
1364
|
-
sphere: { radius: 0.5 }
|
|
1365
|
-
};
|
|
1366
|
-
var GEOMETRY_TYPE_BY_KIND = {
|
|
1367
|
-
capsule: "CapsuleGeometry",
|
|
1368
|
-
cube: "BoxGeometry",
|
|
1369
|
-
cylinder: "CylinderGeometry",
|
|
1370
|
-
model: "Model",
|
|
1371
|
-
plane: "PlaneGeometry",
|
|
1372
|
-
sphere: "SphereGeometry"
|
|
1373
|
-
};
|
|
1374
|
-
var _MeshGeometryComponent = class _MeshGeometryComponent extends Component {
|
|
1375
|
-
constructor(kind, object, parameters, options) {
|
|
1376
|
-
super();
|
|
1377
|
-
this.kind = kind;
|
|
1378
|
-
this.geometryType = GEOMETRY_TYPE_BY_KIND[kind];
|
|
1379
|
-
this.object = object;
|
|
1380
|
-
this.modelName = options?.modelName ?? "";
|
|
1381
|
-
this.castShadow = options?.castShadow ?? false;
|
|
1382
|
-
this.receiveShadow = options?.receiveShadow ?? false;
|
|
1383
|
-
switch (kind) {
|
|
1384
|
-
case "cube":
|
|
1385
|
-
this.parameters = {
|
|
1386
|
-
...DEFAULT_MESH_GEOMETRY_PARAMETERS.cube,
|
|
1387
|
-
...parameters
|
|
1388
|
-
};
|
|
1389
|
-
break;
|
|
1390
|
-
case "plane":
|
|
1391
|
-
this.parameters = {
|
|
1392
|
-
...DEFAULT_MESH_GEOMETRY_PARAMETERS.plane,
|
|
1393
|
-
...parameters
|
|
1394
|
-
};
|
|
1395
|
-
break;
|
|
1396
|
-
case "sphere":
|
|
1397
|
-
this.parameters = {
|
|
1398
|
-
...DEFAULT_MESH_GEOMETRY_PARAMETERS.sphere,
|
|
1399
|
-
...parameters
|
|
1400
|
-
};
|
|
1401
|
-
break;
|
|
1402
|
-
case "cylinder":
|
|
1403
|
-
this.parameters = {
|
|
1404
|
-
...DEFAULT_MESH_GEOMETRY_PARAMETERS.cylinder,
|
|
1405
|
-
...parameters
|
|
1406
|
-
};
|
|
1407
|
-
break;
|
|
1408
|
-
case "capsule":
|
|
1409
|
-
this.parameters = {
|
|
1410
|
-
...DEFAULT_MESH_GEOMETRY_PARAMETERS.capsule,
|
|
1411
|
-
...parameters
|
|
1412
|
-
};
|
|
1413
|
-
break;
|
|
1414
|
-
case "model":
|
|
1415
|
-
this.parameters = {};
|
|
1416
|
-
break;
|
|
1417
|
-
}
|
|
1418
|
-
}
|
|
1419
|
-
};
|
|
1420
|
-
__name(_MeshGeometryComponent, "MeshGeometryComponent");
|
|
1421
|
-
var MeshGeometryComponent = _MeshGeometryComponent;
|
|
1422
1494
|
|
|
1423
1495
|
// core/factories/components/MeshGeometryFactory.ts
|
|
1424
1496
|
function createMeshGeometryComponent(world, entityId, ...args) {
|