@relu-interactives/spatial-ecs 0.2.15 → 0.2.16

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.
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
- var THREE27 = require('three');
3
+ var THREE28 = require('three');
4
+ var SkeletonUtils_js = require('three/examples/jsm/utils/SkeletonUtils.js');
4
5
  var RectAreaLightHelper_js = require('three/examples/jsm/helpers/RectAreaLightHelper.js');
5
6
  var DRACOLoader_js = require('three/examples/jsm/loaders/DRACOLoader.js');
6
7
  var GLTFLoader_js = require('three/examples/jsm/loaders/GLTFLoader.js');
@@ -24,7 +25,7 @@ function _interopNamespace(e) {
24
25
  return Object.freeze(n);
25
26
  }
26
27
 
27
- var THREE27__namespace = /*#__PURE__*/_interopNamespace(THREE27);
28
+ var THREE28__namespace = /*#__PURE__*/_interopNamespace(THREE28);
28
29
 
29
30
  var __defProp = Object.defineProperty;
30
31
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
@@ -297,14 +298,14 @@ var _AnimationComponent = class _AnimationComponent extends Component {
297
298
  return;
298
299
  }
299
300
  this.importedClips = clips.map((entry) => {
300
- if (entry instanceof THREE27__namespace.AnimationClip) {
301
+ if (entry instanceof THREE28__namespace.AnimationClip) {
301
302
  return { clip: entry, sourceUrl: null };
302
303
  }
303
304
  if (!entry || typeof entry !== "object") {
304
305
  return null;
305
306
  }
306
307
  const candidate = entry;
307
- if (!(candidate.clip instanceof THREE27__namespace.AnimationClip)) {
308
+ if (!(candidate.clip instanceof THREE28__namespace.AnimationClip)) {
308
309
  return null;
309
310
  }
310
311
  return {
@@ -512,11 +513,11 @@ function normalizeDistanceModel(distanceModel) {
512
513
  }
513
514
  __name(normalizeDistanceModel, "normalizeDistanceModel");
514
515
  function createConfiguredAudio(listener, options) {
515
- const sound = options.positional ? new THREE27__namespace.PositionalAudio(listener) : new THREE27__namespace.Audio(listener);
516
+ const sound = options.positional ? new THREE28__namespace.PositionalAudio(listener) : new THREE28__namespace.Audio(listener);
516
517
  sound.setLoop(options.loop);
517
518
  sound.setVolume(options.volume);
518
519
  sound.setPlaybackRate(options.pitch);
519
- if (sound instanceof THREE27__namespace.PositionalAudio) {
520
+ if (sound instanceof THREE28__namespace.PositionalAudio) {
520
521
  sound.setRefDistance(options.refDistance);
521
522
  sound.setDistanceModel(normalizeDistanceModel(options.distanceModel));
522
523
  sound.setRolloffFactor(options.rolloffFactor);
@@ -526,16 +527,16 @@ function createConfiguredAudio(listener, options) {
526
527
  __name(createConfiguredAudio, "createConfiguredAudio");
527
528
  function createAudioEditorHelper() {
528
529
  if (typeof document === "undefined") {
529
- const geometry = new THREE27__namespace.EdgesGeometry(
530
- new THREE27__namespace.OctahedronGeometry(0.22, 0)
530
+ const geometry = new THREE28__namespace.EdgesGeometry(
531
+ new THREE28__namespace.OctahedronGeometry(0.22, 0)
531
532
  );
532
- const material2 = new THREE27__namespace.LineBasicMaterial({
533
+ const material2 = new THREE28__namespace.LineBasicMaterial({
533
534
  color: "#8bc8ff",
534
535
  transparent: true,
535
536
  opacity: 0.95,
536
537
  depthTest: false
537
538
  });
538
- const fallback = new THREE27__namespace.LineSegments(geometry, material2);
539
+ const fallback = new THREE28__namespace.LineSegments(geometry, material2);
539
540
  fallback.renderOrder = 10;
540
541
  fallback.userData.ecsHelper = true;
541
542
  fallback.visible = false;
@@ -547,7 +548,7 @@ function createAudioEditorHelper() {
547
548
  canvas.height = size;
548
549
  const ctx = canvas.getContext("2d");
549
550
  if (!ctx) {
550
- return new THREE27__namespace.Object3D();
551
+ return new THREE28__namespace.Object3D();
551
552
  }
552
553
  ctx.clearRect(0, 0, size, size);
553
554
  ctx.fillStyle = "rgba(27, 35, 52, 0.9)";
@@ -578,14 +579,14 @@ function createAudioEditorHelper() {
578
579
  ctx.beginPath();
579
580
  ctx.arc(56, 48, 16, -0.8, 0.8);
580
581
  ctx.stroke();
581
- const texture = new THREE27__namespace.CanvasTexture(canvas);
582
+ const texture = new THREE28__namespace.CanvasTexture(canvas);
582
583
  texture.needsUpdate = true;
583
- const material = new THREE27__namespace.SpriteMaterial({
584
+ const material = new THREE28__namespace.SpriteMaterial({
584
585
  map: texture,
585
586
  transparent: true,
586
587
  depthTest: false
587
588
  });
588
- const helper = new THREE27__namespace.Sprite(material);
589
+ const helper = new THREE28__namespace.Sprite(material);
589
590
  helper.scale.set(0.68, 0.68, 0.68);
590
591
  helper.renderOrder = 10;
591
592
  helper.userData.ecsHelper = true;
@@ -619,7 +620,7 @@ var DEFAULT_ORTHO_TOP = 5;
619
620
  var DEFAULT_ORTHO_BOTTOM = -5;
620
621
  var DEFAULT_ZOOM = 1;
621
622
  function inferProjection(camera) {
622
- if (camera instanceof THREE27__namespace.OrthographicCamera) {
623
+ if (camera instanceof THREE28__namespace.OrthographicCamera) {
623
624
  return "orthographic";
624
625
  }
625
626
  return "perspective";
@@ -640,7 +641,7 @@ function readCameraFar(camera) {
640
641
  }
641
642
  __name(readCameraFar, "readCameraFar");
642
643
  function inferFov(camera) {
643
- if (camera instanceof THREE27__namespace.PerspectiveCamera && Number.isFinite(camera.fov)) {
644
+ if (camera instanceof THREE28__namespace.PerspectiveCamera && Number.isFinite(camera.fov)) {
644
645
  return camera.fov;
645
646
  }
646
647
  return DEFAULT_FOV;
@@ -663,28 +664,28 @@ function inferFar(camera) {
663
664
  }
664
665
  __name(inferFar, "inferFar");
665
666
  function inferOrthoLeft(camera) {
666
- if (camera instanceof THREE27__namespace.OrthographicCamera && Number.isFinite(camera.left)) {
667
+ if (camera instanceof THREE28__namespace.OrthographicCamera && Number.isFinite(camera.left)) {
667
668
  return camera.left;
668
669
  }
669
670
  return DEFAULT_ORTHO_LEFT;
670
671
  }
671
672
  __name(inferOrthoLeft, "inferOrthoLeft");
672
673
  function inferOrthoRight(camera) {
673
- if (camera instanceof THREE27__namespace.OrthographicCamera && Number.isFinite(camera.right)) {
674
+ if (camera instanceof THREE28__namespace.OrthographicCamera && Number.isFinite(camera.right)) {
674
675
  return camera.right;
675
676
  }
676
677
  return DEFAULT_ORTHO_RIGHT;
677
678
  }
678
679
  __name(inferOrthoRight, "inferOrthoRight");
679
680
  function inferOrthoTop(camera) {
680
- if (camera instanceof THREE27__namespace.OrthographicCamera && Number.isFinite(camera.top)) {
681
+ if (camera instanceof THREE28__namespace.OrthographicCamera && Number.isFinite(camera.top)) {
681
682
  return camera.top;
682
683
  }
683
684
  return DEFAULT_ORTHO_TOP;
684
685
  }
685
686
  __name(inferOrthoTop, "inferOrthoTop");
686
687
  function inferOrthoBottom(camera) {
687
- if (camera instanceof THREE27__namespace.OrthographicCamera && Number.isFinite(camera.bottom)) {
688
+ if (camera instanceof THREE28__namespace.OrthographicCamera && Number.isFinite(camera.bottom)) {
688
689
  return camera.bottom;
689
690
  }
690
691
  return DEFAULT_ORTHO_BOTTOM;
@@ -700,7 +701,7 @@ __name(inferZoom, "inferZoom");
700
701
  var _CameraComponent = class _CameraComponent extends Component {
701
702
  constructor(payload = {}) {
702
703
  super();
703
- this.camera = payload.camera ?? new THREE27__namespace.PerspectiveCamera();
704
+ this.camera = payload.camera ?? new THREE28__namespace.PerspectiveCamera();
704
705
  this.type = payload.type ?? "3d";
705
706
  this.isDefault = typeof payload.isDefault === "boolean" ? payload.isDefault : false;
706
707
  this.projection = payload.projection ?? inferProjection(payload.camera);
@@ -731,7 +732,7 @@ var Object3DRef = _Object3DRef;
731
732
  // core/factories/components/CameraFactory.ts
732
733
  function createCameraComponent(world, entityId, payload = {}) {
733
734
  const object = world.getComponent(entityId, Object3DRef)?.object;
734
- const objectCamera = object instanceof THREE27__namespace.Camera ? object : void 0;
735
+ const objectCamera = object instanceof THREE28__namespace.Camera ? object : void 0;
735
736
  const component = new CameraComponent({
736
737
  ...payload,
737
738
  camera: payload.camera ?? objectCamera
@@ -1160,15 +1161,15 @@ function createValueState(light) {
1160
1161
  castShadow: light.castShadow ?? false,
1161
1162
  frustumCulling: light.frustumCulled
1162
1163
  };
1163
- if (light instanceof THREE27__namespace.PointLight) {
1164
+ if (light instanceof THREE28__namespace.PointLight) {
1164
1165
  base.distance = light.distance;
1165
1166
  base.decay = light.decay;
1166
- } else if (light instanceof THREE27__namespace.SpotLight) {
1167
+ } else if (light instanceof THREE28__namespace.SpotLight) {
1167
1168
  base.distance = light.distance;
1168
1169
  base.decay = light.decay;
1169
1170
  base.angle = light.angle;
1170
1171
  base.penumbra = light.penumbra;
1171
- } else if (light instanceof THREE27__namespace.RectAreaLight) {
1172
+ } else if (light instanceof THREE28__namespace.RectAreaLight) {
1172
1173
  base.width = light.width;
1173
1174
  base.height = light.height;
1174
1175
  }
@@ -1211,13 +1212,13 @@ function toHexColor2(value, fallback) {
1211
1212
  }
1212
1213
  __name(toHexColor2, "toHexColor");
1213
1214
  function getMaterialType(material) {
1214
- if (material instanceof THREE27__namespace.MeshPhysicalMaterial) {
1215
+ if (material instanceof THREE28__namespace.MeshPhysicalMaterial) {
1215
1216
  return "physical";
1216
1217
  }
1217
- if (material instanceof THREE27__namespace.MeshPhongMaterial) {
1218
+ if (material instanceof THREE28__namespace.MeshPhongMaterial) {
1218
1219
  return "phong";
1219
1220
  }
1220
- if (material instanceof THREE27__namespace.MeshBasicMaterial) {
1221
+ if (material instanceof THREE28__namespace.MeshBasicMaterial) {
1221
1222
  return "basic";
1222
1223
  }
1223
1224
  return "standard";
@@ -1236,8 +1237,8 @@ function createMaterialValue(material) {
1236
1237
  opacity: typeof materialRecord.opacity === "number" ? materialRecord.opacity : 1,
1237
1238
  emissive: toHexColor2(materialRecord.emissive, "#000000"),
1238
1239
  emissiveIntensity: typeof materialRecord.emissiveIntensity === "number" ? materialRecord.emissiveIntensity : 0,
1239
- side: typeof materialRecord.side === "number" ? materialRecord.side : THREE27__namespace.FrontSide,
1240
- blending: typeof materialRecord.blending === "number" ? materialRecord.blending : THREE27__namespace.NormalBlending,
1240
+ side: typeof materialRecord.side === "number" ? materialRecord.side : THREE28__namespace.FrontSide,
1241
+ blending: typeof materialRecord.blending === "number" ? materialRecord.blending : THREE28__namespace.NormalBlending,
1241
1242
  depthTest: materialRecord.depthTest !== false,
1242
1243
  depthWrite: materialRecord.depthWrite !== false,
1243
1244
  wireframe: Boolean(materialRecord.wireframe),
@@ -1253,7 +1254,7 @@ function createMaterialValue(material) {
1253
1254
  displacementMap: materialRecord.displacementMap?.image?.src,
1254
1255
  lightMap: materialRecord.lightMap?.image?.src,
1255
1256
  envMap: materialRecord.envMap?.image?.src,
1256
- textureFiltering: map?.magFilter === THREE27__namespace.NearestFilter ? "sharp" : "smooth",
1257
+ textureFiltering: map?.magFilter === THREE28__namespace.NearestFilter ? "sharp" : "smooth",
1257
1258
  useMipmaps: map?.generateMipmaps !== false
1258
1259
  };
1259
1260
  }
@@ -1268,8 +1269,8 @@ function defaultMaterialValue() {
1268
1269
  opacity: 1,
1269
1270
  emissive: "#000000",
1270
1271
  emissiveIntensity: 0,
1271
- side: THREE27__namespace.FrontSide,
1272
- blending: THREE27__namespace.NormalBlending,
1272
+ side: THREE28__namespace.FrontSide,
1273
+ blending: THREE28__namespace.NormalBlending,
1273
1274
  depthTest: true,
1274
1275
  depthWrite: true,
1275
1276
  wireframe: false,
@@ -1860,14 +1861,14 @@ var _TransformComponent = class _TransformComponent extends Component {
1860
1861
  z: scale.z ?? 1
1861
1862
  };
1862
1863
  }
1863
- toPositionVector3(target = new THREE27.Vector3()) {
1864
+ toPositionVector3(target = new THREE28.Vector3()) {
1864
1865
  return target.set(this.position.x, this.position.y, this.position.z);
1865
1866
  }
1866
- toRotationEuler(target = new THREE27.Euler(), order = "XYZ") {
1867
+ toRotationEuler(target = new THREE28.Euler(), order = "XYZ") {
1867
1868
  return target.set(this.rotation.x, this.rotation.y, this.rotation.z, order);
1868
1869
  }
1869
- toRotationQuaternion(target = new THREE27.Quaternion(), order = "XYZ") {
1870
- const euler = new THREE27.Euler(
1870
+ toRotationQuaternion(target = new THREE28.Quaternion(), order = "XYZ") {
1871
+ const euler = new THREE28.Euler(
1871
1872
  this.rotation.x,
1872
1873
  this.rotation.y,
1873
1874
  this.rotation.z,
@@ -1875,7 +1876,7 @@ var _TransformComponent = class _TransformComponent extends Component {
1875
1876
  );
1876
1877
  return target.setFromEuler(euler);
1877
1878
  }
1878
- toScaleVector3(target = new THREE27.Vector3()) {
1879
+ toScaleVector3(target = new THREE28.Vector3()) {
1879
1880
  return target.set(this.scale.x, this.scale.y, this.scale.z);
1880
1881
  }
1881
1882
  setPosition(input) {
@@ -1893,8 +1894,8 @@ var _TransformComponent = class _TransformComponent extends Component {
1893
1894
  return this;
1894
1895
  }
1895
1896
  setRotation(input, order = "XYZ") {
1896
- if (input instanceof THREE27.Quaternion) {
1897
- const euler = new THREE27.Euler().setFromQuaternion(input, order);
1897
+ if (input instanceof THREE28.Quaternion) {
1898
+ const euler = new THREE28.Euler().setFromQuaternion(input, order);
1898
1899
  this.rotation.x = euler.x;
1899
1900
  this.rotation.y = euler.y;
1900
1901
  this.rotation.z = euler.z;
@@ -2143,6 +2144,46 @@ function registerDefaultComponentFactories(objectManagementSystem) {
2143
2144
  objectManagementSystem.registerComponentFactory("instancedMesh", createInstancedMeshComponent);
2144
2145
  }
2145
2146
  __name(registerDefaultComponentFactories, "registerDefaultComponentFactories");
2147
+ var SHARED_MODEL_RESOURCE_FLAG = "spatialEcsSharedModelResource";
2148
+ var modelCache = /* @__PURE__ */ new Map();
2149
+ function markSharedResources(root) {
2150
+ root.traverse((child) => {
2151
+ if (!(child instanceof THREE28__namespace.Mesh)) {
2152
+ return;
2153
+ }
2154
+ if (child.geometry) {
2155
+ child.geometry.userData[SHARED_MODEL_RESOURCE_FLAG] = true;
2156
+ }
2157
+ const materials = Array.isArray(child.material) ? child.material : [child.material];
2158
+ for (const material of materials) {
2159
+ if (material) {
2160
+ material.userData[SHARED_MODEL_RESOURCE_FLAG] = true;
2161
+ }
2162
+ }
2163
+ });
2164
+ }
2165
+ __name(markSharedResources, "markSharedResources");
2166
+ function loadSharedGltf(url, load) {
2167
+ let pending = modelCache.get(url);
2168
+ if (!pending) {
2169
+ pending = load().then((gltf) => {
2170
+ markSharedResources(gltf.scene);
2171
+ return gltf;
2172
+ });
2173
+ pending.catch(() => {
2174
+ modelCache.delete(url);
2175
+ });
2176
+ modelCache.set(url, pending);
2177
+ }
2178
+ return pending;
2179
+ }
2180
+ __name(loadSharedGltf, "loadSharedGltf");
2181
+ function cloneModelScene(scene) {
2182
+ return SkeletonUtils_js.clone(scene);
2183
+ }
2184
+ __name(cloneModelScene, "cloneModelScene");
2185
+
2186
+ // core/systems/ObjectManagementSystem.ts
2146
2187
  function createTransform(input) {
2147
2188
  return new TransformComponent(input);
2148
2189
  }
@@ -2181,10 +2222,10 @@ __name(createBaseEntity, "createBaseEntity");
2181
2222
  // core/factories/objects/AudioFactory.ts
2182
2223
  function getOrCreateListener(camera) {
2183
2224
  const existing = camera.userData.ecsAudioListener;
2184
- if (existing instanceof THREE27__namespace.AudioListener) {
2225
+ if (existing instanceof THREE28__namespace.AudioListener) {
2185
2226
  return existing;
2186
2227
  }
2187
- const listener = new THREE27__namespace.AudioListener();
2228
+ const listener = new THREE28__namespace.AudioListener();
2188
2229
  camera.add(listener);
2189
2230
  camera.userData.ecsAudioListener = listener;
2190
2231
  return listener;
@@ -2197,7 +2238,7 @@ function createAudio({
2197
2238
  payload,
2198
2239
  isEditor
2199
2240
  }) {
2200
- const anchor = new THREE27__namespace.Object3D();
2241
+ const anchor = new THREE28__namespace.Object3D();
2201
2242
  const entityId = createBaseEntity(world, anchor, {
2202
2243
  label: payload.name ?? "Audio",
2203
2244
  entityType: "audio",
@@ -2219,7 +2260,7 @@ function createAudio({
2219
2260
  return entityId;
2220
2261
  }
2221
2262
  if (!isEditor) {
2222
- const loader = new THREE27__namespace.AudioLoader();
2263
+ const loader = new THREE28__namespace.AudioLoader();
2223
2264
  loader.load(
2224
2265
  audio.path,
2225
2266
  (buffer) => {
@@ -2294,7 +2335,7 @@ function applyCameraSettings(camera, options) {
2294
2335
  const near = typeof options.near === "number" ? options.near : DEFAULT_NEAR2;
2295
2336
  const far = typeof options.far === "number" ? options.far : DEFAULT_FAR2;
2296
2337
  const projection = options.projection;
2297
- if (camera instanceof THREE27__namespace.PerspectiveCamera) {
2338
+ if (camera instanceof THREE28__namespace.PerspectiveCamera) {
2298
2339
  if (!projection || projection === "perspective") {
2299
2340
  camera.fov = typeof options.fov === "number" ? options.fov : DEFAULT_FOV2;
2300
2341
  }
@@ -2304,7 +2345,7 @@ function applyCameraSettings(camera, options) {
2304
2345
  camera.updateProjectionMatrix();
2305
2346
  return;
2306
2347
  }
2307
- if (camera instanceof THREE27__namespace.OrthographicCamera) {
2348
+ if (camera instanceof THREE28__namespace.OrthographicCamera) {
2308
2349
  camera.left = typeof options.left === "number" ? options.left : -DEFAULT_ORTHOGRAPHIC_HALF_HEIGHT;
2309
2350
  camera.right = typeof options.right === "number" ? options.right : DEFAULT_ORTHOGRAPHIC_HALF_HEIGHT;
2310
2351
  camera.top = typeof options.top === "number" ? options.top : DEFAULT_ORTHOGRAPHIC_HALF_HEIGHT;
@@ -2325,7 +2366,7 @@ function createCameraObject(options) {
2325
2366
  const bottom = options.bottom ?? -DEFAULT_ORTHOGRAPHIC_HALF_HEIGHT;
2326
2367
  const left = options.left ?? -DEFAULT_ORTHOGRAPHIC_HALF_HEIGHT;
2327
2368
  const right = options.right ?? DEFAULT_ORTHOGRAPHIC_HALF_HEIGHT;
2328
- const camera = new THREE27__namespace.OrthographicCamera(
2369
+ const camera = new THREE28__namespace.OrthographicCamera(
2329
2370
  left,
2330
2371
  right,
2331
2372
  top,
@@ -2337,7 +2378,7 @@ function createCameraObject(options) {
2337
2378
  camera.updateProjectionMatrix();
2338
2379
  return camera;
2339
2380
  }
2340
- return new THREE27__namespace.PerspectiveCamera(
2381
+ return new THREE28__namespace.PerspectiveCamera(
2341
2382
  options.fov ?? DEFAULT_FOV2,
2342
2383
  readViewportAspect(),
2343
2384
  near,
@@ -2355,7 +2396,7 @@ function createCamera({ world, scene, camera, payload, isEditor }) {
2355
2396
  transformInput: payload.transform
2356
2397
  });
2357
2398
  const objectRef = world.getComponent(entityId, Object3DRef);
2358
- if (objectRef?.object instanceof THREE27__namespace.Camera) {
2399
+ if (objectRef?.object instanceof THREE28__namespace.Camera) {
2359
2400
  objectRef.object.userData.entityId = entityId;
2360
2401
  }
2361
2402
  const componentOptions = {
@@ -2378,7 +2419,7 @@ function createCamera({ world, scene, camera, payload, isEditor }) {
2378
2419
  } else {
2379
2420
  applyCameraSettings(object, options);
2380
2421
  if (isEditor && component.isDefault) {
2381
- const helper = new THREE27__namespace.CameraHelper(object);
2422
+ const helper = new THREE28__namespace.CameraHelper(object);
2382
2423
  helper.onBeforeRender = () => {
2383
2424
  helper.update();
2384
2425
  };
@@ -2396,9 +2437,9 @@ function createCapsule({
2396
2437
  scene,
2397
2438
  payload
2398
2439
  }) {
2399
- const geometry = new THREE27__namespace.CapsuleGeometry(0.5, 1, 4, 8);
2400
- const material = new THREE27__namespace.MeshStandardMaterial({ color: "#ffffff" });
2401
- const mesh = new THREE27__namespace.Mesh(geometry, material);
2440
+ const geometry = new THREE28__namespace.CapsuleGeometry(0.5, 1, 4, 8);
2441
+ const material = new THREE28__namespace.MeshStandardMaterial({ color: "#ffffff" });
2442
+ const mesh = new THREE28__namespace.Mesh(geometry, material);
2402
2443
  const entityId = createBaseEntity(world, mesh, {
2403
2444
  label: payload.name ?? "Capsule",
2404
2445
  entityType: "capsule",
@@ -2418,9 +2459,9 @@ function createCapsule({
2418
2459
  }
2419
2460
  __name(createCapsule, "createCapsule");
2420
2461
  function createCube({ world, scene, payload }) {
2421
- const geometry = new THREE27__namespace.BoxGeometry(1, 1, 1);
2422
- const material = new THREE27__namespace.MeshStandardMaterial({ color: "#ffffff" });
2423
- const mesh = new THREE27__namespace.Mesh(geometry, material);
2462
+ const geometry = new THREE28__namespace.BoxGeometry(1, 1, 1);
2463
+ const material = new THREE28__namespace.MeshStandardMaterial({ color: "#ffffff" });
2464
+ const mesh = new THREE28__namespace.Mesh(geometry, material);
2424
2465
  const entityId = createBaseEntity(world, mesh, {
2425
2466
  label: payload.name ?? "Cube",
2426
2467
  entityType: "cube",
@@ -2445,9 +2486,9 @@ function createCylinder({
2445
2486
  scene,
2446
2487
  payload
2447
2488
  }) {
2448
- const geometry = new THREE27__namespace.CylinderGeometry(0.5, 0.5, 1, 20);
2449
- const material = new THREE27__namespace.MeshStandardMaterial({ color: "#ffffff" });
2450
- const mesh = new THREE27__namespace.Mesh(geometry, material);
2489
+ const geometry = new THREE28__namespace.CylinderGeometry(0.5, 0.5, 1, 20);
2490
+ const material = new THREE28__namespace.MeshStandardMaterial({ color: "#ffffff" });
2491
+ const mesh = new THREE28__namespace.Mesh(geometry, material);
2451
2492
  const entityId = createBaseEntity(world, mesh, {
2452
2493
  label: payload.name ?? "Cylinder",
2453
2494
  entityType: "cylinder",
@@ -2467,7 +2508,7 @@ function createCylinder({
2467
2508
  }
2468
2509
  __name(createCylinder, "createCylinder");
2469
2510
  function createEmpty({ world, scene, payload, isEditor }) {
2470
- const object = new THREE27__namespace.Group();
2511
+ const object = new THREE28__namespace.Group();
2471
2512
  const entityId = createBaseEntity(world, object, {
2472
2513
  label: payload.name ?? "Empty",
2473
2514
  entityType: "empty",
@@ -2478,7 +2519,7 @@ function createEmpty({ world, scene, payload, isEditor }) {
2478
2519
  }
2479
2520
  __name(createEmpty, "createEmpty");
2480
2521
  function createImage({ world, scene, payload }) {
2481
- const anchor = new THREE27__namespace.Object3D();
2522
+ const anchor = new THREE28__namespace.Object3D();
2482
2523
  const imagePath = payload.path ?? "";
2483
2524
  const entityId = createBaseEntity(world, anchor, {
2484
2525
  label: payload.name ?? "Image",
@@ -2491,7 +2532,7 @@ function createImage({ world, scene, payload }) {
2491
2532
  if (!imagePath) {
2492
2533
  return entityId;
2493
2534
  }
2494
- const loader = new THREE27__namespace.TextureLoader();
2535
+ const loader = new THREE28__namespace.TextureLoader();
2495
2536
  loader.load(
2496
2537
  imagePath,
2497
2538
  (texture) => {
@@ -2499,13 +2540,13 @@ function createImage({ world, scene, payload }) {
2499
2540
  texture.dispose();
2500
2541
  return;
2501
2542
  }
2502
- const material = new THREE27__namespace.MeshBasicMaterial({
2543
+ const material = new THREE28__namespace.MeshBasicMaterial({
2503
2544
  map: texture,
2504
2545
  transparent: true,
2505
- side: THREE27__namespace.DoubleSide
2546
+ side: THREE28__namespace.DoubleSide
2506
2547
  });
2507
- const geometry = new THREE27__namespace.PlaneGeometry(1, 1);
2508
- const plane = new THREE27__namespace.Mesh(geometry, material);
2548
+ const geometry = new THREE28__namespace.PlaneGeometry(1, 1);
2549
+ const plane = new THREE28__namespace.Mesh(geometry, material);
2509
2550
  plane.userData.entityId = entityId;
2510
2551
  const textureImage = texture.image;
2511
2552
  const width = textureImage?.width ?? 1;
@@ -2551,7 +2592,7 @@ function createImageTarget({
2551
2592
  payload,
2552
2593
  isEditor
2553
2594
  }) {
2554
- const anchor = new THREE27__namespace.Object3D();
2595
+ const anchor = new THREE28__namespace.Object3D();
2555
2596
  const imagePath = payload.path ?? "";
2556
2597
  const entityId = createBaseEntity(world, anchor, {
2557
2598
  label: payload.name ?? "Image Target",
@@ -2568,7 +2609,7 @@ function createImageTarget({
2568
2609
  if (!isEditor || !imagePath) {
2569
2610
  return entityId;
2570
2611
  }
2571
- const loader = new THREE27__namespace.TextureLoader();
2612
+ const loader = new THREE28__namespace.TextureLoader();
2572
2613
  loader.load(
2573
2614
  imagePath,
2574
2615
  (texture) => {
@@ -2576,13 +2617,13 @@ function createImageTarget({
2576
2617
  texture.dispose();
2577
2618
  return;
2578
2619
  }
2579
- const material = new THREE27__namespace.MeshBasicMaterial({
2620
+ const material = new THREE28__namespace.MeshBasicMaterial({
2580
2621
  map: texture,
2581
2622
  transparent: true,
2582
- side: THREE27__namespace.DoubleSide
2623
+ side: THREE28__namespace.DoubleSide
2583
2624
  });
2584
- const geometry = new THREE27__namespace.PlaneGeometry(1, 1);
2585
- const plane = new THREE27__namespace.Mesh(geometry, material);
2625
+ const geometry = new THREE28__namespace.PlaneGeometry(1, 1);
2626
+ const plane = new THREE28__namespace.Mesh(geometry, material);
2586
2627
  plane.userData.entityId = entityId;
2587
2628
  const textureImage = texture.image;
2588
2629
  const width = textureImage?.width ?? 1;
@@ -2633,7 +2674,7 @@ function createInstancedMesh({
2633
2674
  scene,
2634
2675
  payload
2635
2676
  }) {
2636
- const anchor = new THREE27__namespace.Object3D();
2677
+ const anchor = new THREE28__namespace.Object3D();
2637
2678
  const opts = payload.options ?? {};
2638
2679
  const meshKind = isInstancedMeshKind(opts.meshKind) ? opts.meshKind : "cube";
2639
2680
  const meshParameters = opts.meshParameters && typeof opts.meshParameters === "object" ? opts.meshParameters : void 0;
@@ -2704,7 +2745,7 @@ function createAmbientLight({
2704
2745
  scene,
2705
2746
  payload
2706
2747
  }) {
2707
- const light = new THREE27__namespace.AmbientLight("#ffffff", 0.6);
2748
+ const light = new THREE28__namespace.AmbientLight("#ffffff", 0.6);
2708
2749
  const entityId = createBaseEntity(world, light, {
2709
2750
  label: payload.name ?? "Ambient Light",
2710
2751
  entityType: "ambientLight",
@@ -2721,7 +2762,7 @@ function createAreaLight({
2721
2762
  payload,
2722
2763
  isEditor
2723
2764
  }) {
2724
- const light = new THREE27__namespace.RectAreaLight("#ffffff", 5, 4, 4);
2765
+ const light = new THREE28__namespace.RectAreaLight("#ffffff", 5, 4, 4);
2725
2766
  light.lookAt(0, 0, 0);
2726
2767
  const entityId = createBaseEntity(world, light, {
2727
2768
  label: payload.name ?? "Area Light",
@@ -2750,7 +2791,7 @@ function createDirectionalLight({
2750
2791
  payload,
2751
2792
  isEditor
2752
2793
  }) {
2753
- const light = new THREE27__namespace.DirectionalLight("#ffffff", 1.5);
2794
+ const light = new THREE28__namespace.DirectionalLight("#ffffff", 1.5);
2754
2795
  light.castShadow = true;
2755
2796
  const entityId = createBaseEntity(world, light, {
2756
2797
  label: payload.name ?? "Directional Light",
@@ -2761,7 +2802,7 @@ function createDirectionalLight({
2761
2802
  });
2762
2803
  createLightComponent(world, entityId, light);
2763
2804
  if (isEditor) {
2764
- const helper = new THREE27__namespace.DirectionalLightHelper(light, 1.8, "#38bdf8");
2805
+ const helper = new THREE28__namespace.DirectionalLightHelper(light, 1.8, "#38bdf8");
2765
2806
  helper.onBeforeRender = () => {
2766
2807
  helper.update();
2767
2808
  };
@@ -2779,7 +2820,7 @@ function createPointLight({
2779
2820
  payload,
2780
2821
  isEditor
2781
2822
  }) {
2782
- const light = new THREE27__namespace.PointLight("#ffffff", 1, 10);
2823
+ const light = new THREE28__namespace.PointLight("#ffffff", 1, 10);
2783
2824
  const entityId = createBaseEntity(world, light, {
2784
2825
  label: payload.name ?? "Point Light",
2785
2826
  entityType: "pointLight",
@@ -2789,7 +2830,7 @@ function createPointLight({
2789
2830
  });
2790
2831
  createLightComponent(world, entityId, light);
2791
2832
  if (isEditor) {
2792
- const helper = new THREE27__namespace.PointLightHelper(light, 0.35, "#fbbf24");
2833
+ const helper = new THREE28__namespace.PointLightHelper(light, 0.35, "#fbbf24");
2793
2834
  helper.onBeforeRender = () => {
2794
2835
  helper.update();
2795
2836
  };
@@ -2807,7 +2848,7 @@ function createSpotLight({
2807
2848
  payload,
2808
2849
  isEditor
2809
2850
  }) {
2810
- const light = new THREE27__namespace.SpotLight("#ffffff", 1, 20, Math.PI / 6, 0.1, 1);
2851
+ const light = new THREE28__namespace.SpotLight("#ffffff", 1, 20, Math.PI / 6, 0.1, 1);
2811
2852
  const entityId = createBaseEntity(world, light, {
2812
2853
  label: payload.name ?? "Spot Light",
2813
2854
  entityType: "spotLight",
@@ -2817,7 +2858,7 @@ function createSpotLight({
2817
2858
  });
2818
2859
  createLightComponent(world, entityId, light);
2819
2860
  if (isEditor) {
2820
- const helper = new THREE27__namespace.SpotLightHelper(light, "#f59e0b");
2861
+ const helper = new THREE28__namespace.SpotLightHelper(light, "#f59e0b");
2821
2862
  helper.onBeforeRender = () => {
2822
2863
  helper.update();
2823
2864
  };
@@ -2854,7 +2895,6 @@ function resolveDracoDecoderPath() {
2854
2895
  __name(resolveDracoDecoderPath, "resolveDracoDecoderPath");
2855
2896
 
2856
2897
  // core/factories/objects/ModelFactory.ts
2857
- var DEFAULT_DRACO_DECODER_PATH = resolveDracoDecoderPath();
2858
2898
  function getModelFileName(path) {
2859
2899
  const segments = path.split(/[\\/]/).filter(Boolean);
2860
2900
  return segments[segments.length - 1] ?? "";
@@ -2864,7 +2904,7 @@ function createModelLoader() {
2864
2904
  const loader = new GLTFLoader_js.GLTFLoader();
2865
2905
  try {
2866
2906
  const dracoLoader = new DRACOLoader_js.DRACOLoader();
2867
- dracoLoader.setDecoderPath(DEFAULT_DRACO_DECODER_PATH);
2907
+ dracoLoader.setDecoderPath(resolveDracoDecoderPath());
2868
2908
  loader.setDRACOLoader(dracoLoader);
2869
2909
  } catch (error) {
2870
2910
  console.warn("DRACOLoader could not be configured. Loading non-Draco models only.", error);
@@ -2872,8 +2912,13 @@ function createModelLoader() {
2872
2912
  return loader;
2873
2913
  }
2874
2914
  __name(createModelLoader, "createModelLoader");
2875
- function createModel({ world, scene, payload }) {
2876
- const anchor = new THREE27__namespace.Object3D();
2915
+ function createModel({
2916
+ world,
2917
+ scene,
2918
+ payload,
2919
+ isEditor
2920
+ }) {
2921
+ const anchor = new THREE28__namespace.Object3D();
2877
2922
  const modelPath = payload.path ?? "";
2878
2923
  const entityId = createBaseEntity(world, anchor, {
2879
2924
  label: payload.name ?? "Model",
@@ -2891,51 +2936,60 @@ function createModel({ world, scene, payload }) {
2891
2936
  if (!modelPath) {
2892
2937
  return entityId;
2893
2938
  }
2894
- const loader = createModelLoader();
2895
- loader.load(
2896
- modelPath,
2897
- (gltf) => {
2898
- if (!world.hasEntity(entityId)) {
2899
- return;
2900
- }
2901
- const object = gltf.scene;
2902
- object.userData.entityId = entityId;
2903
- object.traverse((child) => {
2904
- child.userData.entityId = entityId;
2905
- });
2906
- anchor.add(object);
2907
- model.object = object;
2908
- meshGeometry.object = object;
2909
- if (gltf.animations.length > 0) {
2910
- let animation = world.getComponent(entityId, AnimationComponent);
2911
- if (!animation) {
2912
- animation = createAnimationComponent(world, entityId, {
2913
- clips: gltf.animations,
2914
- externalClipSources: [],
2915
- paused: false,
2916
- reverse: false,
2917
- timeScale: 1,
2918
- crossFadeDuration: 0
2919
- });
2920
- }
2921
- animation.setModelClips(gltf.animations);
2939
+ const attachLoadedModel = /* @__PURE__ */ __name((gltf, object) => {
2940
+ if (!world.hasEntity(entityId)) {
2941
+ return;
2942
+ }
2943
+ object.userData.entityId = entityId;
2944
+ object.traverse((child) => {
2945
+ child.userData.entityId = entityId;
2946
+ });
2947
+ anchor.add(object);
2948
+ model.object = object;
2949
+ meshGeometry.object = object;
2950
+ if (gltf.animations.length > 0) {
2951
+ let animation = world.getComponent(entityId, AnimationComponent);
2952
+ if (!animation) {
2953
+ animation = createAnimationComponent(world, entityId, {
2954
+ clips: gltf.animations,
2955
+ externalClipSources: [],
2956
+ paused: false,
2957
+ reverse: false,
2958
+ timeScale: 1,
2959
+ crossFadeDuration: 0
2960
+ });
2922
2961
  }
2923
- },
2924
- void 0,
2925
- (error) => {
2926
- console.error(`Failed to load model: ${modelPath}`, error);
2962
+ animation.setModelClips(gltf.animations);
2927
2963
  }
2928
- );
2964
+ }, "attachLoadedModel");
2965
+ const onLoadError = /* @__PURE__ */ __name((error) => {
2966
+ console.error(`Failed to load model: ${modelPath}`, error);
2967
+ }, "onLoadError");
2968
+ if (isEditor) {
2969
+ createModelLoader().load(
2970
+ modelPath,
2971
+ (gltf) => attachLoadedModel(gltf, gltf.scene),
2972
+ void 0,
2973
+ onLoadError
2974
+ );
2975
+ } else {
2976
+ loadSharedGltf(
2977
+ modelPath,
2978
+ () => new Promise((resolve, reject) => {
2979
+ createModelLoader().load(modelPath, resolve, void 0, reject);
2980
+ })
2981
+ ).then((gltf) => attachLoadedModel(gltf, cloneModelScene(gltf.scene))).catch(onLoadError);
2982
+ }
2929
2983
  return entityId;
2930
2984
  }
2931
2985
  __name(createModel, "createModel");
2932
2986
  function createPlane({ world, scene, payload }) {
2933
- const geometry = new THREE27__namespace.PlaneGeometry(100, 100);
2934
- const material = new THREE27__namespace.MeshStandardMaterial({
2987
+ const geometry = new THREE28__namespace.PlaneGeometry(100, 100);
2988
+ const material = new THREE28__namespace.MeshStandardMaterial({
2935
2989
  color: "#ffffff",
2936
- side: THREE27__namespace.DoubleSide
2990
+ side: THREE28__namespace.DoubleSide
2937
2991
  });
2938
- const mesh = new THREE27__namespace.Mesh(geometry, material);
2992
+ const mesh = new THREE28__namespace.Mesh(geometry, material);
2939
2993
  const entityId = createBaseEntity(
2940
2994
  world,
2941
2995
  mesh,
@@ -2967,7 +3021,7 @@ function createPlane({ world, scene, payload }) {
2967
3021
  }
2968
3022
  __name(createPlane, "createPlane");
2969
3023
  function createSprite({ world, scene, payload }) {
2970
- const anchor = new THREE27__namespace.Object3D();
3024
+ const anchor = new THREE28__namespace.Object3D();
2971
3025
  const imagePath = payload.path ?? "";
2972
3026
  const entityId = createBaseEntity(world, anchor, {
2973
3027
  label: payload.name ?? "Sprite",
@@ -2979,7 +3033,7 @@ function createSprite({ world, scene, payload }) {
2979
3033
  if (!imagePath) {
2980
3034
  return entityId;
2981
3035
  }
2982
- const loader = new THREE27__namespace.TextureLoader();
3036
+ const loader = new THREE28__namespace.TextureLoader();
2983
3037
  loader.load(
2984
3038
  imagePath,
2985
3039
  (texture) => {
@@ -2987,11 +3041,11 @@ function createSprite({ world, scene, payload }) {
2987
3041
  texture.dispose();
2988
3042
  return;
2989
3043
  }
2990
- const material = new THREE27__namespace.SpriteMaterial({
3044
+ const material = new THREE28__namespace.SpriteMaterial({
2991
3045
  map: texture,
2992
3046
  transparent: true
2993
3047
  });
2994
- const sprite = new THREE27__namespace.Sprite(material);
3048
+ const sprite = new THREE28__namespace.Sprite(material);
2995
3049
  sprite.userData.entityId = entityId;
2996
3050
  const textureImage = texture.image;
2997
3051
  spriteComponent.width = textureImage?.width ?? 1;
@@ -3009,9 +3063,9 @@ function createSprite({ world, scene, payload }) {
3009
3063
  }
3010
3064
  __name(createSprite, "createSprite");
3011
3065
  function createSphere({ world, scene, payload }) {
3012
- const geometry = new THREE27__namespace.SphereGeometry(0.5, 24, 24);
3013
- const material = new THREE27__namespace.MeshStandardMaterial({ color: "#ffffff" });
3014
- const mesh = new THREE27__namespace.Mesh(geometry, material);
3066
+ const geometry = new THREE28__namespace.SphereGeometry(0.5, 24, 24);
3067
+ const material = new THREE28__namespace.MeshStandardMaterial({ color: "#ffffff" });
3068
+ const mesh = new THREE28__namespace.Mesh(geometry, material);
3015
3069
  const entityId = createBaseEntity(world, mesh, {
3016
3070
  label: payload.name ?? "Sphere",
3017
3071
  entityType: "sphere",
@@ -3031,10 +3085,10 @@ function createSphere({ world, scene, payload }) {
3031
3085
  __name(createSphere, "createSphere");
3032
3086
  function getOrCreateListener2(camera) {
3033
3087
  const existing = camera.userData.ecsAudioListener;
3034
- if (existing instanceof THREE27__namespace.AudioListener) {
3088
+ if (existing instanceof THREE28__namespace.AudioListener) {
3035
3089
  return existing;
3036
3090
  }
3037
- const listener = new THREE27__namespace.AudioListener();
3091
+ const listener = new THREE28__namespace.AudioListener();
3038
3092
  camera.add(listener);
3039
3093
  camera.userData.ecsAudioListener = listener;
3040
3094
  return listener;
@@ -3084,10 +3138,10 @@ function normalizeOptions(input) {
3084
3138
  }
3085
3139
  __name(normalizeOptions, "normalizeOptions");
3086
3140
  function createChromaMaterial(texture, options) {
3087
- return new THREE27__namespace.ShaderMaterial({
3141
+ return new THREE28__namespace.ShaderMaterial({
3088
3142
  uniforms: {
3089
3143
  tex: { value: texture },
3090
- keyColor: { value: new THREE27__namespace.Color(options.backgroundColor) },
3144
+ keyColor: { value: new THREE28__namespace.Color(options.backgroundColor) },
3091
3145
  similarity: { value: options.similarity },
3092
3146
  smoothness: { value: options.smoothness },
3093
3147
  spill: { value: options.spill }
@@ -3119,22 +3173,22 @@ function createChromaMaterial(texture, options) {
3119
3173
  }
3120
3174
  `,
3121
3175
  transparent: true,
3122
- side: THREE27__namespace.DoubleSide
3176
+ side: THREE28__namespace.DoubleSide
3123
3177
  });
3124
3178
  }
3125
3179
  __name(createChromaMaterial, "createChromaMaterial");
3126
3180
  function createStandardMaterial(texture) {
3127
- return new THREE27__namespace.MeshBasicMaterial({
3181
+ return new THREE28__namespace.MeshBasicMaterial({
3128
3182
  map: texture,
3129
3183
  transparent: true,
3130
- side: THREE27__namespace.DoubleSide
3184
+ side: THREE28__namespace.DoubleSide
3131
3185
  });
3132
3186
  }
3133
3187
  __name(createStandardMaterial, "createStandardMaterial");
3134
3188
  function createVideoMesh(entityId, texture, options) {
3135
- const geometry = new THREE27__namespace.PlaneGeometry(1, 1);
3189
+ const geometry = new THREE28__namespace.PlaneGeometry(1, 1);
3136
3190
  const material = options.isGreenScreen ? createChromaMaterial(texture, options) : createStandardMaterial(texture);
3137
- const mesh = new THREE27__namespace.Mesh(geometry, material);
3191
+ const mesh = new THREE28__namespace.Mesh(geometry, material);
3138
3192
  mesh.userData.entityId = entityId;
3139
3193
  mesh.scale.set(options.width, options.height, 1);
3140
3194
  return { mesh, material };
@@ -3169,7 +3223,7 @@ function createVideo({
3169
3223
  payload,
3170
3224
  isEditor
3171
3225
  }) {
3172
- const anchor = new THREE27__namespace.Object3D();
3226
+ const anchor = new THREE28__namespace.Object3D();
3173
3227
  const path = payload.path ?? "";
3174
3228
  const options = normalizeOptions(payload.options);
3175
3229
  const entityId = createBaseEntity(world, anchor, {
@@ -3184,8 +3238,8 @@ function createVideo({
3184
3238
  return entityId;
3185
3239
  }
3186
3240
  const video = createVideoElement(path, options);
3187
- const texture = new THREE27__namespace.VideoTexture(video);
3188
- texture.colorSpace = THREE27__namespace.SRGBColorSpace;
3241
+ const texture = new THREE28__namespace.VideoTexture(video);
3242
+ texture.colorSpace = THREE28__namespace.SRGBColorSpace;
3189
3243
  texture.needsUpdate = true;
3190
3244
  const { mesh, material } = createVideoMesh(entityId, texture, options);
3191
3245
  anchor.add(mesh);
@@ -3201,7 +3255,7 @@ function createVideo({
3201
3255
  });
3202
3256
  if (!isEditor && options.positional) {
3203
3257
  const listener = getOrCreateListener2(camera);
3204
- const audioNode = new THREE27__namespace.PositionalAudio(listener);
3258
+ const audioNode = new THREE28__namespace.PositionalAudio(listener);
3205
3259
  audioNode.setVolume(options.volume);
3206
3260
  audioNode.setRefDistance(options.refDistance);
3207
3261
  audioNode.setDistanceModel(normalizeDistanceModel2(options.distanceModel));