@relu-interactives/spatial-ecs 0.2.21 → 0.2.23

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 (50) hide show
  1. package/dist/{System-me3iAcMF.d.cts → System-CYWZ_Zx5.d.cts} +4 -3
  2. package/dist/{System-me3iAcMF.d.ts → System-CYWZ_Zx5.d.ts} +4 -3
  3. package/dist/{Video-DHnxjGhW.d.ts → Video-C1IOat7L.d.ts} +38 -9
  4. package/dist/{Video-U9hAnf9y.d.cts → Video-ppAXaKt0.d.cts} +38 -9
  5. package/dist/{chunk-K6KMKKJ6.js → chunk-52CHDPRQ.js} +118 -92
  6. package/dist/chunk-52CHDPRQ.js.map +1 -0
  7. package/dist/{chunk-5U3YS4JD.js → chunk-7BEZBIVB.js} +428 -65
  8. package/dist/chunk-7BEZBIVB.js.map +1 -0
  9. package/dist/{chunk-V7BNVTJW.js → chunk-JHCPRVBC.js} +25 -4
  10. package/dist/chunk-JHCPRVBC.js.map +1 -0
  11. package/dist/{chunk-AXRCGF63.js → chunk-WKGCC7YL.js} +3 -3
  12. package/dist/{chunk-AXRCGF63.js.map → chunk-WKGCC7YL.js.map} +1 -1
  13. package/dist/components/index.cjs +22 -1
  14. package/dist/components/index.cjs.map +1 -1
  15. package/dist/components/index.d.cts +3 -3
  16. package/dist/components/index.d.ts +3 -3
  17. package/dist/components/index.js +1 -1
  18. package/dist/docs/guide/authoring-a-behaviour.md +3 -40
  19. package/dist/docs/guide/authoring-a-script-object.md +115 -0
  20. package/dist/docs/guide/behaviour-lifecycle.md +4 -4
  21. package/dist/docs/guide/spawning/script-object.md +36 -0
  22. package/dist/docs/guide/systems/_sidebar.json +4 -0
  23. package/dist/docs/guide/systems/script-behaviour-system.md +1 -17
  24. package/dist/docs/guide/systems/script-object-system.md +44 -0
  25. package/dist/factories/index.cjs +164 -117
  26. package/dist/factories/index.cjs.map +1 -1
  27. package/dist/factories/index.d.cts +5 -3
  28. package/dist/factories/index.d.ts +5 -3
  29. package/dist/factories/index.js +3 -3
  30. package/dist/{index-D7FSg0Au.d.ts → index-Cu2Pt7wN.d.cts} +6 -3
  31. package/dist/{index-CZo5I5Gs.d.cts → index-DdiWu1b6.d.ts} +6 -3
  32. package/dist/index.cjs +684 -265
  33. package/dist/index.cjs.map +1 -1
  34. package/dist/index.d.cts +117 -28
  35. package/dist/index.d.ts +117 -28
  36. package/dist/index.js +13 -8
  37. package/dist/index.js.map +1 -1
  38. package/dist/systems/index.cjs +410 -36
  39. package/dist/systems/index.cjs.map +1 -1
  40. package/dist/systems/index.d.cts +44 -3
  41. package/dist/systems/index.d.ts +44 -3
  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.d.cts +1 -1
  46. package/dist/worldSnapshotUtils.d.ts +1 -1
  47. package/package.json +1 -1
  48. package/dist/chunk-5U3YS4JD.js.map +0 -1
  49. package/dist/chunk-K6KMKKJ6.js.map +0 -1
  50. package/dist/chunk-V7BNVTJW.js.map +0 -1
package/dist/index.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var THREE35 = require('three');
3
+ var THREE36 = require('three');
4
4
  var SkeletonUtils_js = require('three/examples/jsm/utils/SkeletonUtils.js');
5
5
  var RectAreaLightHelper_js = require('three/examples/jsm/helpers/RectAreaLightHelper.js');
6
6
  var DRACOLoader_js = require('three/examples/jsm/loaders/DRACOLoader.js');
@@ -39,7 +39,7 @@ function _interopNamespace(e) {
39
39
  return Object.freeze(n);
40
40
  }
41
41
 
42
- var THREE35__namespace = /*#__PURE__*/_interopNamespace(THREE35);
42
+ var THREE36__namespace = /*#__PURE__*/_interopNamespace(THREE36);
43
43
 
44
44
  var __defProp = Object.defineProperty;
45
45
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
@@ -593,14 +593,14 @@ var _AnimationComponent = class _AnimationComponent extends Component {
593
593
  return;
594
594
  }
