@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.
Files changed (54) hide show
  1. package/dist/{System-BeuJ1xt5.d.cts → System-me3iAcMF.d.cts} +150 -1
  2. package/dist/{System-BeuJ1xt5.d.ts → System-me3iAcMF.d.ts} +150 -1
  3. package/dist/{Video-Cym2C52L.d.ts → Video-DHnxjGhW.d.ts} +17 -3
  4. package/dist/{Video-D4B-z74P.d.cts → Video-U9hAnf9y.d.cts} +17 -3
  5. package/dist/{chunk-EPK6MA7X.js → chunk-5U3YS4JD.js} +1809 -8
  6. package/dist/chunk-5U3YS4JD.js.map +1 -0
  7. package/dist/{chunk-GRUK5TNL.js → chunk-AXRCGF63.js} +3 -3
  8. package/dist/{chunk-GRUK5TNL.js.map → chunk-AXRCGF63.js.map} +1 -1
  9. package/dist/{chunk-CJW6K3CL.js → chunk-K6KMKKJ6.js} +62 -5
  10. package/dist/chunk-K6KMKKJ6.js.map +1 -0
  11. package/dist/{chunk-FTIQQK62.js → chunk-V7BNVTJW.js} +50 -3
  12. package/dist/chunk-V7BNVTJW.js.map +1 -0
  13. package/dist/{chunk-R2WMVXZZ.js → chunk-ZXGHKX7N.js} +5 -3
  14. package/dist/chunk-ZXGHKX7N.js.map +1 -0
  15. package/dist/components/index.cjs +47 -0
  16. package/dist/components/index.cjs.map +1 -1
  17. package/dist/components/index.d.cts +3 -2
  18. package/dist/components/index.d.ts +3 -2
  19. package/dist/components/index.js +1 -1
  20. package/dist/docs/guide/components/material.md +4 -0
  21. package/dist/docs/guide/components/physics.md +10 -0
  22. package/dist/docs/guide/getting-started/editor/assets-browser.md +1 -1
  23. package/dist/docs/guide/prefabs.md +152 -0
  24. package/dist/docs/guide/world-api.md +1 -1
  25. package/dist/factories/index.cjs +136 -64
  26. package/dist/factories/index.cjs.map +1 -1
  27. package/dist/factories/index.d.cts +5 -4
  28. package/dist/factories/index.d.ts +5 -4
  29. package/dist/factories/index.js +3 -3
  30. package/dist/{index-BfoOC2CG.d.cts → index-CZo5I5Gs.d.cts} +76 -4
  31. package/dist/{index-BoJ3_6a3.d.ts → index-D7FSg0Au.d.ts} +76 -4
  32. package/dist/index.cjs +6386 -4962
  33. package/dist/index.cjs.map +1 -1
  34. package/dist/index.d.cts +313 -7
  35. package/dist/index.d.ts +313 -7
  36. package/dist/index.js +407 -926
  37. package/dist/index.js.map +1 -1
  38. package/dist/systems/index.cjs +1386 -0
  39. package/dist/systems/index.cjs.map +1 -1
  40. package/dist/systems/index.d.cts +2 -2
  41. package/dist/systems/index.d.ts +2 -2
  42. package/dist/systems/index.js +3 -3
  43. package/dist/types.d.cts +1 -1
  44. package/dist/types.d.ts +1 -1
  45. package/dist/worldSnapshotUtils.cjs +3 -1
  46. package/dist/worldSnapshotUtils.cjs.map +1 -1
  47. package/dist/worldSnapshotUtils.d.cts +1 -1
  48. package/dist/worldSnapshotUtils.d.ts +1 -1
  49. package/dist/worldSnapshotUtils.js +1 -1
  50. package/package.json +4 -2
  51. package/dist/chunk-CJW6K3CL.js.map +0 -1
  52. package/dist/chunk-EPK6MA7X.js.map +0 -1
  53. package/dist/chunk-FTIQQK62.js.map +0 -1
  54. package/dist/chunk-R2WMVXZZ.js.map +0 -1
