@relu-interactives/spatial-ecs 0.2.17 → 0.2.20

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