595
595
  this.importedClips = clips.map((entry) => {
596
- if (entry instanceof THREE35__namespace.AnimationClip) {
596
+ if (entry instanceof THREE36__namespace.AnimationClip) {
597
597
  return { clip: entry, sourceUrl: null };
598
598
  }
599
599
  if (!entry || typeof entry !== "object") {
600
600
  return null;
601
601
  }
602
602
  const candidate = entry;
603
- if (!(candidate.clip instanceof THREE35__namespace.AnimationClip)) {
603
+ if (!(candidate.clip instanceof THREE36__namespace.AnimationClip)) {
604
604
  return null;
605
605
  }
606
606
  return {
@@ -808,11 +808,11 @@ function normalizeDistanceModel(distanceModel) {
808
808
  }
809
809
  __name(normalizeDistanceModel, "normalizeDistanceModel");
810
810
  function createConfiguredAudio(listener, options) {
811
- const sound = options.positional ? new THREE35__namespace.PositionalAudio(listener) : new THREE35__namespace.Audio(listener);
811
+ const sound = options.positional ? new THREE36__namespace.PositionalAudio(listener) : new THREE36__namespace.Audio(listener);
812
812
  sound.setLoop(options.loop);
813
813
  sound.setVolume(options.volume);
814
814
  sound.setPlaybackRate(options.pitch);
815
- if (sound instanceof THREE35__namespace.PositionalAudio) {
815
+ if (sound instanceof THREE36__namespace.PositionalAudio) {
816
816
  sound.setRefDistance(options.refDistance);
817
817
  sound.setDistanceModel(normalizeDistanceModel(options.distanceModel));
818
818
  sound.setRolloffFactor(options.rolloffFactor);
@@ -822,16 +822,16 @@ function createConfiguredAudio(listener, options) {
822
822
  __name(createConfiguredAudio, "createConfiguredAudio");
823
823
  function createAudioEditorHelper() {
824
824
  if (typeof document === "undefined") {
825
- const geometry = new THREE35__namespace.EdgesGeometry(
826
- new THREE35__namespace.OctahedronGeometry(0.22, 0)
825
+ const geometry = new THREE36__namespace.EdgesGeometry(
826
+ new THREE36__namespace.OctahedronGeometry(0.22, 0)
827
827
  );
828
- const material2 = new THREE35__namespace.LineBasicMaterial({
828
+ const material2 = new THREE36__namespace.LineBasicMaterial({
829
829
  color: "#8bc8ff",
830
830
  transparent: true,
831
831
  opacity: 0.95,
832
832
  depthTest: false
833
833
  });
834
- const fallback = new THREE35__namespace.LineSegments(geometry, material2);
834
+ const fallback = new THREE36__namespace.LineSegments(geometry, material2);
835
835
  fallback.renderOrder = 10;
836
836
  fallback.userData.ecsHelper = true;
837
837
  fallback.visible = false;
@@ -843,7 +843,7 @@ function createAudioEditorHelper() {
843
843
  canvas.height = size;
844
844
  const ctx = canvas.getContext("2d");
845
845
  if (!ctx) {
846
- return new THREE35__namespace.Object3D();
846
+ return new THREE36__namespace.Object3D();
847
847
  }
848
848
  ctx.clearRect(0, 0, size, size);
849
849
  ctx.fillStyle = "rgba(27, 35, 52, 0.9)";
@@ -874,14 +874,14 @@ function createAudioEditorHelper() {
874
874
  ctx.beginPath();
875
875
  ctx.arc(56, 48, 16, -0.8, 0.8);
876
876
  ctx.stroke();
877
- const texture = new THREE35__namespace.CanvasTexture(canvas);
877
+ const texture = new THREE36__namespace.CanvasTexture(canvas);
878
878
  texture.needsUpdate = true;
879
- const material = new THREE35__namespace.SpriteMaterial({
879
+ const material = new THREE36__namespace.SpriteMaterial({
880
880
  map: texture,
881
881
  transparent: true,
882
882
  depthTest: false
883
883
  });
884
- const helper = new THREE35__namespace.Sprite(material);
884
+ const helper = new THREE36__namespace.Sprite(material);
885
885
  helper.scale.set(0.68, 0.68, 0.68);
886
886
  helper.renderOrder = 10;
887
887
  helper.userData.ecsHelper = true;
@@ -915,7 +915,7 @@ var DEFAULT_ORTHO_TOP = 5;
915
915
  var DEFAULT_ORTHO_BOTTOM = -5;
916
916
  var DEFAULT_ZOOM = 1;
917
917
  function inferProjection(camera) {
918
- if (camera instanceof THREE35__namespace.OrthographicCamera) {
918
+ if (camera instanceof THREE36__namespace.OrthographicCamera) {
919
919
  return "orthographic";
920
920
  }
921
921
  return "perspective";
@@ -936,7 +936,7 @@ function readCameraFar(camera) {
936
936
  }
937
937
  __name(readCameraFar, "readCameraFar");
938
938
  function inferFov(camera) {
939
- if (camera instanceof THREE35__namespace.PerspectiveCamera && Number.isFinite(camera.fov)) {
939
+ if (camera instanceof THREE36__namespace.PerspectiveCamera && Number.isFinite(camera.fov)) {
940
940
  return camera.fov;
941
941
  }
942
942
  return DEFAULT_FOV;
@@ -959,28 +959,28 @@ function inferFar(camera) {
959
959
  }
960
960
  __name(inferFar, "inferFar");
961
961
  function inferOrthoLeft(camera) {
962
- if (camera instanceof THREE35__namespace.OrthographicCamera && Number.isFinite(camera.left)) {
962
+ if (camera instanceof THREE36__namespace.OrthographicCamera && Number.isFinite(camera.left)) {
963
963
  return camera.left;
964
964
  }
965
965
  return DEFAULT_ORTHO_LEFT;
966
966
  }
967
967
  __name(inferOrthoLeft, "inferOrthoLeft");
968
968
  function inferOrthoRight(camera) {
969
- if (camera instanceof THREE35__namespace.OrthographicCamera && Number.isFinite(camera.right)) {
969
+ if (camera instanceof THREE36__namespace.OrthographicCamera && Number.isFinite(camera.right)) {
970
970
  return camera.right;
971
971
  }
972
972
  return DEFAULT_ORTHO_RIGHT;
973
973
  }
974
974
  __name(inferOrthoRight, "inferOrthoRight");
975
975
  function inferOrthoTop(camera) {
976
- if (camera instanceof THREE35__namespace.OrthographicCamera && Number.isFinite(camera.top)) {
976
+ if (camera instanceof THREE36__namespace.OrthographicCamera && Number.isFinite(camera.top)) {
977
977
  return camera.top;
978
978
  }
979
979
  return DEFAULT_ORTHO_TOP;
980
980
  }
981
981
  __name(inferOrthoTop, "inferOrthoTop");
982
982
  function inferOrthoBottom(camera) {
983
- if (camera instanceof THREE35__namespace.OrthographicCamera && Number.isFinite(camera.bottom)) {
983
+ if (camera instanceof THREE36__namespace.OrthographicCamera && Number.isFinite(camera.bottom)) {
984
984
  return camera.bottom;
985
985
  }
986
986
  return DEFAULT_ORTHO_BOTTOM;
@@ -996,7 +996,7 @@ __name(inferZoom, "inferZoom");
996
996
  var _CameraComponent = class _CameraComponent extends Component {
997
997
  constructor(payload = {}) {
998
998
  super();
999
- this.camera = payload.camera ?? new THREE35__namespace.PerspectiveCamera();
999
+ this.camera = payload.camera ?? new THREE36__namespace.PerspectiveCamera();
1000
1000
  this.type = payload.type ?? "3d";
1001
1001
  this.isDefault = typeof payload.isDefault === "boolean" ? payload.isDefault : false;
1002
1002
  this.projection = payload.projection ?? inferProjection(payload.camera);
@@ -1027,7 +1027,7 @@ var Object3DRef = _Object3DRef;
1027
1027
  // core/factories/components/CameraFactory.ts
1028
1028
  function createCameraComponent(world, entityId, payload = {}) {
1029
1029
  const object = world.getComponent(entityId, Object3DRef)?.object;
1030
- const objectCamera = object instanceof THREE35__namespace.Camera ? object : void 0;
1030
+ const objectCamera = object instanceof THREE36__namespace.Camera ? object : void 0;
1031
1031
  const component = new CameraComponent({
1032
1032
  ...payload,
1033
1033
  camera: payload.camera ?? objectCamera
@@ -1588,15 +1588,15 @@ function createValueState(light) {
1588
1588
  castShadow: light.castShadow ?? false,
1589
1589
  frustumCulling: light.frustumCulled
1590
1590
  };
1591
- if (light instanceof THREE35__namespace.PointLight) {
1591
+ if (light instanceof THREE36__namespace.PointLight) {
1592
1592
  base.distance = light.distance;
1593
1593
  base.decay = light.decay;
1594
- } else if (light instanceof THREE35__namespace.SpotLight) {
1594
+ } else if (light instanceof THREE36__namespace.SpotLight) {
1595
1595
  base.distance = light.distance;
1596
1596
  base.decay = light.decay;
1597
1597
  base.angle = light.angle;
1598
1598
  base.penumbra = light.penumbra;
1599
- } else if (light instanceof THREE35__namespace.RectAreaLight) {
1599
+ } else if (light instanceof THREE36__namespace.RectAreaLight) {
1600
1600
  base.width = light.width;
1601
1601
  base.height = light.height;
1602
1602
  }
@@ -1639,13 +1639,13 @@ function toHexColor2(value, fallback) {
1639
1639
  }
1640
1640
  __name(toHexColor2, "toHexColor");
1641
1641
  function getMaterialType(material) {
1642
- if (material instanceof THREE35__namespace.MeshPhysicalMaterial) {
1642
+ if (material instanceof THREE36__namespace.MeshPhysicalMaterial) {
1643
1643
  return "physical";
1644
1644
  }
1645
- if (material instanceof THREE35__namespace.MeshPhongMaterial) {
1645
+ if (material instanceof THREE36__namespace.MeshPhongMaterial) {
1646
1646
  return "phong";
1647
1647
  }
1648
- if (material instanceof THREE35__namespace.MeshBasicMaterial) {
1648
+ if (material instanceof THREE36__namespace.MeshBasicMaterial) {
1649
1649
  return "basic";
1650
1650
  }
1651
1651
  return "standard";
@@ -1664,8 +1664,8 @@ function createMaterialValue(material) {
1664
1664
  opacity: typeof materialRecord.opacity === "number" ? materialRecord.opacity : 1,
1665
1665
  emissive: toHexColor2(materialRecord.emissive, "#000000"),
1666
1666
  emissiveIntensity: typeof materialRecord.emissiveIntensity === "number" ? materialRecord.emissiveIntensity : 0,
1667
- side: typeof materialRecord.side === "number" ? materialRecord.side : THREE35__namespace.FrontSide,
1668
- blending: typeof materialRecord.blending === "number" ? materialRecord.blending : THREE35__namespace.NormalBlending,
1667
+ side: typeof materialRecord.side === "number" ? materialRecord.side : THREE36__namespace.FrontSide,
1668
+ blending: typeof materialRecord.blending === "number" ? materialRecord.blending : THREE36__namespace.NormalBlending,
1669
1669
  depthTest: materialRecord.depthTest !== false,
1670
1670
  depthWrite: materialRecord.depthWrite !== false,
1671
1671
  wireframe: Boolean(materialRecord.wireframe),
@@ -1681,7 +1681,7 @@ function createMaterialValue(material) {
1681
1681
  displacementMap: materialRecord.displacementMap?.image?.src,
1682
1682
  lightMap: materialRecord.lightMap?.image?.src,
1683
1683
  envMap: materialRecord.envMap?.image?.src,
1684
- textureFiltering: map?.magFilter === THREE35__namespace.NearestFilter ? "sharp" : "smooth",
1684
+ textureFiltering: map?.magFilter === THREE36__namespace.NearestFilter ? "sharp" : "smooth",
1685
1685
  useMipmaps: map?.generateMipmaps !== false
1686
1686
  };
1687
1687
  }
@@ -1696,8 +1696,8 @@ function defaultMaterialValue() {
1696
1696
  opacity: 1,
1697
1697
  emissive: "#000000",
1698
1698
  emissiveIntensity: 0,
1699
- side: THREE35__namespace.FrontSide,
1700
- blending: THREE35__namespace.NormalBlending,
1699
+ side: THREE36__namespace.FrontSide,
1700
+ blending: THREE36__namespace.NormalBlending,
1701
1701
  depthTest: true,
1702
1702
  depthWrite: true,
1703
1703
  wireframe: false,
@@ -2118,7 +2118,6 @@ var _ScriptComponent = class _ScriptComponent extends Component {
2118
2118
  className: typeof entry.className === "string" ? entry.className : "",
2119
2119
  scriptUrl: typeof entry.scriptUrl === "string" ? entry.scriptUrl : "",
2120
2120
  enabled: typeof entry.enabled === "boolean" ? entry.enabled : true,
2121
- executeInEditor: typeof entry.executeInEditor === "boolean" ? entry.executeInEditor : false,
2122
2121
  data: entry.data && typeof entry.data === "object" && !Array.isArray(entry.data) ? entry.data : {},
2123
2122
  runtimeState: entry.runtimeState,
2124
2123
  runtimeMessage: typeof entry.runtimeMessage === "string" ? entry.runtimeMessage : void 0
@@ -2157,6 +2156,35 @@ function createScriptComponent(world, entityId, payload = {}) {
2157
2156
  }
2158
2157
  __name(createScriptComponent, "createScriptComponent");
2159
2158
 
2159
+ // core/components/ScriptObjectComponent.ts
2160
+ var _ScriptObjectComponent = class _ScriptObjectComponent extends Component {
2161
+ constructor(input = {}) {
2162
+ super();
2163
+ this.scriptUrl = typeof input.scriptUrl === "string" && input.scriptUrl.length > 0 ? input.scriptUrl : null;
2164
+ this.className = typeof input.className === "string" && input.className.length > 0 ? input.className : null;
2165
+ this.enabled = typeof input.enabled === "boolean" ? input.enabled : true;
2166
+ this.data = input.data && typeof input.data === "object" && !Array.isArray(input.data) ? input.data : {};
2167
+ this.runtimeState = input.runtimeState === "idle" || input.runtimeState === "loading" || input.runtimeState === "ready" || input.runtimeState === "error" ? input.runtimeState : "idle";
2168
+ this.runtimeMessage = typeof input.runtimeMessage === "string" ? input.runtimeMessage : void 0;
2169
+ Object.defineProperty(this, "instance", {
2170
+ value: null,
2171
+ writable: true,
2172
+ configurable: true,
2173
+ enumerable: false
2174
+ });
2175
+ }
2176
+ };
2177
+ __name(_ScriptObjectComponent, "ScriptObjectComponent");
2178
+ var ScriptObjectComponent = _ScriptObjectComponent;
2179
+
2180
+ // core/factories/components/ScriptObjectComponentFactory.ts
2181
+ function createScriptObjectComponent(world, entityId, payload = {}) {
2182
+ const component = new ScriptObjectComponent(payload);
2183
+ world.addComponent(entityId, component);
2184
+ return component;
2185
+ }
2186
+ __name(createScriptObjectComponent, "createScriptObjectComponent");
2187
+
2160
2188
  // core/components/Selectable.ts
2161
2189
  var _Selectable = class _Selectable extends Component {
2162
2190
  constructor(enabled = true) {
@@ -2246,14 +2274,14 @@ var _TransformComponent = class _TransformComponent extends Component {
2246
2274
  z: scale.z ?? 1
2247
2275
  };
2248
2276
  }
2249
- toPositionVector3(target = new THREE35.Vector3()) {
2277
+ toPositionVector3(target = new THREE36.Vector3()) {
2250
2278
  return target.set(this.position.x, this.position.y, this.position.z);
2251
2279
  }
2252
- toRotationEuler(target = new THREE35.Euler(), order = "XYZ") {
2280
+ toRotationEuler(target = new THREE36.Euler(), order = "XYZ") {
2253
2281
  return target.set(this.rotation.x, this.rotation.y, this.rotation.z, order);
2254
2282
  }
2255
- toRotationQuaternion(target = new THREE35.Quaternion(), order = "XYZ") {
2256
- const euler = new THREE35.Euler(
2283
+ toRotationQuaternion(target = new THREE36.Quaternion(), order = "XYZ") {
2284
+ const euler = new THREE36.Euler(
2257
2285
  this.rotation.x,
2258
2286
  this.rotation.y,
2259
2287
  this.rotation.z,
@@ -2261,7 +2289,7 @@ var _TransformComponent = class _TransformComponent extends Component {
2261
2289
  );
2262
2290
  return target.setFromEuler(euler);
2263
2291
  }
2264
- toScaleVector3(target = new THREE35.Vector3()) {
2292
+ toScaleVector3(target = new THREE36.Vector3()) {
2265
2293
  return target.set(this.scale.x, this.scale.y, this.scale.z);
2266
2294
  }
2267
2295
  setPosition(input) {
@@ -2279,8 +2307,8 @@ var _TransformComponent = class _TransformComponent extends Component {
2279
2307
  return this;
2280
2308
  }
2281
2309
  setRotation(input, order = "XYZ") {
2282
- if (input instanceof THREE35.Quaternion) {
2283
- const euler = new THREE35.Euler().setFromQuaternion(input, order);
2310
+ if (input instanceof THREE36.Quaternion) {
2311
+ const euler = new THREE36.Euler().setFromQuaternion(input, order);
2284
2312
  this.rotation.x = euler.x;
2285
2313
  this.rotation.y = euler.y;
2286
2314
  this.rotation.z = euler.z;
@@ -2518,6 +2546,10 @@ function registerDefaultComponentFactories(objectManagementSystem) {
2518
2546
  createPostprocessingComponent
2519
2547
  );
2520
2548
  objectManagementSystem.registerComponentFactory("script", createScriptComponent);
2549
+ objectManagementSystem.registerComponentFactory(
2550
+ "scriptObject",
2551
+ createScriptObjectComponent
2552
+ );
2521
2553
  objectManagementSystem.registerComponentFactory("selectable", createSelectableComponent);
2522
2554
  objectManagementSystem.registerComponentFactory(
2523
2555
  "selectionTransformState",
@@ -2533,7 +2565,7 @@ var SHARED_MODEL_RESOURCE_FLAG = "spatialEcsSharedModelResource";
2533
2565
  var modelCache = /* @__PURE__ */ new Map();
2534
2566
  function markSharedResources(root) {
2535
2567
  root.traverse((child) => {
2536
- if (!(child instanceof THREE35__namespace.Mesh)) {
2568
+ if (!(child instanceof THREE36__namespace.Mesh)) {
2537
2569
  return;
2538
2570
  }
2539
2571
  if (child.geometry) {
@@ -2612,10 +2644,10 @@ var _ObjectManagementSystem = class _ObjectManagementSystem {
2612
2644
  }
2613
2645
  getOrCreateAudioListener() {
2614
2646
  const existing = this.camera.userData.ecsAudioListener;
2615
- if (existing instanceof THREE35__namespace.AudioListener) {
2647
+ if (existing instanceof THREE36__namespace.AudioListener) {
2616
2648
  return existing;
2617
2649
  }
2618
- const listener = new THREE35__namespace.AudioListener();
2650
+ const listener = new THREE36__namespace.AudioListener();
2619
2651
  this.camera.add(listener);
2620
2652
  this.camera.userData.ecsAudioListener = listener;
2621
2653
  return listener;
@@ -2689,7 +2721,7 @@ var _ObjectManagementSystem = class _ObjectManagementSystem {
2689
2721
  }
2690
2722
  if (dispose && object3d) {
2691
2723
  object3d.traverse((child) => {
2692
- if (child instanceof THREE35__namespace.Mesh) {
2724
+ if (child instanceof THREE36__namespace.Mesh) {
2693
2725
  if (!child.geometry?.userData?.[SHARED_MODEL_RESOURCE_FLAG]) {
2694
2726
  child.geometry?.dispose();
2695
2727
  }
@@ -2826,10 +2858,10 @@ __name(createBaseEntity, "createBaseEntity");
2826
2858
  // core/factories/objects/AudioFactory.ts
2827
2859
  function getOrCreateListener(camera) {
2828
2860
  const existing = camera.userData.ecsAudioListener;
2829
- if (existing instanceof THREE35__namespace.AudioListener) {
2861
+ if (existing instanceof THREE36__namespace.AudioListener) {
2830
2862
  return existing;
2831
2863
  }
2832
- const listener = new THREE35__namespace.AudioListener();
2864
+ const listener = new THREE36__namespace.AudioListener();
2833
2865
  camera.add(listener);
2834
2866
  camera.userData.ecsAudioListener = listener;
2835
2867
  return listener;
@@ -2842,7 +2874,7 @@ function createAudio({
2842
2874
  payload,
2843
2875
  isEditor
2844
2876
  }) {
2845
- const anchor = new THREE35__namespace.Object3D();
2877
+ const anchor = new THREE36__namespace.Object3D();
2846
2878
  const entityId = createBaseEntity(world, anchor, {
2847
2879
  label: payload.name ?? "Audio",
2848
2880
  entityType: "audio",
@@ -2864,7 +2896,7 @@ function createAudio({
2864
2896
  return entityId;
2865
2897
  }
2866
2898
  if (!isEditor) {
2867
- const loader = new THREE35__namespace.AudioLoader();
2899
+ const loader = new THREE36__namespace.AudioLoader();
2868
2900
  loader.load(
2869
2901
  audio.path,
2870
2902
  (buffer) => {
@@ -2939,7 +2971,7 @@ function applyCameraSettings(camera, options) {
2939
2971
  const near = typeof options.near === "number" ? options.near : DEFAULT_NEAR2;
2940
2972
  const far = typeof options.far === "number" ? options.far : DEFAULT_FAR2;
2941
2973
  const projection = options.projection;
2942
- if (camera instanceof THREE35__namespace.PerspectiveCamera) {
2974
+ if (camera instanceof THREE36__namespace.PerspectiveCamera) {
2943
2975
  if (!projection || projection === "perspective") {
2944
2976
  camera.fov = typeof options.fov === "number" ? options.fov : DEFAULT_FOV2;
2945
2977
  }
@@ -2949,7 +2981,7 @@ function applyCameraSettings(camera, options) {
2949
2981
  camera.updateProjectionMatrix();
2950
2982
  return;
2951
2983
  }
2952
- if (camera instanceof THREE35__namespace.OrthographicCamera) {
2984
+ if (camera instanceof THREE36__namespace.OrthographicCamera) {
2953
2985
  camera.left = typeof options.left === "number" ? options.left : -DEFAULT_ORTHOGRAPHIC_HALF_HEIGHT;
2954
2986
  camera.right = typeof options.right === "number" ? options.right : DEFAULT_ORTHOGRAPHIC_HALF_HEIGHT;
2955
2987
  camera.top = typeof options.top === "number" ? options.top : DEFAULT_ORTHOGRAPHIC_HALF_HEIGHT;
@@ -2970,7 +3002,7 @@ function createCameraObject(options) {
2970
3002
  const bottom = options.bottom ?? -DEFAULT_ORTHOGRAPHIC_HALF_HEIGHT;
2971
3003
  const left = options.left ?? -DEFAULT_ORTHOGRAPHIC_HALF_HEIGHT;
2972
3004
  const right = options.right ?? DEFAULT_ORTHOGRAPHIC_HALF_HEIGHT;
2973
- const camera = new THREE35__namespace.OrthographicCamera(
3005
+ const camera = new THREE36__namespace.OrthographicCamera(
2974
3006
  left,
2975
3007
  right,
2976
3008
  top,
@@ -2982,7 +3014,7 @@ function createCameraObject(options) {
2982
3014
  camera.updateProjectionMatrix();
2983
3015
  return camera;
2984
3016
  }
2985
- return new THREE35__namespace.PerspectiveCamera(
3017
+ return new THREE36__namespace.PerspectiveCamera(
2986
3018
  options.fov ?? DEFAULT_FOV2,
2987
3019
  readViewportAspect(),
2988
3020
  near,
@@ -3000,7 +3032,7 @@ function createCamera({ world, scene, camera, payload, isEditor }) {
3000
3032
  transformInput: payload.transform
3001
3033
  });
3002
3034
  const objectRef = world.getComponent(entityId, Object3DRef);
3003
- if (objectRef?.object instanceof THREE35__namespace.Camera) {
3035
+ if (objectRef?.object instanceof THREE36__namespace.Camera) {
3004
3036
  objectRef.object.userData.entityId = entityId;
3005
3037
  }
3006
3038
  const componentOptions = {
@@ -3017,20 +3049,11 @@ function createCamera({ world, scene, camera, payload, isEditor }) {
3017
3049
  bottom: options.bottom,
3018
3050
  zoom: options.zoom
3019
3051
  };
3020
- const component = createCameraComponent(world, entityId, componentOptions);
3052
+ createCameraComponent(world, entityId, componentOptions);
3021
3053
  if (useWorldCamera) {
3022
3054
  applyCameraSettings(object, options);
3023
3055
  } else {
3024
3056
  applyCameraSettings(object, options);
3025
- if (isEditor && component.isDefault) {
3026
- const helper = new THREE35__namespace.CameraHelper(object);
3027
- helper.onBeforeRender = () => {
3028
- helper.update();
3029
- };
3030
- helper.userData.ecsHelper = true;
3031
- helper.visible = false;
3032
- object.add(helper);
3033
- }
3034
3057
  scene.add(object);
3035
3058
  }
3036
3059
  return entityId;
@@ -3041,9 +3064,9 @@ function createCapsule({
3041
3064
  scene,
3042
3065
  payload
3043
3066
  }) {
3044
- const geometry = new THREE35__namespace.CapsuleGeometry(0.5, 1, 4, 8);
3045
- const material = new THREE35__namespace.MeshStandardMaterial({ color: "#ffffff" });
3046
- const mesh = new THREE35__namespace.Mesh(geometry, material);
3067
+ const geometry = new THREE36__namespace.CapsuleGeometry(0.5, 1, 4, 8);
3068
+ const material = new THREE36__namespace.MeshStandardMaterial({ color: "#ffffff" });
3069
+ const mesh = new THREE36__namespace.Mesh(geometry, material);
3047
3070
  const entityId = createBaseEntity(world, mesh, {
3048
3071
  label: payload.name ?? "Capsule",
3049
3072
  entityType: "capsule",
@@ -3063,9 +3086,9 @@ function createCapsule({
3063
3086
  }
3064
3087
  __name(createCapsule, "createCapsule");
3065
3088
  function createCube({ world, scene, payload }) {
3066
- const geometry = new THREE35__namespace.BoxGeometry(1, 1, 1);
3067
- const material = new THREE35__namespace.MeshStandardMaterial({ color: "#ffffff" });
3068
- const mesh = new THREE35__namespace.Mesh(geometry, material);
3089
+ const geometry = new THREE36__namespace.BoxGeometry(1, 1, 1);
3090
+ const material = new THREE36__namespace.MeshStandardMaterial({ color: "#ffffff" });
3091
+ const mesh = new THREE36__namespace.Mesh(geometry, material);
3069
3092
  const entityId = createBaseEntity(world, mesh, {
3070
3093
  label: payload.name ?? "Cube",
3071
3094
  entityType: "cube",
@@ -3090,9 +3113,9 @@ function createCylinder({
3090
3113
  scene,
3091
3114
  payload
3092
3115
  }) {
3093
- const geometry = new THREE35__namespace.CylinderGeometry(0.5, 0.5, 1, 20);
3094
- const material = new THREE35__namespace.MeshStandardMaterial({ color: "#ffffff" });
3095
- const mesh = new THREE35__namespace.Mesh(geometry, material);
3116
+ const geometry = new THREE36__namespace.CylinderGeometry(0.5, 0.5, 1, 20);
3117
+ const material = new THREE36__namespace.MeshStandardMaterial({ color: "#ffffff" });
3118
+ const mesh = new THREE36__namespace.Mesh(geometry, material);
3096
3119
  const entityId = createBaseEntity(world, mesh, {
3097
3120
  label: payload.name ?? "Cylinder",
3098
3121
  entityType: "cylinder",
@@ -3112,7 +3135,7 @@ function createCylinder({
3112
3135
  }
3113
3136
  __name(createCylinder, "createCylinder");
3114
3137
  function createEmpty({ world, scene, payload, isEditor }) {
3115
- const object = new THREE35__namespace.Group();
3138
+ const object = new THREE36__namespace.Group();
3116
3139
  const entityId = createBaseEntity(world, object, {
3117
3140
  label: payload.name ?? "Empty",
3118
3141
  entityType: "empty",
@@ -3123,7 +3146,7 @@ function createEmpty({ world, scene, payload, isEditor }) {
3123
3146
  }
3124
3147
  __name(createEmpty, "createEmpty");
3125
3148
  function createImage({ world, scene, payload }) {
3126
- const anchor = new THREE35__namespace.Object3D();
3149
+ const anchor = new THREE36__namespace.Object3D();
3127
3150
  const imagePath = payload.path ?? "";
3128
3151
  const entityId = createBaseEntity(world, anchor, {
3129
3152
  label: payload.name ?? "Image",
@@ -3136,7 +3159,7 @@ function createImage({ world, scene, payload }) {
3136
3159
  if (!imagePath) {
3137
3160
  return entityId;
3138
3161
  }
3139
- const loader = new THREE35__namespace.TextureLoader();
3162
+ const loader = new THREE36__namespace.TextureLoader();
3140
3163
  loader.load(
3141
3164
  imagePath,
3142
3165
  (texture) => {
@@ -3144,13 +3167,13 @@ function createImage({ world, scene, payload }) {
3144
3167
  texture.dispose();
3145
3168
  return;
3146
3169
  }
3147
- const material = new THREE35__namespace.MeshBasicMaterial({
3170
+ const material = new THREE36__namespace.MeshBasicMaterial({
3148
3171
  map: texture,
3149
3172
  transparent: true,
3150
- side: THREE35__namespace.DoubleSide
3173
+ side: THREE36__namespace.DoubleSide
3151
3174
  });
3152
- const geometry = new THREE35__namespace.PlaneGeometry(1, 1);
3153
- const plane = new THREE35__namespace.Mesh(geometry, material);
3175
+ const geometry = new THREE36__namespace.PlaneGeometry(1, 1);
3176
+ const plane = new THREE36__namespace.Mesh(geometry, material);
3154
3177
  plane.userData.entityId = entityId;
3155
3178
  const textureImage = texture.image;
3156
3179
  const width = textureImage?.width ?? 1;
@@ -3196,7 +3219,7 @@ function createImageTarget({
3196
3219
  payload,
3197
3220
  isEditor
3198
3221
  }) {
3199
- const anchor = new THREE35__namespace.Object3D();
3222
+ const anchor = new THREE36__namespace.Object3D();
3200
3223
  const imagePath = payload.path ?? "";
3201
3224
  const entityId = createBaseEntity(world, anchor, {
3202
3225
  label: payload.name ?? "Image Target",
@@ -3213,7 +3236,7 @@ function createImageTarget({
3213
3236
  if (!isEditor || !imagePath) {
3214
3237
  return entityId;
3215
3238
  }
3216
- const loader = new THREE35__namespace.TextureLoader();
3239
+ const loader = new THREE36__namespace.TextureLoader();
3217
3240
  loader.load(
3218
3241
  imagePath,
3219
3242
  (texture) => {
@@ -3221,13 +3244,13 @@ function createImageTarget({
3221
3244
  texture.dispose();
3222
3245
  return;
3223
3246
  }
3224
- const material = new THREE35__namespace.MeshBasicMaterial({
3247
+ const material = new THREE36__namespace.MeshBasicMaterial({
3225
3248
  map: texture,
3226
3249
  transparent: true,
3227
- side: THREE35__namespace.DoubleSide
3250
+ side: THREE36__namespace.DoubleSide
3228
3251
  });
3229
- const geometry = new THREE35__namespace.PlaneGeometry(1, 1);
3230
- const plane = new THREE35__namespace.Mesh(geometry, material);
3252
+ const geometry = new THREE36__namespace.PlaneGeometry(1, 1);
3253
+ const plane = new THREE36__namespace.Mesh(geometry, material);
3231
3254
  plane.userData.entityId = entityId;
3232
3255
  const textureImage = texture.image;
3233
3256
  const width = textureImage?.width ?? 1;
@@ -3278,7 +3301,7 @@ function createInstancedMesh({
3278
3301
  scene,
3279
3302
  payload
3280
3303
  }) {
3281
- const anchor = new THREE35__namespace.Object3D();
3304
+ const anchor = new THREE36__namespace.Object3D();
3282
3305
  const opts = payload.options ?? {};
3283
3306
  const meshKind = isInstancedMeshKind(opts.meshKind) ? opts.meshKind : "cube";
3284
3307
  const meshParameters = opts.meshParameters && typeof opts.meshParameters === "object" ? opts.meshParameters : void 0;
@@ -3349,7 +3372,7 @@ function createAmbientLight({
3349
3372
  scene,
3350
3373
  payload
3351
3374
  }) {
3352
- const light = new THREE35__namespace.AmbientLight("#ffffff", 0.6);
3375
+ const light = new THREE36__namespace.AmbientLight("#ffffff", 0.6);
3353
3376
  const entityId = createBaseEntity(world, light, {
3354
3377
  label: payload.name ?? "Ambient Light",
3355
3378
  entityType: "ambientLight",
@@ -3366,7 +3389,7 @@ function createAreaLight({
3366
3389
  payload,
3367
3390
  isEditor
3368
3391
  }) {
3369
- const light = new THREE35__namespace.RectAreaLight("#ffffff", 5, 4, 4);
3392
+ const light = new THREE36__namespace.RectAreaLight("#ffffff", 5, 4, 4);
3370
3393
  light.lookAt(0, 0, 0);
3371
3394
  const entityId = createBaseEntity(world, light, {
3372
3395
  label: payload.name ?? "Area Light",
@@ -3395,7 +3418,7 @@ function createDirectionalLight({
3395
3418
  payload,
3396
3419
  isEditor
3397
3420
  }) {
3398
- const light = new THREE35__namespace.DirectionalLight("#ffffff", 1.5);
3421
+ const light = new THREE36__namespace.DirectionalLight("#ffffff", 1.5);
3399
3422
  light.castShadow = true;
3400
3423
  const entityId = createBaseEntity(world, light, {
3401
3424
  label: payload.name ?? "Directional Light",
@@ -3406,7 +3429,7 @@ function createDirectionalLight({
3406
3429
  });
3407
3430
  createLightComponent(world, entityId, light);
3408
3431
  if (isEditor) {
3409
- const helper = new THREE35__namespace.DirectionalLightHelper(light, 1.8, "#38bdf8");
3432
+ const helper = new THREE36__namespace.DirectionalLightHelper(light, 1.8, "#38bdf8");
3410
3433
  helper.onBeforeRender = () => {
3411
3434
  helper.update();
3412
3435
  };
@@ -3424,7 +3447,7 @@ function createPointLight({
3424
3447
  payload,
3425
3448
  isEditor
3426
3449
  }) {
3427
- const light = new THREE35__namespace.PointLight("#ffffff", 1, 10);
3450
+ const light = new THREE36__namespace.PointLight("#ffffff", 1, 10);
3428
3451
  const entityId = createBaseEntity(world, light, {
3429
3452
  label: payload.name ?? "Point Light",
3430
3453
  entityType: "pointLight",
@@ -3434,7 +3457,7 @@ function createPointLight({
3434
3457
  });
3435
3458
  createLightComponent(world, entityId, light);
3436
3459
  if (isEditor) {
3437
- const helper = new THREE35__namespace.PointLightHelper(light, 0.35, "#fbbf24");
3460
+ const helper = new THREE36__namespace.PointLightHelper(light, 0.35, "#fbbf24");
3438
3461
  helper.onBeforeRender = () => {
3439
3462
  helper.update();
3440
3463
  };
@@ -3452,7 +3475,7 @@ function createSpotLight({
3452
3475
  payload,
3453
3476
  isEditor
3454
3477
  }) {
3455
- const light = new THREE35__namespace.SpotLight("#ffffff", 1, 20, Math.PI / 6, 0.1, 1);
3478
+ const light = new THREE36__namespace.SpotLight("#ffffff", 1, 20, Math.PI / 6, 0.1, 1);
3456
3479
  const entityId = createBaseEntity(world, light, {
3457
3480
  label: payload.name ?? "Spot Light",
3458
3481
  entityType: "spotLight",
@@ -3462,7 +3485,7 @@ function createSpotLight({
3462
3485
  });
3463
3486
  createLightComponent(world, entityId, light);
3464
3487
  if (isEditor) {
3465
- const helper = new THREE35__namespace.SpotLightHelper(light, "#f59e0b");
3488
+ const helper = new THREE36__namespace.SpotLightHelper(light, "#f59e0b");
3466
3489
  helper.onBeforeRender = () => {
3467
3490
  helper.update();
3468
3491
  };
@@ -3540,6 +3563,7 @@ __export(components_exports, {
3540
3563
  PrefabInstance: () => PrefabInstance,
3541
3564
  PrefabNode: () => PrefabNode,
3542
3565
  ScriptComponent: () => ScriptComponent,
3566
+ ScriptObjectComponent: () => ScriptObjectComponent,
3543
3567
  Selectable: () => Selectable,
3544
3568
  SelectionTransformState: () => SelectionTransformState,
3545
3569
  SpriteComponent: () => SpriteComponent,
@@ -3602,7 +3626,7 @@ function createModel({
3602
3626
  payload,
3603
3627
  isEditor
3604
3628
  }) {
3605
- const anchor = new THREE35__namespace.Object3D();
3629
+ const anchor = new THREE36__namespace.Object3D();
3606
3630
  const modelPath = payload.path ?? "";
3607
3631
  const entityId = createBaseEntity(world, anchor, {
3608
3632
  label: payload.name ?? "Model",
@@ -3668,12 +3692,12 @@ function createModel({
3668
3692
  }
3669
3693
  __name(createModel, "createModel");
3670
3694
  function createPlane({ world, scene, payload }) {
3671
- const geometry = new THREE35__namespace.PlaneGeometry(100, 100);
3672
- const material = new THREE35__namespace.MeshStandardMaterial({
3695
+ const geometry = new THREE36__namespace.PlaneGeometry(100, 100);
3696
+ const material = new THREE36__namespace.MeshStandardMaterial({
3673
3697
  color: "#ffffff",
3674
- side: THREE35__namespace.DoubleSide
3698
+ side: THREE36__namespace.DoubleSide
3675
3699
  });
3676
- const mesh = new THREE35__namespace.Mesh(geometry, material);
3700
+ const mesh = new THREE36__namespace.Mesh(geometry, material);
3677
3701
  const entityId = createBaseEntity(
3678
3702
  world,
3679
3703
  mesh,
@@ -3704,8 +3728,30 @@ function createPlane({ world, scene, payload }) {
3704
3728
  return entityId;
3705
3729
  }
3706
3730
  __name(createPlane, "createPlane");
3731
+ function createScriptObject({
3732
+ world,
3733
+ scene,
3734
+ payload
3735
+ }) {
3736
+ const object = new THREE36__namespace.Group();
3737
+ const entityId = createBaseEntity(world, object, {
3738
+ label: payload.name ?? "Script Object",
3739
+ entityType: "scriptObject",
3740
+ transformInput: payload.transform
3741
+ });
3742
+ const options = payload.options ?? {};
3743
+ createScriptObjectComponent(world, entityId, {
3744
+ scriptUrl: typeof options.scriptUrl === "string" ? options.scriptUrl : null,
3745
+ className: typeof options.className === "string" ? options.className : null,
3746
+ enabled: typeof options.enabled === "boolean" ? options.enabled : true,
3747
+ data: options.data && typeof options.data === "object" && !Array.isArray(options.data) ? options.data : {}
3748
+ });
3749
+ scene.add(object);
3750
+ return entityId;
3751
+ }
3752
+ __name(createScriptObject, "createScriptObject");
3707
3753
  function createSprite({ world, scene, payload }) {
3708
- const anchor = new THREE35__namespace.Object3D();
3754
+ const anchor = new THREE36__namespace.Object3D();
3709
3755
  const imagePath = payload.path ?? "";
3710
3756
  const entityId = createBaseEntity(world, anchor, {
3711
3757
  label: payload.name ?? "Sprite",
@@ -3717,7 +3763,7 @@ function createSprite({ world, scene, payload }) {
3717
3763
  if (!imagePath) {
3718
3764
  return entityId;
3719
3765
  }
3720
- const loader = new THREE35__namespace.TextureLoader();
3766
+ const loader = new THREE36__namespace.TextureLoader();
3721
3767
  loader.load(
3722
3768
  imagePath,
3723
3769
  (texture) => {
@@ -3725,11 +3771,11 @@ function createSprite({ world, scene, payload }) {
3725
3771
  texture.dispose();
3726
3772
  return;
3727
3773
  }
3728
- const material = new THREE35__namespace.SpriteMaterial({
3774
+ const material = new THREE36__namespace.SpriteMaterial({
3729
3775
  map: texture,
3730
3776
  transparent: true
3731
3777
  });
3732
- const sprite = new THREE35__namespace.Sprite(material);
3778
+ const sprite = new THREE36__namespace.Sprite(material);
3733
3779
  sprite.userData.entityId = entityId;
3734
3780
  const textureImage = texture.image;
3735
3781
  spriteComponent.width = textureImage?.width ?? 1;
@@ -3747,9 +3793,9 @@ function createSprite({ world, scene, payload }) {
3747
3793
  }
3748
3794
  __name(createSprite, "createSprite");
3749
3795
  function createSphere({ world, scene, payload }) {
3750
- const geometry = new THREE35__namespace.SphereGeometry(0.5, 24, 24);
3751
- const material = new THREE35__namespace.MeshStandardMaterial({ color: "#ffffff" });
3752
- const mesh = new THREE35__namespace.Mesh(geometry, material);
3796
+ const geometry = new THREE36__namespace.SphereGeometry(0.5, 24, 24);
3797
+ const material = new THREE36__namespace.MeshStandardMaterial({ color: "#ffffff" });
3798
+ const mesh = new THREE36__namespace.Mesh(geometry, material);
3753
3799
  const entityId = createBaseEntity(world, mesh, {
3754
3800
  label: payload.name ?? "Sphere",
3755
3801
  entityType: "sphere",
@@ -3769,10 +3815,10 @@ function createSphere({ world, scene, payload }) {
3769
3815
  __name(createSphere, "createSphere");
3770
3816
  function getOrCreateListener2(camera) {
3771
3817
  const existing = camera.userData.ecsAudioListener;
3772
- if (existing instanceof THREE35__namespace.AudioListener) {
3818
+ if (existing instanceof THREE36__namespace.AudioListener) {
3773
3819
  return existing;
3774
3820
  }
3775
- const listener = new THREE35__namespace.AudioListener();
3821
+ const listener = new THREE36__namespace.AudioListener();
3776
3822
  camera.add(listener);
3777
3823
  camera.userData.ecsAudioListener = listener;
3778
3824
  return listener;
@@ -3822,10 +3868,10 @@ function normalizeOptions(input) {
3822
3868
  }
3823
3869
  __name(normalizeOptions, "normalizeOptions");
3824
3870
  function createChromaMaterial(texture, options) {
3825
- return new THREE35__namespace.ShaderMaterial({
3871
+ return new THREE36__namespace.ShaderMaterial({
3826
3872
  uniforms: {
3827
3873
  tex: { value: texture },
3828
- keyColor: { value: new THREE35__namespace.Color(options.backgroundColor) },
3874
+ keyColor: { value: new THREE36__namespace.Color(options.backgroundColor) },
3829
3875
  similarity: { value: options.similarity },
3830
3876
  smoothness: { value: options.smoothness },
3831
3877
  spill: { value: options.spill }
@@ -3857,22 +3903,22 @@ function createChromaMaterial(texture, options) {
3857
3903
  }
3858
3904
  `,
3859
3905
  transparent: true,
3860
- side: THREE35__namespace.DoubleSide
3906
+ side: THREE36__namespace.DoubleSide
3861
3907
  });
3862
3908
  }
3863
3909
  __name(createChromaMaterial, "createChromaMaterial");
3864
3910
  function createStandardMaterial(texture) {
3865
- return new THREE35__namespace.MeshBasicMaterial({
3911
+ return new THREE36__namespace.MeshBasicMaterial({
3866
3912
  map: texture,
3867
3913
  transparent: true,
3868
- side: THREE35__namespace.DoubleSide
3914
+ side: THREE36__namespace.DoubleSide
3869
3915
  });
3870
3916
  }
3871
3917
  __name(createStandardMaterial, "createStandardMaterial");
3872
3918
  function createVideoMesh(entityId, texture, options) {
3873
- const geometry = new THREE35__namespace.PlaneGeometry(1, 1);
3919
+ const geometry = new THREE36__namespace.PlaneGeometry(1, 1);
3874
3920
  const material = options.isGreenScreen ? createChromaMaterial(texture, options) : createStandardMaterial(texture);
3875
- const mesh = new THREE35__namespace.Mesh(geometry, material);
3921
+ const mesh = new THREE36__namespace.Mesh(geometry, material);
3876
3922
  mesh.userData.entityId = entityId;
3877
3923
  mesh.scale.set(options.width, options.height, 1);
3878
3924
  return { mesh, material };
@@ -3907,7 +3953,7 @@ function createVideo({
3907
3953
  payload,
3908
3954
  isEditor
3909
3955
  }) {
3910
- const anchor = new THREE35__namespace.Object3D();
3956
+ const anchor = new THREE36__namespace.Object3D();
3911
3957
  const path = payload.path ?? "";
3912
3958
  const options = normalizeOptions(payload.options);
3913
3959
  const entityId = createBaseEntity(world, anchor, {
@@ -3922,8 +3968,8 @@ function createVideo({
3922
3968
  return entityId;
3923
3969
  }
3924
3970
  const video = createVideoElement(path, options);
3925
- const texture = new THREE35__namespace.VideoTexture(video);
3926
- texture.colorSpace = THREE35__namespace.SRGBColorSpace;
3971
+ const texture = new THREE36__namespace.VideoTexture(video);
3972
+ texture.colorSpace = THREE36__namespace.SRGBColorSpace;
3927
3973
  texture.needsUpdate = true;
3928
3974
  const { mesh, material } = createVideoMesh(entityId, texture, options);
3929
3975
  anchor.add(mesh);
@@ -3939,7 +3985,7 @@ function createVideo({
3939
3985
  });
3940
3986
  if (!isEditor && options.positional) {
3941
3987
  const listener = getOrCreateListener2(camera);
3942
- const audioNode = new THREE35__namespace.PositionalAudio(listener);
3988
+ const audioNode = new THREE36__namespace.PositionalAudio(listener);
3943
3989
  audioNode.setVolume(options.volume);
3944
3990
  audioNode.setRefDistance(options.refDistance);
3945
3991
  audioNode.setDistanceModel(normalizeDistanceModel2(options.distanceModel));
@@ -3978,6 +4024,7 @@ function registerDefaultFactories(objectManagementSystem) {
3978
4024
  objectManagementSystem.register("pointLight", createPointLight);
3979
4025
  objectManagementSystem.register("spotLight", createSpotLight);
3980
4026
  objectManagementSystem.register("areaLight", createAreaLight);
4027
+ objectManagementSystem.register("scriptObject", createScriptObject);
3981
4028
  registerDefaultComponentFactories(objectManagementSystem);
3982
4029
  }
3983
4030
  __name(registerDefaultFactories, "registerDefaultFactories");
@@ -4106,6 +4153,10 @@ function buildComponentValueMaps(snapshot) {
4106
4153
  animationValues: readByComponent(snapshot.components, "AnimationComponent"),
4107
4154
  imageTargetAnchorValues: readByComponent(snapshot.components, "ImageTargetAnchor"),
4108
4155
  scriptValues: readByComponent(snapshot.components, "ScriptComponent"),
4156
+ scriptObjectValues: readByComponent(
4157
+ snapshot.components,
4158
+ "ScriptObjectComponent"
4159
+ ),
4109
4160
  instancedMeshValues: readByComponent(snapshot.components, "InstancedMeshComponent"),
4110
4161
  instanceSlotValues: readByComponent(snapshot.components, "InstanceSlotComponent"),
4111
4162
  prefabNodeValues: readByComponent(snapshot.components, "PrefabNode"),
@@ -4223,6 +4274,14 @@ function restorePostCreateComponents(world, objectManagementSystem, targetEntity
4223
4274
  new ScriptComponent(entries)
4224
4275
  );
4225
4276
  }
4277
+ const sourceScriptObject = asRecord3(values.scriptObjectValues.get(sourceEntityId));
4278
+ if (sourceScriptObject) {
4279
+ const soc = world.getComponent(targetEntityId, ScriptObjectComponent);
4280
+ const data = asRecord3(sourceScriptObject.data);
4281
+ if (soc && data) {
4282
+ soc.data = remapEntityRefsInScriptData(data, idMap);
4283
+ }
4284
+ }
4226
4285
  {
4227
4286
  const imComponent = world.getComponent(targetEntityId, InstancedMeshComponent);
4228
4287
  if (imComponent && imComponent.instanceEntityIds.length > 0) {
@@ -4809,7 +4868,8 @@ var HYDRATABLE_ENTITY_KINDS = /* @__PURE__ */ new Set([
4809
4868
  "spotLight",
4810
4869
  "areaLight",
4811
4870
  "instancedMesh",
4812
- "instanceSlot"
4871
+ "instanceSlot",
4872
+ "scriptObject"
4813
4873
  ]);
4814
4874
 
4815
4875
  // core/hydration/hydrateWorld.ts
@@ -4911,6 +4971,16 @@ function buildEntityCreationPayload(sourceEntityId, kind, componentValues) {
4911
4971
  };
4912
4972
  }
4913
4973
  }
4974
+ if (kind === "scriptObject") {
4975
+ const so = asRecord3(componentValues.scriptObjectValues.get(sourceEntityId));
4976
+ if (so) {
4977
+ payload.options = {
4978
+ scriptUrl: typeof so.scriptUrl === "string" ? so.scriptUrl : null,
4979
+ className: typeof so.className === "string" ? so.className : null,
4980
+ enabled: typeof so.enabled === "boolean" ? so.enabled : true
4981
+ };
4982
+ }
4983
+ }
4914
4984
  return payload;
4915
4985
  }
4916
4986
  __name(buildEntityCreationPayload, "buildEntityCreationPayload");
@@ -5242,6 +5312,33 @@ var toRefOrRaw = /* @__PURE__ */ __name((id, idToNode) => {
5242
5312
  const nodeId = idToNode.get(id);
5243
5313
  return nodeId !== void 0 ? makeNodeRef(nodeId) : id;
5244
5314
  }, "toRefOrRaw");
5315
+ function canonicalizeScriptDataFields(data, idToNode) {
5316
+ const canonicalData = {};
5317
+ for (const [key, fieldValue] of Object.entries(data)) {
5318
+ const field = asRecord5(fieldValue);
5319
+ if (field?.type === "entity" && typeof field.value === "number") {
5320
+ canonicalData[key] = {
5321
+ ...field,
5322
+ value: toRefOrRaw(field.value, idToNode)
5323
+ };
5324
+ continue;
5325
+ }
5326
+ const componentRef = asRecord5(field?.value);
5327
+ if (field?.type === "component" && componentRef && typeof componentRef.entityId === "number") {
5328
+ canonicalData[key] = {
5329
+ ...field,
5330
+ value: {
5331
+ ...componentRef,
5332
+ entityId: toRefOrRaw(componentRef.entityId, idToNode)
5333
+ }
5334
+ };
5335
+ continue;
5336
+ }
5337
+ canonicalData[key] = fieldValue;
5338
+ }
5339
+ return canonicalData;
5340
+ }
5341
+ __name(canonicalizeScriptDataFields, "canonicalizeScriptDataFields");
5245
5342
  function canonicalizeComponentValue(componentName, value, idToNode) {
5246
5343
  const cloned = clone(value);
5247
5344
  const record = asRecord5(cloned);
@@ -5267,39 +5364,23 @@ function canonicalizeComponentValue(componentName, value, idToNode) {
5267
5364
  if (!entry) {
5268
5365
  return rawEntry;
5269
5366
  }
5270
- const data = asRecord5(entry.data) ?? {};
5271
- const canonicalData = {};
5272
- for (const [key, fieldValue] of Object.entries(data)) {
5273
- const field = asRecord5(fieldValue);
5274
- if (field?.type === "entity" && typeof field.value === "number") {
5275
- canonicalData[key] = {
5276
- ...field,
5277
- value: toRefOrRaw(field.value, idToNode)
5278
- };
5279
- continue;
5280
- }
5281
- const componentRef = asRecord5(field?.value);
5282
- if (field?.type === "component" && componentRef && typeof componentRef.entityId === "number") {
5283
- canonicalData[key] = {
5284
- ...field,
5285
- value: {
5286
- ...componentRef,
5287
- entityId: toRefOrRaw(componentRef.entityId, idToNode)
5288
- }
5289
- };
5290
- continue;
5291
- }
5292
- canonicalData[key] = fieldValue;
5293
- }
5294
5367
  return {
5295
5368
  className: typeof entry.className === "string" ? entry.className : "",
5296
5369
  scriptUrl: typeof entry.scriptUrl === "string" ? entry.scriptUrl : "",
5297
5370
  enabled: typeof entry.enabled === "boolean" ? entry.enabled : true,
5298
- data: canonicalData
5371
+ data: canonicalizeScriptDataFields(asRecord5(entry.data) ?? {}, idToNode)
5299
5372
  };
5300
5373
  })
5301
5374
  };
5302
5375
  }
5376
+ if (componentName === "ScriptObjectComponent") {
5377
+ return {
5378
+ scriptUrl: typeof record.scriptUrl === "string" ? record.scriptUrl : null,
5379
+ className: typeof record.className === "string" ? record.className : null,
5380
+ enabled: typeof record.enabled === "boolean" ? record.enabled : true,
5381
+ data: canonicalizeScriptDataFields(asRecord5(record.data) ?? {}, idToNode)
5382
+ };
5383
+ }
5303
5384
  if (componentName === "InstancedMeshComponent") {
5304
5385
  if (Array.isArray(record.instanceEntityIds)) {
5305
5386
  record.instanceEntityIds = record.instanceEntityIds.map(
@@ -5892,7 +5973,7 @@ function transitionToClip(runtime, nextClipId, crossFadeDuration) {
5892
5973
  }
5893
5974
  __name(transitionToClip, "transitionToClip");
5894
5975
  function applyActionState(action, component, paused, shouldLoop) {
5895
- const loopMode = shouldLoop ? THREE35__namespace.LoopRepeat : THREE35__namespace.LoopOnce;
5976
+ const loopMode = shouldLoop ? THREE36__namespace.LoopRepeat : THREE36__namespace.LoopOnce;
5896
5977
  const repetitions = shouldLoop ? Infinity : 1;
5897
5978
  action.setLoop(loopMode, repetitions);
5898
5979
  action.clampWhenFinished = !shouldLoop;
@@ -6065,7 +6146,7 @@ var _AnimationSystem = class _AnimationSystem {
6065
6146
  if (runtime) {
6066
6147
  stopAllActions(runtime);
6067
6148
  }
6068
- const mixer = new THREE35__namespace.AnimationMixer(root);
6149
+ const mixer = new THREE36__namespace.AnimationMixer(root);
6069
6150
  const entries2 = readRuntimeClipEntries(animation);
6070
6151
  const indexedActions = createActions(mixer, entries2);
6071
6152
  runtime = {
@@ -6191,11 +6272,11 @@ function normalizeOrthoBounds(component) {
6191
6272
  }
6192
6273
  __name(normalizeOrthoBounds, "normalizeOrthoBounds");
6193
6274
  function isPerspectiveCamera(camera) {
6194
- return camera instanceof THREE35__namespace.PerspectiveCamera;
6275
+ return camera instanceof THREE36__namespace.PerspectiveCamera;
6195
6276
  }
6196
6277
  __name(isPerspectiveCamera, "isPerspectiveCamera");
6197
6278
  function isOrthographicCamera(camera) {
6198
- return camera instanceof THREE35__namespace.OrthographicCamera;
6279
+ return camera instanceof THREE36__namespace.OrthographicCamera;
6199
6280
  }
6200
6281
  __name(isOrthographicCamera, "isOrthographicCamera");
6201
6282
  function readWindowAspect() {
@@ -6248,7 +6329,7 @@ var _CameraSyncSystem = class _CameraSyncSystem {
6248
6329
  continue;
6249
6330
  }
6250
6331
  const camera = objectRef.object;
6251
- if (!(camera instanceof THREE35__namespace.Camera)) {
6332
+ if (!(camera instanceof THREE36__namespace.Camera)) {
6252
6333
  continue;
6253
6334
  }
6254
6335
  const nextSignature = buildSignature(component, camera, windowAspect);
@@ -6312,7 +6393,7 @@ var MIN_DENSITY = 0;
6312
6393
  function createGradientTexture(effect, colors) {
6313
6394
  if (typeof document === "undefined") {
6314
6395
  const pixel = new Uint8Array([30, 30, 30, 255]);
6315
- const fallback = new THREE35__namespace.DataTexture(pixel, 1, 1, THREE35__namespace.RGBAFormat);
6396
+ const fallback = new THREE36__namespace.DataTexture(pixel, 1, 1, THREE36__namespace.RGBAFormat);
6316
6397
  fallback.needsUpdate = true;
6317
6398
  return fallback;
6318
6399
  }
@@ -6321,7 +6402,7 @@ function createGradientTexture(effect, colors) {
6321
6402
  canvas.height = 512;
6322
6403
  const context = canvas.getContext("2d");
6323
6404
  if (!context) {
6324
- const fallback = new THREE35__namespace.CanvasTexture(canvas);
6405
+ const fallback = new THREE36__namespace.CanvasTexture(canvas);
6325
6406
  fallback.needsUpdate = true;
6326
6407
  return fallback;
6327
6408
  }
@@ -6349,15 +6430,15 @@ function createGradientTexture(effect, colors) {
6349
6430
  context.fillRect(0, 0, 512, 512);
6350
6431
  context.globalCompositeOperation = "source-over";
6351
6432
  }
6352
- const texture = new THREE35__namespace.CanvasTexture(canvas);
6353
- texture.colorSpace = THREE35__namespace.SRGBColorSpace;
6433
+ const texture = new THREE36__namespace.CanvasTexture(canvas);
6434
+ texture.colorSpace = THREE36__namespace.SRGBColorSpace;
6354
6435
  texture.needsUpdate = true;
6355
6436
  return texture;
6356
6437
  }
6357
6438
  __name(createGradientTexture, "createGradientTexture");
6358
6439
  var _EnvironmentSyncSystem = class _EnvironmentSyncSystem {
6359
6440
  constructor(scene) {
6360
- this.textureLoader = new THREE35__namespace.TextureLoader();
6441
+ this.textureLoader = new THREE36__namespace.TextureLoader();
6361
6442
  this.signature = null;
6362
6443
  this.activeTexture = null;
6363
6444
  this.pendingImageUrl = null;
@@ -6380,7 +6461,7 @@ var _EnvironmentSyncSystem = class _EnvironmentSyncSystem {
6380
6461
  if (skybox.type === "color") {
6381
6462
  this.disposeActiveTexture();
6382
6463
  this.pendingImageUrl = null;
6383
- this.scene.background = new THREE35__namespace.Color(skybox.color || "#1e1e1e");
6464
+ this.scene.background = new THREE36__namespace.Color(skybox.color || "#1e1e1e");
6384
6465
  return;
6385
6466
  }
6386
6467
  if (skybox.type === "gradient") {
@@ -6414,7 +6495,7 @@ var _EnvironmentSyncSystem = class _EnvironmentSyncSystem {
6414
6495
  texture.dispose();
6415
6496
  return;
6416
6497
  }
6417
- texture.colorSpace = THREE35__namespace.SRGBColorSpace;
6498
+ texture.colorSpace = THREE36__namespace.SRGBColorSpace;
6418
6499
  this.activeTexture = texture;
6419
6500
  this.scene.background = texture;
6420
6501
  },
@@ -6433,16 +6514,16 @@ var _EnvironmentSyncSystem = class _EnvironmentSyncSystem {
6433
6514
  this.scene.fog = null;
6434
6515
  return;
6435
6516
  }
6436
- const fogColor = new THREE35__namespace.Color(fog.color || "#1e1e1e");
6517
+ const fogColor = new THREE36__namespace.Color(fog.color || "#1e1e1e");
6437
6518
  if (fog.type === "linear") {
6438
6519
  const near = Number.isFinite(fog.linear.near) ? fog.linear.near : 1;
6439
6520
  const farCandidate = Number.isFinite(fog.linear.far) ? fog.linear.far : near + 10;
6440
6521
  const far = Math.max(near + MIN_FOG_DELTA, farCandidate);
6441
- this.scene.fog = new THREE35__namespace.Fog(fogColor, near, far);
6522
+ this.scene.fog = new THREE36__namespace.Fog(fogColor, near, far);
6442
6523
  return;
6443
6524
  }
6444
6525
  const density = Number.isFinite(fog.exponential.density) ? Math.max(MIN_DENSITY, fog.exponential.density) : 2e-3;
6445
- this.scene.fog = new THREE35__namespace.FogExp2(fogColor, density);
6526
+ this.scene.fog = new THREE36__namespace.FogExp2(fogColor, density);
6446
6527
  }
6447
6528
  update(world) {
6448
6529
  const entityIds = world.query(Environment);
@@ -6524,10 +6605,10 @@ var _PostprocessingSyncSystem = class _PostprocessingSyncSystem {
6524
6605
  );
6525
6606
  }
6526
6607
  if (values.bloom.enabled) {
6527
- const size = this.renderer.getSize(new THREE35__namespace.Vector2());
6608
+ const size = this.renderer.getSize(new THREE36__namespace.Vector2());
6528
6609
  composer.addPass(
6529
6610
  new UnrealBloomPass_js.UnrealBloomPass(
6530
- new THREE35__namespace.Vector2(size.width, size.height),
6611
+ new THREE36__namespace.Vector2(size.width, size.height),
6531
6612
  values.bloom.intensity,
6532
6613
  values.bloom.radius,
6533
6614
  values.bloom.threshold
@@ -6572,7 +6653,7 @@ var _PostprocessingSyncSystem = class _PostprocessingSyncSystem {
6572
6653
  if (values.dotScreen.enabled) {
6573
6654
  composer.addPass(
6574
6655
  new DotScreenPass_js.DotScreenPass(
6575
- new THREE35__namespace.Vector2(0, 0),
6656
+ new THREE36__namespace.Vector2(0, 0),
6576
6657
  values.dotScreen.angle ?? values.dotScreen.dotScreenAngle,
6577
6658
  values.dotScreen.scale ?? values.dotScreen.dotScreenScale
6578
6659
  )
@@ -6646,7 +6727,7 @@ function computeColliderState(colliderValues, object) {
6646
6727
  if (!object) {
6647
6728
  return colliderValues;
6648
6729
  }
6649
- const scale = new THREE35__namespace.Vector3();
6730
+ const scale = new THREE36__namespace.Vector3();
6650
6731
  object.getWorldScale(scale);
6651
6732
  return {
6652
6733
  ...colliderValues,
@@ -6697,8 +6778,8 @@ function createColliderDesc(RAPIER, values, triMeshData) {
6697
6778
  values.offsetPosition.y,
6698
6779
  values.offsetPosition.z
6699
6780
  );
6700
- const offsetQuaternion = new THREE35__namespace.Quaternion().setFromEuler(
6701
- new THREE35__namespace.Euler(
6781
+ const offsetQuaternion = new THREE36__namespace.Quaternion().setFromEuler(
6782
+ new THREE36__namespace.Euler(
6702
6783
  values.offsetRotation.x,
6703
6784
  values.offsetRotation.y,
6704
6785
  values.offsetRotation.z
@@ -6709,7 +6790,7 @@ function createColliderDesc(RAPIER, values, triMeshData) {
6709
6790
  }
6710
6791
  __name(createColliderDesc, "createColliderDesc");
6711
6792
  function findFirstMeshWithGeometry(object) {
6712
- if (object instanceof THREE35__namespace.Mesh && object.geometry) {
6793
+ if (object instanceof THREE36__namespace.Mesh && object.geometry) {
6713
6794
  return object;
6714
6795
  }
6715
6796
  let found = null;
@@ -6717,7 +6798,7 @@ function findFirstMeshWithGeometry(object) {
6717
6798
  if (found) {
6718
6799
  return;
6719
6800
  }
6720
- if (child instanceof THREE35__namespace.Mesh && child.geometry) {
6801
+ if (child instanceof THREE36__namespace.Mesh && child.geometry) {
6721
6802
  found = child;
6722
6803
  }
6723
6804
  });
@@ -6743,13 +6824,13 @@ function createTriMeshData(object) {
6743
6824
  }
6744
6825
  object.updateWorldMatrix(true, true);
6745
6826
  mesh.updateWorldMatrix(true, true);
6746
- const worldToObject = new THREE35__namespace.Matrix4().copy(object.matrixWorld).invert();
6747
- const relativeMatrix = new THREE35__namespace.Matrix4().multiplyMatrices(
6827
+ const worldToObject = new THREE36__namespace.Matrix4().copy(object.matrixWorld).invert();
6828
+ const relativeMatrix = new THREE36__namespace.Matrix4().multiplyMatrices(
6748
6829
  worldToObject,
6749
6830
  mesh.matrixWorld
6750
6831
  );
6751
6832
  const vertices = new Float32Array(positionCount * 3);
6752
- const point = new THREE35__namespace.Vector3();
6833
+ const point = new THREE36__namespace.Vector3();
6753
6834
  for (let index = 0; index < positionCount; index += 1) {
6754
6835
  point.set(
6755
6836
  positionAttribute.getX(index),
@@ -6787,8 +6868,8 @@ function createTriMeshData(object) {
6787
6868
  }
6788
6869
  __name(createTriMeshData, "createTriMeshData");
6789
6870
  function syncBodyFromTransform(body, transform) {
6790
- const quaternion = new THREE35__namespace.Quaternion().setFromEuler(
6791
- new THREE35__namespace.Euler(transform.rotation.x, transform.rotation.y, transform.rotation.z)
6871
+ const quaternion = new THREE36__namespace.Quaternion().setFromEuler(
6872
+ new THREE36__namespace.Euler(transform.rotation.x, transform.rotation.y, transform.rotation.z)
6792
6873
  );
6793
6874
  body.setTranslation(
6794
6875
  {
@@ -6815,8 +6896,8 @@ function syncTransformFromBody(transform, body) {
6815
6896
  transform.position.x = position.x;
6816
6897
  transform.position.y = position.y;
6817
6898
  transform.position.z = position.z;
6818
- const euler = new THREE35__namespace.Euler().setFromQuaternion(
6819
- new THREE35__namespace.Quaternion(rotation.x, rotation.y, rotation.z, rotation.w)
6899
+ const euler = new THREE36__namespace.Euler().setFromQuaternion(
6900
+ new THREE36__namespace.Quaternion(rotation.x, rotation.y, rotation.z, rotation.w)
6820
6901
  );
6821
6902
  transform.rotation.x = euler.x;
6822
6903
  transform.rotation.y = euler.y;
@@ -6928,8 +7009,8 @@ var _PhysicsSyncSystem = class _PhysicsSyncSystem {
6928
7009
  transform.position.y,
6929
7010
  transform.position.z
6930
7011
  );
6931
- const quaternion = new THREE35__namespace.Quaternion().setFromEuler(
6932
- new THREE35__namespace.Euler(
7012
+ const quaternion = new THREE36__namespace.Quaternion().setFromEuler(
7013
+ new THREE36__namespace.Euler(
6933
7014
  transform.rotation.x,
6934
7015
  transform.rotation.y,
6935
7016
  transform.rotation.z
@@ -7504,7 +7585,7 @@ function applyLightValues(lightComponent) {
7504
7585
  values.castShadow
7505
7586
  );
7506
7587
  }
7507
- if (light instanceof THREE35__namespace.PointLight) {
7588
+ if (light instanceof THREE36__namespace.PointLight) {
7508
7589
  if (typeof values.distance === "number" && Number.isFinite(values.distance)) {
7509
7590
  light.distance = Math.max(MIN_LIGHT_DISTANCE, values.distance);
7510
7591
  }
@@ -7512,7 +7593,7 @@ function applyLightValues(lightComponent) {
7512
7593
  light.decay = Math.max(0, values.decay);
7513
7594
  }
7514
7595
  }
7515
- if (light instanceof THREE35__namespace.SpotLight) {
7596
+ if (light instanceof THREE36__namespace.SpotLight) {
7516
7597
  if (typeof values.distance === "number" && Number.isFinite(values.distance)) {
7517
7598
  light.distance = Math.max(MIN_LIGHT_DISTANCE, values.distance);
7518
7599
  }
@@ -7526,7 +7607,7 @@ function applyLightValues(lightComponent) {
7526
7607
  light.penumbra = Math.max(0, Math.min(1, values.penumbra));
7527
7608
  }
7528
7609
  }
7529
- if (light instanceof THREE35__namespace.RectAreaLight) {
7610
+ if (light instanceof THREE36__namespace.RectAreaLight) {
7530
7611
  if (typeof values.width === "number" && Number.isFinite(values.width)) {
7531
7612
  light.width = Math.max(MIN_AREA_SIZE, values.width);
7532
7613
  }
@@ -7587,15 +7668,15 @@ function resolveMaterialPropertyKey(key) {
7587
7668
  __name(resolveMaterialPropertyKey, "resolveMaterialPropertyKey");
7588
7669
  function createMaterialByType(type) {
7589
7670
  if (type === "basic") {
7590
- return new THREE35__namespace.MeshBasicMaterial();
7671
+ return new THREE36__namespace.MeshBasicMaterial();
7591
7672
  }
7592
7673
  if (type === "phong") {
7593
- return new THREE35__namespace.MeshPhongMaterial();
7674
+ return new THREE36__namespace.MeshPhongMaterial();
7594
7675
  }
7595
7676
  if (type === "physical") {
7596
- return new THREE35__namespace.MeshPhysicalMaterial();
7677
+ return new THREE36__namespace.MeshPhysicalMaterial();
7597
7678
  }
7598
- return new THREE35__namespace.MeshStandardMaterial();
7679
+ return new THREE36__namespace.MeshStandardMaterial();
7599
7680
  }
7600
7681
  __name(createMaterialByType, "createMaterialByType");
7601
7682
  function replaceMaterialAcrossObject(object, previous, next) {
@@ -7654,12 +7735,12 @@ function applyTextureFiltering(material, filtering) {
7654
7735
  const target = material;
7655
7736
  for (const slot of materialTextureSlots) {
7656
7737
  const texture = target[slot];
7657
- if (!texture || !(texture instanceof THREE35__namespace.Texture)) {
7738
+ if (!texture || !(texture instanceof THREE36__namespace.Texture)) {
7658
7739
  continue;
7659
7740
  }
7660
7741
  const useMipmaps = texture.generateMipmaps !== false;
7661
- texture.magFilter = sharp ? THREE35__namespace.NearestFilter : THREE35__namespace.LinearFilter;
7662
- texture.minFilter = useMipmaps ? sharp ? THREE35__namespace.NearestMipmapNearestFilter : THREE35__namespace.LinearMipmapLinearFilter : sharp ? THREE35__namespace.NearestFilter : THREE35__namespace.LinearFilter;
7742
+ texture.magFilter = sharp ? THREE36__namespace.NearestFilter : THREE36__namespace.LinearFilter;
7743
+ texture.minFilter = useMipmaps ? sharp ? THREE36__namespace.NearestMipmapNearestFilter : THREE36__namespace.LinearMipmapLinearFilter : sharp ? THREE36__namespace.NearestFilter : THREE36__namespace.LinearFilter;
7663
7744
  texture.needsUpdate = true;
7664
7745
  }
7665
7746
  material.needsUpdate = true;
@@ -7669,12 +7750,12 @@ function setTextureMipmaps(material, enabled) {
7669
7750
  const target = material;
7670
7751
  for (const slot of materialTextureSlots) {
7671
7752
  const texture = target[slot];
7672
- if (!texture || !(texture instanceof THREE35__namespace.Texture)) {
7753
+ if (!texture || !(texture instanceof THREE36__namespace.Texture)) {
7673
7754
  continue;
7674
7755
  }
7675
7756
  texture.generateMipmaps = enabled;
7676
- const sharp = texture.magFilter === THREE35__namespace.NearestFilter;
7677
- texture.minFilter = enabled ? sharp ? THREE35__namespace.NearestMipmapNearestFilter : THREE35__namespace.LinearMipmapLinearFilter : sharp ? THREE35__namespace.NearestFilter : THREE35__namespace.LinearFilter;
7757
+ const sharp = texture.magFilter === THREE36__namespace.NearestFilter;
7758
+ texture.minFilter = enabled ? sharp ? THREE36__namespace.NearestMipmapNearestFilter : THREE36__namespace.LinearMipmapLinearFilter : sharp ? THREE36__namespace.NearestFilter : THREE36__namespace.LinearFilter;
7678
7759
  texture.needsUpdate = true;
7679
7760
  }
7680
7761
  material.needsUpdate = true;
@@ -7685,7 +7766,7 @@ function assignMaterialTexture(material, rawKey, url, textureCache) {
7685
7766
  const key = resolveMaterialPropertyKey(rawKey);
7686
7767
  let texture = textureCache.get(url);
7687
7768
  if (!texture) {
7688
- texture = new THREE35__namespace.TextureLoader().load(url);
7769
+ texture = new THREE36__namespace.TextureLoader().load(url);
7689
7770
  textureCache.set(url, texture);
7690
7771
  }
7691
7772
  target[key] = texture;
@@ -7883,12 +7964,12 @@ function resolvePrimaryMesh(object) {
7883
7964
  if (!object) {
7884
7965
  return null;
7885
7966
  }
7886
- if (object instanceof THREE35__namespace.Mesh) {
7967
+ if (object instanceof THREE36__namespace.Mesh) {
7887
7968
  return object;
7888
7969
  }
7889
7970
  let found = null;
7890
7971
  object.traverse((child) => {
7891
- if (!found && child instanceof THREE35__namespace.Mesh) {
7972
+ if (!found && child instanceof THREE36__namespace.Mesh) {
7892
7973
  found = child;
7893
7974
  }
7894
7975
  });
@@ -7909,22 +7990,22 @@ function applyGeometry(component) {
7909
7990
  switch (component.kind) {
7910
7991
  case "cube": {
7911
7992
  const params = sanitized;
7912
- nextGeometry = new THREE35__namespace.BoxGeometry(params.width, params.height, params.depth);
7993
+ nextGeometry = new THREE36__namespace.BoxGeometry(params.width, params.height, params.depth);
7913
7994
  break;
7914
7995
  }
7915
7996
  case "plane": {
7916
7997
  const params = sanitized;
7917
- nextGeometry = new THREE35__namespace.PlaneGeometry(params.width, params.height);
7998
+ nextGeometry = new THREE36__namespace.PlaneGeometry(params.width, params.height);
7918
7999
  break;
7919
8000
  }
7920
8001
  case "sphere": {
7921
8002
  const params = sanitized;
7922
- nextGeometry = new THREE35__namespace.SphereGeometry(params.radius, 24, 24);
8003
+ nextGeometry = new THREE36__namespace.SphereGeometry(params.radius, 24, 24);
7923
8004
  break;
7924
8005
  }
7925
8006
  case "cylinder": {
7926
8007
  const params = sanitized;
7927
- nextGeometry = new THREE35__namespace.CylinderGeometry(
8008
+ nextGeometry = new THREE36__namespace.CylinderGeometry(
7928
8009
  params.radius,
7929
8010
  params.radius,
7930
8011
  params.height,
@@ -7934,7 +8015,7 @@ function applyGeometry(component) {
7934
8015
  }
7935
8016
  case "capsule": {
7936
8017
  const params = sanitized;
7937
- nextGeometry = new THREE35__namespace.CapsuleGeometry(params.radius, params.height, 4, 8);
8018
+ nextGeometry = new THREE36__namespace.CapsuleGeometry(params.radius, params.height, 4, 8);
7938
8019
  break;
7939
8020
  }
7940
8021
  default:
@@ -7950,7 +8031,7 @@ function applyShadowFlags(component) {
7950
8031
  return;
7951
8032
  }
7952
8033
  component.object.traverse((child) => {
7953
- if (child instanceof THREE35__namespace.Mesh) {
8034
+ if (child instanceof THREE36__namespace.Mesh) {
7954
8035
  child.castShadow = component.castShadow;
7955
8036
  child.receiveShadow = component.receiveShadow;
7956
8037
  }
@@ -8033,35 +8114,35 @@ function buildGeometry(component) {
8033
8114
  switch (component.meshKind) {
8034
8115
  case "cube": {
8035
8116
  const params = p;
8036
- return new THREE35__namespace.BoxGeometry(params.width, params.height, params.depth);
8117
+ return new THREE36__namespace.BoxGeometry(params.width, params.height, params.depth);
8037
8118
  }
8038
8119
  case "plane": {
8039
8120
  const params = p;
8040
- return new THREE35__namespace.PlaneGeometry(params.width, params.height);
8121
+ return new THREE36__namespace.PlaneGeometry(params.width, params.height);
8041
8122
  }
8042
8123
  case "sphere": {
8043
8124
  const params = p;
8044
- return new THREE35__namespace.SphereGeometry(params.radius, 24, 24);
8125
+ return new THREE36__namespace.SphereGeometry(params.radius, 24, 24);
8045
8126
  }
8046
8127
  case "cylinder": {
8047
8128
  const params = p;
8048
- return new THREE35__namespace.CylinderGeometry(params.radius, params.radius, params.height, 20);
8129
+ return new THREE36__namespace.CylinderGeometry(params.radius, params.radius, params.height, 20);
8049
8130
  }
8050
8131
  case "capsule": {
8051
8132
  const params = p;
8052
- return new THREE35__namespace.CapsuleGeometry(params.radius, params.height, 4, 8);
8133
+ return new THREE36__namespace.CapsuleGeometry(params.radius, params.height, 4, 8);
8053
8134
  }
8054
8135
  default:
8055
- return new THREE35__namespace.BoxGeometry(1, 1, 1);
8136
+ return new THREE36__namespace.BoxGeometry(1, 1, 1);
8056
8137
  }
8057
8138
  }
8058
8139
  __name(buildGeometry, "buildGeometry");
8059
- var _position = new THREE35__namespace.Vector3();
8060
- var _quaternion = new THREE35__namespace.Quaternion();
8061
- var _euler = new THREE35__namespace.Euler();
8062
- var _scale = new THREE35__namespace.Vector3();
8063
- var _matrix = new THREE35__namespace.Matrix4();
8064
- var _modelMatrix = new THREE35__namespace.Matrix4();
8140
+ var _position = new THREE36__namespace.Vector3();
8141
+ var _quaternion = new THREE36__namespace.Quaternion();
8142
+ var _euler = new THREE36__namespace.Euler();
8143
+ var _scale = new THREE36__namespace.Vector3();
8144
+ var _matrix = new THREE36__namespace.Matrix4();
8145
+ var _modelMatrix = new THREE36__namespace.Matrix4();
8065
8146
  function instanceTransformFromComponent(transform, out) {
8066
8147
  _position.set(transform.position.x, transform.position.y, transform.position.z);
8067
8148
  _euler.set(transform.rotation.x, transform.rotation.y, transform.rotation.z, "XYZ");
@@ -8214,7 +8295,7 @@ var _InstancedMeshSystem = class _InstancedMeshSystem {
8214
8295
  const sourceMaterial = Array.isArray(meshChild.material) ? meshChild.material.map((m) => m.clone()) : meshChild.material.clone();
8215
8296
  meshChild.updateWorldMatrix(true, false);
8216
8297
  const localMatrix = meshChild.matrixWorld.clone();
8217
- const instancedMesh2 = new THREE35__namespace.InstancedMesh(
8298
+ const instancedMesh2 = new THREE36__namespace.InstancedMesh(
8218
8299
  geometry2,
8219
8300
  Array.isArray(sourceMaterial) ? sourceMaterial : sourceMaterial,
8220
8301
  count2
@@ -8239,7 +8320,7 @@ var _InstancedMeshSystem = class _InstancedMeshSystem {
8239
8320
  this.loadingSignatures.delete(targetEntityId);
8240
8321
  return;
8241
8322
  }
8242
- const group = new THREE35__namespace.Group();
8323
+ const group = new THREE36__namespace.Group();
8243
8324
  for (const entry of entries) {
8244
8325
  group.add(entry.instancedMesh);
8245
8326
  }
@@ -8257,8 +8338,8 @@ var _InstancedMeshSystem = class _InstancedMeshSystem {
8257
8338
  }
8258
8339
  const count = instanceCount;
8259
8340
  const geometry = buildGeometry(comp);
8260
- const material = new THREE35__namespace.MeshStandardMaterial({ color: "#ffffff" });
8261
- const instancedMesh = new THREE35__namespace.InstancedMesh(geometry, material, count);
8341
+ const material = new THREE36__namespace.MeshStandardMaterial({ color: "#ffffff" });
8342
+ const instancedMesh = new THREE36__namespace.InstancedMesh(geometry, material, count);
8262
8343
  instancedMesh.castShadow = comp.castShadow;
8263
8344
  instancedMesh.receiveShadow = comp.receiveShadow;
8264
8345
  for (let i = 0; i < count; i++) {
@@ -8441,7 +8522,7 @@ var _Behaviour = class _Behaviour {
8441
8522
  if (!this.threeRef) {
8442
8523
  return null;
8443
8524
  }
8444
- const position = new THREE35__namespace.Vector3();
8525
+ const position = new THREE36__namespace.Vector3();
8445
8526
  this.threeRef.object.getWorldPosition(position);
8446
8527
  return position;
8447
8528
  }
@@ -8453,7 +8534,7 @@ var _Behaviour = class _Behaviour {
8453
8534
  if (!this.threeRef) {
8454
8535
  return null;
8455
8536
  }
8456
- const target = new THREE35__namespace.Vector3();
8537
+ const target = new THREE36__namespace.Vector3();
8457
8538
  this.threeRef.object.getWorldDirection(target);
8458
8539
  return target;
8459
8540
  }
@@ -8515,7 +8596,7 @@ var _Behaviour = class _Behaviour {
8515
8596
  if (!this.threeRef) {
8516
8597
  return;
8517
8598
  }
8518
- const rotation = new THREE35__namespace.Quaternion();
8599
+ const rotation = new THREE36__namespace.Quaternion();
8519
8600
  this.threeRef.object.getWorldQuaternion(rotation);
8520
8601
  rotation.slerp(targetRotation, alpha);
8521
8602
  this.transform.setRotation(rotation);
@@ -8532,7 +8613,7 @@ var _Behaviour = class _Behaviour {
8532
8613
  return;
8533
8614
  }
8534
8615
  const clone3 = this.threeRef.object.clone();
8535
- const rotation = new THREE35__namespace.Quaternion();
8616
+ const rotation = new THREE36__namespace.Quaternion();
8536
8617
  clone3.lookAt(targetPosition);
8537
8618
  clone3.getWorldQuaternion(rotation);
8538
8619
  this.transform.setRotation(rotation);
@@ -8599,22 +8680,14 @@ var _Behaviour = class _Behaviour {
8599
8680
  /**
8600
8681
  * Called once before the first {@link Behaviour.onUpdate}. Override to
8601
8682
  * default and validate {@link Behaviour.data}, cache references, or set
8602
- * initial state.
8603
- *
8604
- * @remarks
8605
- * Also called in editor mode when `executeInEditor` is `true` on the script
8606
- * entry.
8683
+ * initial state. Runs at preview/runtime only — never in the editor.
8607
8684
  */
8608
8685
  init() {
8609
8686
  }
8610
8687
  /**
8611
8688
  * Called every frame while the script is enabled. Override with the
8612
- * script's main per-frame logic.
8613
- *
8614
- * @remarks
8615
- * Also called every frame in editor mode when `executeInEditor` is `true`.
8616
- * Access the Three.js scene with `this.world.getScene()` for editor-only
8617
- * rendering work such as custom shaders or procedural geometry.
8689
+ * script's main per-frame logic. Runs at preview/runtime only — never in the
8690
+ * editor (use {@link ScriptObject} for editor-visible visuals).
8618
8691
  */
8619
8692
  onUpdate() {
8620
8693
  }
@@ -8653,7 +8726,14 @@ __name(_Behaviour, "Behaviour");
8653
8726
  _Behaviour.__reluBehaviourClass = true;
8654
8727
  var Behaviour = _Behaviour;
8655
8728
 
8656
- // core/systems/ScriptBehaviourSystem.ts
8729
+ // core/systems/scriptShared.ts
8730
+ async function defaultModuleLoader(scriptUrl) {
8731
+ return await import(
8732
+ /* webpackIgnore: true */
8733
+ scriptUrl
8734
+ );
8735
+ }
8736
+ __name(defaultModuleLoader, "defaultModuleLoader");
8657
8737
  function toErrorMessage(error) {
8658
8738
  const sanitize = /* @__PURE__ */ __name((value) => value.replace(/localasset:\/\/[^/]+\//g, "localasset://").replace(/\/Users\/[^\s)]+/g, "[local path]"), "sanitize");
8659
8739
  if (error instanceof Error && error.message) {
@@ -8665,26 +8745,22 @@ function toErrorMessage(error) {
8665
8745
  return "Unknown script error.";
8666
8746
  }
8667
8747
  __name(toErrorMessage, "toErrorMessage");
8668
- function buildInstanceKey(entityId, scriptUrl, className) {
8669
- return `${entityId}:${scriptUrl}:${className}`;
8670
- }
8671
- __name(buildInstanceKey, "buildInstanceKey");
8672
- function resolveBehaviourCtor(moduleValue, className) {
8748
+ function resolveScriptCtor(moduleValue, className, options) {
8673
8749
  const named = moduleValue[className];
8674
8750
  const fallback = moduleValue.default;
8675
8751
  const candidate = typeof named === "function" ? named : typeof fallback === "function" ? fallback : null;
8676
8752
  if (!candidate) {
8677
8753
  return null;
8678
8754
  }
8679
- if (!(candidate.prototype instanceof Behaviour)) {
8680
- const isBehaviourSubclass = !!candidate.__reluBehaviourClass;
8681
- if (!isBehaviourSubclass) {
8755
+ if (!(candidate.prototype instanceof options.baseClass)) {
8756
+ const marker = candidate[options.markerKey];
8757
+ if (!marker) {
8682
8758
  return null;
8683
8759
  }
8684
8760
  }
8685
8761
  return candidate;
8686
8762
  }
8687
- __name(resolveBehaviourCtor, "resolveBehaviourCtor");
8763
+ __name(resolveScriptCtor, "resolveScriptCtor");
8688
8764
  function normalizeScriptData(value) {
8689
8765
  return value && typeof value === "object" && !Array.isArray(value) ? value : {};
8690
8766
  }
@@ -8766,8 +8842,8 @@ function resolveInputData(world, rawData) {
8766
8842
  return resolved;
8767
8843
  }
8768
8844
  __name(resolveInputData, "resolveInputData");
8769
- function serializeDataForStorage(rawData, behaviourData) {
8770
- const result = { ...behaviourData };
8845
+ function serializeDataForStorage(rawData, instanceData) {
8846
+ const result = { ...instanceData };
8771
8847
  for (const [key, rawValue] of Object.entries(rawData)) {
8772
8848
  if (isRawEntityInput(rawValue) || isRawComponentInput(rawValue)) {
8773
8849
  result[key] = rawValue;
@@ -8776,13 +8852,25 @@ function serializeDataForStorage(rawData, behaviourData) {
8776
8852
  return result;
8777
8853
  }
8778
8854
  __name(serializeDataForStorage, "serializeDataForStorage");
8855
+
8856
+ // core/systems/ScriptBehaviourSystem.ts
8857
+ function buildInstanceKey(entityId, scriptUrl, className) {
8858
+ return `${entityId}:${scriptUrl}:${className}`;
8859
+ }
8860
+ __name(buildInstanceKey, "buildInstanceKey");
8861
+ function resolveBehaviourCtor(moduleValue, className) {
8862
+ return resolveScriptCtor(moduleValue, className, {
8863
+ baseClass: Behaviour,
8864
+ markerKey: "__reluBehaviourClass"
8865
+ });
8866
+ }
8867
+ __name(resolveBehaviourCtor, "resolveBehaviourCtor");
8779
8868
  function normalizeEntry(value, fallbackEntityId) {
8780
8869
  return {
8781
8870
  entityId: typeof value?.entityId === "number" ? value.entityId : fallbackEntityId,
8782
8871
  className: typeof value?.className === "string" ? value.className : "",
8783
8872
  scriptUrl: typeof value?.scriptUrl === "string" ? value.scriptUrl : "",
8784
8873
  enabled: typeof value?.enabled === "boolean" ? value.enabled : true,
8785
- executeInEditor: typeof value?.executeInEditor === "boolean" ? value.executeInEditor : false,
8786
8874
  data: normalizeScriptData(value?.data),
8787
8875
  runtimeState: value?.runtimeState === "idle" || value?.runtimeState === "loading" || value?.runtimeState === "ready" || value?.runtimeState === "error" ? value.runtimeState : void 0,
8788
8876
  runtimeMessage: typeof value?.runtimeMessage === "string" ? value.runtimeMessage : void 0
@@ -8805,13 +8893,6 @@ function writeScriptEntries(component, entries) {
8805
8893
  }
8806
8894
  }
8807
8895
  __name(writeScriptEntries, "writeScriptEntries");
8808
- async function defaultModuleLoader(scriptUrl) {
8809
- return await import(
8810
- /* webpackIgnore: true */
8811
- scriptUrl
8812
- );
8813
- }
8814
- __name(defaultModuleLoader, "defaultModuleLoader");
8815
8896
  var _ScriptBehaviourSystem = class _ScriptBehaviourSystem {
8816
8897
  constructor(moduleLoader, selectionContext) {
8817
8898
  this.instances = /* @__PURE__ */ new Map();
@@ -8833,8 +8914,8 @@ var _ScriptBehaviourSystem = class _ScriptBehaviourSystem {
8833
8914
  }, "onPointerUp");
8834
8915
  this.moduleLoader = moduleLoader ?? defaultModuleLoader;
8835
8916
  this.selectionCtx = selectionContext ?? null;
8836
- this.raycaster = new THREE35__namespace.Raycaster();
8837
- this.ndcPointer = new THREE35__namespace.Vector2();
8917
+ this.raycaster = new THREE36__namespace.Raycaster();
8918
+ this.ndcPointer = new THREE36__namespace.Vector2();
8838
8919
  if (this.selectionCtx) {
8839
8920
  this.selectionCtx.domElement.addEventListener("pointerdown", this.onPointerDown);
8840
8921
  this.selectionCtx.domElement.addEventListener("pointerup", this.onPointerUp);
@@ -8927,11 +9008,11 @@ var _ScriptBehaviourSystem = class _ScriptBehaviourSystem {
8927
9008
  let hasEnabledScript = false;
8928
9009
  for (let entryIndex = 0; entryIndex < nextEntries.length; entryIndex += 1) {
8929
9010
  const entry = nextEntries[entryIndex];
8930
- const skipInEditor = world.isEditorMode() && !entry.executeInEditor;
9011
+ const skipInEditor = world.isEditorMode();
8931
9012
  if (!entry.enabled || !entry.scriptUrl || skipInEditor) {
8932
9013
  nextEntries[entryIndex] = {
8933
9014
  ...entry,
8934
- runtimeState: skipInEditor ? "idle" : "idle",
9015
+ runtimeState: "idle",
8935
9016
  runtimeMessage: void 0
8936
9017
  };
8937
9018
  continue;
@@ -9118,7 +9199,7 @@ var _ScriptBehaviourSystem = class _ScriptBehaviourSystem {
9118
9199
  const mergedData = mergeDataByCurrentDefaults(defaults, currentData);
9119
9200
  const resolvedData = resolveInputData(world, mergedData);
9120
9201
  behaviour.data = resolvedData;
9121
- if (!world.isEditorMode() || liveEntry.executeInEditor === true) {
9202
+ if (!world.isEditorMode()) {
9122
9203
  behaviour.init();
9123
9204
  }
9124
9205
  liveEntries[entryIndex] = {
@@ -9146,6 +9227,335 @@ __name(_ScriptBehaviourSystem, "ScriptBehaviourSystem");
9146
9227
  _ScriptBehaviourSystem.CLICK_THRESHOLD = 6;
9147
9228
  var ScriptBehaviourSystem = _ScriptBehaviourSystem;
9148
9229
 
9230
+ // core/ScriptObject.ts
9231
+ var _ScriptObject = class _ScriptObject {
9232
+ /**
9233
+ * Engine-managed constructor. `ScriptObjectSystem` instantiates subclasses
9234
+ * with the owning world, the entity id, and the component's `data`. User code
9235
+ * should not call this directly.
9236
+ */
9237
+ constructor(world, entityId, data) {
9238
+ /**
9239
+ * The script's data payload (the `ScriptObjectComponent.data`). Declare a
9240
+ * concrete shape on subclasses with `declare data: MyShape` for type safety.
9241
+ * Use the same typed input envelopes as Behaviours (`ColorInput`,
9242
+ * `SliderInput`, `EntityInput`, …) to get inspector fields.
9243
+ */
9244
+ this.data = {};
9245
+ /**
9246
+ * The Object3D returned by {@link ScriptObject.build}. Assigned by
9247
+ * `ScriptObjectSystem` after `build()` runs; `null` until then.
9248
+ */
9249
+ this.root = null;
9250
+ this.world = world;
9251
+ this.entityId = entityId;
9252
+ if (data) this.data = data;
9253
+ }
9254
+ /**
9255
+ * REQUIRED — build and return the visual root. Called once by
9256
+ * `ScriptObjectSystem` after construction. The returned object is attached
9257
+ * under the entity's Object3D (so it inherits the entity transform, selection
9258
+ * and visibility). Subclasses MUST override.
9259
+ */
9260
+ build() {
9261
+ throw new Error("ScriptObject subclasses must implement build()");
9262
+ }
9263
+ };
9264
+ __name(_ScriptObject, "ScriptObject");
9265
+ /**
9266
+ * Static marker used by `ScriptObjectSystem` to detect `ScriptObject`
9267
+ * subclasses even when a bundler ships a second copy of the package into the
9268
+ * script blob (breaking `instanceof`). Do NOT override.
9269
+ */
9270
+ _ScriptObject.__reluScriptObjectClass = true;
9271
+ var ScriptObject = _ScriptObject;
9272
+
9273
+ // core/systems/ScriptObjectSystem.ts
9274
+ var SCRIPT_OBJECT_ROOT_FLAG = "__scriptObjectRoot";
9275
+ function setInstanceRef(component, value) {
9276
+ Object.defineProperty(component, "instance", {
9277
+ value,
9278
+ writable: true,
9279
+ configurable: true,
9280
+ enumerable: false
9281
+ });
9282
+ }
9283
+ __name(setInstanceRef, "setInstanceRef");
9284
+ function disposeBuiltObject(root) {
9285
+ root.parent?.remove(root);
9286
+ root.traverse((node) => {
9287
+ const mesh = node;
9288
+ const geometry = mesh.geometry;
9289
+ if (geometry?.dispose && !geometry.userData?.[SHARED_MODEL_RESOURCE_FLAG]) {
9290
+ geometry.dispose();
9291
+ }
9292
+ const material = mesh.material;
9293
+ const materials = Array.isArray(material) ? material : material ? [material] : [];
9294
+ for (const mat of materials) {
9295
+ if (mat.userData?.[SHARED_MODEL_RESOURCE_FLAG]) continue;
9296
+ for (const value of Object.values(mat)) {
9297
+ if (value instanceof THREE36__namespace.Texture) value.dispose();
9298
+ }
9299
+ mat.dispose?.();
9300
+ }
9301
+ });
9302
+ }
9303
+ __name(disposeBuiltObject, "disposeBuiltObject");
9304
+ var _ScriptObjectSystem = class _ScriptObjectSystem {
9305
+ constructor(moduleLoader) {
9306
+ this.instances = /* @__PURE__ */ new Map();
9307
+ this.loading = /* @__PURE__ */ new Map();
9308
+ /** Bumped by invalidate*() so in-flight loads that predate it are discarded. */
9309
+ this.epoch = 0;
9310
+ this.moduleLoader = moduleLoader ?? defaultModuleLoader;
9311
+ }
9312
+ update(world, deltaTime) {
9313
+ const active = /* @__PURE__ */ new Map();
9314
+ for (const entityId of world.query(ScriptObjectComponent)) {
9315
+ const component = world.getComponent(entityId, ScriptObjectComponent);
9316
+ if (!component) continue;
9317
+ const wantsRun = component.enabled && typeof component.scriptUrl === "string" && typeof component.className === "string";
9318
+ if (!wantsRun) {
9319
+ const record = this.instances.get(entityId);
9320
+ if (record) this.teardownRecord(world, entityId, record, false);
9321
+ this.loading.delete(entityId);
9322
+ if (component.runtimeState !== "idle") {
9323
+ component.runtimeState = "idle";
9324
+ component.runtimeMessage = void 0;
9325
+ }
9326
+ continue;
9327
+ }
9328
+ active.set(entityId, component);
9329
+ }
9330
+ for (const [entityId, record] of this.instances) {
9331
+ const component = active.get(entityId);
9332
+ const identityChanged = !component || record.scriptUrl !== component.scriptUrl || record.className !== component.className;
9333
+ if (!world.hasEntity(entityId) || identityChanged) {
9334
+ this.teardownRecord(world, entityId, record, false);
9335
+ }
9336
+ }
9337
+ for (const [entityId, component] of active) {
9338
+ const record = this.instances.get(entityId);
9339
+ if (!record || record.status !== "ready" || !record.instance) continue;
9340
+ if (!world.isEntityVisible(entityId)) continue;
9341
+ if (component.data !== record.lastWrittenData) {
9342
+ try {
9343
+ const merged = mergeDataByCurrentDefaults(
9344
+ record.rawData,
9345
+ normalizeScriptData(component.data)
9346
+ );
9347
+ record.rawData = merged;
9348
+ record.instance.data = resolveInputData(world, merged);
9349
+ const stored = serializeDataForStorage(merged, merged);
9350
+ component.data = stored;
9351
+ record.lastWrittenData = stored;
9352
+ } catch (error) {
9353
+ this.markError(world, entityId, component, error);
9354
+ continue;
9355
+ }
9356
+ }
9357
+ try {
9358
+ record.instance.update?.(deltaTime);
9359
+ } catch (error) {
9360
+ this.markError(world, entityId, component, error);
9361
+ }
9362
+ }
9363
+ for (const [entityId, component] of active) {
9364
+ if (this.instances.has(entityId) || this.loading.has(entityId)) continue;
9365
+ const scriptUrl = component.scriptUrl;
9366
+ const className = component.className;
9367
+ if (component.runtimeState !== "loading") {
9368
+ component.runtimeState = "loading";
9369
+ component.runtimeMessage = void 0;
9370
+ }
9371
+ const epochAtStart = this.epoch;
9372
+ const key = `${epochAtStart}:${scriptUrl}:${className}`;
9373
+ const promise = this.loadScriptObject(
9374
+ world,
9375
+ entityId,
9376
+ scriptUrl,
9377
+ className,
9378
+ key,
9379
+ epochAtStart
9380
+ ).catch((error) => {
9381
+ this.markError(world, entityId, void 0, error);
9382
+ console.error(
9383
+ `[ScriptObjectSystem] Failed loading ${className} (${scriptUrl})`,
9384
+ error
9385
+ );
9386
+ }).finally(() => {
9387
+ if (this.loading.get(entityId)?.key === key) {
9388
+ this.loading.delete(entityId);
9389
+ }
9390
+ });
9391
+ this.loading.set(entityId, { key, promise });
9392
+ }
9393
+ for (const entityId of this.loading.keys()) {
9394
+ if (!active.has(entityId)) this.loading.delete(entityId);
9395
+ }
9396
+ }
9397
+ async loadScriptObject(world, entityId, scriptUrl, className, key, epochAtStart) {
9398
+ const moduleValue = await this.moduleLoader(scriptUrl);
9399
+ if (this.loading.get(entityId)?.key !== key || epochAtStart !== this.epoch || !world.hasEntity(entityId)) {
9400
+ return;
9401
+ }
9402
+ const component = world.getComponent(entityId, ScriptObjectComponent);
9403
+ if (!component || !component.enabled || component.scriptUrl !== scriptUrl || component.className !== className) {
9404
+ return;
9405
+ }
9406
+ const ctor = resolveScriptCtor(moduleValue, className, {
9407
+ baseClass: ScriptObject,
9408
+ markerKey: "__reluScriptObjectClass"
9409
+ });
9410
+ if (!ctor) {
9411
+ throw new Error(
9412
+ `Missing ScriptObject export '${className}' in ${scriptUrl}`
9413
+ );
9414
+ }
9415
+ const currentData = normalizeScriptData(component.data);
9416
+ let instance;
9417
+ try {
9418
+ instance = new ctor(world, entityId, void 0);
9419
+ } catch {
9420
+ instance = new ctor(world, entityId, currentData);
9421
+ }
9422
+ const literalDefaults = normalizeScriptData(instance.data);
9423
+ const seed = Object.keys(literalDefaults).length > 0 ? mergeDataByCurrentDefaults(literalDefaults, currentData) : { ...currentData };
9424
+ instance.data = resolveInputData(world, seed);
9425
+ const parent = world.getComponent(entityId, Object3DRef)?.object;
9426
+ if (!parent) {
9427
+ throw new Error("Script object entity has no Object3D to attach to.");
9428
+ }
9429
+ for (const child of [...parent.children]) {
9430
+ if (child.userData?.[SCRIPT_OBJECT_ROOT_FLAG]) {
9431
+ disposeBuiltObject(child);
9432
+ }
9433
+ }
9434
+ let built;
9435
+ try {
9436
+ built = instance.build();
9437
+ } catch (error) {
9438
+ try {
9439
+ instance.dispose?.();
9440
+ } catch {
9441
+ }
9442
+ throw error;
9443
+ }
9444
+ if (!built || built.isObject3D !== true) {
9445
+ try {
9446
+ instance.dispose?.();
9447
+ } catch {
9448
+ }
9449
+ throw new Error("build() must return a THREE.Object3D.");
9450
+ }
9451
+ built.userData[SCRIPT_OBJECT_ROOT_FLAG] = true;
9452
+ parent.add(built);
9453
+ instance.root = built;
9454
+ const postBuildData = normalizeScriptData(instance.data);
9455
+ const schemaDefaults = { ...literalDefaults };
9456
+ for (const [key2, value] of Object.entries(postBuildData)) {
9457
+ if (!(key2 in schemaDefaults)) schemaDefaults[key2] = value;
9458
+ }
9459
+ const merged = mergeDataByCurrentDefaults(schemaDefaults, currentData);
9460
+ instance.data = resolveInputData(world, merged);
9461
+ const stored = serializeDataForStorage(merged, merged);
9462
+ component.data = stored;
9463
+ component.runtimeState = "ready";
9464
+ component.runtimeMessage = void 0;
9465
+ setInstanceRef(component, instance);
9466
+ this.instances.set(entityId, {
9467
+ entityId,
9468
+ scriptUrl,
9469
+ className,
9470
+ status: "ready",
9471
+ instance,
9472
+ root: built,
9473
+ rawData: merged,
9474
+ lastWrittenData: stored
9475
+ });
9476
+ }
9477
+ /** Dispose a record's instance + built subtree. `keepTombstone` leaves an error marker. */
9478
+ teardownRecord(world, entityId, record, keepTombstone) {
9479
+ try {
9480
+ record.instance?.dispose?.();
9481
+ } catch {
9482
+ }
9483
+ if (record.root) disposeBuiltObject(record.root);
9484
+ const component = world.getComponent(entityId, ScriptObjectComponent);
9485
+ if (component) setInstanceRef(component, null);
9486
+ if (keepTombstone) {
9487
+ this.instances.set(entityId, {
9488
+ ...record,
9489
+ status: "error",
9490
+ instance: null,
9491
+ root: null
9492
+ });
9493
+ } else {
9494
+ this.instances.delete(entityId);
9495
+ }
9496
+ }
9497
+ markError(world, entityId, component, error) {
9498
+ const comp = component ?? world.getComponent(entityId, ScriptObjectComponent) ?? null;
9499
+ if (comp) {
9500
+ comp.runtimeState = "error";
9501
+ comp.runtimeMessage = toErrorMessage(error);
9502
+ }
9503
+ const record = this.instances.get(entityId);
9504
+ if (record) {
9505
+ this.teardownRecord(world, entityId, record, true);
9506
+ } else {
9507
+ this.instances.set(entityId, {
9508
+ entityId,
9509
+ scriptUrl: comp?.scriptUrl ?? "",
9510
+ className: comp?.className ?? "",
9511
+ status: "error",
9512
+ instance: null,
9513
+ root: null,
9514
+ rawData: {},
9515
+ lastWrittenData: null
9516
+ });
9517
+ }
9518
+ }
9519
+ /** Dispose all live instances so the next update() reloads with fresh modules. */
9520
+ invalidateAll() {
9521
+ this.epoch += 1;
9522
+ for (const [entityId, record] of [...this.instances]) {
9523
+ try {
9524
+ record.instance?.dispose?.();
9525
+ } catch {
9526
+ }
9527
+ if (record.root) disposeBuiltObject(record.root);
9528
+ this.instances.delete(entityId);
9529
+ }
9530
+ this.loading.clear();
9531
+ }
9532
+ /** Invalidate only the entities whose script matches `scriptUrl`. */
9533
+ invalidate(scriptUrl) {
9534
+ this.epoch += 1;
9535
+ for (const [entityId, record] of [...this.instances]) {
9536
+ if (record.scriptUrl !== scriptUrl) continue;
9537
+ try {
9538
+ record.instance?.dispose?.();
9539
+ } catch {
9540
+ }
9541
+ if (record.root) disposeBuiltObject(record.root);
9542
+ this.instances.delete(entityId);
9543
+ }
9544
+ for (const [entityId, entry] of [...this.loading]) {
9545
+ if (entry.key.includes(`:${scriptUrl}:`)) this.loading.delete(entityId);
9546
+ }
9547
+ }
9548
+ dispose(world) {
9549
+ for (const [entityId, record] of [...this.instances]) {
9550
+ this.teardownRecord(world, entityId, record, false);
9551
+ }
9552
+ this.instances.clear();
9553
+ this.loading.clear();
9554
+ }
9555
+ };
9556
+ __name(_ScriptObjectSystem, "ScriptObjectSystem");
9557
+ var ScriptObjectSystem = _ScriptObjectSystem;
9558
+
9149
9559
  // core/systems/TransformSyncSystem.ts
9150
9560
  var _TransformSyncSystem = class _TransformSyncSystem {
9151
9561
  update(world) {
@@ -9244,7 +9654,7 @@ var _AudioSystem = class _AudioSystem {
9244
9654
  if (!prev || prev.volume !== opts.volume) {
9245
9655
  sound.setVolume(opts.volume);
9246
9656
  }
9247
- if (opts.positional && sound instanceof THREE35__namespace.PositionalAudio) {
9657
+ if (opts.positional && sound instanceof THREE36__namespace.PositionalAudio) {
9248
9658
  if (!prev || prev.refDistance !== opts.refDistance) {
9249
9659
  sound.setRefDistance(opts.refDistance);
9250
9660
  }
@@ -9370,7 +9780,7 @@ var _VideoSystem = class _VideoSystem {
9370
9780
  component.object.scale.set(opts.width, opts.height, 1);
9371
9781
  }
9372
9782
  const material = component.material;
9373
- if (material instanceof THREE35__namespace.ShaderMaterial) {
9783
+ if (material instanceof THREE36__namespace.ShaderMaterial) {
9374
9784
  if (!prev || prev.backgroundColor !== opts.backgroundColor) {
9375
9785
  material.uniforms.keyColor.value.set(opts.backgroundColor);
9376
9786
  }
@@ -9384,7 +9794,7 @@ var _VideoSystem = class _VideoSystem {
9384
9794
  material.uniforms.spill.value = opts.spill;
9385
9795
  }
9386
9796
  }
9387
- if (opts.positional && component.audioNode instanceof THREE35__namespace.PositionalAudio) {
9797
+ if (opts.positional && component.audioNode instanceof THREE36__namespace.PositionalAudio) {
9388
9798
  const posAudio = component.audioNode;
9389
9799
  if (!prev || prev.refDistance !== opts.refDistance) {
9390
9800
  posAudio.setRefDistance(opts.refDistance);
@@ -10058,8 +10468,8 @@ var _World = class _World {
10058
10468
  * ```
10059
10469
  */
10060
10470
  raycast(origin, direction, near = 0, far = Infinity) {
10061
- const rayOrigin = new THREE35__namespace.Vector3(origin.x, origin.y, origin.z);
10062
- const rayDirection = new THREE35__namespace.Vector3(
10471
+ const rayOrigin = new THREE36__namespace.Vector3(origin.x, origin.y, origin.z);
10472
+ const rayDirection = new THREE36__namespace.Vector3(
10063
10473
  direction.x,
10064
10474
  direction.y,
10065
10475
  direction.z
@@ -10068,7 +10478,7 @@ var _World = class _World {
10068
10478
  return [];
10069
10479
  }
10070
10480
  rayDirection.normalize();
10071
- const raycaster = new THREE35__namespace.Raycaster(rayOrigin, rayDirection, near, far);
10481
+ const raycaster = new THREE36__namespace.Raycaster(rayOrigin, rayDirection, near, far);
10072
10482
  const intersections = raycaster.intersectObjects(
10073
10483
  this.scene.children,
10074
10484
  true
@@ -10102,14 +10512,14 @@ var _World = class _World {
10102
10512
  if (!sourceObject) {
10103
10513
  return [];
10104
10514
  }
10105
- const rayOrigin = new THREE35__namespace.Vector3();
10106
- const rayDirection = new THREE35__namespace.Vector3();
10515
+ const rayOrigin = new THREE36__namespace.Vector3();
10516
+ const rayDirection = new THREE36__namespace.Vector3();
10107
10517
  sourceObject.getWorldPosition(rayOrigin);
10108
10518
  sourceObject.getWorldDirection(rayDirection);
10109
10519
  if (rayDirection.lengthSq() === 0) {
10110
10520
  return [];
10111
10521
  }
10112
- const raycaster = new THREE35__namespace.Raycaster(rayOrigin, rayDirection, near, far);
10522
+ const raycaster = new THREE36__namespace.Raycaster(rayOrigin, rayDirection, near, far);
10113
10523
  const intersections = raycaster.intersectObjects(
10114
10524
  this.scene.children,
10115
10525
  true
@@ -10433,6 +10843,11 @@ function remapSnapshotEntityIds(snapshot, idMap, options) {
10433
10843
  };
10434
10844
  });
10435
10845
  }
10846
+ } else if (block.component === "ScriptObjectComponent" && record) {
10847
+ const data = asRecord6(record.data);
10848
+ if (data) {
10849
+ record.data = remapScriptData(data, idMap, nullExternal, warn);
10850
+ }
10436
10851
  } else if (block.component === "InstancedMeshComponent" && record) {
10437
10852
  if (Array.isArray(record.instanceEntityIds)) {
10438
10853
  const remapped = [];
@@ -10783,8 +11198,11 @@ exports.PREFAB_FILE_VERSION_NESTED = PREFAB_FILE_VERSION_NESTED;
10783
11198
  exports.PhysicsSyncSystem = PhysicsSyncSystem;
10784
11199
  exports.PostprocessingSyncSystem = PostprocessingSyncSystem;
10785
11200
  exports.RenderSystem = RenderSystem;
11201
+ exports.SCRIPT_OBJECT_ROOT_FLAG = SCRIPT_OBJECT_ROOT_FLAG;
10786
11202
  exports.SHARED_MODEL_RESOURCE_FLAG = SHARED_MODEL_RESOURCE_FLAG;
10787
11203
  exports.ScriptBehaviourSystem = ScriptBehaviourSystem;
11204
+ exports.ScriptObject = ScriptObject;
11205
+ exports.ScriptObjectSystem = ScriptObjectSystem;
10788
11206
  exports.TransformSyncSystem = TransformSyncSystem;
10789
11207
  exports.VideoSystem = VideoSystem;
10790
11208
  exports.World = World;
@@ -10821,6 +11239,7 @@ exports.createParentIdComponent = createParentIdComponent;
10821
11239
  exports.createPhysicsComponent = createPhysicsComponent;
10822
11240
  exports.createPostprocessingComponent = createPostprocessingComponent;
10823
11241
  exports.createScriptComponent = createScriptComponent;
11242
+ exports.createScriptObjectComponent = createScriptObjectComponent;
10824
11243
  exports.createSelectableComponent = createSelectableComponent;
10825
11244
  exports.createSelectionTransformStateComponent = createSelectionTransformStateComponent;
10826
11245
  exports.createSpriteComponent = createSpriteComponent;