@@ -1418,6 +1418,17 @@ var _InstancedMeshComponent = class _InstancedMeshComponent extends Component {
1418
1418
  __name(_InstancedMeshComponent, "InstancedMeshComponent");
1419
1419
  var InstancedMeshComponent = _InstancedMeshComponent;
1420
1420
 
1421
+ // core/components/InstanceSlotComponent.ts
1422
+ var _InstanceSlotComponent = class _InstanceSlotComponent extends Component {
1423
+ constructor(groupEntityId, slotIndex) {
1424
+ super();
1425
+ this.groupEntityId = groupEntityId;
1426
+ this.slotIndex = slotIndex;
1427
+ }
1428
+ };
1429
+ __name(_InstanceSlotComponent, "InstanceSlotComponent");
1430
+ var InstanceSlotComponent = _InstanceSlotComponent;
1431
+
1421
1432
  // core/components/Physics.ts
1422
1433
  var DEFAULT_RIGIDBODY_STATE = {
1423
1434
  enabled: true,
@@ -1605,6 +1616,34 @@ var _PhysicsComponent = class _PhysicsComponent extends Component {
1605
1616
  };
1606
1617
  __name(_PhysicsComponent, "PhysicsComponent");
1607
1618
  var PhysicsComponent = _PhysicsComponent;
1619
+
1620
+ // core/components/Image.ts
1621
+ var _ImageComponent = class _ImageComponent extends Component {
1622
+ constructor(path, width = 1, height = 1) {
1623
+ super();
1624
+ this.path = path;
1625
+ this.width = width;
1626
+ this.height = height;
1627
+ this.texture = null;
1628
+ this.object = null;
1629
+ }
1630
+ };
1631
+ __name(_ImageComponent, "ImageComponent");
1632
+ var ImageComponent = _ImageComponent;
1633
+
1634
+ // core/components/ImageTarget.ts
1635
+ var _ImageTarget = class _ImageTarget extends Component {
1636
+ constructor(options, texture, object) {
1637
+ super();
1638
+ this.targets = options?.targets ?? [];
1639
+ this.compiledTargetUrl = options?.compiledTargetUrl;
1640
+ this.compiledTargetDir = options?.compiledTargetDir;
1641
+ this.texture = texture ?? null;
1642
+ this.object = object ?? null;
1643
+ }
1644
+ };
1645
+ __name(_ImageTarget, "ImageTarget");
1646
+ var ImageTarget = _ImageTarget;
1608
1647
  function toHexColor(value) {
1609
1648
  return `#${value.getHexString()}`;
1610
1649
  }
@@ -1733,8 +1772,23 @@ var _MaterialComponent = class _MaterialComponent extends Component {
1733
1772
  this.materials = [];
1734
1773
  this.material = null;
1735
1774
  this.values = [];
1775
+ this.assetRefs = [];
1736
1776
  this.setMaterials(materialOrMaterials);
1737
1777
  }
1778
+ /** Link/unlink a slot to a material asset URL (editor bookkeeping only). */
1779
+ setAssetRef(index, url) {
1780
+ if (index < 0) {
1781
+ return;
1782
+ }
1783
+ while (this.assetRefs.length <= index) {
1784
+ this.assetRefs.push(null);
1785
+ }
1786
+ this.assetRefs[index] = url;
1787
+ }
1788
+ /** The material-asset URL a slot is linked to, or null when local. */
1789
+ getAssetRef(index) {
1790
+ return this.assetRefs[index] ?? null;
1791
+ }
1738
1792
  setMaterials(materialOrMaterials = []) {
1739
1793
  this.materials = Array.isArray(materialOrMaterials) ? materialOrMaterials.filter(Boolean) : materialOrMaterials ? [materialOrMaterials] : [];
1740
1794
  this.material = this.materials[0] ?? null;
@@ -1789,6 +1843,45 @@ var _ModelComponent = class _ModelComponent extends Component {
1789
1843
  __name(_ModelComponent, "ModelComponent");
1790
1844
  var ModelComponent = _ModelComponent;
1791
1845
 
1846
+ // core/components/Name.ts
1847
+ var _Name = class _Name extends Component {
1848
+ constructor(value) {
1849
+ super();
1850
+ this.value = value;
1851
+ }
1852
+ };
1853
+ __name(_Name, "Name");
1854
+ var Name = _Name;
1855
+
1856
+ // core/components/PrefabInstance.ts
1857
+ var generateInstanceId = /* @__PURE__ */ __name(() => {
1858
+ try {
1859
+ return crypto.randomUUID();
1860
+ } catch {
1861
+ return `i-${Math.random().toString(36).slice(2, 10)}${Date.now().toString(36)}`;
1862
+ }
1863
+ }, "generateInstanceId");
1864
+ var _PrefabInstance = class _PrefabInstance extends Component {
1865
+ constructor(url, overrides = [], instanceId) {
1866
+ super();
1867
+ this.url = url;
1868
+ this.overrides = overrides;
1869
+ this.instanceId = typeof instanceId === "string" && instanceId.length > 0 ? instanceId : generateInstanceId();
1870
+ }
1871
+ };
1872
+ __name(_PrefabInstance, "PrefabInstance");
1873
+ var PrefabInstance = _PrefabInstance;
1874
+
1875
+ // core/components/PrefabNode.ts
1876
+ var _PrefabNode = class _PrefabNode extends Component {
1877
+ constructor(nodeId) {
1878
+ super();
1879
+ this.nodeId = nodeId;
1880
+ }
1881
+ };
1882
+ __name(_PrefabNode, "PrefabNode");
1883
+ var PrefabNode = _PrefabNode;
1884
+
1792
1885
  // core/components/ScriptComponent.ts
1793
1886
  var _ScriptComponent = class _ScriptComponent extends Component {
1794
1887
  constructor(entries = []) {
@@ -1820,6 +1913,30 @@ var _ScriptComponent = class _ScriptComponent extends Component {
1820
1913
  __name(_ScriptComponent, "ScriptComponent");
1821
1914
  var ScriptComponent = _ScriptComponent;
1822
1915
 
1916
+ // core/components/Selectable.ts
1917
+ var _Selectable = class _Selectable extends Component {
1918
+ constructor(enabled = true) {
1919
+ super();
1920
+ this.enabled = enabled;
1921
+ }
1922
+ };
1923
+ __name(_Selectable, "Selectable");
1924
+ var Selectable = _Selectable;
1925
+
1926
+ // core/components/Sprite.ts
1927
+ var _SpriteComponent = class _SpriteComponent extends Component {
1928
+ constructor(path, width = 1, height = 1) {
1929
+ super();
1930
+ this.path = path;
1931
+ this.width = width;
1932
+ this.height = height;
1933
+ this.texture = null;
1934
+ this.object = null;
1935
+ }
1936
+ };
1937
+ __name(_SpriteComponent, "SpriteComponent");
1938
+ var SpriteComponent = _SpriteComponent;
1939
+
1823
1940
  // core/components/Video.ts
1824
1941
  var DEFAULT_VIDEO_OPTIONS = {
1825
1942
  autoplay: false,
@@ -4518,6 +4635,1246 @@ var _RenderSystem = class _RenderSystem {
4518
4635
  };
4519
4636
  __name(_RenderSystem, "RenderSystem");
4520
4637
  var RenderSystem = _RenderSystem;
4638
+
4639
+ // core/prefab/collectEntitySubtree.ts
4640
+ function collectEntitySubtree(world, rootIds) {
4641
+ const childrenByParent = /* @__PURE__ */ new Map();
4642
+ for (const entityId of world.query(ParentId)) {
4643
+ const parentId = world.getComponent(entityId, ParentId)?.value;
4644
+ if (parentId === null || parentId === void 0) {
4645
+ continue;
4646
+ }
4647
+ const siblings = childrenByParent.get(parentId);
4648
+ if (siblings) {
4649
+ siblings.push(entityId);
4650
+ } else {
4651
+ childrenByParent.set(parentId, [entityId]);
4652
+ }
4653
+ }
4654
+ const ordered = [];
4655
+ const seen = /* @__PURE__ */ new Set();
4656
+ const queue = [...rootIds];
4657
+ while (queue.length > 0) {
4658
+ const entityId = queue.shift();
4659
+ if (seen.has(entityId)) {
4660
+ continue;
4661
+ }
4662
+ seen.add(entityId);
4663
+ ordered.push(entityId);
4664
+ const children = childrenByParent.get(entityId);
4665
+ if (children) {
4666
+ queue.push(...children.sort((a, b) => a - b));
4667
+ }
4668
+ }
4669
+ return ordered;
4670
+ }
4671
+ __name(collectEntitySubtree, "collectEntitySubtree");
4672
+
4673
+ // core/hydration/readers.ts
4674
+ function asRecord3(value) {
4675
+ if (!value || typeof value !== "object") {
4676
+ return null;
4677
+ }
4678
+ return value;
4679
+ }
4680
+ __name(asRecord3, "asRecord");
4681
+ function readString(value) {
4682
+ if (typeof value === "string") {
4683
+ return value;
4684
+ }
4685
+ const record = asRecord3(value);
4686
+ if (!record) {
4687
+ return null;
4688
+ }
4689
+ return typeof record.value === "string" ? record.value : null;
4690
+ }
4691
+ __name(readString, "readString");
4692
+ function readTransform(value) {
4693
+ const record = asRecord3(value);
4694
+ if (!record) {
4695
+ return void 0;
4696
+ }
4697
+ const position = asRecord3(record.position);
4698
+ const rotation = asRecord3(record.rotation);
4699
+ const scale = asRecord3(record.scale);
4700
+ return {
4701
+ position: position ? {
4702
+ x: typeof position.x === "number" ? position.x : void 0,
4703
+ y: typeof position.y === "number" ? position.y : void 0,
4704
+ z: typeof position.z === "number" ? position.z : void 0
4705
+ } : void 0,
4706
+ rotation: rotation ? {
4707
+ x: typeof rotation.x === "number" ? rotation.x : void 0,
4708
+ y: typeof rotation.y === "number" ? rotation.y : void 0,
4709
+ z: typeof rotation.z === "number" ? rotation.z : void 0
4710
+ } : void 0,
4711
+ scale: scale ? {
4712
+ x: typeof scale.x === "number" ? scale.x : void 0,
4713
+ y: typeof scale.y === "number" ? scale.y : void 0,
4714
+ z: typeof scale.z === "number" ? scale.z : void 0
4715
+ } : void 0
4716
+ };
4717
+ }
4718
+ __name(readTransform, "readTransform");
4719
+ function readByComponent(components, componentName) {
4720
+ const component = components.find((entry) => entry.component === componentName);
4721
+ const map = /* @__PURE__ */ new Map();
4722
+ if (!component) {
4723
+ return map;
4724
+ }
4725
+ for (const entry of component.entries) {
4726
+ map.set(entry.entityId, entry.value);
4727
+ }
4728
+ return map;
4729
+ }
4730
+ __name(readByComponent, "readByComponent");
4731
+ function readBoolean(value) {
4732
+ return typeof value === "boolean" ? value : void 0;
4733
+ }
4734
+ __name(readBoolean, "readBoolean");
4735
+ function readNumber(value) {
4736
+ return typeof value === "number" ? value : void 0;
4737
+ }
4738
+ __name(readNumber, "readNumber");
4739
+
4740
+ // core/hydration/componentValues.ts
4741
+ function buildComponentValueMaps(snapshot) {
4742
+ return {
4743
+ object3DRefValues: readByComponent(snapshot.components, "Object3DRef"),
4744
+ nameValues: readByComponent(snapshot.components, "Name"),
4745
+ transformValues: readByComponent(snapshot.components, "TransformComponent"),
4746
+ modelValues: readByComponent(snapshot.components, "ModelComponent"),
4747
+ imageValues: readByComponent(snapshot.components, "ImageComponent"),
4748
+ spriteValues: readByComponent(snapshot.components, "SpriteComponent"),
4749
+ videoValues: readByComponent(snapshot.components, "VideoComponent"),
4750
+ cameraValues: readByComponent(snapshot.components, "CameraComponent"),
4751
+ environmentValues: readByComponent(snapshot.components, "Environment"),
4752
+ postprocessingValues: readByComponent(snapshot.components, "Postprocessing"),
4753
+ audioValues: readByComponent(snapshot.components, "AudioComponent"),
4754
+ imageTargetValues: readByComponent(snapshot.components, "ImageTarget"),
4755
+ lightValues: readByComponent(snapshot.components, "LightComponent"),
4756
+ materialValues: readByComponent(snapshot.components, "MaterialComponent"),
4757
+ meshGeometryValues: readByComponent(snapshot.components, "MeshGeometryComponent"),
4758
+ selectableValues: readByComponent(snapshot.components, "Selectable"),
4759
+ physicsValues: readByComponent(snapshot.components, "PhysicsComponent"),
4760
+ animationValues: readByComponent(snapshot.components, "AnimationComponent"),
4761
+ imageTargetAnchorValues: readByComponent(snapshot.components, "ImageTargetAnchor"),
4762
+ scriptValues: readByComponent(snapshot.components, "ScriptComponent"),
4763
+ instancedMeshValues: readByComponent(snapshot.components, "InstancedMeshComponent"),
4764
+ instanceSlotValues: readByComponent(snapshot.components, "InstanceSlotComponent"),
4765
+ prefabNodeValues: readByComponent(snapshot.components, "PrefabNode"),
4766
+ prefabInstanceValues: readByComponent(snapshot.components, "PrefabInstance")
4767
+ };
4768
+ }
4769
+ __name(buildComponentValueMaps, "buildComponentValueMaps");
4770
+
4771
+ // core/hydration/parentLinks.ts
4772
+ function applyParentLinks(snapshot, idMap, objectManagementSystem, world) {
4773
+ const parentValues = readByComponent(snapshot.components, "ParentId");
4774
+ for (const [sourceEntityId, parentValue] of parentValues.entries()) {
4775
+ const targetEntityId = idMap.get(sourceEntityId);
4776
+ if (targetEntityId === void 0) {
4777
+ continue;
4778
+ }
4779
+ const parentRecord = asRecord3(parentValue);
4780
+ const sourceParentId = parentRecord && typeof parentRecord.value === "number" ? parentRecord.value : null;
4781
+ if (sourceParentId === null) {
4782
+ objectManagementSystem.setParent(world, targetEntityId, null, {
4783
+ preserveWorldTransform: false
4784
+ });
4785
+ continue;
4786
+ }
4787
+ const mappedParentId = idMap.get(sourceParentId);
4788
+ objectManagementSystem.setParent(world, targetEntityId, mappedParentId ?? null, {
4789
+ preserveWorldTransform: false
4790
+ });
4791
+ }
4792
+ }
4793
+ __name(applyParentLinks, "applyParentLinks");
4794
+
4795
+ // core/hydration/postCreateComponents.ts
4796
+ function remapEntityRefsInScriptData(data, idMap) {
4797
+ const result = {};
4798
+ for (const [key, value] of Object.entries(data)) {
4799
+ if (value !== null && typeof value === "object" && !Array.isArray(value)) {
4800
+ const v = value;
4801
+ if (v.type === "entity" && typeof v.value === "number") {
4802
+ result[key] = { ...v, value: idMap.get(v.value) ?? v.value };
4803
+ } else if (v.type === "component" && v.value !== null && typeof v.value === "object" && !Array.isArray(v.value) && typeof v.value.entityId === "number") {
4804
+ const ref = v.value;
4805
+ result[key] = {
4806
+ ...v,
4807
+ value: { ...ref, entityId: idMap.get(ref.entityId) ?? ref.entityId }
4808
+ };
4809
+ } else {
4810
+ result[key] = value;
4811
+ }
4812
+ } else {
4813
+ result[key] = value;
4814
+ }
4815
+ }
4816
+ return result;
4817
+ }
4818
+ __name(remapEntityRefsInScriptData, "remapEntityRefsInScriptData");
4819
+ function restorePostCreateComponents(world, objectManagementSystem, targetEntityId, sourceEntityId, entityType, values, idMap) {
4820
+ const objectRef = world.getComponent(targetEntityId, Object3DRef)?.object ?? null;
4821
+ const sourceAudio = asRecord3(values.audioValues.get(sourceEntityId));
4822
+ if (sourceAudio && entityType !== "audio") {
4823
+ const sourceOptions = asRecord3(sourceAudio.options) ?? {};
4824
+ objectManagementSystem.createComponentNow(
4825
+ "audio",
4826
+ world,
4827
+ targetEntityId,
4828
+ typeof sourceAudio.path === "string" ? sourceAudio.path : "",
4829
+ sourceOptions,
4830
+ {
4831
+ object: objectRef,
4832
+ listener: objectManagementSystem.getOrCreateAudioListener(),
4833
+ isEditor: objectManagementSystem.isEditorMode()
4834
+ }
4835
+ );
4836
+ }
4837
+ const sourceImageTarget = asRecord3(values.imageTargetValues.get(sourceEntityId));
4838
+ if (sourceImageTarget && entityType !== "imageTarget") {
4839
+ objectManagementSystem.createComponentNow(
4840
+ "imageTarget",
4841
+ world,
4842
+ targetEntityId,
4843
+ {
4844
+ targets: Array.isArray(sourceImageTarget.targets) ? sourceImageTarget.targets : [],
4845
+ compiledTargetUrl: typeof sourceImageTarget.compiledTargetUrl === "string" ? sourceImageTarget.compiledTargetUrl : void 0,
4846
+ compiledTargetDir: typeof sourceImageTarget.compiledTargetDir === "string" ? sourceImageTarget.compiledTargetDir : void 0
4847
+ }
4848
+ );
4849
+ }
4850
+ const sourceImageTargetAnchor = asRecord3(values.imageTargetAnchorValues.get(sourceEntityId));
4851
+ if (sourceImageTargetAnchor) {
4852
+ const mappedTargetId = typeof sourceImageTargetAnchor.targetId === "number" && Number.isFinite(sourceImageTargetAnchor.targetId) ? sourceImageTargetAnchor.targetId : null;
4853
+ objectManagementSystem.createComponentNow("imageTargetAnchor", world, targetEntityId, {
4854
+ targetId: mappedTargetId,
4855
+ targetUrl: typeof sourceImageTargetAnchor.targetUrl === "string" ? sourceImageTargetAnchor.targetUrl : void 0
4856
+ });
4857
+ }
4858
+ const sourceScript = asRecord3(values.scriptValues.get(sourceEntityId));
4859
+ if (sourceScript) {
4860
+ const entries = Array.isArray(sourceScript.entries) ? sourceScript.entries.map((entry) => asRecord3(entry)).filter((entry) => Boolean(entry)).map((entry) => {
4861
+ const runtimeState = entry.runtimeState === "idle" || entry.runtimeState === "loading" || entry.runtimeState === "ready" || entry.runtimeState === "error" ? entry.runtimeState : void 0;
4862
+ return {
4863
+ entityId: targetEntityId,
4864
+ className: typeof entry.className === "string" ? entry.className : "",
4865
+ scriptUrl: typeof entry.scriptUrl === "string" ? entry.scriptUrl : "",
4866
+ enabled: typeof entry.enabled === "boolean" ? entry.enabled : true,
4867
+ data: entry.data && typeof entry.data === "object" && !Array.isArray(entry.data) ? remapEntityRefsInScriptData(entry.data, idMap) : {},
4868
+ runtimeState,
4869
+ runtimeMessage: typeof entry.runtimeMessage === "string" ? entry.runtimeMessage : void 0
4870
+ };
4871
+ }).filter((entry) => entry.className || entry.scriptUrl) : [];
4872
+ if (!entries.length) {
4873
+ return;
4874
+ }
4875
+ world.addComponent(
4876
+ targetEntityId,
4877
+ new ScriptComponent(entries)
4878
+ );
4879
+ }
4880
+ {
4881
+ const imComponent = world.getComponent(targetEntityId, InstancedMeshComponent);
4882
+ if (imComponent && imComponent.instanceEntityIds.length > 0) {
4883
+ imComponent.instanceEntityIds = imComponent.instanceEntityIds.map(
4884
+ (oldId) => idMap.get(oldId) ?? oldId
4885
+ );
4886
+ }
4887
+ }
4888
+ {
4889
+ const slotComponent = world.getComponent(targetEntityId, InstanceSlotComponent);
4890
+ if (slotComponent && slotComponent.groupEntityId !== -1) {
4891
+ slotComponent.groupEntityId = idMap.get(slotComponent.groupEntityId) ?? slotComponent.groupEntityId;
4892
+ }
4893
+ }
4894
+ }
4895
+ __name(restorePostCreateComponents, "restorePostCreateComponents");
4896
+
4897
+ // core/hydration/animation.ts
4898
+ function readAnimationClipName(value) {
4899
+ if (typeof value === "string") {
4900
+ return value;
4901
+ }
4902
+ const record = asRecord3(value);
4903
+ if (!record) {
4904
+ return null;
4905
+ }
4906
+ if (typeof record.name === "string") {
4907
+ return record.name;
4908
+ }
4909
+ return null;
4910
+ }
4911
+ __name(readAnimationClipName, "readAnimationClipName");
4912
+ function readAnimationStates(value) {
4913
+ if (!Array.isArray(value)) {
4914
+ return [];
4915
+ }
4916
+ const states = [];
4917
+ for (const entry of value) {
4918
+ const state = asRecord3(entry);
4919
+ if (!state) {
4920
+ continue;
4921
+ }
4922
+ const name = typeof state.name === "string" ? state.name : null;
4923
+ const clip = readAnimationClipName(state.clip);
4924
+ if (!name || !clip) {
4925
+ continue;
4926
+ }
4927
+ states.push({
4928
+ name,
4929
+ clip,
4930
+ clipId: typeof state.clipId === "string" ? state.clipId : void 0,
4931
+ loop: typeof state.loop === "boolean" ? state.loop : false
4932
+ });
4933
+ }
4934
+ return states;
4935
+ }
4936
+ __name(readAnimationStates, "readAnimationStates");
4937
+ function readAnimationClipSources(value) {
4938
+ if (!Array.isArray(value)) {
4939
+ return [];
4940
+ }
4941
+ const seen = /* @__PURE__ */ new Set();
4942
+ const sources = [];
4943
+ for (const entry of value) {
4944
+ if (typeof entry !== "string") {
4945
+ continue;
4946
+ }
4947
+ const trimmed = entry.trim();
4948
+ if (!trimmed || seen.has(trimmed)) {
4949
+ continue;
4950
+ }
4951
+ seen.add(trimmed);
4952
+ sources.push(trimmed);
4953
+ }
4954
+ return sources;
4955
+ }
4956
+ __name(readAnimationClipSources, "readAnimationClipSources");
4957
+ function toAnimationOptions(sourceAnimation) {
4958
+ const paused = readBoolean(sourceAnimation.paused);
4959
+ const reverse = readBoolean(sourceAnimation.reverse);
4960
+ const timeScale = readNumber(sourceAnimation.timeScale);
4961
+ const crossFadeDuration = readNumber(sourceAnimation.crossFadeDuration);
4962
+ const states = readAnimationStates(sourceAnimation.states);
4963
+ const externalClipSources = readAnimationClipSources(
4964
+ sourceAnimation.externalClipSources
4965
+ );
4966
+ const activeStateName = typeof sourceAnimation.activeStateName === "string" ? sourceAnimation.activeStateName : typeof sourceAnimation.activeState === "string" ? sourceAnimation.activeState : typeof sourceAnimation.active?.name === "string" ? sourceAnimation.active.name ?? null : null;
4967
+ return {
4968
+ paused,
4969
+ reverse,
4970
+ timeScale,
4971
+ crossFadeDuration,
4972
+ states,
4973
+ externalClipSources,
4974
+ activeState: activeStateName
4975
+ };
4976
+ }
4977
+ __name(toAnimationOptions, "toAnimationOptions");
4978
+ function restoreAnimationComponent(world, objectManagementSystem, targetEntityId, sourceAnimation) {
4979
+ const options = toAnimationOptions(sourceAnimation);
4980
+ let animation = world.getComponent(targetEntityId, AnimationComponent);
4981
+ if (!animation) {
4982
+ objectManagementSystem.createComponentNow(
4983
+ "animation",
4984
+ world,
4985
+ targetEntityId,
4986
+ options
4987
+ );
4988
+ animation = world.getComponent(targetEntityId, AnimationComponent);
4989
+ }
4990
+ if (!animation) {
4991
+ return;
4992
+ }
4993
+ const availableClips = Array.isArray(sourceAnimation.availableClips) ? sourceAnimation.availableClips.filter(
4994
+ (clip) => typeof clip === "string" && clip.length > 0
4995
+ ) : [];
4996
+ if (availableClips.length > 0) {
4997
+ animation.availableClips = [...availableClips];
4998
+ }
4999
+ if (Array.isArray(options.externalClipSources)) {
5000
+ animation.setExternalClipSources(options.externalClipSources);
5001
+ }
5002
+ const states = options.states ?? [];
5003
+ const hasClips = Array.isArray(animation.clips) && animation.clips.length > 0;
5004
+ if (!hasClips) {
5005
+ animation.__pendingHydratedOptions = options;
5006
+ if (typeof options.reverse === "boolean") {
5007
+ animation.reverse = options.reverse;
5008
+ }
5009
+ if (typeof options.timeScale === "number") {
5010
+ animation.timeScale = options.timeScale;
5011
+ }
5012
+ if (typeof options.crossFadeDuration === "number") {
5013
+ animation.crossFadeDuration = options.crossFadeDuration;
5014
+ }
5015
+ if (typeof options.paused === "boolean") {
5016
+ animation.paused = options.paused;
5017
+ }
5018
+ return;
5019
+ }
5020
+ if (states.length > 0) {
5021
+ animation.setStates(states);
5022
+ }
5023
+ if (typeof options.reverse === "boolean") {
5024
+ animation.reverse = options.reverse;
5025
+ }
5026
+ if (typeof options.timeScale === "number") {
5027
+ animation.timeScale = options.timeScale;
5028
+ }
5029
+ if (typeof options.crossFadeDuration === "number") {
5030
+ animation.crossFadeDuration = options.crossFadeDuration;
5031
+ }
5032
+ if (typeof options.activeState === "string" && options.activeState.length > 0) {
5033
+ animation.setActiveState(options.activeState, !options.paused);
5034
+ }
5035
+ if (typeof options.paused === "boolean") {
5036
+ if (options.paused) {
5037
+ animation.pauseState();
5038
+ } else if (typeof options.activeState === "string" && options.activeState.length > 0) {
5039
+ animation.playState(options.activeState);
5040
+ }
5041
+ }
5042
+ }
5043
+ __name(restoreAnimationComponent, "restoreAnimationComponent");
5044
+
5045
+ // core/hydration/restoreComponentState.ts
5046
+ function readEnvironmentState(value) {
5047
+ const record = asRecord3(value);
5048
+ if (!record) {
5049
+ return null;
5050
+ }
5051
+ const nestedValues = asRecord3(record.values);
5052
+ if (nestedValues) {
5053
+ return nestedValues;
5054
+ }
5055
+ return record;
5056
+ }
5057
+ __name(readEnvironmentState, "readEnvironmentState");
5058
+ function readPostprocessingState(value) {
5059
+ const record = asRecord3(value);
5060
+ if (!record) {
5061
+ return null;
5062
+ }
5063
+ const nestedValues = asRecord3(record.values);
5064
+ if (nestedValues) {
5065
+ return nestedValues;
5066
+ }
5067
+ return record;
5068
+ }
5069
+ __name(readPostprocessingState, "readPostprocessingState");
5070
+ function restoreComponentState(world, objectManagementSystem, targetEntityId, sourceEntityId, entityType, values) {
5071
+ const sourceName = readString(values.nameValues.get(sourceEntityId));
5072
+ if (sourceName !== null) {
5073
+ const nameComponent = world.getComponent(targetEntityId, Name);
5074
+ if (nameComponent) {
5075
+ nameComponent.value = sourceName;
5076
+ }
5077
+ }
5078
+ const sourceObject3DRef = asRecord3(values.object3DRefValues.get(sourceEntityId));
5079
+ if (sourceObject3DRef) {
5080
+ const object3DRefComponent = world.getComponent(targetEntityId, Object3DRef);
5081
+ const visibility = readBoolean(sourceObject3DRef.visibility);
5082
+ if (object3DRefComponent && typeof visibility === "boolean") {
5083
+ object3DRefComponent.visibility = visibility;
5084
+ }
5085
+ }
5086
+ const sourceTransform = readTransform(values.transformValues.get(sourceEntityId));
5087
+ if (sourceTransform) {
5088
+ const transformComponent = world.getComponent(targetEntityId, TransformComponent);
5089
+ if (transformComponent) {
5090
+ if (typeof sourceTransform.position?.x === "number") {
5091
+ transformComponent.position.x = sourceTransform.position.x;
5092
+ }
5093
+ if (typeof sourceTransform.position?.y === "number") {
5094
+ transformComponent.position.y = sourceTransform.position.y;
5095
+ }
5096
+ if (typeof sourceTransform.position?.z === "number") {
5097
+ transformComponent.position.z = sourceTransform.position.z;
5098
+ }
5099
+ if (typeof sourceTransform.rotation?.x === "number") {
5100
+ transformComponent.rotation.x = sourceTransform.rotation.x;
5101
+ }
5102
+ if (typeof sourceTransform.rotation?.y === "number") {
5103
+ transformComponent.rotation.y = sourceTransform.rotation.y;
5104
+ }
5105
+ if (typeof sourceTransform.rotation?.z === "number") {
5106
+ transformComponent.rotation.z = sourceTransform.rotation.z;
5107
+ }
5108
+ if (typeof sourceTransform.scale?.x === "number") {
5109
+ transformComponent.scale.x = sourceTransform.scale.x;
5110
+ }
5111
+ if (typeof sourceTransform.scale?.y === "number") {
5112
+ transformComponent.scale.y = sourceTransform.scale.y;
5113
+ }
5114
+ if (typeof sourceTransform.scale?.z === "number") {
5115
+ transformComponent.scale.z = sourceTransform.scale.z;
5116
+ }
5117
+ }
5118
+ }
5119
+ const sourceModel = asRecord3(values.modelValues.get(sourceEntityId));
5120
+ if (sourceModel) {
5121
+ const modelComponent = world.getComponent(targetEntityId, ModelComponent);
5122
+ if (modelComponent && typeof sourceModel.path === "string") {
5123
+ modelComponent.path = sourceModel.path;
5124
+ }
5125
+ }
5126
+ const sourceImage = asRecord3(values.imageValues.get(sourceEntityId));
5127
+ if (sourceImage) {
5128
+ const imageComponent = world.getComponent(targetEntityId, ImageComponent);
5129
+ if (imageComponent) {
5130
+ if (typeof sourceImage.path === "string") {
5131
+ imageComponent.path = sourceImage.path;
5132
+ }
5133
+ const width = readNumber(sourceImage.width);
5134
+ if (typeof width === "number") {
5135
+ imageComponent.width = width;
5136
+ }
5137
+ const height = readNumber(sourceImage.height);
5138
+ if (typeof height === "number") {
5139
+ imageComponent.height = height;
5140
+ }
5141
+ }
5142
+ }
5143
+ const sourceSprite = asRecord3(values.spriteValues.get(sourceEntityId));
5144
+ if (sourceSprite) {
5145
+ const spriteComponent = world.getComponent(targetEntityId, SpriteComponent);
5146
+ if (spriteComponent) {
5147
+ if (typeof sourceSprite.path === "string") {
5148
+ spriteComponent.path = sourceSprite.path;
5149
+ }
5150
+ const width = readNumber(sourceSprite.width);
5151
+ if (typeof width === "number") {
5152
+ spriteComponent.width = width;
5153
+ }
5154
+ const height = readNumber(sourceSprite.height);
5155
+ if (typeof height === "number") {
5156
+ spriteComponent.height = height;
5157
+ }
5158
+ }
5159
+ }
5160
+ const sourceVideo = asRecord3(values.videoValues.get(sourceEntityId));
5161
+ if (sourceVideo) {
5162
+ const videoComponent = world.getComponent(targetEntityId, VideoComponent);
5163
+ if (videoComponent) {
5164
+ if (typeof sourceVideo.path === "string") {
5165
+ videoComponent.path = sourceVideo.path;
5166
+ }
5167
+ const videoOptions = asRecord3(sourceVideo.options);
5168
+ if (videoOptions) {
5169
+ videoComponent.options = {
5170
+ ...videoComponent.options,
5171
+ ...videoOptions
5172
+ };
5173
+ }
5174
+ }
5175
+ }
5176
+ const sourceAudio = asRecord3(values.audioValues.get(sourceEntityId));
5177
+ if (sourceAudio && entityType === "audio") {
5178
+ const audioComponent = world.getComponent(targetEntityId, AudioComponent);
5179
+ if (audioComponent) {
5180
+ if (typeof sourceAudio.path === "string") {
5181
+ audioComponent.path = sourceAudio.path;
5182
+ }
5183
+ const audioOptions = asRecord3(sourceAudio.options);
5184
+ if (audioOptions) {
5185
+ audioComponent.options = {
5186
+ ...audioComponent.options,
5187
+ ...audioOptions
5188
+ };
5189
+ }
5190
+ }
5191
+ }
5192
+ const sourceCamera = asRecord3(values.cameraValues.get(sourceEntityId));
5193
+ if (sourceCamera) {
5194
+ const cameraComponent = world.getComponent(targetEntityId, CameraComponent);
5195
+ if (cameraComponent) {
5196
+ if (sourceCamera.projection === "orthographic" || sourceCamera.projection === "perspective") {
5197
+ cameraComponent.projection = sourceCamera.projection;
5198
+ }
5199
+ if (sourceCamera.type === "3d" || sourceCamera.type === "ar") {
5200
+ cameraComponent.type = sourceCamera.type;
5201
+ }
5202
+ if (typeof sourceCamera.isDefault === "boolean") {
5203
+ cameraComponent.isDefault = sourceCamera.isDefault;
5204
+ }
5205
+ const fov = readNumber(sourceCamera.fov);
5206
+ if (typeof fov === "number") {
5207
+ cameraComponent.fov = fov;
5208
+ }
5209
+ const near = readNumber(sourceCamera.near);
5210
+ if (typeof near === "number") {
5211
+ cameraComponent.near = near;
5212
+ }
5213
+ const far = readNumber(sourceCamera.far);
5214
+ if (typeof far === "number") {
5215
+ cameraComponent.far = far;
5216
+ }
5217
+ const left = readNumber(sourceCamera.left);
5218
+ if (typeof left === "number") {
5219
+ cameraComponent.left = left;
5220
+ }
5221
+ const right = readNumber(sourceCamera.right);
5222
+ if (typeof right === "number") {
5223
+ cameraComponent.right = right;
5224
+ }
5225
+ const top = readNumber(sourceCamera.top);
5226
+ if (typeof top === "number") {
5227
+ cameraComponent.top = top;
5228
+ }
5229
+ const bottom = readNumber(sourceCamera.bottom);
5230
+ if (typeof bottom === "number") {
5231
+ cameraComponent.bottom = bottom;
5232
+ }
5233
+ const zoom = readNumber(sourceCamera.zoom);
5234
+ if (typeof zoom === "number") {
5235
+ cameraComponent.zoom = zoom;
5236
+ }
5237
+ }
5238
+ }
5239
+ const sourceEnvironment = readEnvironmentState(
5240
+ values.environmentValues.get(sourceEntityId)
5241
+ );
5242
+ if (sourceEnvironment) {
5243
+ let environmentComponent = world.getComponent(targetEntityId, Environment);
5244
+ if (!environmentComponent) {
5245
+ objectManagementSystem.createComponentNow(
5246
+ "environment",
5247
+ world,
5248
+ targetEntityId,
5249
+ sourceEnvironment
5250
+ );
5251
+ environmentComponent = world.getComponent(targetEntityId, Environment);
5252
+ }
5253
+ if (environmentComponent) {
5254
+ environmentComponent.values = new Environment({
5255
+ ...environmentComponent.values,
5256
+ ...sourceEnvironment
5257
+ }).values;
5258
+ }
5259
+ }
5260
+ const sourcePostprocessing = readPostprocessingState(
5261
+ values.postprocessingValues.get(sourceEntityId)
5262
+ );
5263
+ if (sourcePostprocessing) {
5264
+ let postprocessingComponent = world.getComponent(targetEntityId, Postprocessing);
5265
+ if (!postprocessingComponent) {
5266
+ objectManagementSystem.createComponentNow(
5267
+ "postprocessing",
5268
+ world,
5269
+ targetEntityId,
5270
+ sourcePostprocessing
5271
+ );
5272
+ postprocessingComponent = world.getComponent(targetEntityId, Postprocessing);
5273
+ }
5274
+ if (postprocessingComponent) {
5275
+ postprocessingComponent.values = new Postprocessing({
5276
+ ...postprocessingComponent.values,
5277
+ ...sourcePostprocessing
5278
+ }).values;
5279
+ }
5280
+ }
5281
+ const sourceImageTarget = asRecord3(values.imageTargetValues.get(sourceEntityId));
5282
+ if (sourceImageTarget && entityType === "imageTarget") {
5283
+ const imageTargetComponent = world.getComponent(targetEntityId, ImageTarget);
5284
+ if (imageTargetComponent) {
5285
+ imageTargetComponent.targets = Array.isArray(sourceImageTarget.targets) ? sourceImageTarget.targets : [];
5286
+ imageTargetComponent.compiledTargetUrl = typeof sourceImageTarget.compiledTargetUrl === "string" ? sourceImageTarget.compiledTargetUrl : void 0;
5287
+ imageTargetComponent.compiledTargetDir = typeof sourceImageTarget.compiledTargetDir === "string" ? sourceImageTarget.compiledTargetDir : void 0;
5288
+ }
5289
+ }
5290
+ const sourceLight = asRecord3(values.lightValues.get(sourceEntityId));
5291
+ if (sourceLight) {
5292
+ const lightComponent = world.getComponent(targetEntityId, LightComponent);
5293
+ const sourceValues = asRecord3(sourceLight.values);
5294
+ if (lightComponent && sourceValues) {
5295
+ lightComponent.values = {
5296
+ ...lightComponent.values,
5297
+ ...sourceValues
5298
+ };
5299
+ }
5300
+ }
5301
+ const sourceMaterial = asRecord3(values.materialValues.get(sourceEntityId));
5302
+ if (sourceMaterial) {
5303
+ const materialComponent = world.getComponent(targetEntityId, MaterialComponent);
5304
+ const sourceValues = sourceMaterial.values;
5305
+ if (materialComponent && Array.isArray(sourceValues)) {
5306
+ materialComponent.values = sourceValues;
5307
+ }
5308
+ const sourceAssetRefs = sourceMaterial.assetRefs;
5309
+ if (materialComponent && Array.isArray(sourceAssetRefs)) {
5310
+ materialComponent.assetRefs = sourceAssetRefs;
5311
+ }
5312
+ }
5313
+ const sourceMeshGeometry = asRecord3(values.meshGeometryValues.get(sourceEntityId));
5314
+ if (sourceMeshGeometry) {
5315
+ const meshGeometryComponent = world.getComponent(
5316
+ targetEntityId,
5317
+ MeshGeometryComponent
5318
+ );
5319
+ if (meshGeometryComponent) {
5320
+ const parameters = asRecord3(sourceMeshGeometry.parameters);
5321
+ if (parameters) {
5322
+ meshGeometryComponent.parameters = parameters;
5323
+ }
5324
+ if (typeof sourceMeshGeometry.modelName === "string") {
5325
+ meshGeometryComponent.modelName = sourceMeshGeometry.modelName;
5326
+ }
5327
+ if (typeof sourceMeshGeometry.castShadow === "boolean") {
5328
+ meshGeometryComponent.castShadow = sourceMeshGeometry.castShadow;
5329
+ }
5330
+ if (typeof sourceMeshGeometry.receiveShadow === "boolean") {
5331
+ meshGeometryComponent.receiveShadow = sourceMeshGeometry.receiveShadow;
5332
+ }
5333
+ }
5334
+ }
5335
+ const sourceSelectable = asRecord3(values.selectableValues.get(sourceEntityId));
5336
+ if (sourceSelectable) {
5337
+ const enabled = readBoolean(sourceSelectable.enabled);
5338
+ let selectable = world.getComponent(targetEntityId, Selectable);
5339
+ if (!selectable) {
5340
+ objectManagementSystem.createComponentNow(
5341
+ "selectable",
5342
+ world,
5343
+ targetEntityId,
5344
+ enabled ?? true
5345
+ );
5346
+ selectable = world.getComponent(targetEntityId, Selectable);
5347
+ }
5348
+ if (selectable && typeof enabled === "boolean") {
5349
+ selectable.enabled = enabled;
5350
+ }
5351
+ }
5352
+ const sourcePhysics = asRecord3(values.physicsValues.get(sourceEntityId));
5353
+ if (sourcePhysics) {
5354
+ const physicsValues = asRecord3(sourcePhysics.values) ?? sourcePhysics;
5355
+ let physics = world.getComponent(targetEntityId, PhysicsComponent);
5356
+ if (!physics) {
5357
+ objectManagementSystem.createComponentNow(
5358
+ "physics",
5359
+ world,
5360
+ targetEntityId,
5361
+ physicsValues
5362
+ );
5363
+ physics = world.getComponent(targetEntityId, PhysicsComponent);
5364
+ }
5365
+ if (physics) {
5366
+ physics.setValues({
5367
+ rigidbody: asRecord3(physicsValues.rigidbody) ?? {},
5368
+ collider: asRecord3(physicsValues.collider) ?? {}
5369
+ });
5370
+ }
5371
+ }
5372
+ const sourceAnimation = asRecord3(values.animationValues.get(sourceEntityId));
5373
+ if (sourceAnimation) {
5374
+ restoreAnimationComponent(
5375
+ world,
5376
+ objectManagementSystem,
5377
+ targetEntityId,
5378
+ sourceAnimation
5379
+ );
5380
+ }
5381
+ const sourceInstancedMesh = asRecord3(values.instancedMeshValues.get(sourceEntityId));
5382
+ if (sourceInstancedMesh) {
5383
+ const imComponent = world.getComponent(targetEntityId, InstancedMeshComponent);
5384
+ if (imComponent) {
5385
+ if (typeof sourceInstancedMesh.meshKind === "string") {
5386
+ imComponent.meshKind = sourceInstancedMesh.meshKind;
5387
+ }
5388
+ if (typeof sourceInstancedMesh.modelPath === "string") {
5389
+ imComponent.modelPath = sourceInstancedMesh.modelPath;
5390
+ }
5391
+ const parameters = asRecord3(sourceInstancedMesh.meshParameters);
5392
+ if (parameters) {
5393
+ imComponent.meshParameters = parameters;
5394
+ }
5395
+ if (typeof sourceInstancedMesh.castShadow === "boolean") {
5396
+ imComponent.castShadow = sourceInstancedMesh.castShadow;
5397
+ }
5398
+ if (typeof sourceInstancedMesh.receiveShadow === "boolean") {
5399
+ imComponent.receiveShadow = sourceInstancedMesh.receiveShadow;
5400
+ }
5401
+ if (Array.isArray(sourceInstancedMesh.instanceEntityIds)) {
5402
+ imComponent.instanceEntityIds = sourceInstancedMesh.instanceEntityIds;
5403
+ }
5404
+ imComponent.instancedMesh = null;
5405
+ }
5406
+ }
5407
+ const sourceInstanceSlot = asRecord3(values.instanceSlotValues.get(sourceEntityId));
5408
+ if (sourceInstanceSlot) {
5409
+ const slotComponent = world.getComponent(targetEntityId, InstanceSlotComponent);
5410
+ if (slotComponent) {
5411
+ if (typeof sourceInstanceSlot.slotIndex === "number") {
5412
+ slotComponent.slotIndex = sourceInstanceSlot.slotIndex;
5413
+ }
5414
+ }
5415
+ }
5416
+ const sourcePrefabNode = asRecord3(values.prefabNodeValues.get(sourceEntityId));
5417
+ if (sourcePrefabNode && typeof sourcePrefabNode.nodeId === "string") {
5418
+ if (!world.getComponent(targetEntityId, PrefabNode)) {
5419
+ world.addComponent(targetEntityId, new PrefabNode(sourcePrefabNode.nodeId));
5420
+ }
5421
+ }
5422
+ const sourcePrefabInstance = asRecord3(
5423
+ values.prefabInstanceValues.get(sourceEntityId)
5424
+ );
5425
+ if (sourcePrefabInstance && typeof sourcePrefabInstance.url === "string") {
5426
+ if (!world.getComponent(targetEntityId, PrefabInstance)) {
5427
+ const overrides = Array.isArray(sourcePrefabInstance.overrides) ? sourcePrefabInstance.overrides.filter(
5428
+ (entry) => typeof entry === "string"
5429
+ ) : [];
5430
+ world.addComponent(
5431
+ targetEntityId,
5432
+ new PrefabInstance(
5433
+ sourcePrefabInstance.url,
5434
+ overrides,
5435
+ // Preserve the placement identity; the constructor generates a
5436
+ // fresh one for legacy snapshots that predate instanceId.
5437
+ typeof sourcePrefabInstance.instanceId === "string" && sourcePrefabInstance.instanceId.length > 0 ? sourcePrefabInstance.instanceId : void 0
5438
+ )
5439
+ );
5440
+ }
5441
+ }
5442
+ }
5443
+ __name(restoreComponentState, "restoreComponentState");
5444
+
5445
+ // core/hydration/types.ts
5446
+ var HYDRATABLE_ENTITY_KINDS = /* @__PURE__ */ new Set([
5447
+ "cube",
5448
+ "sphere",
5449
+ "plane",
5450
+ "capsule",
5451
+ "cylinder",
5452
+ "empty",
5453
+ "model",
5454
+ "image",
5455
+ "imageTarget",
5456
+ "sprite",
5457
+ "audio",
5458
+ "camera",
5459
+ "video",
5460
+ "ambientLight",
5461
+ "directionalLight",
5462
+ "pointLight",
5463
+ "spotLight",
5464
+ "areaLight",
5465
+ "instancedMesh",
5466
+ "instanceSlot"
5467
+ ]);
5468
+
5469
+ // core/hydration/hydrateWorld.ts
5470
+ function buildEntityCreationPayload(sourceEntityId, kind, componentValues) {
5471
+ const payload = {
5472
+ name: readString(componentValues.nameValues.get(sourceEntityId)) ?? void 0,
5473
+ transform: readTransform(componentValues.transformValues.get(sourceEntityId))
5474
+ };
5475
+ if (kind === "model") {
5476
+ const model = asRecord3(componentValues.modelValues.get(sourceEntityId));
5477
+ if (typeof model?.path === "string") {
5478
+ payload.path = model.path;
5479
+ }
5480
+ }
5481
+ if (kind === "image") {
5482
+ const image = asRecord3(componentValues.imageValues.get(sourceEntityId));
5483
+ if (typeof image?.path === "string") {
5484
+ payload.path = image.path;
5485
+ }
5486
+ }
5487
+ if (kind === "sprite") {
5488
+ const sprite = asRecord3(componentValues.spriteValues.get(sourceEntityId));
5489
+ if (typeof sprite?.path === "string") {
5490
+ payload.path = sprite.path;
5491
+ }
5492
+ }
5493
+ if (kind === "video") {
5494
+ const video = asRecord3(componentValues.videoValues.get(sourceEntityId));
5495
+ if (typeof video?.path === "string") {
5496
+ payload.path = video.path;
5497
+ }
5498
+ const videoOptions = asRecord3(video?.options);
5499
+ if (videoOptions) {
5500
+ payload.options = videoOptions;
5501
+ }
5502
+ }
5503
+ if (kind === "audio") {
5504
+ const audio = asRecord3(componentValues.audioValues.get(sourceEntityId));
5505
+ if (typeof audio?.path === "string") {
5506
+ payload.path = audio.path;
5507
+ }
5508
+ const audioOptions = asRecord3(audio?.options);
5509
+ if (audioOptions) {
5510
+ payload.options = audioOptions;
5511
+ }
5512
+ }
5513
+ if (kind === "camera") {
5514
+ const camera = asRecord3(componentValues.cameraValues.get(sourceEntityId));
5515
+ if (camera) {
5516
+ const projection = camera.projection === "orthographic" || camera.projection === "perspective" ? camera.projection : void 0;
5517
+ const type = camera.type === "3d" || camera.type === "ar" ? camera.type : void 0;
5518
+ payload.options = {
5519
+ isDefault: typeof camera.isDefault === "boolean" ? camera.isDefault : void 0,
5520
+ projection,
5521
+ type,
5522
+ fov: typeof camera.fov === "number" ? camera.fov : void 0,
5523
+ near: typeof camera.near === "number" ? camera.near : void 0,
5524
+ far: typeof camera.far === "number" ? camera.far : void 0,
5525
+ left: typeof camera.left === "number" ? camera.left : void 0,
5526
+ right: typeof camera.right === "number" ? camera.right : void 0,
5527
+ top: typeof camera.top === "number" ? camera.top : void 0,
5528
+ bottom: typeof camera.bottom === "number" ? camera.bottom : void 0,
5529
+ zoom: typeof camera.zoom === "number" ? camera.zoom : void 0
5530
+ };
5531
+ }
5532
+ }
5533
+ if (kind === "imageTarget") {
5534
+ const imageTarget = asRecord3(componentValues.imageTargetValues.get(sourceEntityId));
5535
+ if (imageTarget) {
5536
+ payload.options = {
5537
+ targets: Array.isArray(imageTarget.targets) ? imageTarget.targets : [],
5538
+ compiledTargetUrl: typeof imageTarget.compiledTargetUrl === "string" ? imageTarget.compiledTargetUrl : void 0,
5539
+ compiledTargetDir: typeof imageTarget.compiledTargetDir === "string" ? imageTarget.compiledTargetDir : void 0
5540
+ };
5541
+ }
5542
+ }
5543
+ if (kind === "instancedMesh") {
5544
+ const im = asRecord3(componentValues.instancedMeshValues.get(sourceEntityId));
5545
+ if (im) {
5546
+ payload.options = {
5547
+ meshKind: typeof im.meshKind === "string" ? im.meshKind : "cube",
5548
+ modelPath: typeof im.modelPath === "string" ? im.modelPath : void 0,
5549
+ meshParameters: asRecord3(im.meshParameters) ?? void 0,
5550
+ castShadow: typeof im.castShadow === "boolean" ? im.castShadow : false,
5551
+ receiveShadow: typeof im.receiveShadow === "boolean" ? im.receiveShadow : false,
5552
+ // New format: signal the factory to skip child entity creation.
5553
+ // Old format (instances[]): pass through for migration — factory will
5554
+ // create slot entities from the legacy InstanceTransform array.
5555
+ ...Array.isArray(im.instanceEntityIds) ? { instanceEntityIds: im.instanceEntityIds } : Array.isArray(im.instances) ? { instances: im.instances } : {}
5556
+ };
5557
+ }
5558
+ }
5559
+ if (kind === "instanceSlot") {
5560
+ const slot = asRecord3(componentValues.instanceSlotValues.get(sourceEntityId));
5561
+ if (slot) {
5562
+ payload.options = {
5563
+ groupEntityId: typeof slot.groupEntityId === "number" ? slot.groupEntityId : -1,
5564
+ slotIndex: typeof slot.slotIndex === "number" ? slot.slotIndex : 0
5565
+ };
5566
+ }
5567
+ }
5568
+ return payload;
5569
+ }
5570
+ __name(buildEntityCreationPayload, "buildEntityCreationPayload");
5571
+ function resolvePrimaryCameraSourceEntityId(snapshot, componentValues, entityTypeValues) {
5572
+ let firstCameraSourceEntityId = null;
5573
+ for (const sourceEntityId of snapshot.entities) {
5574
+ const entityType = readString(entityTypeValues.get(sourceEntityId));
5575
+ if (entityType !== "camera") {
5576
+ continue;
5577
+ }
5578
+ if (firstCameraSourceEntityId === null) {
5579
+ firstCameraSourceEntityId = sourceEntityId;
5580
+ }
5581
+ const cameraValue = asRecord3(componentValues.cameraValues.get(sourceEntityId));
5582
+ if (cameraValue?.isDefault === true) {
5583
+ return sourceEntityId;
5584
+ }
5585
+ }
5586
+ return firstCameraSourceEntityId;
5587
+ }
5588
+ __name(resolvePrimaryCameraSourceEntityId, "resolvePrimaryCameraSourceEntityId");
5589
+ function applyLocalTransformsAfterHierarchyRestore(world, scopeEntityIds) {
5590
+ const transformEntities = scopeEntityIds ? Array.from(scopeEntityIds) : world.query(TransformComponent, Object3DRef);
5591
+ for (const entityId of transformEntities) {
5592
+ const transform = world.getComponent(entityId, TransformComponent);
5593
+ const object = world.getComponent(entityId, Object3DRef)?.object;
5594
+ if (!transform || !object) {
5595
+ continue;
5596
+ }
5597
+ applyTransform(object, transform);
5598
+ object.updateMatrixWorld(true);
5599
+ }
5600
+ }
5601
+ __name(applyLocalTransformsAfterHierarchyRestore, "applyLocalTransformsAfterHierarchyRestore");
5602
+ function hydrateWorldFromSnapshotDetailed(snapshot, world, objectManagementSystem, options) {
5603
+ if (!snapshot || !snapshot.entities.length) {
5604
+ return {
5605
+ restoredCount: 0,
5606
+ selectedEntityId: null,
5607
+ idMap: /* @__PURE__ */ new Map()
5608
+ };
5609
+ }
5610
+ const assignPrimaryCamera = options?.assignPrimaryCamera !== false;
5611
+ const entityTypeValues = readByComponent(snapshot.components, "EntityType");
5612
+ const componentValues = buildComponentValueMaps(snapshot);
5613
+ const primaryCameraSourceEntityId = assignPrimaryCamera ? resolvePrimaryCameraSourceEntityId(
5614
+ snapshot,
5615
+ componentValues,
5616
+ entityTypeValues
5617
+ ) : null;
5618
+ const idMap = /* @__PURE__ */ new Map();
5619
+ for (const sourceEntityId of snapshot.entities) {
5620
+ const entityTypeValue = entityTypeValues.get(sourceEntityId);
5621
+ const entityType = readString(entityTypeValue);
5622
+ if (!entityType || !HYDRATABLE_ENTITY_KINDS.has(entityType)) {
5623
+ continue;
5624
+ }
5625
+ const kind = entityType;
5626
+ const payload = buildEntityCreationPayload(sourceEntityId, kind, componentValues);
5627
+ if (kind === "camera" && sourceEntityId === primaryCameraSourceEntityId) {
5628
+ payload.useWorldCamera = true;
5629
+ const options2 = asRecord3(payload.options);
5630
+ payload.options = {
5631
+ ...options2 ?? {},
5632
+ isDefault: true
5633
+ };
5634
+ }
5635
+ const createdEntityId = objectManagementSystem.createNow(kind, world, payload);
5636
+ idMap.set(sourceEntityId, createdEntityId);
5637
+ }
5638
+ for (const sourceEntityId of snapshot.entities) {
5639
+ const targetEntityId = idMap.get(sourceEntityId);
5640
+ if (targetEntityId === void 0) {
5641
+ continue;
5642
+ }
5643
+ const entityType = readString(entityTypeValues.get(sourceEntityId));
5644
+ restoreComponentState(
5645
+ world,
5646
+ objectManagementSystem,
5647
+ targetEntityId,
5648
+ sourceEntityId,
5649
+ entityType,
5650
+ componentValues
5651
+ );
5652
+ restorePostCreateComponents(
5653
+ world,
5654
+ objectManagementSystem,
5655
+ targetEntityId,
5656
+ sourceEntityId,
5657
+ entityType,
5658
+ componentValues,
5659
+ idMap
5660
+ );
5661
+ }
5662
+ applyParentLinks(snapshot, idMap, objectManagementSystem, world);
5663
+ objectManagementSystem.reconcileSceneFromWorld(world);
5664
+ applyLocalTransformsAfterHierarchyRestore(
5665
+ world,
5666
+ options?.applyTransformsScope === "created" ? idMap.values() : void 0
5667
+ );
5668
+ const selectedEntityId = typeof snapshot.selectedEntityId === "number" ? idMap.get(snapshot.selectedEntityId) ?? null : null;
5669
+ return {
5670
+ restoredCount: idMap.size,
5671
+ selectedEntityId,
5672
+ idMap
5673
+ };
5674
+ }
5675
+ __name(hydrateWorldFromSnapshotDetailed, "hydrateWorldFromSnapshotDetailed");
5676
+
5677
+ // core/prefab/overrides.ts
5678
+ var asRecord4 = /* @__PURE__ */ __name((value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : null, "asRecord");
5679
+ function findSnapshotRootEntityIds(snapshot) {
5680
+ const parentBlock = snapshot.components.find(
5681
+ (block) => block.component === "ParentId"
5682
+ );
5683
+ const parentByEntity = /* @__PURE__ */ new Map();
5684
+ for (const entry of parentBlock?.entries ?? []) {
5685
+ parentByEntity.set(entry.entityId, asRecord4(entry.value)?.value ?? null);
5686
+ }
5687
+ return snapshot.entities.filter(
5688
+ (entityId) => typeof parentByEntity.get(entityId) !== "number"
5689
+ );
5690
+ }
5691
+ __name(findSnapshotRootEntityIds, "findSnapshotRootEntityIds");
5692
+
5693
+ // core/prefab/instantiateSubtree.ts
5694
+ var INSTANTIATE_EXCLUDED_COMPONENTS = /* @__PURE__ */ new Set([
5695
+ "Environment",
5696
+ "Postprocessing",
5697
+ "SelectionTransformState"
5698
+ ]);
5699
+ function instantiateSubtree(world, objectManagementSystem, snapshot) {
5700
+ const snapshotRootIds = new Set(findSnapshotRootEntityIds(snapshot));
5701
+ const safeSnapshot = {
5702
+ entities: snapshot.entities,
5703
+ components: snapshot.components.filter((block) => !INSTANTIATE_EXCLUDED_COMPONENTS.has(block.component)).map(
5704
+ (block) => block.component === "PrefabInstance" ? {
5705
+ component: block.component,
5706
+ entries: block.entries.filter(
5707
+ (entry) => !snapshotRootIds.has(entry.entityId)
5708
+ )
5709
+ } : block
5710
+ ).filter((block) => block.entries.length > 0)
5711
+ };
5712
+ const result = hydrateWorldFromSnapshotDetailed(
5713
+ safeSnapshot,
5714
+ world,
5715
+ objectManagementSystem,
5716
+ { assignPrimaryCamera: false, applyTransformsScope: "created" }
5717
+ );
5718
+ const rootSourceId = findSnapshotRootEntityIds(safeSnapshot).find(
5719
+ (sourceId) => result.idMap.has(sourceId)
5720
+ );
5721
+ return {
5722
+ rootId: rootSourceId !== void 0 ? result.idMap.get(rootSourceId) ?? null : null,
5723
+ idMap: result.idMap
5724
+ };
5725
+ }
5726
+ __name(instantiateSubtree, "instantiateSubtree");
5727
+
5728
+ // core/prefab/types.ts
5729
+ var isRecord = /* @__PURE__ */ __name((value) => value !== null && typeof value === "object" && !Array.isArray(value), "isRecord");
5730
+ function parsePrefabAsset(json) {
5731
+ if (!isRecord(json)) {
5732
+ return null;
5733
+ }
5734
+ if (typeof json.version !== "number" || json.version < 1) {
5735
+ return null;
5736
+ }
5737
+ const snapshot = json.snapshot;
5738
+ if (!isRecord(snapshot)) {
5739
+ return null;
5740
+ }
5741
+ const entities = snapshot.entities;
5742
+ const components = snapshot.components;
5743
+ if (!Array.isArray(entities) || !Array.isArray(components)) {
5744
+ return null;
5745
+ }
5746
+ if (!entities.every((id) => typeof id === "number")) {
5747
+ return null;
5748
+ }
5749
+ if (!components.every(
5750
+ (block) => isRecord(block) && typeof block.component === "string" && Array.isArray(block.entries)
5751
+ )) {
5752
+ return null;
5753
+ }
5754
+ return {
5755
+ version: json.version,
5756
+ type: json.type === "scene" ? "scene" : "prefab",
5757
+ name: typeof json.name === "string" ? json.name : void 0,
5758
+ snapshot
5759
+ };
5760
+ }
5761
+ __name(parsePrefabAsset, "parsePrefabAsset");
5762
+ var resolveUrl = /* @__PURE__ */ __name((url) => url, "resolveUrl");
5763
+ function transformStringsDeep(value, fn) {
5764
+ if (typeof value === "string") {
5765
+ return fn(value);
5766
+ }
5767
+ if (Array.isArray(value)) {
5768
+ return value.map((item) => transformStringsDeep(item, fn));
5769
+ }
5770
+ if (value !== null && typeof value === "object") {
5771
+ const result = {};
5772
+ for (const [key, item] of Object.entries(value)) {
5773
+ result[key] = transformStringsDeep(item, fn);
5774
+ }
5775
+ return result;
5776
+ }
5777
+ return value;
5778
+ }
5779
+ __name(transformStringsDeep, "transformStringsDeep");
5780
+ var prefabCache = /* @__PURE__ */ new Map();
5781
+ function loadPrefab(url) {
5782
+ const cached = prefabCache.get(url);
5783
+ if (cached) {
5784
+ return cached;
5785
+ }
5786
+ const pending = (async () => {
5787
+ const response = await fetch(resolveUrl(url));
5788
+ if (!response.ok) {
5789
+ throw new Error(`Failed to fetch prefab "${url}" (${response.status})`);
5790
+ }
5791
+ const json = await response.json();
5792
+ const parsed = parsePrefabAsset(json);
5793
+ if (!parsed) {
5794
+ throw new Error(`Invalid prefab file at "${url}"`);
5795
+ }
5796
+ return {
5797
+ ...parsed,
5798
+ snapshot: transformStringsDeep(
5799
+ parsed.snapshot,
5800
+ resolveUrl
5801
+ )
5802
+ };
5803
+ })();
5804
+ prefabCache.set(url, pending);
5805
+ pending.catch(() => {
5806
+ if (prefabCache.get(url) === pending) {
5807
+ prefabCache.delete(url);
5808
+ }
5809
+ });
5810
+ return pending;
5811
+ }
5812
+ __name(loadPrefab, "loadPrefab");
5813
+ function resolveSource(source) {
5814
+ if (typeof source === "string") {
5815
+ return { url: source, asset: loadPrefab(source) };
5816
+ }
5817
+ if ("path" in source && typeof source.path === "string") {
5818
+ return { url: source.path, asset: loadPrefab(source.path) };
5819
+ }
5820
+ const asset = source;
5821
+ return { url: asset.name ?? "", asset };
5822
+ }
5823
+ __name(resolveSource, "resolveSource");
5824
+ async function spawnPrefab(world, source, options) {
5825
+ const { url, asset } = resolveSource(source);
5826
+ const prefab = await asset;
5827
+ const objectManagementSystem = world.getObjectManagementSystem();
5828
+ const { rootId } = instantiateSubtree(
5829
+ world,
5830
+ objectManagementSystem,
5831
+ prefab.snapshot
5832
+ );
5833
+ if (rootId === null) {
5834
+ throw new Error(
5835
+ `Prefab "${url || prefab.name || "unknown"}" contained no spawnable entities`
5836
+ );
5837
+ }
5838
+ if (!world.getComponent(rootId, PrefabInstance)) {
5839
+ world.addComponent(rootId, new PrefabInstance(url, []));
5840
+ }
5841
+ if (options?.parentId !== void 0 && options.parentId !== null) {
5842
+ objectManagementSystem.setParent(world, rootId, options.parentId, {
5843
+ preserveWorldTransform: false
5844
+ });
5845
+ }
5846
+ const transform = world.getComponent(rootId, TransformComponent);
5847
+ if (transform && (options?.position || options?.rotation || options?.scale)) {
5848
+ const write = /* @__PURE__ */ __name((target, src) => {
5849
+ if (!src) return;
5850
+ if (typeof src.x === "number") target.x = src.x;
5851
+ if (typeof src.y === "number") target.y = src.y;
5852
+ if (typeof src.z === "number") target.z = src.z;
5853
+ }, "write");
5854
+ write(transform.position, options.position);
5855
+ write(transform.rotation, options.rotation);
5856
+ write(transform.scale, options.scale);
5857
+ const object = world.getComponent(rootId, Object3DRef)?.object;
5858
+ if (object) {
5859
+ applyTransform(object, transform);
5860
+ object.updateMatrixWorld(true);
5861
+ }
5862
+ }
5863
+ return rootId;
5864
+ }
5865
+ __name(spawnPrefab, "spawnPrefab");
5866
+ function despawnPrefab(world, rootId, dispose = true) {
5867
+ const objectManagementSystem = world.getObjectManagementSystem();
5868
+ const subtree = collectEntitySubtree(world, [rootId]).reverse();
5869
+ let removed = 0;
5870
+ for (const entityId of subtree) {
5871
+ if (objectManagementSystem.deleteEntity(world, entityId, dispose)) {
5872
+ removed += 1;
5873
+ }
5874
+ }
5875
+ return removed;
5876
+ }
5877
+ __name(despawnPrefab, "despawnPrefab");
4521
5878
  var _Behaviour = class _Behaviour {
4522
5879
  /**
4523
5880
  * Engine-managed constructor. Hosts (`ScriptBehaviourSystem`) instantiate
@@ -4572,6 +5929,35 @@ var _Behaviour = class _Behaviour {
4572
5929
  */
4573
5930
  dispose(world) {
4574
5931
  }
5932
+ /**
5933
+ * Instantiate a prefab asset into the world at runtime.
5934
+ *
5935
+ * `source` is typically an `AssetInput` field from this script's `data`
5936
+ * (drag a `.prefab` from the asset browser onto the field in the editor),
5937
+ * a URL string, or a pre-loaded `PrefabAsset`. Resolves with the new root
5938
+ * entity id.
5939
+ *
5940
+ * ```ts
5941
+ * data = { enemyPrefab: { path: "", type: "prefab" } };
5942
+ * async onUpdate() {
5943
+ * if (shouldSpawn) {
5944
+ * const id = await this.spawnPrefab(this.data.enemyPrefab, {
5945
+ * position: { x: 0, y: 0, z: -5 },
5946
+ * });
5947
+ * }
5948
+ * }
5949
+ * ```
5950
+ */
5951
+ spawnPrefab(source, options) {
5952
+ return spawnPrefab(this.world, source, options);
5953
+ }
5954
+ /**
5955
+ * Remove a spawned prefab instance (the root entity and all descendants).
5956
+ * Returns the number of entities removed.
5957
+ */
5958
+ despawn(rootEntityId) {
5959
+ return despawnPrefab(this.world, rootEntityId);
5960
+ }
4575
5961
  /**
4576
5962
  * Returns the entity's world-space position as a new `THREE.Vector3`, or
4577
5963
  * `null` if the entity has no scene presence.