cubeforge 0.6.3 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -66,7 +66,7 @@ import {
66
66
  } from "./chunk-UMHYQ4EP.js";
67
67
 
68
68
  // src/components/Game.tsx
69
- import { useEffect as useEffect11, useRef as useRef11, useState as useState3 } from "react";
69
+ import { useEffect as useEffect12, useRef as useRef12, useState as useState3 } from "react";
70
70
 
71
71
  // ../../packages/core/src/ecs/world.ts
72
72
  function applyDeltaSnapshot(baseline, delta) {
@@ -83,6 +83,20 @@ function applyDeltaSnapshot(baseline, delta) {
83
83
  }
84
84
  return { nextId: delta.nextId, rngState: delta.rngState, entities };
85
85
  }
86
+ function _componentsChanged(a, b) {
87
+ if (a.length !== b.length) return true;
88
+ for (let i = 0; i < a.length; i++) {
89
+ const ca = a[i];
90
+ const cb = b[i];
91
+ if (ca["type"] !== cb["type"]) return true;
92
+ const keysA = Object.keys(ca);
93
+ if (keysA.length !== Object.keys(cb).length) return true;
94
+ for (const k of keysA) {
95
+ if (ca[k] !== cb[k]) return true;
96
+ }
97
+ }
98
+ return false;
99
+ }
86
100
  var ECSWorld = class {
87
101
  nextId = 0;
88
102
  // Secondary index: O(1) single-entity component lookup
@@ -201,6 +215,23 @@ var ECSWorld = class {
201
215
  hasComponent(id, type) {
202
216
  return this.componentIndex.get(id)?.has(type) ?? false;
203
217
  }
218
+ /**
219
+ * Returns live references to all components on an entity.
220
+ * Useful for editor / inspector tooling. Returns an empty array if the
221
+ * entity does not exist.
222
+ *
223
+ * **Do not mutate structural fields** (e.g. `type`) — doing so will
224
+ * desync the archetype index. Mutating value fields (x, y, color …) is safe.
225
+ */
226
+ getEntityComponents(id) {
227
+ const map = this.componentIndex.get(id);
228
+ if (!map) return [];
229
+ return [...map.values()];
230
+ }
231
+ /** Returns all live entity IDs currently in the world. */
232
+ getAllEntityIds() {
233
+ return [...this.componentIndex.keys()];
234
+ }
204
235
  // Flush pending dirty flags into the query cache immediately.
205
236
  // Called inline at the top of query() so any mid-frame mutation
206
237
  // (destroyEntity, addComponent, removeComponent) is reflected before
@@ -437,7 +468,7 @@ var ECSWorld = class {
437
468
  const removed = [];
438
469
  for (const entity of current.entities) {
439
470
  const base = baseMap.get(entity.id);
440
- if (!base || JSON.stringify(entity.components) !== JSON.stringify(base.components)) {
471
+ if (!base || _componentsChanged(entity.components, base.components)) {
441
472
  changed.push(entity);
442
473
  }
443
474
  }
@@ -4583,7 +4614,7 @@ function useCollidingWith() {
4583
4614
  // ../devtools/src/DevTools.tsx
4584
4615
  import React from "react";
4585
4616
  import { createPortal } from "react-dom";
4586
- import { useState as useState2, useEffect as useEffect10, useCallback, useRef as useRef10 } from "react";
4617
+ import { useState as useState2, useEffect as useEffect11, useCallback as useCallback2, useRef as useRef11 } from "react";
4587
4618
 
4588
4619
  // ../../packages/audio/src/useSound.ts
4589
4620
  import { useEffect as useEffect3, useRef as useRef3 } from "react";
@@ -4905,24 +4936,24 @@ function useSound(src, opts = {}) {
4905
4936
  // ../../packages/audio/src/useSpatialSound.ts
4906
4937
  import { useEffect as useEffect4, useRef as useRef4 } from "react";
4907
4938
  async function loadBuffer2(src) {
4908
- const bufferCache2 = _getBufferCache();
4939
+ const bufferCache3 = _getBufferCache();
4909
4940
  const bufferRefCount2 = _getBufferRefCount();
4910
4941
  bufferRefCount2.set(src, (bufferRefCount2.get(src) ?? 0) + 1);
4911
- const cached = bufferCache2.get(src);
4942
+ const cached = bufferCache3.get(src);
4912
4943
  if (cached) return cached;
4913
4944
  const res = await fetch(src);
4914
4945
  const data = await res.arrayBuffer();
4915
4946
  const buf = await getAudioCtx().decodeAudioData(data);
4916
- bufferCache2.set(src, buf);
4947
+ bufferCache3.set(src, buf);
4917
4948
  return buf;
4918
4949
  }
4919
4950
  function releaseBuffer2(src) {
4920
- const bufferCache2 = _getBufferCache();
4951
+ const bufferCache3 = _getBufferCache();
4921
4952
  const bufferRefCount2 = _getBufferRefCount();
4922
4953
  const count = bufferRefCount2.get(src) ?? 0;
4923
4954
  if (count <= 1) {
4924
4955
  bufferRefCount2.delete(src);
4925
- bufferCache2.delete(src);
4956
+ bufferCache3.delete(src);
4926
4957
  } else {
4927
4958
  bufferRefCount2.set(src, count - 1);
4928
4959
  }
@@ -5492,20 +5523,20 @@ function usePreloadAudio(srcs) {
5492
5523
  cancelledRef.current = false;
5493
5524
  if (srcs.length === 0) return;
5494
5525
  const unique = [...new Set(srcs)];
5495
- const bufferCache2 = _getBufferCache();
5526
+ const bufferCache3 = _getBufferCache();
5496
5527
  const bufferRefCount2 = _getBufferRefCount();
5497
5528
  const ctx = getAudioCtx();
5498
5529
  const loadOne = async (src) => {
5499
5530
  try {
5500
- if (!preloadCache.has(src) && !bufferCache2.has(src)) {
5531
+ if (!preloadCache.has(src) && !bufferCache3.has(src)) {
5501
5532
  const res = await fetch(src);
5502
5533
  const data = await res.arrayBuffer();
5503
5534
  const buf = await ctx.decodeAudioData(data);
5504
5535
  preloadCache.set(src, buf);
5505
- bufferCache2.set(src, buf);
5536
+ bufferCache3.set(src, buf);
5506
5537
  bufferRefCount2.set(src, (bufferRefCount2.get(src) ?? 0) + 1);
5507
- } else if (!preloadCache.has(src) && bufferCache2.has(src)) {
5508
- preloadCache.set(src, bufferCache2.get(src));
5538
+ } else if (!preloadCache.has(src) && bufferCache3.has(src)) {
5539
+ preloadCache.set(src, bufferCache3.get(src));
5509
5540
  }
5510
5541
  } catch {
5511
5542
  if (!cancelledRef.current) {
@@ -5533,6 +5564,156 @@ function usePreloadAudio(srcs) {
5533
5564
  };
5534
5565
  }
5535
5566
 
5567
+ // ../../packages/audio/src/useSoundscape.ts
5568
+ import { useEffect as useEffect10, useRef as useRef10, useCallback } from "react";
5569
+ var bufferCache2 = /* @__PURE__ */ new Map();
5570
+ async function loadBuffer3(src) {
5571
+ const cached = bufferCache2.get(src);
5572
+ if (cached) return cached;
5573
+ const res = await fetch(src);
5574
+ const data = await res.arrayBuffer();
5575
+ const buf = await getAudioCtx().decodeAudioData(data);
5576
+ bufferCache2.set(src, buf);
5577
+ return buf;
5578
+ }
5579
+ function useSoundscape(layers, opts = {}) {
5580
+ const { volume: masterVolume = 1, fadeIn = 1, fadeOut = 1, group = "ambient", active = true } = opts;
5581
+ const masterGainRef = useRef10(null);
5582
+ const layerStatesRef = useRef10(/* @__PURE__ */ new Map());
5583
+ const activeRef = useRef10(active);
5584
+ useEffect10(() => {
5585
+ const ctx = getAudioCtx();
5586
+ const masterGain = ctx.createGain();
5587
+ masterGain.gain.setValueAtTime(0, ctx.currentTime);
5588
+ masterGain.connect(getGroupGainNode(group));
5589
+ masterGainRef.current = masterGain;
5590
+ const destroyed = { current: false };
5591
+ const layerStates = layerStatesRef.current;
5592
+ const loadPromises = [];
5593
+ for (const layer of layers) {
5594
+ const layerGain = ctx.createGain();
5595
+ const targetVol = layer.active === false ? 0 : layer.volume ?? 1;
5596
+ layerGain.gain.setValueAtTime(targetVol, ctx.currentTime);
5597
+ layerGain.connect(masterGain);
5598
+ const state = {
5599
+ src: layer.src,
5600
+ gainNode: layerGain,
5601
+ source: null,
5602
+ targetVolume: targetVol,
5603
+ unregister: null
5604
+ };
5605
+ layerStates.set(layer.src, state);
5606
+ const p = loadBuffer3(layer.src).then((buf) => {
5607
+ if (destroyed.current) return;
5608
+ const source = ctx.createBufferSource();
5609
+ source.buffer = buf;
5610
+ source.loop = true;
5611
+ source.connect(layerGain);
5612
+ const offset = layer.randomOffset && layer.randomOffset > 0 ? Math.random() * layer.randomOffset : 0;
5613
+ source.start(0, offset % buf.duration);
5614
+ state.source = source;
5615
+ state.unregister = registerGroupSource(group, () => {
5616
+ try {
5617
+ source.stop();
5618
+ } catch {
5619
+ }
5620
+ });
5621
+ });
5622
+ loadPromises.push(p);
5623
+ }
5624
+ Promise.all(loadPromises).then(() => {
5625
+ if (destroyed.current) return;
5626
+ if (!activeRef.current) return;
5627
+ const now = ctx.currentTime;
5628
+ if (fadeIn > 0) {
5629
+ masterGain.gain.cancelScheduledValues(now);
5630
+ masterGain.gain.setValueAtTime(0, now);
5631
+ masterGain.gain.linearRampToValueAtTime(masterVolume, now + fadeIn);
5632
+ } else {
5633
+ masterGain.gain.setValueAtTime(masterVolume, now);
5634
+ }
5635
+ });
5636
+ return () => {
5637
+ destroyed.current = true;
5638
+ const now = ctx.currentTime;
5639
+ const stopAll = () => {
5640
+ for (const state of layerStates.values()) {
5641
+ state.unregister?.();
5642
+ if (state.source) {
5643
+ try {
5644
+ state.source.stop();
5645
+ } catch {
5646
+ }
5647
+ }
5648
+ state.gainNode.disconnect();
5649
+ }
5650
+ layerStates.clear();
5651
+ masterGain.disconnect();
5652
+ };
5653
+ if (fadeOut > 0) {
5654
+ masterGain.gain.cancelScheduledValues(now);
5655
+ masterGain.gain.setValueAtTime(masterGain.gain.value, now);
5656
+ masterGain.gain.linearRampToValueAtTime(0, now + fadeOut);
5657
+ setTimeout(stopAll, fadeOut * 1e3 + 50);
5658
+ } else {
5659
+ stopAll();
5660
+ }
5661
+ };
5662
+ }, []);
5663
+ useEffect10(() => {
5664
+ activeRef.current = active;
5665
+ const masterGain = masterGainRef.current;
5666
+ if (!masterGain) return;
5667
+ const ctx = getAudioCtx();
5668
+ const now = ctx.currentTime;
5669
+ const target = active ? masterVolume : 0;
5670
+ const duration = active ? fadeIn : fadeOut;
5671
+ masterGain.gain.cancelScheduledValues(now);
5672
+ masterGain.gain.setValueAtTime(masterGain.gain.value, now);
5673
+ if (duration > 0) {
5674
+ masterGain.gain.linearRampToValueAtTime(target, now + duration);
5675
+ } else {
5676
+ masterGain.gain.setValueAtTime(target, now);
5677
+ }
5678
+ }, [active, masterVolume, fadeIn, fadeOut]);
5679
+ const setVolume = useCallback((volume, duration = 0) => {
5680
+ const masterGain = masterGainRef.current;
5681
+ if (!masterGain) return;
5682
+ const ctx = getAudioCtx();
5683
+ const now = ctx.currentTime;
5684
+ const clamped = Math.max(0, Math.min(1, volume));
5685
+ masterGain.gain.cancelScheduledValues(now);
5686
+ masterGain.gain.setValueAtTime(masterGain.gain.value, now);
5687
+ if (duration > 0) {
5688
+ masterGain.gain.linearRampToValueAtTime(clamped, now + duration);
5689
+ } else {
5690
+ masterGain.gain.setValueAtTime(clamped, now);
5691
+ }
5692
+ }, []);
5693
+ const setLayerVolume = useCallback((src, volume, duration = 0) => {
5694
+ const state = layerStatesRef.current.get(src);
5695
+ if (!state) return;
5696
+ const ctx = getAudioCtx();
5697
+ const now = ctx.currentTime;
5698
+ const clamped = Math.max(0, Math.min(1, volume));
5699
+ state.targetVolume = clamped;
5700
+ state.gainNode.gain.cancelScheduledValues(now);
5701
+ state.gainNode.gain.setValueAtTime(state.gainNode.gain.value, now);
5702
+ if (duration > 0) {
5703
+ state.gainNode.gain.linearRampToValueAtTime(clamped, now + duration);
5704
+ } else {
5705
+ state.gainNode.gain.setValueAtTime(clamped, now);
5706
+ }
5707
+ }, []);
5708
+ const fadeLayer = useCallback(
5709
+ (src, targetVolume, duration) => {
5710
+ setLayerVolume(src, targetVolume, duration);
5711
+ },
5712
+ [setLayerVolume]
5713
+ );
5714
+ return { setVolume, setLayerVolume, fadeLayer };
5715
+ }
5716
+
5536
5717
  // ../../packages/audio/src/listener.ts
5537
5718
  function setListenerPosition(x, y) {
5538
5719
  const ctx = getAudioCtx();
@@ -5720,8 +5901,8 @@ function DevToolsOverlay({ handle, loop, ecs, engine }) {
5720
5901
  const [showNavGrid, setShowNavGrid] = useState2(false);
5721
5902
  const [showContactFlash, setShowContactFlash] = useState2(false);
5722
5903
  const [hidden, setHidden] = useState2(false);
5723
- const frameRef = useRef10(0);
5724
- useEffect10(() => {
5904
+ const frameRef = useRef11(0);
5905
+ useEffect11(() => {
5725
5906
  const onKey = (e) => {
5726
5907
  if (e.key === "`" && !e.ctrlKey && !e.metaKey && !e.altKey) {
5727
5908
  setHidden((v) => !v);
@@ -5730,7 +5911,7 @@ function DevToolsOverlay({ handle, loop, ecs, engine }) {
5730
5911
  window.addEventListener("keydown", onKey);
5731
5912
  return () => window.removeEventListener("keydown", onKey);
5732
5913
  }, []);
5733
- useEffect10(() => {
5914
+ useEffect11(() => {
5734
5915
  handle.onFrame = () => {
5735
5916
  frameRef.current++;
5736
5917
  if (!paused) {
@@ -5742,14 +5923,14 @@ function DevToolsOverlay({ handle, loop, ecs, engine }) {
5742
5923
  handle.onFrame = void 0;
5743
5924
  };
5744
5925
  }, [handle, paused]);
5745
- useEffect10(() => {
5926
+ useEffect11(() => {
5746
5927
  const rs = engine?.activeRenderSystem;
5747
5928
  rs?.setEntityHighlight?.(selectedEntity);
5748
5929
  return () => {
5749
5930
  rs?.setEntityHighlight?.(null);
5750
5931
  };
5751
5932
  }, [engine, selectedEntity]);
5752
- useEffect10(() => {
5933
+ useEffect11(() => {
5753
5934
  if (!engine) return;
5754
5935
  const events = engine.events;
5755
5936
  const types = ["triggerEnter", "triggerExit", "collisionEnter", "collisionExit", "circleEnter", "circleExit"];
@@ -5781,7 +5962,7 @@ function DevToolsOverlay({ handle, loop, ecs, engine }) {
5781
5962
  }, [engine, showContactFlash]);
5782
5963
  const totalFrames = handle.buffer.length;
5783
5964
  const currentSnap = handle.buffer[selectedIdx];
5784
- const handlePauseResume = useCallback(() => {
5965
+ const handlePauseResume = useCallback2(() => {
5785
5966
  if (paused) {
5786
5967
  if (currentSnap) ecs.restoreSnapshot(currentSnap);
5787
5968
  loop.resume();
@@ -5793,15 +5974,15 @@ function DevToolsOverlay({ handle, loop, ecs, engine }) {
5793
5974
  setSelectedIdx(Math.max(0, handle.buffer.length - 1));
5794
5975
  }
5795
5976
  }, [paused, currentSnap, ecs, loop, handle]);
5796
- const stepBack = useCallback(() => {
5977
+ const stepBack = useCallback2(() => {
5797
5978
  setSelectedIdx((i) => Math.max(0, i - 1));
5798
5979
  setSelectedEntity(null);
5799
5980
  }, []);
5800
- const stepForward = useCallback(() => {
5981
+ const stepForward = useCallback2(() => {
5801
5982
  setSelectedIdx((i) => Math.min(handle.buffer.length - 1, i + 1));
5802
5983
  setSelectedEntity(null);
5803
5984
  }, [handle]);
5804
- const handleToggleNavGrid = useCallback(() => {
5985
+ const handleToggleNavGrid = useCallback2(() => {
5805
5986
  if (!engine) return;
5806
5987
  const renderer = engine.activeRenderSystem;
5807
5988
  if (!renderer?.setDebugNavGrid) return;
@@ -6668,14 +6849,14 @@ function Game({
6668
6849
  className,
6669
6850
  children
6670
6851
  }) {
6671
- const canvasRef = useRef11(null);
6672
- const debugCanvasRef = useRef11(null);
6673
- const wrapperRef = useRef11(null);
6852
+ const canvasRef = useRef12(null);
6853
+ const debugCanvasRef = useRef12(null);
6854
+ const wrapperRef = useRef12(null);
6674
6855
  const [engine, setEngine] = useState3(null);
6675
6856
  const [assetsReady, setAssetsReady] = useState3(asyncAssets);
6676
6857
  const [webglError, setWebglError] = useState3(null);
6677
- const devtoolsHandle = useRef11({ buffer: [] });
6678
- useEffect11(() => {
6858
+ const devtoolsHandle = useRef12({ buffer: [] });
6859
+ useEffect12(() => {
6679
6860
  const canvas = canvasRef.current;
6680
6861
  const ecs = new ECSWorld();
6681
6862
  if (deterministic) ecs.setDeterministicSeed(seed);
@@ -6829,7 +7010,7 @@ function Game({
6829
7010
  }
6830
7011
  };
6831
7012
  }, []);
6832
- useEffect11(() => {
7013
+ useEffect12(() => {
6833
7014
  if (!engine) return;
6834
7015
  let cancelled = false;
6835
7016
  if (asyncAssets) {
@@ -6847,7 +7028,7 @@ function Game({
6847
7028
  cancelled = true;
6848
7029
  };
6849
7030
  }, [engine]);
6850
- useEffect11(() => {
7031
+ useEffect12(() => {
6851
7032
  if (!engine) return;
6852
7033
  const dpr = window.devicePixelRatio || 1;
6853
7034
  const physW = Math.round(width * dpr);
@@ -6858,7 +7039,7 @@ function Game({
6858
7039
  canvas.style.width = `${width}px`;
6859
7040
  canvas.style.height = `${height}px`;
6860
7041
  }, [width, height, engine]);
6861
- useEffect11(() => {
7042
+ useEffect12(() => {
6862
7043
  engine?.physics.setGravity(gravity);
6863
7044
  }, [gravity, engine]);
6864
7045
  const canvasStyle = {
@@ -6974,15 +7155,15 @@ function Stage(props) {
6974
7155
  }
6975
7156
 
6976
7157
  // src/components/World.tsx
6977
- import { useEffect as useEffect12, useContext as useContext3 } from "react";
7158
+ import { useEffect as useEffect13, useContext as useContext3 } from "react";
6978
7159
  import { Fragment as Fragment2, jsx as jsx4 } from "react/jsx-runtime";
6979
7160
  function World({ gravity, background = "#1a1a2e", children }) {
6980
7161
  const engine = useContext3(EngineContext);
6981
- useEffect12(() => {
7162
+ useEffect13(() => {
6982
7163
  if (!engine) return;
6983
7164
  if (gravity !== void 0) engine.physics.setGravity(gravity);
6984
7165
  }, [gravity, engine]);
6985
- useEffect12(() => {
7166
+ useEffect13(() => {
6986
7167
  if (!engine) return;
6987
7168
  const camId = engine.ecs.queryOne("Camera2D");
6988
7169
  if (camId !== void 0) {
@@ -6996,7 +7177,7 @@ function World({ gravity, background = "#1a1a2e", children }) {
6996
7177
  }
6997
7178
 
6998
7179
  // src/components/Entity.tsx
6999
- import { useEffect as useEffect13, useContext as useContext4, useState as useState4 } from "react";
7180
+ import { useEffect as useEffect14, useContext as useContext4, useState as useState4 } from "react";
7000
7181
  import { jsx as jsx5 } from "react/jsx-runtime";
7001
7182
  function Entity({ id, tags = [], children }) {
7002
7183
  const engine = useContext4(EngineContext);
@@ -7006,7 +7187,7 @@ function Entity({ id, tags = [], children }) {
7006
7187
  console.warn("[Cubeforge] <Entity> must be inside a <World>. No EngineContext found.");
7007
7188
  }
7008
7189
  }
7009
- useEffect13(() => {
7190
+ useEffect14(() => {
7010
7191
  const eid = engine.ecs.createEntity();
7011
7192
  if (id) {
7012
7193
  if (engine.entityIds.has(id)) {
@@ -7028,15 +7209,15 @@ function Entity({ id, tags = [], children }) {
7028
7209
  }
7029
7210
 
7030
7211
  // src/components/Transform.tsx
7031
- import { useEffect as useEffect14, useContext as useContext5 } from "react";
7212
+ import { useEffect as useEffect15, useContext as useContext5 } from "react";
7032
7213
  function Transform({ x = 0, y = 0, rotation = 0, scaleX = 1, scaleY = 1 }) {
7033
7214
  const engine = useContext5(EngineContext);
7034
7215
  const entityId = useContext5(EntityContext);
7035
- useEffect14(() => {
7216
+ useEffect15(() => {
7036
7217
  engine.ecs.addComponent(entityId, createTransform(x, y, rotation, scaleX, scaleY));
7037
7218
  return () => engine.ecs.removeComponent(entityId, "Transform");
7038
7219
  }, []);
7039
- useEffect14(() => {
7220
+ useEffect15(() => {
7040
7221
  const comp = engine.ecs.getComponent(entityId, "Transform");
7041
7222
  if (comp) {
7042
7223
  comp.x = x;
@@ -7050,7 +7231,7 @@ function Transform({ x = 0, y = 0, rotation = 0, scaleX = 1, scaleY = 1 }) {
7050
7231
  }
7051
7232
 
7052
7233
  // src/components/Sprite.tsx
7053
- import { useEffect as useEffect15, useContext as useContext6, useRef as useRef12 } from "react";
7234
+ import { useEffect as useEffect16, useContext as useContext6, useRef as useRef13 } from "react";
7054
7235
  function Sprite({
7055
7236
  width,
7056
7237
  height,
@@ -7101,7 +7282,7 @@ function Sprite({
7101
7282
  );
7102
7283
  }
7103
7284
  }
7104
- useEffect15(() => {
7285
+ useEffect16(() => {
7105
7286
  const comp = createSprite({
7106
7287
  width,
7107
7288
  height,
@@ -7153,8 +7334,8 @@ function Sprite({
7153
7334
  }
7154
7335
  return () => engine.ecs.removeComponent(entityId, "Sprite");
7155
7336
  }, []);
7156
- const didMount = useRef12(false);
7157
- useEffect15(() => {
7337
+ const didMount = useRef13(false);
7338
+ useEffect16(() => {
7158
7339
  if (!didMount.current) {
7159
7340
  didMount.current = true;
7160
7341
  return;
@@ -7184,7 +7365,7 @@ function Sprite({
7184
7365
  cancelled = true;
7185
7366
  };
7186
7367
  }, [src, engine, entityId]);
7187
- useEffect15(() => {
7368
+ useEffect16(() => {
7188
7369
  const comp = engine.ecs.getComponent(entityId, "Sprite");
7189
7370
  if (!comp) return;
7190
7371
  comp.color = color;
@@ -7231,7 +7412,7 @@ function Sprite({
7231
7412
  }
7232
7413
 
7233
7414
  // src/components/Text.tsx
7234
- import { useEffect as useEffect16, useContext as useContext7 } from "react";
7415
+ import { useEffect as useEffect17, useContext as useContext7 } from "react";
7235
7416
  function Text({
7236
7417
  text,
7237
7418
  fontSize = 16,
@@ -7256,7 +7437,7 @@ function Text({
7256
7437
  }) {
7257
7438
  const engine = useContext7(EngineContext);
7258
7439
  const entityId = useContext7(EntityContext);
7259
- useEffect16(() => {
7440
+ useEffect17(() => {
7260
7441
  const comp = createText({
7261
7442
  text,
7262
7443
  fontSize,
@@ -7282,7 +7463,7 @@ function Text({
7282
7463
  engine.ecs.addComponent(entityId, comp);
7283
7464
  return () => engine.ecs.removeComponent(entityId, "Text");
7284
7465
  }, []);
7285
- useEffect16(() => {
7466
+ useEffect17(() => {
7286
7467
  const comp = engine.ecs.getComponent(entityId, "Text");
7287
7468
  if (!comp) return;
7288
7469
  comp.text = text;
@@ -7319,7 +7500,7 @@ function Text({
7319
7500
  }
7320
7501
 
7321
7502
  // src/components/RigidBody.tsx
7322
- import { useEffect as useEffect17, useContext as useContext8 } from "react";
7503
+ import { useEffect as useEffect18, useContext as useContext8 } from "react";
7323
7504
  function RigidBody({
7324
7505
  mass = 0,
7325
7506
  gravityScale = 1,
@@ -7349,7 +7530,7 @@ function RigidBody({
7349
7530
  console.warn("[Cubeforge] <RigidBody> must be inside an <Entity>. No EntityContext found.");
7350
7531
  }
7351
7532
  }
7352
- useEffect17(() => {
7533
+ useEffect18(() => {
7353
7534
  engine.ecs.addComponent(
7354
7535
  entityId,
7355
7536
  createRigidBody({
@@ -7381,7 +7562,7 @@ function RigidBody({
7381
7562
  }
7382
7563
 
7383
7564
  // src/components/BoxCollider.tsx
7384
- import { useEffect as useEffect18, useContext as useContext9 } from "react";
7565
+ import { useEffect as useEffect19, useContext as useContext9 } from "react";
7385
7566
  function BoxCollider({
7386
7567
  width,
7387
7568
  height,
@@ -7399,7 +7580,7 @@ function BoxCollider({
7399
7580
  }) {
7400
7581
  const engine = useContext9(EngineContext);
7401
7582
  const entityId = useContext9(EntityContext);
7402
- useEffect18(() => {
7583
+ useEffect19(() => {
7403
7584
  engine.ecs.addComponent(
7404
7585
  entityId,
7405
7586
  createBoxCollider(width, height, {
@@ -7437,7 +7618,7 @@ function BoxCollider({
7437
7618
  }
7438
7619
 
7439
7620
  // src/components/CircleCollider.tsx
7440
- import { useEffect as useEffect19, useContext as useContext10 } from "react";
7621
+ import { useEffect as useEffect20, useContext as useContext10 } from "react";
7441
7622
  function CircleCollider({
7442
7623
  radius,
7443
7624
  offsetX = 0,
@@ -7453,7 +7634,7 @@ function CircleCollider({
7453
7634
  }) {
7454
7635
  const engine = useContext10(EngineContext);
7455
7636
  const entityId = useContext10(EntityContext);
7456
- useEffect19(() => {
7637
+ useEffect20(() => {
7457
7638
  engine.ecs.addComponent(
7458
7639
  entityId,
7459
7640
  createCircleCollider(radius, {
@@ -7475,7 +7656,7 @@ function CircleCollider({
7475
7656
  }
7476
7657
 
7477
7658
  // src/components/CapsuleCollider.tsx
7478
- import { useEffect as useEffect20, useContext as useContext11 } from "react";
7659
+ import { useEffect as useEffect21, useContext as useContext11 } from "react";
7479
7660
  function CapsuleCollider({
7480
7661
  width,
7481
7662
  height,
@@ -7492,7 +7673,7 @@ function CapsuleCollider({
7492
7673
  }) {
7493
7674
  const engine = useContext11(EngineContext);
7494
7675
  const entityId = useContext11(EntityContext);
7495
- useEffect20(() => {
7676
+ useEffect21(() => {
7496
7677
  engine.ecs.addComponent(
7497
7678
  entityId,
7498
7679
  createCapsuleCollider(width, height, {
@@ -7514,11 +7695,11 @@ function CapsuleCollider({
7514
7695
  }
7515
7696
 
7516
7697
  // src/components/CompoundCollider.tsx
7517
- import { useEffect as useEffect21, useContext as useContext12 } from "react";
7698
+ import { useEffect as useEffect22, useContext as useContext12 } from "react";
7518
7699
  function CompoundCollider({ shapes, isTrigger = false, layer = "default", mask = "*" }) {
7519
7700
  const engine = useContext12(EngineContext);
7520
7701
  const entityId = useContext12(EntityContext);
7521
- useEffect21(() => {
7702
+ useEffect22(() => {
7522
7703
  engine.ecs.addComponent(entityId, createCompoundCollider(shapes, { isTrigger, layer, mask }));
7523
7704
  const checkId = setTimeout(() => {
7524
7705
  if (engine.ecs.hasEntity(entityId) && !engine.ecs.hasComponent(entityId, "Transform")) {
@@ -7534,7 +7715,7 @@ function CompoundCollider({ shapes, isTrigger = false, layer = "default", mask =
7534
7715
  }
7535
7716
 
7536
7717
  // src/components/Script.tsx
7537
- import { useEffect as useEffect22, useContext as useContext13, useRef as useRef13 } from "react";
7718
+ import { useEffect as useEffect23, useContext as useContext13, useRef as useRef14 } from "react";
7538
7719
  function Script({ init, update }) {
7539
7720
  const engine = useContext13(EngineContext);
7540
7721
  const entityId = useContext13(EntityContext);
@@ -7543,11 +7724,11 @@ function Script({ init, update }) {
7543
7724
  console.warn("[Cubeforge] <Script> must be inside an <Entity>. No EntityContext found.");
7544
7725
  }
7545
7726
  }
7546
- const initRef = useRef13(init);
7727
+ const initRef = useRef14(init);
7547
7728
  initRef.current = init;
7548
- const updateRef = useRef13(update);
7729
+ const updateRef = useRef14(update);
7549
7730
  updateRef.current = update;
7550
- useEffect22(() => {
7731
+ useEffect23(() => {
7551
7732
  if (initRef.current) {
7552
7733
  try {
7553
7734
  initRef.current(entityId, engine.ecs);
@@ -7563,7 +7744,7 @@ function Script({ init, update }) {
7563
7744
  }
7564
7745
 
7565
7746
  // src/components/Camera2D.tsx
7566
- import { useEffect as useEffect23, useContext as useContext14 } from "react";
7747
+ import { useEffect as useEffect24, useContext as useContext14 } from "react";
7567
7748
  function Camera2D({
7568
7749
  followEntity,
7569
7750
  x = 0,
@@ -7577,7 +7758,7 @@ function Camera2D({
7577
7758
  followOffsetY = 0
7578
7759
  }) {
7579
7760
  const engine = useContext14(EngineContext);
7580
- useEffect23(() => {
7761
+ useEffect24(() => {
7581
7762
  const entityId = engine.ecs.createEntity();
7582
7763
  engine.ecs.addComponent(
7583
7764
  entityId,
@@ -7596,7 +7777,7 @@ function Camera2D({
7596
7777
  );
7597
7778
  return () => engine.ecs.destroyEntity(entityId);
7598
7779
  }, []);
7599
- useEffect23(() => {
7780
+ useEffect24(() => {
7600
7781
  const camId = engine.ecs.queryOne("Camera2D");
7601
7782
  if (camId === void 0) return;
7602
7783
  const cam = engine.ecs.getComponent(camId, "Camera2D");
@@ -7615,11 +7796,11 @@ function Camera2D({
7615
7796
  }
7616
7797
 
7617
7798
  // src/components/Animation.tsx
7618
- import { useEffect as useEffect24, useContext as useContext15 } from "react";
7799
+ import { useEffect as useEffect25, useContext as useContext15 } from "react";
7619
7800
  function Animation({ frames, fps = 12, loop = true, playing = true, onComplete, frameEvents }) {
7620
7801
  const engine = useContext15(EngineContext);
7621
7802
  const entityId = useContext15(EntityContext);
7622
- useEffect24(() => {
7803
+ useEffect25(() => {
7623
7804
  const state = {
7624
7805
  type: "AnimationState",
7625
7806
  frames,
@@ -7637,7 +7818,7 @@ function Animation({ frames, fps = 12, loop = true, playing = true, onComplete,
7637
7818
  engine.ecs.removeComponent(entityId, "AnimationState");
7638
7819
  };
7639
7820
  }, []);
7640
- useEffect24(() => {
7821
+ useEffect25(() => {
7641
7822
  const anim = engine.ecs.getComponent(entityId, "AnimationState");
7642
7823
  if (!anim) return;
7643
7824
  const wasFramesChanged = anim.frames !== frames;
@@ -7657,7 +7838,7 @@ function Animation({ frames, fps = 12, loop = true, playing = true, onComplete,
7657
7838
  }
7658
7839
 
7659
7840
  // src/components/AnimatedSprite.tsx
7660
- import { useEffect as useEffect25, useContext as useContext16 } from "react";
7841
+ import { useEffect as useEffect26, useContext as useContext16 } from "react";
7661
7842
  import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
7662
7843
  function defineAnimations(clips) {
7663
7844
  return clips;
@@ -7746,7 +7927,7 @@ function AnimatedSprite(props) {
7746
7927
  function MultiClipAnimation({ animations, current }) {
7747
7928
  const engine = useContext16(EngineContext);
7748
7929
  const entityId = useContext16(EntityContext);
7749
- useEffect25(() => {
7930
+ useEffect26(() => {
7750
7931
  const clip = animations[current] ?? Object.values(animations)[0];
7751
7932
  const state = {
7752
7933
  type: "AnimationState",
@@ -7765,7 +7946,7 @@ function MultiClipAnimation({ animations, current }) {
7765
7946
  engine.ecs.addComponent(entityId, state);
7766
7947
  return () => engine.ecs.removeComponent(entityId, "AnimationState");
7767
7948
  }, []);
7768
- useEffect25(() => {
7949
+ useEffect26(() => {
7769
7950
  const anim = engine.ecs.getComponent(entityId, "AnimationState");
7770
7951
  if (!anim) return;
7771
7952
  anim.clips = animations;
@@ -7775,11 +7956,11 @@ function MultiClipAnimation({ animations, current }) {
7775
7956
  }
7776
7957
 
7777
7958
  // src/components/Animator.tsx
7778
- import { useEffect as useEffect26, useContext as useContext17 } from "react";
7959
+ import { useEffect as useEffect27, useContext as useContext17 } from "react";
7779
7960
  function Animator({ initial, states, params = {}, playing = true }) {
7780
7961
  const engine = useContext17(EngineContext);
7781
7962
  const entityId = useContext17(EntityContext);
7782
- useEffect26(() => {
7963
+ useEffect27(() => {
7783
7964
  const comp = {
7784
7965
  type: "Animator",
7785
7966
  initialState: initial,
@@ -7792,13 +7973,13 @@ function Animator({ initial, states, params = {}, playing = true }) {
7792
7973
  engine.ecs.addComponent(entityId, comp);
7793
7974
  return () => engine.ecs.removeComponent(entityId, "Animator");
7794
7975
  }, []);
7795
- useEffect26(() => {
7976
+ useEffect27(() => {
7796
7977
  const comp = engine.ecs.getComponent(entityId, "Animator");
7797
7978
  if (!comp) return;
7798
7979
  Object.assign(comp.params, params);
7799
7980
  comp.playing = playing;
7800
7981
  }, [params, playing, engine, entityId]);
7801
- useEffect26(() => {
7982
+ useEffect27(() => {
7802
7983
  const comp = engine.ecs.getComponent(entityId, "Animator");
7803
7984
  if (!comp) return;
7804
7985
  comp.states = states;
@@ -7807,11 +7988,11 @@ function Animator({ initial, states, params = {}, playing = true }) {
7807
7988
  }
7808
7989
 
7809
7990
  // src/components/SquashStretch.tsx
7810
- import { useEffect as useEffect27, useContext as useContext18 } from "react";
7991
+ import { useEffect as useEffect28, useContext as useContext18 } from "react";
7811
7992
  function SquashStretch({ intensity = 0.2, recovery = 8 }) {
7812
7993
  const engine = useContext18(EngineContext);
7813
7994
  const entityId = useContext18(EntityContext);
7814
- useEffect27(() => {
7995
+ useEffect28(() => {
7815
7996
  engine.ecs.addComponent(entityId, {
7816
7997
  type: "SquashStretch",
7817
7998
  intensity,
@@ -7825,7 +8006,7 @@ function SquashStretch({ intensity = 0.2, recovery = 8 }) {
7825
8006
  }
7826
8007
 
7827
8008
  // src/components/ParticleEmitter.tsx
7828
- import { useEffect as useEffect28, useContext as useContext19 } from "react";
8009
+ import { useEffect as useEffect29, useContext as useContext19 } from "react";
7829
8010
 
7830
8011
  // src/components/particlePresets.ts
7831
8012
  var PARTICLE_PRESETS = {
@@ -8109,7 +8290,7 @@ function ParticleEmitter({
8109
8290
  const resolvedSizeOverLife = sizeOverLife ?? presetConfig.sizeOverLife;
8110
8291
  const engine = useContext19(EngineContext);
8111
8292
  const entityId = useContext19(EntityContext);
8112
- useEffect28(() => {
8293
+ useEffect29(() => {
8113
8294
  engine.ecs.addComponent(entityId, {
8114
8295
  type: "ParticlePool",
8115
8296
  particles: [],
@@ -8144,23 +8325,23 @@ function ParticleEmitter({
8144
8325
  });
8145
8326
  return () => engine.ecs.removeComponent(entityId, "ParticlePool");
8146
8327
  }, []);
8147
- useEffect28(() => {
8328
+ useEffect29(() => {
8148
8329
  const pool = engine.ecs.getComponent(entityId, "ParticlePool");
8149
8330
  if (!pool) return;
8150
8331
  pool.active = active;
8151
8332
  }, [active, engine, entityId]);
8152
- useEffect28(() => {
8333
+ useEffect29(() => {
8153
8334
  const pool = engine.ecs.getComponent(entityId, "ParticlePool");
8154
8335
  if (!pool) return;
8155
8336
  pool.blendMode = resolvedBlendMode;
8156
8337
  pool.particleShape = resolvedParticleShape;
8157
8338
  }, [resolvedBlendMode, resolvedParticleShape, engine, entityId]);
8158
- useEffect28(() => {
8339
+ useEffect29(() => {
8159
8340
  const pool = engine.ecs.getComponent(entityId, "ParticlePool");
8160
8341
  if (!pool) return;
8161
8342
  pool.attractors = attractors;
8162
8343
  }, [attractors, engine, entityId]);
8163
- useEffect28(() => {
8344
+ useEffect29(() => {
8164
8345
  const pool = engine.ecs.getComponent(entityId, "ParticlePool");
8165
8346
  if (!pool || pool.mode !== "formation" || !formationPoints) return;
8166
8347
  pool.formationPoints = formationPoints;
@@ -8172,7 +8353,7 @@ function ParticleEmitter({
8172
8353
  }
8173
8354
  });
8174
8355
  }, [formationPoints, engine, entityId]);
8175
- useEffect28(() => {
8356
+ useEffect29(() => {
8176
8357
  const pool = engine.ecs.getComponent(entityId, "ParticlePool");
8177
8358
  if (!pool || !targetColor) return;
8178
8359
  pool._colorTransitionFrom = pool.color;
@@ -8184,7 +8365,7 @@ function ParticleEmitter({
8184
8365
  }
8185
8366
 
8186
8367
  // src/components/VirtualJoystick.tsx
8187
- import { useRef as useRef14 } from "react";
8368
+ import { useRef as useRef15 } from "react";
8188
8369
 
8189
8370
  // src/hooks/useVirtualInput.ts
8190
8371
  var _axes = { x: 0, y: 0 };
@@ -8218,10 +8399,10 @@ function VirtualJoystick({
8218
8399
  actionLabel = "A",
8219
8400
  actionName = "action"
8220
8401
  }) {
8221
- const baseRef = useRef14(null);
8222
- const stickRef = useRef14(null);
8223
- const activePtr = useRef14(null);
8224
- const baseCenterRef = useRef14({ x: 0, y: 0 });
8402
+ const baseRef = useRef15(null);
8403
+ const stickRef = useRef15(null);
8404
+ const activePtr = useRef15(null);
8405
+ const baseCenterRef = useRef15({ x: 0, y: 0 });
8225
8406
  const radius = size / 2 - 16;
8226
8407
  const applyStickPosition = (dx, dy) => {
8227
8408
  if (!stickRef.current) return;
@@ -8445,9 +8626,8 @@ function Checkpoint({
8445
8626
  }
8446
8627
 
8447
8628
  // src/components/Tilemap.tsx
8448
- import { useEffect as useEffect29, useState as useState6, useContext as useContext20 } from "react";
8629
+ import { useEffect as useEffect30, useState as useState6, useContext as useContext20 } from "react";
8449
8630
  import { Fragment as Fragment5, jsx as jsx10 } from "react/jsx-runtime";
8450
- var animatedTiles = /* @__PURE__ */ new Map();
8451
8631
  function getProperty(props, name) {
8452
8632
  return props?.find((p) => p.name === name)?.value;
8453
8633
  }
@@ -8476,9 +8656,10 @@ function Tilemap({
8476
8656
  }) {
8477
8657
  const engine = useContext20(EngineContext);
8478
8658
  const [spawnedNodes, setSpawnedNodes] = useState6([]);
8479
- useEffect29(() => {
8659
+ useEffect30(() => {
8480
8660
  if (!engine) return;
8481
8661
  const createdEntities = [];
8662
+ const animatedTiles = /* @__PURE__ */ new Map();
8482
8663
  async function load() {
8483
8664
  let mapData;
8484
8665
  try {
@@ -8614,6 +8795,7 @@ function Tilemap({
8614
8795
  if (frame) {
8615
8796
  sprite.frame = { sx: frame.sx, sy: frame.sy, sw: frame.sw, sh: frame.sh };
8616
8797
  engine.assets.loadImage(frame.imageSrc).then((img) => {
8798
+ if (!engine.ecs.hasEntity(eid)) return;
8617
8799
  const s2 = engine.ecs.getComponent(eid, "Sprite");
8618
8800
  if (s2) s2.image = img;
8619
8801
  }).catch(() => {
@@ -8629,6 +8811,7 @@ function Tilemap({
8629
8811
  animatedTiles.set(eid, state);
8630
8812
  const firstFrameRegion = getFrameForLocalId(resolved.tileset, frames[0]);
8631
8813
  engine.assets.loadImage(firstFrameRegion.imageSrc).then((img) => {
8814
+ if (!engine.ecs.hasEntity(eid)) return;
8632
8815
  const s2 = engine.ecs.getComponent(eid, "Sprite");
8633
8816
  if (s2) {
8634
8817
  s2.image = img;
@@ -8696,7 +8879,7 @@ function Tilemap({
8696
8879
  }
8697
8880
 
8698
8881
  // src/components/ParallaxLayer.tsx
8699
- import { useEffect as useEffect30, useContext as useContext21 } from "react";
8882
+ import { useEffect as useEffect31, useContext as useContext21 } from "react";
8700
8883
  import { jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
8701
8884
  function ParallaxLayerInner({
8702
8885
  src,
@@ -8710,7 +8893,7 @@ function ParallaxLayerInner({
8710
8893
  }) {
8711
8894
  const engine = useContext21(EngineContext);
8712
8895
  const entityId = useContext21(EntityContext);
8713
- useEffect30(() => {
8896
+ useEffect31(() => {
8714
8897
  engine.ecs.addComponent(entityId, {
8715
8898
  type: "ParallaxLayer",
8716
8899
  src,
@@ -8726,7 +8909,7 @@ function ParallaxLayerInner({
8726
8909
  });
8727
8910
  return () => engine.ecs.removeComponent(entityId, "ParallaxLayer");
8728
8911
  }, []);
8729
- useEffect30(() => {
8912
+ useEffect31(() => {
8730
8913
  const layer = engine.ecs.getComponent(entityId, "ParallaxLayer");
8731
8914
  if (!layer) return;
8732
8915
  layer.src = src;
@@ -8769,10 +8952,10 @@ function ParallaxLayer({
8769
8952
  }
8770
8953
 
8771
8954
  // src/components/ScreenFlash.tsx
8772
- import { forwardRef, useImperativeHandle, useRef as useRef15 } from "react";
8955
+ import { forwardRef, useImperativeHandle, useRef as useRef16 } from "react";
8773
8956
  import { jsx as jsx12 } from "react/jsx-runtime";
8774
8957
  var ScreenFlash = forwardRef((_, ref) => {
8775
- const divRef = useRef15(null);
8958
+ const divRef = useRef16(null);
8776
8959
  useImperativeHandle(ref, () => ({
8777
8960
  flash(color, duration) {
8778
8961
  const el = divRef.current;
@@ -8808,13 +8991,13 @@ var ScreenFlash = forwardRef((_, ref) => {
8808
8991
  ScreenFlash.displayName = "ScreenFlash";
8809
8992
 
8810
8993
  // src/components/CameraZone.tsx
8811
- import { useEffect as useEffect31, useContext as useContext22, useRef as useRef16 } from "react";
8994
+ import { useEffect as useEffect32, useContext as useContext22, useRef as useRef17 } from "react";
8812
8995
  import { Fragment as Fragment6, jsx as jsx13 } from "react/jsx-runtime";
8813
8996
  function CameraZone({ x, y, width, height, watchTag = "player", targetX, targetY, children }) {
8814
8997
  const engine = useContext22(EngineContext);
8815
- const prevFollowRef = useRef16(void 0);
8816
- const activeRef = useRef16(false);
8817
- useEffect31(() => {
8998
+ const prevFollowRef = useRef17(void 0);
8999
+ const activeRef = useRef17(false);
9000
+ useEffect32(() => {
8818
9001
  const eid = engine.ecs.createEntity();
8819
9002
  engine.ecs.addComponent(
8820
9003
  eid,
@@ -8864,7 +9047,7 @@ function CameraZone({ x, y, width, height, watchTag = "player", targetX, targetY
8864
9047
  }
8865
9048
 
8866
9049
  // src/components/VirtualCamera.tsx
8867
- import { useEffect as useEffect32, useContext as useContext23 } from "react";
9050
+ import { useEffect as useEffect33, useContext as useContext23 } from "react";
8868
9051
  var registries = /* @__PURE__ */ new WeakMap();
8869
9052
  var driverEids = /* @__PURE__ */ new WeakMap();
8870
9053
  var driverRefs = /* @__PURE__ */ new WeakMap();
@@ -8966,7 +9149,7 @@ function VirtualCamera({
8966
9149
  blendDuration = 0.4
8967
9150
  }) {
8968
9151
  const engine = useContext23(EngineContext);
8969
- useEffect32(() => {
9152
+ useEffect33(() => {
8970
9153
  acquireDriver(engine);
8971
9154
  const registry2 = getRegistry(engine);
8972
9155
  registry2.set(id, {
@@ -8986,7 +9169,7 @@ function VirtualCamera({
8986
9169
  releaseDriver(engine);
8987
9170
  };
8988
9171
  }, []);
8989
- useEffect32(() => {
9172
+ useEffect33(() => {
8990
9173
  const entry = getRegistry(engine).get(id);
8991
9174
  if (!entry) return;
8992
9175
  entry.priority = priority;
@@ -9003,11 +9186,11 @@ function VirtualCamera({
9003
9186
  }
9004
9187
 
9005
9188
  // src/components/Trail.tsx
9006
- import { useEffect as useEffect33, useContext as useContext24 } from "react";
9189
+ import { useEffect as useEffect34, useContext as useContext24 } from "react";
9007
9190
  function Trail({ length = 20, color = "#ffffff", width = 3 }) {
9008
9191
  const engine = useContext24(EngineContext);
9009
9192
  const entityId = useContext24(EntityContext);
9010
- useEffect33(() => {
9193
+ useEffect34(() => {
9011
9194
  engine.ecs.addComponent(entityId, createTrail({ length, color, width }));
9012
9195
  return () => engine.ecs.removeComponent(entityId, "Trail");
9013
9196
  }, []);
@@ -9015,7 +9198,7 @@ function Trail({ length = 20, color = "#ffffff", width = 3 }) {
9015
9198
  }
9016
9199
 
9017
9200
  // src/components/NineSlice.tsx
9018
- import { useEffect as useEffect34, useContext as useContext25 } from "react";
9201
+ import { useEffect as useEffect35, useContext as useContext25 } from "react";
9019
9202
  function NineSlice({
9020
9203
  src,
9021
9204
  width,
@@ -9028,7 +9211,7 @@ function NineSlice({
9028
9211
  }) {
9029
9212
  const engine = useContext25(EngineContext);
9030
9213
  const entityId = useContext25(EntityContext);
9031
- useEffect34(() => {
9214
+ useEffect35(() => {
9032
9215
  engine.ecs.addComponent(
9033
9216
  entityId,
9034
9217
  createNineSlice(src, width, height, {
@@ -9045,10 +9228,10 @@ function NineSlice({
9045
9228
  }
9046
9229
 
9047
9230
  // src/components/AssetLoader.tsx
9048
- import { useEffect as useEffect36 } from "react";
9231
+ import { useEffect as useEffect37 } from "react";
9049
9232
 
9050
9233
  // src/hooks/usePreload.ts
9051
- import { useState as useState7, useEffect as useEffect35, useContext as useContext26 } from "react";
9234
+ import { useState as useState7, useEffect as useEffect36, useContext as useContext26 } from "react";
9052
9235
  function usePreload(assets) {
9053
9236
  const engine = useContext26(EngineContext);
9054
9237
  const [state, setState] = useState7({
@@ -9056,7 +9239,7 @@ function usePreload(assets) {
9056
9239
  loaded: assets.length === 0,
9057
9240
  error: null
9058
9241
  });
9059
- useEffect35(() => {
9242
+ useEffect36(() => {
9060
9243
  if (assets.length === 0) {
9061
9244
  setState({ progress: 1, loaded: true, error: null });
9062
9245
  return;
@@ -9093,7 +9276,7 @@ function usePreload(assets) {
9093
9276
  import { Fragment as Fragment7, jsx as jsx14 } from "react/jsx-runtime";
9094
9277
  function AssetLoader({ assets, fallback = null, onError, children }) {
9095
9278
  const { loaded, error } = usePreload(assets);
9096
- useEffect36(() => {
9279
+ useEffect37(() => {
9097
9280
  if (error && onError) onError(error);
9098
9281
  }, [error, onError]);
9099
9282
  if (!loaded) {
@@ -9103,7 +9286,7 @@ function AssetLoader({ assets, fallback = null, onError, children }) {
9103
9286
  }
9104
9287
 
9105
9288
  // src/components/Circle.tsx
9106
- import { useEffect as useEffect37, useContext as useContext27 } from "react";
9289
+ import { useEffect as useEffect38, useContext as useContext27 } from "react";
9107
9290
  function Circle({
9108
9291
  radius = 16,
9109
9292
  color = "#ffffff",
@@ -9114,7 +9297,7 @@ function Circle({
9114
9297
  }) {
9115
9298
  const engine = useContext27(EngineContext);
9116
9299
  const entityId = useContext27(EntityContext);
9117
- useEffect37(() => {
9300
+ useEffect38(() => {
9118
9301
  const comp = createCircleShape({
9119
9302
  radius,
9120
9303
  color,
@@ -9126,7 +9309,7 @@ function Circle({
9126
9309
  engine.ecs.addComponent(entityId, comp);
9127
9310
  return () => engine.ecs.removeComponent(entityId, "CircleShape");
9128
9311
  }, []);
9129
- useEffect37(() => {
9312
+ useEffect38(() => {
9130
9313
  const comp = engine.ecs.getComponent(entityId, "CircleShape");
9131
9314
  if (!comp) return;
9132
9315
  comp.radius = radius;
@@ -9140,7 +9323,7 @@ function Circle({
9140
9323
  }
9141
9324
 
9142
9325
  // src/components/Line.tsx
9143
- import { useEffect as useEffect38, useContext as useContext28 } from "react";
9326
+ import { useEffect as useEffect39, useContext as useContext28 } from "react";
9144
9327
  function Line({
9145
9328
  endX,
9146
9329
  endY,
@@ -9152,7 +9335,7 @@ function Line({
9152
9335
  }) {
9153
9336
  const engine = useContext28(EngineContext);
9154
9337
  const entityId = useContext28(EntityContext);
9155
- useEffect38(() => {
9338
+ useEffect39(() => {
9156
9339
  const comp = createLineShape({
9157
9340
  endX,
9158
9341
  endY,
@@ -9165,7 +9348,7 @@ function Line({
9165
9348
  engine.ecs.addComponent(entityId, comp);
9166
9349
  return () => engine.ecs.removeComponent(entityId, "LineShape");
9167
9350
  }, []);
9168
- useEffect38(() => {
9351
+ useEffect39(() => {
9169
9352
  const comp = engine.ecs.getComponent(entityId, "LineShape");
9170
9353
  if (!comp) return;
9171
9354
  comp.endX = endX;
@@ -9180,7 +9363,7 @@ function Line({
9180
9363
  }
9181
9364
 
9182
9365
  // src/components/Polygon.tsx
9183
- import { useEffect as useEffect39, useContext as useContext29 } from "react";
9366
+ import { useEffect as useEffect40, useContext as useContext29 } from "react";
9184
9367
  function Polygon({
9185
9368
  points,
9186
9369
  color = "#ffffff",
@@ -9192,7 +9375,7 @@ function Polygon({
9192
9375
  }) {
9193
9376
  const engine = useContext29(EngineContext);
9194
9377
  const entityId = useContext29(EntityContext);
9195
- useEffect39(() => {
9378
+ useEffect40(() => {
9196
9379
  const comp = createPolygonShape({
9197
9380
  points,
9198
9381
  color,
@@ -9205,7 +9388,7 @@ function Polygon({
9205
9388
  engine.ecs.addComponent(entityId, comp);
9206
9389
  return () => engine.ecs.removeComponent(entityId, "PolygonShape");
9207
9390
  }, []);
9208
- useEffect39(() => {
9391
+ useEffect40(() => {
9209
9392
  const comp = engine.ecs.getComponent(entityId, "PolygonShape");
9210
9393
  if (!comp) return;
9211
9394
  comp.points = points;
@@ -9220,7 +9403,7 @@ function Polygon({
9220
9403
  }
9221
9404
 
9222
9405
  // src/components/Gradient.tsx
9223
- import { useEffect as useEffect40, useContext as useContext30 } from "react";
9406
+ import { useEffect as useEffect41, useContext as useContext30 } from "react";
9224
9407
  function Gradient({
9225
9408
  gradientType = "linear",
9226
9409
  stops,
@@ -9235,7 +9418,7 @@ function Gradient({
9235
9418
  }) {
9236
9419
  const engine = useContext30(EngineContext);
9237
9420
  const entityId = useContext30(EntityContext);
9238
- useEffect40(() => {
9421
+ useEffect41(() => {
9239
9422
  const comp = createGradient({
9240
9423
  gradientType,
9241
9424
  stops,
@@ -9251,7 +9434,7 @@ function Gradient({
9251
9434
  engine.ecs.addComponent(entityId, comp);
9252
9435
  return () => engine.ecs.removeComponent(entityId, "Gradient");
9253
9436
  }, []);
9254
- useEffect40(() => {
9437
+ useEffect41(() => {
9255
9438
  const comp = engine.ecs.getComponent(entityId, "Gradient");
9256
9439
  if (!comp) return;
9257
9440
  comp.gradientType = gradientType;
@@ -9265,16 +9448,16 @@ function Gradient({
9265
9448
  }
9266
9449
 
9267
9450
  // src/components/Mask.tsx
9268
- import { useEffect as useEffect41, useContext as useContext31 } from "react";
9451
+ import { useEffect as useEffect42, useContext as useContext31 } from "react";
9269
9452
  function Mask({ shape = "rect", width = 64, height = 64, radius = 32, inverted = false }) {
9270
9453
  const engine = useContext31(EngineContext);
9271
9454
  const entityId = useContext31(EntityContext);
9272
- useEffect41(() => {
9455
+ useEffect42(() => {
9273
9456
  const comp = createMask({ shape, width, height, radius, inverted });
9274
9457
  engine.ecs.addComponent(entityId, comp);
9275
9458
  return () => engine.ecs.removeComponent(entityId, "Mask");
9276
9459
  }, []);
9277
- useEffect41(() => {
9460
+ useEffect42(() => {
9278
9461
  const comp = engine.ecs.getComponent(entityId, "Mask");
9279
9462
  if (!comp) return;
9280
9463
  comp.shape = shape;
@@ -9287,11 +9470,11 @@ function Mask({ shape = "rect", width = 64, height = 64, radius = 32, inverted =
9287
9470
  }
9288
9471
 
9289
9472
  // src/components/Joint.tsx
9290
- import { useEffect as useEffect42, useContext as useContext32 } from "react";
9473
+ import { useEffect as useEffect43, useContext as useContext32 } from "react";
9291
9474
  function Joint({ type, target, anchorA, anchorB, length, stiffness, damping, maxLength }) {
9292
9475
  const engine = useContext32(EngineContext);
9293
9476
  const entityId = useContext32(EntityContext);
9294
- useEffect42(() => {
9477
+ useEffect43(() => {
9295
9478
  const checkId = setTimeout(() => {
9296
9479
  const targetEntityId = engine.entityIds.get(target);
9297
9480
  if (!targetEntityId) {
@@ -9326,7 +9509,7 @@ function Joint({ type, target, anchorA, anchorB, length, stiffness, damping, max
9326
9509
  }
9327
9510
 
9328
9511
  // src/components/ConvexCollider.tsx
9329
- import { useEffect as useEffect43, useContext as useContext33 } from "react";
9512
+ import { useEffect as useEffect44, useContext as useContext33 } from "react";
9330
9513
  function ConvexCollider({
9331
9514
  vertices,
9332
9515
  offsetX = 0,
@@ -9342,7 +9525,7 @@ function ConvexCollider({
9342
9525
  }) {
9343
9526
  const engine = useContext33(EngineContext);
9344
9527
  const entityId = useContext33(EntityContext);
9345
- useEffect43(() => {
9528
+ useEffect44(() => {
9346
9529
  engine.ecs.addComponent(
9347
9530
  entityId,
9348
9531
  createConvexPolygonCollider(vertices, {
@@ -9364,7 +9547,7 @@ function ConvexCollider({
9364
9547
  }
9365
9548
 
9366
9549
  // src/components/TriangleCollider.tsx
9367
- import { useEffect as useEffect44, useContext as useContext34 } from "react";
9550
+ import { useEffect as useEffect45, useContext as useContext34 } from "react";
9368
9551
  function TriangleCollider({
9369
9552
  a,
9370
9553
  b,
@@ -9382,7 +9565,7 @@ function TriangleCollider({
9382
9565
  }) {
9383
9566
  const engine = useContext34(EngineContext);
9384
9567
  const entityId = useContext34(EntityContext);
9385
- useEffect44(() => {
9568
+ useEffect45(() => {
9386
9569
  engine.ecs.addComponent(
9387
9570
  entityId,
9388
9571
  createTriangleCollider(a, b, c, {
@@ -9404,7 +9587,7 @@ function TriangleCollider({
9404
9587
  }
9405
9588
 
9406
9589
  // src/components/SegmentCollider.tsx
9407
- import { useEffect as useEffect45, useContext as useContext35 } from "react";
9590
+ import { useEffect as useEffect46, useContext as useContext35 } from "react";
9408
9591
  function SegmentCollider({
9409
9592
  start: start2,
9410
9593
  end,
@@ -9420,7 +9603,7 @@ function SegmentCollider({
9420
9603
  }) {
9421
9604
  const engine = useContext35(EngineContext);
9422
9605
  const entityId = useContext35(EntityContext);
9423
- useEffect45(() => {
9606
+ useEffect46(() => {
9424
9607
  engine.ecs.addComponent(
9425
9608
  entityId,
9426
9609
  createSegmentCollider(start2, end, {
@@ -9441,7 +9624,7 @@ function SegmentCollider({
9441
9624
  }
9442
9625
 
9443
9626
  // src/components/HeightFieldCollider.tsx
9444
- import { useEffect as useEffect46, useContext as useContext36 } from "react";
9627
+ import { useEffect as useEffect47, useContext as useContext36 } from "react";
9445
9628
  function HeightFieldCollider({
9446
9629
  heights,
9447
9630
  scaleX = 1,
@@ -9456,7 +9639,7 @@ function HeightFieldCollider({
9456
9639
  }) {
9457
9640
  const engine = useContext36(EngineContext);
9458
9641
  const entityId = useContext36(EntityContext);
9459
- useEffect46(() => {
9642
+ useEffect47(() => {
9460
9643
  engine.ecs.addComponent(
9461
9644
  entityId,
9462
9645
  createHeightFieldCollider(heights, {
@@ -9477,7 +9660,7 @@ function HeightFieldCollider({
9477
9660
  }
9478
9661
 
9479
9662
  // src/components/HalfSpaceCollider.tsx
9480
- import { useEffect as useEffect47, useContext as useContext37 } from "react";
9663
+ import { useEffect as useEffect48, useContext as useContext37 } from "react";
9481
9664
  function HalfSpaceCollider({
9482
9665
  normalX = 0,
9483
9666
  normalY = -1,
@@ -9491,7 +9674,7 @@ function HalfSpaceCollider({
9491
9674
  }) {
9492
9675
  const engine = useContext37(EngineContext);
9493
9676
  const entityId = useContext37(EntityContext);
9494
- useEffect47(() => {
9677
+ useEffect48(() => {
9495
9678
  engine.ecs.addComponent(
9496
9679
  entityId,
9497
9680
  createHalfSpaceCollider({
@@ -9512,7 +9695,7 @@ function HalfSpaceCollider({
9512
9695
  }
9513
9696
 
9514
9697
  // src/components/TriMeshCollider.tsx
9515
- import { useEffect as useEffect48, useContext as useContext38 } from "react";
9698
+ import { useEffect as useEffect49, useContext as useContext38 } from "react";
9516
9699
  function TriMeshCollider({
9517
9700
  vertices,
9518
9701
  indices,
@@ -9526,7 +9709,7 @@ function TriMeshCollider({
9526
9709
  }) {
9527
9710
  const engine = useContext38(EngineContext);
9528
9711
  const entityId = useContext38(EntityContext);
9529
- useEffect48(() => {
9712
+ useEffect49(() => {
9530
9713
  engine.ecs.addComponent(
9531
9714
  entityId,
9532
9715
  createTriMeshCollider(vertices, indices, {
@@ -9609,11 +9792,11 @@ function useCamera() {
9609
9792
  }
9610
9793
 
9611
9794
  // src/hooks/useCameraLookahead.ts
9612
- import { useContext as useContext40, useEffect as useEffect49 } from "react";
9795
+ import { useContext as useContext40, useEffect as useEffect50 } from "react";
9613
9796
  function useCameraLookahead(entityId, opts = {}) {
9614
9797
  const engine = useContext40(EngineContext);
9615
9798
  const { distance = 100, smoothing = 3, vertical = false } = opts;
9616
- useEffect49(() => {
9799
+ useEffect50(() => {
9617
9800
  let offsetX = 0;
9618
9801
  let offsetY = 0;
9619
9802
  const script = createScript((id, world, _input, dt) => {
@@ -9699,17 +9882,17 @@ function useCameraBlend() {
9699
9882
  }
9700
9883
 
9701
9884
  // src/hooks/useCinematicSequence.ts
9702
- import { useEffect as useEffect50, useRef as useRef17, useCallback as useCallback2, useState as useState8, useContext as useContext41 } from "react";
9885
+ import { useEffect as useEffect51, useRef as useRef18, useCallback as useCallback3, useState as useState8, useContext as useContext41 } from "react";
9703
9886
  function useCinematicSequence(steps, opts) {
9704
9887
  const engine = useContext41(EngineContext);
9705
- const stepsRef = useRef17(steps);
9888
+ const stepsRef = useRef18(steps);
9706
9889
  stepsRef.current = steps;
9707
- const optsRef = useRef17(opts);
9890
+ const optsRef = useRef18(opts);
9708
9891
  optsRef.current = opts;
9709
9892
  const [isPlaying, setIsPlaying] = useState8(false);
9710
9893
  const [currentStep, setCurrentStep] = useState8(-1);
9711
- const stateRef = useRef17({ playing: false, step: -1, elapsed: 0, scriptEid: null });
9712
- const activateStep = useCallback2(
9894
+ const stateRef = useRef18({ playing: false, step: -1, elapsed: 0, scriptEid: null });
9895
+ const activateStep = useCallback3(
9713
9896
  (idx) => {
9714
9897
  const steps2 = stepsRef.current;
9715
9898
  if (idx < 0 || idx >= steps2.length) return;
@@ -9729,7 +9912,7 @@ function useCinematicSequence(steps, opts) {
9729
9912
  },
9730
9913
  [engine]
9731
9914
  );
9732
- const play = useCallback2(() => {
9915
+ const play = useCallback3(() => {
9733
9916
  const state = stateRef.current;
9734
9917
  state.playing = true;
9735
9918
  state.step = 0;
@@ -9738,7 +9921,7 @@ function useCinematicSequence(steps, opts) {
9738
9921
  setCurrentStep(0);
9739
9922
  activateStep(0);
9740
9923
  }, [activateStep]);
9741
- const stop = useCallback2(() => {
9924
+ const stop = useCallback3(() => {
9742
9925
  const state = stateRef.current;
9743
9926
  if (!state.playing) return;
9744
9927
  state.playing = false;
@@ -9750,7 +9933,7 @@ function useCinematicSequence(steps, opts) {
9750
9933
  if (entry) entry.active = false;
9751
9934
  }
9752
9935
  }, [engine]);
9753
- useEffect50(() => {
9936
+ useEffect51(() => {
9754
9937
  const state = stateRef.current;
9755
9938
  const eid = engine.ecs.createEntity();
9756
9939
  state.scriptEid = eid;
@@ -9819,13 +10002,13 @@ function useEntity() {
9819
10002
  }
9820
10003
 
9821
10004
  // src/hooks/useDestroyEntity.ts
9822
- import { useCallback as useCallback3, useContext as useContext43 } from "react";
10005
+ import { useCallback as useCallback4, useContext as useContext43 } from "react";
9823
10006
  function useDestroyEntity() {
9824
10007
  const engine = useContext43(EngineContext);
9825
10008
  const entityId = useContext43(EntityContext);
9826
10009
  if (!engine) throw new Error("useDestroyEntity must be used inside <Game>");
9827
10010
  if (entityId === null) throw new Error("useDestroyEntity must be used inside <Entity>");
9828
- return useCallback3(() => {
10011
+ return useCallback4(() => {
9829
10012
  if (engine.ecs.hasEntity(entityId)) {
9830
10013
  engine.ecs.destroyEntity(entityId);
9831
10014
  }
@@ -9858,7 +10041,7 @@ function useInputMap(bindings) {
9858
10041
  }
9859
10042
 
9860
10043
  // src/hooks/useEvents.ts
9861
- import { useContext as useContext45, useEffect as useEffect51, useRef as useRef18 } from "react";
10044
+ import { useContext as useContext45, useEffect as useEffect52, useRef as useRef19 } from "react";
9862
10045
  function useEvents() {
9863
10046
  const engine = useContext45(EngineContext);
9864
10047
  if (!engine) throw new Error("useEvents must be used inside <Game>");
@@ -9866,18 +10049,18 @@ function useEvents() {
9866
10049
  }
9867
10050
  function useEvent(event, handler) {
9868
10051
  const events = useEvents();
9869
- const handlerRef = useRef18(handler);
10052
+ const handlerRef = useRef19(handler);
9870
10053
  handlerRef.current = handler;
9871
- useEffect51(() => {
10054
+ useEffect52(() => {
9872
10055
  return events.on(event, (data) => handlerRef.current(data));
9873
10056
  }, [events, event]);
9874
10057
  }
9875
10058
 
9876
10059
  // src/hooks/useCoordinates.ts
9877
- import { useCallback as useCallback4, useContext as useContext46 } from "react";
10060
+ import { useCallback as useCallback5, useContext as useContext46 } from "react";
9878
10061
  function useCoordinates() {
9879
10062
  const engine = useContext46(EngineContext);
9880
- const worldToScreen = useCallback4(
10063
+ const worldToScreen = useCallback5(
9881
10064
  (wx, wy) => {
9882
10065
  const canvas = engine.canvas;
9883
10066
  const camId = engine.ecs.queryOne("Camera2D");
@@ -9891,7 +10074,7 @@ function useCoordinates() {
9891
10074
  },
9892
10075
  [engine.ecs, engine.canvas]
9893
10076
  );
9894
- const screenToWorld3 = useCallback4(
10077
+ const screenToWorld3 = useCallback5(
9895
10078
  (sx, sy) => {
9896
10079
  const canvas = engine.canvas;
9897
10080
  const camId = engine.ecs.queryOne("Camera2D");
@@ -9909,14 +10092,14 @@ function useCoordinates() {
9909
10092
  }
9910
10093
 
9911
10094
  // src/hooks/useWorldQuery.ts
9912
- import { useEffect as useEffect52, useRef as useRef19, useState as useState9 } from "react";
10095
+ import { useEffect as useEffect53, useRef as useRef20, useState as useState9 } from "react";
9913
10096
  function useWorldQuery(...components) {
9914
10097
  const engine = useGame();
9915
10098
  const [result, setResult] = useState9(() => engine.ecs.query(...components));
9916
- const prevRef = useRef19([]);
9917
- const rafRef = useRef19(0);
9918
- const mountedRef = useRef19(true);
9919
- useEffect52(() => {
10099
+ const prevRef = useRef20([]);
10100
+ const rafRef = useRef20(0);
10101
+ const mountedRef = useRef20(true);
10102
+ useEffect53(() => {
9920
10103
  mountedRef.current = true;
9921
10104
  const tick2 = () => {
9922
10105
  if (!mountedRef.current) return;
@@ -9938,9 +10121,9 @@ function useWorldQuery(...components) {
9938
10121
  }
9939
10122
 
9940
10123
  // src/hooks/useInputContext.ts
9941
- import { useEffect as useEffect53, useMemo as useMemo5 } from "react";
10124
+ import { useEffect as useEffect54, useMemo as useMemo5 } from "react";
9942
10125
  function useInputContext(ctx) {
9943
- useEffect53(() => {
10126
+ useEffect54(() => {
9944
10127
  if (!ctx) return;
9945
10128
  globalInputContext.push(ctx);
9946
10129
  return () => globalInputContext.pop(ctx);
@@ -9982,12 +10165,12 @@ function useInputRecorder() {
9982
10165
  }
9983
10166
 
9984
10167
  // src/hooks/useGamepad.ts
9985
- import { useEffect as useEffect54, useRef as useRef20, useState as useState10 } from "react";
10168
+ import { useEffect as useEffect55, useRef as useRef21, useState as useState10 } from "react";
9986
10169
  var EMPTY_STATE = { connected: false, axes: [], buttons: [] };
9987
10170
  function useGamepad(playerIndex = 0) {
9988
10171
  const [state, setState] = useState10(EMPTY_STATE);
9989
- const rafRef = useRef20(0);
9990
- useEffect54(() => {
10172
+ const rafRef = useRef21(0);
10173
+ useEffect55(() => {
9991
10174
  const poll = () => {
9992
10175
  const gp = navigator.getGamepads()[playerIndex];
9993
10176
  if (gp) {
@@ -10008,19 +10191,19 @@ function useGamepad(playerIndex = 0) {
10008
10191
  }
10009
10192
 
10010
10193
  // src/hooks/usePause.ts
10011
- import { useContext as useContext47, useState as useState11, useCallback as useCallback5 } from "react";
10194
+ import { useContext as useContext47, useState as useState11, useCallback as useCallback6 } from "react";
10012
10195
  function usePause() {
10013
10196
  const engine = useContext47(EngineContext);
10014
10197
  const [paused, setPaused] = useState11(false);
10015
- const pause = useCallback5(() => {
10198
+ const pause = useCallback6(() => {
10016
10199
  engine.loop.pause();
10017
10200
  setPaused(true);
10018
10201
  }, [engine]);
10019
- const resume = useCallback5(() => {
10202
+ const resume = useCallback6(() => {
10020
10203
  engine.loop.resume();
10021
10204
  setPaused(false);
10022
10205
  }, [engine]);
10023
- const toggle = useCallback5(() => {
10206
+ const toggle = useCallback6(() => {
10024
10207
  if (engine.loop.isPaused) resume();
10025
10208
  else pause();
10026
10209
  }, [engine, pause, resume]);
@@ -10028,7 +10211,7 @@ function usePause() {
10028
10211
  }
10029
10212
 
10030
10213
  // src/hooks/useProfiler.ts
10031
- import { useContext as useContext48, useEffect as useEffect55, useRef as useRef21, useState as useState12 } from "react";
10214
+ import { useContext as useContext48, useEffect as useEffect56, useRef as useRef22, useState as useState12 } from "react";
10032
10215
  var EMPTY = {
10033
10216
  fps: 0,
10034
10217
  frameTime: 0,
@@ -10038,10 +10221,10 @@ var EMPTY = {
10038
10221
  function useProfiler() {
10039
10222
  const engine = useContext48(EngineContext);
10040
10223
  const [data, setData] = useState12(EMPTY);
10041
- const frameTimesRef = useRef21([]);
10042
- const lastUpdateRef = useRef21(0);
10043
- const prevTimeRef = useRef21(0);
10044
- useEffect55(() => {
10224
+ const frameTimesRef = useRef22([]);
10225
+ const lastUpdateRef = useRef22(0);
10226
+ const prevTimeRef = useRef22(0);
10227
+ useEffect56(() => {
10045
10228
  if (!engine) return;
10046
10229
  let rafId2;
10047
10230
  const frameTimes = frameTimesRef.current;
@@ -10081,10 +10264,10 @@ function useProfiler() {
10081
10264
  }
10082
10265
 
10083
10266
  // src/hooks/usePostProcess.ts
10084
- import { useEffect as useEffect56 } from "react";
10267
+ import { useEffect as useEffect57 } from "react";
10085
10268
  function usePostProcess(effect) {
10086
10269
  const engine = useGame();
10087
- useEffect56(() => {
10270
+ useEffect57(() => {
10088
10271
  engine.postProcessStack.add(effect);
10089
10272
  return () => {
10090
10273
  engine.postProcessStack.remove(effect);
@@ -10093,11 +10276,11 @@ function usePostProcess(effect) {
10093
10276
  }
10094
10277
 
10095
10278
  // src/hooks/useWebGLPostProcess.ts
10096
- import { useEffect as useEffect57, useMemo as useMemo9 } from "react";
10279
+ import { useEffect as useEffect58, useMemo as useMemo9 } from "react";
10097
10280
  function useWebGLPostProcess(opts) {
10098
10281
  const engine = useGame();
10099
10282
  const optsKey = useMemo9(() => JSON.stringify(opts), [JSON.stringify(opts)]);
10100
- useEffect57(() => {
10283
+ useEffect58(() => {
10101
10284
  const rs = engine.activeRenderSystem;
10102
10285
  rs.setPostProcessOptions?.(opts);
10103
10286
  return () => {
@@ -10107,10 +10290,10 @@ function useWebGLPostProcess(opts) {
10107
10290
  }
10108
10291
 
10109
10292
  // src/hooks/useAudioListener.ts
10110
- import { useEffect as useEffect58, useContext as useContext49 } from "react";
10293
+ import { useEffect as useEffect59, useContext as useContext49 } from "react";
10111
10294
  function useAudioListener() {
10112
10295
  const engine = useContext49(EngineContext);
10113
- useEffect58(() => {
10296
+ useEffect59(() => {
10114
10297
  const eid = engine.ecs.createEntity();
10115
10298
  engine.ecs.addComponent(
10116
10299
  eid,
@@ -10154,13 +10337,13 @@ function useTouch() {
10154
10337
  }
10155
10338
 
10156
10339
  // src/hooks/useGestures.ts
10157
- import { useEffect as useEffect59, useRef as useRef22 } from "react";
10340
+ import { useEffect as useEffect60, useRef as useRef23 } from "react";
10158
10341
  function useGestures(handlers, opts = {}) {
10159
- const handlersRef = useRef22(handlers);
10342
+ const handlersRef = useRef23(handlers);
10160
10343
  handlersRef.current = handlers;
10161
- const optsRef = useRef22(opts);
10344
+ const optsRef = useRef23(opts);
10162
10345
  optsRef.current = opts;
10163
- useEffect59(() => {
10346
+ useEffect60(() => {
10164
10347
  const target = optsRef.current.target ?? window;
10165
10348
  let starts = [];
10166
10349
  let longPressTimer = null;
@@ -10320,14 +10503,14 @@ var touchHapticsControls = {
10320
10503
  };
10321
10504
 
10322
10505
  // src/hooks/useTimer.ts
10323
- import { useRef as useRef23, useCallback as useCallback6, useEffect as useEffect60, useContext as useContext51 } from "react";
10506
+ import { useRef as useRef24, useCallback as useCallback7, useEffect as useEffect61, useContext as useContext51 } from "react";
10324
10507
  function useTimer(duration, onComplete, opts) {
10325
10508
  const engine = useContext51(EngineContext);
10326
- const onCompleteRef = useRef23(onComplete);
10509
+ const onCompleteRef = useRef24(onComplete);
10327
10510
  onCompleteRef.current = onComplete;
10328
- const loopRef = useRef23(opts?.loop ?? false);
10511
+ const loopRef = useRef24(opts?.loop ?? false);
10329
10512
  loopRef.current = opts?.loop ?? false;
10330
- const timerRef = useRef23(null);
10513
+ const timerRef = useRef24(null);
10331
10514
  if (!timerRef.current) {
10332
10515
  timerRef.current = createTimer(
10333
10516
  duration,
@@ -10340,7 +10523,7 @@ function useTimer(duration, onComplete, opts) {
10340
10523
  opts?.autoStart ?? false
10341
10524
  );
10342
10525
  }
10343
- useEffect60(() => {
10526
+ useEffect61(() => {
10344
10527
  const eid = engine.ecs.createEntity();
10345
10528
  engine.ecs.addComponent(
10346
10529
  eid,
@@ -10352,13 +10535,13 @@ function useTimer(duration, onComplete, opts) {
10352
10535
  if (engine.ecs.hasEntity(eid)) engine.ecs.destroyEntity(eid);
10353
10536
  };
10354
10537
  }, [engine.ecs]);
10355
- const start2 = useCallback6(() => {
10538
+ const start2 = useCallback7(() => {
10356
10539
  timerRef.current.start();
10357
10540
  }, []);
10358
- const stop = useCallback6(() => {
10541
+ const stop = useCallback7(() => {
10359
10542
  timerRef.current.stop();
10360
10543
  }, []);
10361
- const reset = useCallback6(() => {
10544
+ const reset = useCallback7(() => {
10362
10545
  timerRef.current.reset();
10363
10546
  }, []);
10364
10547
  return {
@@ -10381,15 +10564,15 @@ function useTimer(duration, onComplete, opts) {
10381
10564
  }
10382
10565
 
10383
10566
  // src/hooks/useCoroutine.ts
10384
- import { useRef as useRef24, useEffect as useEffect61, useContext as useContext52 } from "react";
10567
+ import { useRef as useRef25, useEffect as useEffect62, useContext as useContext52 } from "react";
10385
10568
  var wait = (seconds) => ({ type: "wait", seconds });
10386
10569
  var waitFrames = (frames) => ({ type: "waitFrames", frames });
10387
10570
  var waitUntil = (condition) => ({ type: "waitUntil", condition });
10388
10571
  var nextCoroutineId = 1;
10389
10572
  function useCoroutine() {
10390
10573
  const engine = useContext52(EngineContext);
10391
- const coroutinesRef = useRef24(/* @__PURE__ */ new Map());
10392
- useEffect61(() => {
10574
+ const coroutinesRef = useRef25(/* @__PURE__ */ new Map());
10575
+ useEffect62(() => {
10393
10576
  const eid = engine.ecs.createEntity();
10394
10577
  engine.ecs.addComponent(
10395
10578
  eid,
@@ -10454,33 +10637,33 @@ function useCoroutine() {
10454
10637
  return coroutinesRef.current.size;
10455
10638
  }
10456
10639
  };
10457
- const controlsRef = useRef24(controls);
10640
+ const controlsRef = useRef25(controls);
10458
10641
  return controlsRef.current;
10459
10642
  }
10460
10643
 
10461
10644
  // src/hooks/useSceneManager.ts
10462
- import { useState as useState13, useCallback as useCallback7, useRef as useRef25 } from "react";
10645
+ import { useState as useState13, useCallback as useCallback8, useRef as useRef26 } from "react";
10463
10646
  function useSceneManager(initialScene) {
10464
10647
  const [stack, setStack] = useState13([initialScene]);
10465
- const stackRef = useRef25(stack);
10648
+ const stackRef = useRef26(stack);
10466
10649
  stackRef.current = stack;
10467
- const push = useCallback7((scene) => {
10650
+ const push = useCallback8((scene) => {
10468
10651
  setStack((prev) => [...prev, scene]);
10469
10652
  }, []);
10470
- const pop = useCallback7(() => {
10653
+ const pop = useCallback8(() => {
10471
10654
  const prev = stackRef.current;
10472
10655
  if (prev.length <= 1) return void 0;
10473
10656
  const popped = prev[prev.length - 1];
10474
10657
  setStack(prev.slice(0, -1));
10475
10658
  return popped;
10476
10659
  }, []);
10477
- const replace = useCallback7((scene) => {
10660
+ const replace = useCallback8((scene) => {
10478
10661
  setStack((prev) => [...prev.slice(0, -1), scene]);
10479
10662
  }, []);
10480
- const reset = useCallback7((scene) => {
10663
+ const reset = useCallback8((scene) => {
10481
10664
  setStack([scene]);
10482
10665
  }, []);
10483
- const has = useCallback7(
10666
+ const has = useCallback8(
10484
10667
  (scene) => {
10485
10668
  return stack.includes(scene);
10486
10669
  },
@@ -10498,7 +10681,7 @@ function useSceneManager(initialScene) {
10498
10681
  }
10499
10682
 
10500
10683
  // src/hooks/useSceneTransition.ts
10501
- import { useState as useState14, useCallback as useCallback8, useRef as useRef26, useEffect as useEffect62 } from "react";
10684
+ import { useState as useState14, useCallback as useCallback9, useRef as useRef27, useEffect as useEffect63 } from "react";
10502
10685
  function useSceneTransition(initialScene, defaultTransition) {
10503
10686
  const [stack, setStack] = useState14([initialScene]);
10504
10687
  const [transState, setTransState] = useState14({
@@ -10507,11 +10690,11 @@ function useSceneTransition(initialScene, defaultTransition) {
10507
10690
  effect: null,
10508
10691
  pendingAction: null
10509
10692
  });
10510
- const stackRef = useRef26(stack);
10693
+ const stackRef = useRef27(stack);
10511
10694
  stackRef.current = stack;
10512
- const transRef = useRef26(transState);
10695
+ const transRef = useRef27(transState);
10513
10696
  transRef.current = transState;
10514
- useEffect62(() => {
10697
+ useEffect63(() => {
10515
10698
  if (transState.phase === "idle") return;
10516
10699
  const effect = transState.effect;
10517
10700
  if (!effect || effect.type === "instant") return;
@@ -10540,7 +10723,7 @@ function useSceneTransition(initialScene, defaultTransition) {
10540
10723
  rafId2 = requestAnimationFrame(animate);
10541
10724
  return () => cancelAnimationFrame(rafId2);
10542
10725
  }, [transState.phase, transState.effect]);
10543
- const startTransition = useCallback8(
10726
+ const startTransition = useCallback9(
10544
10727
  (effect, action) => {
10545
10728
  const eff = effect ?? defaultTransition ?? { type: "instant" };
10546
10729
  if (eff.type === "instant" || isReducedMotionPreferred()) {
@@ -10556,13 +10739,13 @@ function useSceneTransition(initialScene, defaultTransition) {
10556
10739
  },
10557
10740
  [defaultTransition]
10558
10741
  );
10559
- const push = useCallback8(
10742
+ const push = useCallback9(
10560
10743
  (scene, transition) => {
10561
10744
  startTransition(transition, () => setStack((prev) => [...prev, scene]));
10562
10745
  },
10563
10746
  [startTransition]
10564
10747
  );
10565
- const pop = useCallback8(
10748
+ const pop = useCallback9(
10566
10749
  (transition) => {
10567
10750
  const prev = stackRef.current;
10568
10751
  if (prev.length <= 1) return void 0;
@@ -10572,13 +10755,13 @@ function useSceneTransition(initialScene, defaultTransition) {
10572
10755
  },
10573
10756
  [startTransition]
10574
10757
  );
10575
- const replace = useCallback8(
10758
+ const replace = useCallback9(
10576
10759
  (scene, transition) => {
10577
10760
  startTransition(transition, () => setStack((prev) => [...prev.slice(0, -1), scene]));
10578
10761
  },
10579
10762
  [startTransition]
10580
10763
  );
10581
- const reset = useCallback8(
10764
+ const reset = useCallback9(
10582
10765
  (scene, transition) => {
10583
10766
  startTransition(transition, () => setStack([scene]));
10584
10767
  },
@@ -10679,10 +10862,10 @@ function SceneTransitionOverlay({ controls }) {
10679
10862
  }
10680
10863
 
10681
10864
  // src/hooks/useHitstop.ts
10682
- import { useContext as useContext53, useCallback as useCallback9 } from "react";
10865
+ import { useContext as useContext53, useCallback as useCallback10 } from "react";
10683
10866
  function useHitstop() {
10684
10867
  const engine = useContext53(EngineContext);
10685
- const freeze = useCallback9(
10868
+ const freeze = useCallback10(
10686
10869
  (seconds) => {
10687
10870
  engine.loop.hitPause(seconds);
10688
10871
  },
@@ -10698,9 +10881,9 @@ function useInputBuffer(opts) {
10698
10881
  }
10699
10882
 
10700
10883
  // src/hooks/useComboDetector.ts
10701
- import { useMemo as useMemo11, useRef as useRef27 } from "react";
10884
+ import { useMemo as useMemo11, useRef as useRef28 } from "react";
10702
10885
  function useComboDetector(combos) {
10703
- const lastComboRef = useRef27(null);
10886
+ const lastComboRef = useRef28(null);
10704
10887
  const result = useMemo11(() => {
10705
10888
  const detector = new ComboDetector({ combos });
10706
10889
  const api = {
@@ -10723,11 +10906,11 @@ function useComboDetector(combos) {
10723
10906
  }
10724
10907
 
10725
10908
  // src/hooks/useParent.ts
10726
- import { useEffect as useEffect63, useContext as useContext54 } from "react";
10909
+ import { useEffect as useEffect64, useContext as useContext54 } from "react";
10727
10910
  function useParent(childEntityId, parentEntityId) {
10728
10911
  const engine = useContext54(EngineContext);
10729
10912
  if (!engine) throw new Error("useParent must be used inside <Game>");
10730
- useEffect63(() => {
10913
+ useEffect64(() => {
10731
10914
  setParent(engine.ecs, childEntityId, parentEntityId);
10732
10915
  return () => {
10733
10916
  removeParent(engine.ecs, childEntityId);
@@ -10736,7 +10919,7 @@ function useParent(childEntityId, parentEntityId) {
10736
10919
  }
10737
10920
 
10738
10921
  // src/hooks/useAccessibility.ts
10739
- import { useCallback as useCallback10, useSyncExternalStore } from "react";
10922
+ import { useCallback as useCallback11, useSyncExternalStore } from "react";
10740
10923
  var _version = 0;
10741
10924
  var _listeners = /* @__PURE__ */ new Set();
10742
10925
  function subscribe(cb) {
@@ -10748,12 +10931,12 @@ function getSnapshot() {
10748
10931
  }
10749
10932
  function useAccessibility() {
10750
10933
  useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
10751
- const setOptions = useCallback10((opts) => {
10934
+ const setOptions = useCallback11((opts) => {
10752
10935
  setAccessibilityOptions(opts);
10753
10936
  _version++;
10754
10937
  for (const cb of _listeners) cb();
10755
10938
  }, []);
10756
- const announce = useCallback10((text, priority) => {
10939
+ const announce = useCallback11((text, priority) => {
10757
10940
  announceToScreenReader(text, priority);
10758
10941
  }, []);
10759
10942
  return {
@@ -10764,18 +10947,18 @@ function useAccessibility() {
10764
10947
  }
10765
10948
 
10766
10949
  // src/hooks/useHMR.ts
10767
- import { useEffect as useEffect64, useRef as useRef28, useMemo as useMemo12 } from "react";
10950
+ import { useEffect as useEffect65, useRef as useRef29, useMemo as useMemo12 } from "react";
10768
10951
  var idCounter = 0;
10769
10952
  function useHMR(hmrKey) {
10770
- const idRef = useRef28(null);
10953
+ const idRef = useRef29(null);
10771
10954
  if (idRef.current === null) {
10772
10955
  idRef.current = hmrKey ?? `__hmr_${idCounter++}`;
10773
10956
  }
10774
10957
  const key = idRef.current;
10775
10958
  const isHotReload = hmrLoadState(key) !== void 0;
10776
- const disposeRef = useRef28(null);
10777
- const acceptRef = useRef28(null);
10778
- useEffect64(() => {
10959
+ const disposeRef = useRef29(null);
10960
+ const acceptRef = useRef29(null);
10961
+ useEffect65(() => {
10779
10962
  const hot = import.meta.hot;
10780
10963
  if (!hot) return;
10781
10964
  hot.dispose(() => {
@@ -10808,11 +10991,11 @@ function useHMR(hmrKey) {
10808
10991
  }
10809
10992
 
10810
10993
  // src/hooks/useSquashStretch.ts
10811
- import { useCallback as useCallback11, useContext as useContext55 } from "react";
10994
+ import { useCallback as useCallback12, useContext as useContext55 } from "react";
10812
10995
  function useSquashStretch() {
10813
10996
  const engine = useContext55(EngineContext);
10814
10997
  const entityId = useContext55(EntityContext);
10815
- const trigger = useCallback11(
10998
+ const trigger = useCallback12(
10816
10999
  (scaleX, scaleY) => {
10817
11000
  const ss = engine.ecs.getComponent(entityId, "SquashStretch");
10818
11001
  if (!ss) return;
@@ -10825,16 +11008,16 @@ function useSquashStretch() {
10825
11008
  }
10826
11009
 
10827
11010
  // src/hooks/useHistory.ts
10828
- import { useCallback as useCallback12, useContext as useContext56, useEffect as useEffect65, useRef as useRef29, useState as useState15 } from "react";
11011
+ import { useCallback as useCallback13, useContext as useContext56, useEffect as useEffect66, useRef as useRef30, useState as useState15 } from "react";
10829
11012
  function useHistory(options) {
10830
11013
  const engine = useContext56(EngineContext);
10831
11014
  const capacity = options?.capacity ?? 50;
10832
11015
  const bindKeys = options?.bindKeyboardShortcuts ?? false;
10833
- const stackRef = useRef29([]);
10834
- const indexRef = useRef29(-1);
11016
+ const stackRef = useRef30([]);
11017
+ const indexRef = useRef30(-1);
10835
11018
  const [version, setVersion] = useState15(0);
10836
- const bump = useCallback12(() => setVersion((v) => v + 1), []);
10837
- const push = useCallback12(() => {
11019
+ const bump = useCallback13(() => setVersion((v) => v + 1), []);
11020
+ const push = useCallback13(() => {
10838
11021
  const snap = engine.ecs.getSnapshot();
10839
11022
  const stack = stackRef.current;
10840
11023
  if (indexRef.current < stack.length - 1) {
@@ -10845,14 +11028,14 @@ function useHistory(options) {
10845
11028
  indexRef.current = stack.length - 1;
10846
11029
  bump();
10847
11030
  }, [engine, capacity, bump]);
10848
- const undo = useCallback12(() => {
11031
+ const undo = useCallback13(() => {
10849
11032
  if (indexRef.current <= 0) return;
10850
11033
  indexRef.current -= 1;
10851
11034
  engine.ecs.restoreSnapshot(stackRef.current[indexRef.current]);
10852
11035
  engine.loop.markDirty();
10853
11036
  bump();
10854
11037
  }, [engine, bump]);
10855
- const redo = useCallback12(() => {
11038
+ const redo = useCallback13(() => {
10856
11039
  const stack = stackRef.current;
10857
11040
  if (indexRef.current >= stack.length - 1) return;
10858
11041
  indexRef.current += 1;
@@ -10860,12 +11043,12 @@ function useHistory(options) {
10860
11043
  engine.loop.markDirty();
10861
11044
  bump();
10862
11045
  }, [engine, bump]);
10863
- const clear = useCallback12(() => {
11046
+ const clear = useCallback13(() => {
10864
11047
  stackRef.current = [];
10865
11048
  indexRef.current = -1;
10866
11049
  bump();
10867
11050
  }, [bump]);
10868
- useEffect65(() => {
11051
+ useEffect66(() => {
10869
11052
  if (!bindKeys) return;
10870
11053
  const onKey = (e) => {
10871
11054
  const mod = e.ctrlKey || e.metaKey;
@@ -10890,13 +11073,13 @@ function useHistory(options) {
10890
11073
  }
10891
11074
 
10892
11075
  // src/hooks/useSelection.tsx
10893
- import { createContext as createContext2, useCallback as useCallback13, useContext as useContext57, useEffect as useEffect66, useMemo as useMemo13, useState as useState16 } from "react";
11076
+ import { createContext as createContext2, useCallback as useCallback14, useContext as useContext57, useEffect as useEffect67, useMemo as useMemo13, useState as useState16 } from "react";
10894
11077
  import { jsx as jsx15 } from "react/jsx-runtime";
10895
11078
  var SelectionContext = createContext2(null);
10896
11079
  function Selection({ initial, onChange, children }) {
10897
11080
  const engine = useContext57(EngineContext);
10898
11081
  const [selected, setSelected] = useState16(initial ?? []);
10899
- useEffect66(() => {
11082
+ useEffect67(() => {
10900
11083
  if (!engine) return;
10901
11084
  return engine.ecs.onDestroyEntity((destroyedId) => {
10902
11085
  setSelected((prev) => {
@@ -10907,14 +11090,14 @@ function Selection({ initial, onChange, children }) {
10907
11090
  });
10908
11091
  });
10909
11092
  }, [engine, onChange]);
10910
- const commit = useCallback13(
11093
+ const commit = useCallback14(
10911
11094
  (next) => {
10912
11095
  setSelected(next);
10913
11096
  onChange?.(next);
10914
11097
  },
10915
11098
  [onChange]
10916
11099
  );
10917
- const select = useCallback13(
11100
+ const select = useCallback14(
10918
11101
  (id, opts) => {
10919
11102
  if (opts?.additive) {
10920
11103
  setSelected((prev) => {
@@ -10929,7 +11112,7 @@ function Selection({ initial, onChange, children }) {
10929
11112
  },
10930
11113
  [commit, onChange]
10931
11114
  );
10932
- const deselect = useCallback13(
11115
+ const deselect = useCallback14(
10933
11116
  (id) => {
10934
11117
  setSelected((prev) => {
10935
11118
  if (!prev.includes(id)) return prev;
@@ -10940,7 +11123,7 @@ function Selection({ initial, onChange, children }) {
10940
11123
  },
10941
11124
  [onChange]
10942
11125
  );
10943
- const toggle = useCallback13(
11126
+ const toggle = useCallback14(
10944
11127
  (id) => {
10945
11128
  setSelected((prev) => {
10946
11129
  const next = prev.includes(id) ? prev.filter((x) => x !== id) : [...prev, id];
@@ -10950,8 +11133,8 @@ function Selection({ initial, onChange, children }) {
10950
11133
  },
10951
11134
  [onChange]
10952
11135
  );
10953
- const clear = useCallback13(() => commit([]), [commit]);
10954
- const isSelected = useCallback13((id) => selected.includes(id), [selected]);
11136
+ const clear = useCallback14(() => commit([]), [commit]);
11137
+ const isSelected = useCallback14((id) => selected.includes(id), [selected]);
10955
11138
  const value = useMemo13(
10956
11139
  () => ({ selected, select, deselect, toggle, clear, isSelected }),
10957
11140
  [selected, select, deselect, toggle, clear, isSelected]
@@ -10965,10 +11148,10 @@ function useSelection() {
10965
11148
  }
10966
11149
 
10967
11150
  // src/components/TransformHandles.tsx
10968
- import { useContext as useContext58, useEffect as useEffect68, useRef as useRef30 } from "react";
11151
+ import { useContext as useContext58, useEffect as useEffect69, useRef as useRef31 } from "react";
10969
11152
 
10970
11153
  // src/hooks/useOverlayTick.ts
10971
- import { useEffect as useEffect67 } from "react";
11154
+ import { useEffect as useEffect68 } from "react";
10972
11155
  var callbacks = /* @__PURE__ */ new Set();
10973
11156
  var rafId = 0;
10974
11157
  function tick() {
@@ -10991,7 +11174,7 @@ function register(cb) {
10991
11174
  };
10992
11175
  }
10993
11176
  function useOverlayTick(callback, deps = []) {
10994
- useEffect67(() => {
11177
+ useEffect68(() => {
10995
11178
  return register(callback);
10996
11179
  }, deps);
10997
11180
  }
@@ -11007,8 +11190,8 @@ function TransformHandles({
11007
11190
  }) {
11008
11191
  const engine = useContext58(EngineContext);
11009
11192
  const selection = useSelection();
11010
- const overlayRef = useRef30(null);
11011
- const dragRef = useRef30(null);
11193
+ const overlayRef = useRef31(null);
11194
+ const dragRef = useRef31(null);
11012
11195
  useOverlayTick(() => {
11013
11196
  if (!engine) return;
11014
11197
  const overlay = overlayRef.current;
@@ -11043,7 +11226,7 @@ function TransformHandles({
11043
11226
  node.style.transform = `translate(-50%, -50%) rotate(${t.rotation}rad)`;
11044
11227
  }
11045
11228
  }, [engine, selection.selected]);
11046
- useEffect68(() => {
11229
+ useEffect69(() => {
11047
11230
  if (!engine) return;
11048
11231
  const onMove = (e) => {
11049
11232
  const drag = dragRef.current;
@@ -11267,7 +11450,7 @@ function worldToScreenCss(engine, wx, wy) {
11267
11450
  }
11268
11451
 
11269
11452
  // src/hooks/useSnap.ts
11270
- import { useCallback as useCallback14, useContext as useContext59 } from "react";
11453
+ import { useCallback as useCallback15, useContext as useContext59 } from "react";
11271
11454
  function useSnap(options) {
11272
11455
  const engine = useContext59(EngineContext);
11273
11456
  const gridX = typeof options?.grid === "number" ? options.grid : options?.grid?.x ?? 0;
@@ -11275,7 +11458,7 @@ function useSnap(options) {
11275
11458
  const snapToEntities = options?.snapToEntities ?? false;
11276
11459
  const threshold = options?.threshold ?? 8;
11277
11460
  const exclude = options?.exclude;
11278
- const snapToGrid = useCallback14(
11461
+ const snapToGrid = useCallback15(
11279
11462
  (x, y) => {
11280
11463
  const sx = gridX > 0 ? Math.round(x / gridX) * gridX : x;
11281
11464
  const sy = gridY > 0 ? Math.round(y / gridY) * gridY : y;
@@ -11283,7 +11466,7 @@ function useSnap(options) {
11283
11466
  },
11284
11467
  [gridX, gridY]
11285
11468
  );
11286
- const snap = useCallback14(
11469
+ const snap = useCallback15(
11287
11470
  (x, y) => {
11288
11471
  let outX = x;
11289
11472
  let outY = y;
@@ -11358,7 +11541,7 @@ function getBounds(ecs, id) {
11358
11541
  }
11359
11542
 
11360
11543
  // src/components/EditableText.tsx
11361
- import { useContext as useContext60, useEffect as useEffect69, useRef as useRef31 } from "react";
11544
+ import { useContext as useContext60, useEffect as useEffect70, useRef as useRef32 } from "react";
11362
11545
  import { jsx as jsx17 } from "react/jsx-runtime";
11363
11546
  function EditableText({
11364
11547
  value,
@@ -11382,8 +11565,8 @@ function EditableText({
11382
11565
  }) {
11383
11566
  const engine = useContext60(EngineContext);
11384
11567
  const entityId = useContext60(EntityContext);
11385
- const containerRef = useRef31(null);
11386
- const inputRef = useRef31(null);
11568
+ const containerRef = useRef32(null);
11569
+ const inputRef = useRef32(null);
11387
11570
  useOverlayTick(() => {
11388
11571
  if (!engine || entityId === null || entityId === void 0) return;
11389
11572
  const container = containerRef.current;
@@ -11410,7 +11593,7 @@ function EditableText({
11410
11593
  container.style.setProperty("--cubeforge-canvas-left", `${rect.left + window.scrollX}px`);
11411
11594
  container.style.setProperty("--cubeforge-canvas-top", `${rect.top + window.scrollY}px`);
11412
11595
  }, [engine, entityId, width, height, fontSize]);
11413
- useEffect69(() => {
11596
+ useEffect70(() => {
11414
11597
  if (autoFocus) inputRef.current?.focus();
11415
11598
  }, [autoFocus]);
11416
11599
  if (!engine) return null;
@@ -11541,7 +11724,7 @@ function copyRegion(source, region, scale) {
11541
11724
  }
11542
11725
 
11543
11726
  // src/components/A11yNode.tsx
11544
- import { useContext as useContext61, useRef as useRef32 } from "react";
11727
+ import { useContext as useContext61, useRef as useRef33 } from "react";
11545
11728
  import { jsx as jsx18 } from "react/jsx-runtime";
11546
11729
  function A11yNode({
11547
11730
  label,
@@ -11557,7 +11740,7 @@ function A11yNode({
11557
11740
  }) {
11558
11741
  const engine = useContext61(EngineContext);
11559
11742
  const entityId = useContext61(EntityContext);
11560
- const nodeRef = useRef32(null);
11743
+ const nodeRef = useRef33(null);
11561
11744
  useOverlayTick(() => {
11562
11745
  if (!engine || entityId === null || entityId === void 0) return;
11563
11746
  const node = nodeRef.current;
@@ -11646,7 +11829,7 @@ function worldToScreenCss3(engine, wx, wy) {
11646
11829
  }
11647
11830
 
11648
11831
  // src/components/VectorPath.tsx
11649
- import { useContext as useContext62, useRef as useRef33 } from "react";
11832
+ import { useContext as useContext62, useRef as useRef34 } from "react";
11650
11833
  import { jsx as jsx19 } from "react/jsx-runtime";
11651
11834
  function VectorPath({
11652
11835
  d,
@@ -11662,7 +11845,7 @@ function VectorPath({
11662
11845
  }) {
11663
11846
  const engine = useContext62(EngineContext);
11664
11847
  const entityId = useContext62(EntityContext);
11665
- const svgRef = useRef33(null);
11848
+ const svgRef = useRef34(null);
11666
11849
  useOverlayTick(() => {
11667
11850
  if (!engine || entityId === null || entityId === void 0) return;
11668
11851
  const svg = svgRef.current;
@@ -11723,12 +11906,12 @@ function worldToScreenCss4(engine, wx, wy) {
11723
11906
  }
11724
11907
 
11725
11908
  // src/hooks/useGrid.ts
11726
- import { useCallback as useCallback15, useContext as useContext63, useMemo as useMemo14, useRef as useRef34, useState as useState17 } from "react";
11909
+ import { useCallback as useCallback16, useContext as useContext63, useMemo as useMemo14, useRef as useRef35, useState as useState17 } from "react";
11727
11910
  function useGrid({ width, height, fill }) {
11728
11911
  const engine = useContext63(EngineContext);
11729
11912
  const [version, setVersion] = useState17(0);
11730
- const bump = useCallback15(() => setVersion((v) => v + 1), []);
11731
- const dataRef = useRef34(null);
11913
+ const bump = useCallback16(() => setVersion((v) => v + 1), []);
11914
+ const dataRef = useRef35(null);
11732
11915
  if (dataRef.current === null) {
11733
11916
  const arr = new Array(width * height);
11734
11917
  if (typeof fill === "function") {
@@ -11743,19 +11926,19 @@ function useGrid({ width, height, fill }) {
11743
11926
  }
11744
11927
  dataRef.current = arr;
11745
11928
  }
11746
- const markChanged = useCallback15(() => {
11929
+ const markChanged = useCallback16(() => {
11747
11930
  engine?.loop.markDirty();
11748
11931
  bump();
11749
11932
  }, [engine, bump]);
11750
- const inBounds = useCallback15((x, y) => x >= 0 && y >= 0 && x < width && y < height, [width, height]);
11751
- const get = useCallback15(
11933
+ const inBounds = useCallback16((x, y) => x >= 0 && y >= 0 && x < width && y < height, [width, height]);
11934
+ const get = useCallback16(
11752
11935
  (x, y) => {
11753
11936
  if (!inBounds(x, y)) return void 0;
11754
11937
  return dataRef.current[y * width + x];
11755
11938
  },
11756
11939
  [width, inBounds]
11757
11940
  );
11758
- const set = useCallback15(
11941
+ const set = useCallback16(
11759
11942
  (x, y, value) => {
11760
11943
  if (!inBounds(x, y)) return;
11761
11944
  const data = dataRef.current;
@@ -11766,7 +11949,7 @@ function useGrid({ width, height, fill }) {
11766
11949
  },
11767
11950
  [width, inBounds, markChanged]
11768
11951
  );
11769
- const swap = useCallback15(
11952
+ const swap = useCallback16(
11770
11953
  (ax, ay, bx, by) => {
11771
11954
  if (!inBounds(ax, ay) || !inBounds(bx, by)) return;
11772
11955
  const data = dataRef.current;
@@ -11780,7 +11963,7 @@ function useGrid({ width, height, fill }) {
11780
11963
  },
11781
11964
  [width, inBounds, markChanged]
11782
11965
  );
11783
- const forEach = useCallback15(
11966
+ const forEach = useCallback16(
11784
11967
  (cb) => {
11785
11968
  const data = dataRef.current;
11786
11969
  for (let y = 0; y < height; y++) {
@@ -11791,7 +11974,7 @@ function useGrid({ width, height, fill }) {
11791
11974
  },
11792
11975
  [width, height]
11793
11976
  );
11794
- const find = useCallback15(
11977
+ const find = useCallback16(
11795
11978
  (pred) => {
11796
11979
  const data = dataRef.current;
11797
11980
  for (let y = 0; y < height; y++) {
@@ -11804,7 +11987,7 @@ function useGrid({ width, height, fill }) {
11804
11987
  },
11805
11988
  [width, height]
11806
11989
  );
11807
- const count = useCallback15(
11990
+ const count = useCallback16(
11808
11991
  (pred) => {
11809
11992
  const data = dataRef.current;
11810
11993
  let n = 0;
@@ -11817,7 +12000,7 @@ function useGrid({ width, height, fill }) {
11817
12000
  },
11818
12001
  [width, height]
11819
12002
  );
11820
- const neighbors = useCallback15(
12003
+ const neighbors = useCallback16(
11821
12004
  (x, y, diagonal = false) => {
11822
12005
  const data = dataRef.current;
11823
12006
  const result = [];
@@ -11845,7 +12028,7 @@ function useGrid({ width, height, fill }) {
11845
12028
  },
11846
12029
  [width, inBounds]
11847
12030
  );
11848
- const fillAll = useCallback15(
12031
+ const fillAll = useCallback16(
11849
12032
  (value) => {
11850
12033
  const data = dataRef.current;
11851
12034
  if (typeof value === "function") {
@@ -11862,7 +12045,7 @@ function useGrid({ width, height, fill }) {
11862
12045
  },
11863
12046
  [width, height, markChanged]
11864
12047
  );
11865
- const toArray = useCallback15(() => {
12048
+ const toArray = useCallback16(() => {
11866
12049
  const data = dataRef.current;
11867
12050
  const out = new Array(height);
11868
12051
  for (let y = 0; y < height; y++) {
@@ -11872,7 +12055,7 @@ function useGrid({ width, height, fill }) {
11872
12055
  }
11873
12056
  return out;
11874
12057
  }, [width, height]);
11875
- const fromArray = useCallback15(
12058
+ const fromArray = useCallback16(
11876
12059
  (arr) => {
11877
12060
  const data = dataRef.current;
11878
12061
  for (let y = 0; y < height; y++) {
@@ -11908,7 +12091,7 @@ function useGrid({ width, height, fill }) {
11908
12091
  }
11909
12092
 
11910
12093
  // src/hooks/useTurnSystem.ts
11911
- import { useCallback as useCallback16, useContext as useContext64, useEffect as useEffect70, useMemo as useMemo15, useRef as useRef35, useState as useState18 } from "react";
12094
+ import { useCallback as useCallback17, useContext as useContext64, useEffect as useEffect71, useMemo as useMemo15, useRef as useRef36, useState as useState18 } from "react";
11912
12095
  function useTurnSystem({
11913
12096
  players,
11914
12097
  initialIndex = 0,
@@ -11921,11 +12104,11 @@ function useTurnSystem({
11921
12104
  const [activeIndex, setActiveIndex] = useState18(initialIndex % players.length);
11922
12105
  const [turn, setTurn] = useState18(0);
11923
12106
  const [isPending, setIsPending] = useState18(false);
11924
- const pendingRafId = useRef35(null);
11925
- const pendingRemaining = useRef35(0);
11926
- const pendingTarget = useRef35(null);
11927
- const pendingLastTime = useRef35(0);
11928
- const clearPending = useCallback16(() => {
12107
+ const pendingRafId = useRef36(null);
12108
+ const pendingRemaining = useRef36(0);
12109
+ const pendingTarget = useRef36(null);
12110
+ const pendingLastTime = useRef36(0);
12111
+ const clearPending = useCallback17(() => {
11929
12112
  if (pendingRafId.current !== null) {
11930
12113
  cancelAnimationFrame(pendingRafId.current);
11931
12114
  pendingRafId.current = null;
@@ -11933,13 +12116,13 @@ function useTurnSystem({
11933
12116
  pendingTarget.current = null;
11934
12117
  setIsPending(false);
11935
12118
  }, []);
11936
- const startedOnce = useRef35(false);
11937
- useEffect70(() => {
12119
+ const startedOnce = useRef36(false);
12120
+ useEffect71(() => {
11938
12121
  if (startedOnce.current) return;
11939
12122
  startedOnce.current = true;
11940
12123
  onTurnStart?.({ player: players[activeIndex], index: activeIndex, turn: 0 });
11941
12124
  }, []);
11942
- const applyChange = useCallback16(
12125
+ const applyChange = useCallback17(
11943
12126
  (nextIndex) => {
11944
12127
  const curr = players[activeIndex];
11945
12128
  onTurnEnd?.({ player: curr, index: activeIndex, turn });
@@ -11952,7 +12135,7 @@ function useTurnSystem({
11952
12135
  },
11953
12136
  [players, activeIndex, turn, onTurnStart, onTurnEnd, engine]
11954
12137
  );
11955
- const scheduleChange = useCallback16(
12138
+ const scheduleChange = useCallback17(
11956
12139
  (nextIndex) => {
11957
12140
  clearPending();
11958
12141
  if (aiDelay <= 0) {
@@ -11984,9 +12167,9 @@ function useTurnSystem({
11984
12167
  },
11985
12168
  [aiDelay, applyChange, clearPending, engine]
11986
12169
  );
11987
- const nextTurn = useCallback16(() => scheduleChange(activeIndex + 1), [scheduleChange, activeIndex]);
11988
- const prevTurn = useCallback16(() => scheduleChange(activeIndex - 1), [scheduleChange, activeIndex]);
11989
- const skipTo = useCallback16(
12170
+ const nextTurn = useCallback17(() => scheduleChange(activeIndex + 1), [scheduleChange, activeIndex]);
12171
+ const prevTurn = useCallback17(() => scheduleChange(activeIndex - 1), [scheduleChange, activeIndex]);
12172
+ const skipTo = useCallback17(
11990
12173
  (target) => {
11991
12174
  let idx;
11992
12175
  if (typeof target === "number") {
@@ -11999,13 +12182,13 @@ function useTurnSystem({
11999
12182
  },
12000
12183
  [players, scheduleChange]
12001
12184
  );
12002
- const reset = useCallback16(() => {
12185
+ const reset = useCallback17(() => {
12003
12186
  clearPending();
12004
12187
  setActiveIndex(initialIndex % players.length);
12005
12188
  setTurn(0);
12006
12189
  engine?.loop.markDirty();
12007
12190
  }, [players.length, initialIndex, clearPending, engine]);
12008
- useEffect70(
12191
+ useEffect71(
12009
12192
  () => () => {
12010
12193
  if (pendingRafId.current !== null) cancelAnimationFrame(pendingRafId.current);
12011
12194
  },
@@ -12027,13 +12210,13 @@ function useTurnSystem({
12027
12210
  }
12028
12211
 
12029
12212
  // src/hooks/useHoverable.ts
12030
- import { useContext as useContext65, useEffect as useEffect71, useState as useState19 } from "react";
12213
+ import { useContext as useContext65, useEffect as useEffect72, useState as useState19 } from "react";
12031
12214
  function useHoverable(options) {
12032
12215
  const engine = useContext65(EngineContext);
12033
12216
  const ctxEntityId = useContext65(EntityContext);
12034
12217
  const entityId = options?.entityId ?? ctxEntityId;
12035
12218
  const [isHovered, setIsHovered] = useState19(false);
12036
- useEffect71(() => {
12219
+ useEffect72(() => {
12037
12220
  if (!engine || entityId === null || entityId === void 0 || options?.disabled) return;
12038
12221
  const canvas = engine.canvas;
12039
12222
  let hovered = false;
@@ -12110,7 +12293,7 @@ function screenToWorld(engine, cssX, cssY) {
12110
12293
  }
12111
12294
 
12112
12295
  // src/hooks/useDragDrop.ts
12113
- import { useContext as useContext66, useEffect as useEffect72, useRef as useRef36, useState as useState20 } from "react";
12296
+ import { useContext as useContext66, useEffect as useEffect73, useRef as useRef37, useState as useState20 } from "react";
12114
12297
  var dragStateByEngine = /* @__PURE__ */ new WeakMap();
12115
12298
  function getActiveDrag(engine) {
12116
12299
  return dragStateByEngine.get(engine) ?? null;
@@ -12135,9 +12318,9 @@ function useDraggable(options) {
12135
12318
  const entityId = options?.entityId ?? ctxEntityId;
12136
12319
  const [isDragging, setIsDragging] = useState20(false);
12137
12320
  const [position, setPosition] = useState20({ x: 0, y: 0 });
12138
- const optsRef = useRef36(options);
12321
+ const optsRef = useRef37(options);
12139
12322
  optsRef.current = options;
12140
- useEffect72(() => {
12323
+ useEffect73(() => {
12141
12324
  if (!engine || entityId === null || entityId === void 0 || options?.disabled) return;
12142
12325
  const canvas = engine.canvas;
12143
12326
  let dragging = false;
@@ -12247,9 +12430,9 @@ function useDroppable(options) {
12247
12430
  const entityId = options?.entityId ?? ctxEntityId;
12248
12431
  const [isOver, setIsOver] = useState20(false);
12249
12432
  const [hoveredBy, setHoveredBy] = useState20(null);
12250
- const optsRef = useRef36(options);
12433
+ const optsRef = useRef37(options);
12251
12434
  optsRef.current = options;
12252
- useEffect72(() => {
12435
+ useEffect73(() => {
12253
12436
  if (!engine || entityId === null || entityId === void 0 || options?.disabled) return;
12254
12437
  let currentlyOver = false;
12255
12438
  const check = () => {
@@ -12351,7 +12534,7 @@ function findDroppableUnder(engine, drag) {
12351
12534
  }
12352
12535
 
12353
12536
  // src/hooks/useKeyboardFocus.ts
12354
- import { useContext as useContext67, useEffect as useEffect73, useRef as useRef37, useState as useState21 } from "react";
12537
+ import { useContext as useContext67, useEffect as useEffect74, useRef as useRef38, useState as useState21 } from "react";
12355
12538
  var registry = /* @__PURE__ */ new Map();
12356
12539
  var focusedId = null;
12357
12540
  var subscribers = /* @__PURE__ */ new Set();
@@ -12368,9 +12551,9 @@ function setFocused(id) {
12368
12551
  }
12369
12552
  function useFocusable(options) {
12370
12553
  const entityIdCtx = useContext67(EntityContext);
12371
- const optsRef = useRef37(options);
12554
+ const optsRef = useRef38(options);
12372
12555
  optsRef.current = options;
12373
- useEffect73(() => {
12556
+ useEffect74(() => {
12374
12557
  if (entityIdCtx === null || entityIdCtx === void 0) return;
12375
12558
  const id = entityIdCtx;
12376
12559
  const entry = {
@@ -12390,14 +12573,14 @@ function useFocusable(options) {
12390
12573
  function useKeyboardFocus() {
12391
12574
  const engine = useContext67(EngineContext);
12392
12575
  const [focused, setFocusedState] = useState21(focusedId);
12393
- useEffect73(() => {
12576
+ useEffect74(() => {
12394
12577
  const cb = () => setFocusedState(focusedId);
12395
12578
  subscribers.add(cb);
12396
12579
  return () => {
12397
12580
  subscribers.delete(cb);
12398
12581
  };
12399
12582
  }, []);
12400
- useEffect73(() => {
12583
+ useEffect74(() => {
12401
12584
  if (!engine) return;
12402
12585
  const onKey = (e) => {
12403
12586
  const target = e.target;
@@ -12523,7 +12706,7 @@ function subscribeFocus(cb) {
12523
12706
  }
12524
12707
 
12525
12708
  // src/components/FocusRing.tsx
12526
- import { useContext as useContext68, useEffect as useEffect74, useRef as useRef38, useState as useState22 } from "react";
12709
+ import { useContext as useContext68, useEffect as useEffect75, useRef as useRef39, useState as useState22 } from "react";
12527
12710
  import { Fragment as Fragment9, jsx as jsx20, jsxs as jsxs9 } from "react/jsx-runtime";
12528
12711
  function FocusRing({
12529
12712
  color = "#4fc3f7",
@@ -12533,14 +12716,14 @@ function FocusRing({
12533
12716
  pulse = true
12534
12717
  }) {
12535
12718
  const engine = useContext68(EngineContext);
12536
- const ringRef = useRef38(null);
12719
+ const ringRef = useRef39(null);
12537
12720
  const [focused, setFocused2] = useState22(getFocusedEntityId());
12538
12721
  const [reducedMotion, setReducedMotion] = useState22(false);
12539
- useEffect74(() => {
12722
+ useEffect75(() => {
12540
12723
  const unsub = subscribeFocus(() => setFocused2(getFocusedEntityId()));
12541
12724
  return unsub;
12542
12725
  }, []);
12543
- useEffect74(() => {
12726
+ useEffect75(() => {
12544
12727
  if (typeof window === "undefined" || !window.matchMedia) return;
12545
12728
  const mq = window.matchMedia("(prefers-reduced-motion: reduce)");
12546
12729
  setReducedMotion(mq.matches);
@@ -12677,10 +12860,10 @@ function listSavedScenes(prefix = "") {
12677
12860
  }
12678
12861
 
12679
12862
  // ../gameplay/src/hooks/useAnimationController.ts
12680
- import { useState as useState23, useCallback as useCallback17 } from "react";
12863
+ import { useState as useState23, useCallback as useCallback18 } from "react";
12681
12864
  function useAnimationController(states, initial) {
12682
12865
  const [stateName, setStateName] = useState23(initial);
12683
- const setState = useCallback17((next) => {
12866
+ const setState = useCallback18((next) => {
12684
12867
  setStateName((prev) => prev === next ? prev : next);
12685
12868
  }, []);
12686
12869
  const clip = states[stateName] ?? states[initial];
@@ -12702,39 +12885,39 @@ function useAnimationController(states, initial) {
12702
12885
  }
12703
12886
 
12704
12887
  // ../gameplay/src/hooks/useAISteering.ts
12705
- import { useCallback as useCallback18 } from "react";
12888
+ import { useCallback as useCallback19 } from "react";
12706
12889
  function useAISteering() {
12707
- const seek$ = useCallback18((pos, target, speed) => seek(pos, target, speed), []);
12708
- const flee$ = useCallback18((pos, threat, speed) => flee(pos, threat, speed), []);
12709
- const arrive$ = useCallback18(
12890
+ const seek$ = useCallback19((pos, target, speed) => seek(pos, target, speed), []);
12891
+ const flee$ = useCallback19((pos, threat, speed) => flee(pos, threat, speed), []);
12892
+ const arrive$ = useCallback19(
12710
12893
  (pos, target, speed, slowRadius) => arrive(pos, target, speed, slowRadius),
12711
12894
  []
12712
12895
  );
12713
- const patrol$ = useCallback18(
12896
+ const patrol$ = useCallback19(
12714
12897
  (pos, waypoints, speed, currentIdx, arriveThreshold) => patrol(pos, waypoints, speed, currentIdx, arriveThreshold),
12715
12898
  []
12716
12899
  );
12717
- const wander$ = useCallback18(
12900
+ const wander$ = useCallback19(
12718
12901
  (pos, angle, speed, jitter) => wander(pos, angle, speed, jitter),
12719
12902
  []
12720
12903
  );
12721
- const pursuit$ = useCallback18(
12904
+ const pursuit$ = useCallback19(
12722
12905
  (pos, targetPos, targetVel, speed, lookAhead) => pursuit(pos, targetPos, targetVel, speed, lookAhead),
12723
12906
  []
12724
12907
  );
12725
- const evade$ = useCallback18(
12908
+ const evade$ = useCallback19(
12726
12909
  (pos, threatPos, threatVel, speed, lookAhead) => evade(pos, threatPos, threatVel, speed, lookAhead),
12727
12910
  []
12728
12911
  );
12729
- const separation$ = useCallback18(
12912
+ const separation$ = useCallback19(
12730
12913
  (pos, neighbors, speed, radius) => separation(pos, neighbors, speed, radius),
12731
12914
  []
12732
12915
  );
12733
- const cohesion$ = useCallback18(
12916
+ const cohesion$ = useCallback19(
12734
12917
  (pos, neighbors, speed) => cohesion(pos, neighbors, speed),
12735
12918
  []
12736
12919
  );
12737
- const alignment$ = useCallback18(
12920
+ const alignment$ = useCallback19(
12738
12921
  (neighborVelocities, speed) => alignment(neighborVelocities, speed),
12739
12922
  []
12740
12923
  );
@@ -12765,11 +12948,11 @@ function useDamageZone(damage, opts = {}) {
12765
12948
  }
12766
12949
 
12767
12950
  // ../gameplay/src/hooks/useDropThrough.ts
12768
- import { useContext as useContext70, useCallback as useCallback19 } from "react";
12951
+ import { useContext as useContext70, useCallback as useCallback20 } from "react";
12769
12952
  function useDropThrough(frames = 8) {
12770
12953
  const engine = useContext70(EngineContext);
12771
12954
  const entityId = useContext70(EntityContext);
12772
- const dropThrough = useCallback19(() => {
12955
+ const dropThrough = useCallback20(() => {
12773
12956
  const rb = engine.ecs.getComponent(entityId, "RigidBody");
12774
12957
  if (rb) rb.dropThrough = frames;
12775
12958
  }, [engine.ecs, entityId, frames]);
@@ -12777,17 +12960,17 @@ function useDropThrough(frames = 8) {
12777
12960
  }
12778
12961
 
12779
12962
  // ../gameplay/src/hooks/useGameStateMachine.ts
12780
- import { useState as useState24, useRef as useRef39, useCallback as useCallback20, useEffect as useEffect75, useContext as useContext71 } from "react";
12963
+ import { useState as useState24, useRef as useRef40, useCallback as useCallback21, useEffect as useEffect76, useContext as useContext71 } from "react";
12781
12964
  function useGameStateMachine(states, initial) {
12782
12965
  const engine = useContext71(EngineContext);
12783
12966
  const [state, setState] = useState24(initial);
12784
- const stateRef = useRef39(initial);
12785
- const statesRef = useRef39(states);
12967
+ const stateRef = useRef40(initial);
12968
+ const statesRef = useRef40(states);
12786
12969
  statesRef.current = states;
12787
- useEffect75(() => {
12970
+ useEffect76(() => {
12788
12971
  statesRef.current[initial]?.onEnter?.();
12789
12972
  }, []);
12790
- const transition = useCallback20((to) => {
12973
+ const transition = useCallback21((to) => {
12791
12974
  const current = stateRef.current;
12792
12975
  if (current === to) return;
12793
12976
  statesRef.current[current]?.onExit?.();
@@ -12795,7 +12978,7 @@ function useGameStateMachine(states, initial) {
12795
12978
  setState(to);
12796
12979
  statesRef.current[to]?.onEnter?.();
12797
12980
  }, []);
12798
- useEffect75(() => {
12981
+ useEffect76(() => {
12799
12982
  const eid = engine.ecs.createEntity();
12800
12983
  engine.ecs.addComponent(
12801
12984
  eid,
@@ -12811,27 +12994,27 @@ function useGameStateMachine(states, initial) {
12811
12994
  }
12812
12995
 
12813
12996
  // ../gameplay/src/hooks/useHealth.ts
12814
- import { useRef as useRef40, useEffect as useEffect76, useContext as useContext72, useCallback as useCallback21 } from "react";
12997
+ import { useRef as useRef41, useEffect as useEffect77, useContext as useContext72, useCallback as useCallback22 } from "react";
12815
12998
  function useHealth(maxHp, opts = {}) {
12816
12999
  const engine = useContext72(EngineContext);
12817
13000
  const entityId = useContext72(EntityContext);
12818
- const hpRef = useRef40(maxHp);
12819
- const invincibleRef = useRef40(false);
13001
+ const hpRef = useRef41(maxHp);
13002
+ const invincibleRef = useRef41(false);
12820
13003
  const iFrameDuration = opts.iFrames ?? 1;
12821
- const onDeathRef = useRef40(opts.onDeath);
12822
- const onDamageRef = useRef40(opts.onDamage);
12823
- useEffect76(() => {
13004
+ const onDeathRef = useRef41(opts.onDeath);
13005
+ const onDamageRef = useRef41(opts.onDamage);
13006
+ useEffect77(() => {
12824
13007
  onDeathRef.current = opts.onDeath;
12825
13008
  });
12826
- useEffect76(() => {
13009
+ useEffect77(() => {
12827
13010
  onDamageRef.current = opts.onDamage;
12828
13011
  });
12829
- const timerRef = useRef40(
13012
+ const timerRef = useRef41(
12830
13013
  createTimer(iFrameDuration, () => {
12831
13014
  invincibleRef.current = false;
12832
13015
  })
12833
13016
  );
12834
- const takeDamage = useCallback21(
13017
+ const takeDamage = useCallback22(
12835
13018
  (amount = 1) => {
12836
13019
  if (invincibleRef.current || hpRef.current <= 0) return;
12837
13020
  hpRef.current = Math.max(0, hpRef.current - amount);
@@ -12844,28 +13027,28 @@ function useHealth(maxHp, opts = {}) {
12844
13027
  },
12845
13028
  [iFrameDuration]
12846
13029
  );
12847
- const takeDamageRef = useRef40(takeDamage);
12848
- useEffect76(() => {
13030
+ const takeDamageRef = useRef41(takeDamage);
13031
+ useEffect77(() => {
12849
13032
  takeDamageRef.current = takeDamage;
12850
13033
  }, [takeDamage]);
12851
- useEffect76(() => {
13034
+ useEffect77(() => {
12852
13035
  return engine.events.on(`damage:${entityId}`, ({ amount }) => {
12853
13036
  takeDamageRef.current(amount);
12854
13037
  });
12855
13038
  }, [engine.events, entityId]);
12856
- const heal = useCallback21(
13039
+ const heal = useCallback22(
12857
13040
  (amount) => {
12858
13041
  hpRef.current = Math.min(maxHp, hpRef.current + amount);
12859
13042
  },
12860
13043
  [maxHp]
12861
13044
  );
12862
- const setHp = useCallback21(
13045
+ const setHp = useCallback22(
12863
13046
  (hp) => {
12864
13047
  hpRef.current = Math.min(maxHp, Math.max(0, hp));
12865
13048
  },
12866
13049
  [maxHp]
12867
13050
  );
12868
- const update = useCallback21((dt) => {
13051
+ const update = useCallback22((dt) => {
12869
13052
  timerRef.current.update(dt);
12870
13053
  }, []);
12871
13054
  return {
@@ -12889,11 +13072,11 @@ function useHealth(maxHp, opts = {}) {
12889
13072
  }
12890
13073
 
12891
13074
  // ../gameplay/src/hooks/useKinematicBody.ts
12892
- import { useContext as useContext73, useCallback as useCallback22 } from "react";
13075
+ import { useContext as useContext73, useCallback as useCallback23 } from "react";
12893
13076
  function useKinematicBody() {
12894
13077
  const engine = useContext73(EngineContext);
12895
13078
  const entityId = useContext73(EntityContext);
12896
- const moveAndCollide = useCallback22(
13079
+ const moveAndCollide = useCallback23(
12897
13080
  (dx, dy) => {
12898
13081
  const transform = engine.ecs.getComponent(entityId, "Transform");
12899
13082
  if (!transform) return { dx: 0, dy: 0 };
@@ -12929,7 +13112,7 @@ function useKinematicBody() {
12929
13112
  },
12930
13113
  [engine.ecs, entityId]
12931
13114
  );
12932
- const setVelocity = useCallback22(
13115
+ const setVelocity = useCallback23(
12933
13116
  (vx, vy) => {
12934
13117
  const rb = engine.ecs.getComponent(entityId, "RigidBody");
12935
13118
  if (rb) {
@@ -12939,7 +13122,7 @@ function useKinematicBody() {
12939
13122
  },
12940
13123
  [engine.ecs, entityId]
12941
13124
  );
12942
- const setAngularVelocity = useCallback22(
13125
+ const setAngularVelocity = useCallback23(
12943
13126
  (w) => {
12944
13127
  const rb = engine.ecs.getComponent(entityId, "RigidBody");
12945
13128
  if (rb) rb.angularVelocity = w;
@@ -12950,12 +13133,12 @@ function useKinematicBody() {
12950
13133
  }
12951
13134
 
12952
13135
  // ../gameplay/src/hooks/useLevelTransition.ts
12953
- import { useState as useState25, useRef as useRef41, useCallback as useCallback23 } from "react";
13136
+ import { useState as useState25, useRef as useRef42, useCallback as useCallback24 } from "react";
12954
13137
  function useLevelTransition(initial) {
12955
13138
  const [currentLevel, setCurrentLevel] = useState25(initial);
12956
13139
  const [isTransitioning, setIsTransitioning] = useState25(false);
12957
- const overlayRef = useRef41(null);
12958
- const transitionTo = useCallback23((level, opts = {}) => {
13140
+ const overlayRef = useRef42(null);
13141
+ const transitionTo = useCallback24((level, opts = {}) => {
12959
13142
  const { duration = 0.4, type = "fade" } = opts;
12960
13143
  if (type === "instant") {
12961
13144
  setCurrentLevel(level);
@@ -12992,7 +13175,7 @@ function useLevelTransition(initial) {
12992
13175
  }
12993
13176
 
12994
13177
  // ../gameplay/src/hooks/usePlatformerController.ts
12995
- import { useContext as useContext74, useEffect as useEffect77 } from "react";
13178
+ import { useContext as useContext74, useEffect as useEffect78 } from "react";
12996
13179
  function normalizeKeys(val, defaults) {
12997
13180
  if (!val) return defaults;
12998
13181
  return Array.isArray(val) ? val : [val];
@@ -13016,7 +13199,7 @@ function usePlatformerController(entityId, opts = {}) {
13016
13199
  const leftKeys = normalizeKeys(bindings?.left, ["ArrowLeft", "KeyA", "a"]);
13017
13200
  const rightKeys = normalizeKeys(bindings?.right, ["ArrowRight", "KeyD", "d"]);
13018
13201
  const jumpKeys = normalizeKeys(bindings?.jump, ["Space", "ArrowUp", "KeyW", "w"]);
13019
- useEffect77(() => {
13202
+ useEffect78(() => {
13020
13203
  const state = {
13021
13204
  coyoteTimer: 0,
13022
13205
  jumpBuffer: 0,
@@ -13080,22 +13263,22 @@ function usePlatformerController(entityId, opts = {}) {
13080
13263
  }
13081
13264
 
13082
13265
  // ../gameplay/src/hooks/usePathfinding.ts
13083
- import { useCallback as useCallback24 } from "react";
13266
+ import { useCallback as useCallback25 } from "react";
13084
13267
  function usePathfinding() {
13085
- const createGrid$ = useCallback24(
13268
+ const createGrid$ = useCallback25(
13086
13269
  (cols, rows, cellSize) => createNavGrid(cols, rows, cellSize),
13087
13270
  []
13088
13271
  );
13089
- const setWalkable$ = useCallback24(
13272
+ const setWalkable$ = useCallback25(
13090
13273
  (grid, col, row, walkable) => setWalkable(grid, col, row, walkable),
13091
13274
  []
13092
13275
  );
13093
- const findPath$ = useCallback24((grid, start2, goal) => findPath(grid, start2, goal), []);
13276
+ const findPath$ = useCallback25((grid, start2, goal) => findPath(grid, start2, goal), []);
13094
13277
  return { createGrid: createGrid$, setWalkable: setWalkable$, findPath: findPath$ };
13095
13278
  }
13096
13279
 
13097
13280
  // ../gameplay/src/hooks/usePersistedBindings.ts
13098
- import { useState as useState26, useCallback as useCallback25, useMemo as useMemo16, useContext as useContext75 } from "react";
13281
+ import { useState as useState26, useCallback as useCallback26, useMemo as useMemo16, useContext as useContext75 } from "react";
13099
13282
  function usePersistedBindings(storageKey, defaults) {
13100
13283
  const engine = useContext75(EngineContext);
13101
13284
  const input = engine.input;
@@ -13115,7 +13298,7 @@ function usePersistedBindings(storageKey, defaults) {
13115
13298
  }
13116
13299
  return out;
13117
13300
  }, [bindings]);
13118
- const rebind = useCallback25(
13301
+ const rebind = useCallback26(
13119
13302
  (action, keys) => {
13120
13303
  setBindings((prev) => {
13121
13304
  const next = { ...prev, [action]: Array.isArray(keys) ? keys : [keys] };
@@ -13128,7 +13311,7 @@ function usePersistedBindings(storageKey, defaults) {
13128
13311
  },
13129
13312
  [storageKey]
13130
13313
  );
13131
- const reset = useCallback25(() => {
13314
+ const reset = useCallback26(() => {
13132
13315
  try {
13133
13316
  localStorage.removeItem(storageKey);
13134
13317
  } catch {
@@ -13149,21 +13332,21 @@ function usePersistedBindings(storageKey, defaults) {
13149
13332
  }
13150
13333
 
13151
13334
  // ../gameplay/src/hooks/useRestart.ts
13152
- import { useState as useState27, useCallback as useCallback26 } from "react";
13335
+ import { useState as useState27, useCallback as useCallback27 } from "react";
13153
13336
  function useRestart() {
13154
13337
  const [restartKey, setRestartKey] = useState27(0);
13155
- const restart = useCallback26(() => {
13338
+ const restart = useCallback27(() => {
13156
13339
  setRestartKey((k) => k + 1);
13157
13340
  }, []);
13158
13341
  return { restartKey, restart };
13159
13342
  }
13160
13343
 
13161
13344
  // ../gameplay/src/hooks/useSave.ts
13162
- import { useCallback as useCallback27, useRef as useRef42 } from "react";
13345
+ import { useCallback as useCallback28, useRef as useRef43 } from "react";
13163
13346
  function useSave(key, defaultValue, opts = {}) {
13164
13347
  const version = opts.version ?? 1;
13165
- const dataRef = useRef42(defaultValue);
13166
- const save = useCallback27(
13348
+ const dataRef = useRef43(defaultValue);
13349
+ const save = useCallback28(
13167
13350
  (value) => {
13168
13351
  dataRef.current = value;
13169
13352
  const slot = { version, data: value };
@@ -13175,7 +13358,7 @@ function useSave(key, defaultValue, opts = {}) {
13175
13358
  },
13176
13359
  [key, version]
13177
13360
  );
13178
- const load = useCallback27(() => {
13361
+ const load = useCallback28(() => {
13179
13362
  try {
13180
13363
  const raw = localStorage.getItem(key);
13181
13364
  if (!raw) return defaultValue;
@@ -13195,11 +13378,11 @@ function useSave(key, defaultValue, opts = {}) {
13195
13378
  return defaultValue;
13196
13379
  }
13197
13380
  }, [key, version]);
13198
- const clear = useCallback27(() => {
13381
+ const clear = useCallback28(() => {
13199
13382
  localStorage.removeItem(key);
13200
13383
  dataRef.current = defaultValue;
13201
13384
  }, [key]);
13202
- const exists = useCallback27(() => {
13385
+ const exists = useCallback28(() => {
13203
13386
  return localStorage.getItem(key) !== null;
13204
13387
  }, [key]);
13205
13388
  return {
@@ -13214,7 +13397,7 @@ function useSave(key, defaultValue, opts = {}) {
13214
13397
  }
13215
13398
 
13216
13399
  // ../gameplay/src/hooks/useIDBSave.ts
13217
- import { useCallback as useCallback28, useRef as useRef43 } from "react";
13400
+ import { useCallback as useCallback29, useRef as useRef44 } from "react";
13218
13401
  var DB_NAME = "cubeforge-saves";
13219
13402
  var STORE_NAME = "saves";
13220
13403
  function openDB() {
@@ -13232,12 +13415,12 @@ function openDB() {
13232
13415
  }
13233
13416
  function useIDBSave(key, defaultValue, opts = {}) {
13234
13417
  const version = opts.version ?? 1;
13235
- const dbRef = useRef43(null);
13236
- const getDB = useCallback28(() => {
13418
+ const dbRef = useRef44(null);
13419
+ const getDB = useCallback29(() => {
13237
13420
  if (!dbRef.current) dbRef.current = openDB();
13238
13421
  return dbRef.current;
13239
13422
  }, []);
13240
- const save = useCallback28(
13423
+ const save = useCallback29(
13241
13424
  async (value) => {
13242
13425
  const db = await getDB();
13243
13426
  const slot = { version, data: value };
@@ -13250,7 +13433,7 @@ function useIDBSave(key, defaultValue, opts = {}) {
13250
13433
  },
13251
13434
  [getDB, key, version]
13252
13435
  );
13253
- const load = useCallback28(async () => {
13436
+ const load = useCallback29(async () => {
13254
13437
  const db = await getDB();
13255
13438
  return new Promise((resolve, reject) => {
13256
13439
  const tx = db.transaction(STORE_NAME, "readonly");
@@ -13276,7 +13459,7 @@ function useIDBSave(key, defaultValue, opts = {}) {
13276
13459
  req.onerror = () => reject(req.error);
13277
13460
  });
13278
13461
  }, [getDB, key, version]);
13279
- const clear = useCallback28(async () => {
13462
+ const clear = useCallback29(async () => {
13280
13463
  const db = await getDB();
13281
13464
  return new Promise((resolve, reject) => {
13282
13465
  const tx = db.transaction(STORE_NAME, "readwrite");
@@ -13285,7 +13468,7 @@ function useIDBSave(key, defaultValue, opts = {}) {
13285
13468
  req.onerror = () => reject(req.error);
13286
13469
  });
13287
13470
  }, [getDB, key]);
13288
- const exists = useCallback28(async () => {
13471
+ const exists = useCallback29(async () => {
13289
13472
  const db = await getDB();
13290
13473
  return new Promise((resolve, reject) => {
13291
13474
  const tx = db.transaction(STORE_NAME, "readonly");
@@ -13298,7 +13481,7 @@ function useIDBSave(key, defaultValue, opts = {}) {
13298
13481
  }
13299
13482
 
13300
13483
  // ../gameplay/src/hooks/useSaveSlots.ts
13301
- import { useCallback as useCallback29, useState as useState28 } from "react";
13484
+ import { useCallback as useCallback30, useState as useState28 } from "react";
13302
13485
  function useSaveSlots(namespace, opts = {}) {
13303
13486
  const version = opts.version ?? 1;
13304
13487
  const indexKey = `cubeforge-saves:${namespace}:__index`;
@@ -13352,7 +13535,7 @@ function useSaveSlots(namespace, opts = {}) {
13352
13535
  const metas = readIndex().map((id) => readSlot(id)?.meta).filter((m) => m !== void 0).sort((a, b) => a.savedAt < b.savedAt ? 1 : -1);
13353
13536
  setSlots(metas);
13354
13537
  }
13355
- const save = useCallback29(
13538
+ const save = useCallback30(
13356
13539
  (id, data, label, thumbnail) => {
13357
13540
  const meta = {
13358
13541
  id,
@@ -13367,7 +13550,7 @@ function useSaveSlots(namespace, opts = {}) {
13367
13550
  // eslint-disable-next-line react-hooks/exhaustive-deps
13368
13551
  [namespace, version]
13369
13552
  );
13370
- const load = useCallback29(
13553
+ const load = useCallback30(
13371
13554
  (id) => {
13372
13555
  const entry = readSlot(id);
13373
13556
  if (!entry) return null;
@@ -13383,7 +13566,7 @@ function useSaveSlots(namespace, opts = {}) {
13383
13566
  // eslint-disable-next-line react-hooks/exhaustive-deps
13384
13567
  [namespace, version]
13385
13568
  );
13386
- const deleteFn = useCallback29(
13569
+ const deleteFn = useCallback30(
13387
13570
  (id) => {
13388
13571
  try {
13389
13572
  localStorage.removeItem(slotKey(id));
@@ -13395,7 +13578,7 @@ function useSaveSlots(namespace, opts = {}) {
13395
13578
  // eslint-disable-next-line react-hooks/exhaustive-deps
13396
13579
  [namespace]
13397
13580
  );
13398
- const copy = useCallback29(
13581
+ const copy = useCallback30(
13399
13582
  (fromId, toId) => {
13400
13583
  const entry = readSlot(fromId);
13401
13584
  if (!entry) return false;
@@ -13408,7 +13591,7 @@ function useSaveSlots(namespace, opts = {}) {
13408
13591
  // eslint-disable-next-line react-hooks/exhaustive-deps
13409
13592
  [namespace, version]
13410
13593
  );
13411
- const rename = useCallback29(
13594
+ const rename = useCallback30(
13412
13595
  (id, label) => {
13413
13596
  const entry = readSlot(id);
13414
13597
  if (!entry) return;
@@ -13418,10 +13601,10 @@ function useSaveSlots(namespace, opts = {}) {
13418
13601
  // eslint-disable-next-line react-hooks/exhaustive-deps
13419
13602
  [namespace]
13420
13603
  );
13421
- const listSlots = useCallback29(() => {
13604
+ const listSlots = useCallback30(() => {
13422
13605
  return readIndex().map((id) => readSlot(id)?.meta).filter((m) => m !== void 0).sort((a, b) => a.savedAt < b.savedAt ? 1 : -1);
13423
13606
  }, [namespace]);
13424
- const exists = useCallback29(
13607
+ const exists = useCallback30(
13425
13608
  (id) => {
13426
13609
  return readSlot(id) !== null;
13427
13610
  },
@@ -13443,7 +13626,7 @@ function useSaveSlots(namespace, opts = {}) {
13443
13626
  }
13444
13627
 
13445
13628
  // ../gameplay/src/hooks/useTopDownMovement.ts
13446
- import { useContext as useContext76, useEffect as useEffect78 } from "react";
13629
+ import { useContext as useContext76, useEffect as useEffect79 } from "react";
13447
13630
  function moveToward(current, target, maxDelta) {
13448
13631
  const diff = target - current;
13449
13632
  if (Math.abs(diff) <= maxDelta) return target;
@@ -13452,7 +13635,7 @@ function moveToward(current, target, maxDelta) {
13452
13635
  function useTopDownMovement(entityId, opts = {}) {
13453
13636
  const engine = useContext76(EngineContext);
13454
13637
  const { speed = 200, normalizeDiagonal = true, acceleration = Infinity, deceleration = acceleration } = opts;
13455
- useEffect78(() => {
13638
+ useEffect79(() => {
13456
13639
  const updateFn = (id, world, input, dt) => {
13457
13640
  if (!world.hasEntity(id)) return;
13458
13641
  const rb = world.getComponent(id, "RigidBody");
@@ -13492,18 +13675,18 @@ function useTopDownMovement(entityId, opts = {}) {
13492
13675
  }
13493
13676
 
13494
13677
  // ../gameplay/src/hooks/useDialogue.ts
13495
- import { useState as useState29, useCallback as useCallback30, useRef as useRef44 } from "react";
13678
+ import { useState as useState29, useCallback as useCallback31, useRef as useRef45 } from "react";
13496
13679
  function useDialogue() {
13497
13680
  const [active, setActive] = useState29(false);
13498
13681
  const [currentId, setCurrentId] = useState29(null);
13499
- const scriptRef = useRef44(null);
13500
- const start2 = useCallback30((script, startId) => {
13682
+ const scriptRef = useRef45(null);
13683
+ const start2 = useCallback31((script, startId) => {
13501
13684
  scriptRef.current = script;
13502
13685
  const id = startId ?? Object.keys(script)[0];
13503
13686
  setCurrentId(id);
13504
13687
  setActive(true);
13505
13688
  }, []);
13506
- const advance = useCallback30(
13689
+ const advance = useCallback31(
13507
13690
  (choiceIndex) => {
13508
13691
  if (!scriptRef.current || !currentId) return;
13509
13692
  const line = scriptRef.current[currentId];
@@ -13533,7 +13716,7 @@ function useDialogue() {
13533
13716
  },
13534
13717
  [currentId]
13535
13718
  );
13536
- const close = useCallback30(() => {
13719
+ const close = useCallback31(() => {
13537
13720
  setActive(false);
13538
13721
  setCurrentId(null);
13539
13722
  scriptRef.current = null;
@@ -13542,6 +13725,367 @@ function useDialogue() {
13542
13725
  return { active, current, currentId, start: start2, advance, close };
13543
13726
  }
13544
13727
 
13728
+ // ../gameplay/src/hooks/useDialogueTree.ts
13729
+ import { useState as useState30, useCallback as useCallback32, useRef as useRef46 } from "react";
13730
+ function interpolate(text, vars) {
13731
+ return text.replace(/\{(\w+)\}/g, (_, key) => {
13732
+ const val = vars[key];
13733
+ return val !== void 0 ? String(val) : `{${key}}`;
13734
+ });
13735
+ }
13736
+ function applyVars(node, vars) {
13737
+ return {
13738
+ ...node,
13739
+ text: interpolate(node.text, vars),
13740
+ speaker: node.speaker ? interpolate(node.speaker, vars) : node.speaker
13741
+ };
13742
+ }
13743
+ function useDialogueTree() {
13744
+ const [active, setActive] = useState30(false);
13745
+ const [currentId, setCurrentId] = useState30(null);
13746
+ const [variables, setVariables] = useState30({});
13747
+ const scriptRef = useRef46(null);
13748
+ const varsRef = useRef46({});
13749
+ function setCurrentNode(id) {
13750
+ if (!id || !scriptRef.current) {
13751
+ setActive(false);
13752
+ setCurrentId(null);
13753
+ return;
13754
+ }
13755
+ const node = scriptRef.current[id];
13756
+ if (!node) {
13757
+ setActive(false);
13758
+ setCurrentId(null);
13759
+ return;
13760
+ }
13761
+ node.onEnter?.(varsRef.current);
13762
+ setCurrentId(id);
13763
+ }
13764
+ const start2 = useCallback32(
13765
+ (script, startId, initialVars) => {
13766
+ scriptRef.current = script;
13767
+ const newVars = { ...varsRef.current, ...initialVars };
13768
+ varsRef.current = newVars;
13769
+ setVariables(newVars);
13770
+ const id = startId ?? Object.keys(script)[0];
13771
+ setActive(true);
13772
+ setCurrentNode(id);
13773
+ },
13774
+ // eslint-disable-next-line react-hooks/exhaustive-deps
13775
+ []
13776
+ );
13777
+ const advance = useCallback32(
13778
+ (choiceIndex) => {
13779
+ if (!scriptRef.current || !currentId) return;
13780
+ const node = scriptRef.current[currentId];
13781
+ if (!node) {
13782
+ setActive(false);
13783
+ setCurrentId(null);
13784
+ return;
13785
+ }
13786
+ node.onExit?.(varsRef.current);
13787
+ if (node.choices && node.choices.length > 0 && choiceIndex !== void 0) {
13788
+ const visible = node.choices.filter((c) => !c.condition || c.condition(varsRef.current));
13789
+ const choice = visible[choiceIndex];
13790
+ if (choice) {
13791
+ choice.onSelect?.(varsRef.current);
13792
+ if (choice.next && scriptRef.current[choice.next]) {
13793
+ setCurrentNode(choice.next);
13794
+ } else {
13795
+ setActive(false);
13796
+ setCurrentId(null);
13797
+ }
13798
+ }
13799
+ return;
13800
+ }
13801
+ if (node.next && scriptRef.current[node.next]) {
13802
+ setCurrentNode(node.next);
13803
+ } else {
13804
+ const keys = Object.keys(scriptRef.current);
13805
+ const idx = keys.indexOf(currentId);
13806
+ if (idx >= 0 && idx + 1 < keys.length) {
13807
+ setCurrentNode(keys[idx + 1]);
13808
+ } else {
13809
+ setActive(false);
13810
+ setCurrentId(null);
13811
+ }
13812
+ }
13813
+ },
13814
+ [currentId]
13815
+ );
13816
+ const jumpTo = useCallback32(
13817
+ (id) => {
13818
+ if (!scriptRef.current?.[id]) return;
13819
+ const current2 = scriptRef.current[currentId ?? ""];
13820
+ current2?.onExit?.(varsRef.current);
13821
+ setCurrentNode(id);
13822
+ },
13823
+ [currentId]
13824
+ );
13825
+ const setVar = useCallback32((key, value) => {
13826
+ varsRef.current = { ...varsRef.current, [key]: value };
13827
+ setVariables({ ...varsRef.current });
13828
+ }, []);
13829
+ const close = useCallback32(() => {
13830
+ if (scriptRef.current && currentId) {
13831
+ scriptRef.current[currentId]?.onExit?.(varsRef.current);
13832
+ }
13833
+ setActive(false);
13834
+ setCurrentId(null);
13835
+ scriptRef.current = null;
13836
+ }, [currentId]);
13837
+ const rawNode = scriptRef.current && currentId ? scriptRef.current[currentId] ?? null : null;
13838
+ const current = rawNode ? applyVars(rawNode, varsRef.current) : null;
13839
+ const visibleChoices = rawNode?.choices ? rawNode.choices.filter((c) => !c.condition || c.condition(varsRef.current)) : [];
13840
+ return {
13841
+ active,
13842
+ current,
13843
+ currentId,
13844
+ visibleChoices,
13845
+ variables,
13846
+ start: start2,
13847
+ advance,
13848
+ jumpTo,
13849
+ setVar,
13850
+ close
13851
+ };
13852
+ }
13853
+
13854
+ // ../gameplay/src/hooks/useBehaviorTree.ts
13855
+ import { useRef as useRef47, useCallback as useCallback33 } from "react";
13856
+ function btAction(fn) {
13857
+ return {
13858
+ tick(dt) {
13859
+ const result = fn(dt);
13860
+ if (result === void 0 || result === null) return "success";
13861
+ if (typeof result === "boolean") return result ? "success" : "failure";
13862
+ return result;
13863
+ },
13864
+ reset() {
13865
+ }
13866
+ };
13867
+ }
13868
+ function btCondition(fn) {
13869
+ return {
13870
+ tick() {
13871
+ return fn() ? "success" : "failure";
13872
+ },
13873
+ reset() {
13874
+ }
13875
+ };
13876
+ }
13877
+ function btWait(duration) {
13878
+ let elapsed = 0;
13879
+ return {
13880
+ tick(dt) {
13881
+ elapsed += dt;
13882
+ if (elapsed >= duration) {
13883
+ elapsed = 0;
13884
+ return "success";
13885
+ }
13886
+ return "running";
13887
+ },
13888
+ reset() {
13889
+ elapsed = 0;
13890
+ }
13891
+ };
13892
+ }
13893
+ function btSequence(...children) {
13894
+ let idx = 0;
13895
+ return {
13896
+ tick(dt) {
13897
+ while (idx < children.length) {
13898
+ const s2 = children[idx].tick(dt);
13899
+ if (s2 === "running") return "running";
13900
+ if (s2 === "failure") {
13901
+ idx = 0;
13902
+ return "failure";
13903
+ }
13904
+ idx++;
13905
+ }
13906
+ idx = 0;
13907
+ return "success";
13908
+ },
13909
+ reset() {
13910
+ idx = 0;
13911
+ children.forEach((c) => c.reset());
13912
+ }
13913
+ };
13914
+ }
13915
+ function btSelector(...children) {
13916
+ let idx = 0;
13917
+ return {
13918
+ tick(dt) {
13919
+ while (idx < children.length) {
13920
+ const s2 = children[idx].tick(dt);
13921
+ if (s2 === "running") return "running";
13922
+ if (s2 === "success") {
13923
+ idx = 0;
13924
+ return "success";
13925
+ }
13926
+ idx++;
13927
+ }
13928
+ idx = 0;
13929
+ return "failure";
13930
+ },
13931
+ reset() {
13932
+ idx = 0;
13933
+ children.forEach((c) => c.reset());
13934
+ }
13935
+ };
13936
+ }
13937
+ function btParallel(successPolicy, failPolicy, ...children) {
13938
+ return {
13939
+ tick(dt) {
13940
+ let successCount = 0;
13941
+ let failCount = 0;
13942
+ for (const child of children) {
13943
+ const s2 = child.tick(dt);
13944
+ if (s2 === "success") successCount++;
13945
+ else if (s2 === "failure") failCount++;
13946
+ }
13947
+ if (successPolicy === "any" && successCount > 0) {
13948
+ children.forEach((c) => c.reset());
13949
+ return "success";
13950
+ }
13951
+ if (failPolicy === "any" && failCount > 0) {
13952
+ children.forEach((c) => c.reset());
13953
+ return "failure";
13954
+ }
13955
+ if (successPolicy === "all" && successCount === children.length) return "success";
13956
+ if (failPolicy === "all" && failCount === children.length) return "failure";
13957
+ return "running";
13958
+ },
13959
+ reset() {
13960
+ children.forEach((c) => c.reset());
13961
+ }
13962
+ };
13963
+ }
13964
+ function btInvert(child) {
13965
+ return {
13966
+ tick(dt) {
13967
+ const s2 = child.tick(dt);
13968
+ if (s2 === "success") return "failure";
13969
+ if (s2 === "failure") return "success";
13970
+ return "running";
13971
+ },
13972
+ reset() {
13973
+ child.reset();
13974
+ }
13975
+ };
13976
+ }
13977
+ function btRepeat(count, child) {
13978
+ let done = 0;
13979
+ return {
13980
+ tick(dt) {
13981
+ while (count === "forever" || done < count) {
13982
+ const s2 = child.tick(dt);
13983
+ if (s2 === "running") return "running";
13984
+ if (s2 === "failure") {
13985
+ done = 0;
13986
+ child.reset();
13987
+ return "failure";
13988
+ }
13989
+ done++;
13990
+ child.reset();
13991
+ }
13992
+ done = 0;
13993
+ return "success";
13994
+ },
13995
+ reset() {
13996
+ done = 0;
13997
+ child.reset();
13998
+ }
13999
+ };
14000
+ }
14001
+ function btRetryUntilSuccess(maxAttempts, child) {
14002
+ let attempts = 0;
14003
+ return {
14004
+ tick(dt) {
14005
+ while (attempts < maxAttempts) {
14006
+ const s2 = child.tick(dt);
14007
+ if (s2 === "running") return "running";
14008
+ if (s2 === "success") {
14009
+ attempts = 0;
14010
+ return "success";
14011
+ }
14012
+ attempts++;
14013
+ child.reset();
14014
+ }
14015
+ attempts = 0;
14016
+ return "failure";
14017
+ },
14018
+ reset() {
14019
+ attempts = 0;
14020
+ child.reset();
14021
+ }
14022
+ };
14023
+ }
14024
+ function btCooldown(duration, child) {
14025
+ let remaining = 0;
14026
+ return {
14027
+ tick(dt) {
14028
+ if (remaining > 0) {
14029
+ remaining = Math.max(0, remaining - dt);
14030
+ return "failure";
14031
+ }
14032
+ const s2 = child.tick(dt);
14033
+ if (s2 !== "running") {
14034
+ remaining = duration;
14035
+ child.reset();
14036
+ }
14037
+ return s2;
14038
+ },
14039
+ reset() {
14040
+ remaining = 0;
14041
+ child.reset();
14042
+ }
14043
+ };
14044
+ }
14045
+ function btSucceed(child) {
14046
+ return {
14047
+ tick(dt) {
14048
+ const s2 = child.tick(dt);
14049
+ return s2 === "running" ? "running" : "success";
14050
+ },
14051
+ reset() {
14052
+ child.reset();
14053
+ }
14054
+ };
14055
+ }
14056
+ function btFail(child) {
14057
+ return {
14058
+ tick(dt) {
14059
+ const s2 = child.tick(dt);
14060
+ return s2 === "running" ? "running" : "failure";
14061
+ },
14062
+ reset() {
14063
+ child.reset();
14064
+ }
14065
+ };
14066
+ }
14067
+ function useBehaviorTree(rootFactory) {
14068
+ const rootRef = useRef47(null);
14069
+ if (!rootRef.current) rootRef.current = rootFactory();
14070
+ const statusRef = useRef47("failure");
14071
+ const tick2 = useCallback33((dt) => {
14072
+ if (!rootRef.current) return "failure";
14073
+ const s2 = rootRef.current.tick(dt);
14074
+ statusRef.current = s2;
14075
+ return s2;
14076
+ }, []);
14077
+ const reset = useCallback33(() => {
14078
+ rootRef.current?.reset();
14079
+ }, []);
14080
+ return {
14081
+ tick: tick2,
14082
+ reset,
14083
+ get lastStatus() {
14084
+ return statusRef.current;
14085
+ }
14086
+ };
14087
+ }
14088
+
13545
14089
  // ../gameplay/src/components/DialogueBox.tsx
13546
14090
  import { jsx as jsx21, jsxs as jsxs10 } from "react/jsx-runtime";
13547
14091
  function DialogueBox({ dialogue, onAdvance, onClose, style = {} }) {
@@ -13651,17 +14195,17 @@ function DialogueBox({ dialogue, onAdvance, onClose, style = {} }) {
13651
14195
  }
13652
14196
 
13653
14197
  // ../gameplay/src/hooks/useCutscene.ts
13654
- import { useState as useState30, useCallback as useCallback31, useRef as useRef45, useEffect as useEffect79, useContext as useContext77 } from "react";
14198
+ import { useState as useState31, useCallback as useCallback34, useRef as useRef48, useEffect as useEffect80, useContext as useContext77 } from "react";
13655
14199
  function useCutscene() {
13656
14200
  const engine = useContext77(EngineContext);
13657
- const [playing, setPlaying] = useState30(false);
13658
- const [stepIndex, setStepIndex] = useState30(0);
13659
- const stepsRef = useRef45([]);
13660
- const timerRef = useRef45(0);
13661
- const idxRef = useRef45(0);
13662
- const playingRef = useRef45(false);
13663
- const entityRef = useRef45(null);
13664
- const finish = useCallback31(() => {
14201
+ const [playing, setPlaying] = useState31(false);
14202
+ const [stepIndex, setStepIndex] = useState31(0);
14203
+ const stepsRef = useRef48([]);
14204
+ const timerRef = useRef48(0);
14205
+ const idxRef = useRef48(0);
14206
+ const playingRef = useRef48(false);
14207
+ const entityRef = useRef48(null);
14208
+ const finish = useCallback34(() => {
13665
14209
  playingRef.current = false;
13666
14210
  setPlaying(false);
13667
14211
  setStepIndex(0);
@@ -13671,14 +14215,14 @@ function useCutscene() {
13671
14215
  entityRef.current = null;
13672
14216
  }
13673
14217
  }, [engine.ecs]);
13674
- const fireStep = useCallback31((step) => {
14218
+ const fireStep = useCallback34((step) => {
13675
14219
  if (step.type === "call") step.fn();
13676
14220
  if (step.type === "parallel")
13677
14221
  step.steps.forEach((s2) => {
13678
14222
  if (s2.type === "call") s2.fn();
13679
14223
  });
13680
14224
  }, []);
13681
- const play = useCallback31(
14225
+ const play = useCallback34(
13682
14226
  (steps) => {
13683
14227
  stepsRef.current = steps;
13684
14228
  idxRef.current = 0;
@@ -13735,7 +14279,7 @@ function useCutscene() {
13735
14279
  },
13736
14280
  [engine.ecs, finish, fireStep]
13737
14281
  );
13738
- const skip = useCallback31(() => {
14282
+ const skip = useCallback34(() => {
13739
14283
  for (let i = idxRef.current; i < stepsRef.current.length; i++) {
13740
14284
  const step = stepsRef.current[i];
13741
14285
  if (step.type === "call") step.fn();
@@ -13746,7 +14290,7 @@ function useCutscene() {
13746
14290
  }
13747
14291
  finish();
13748
14292
  }, [finish]);
13749
- useEffect79(() => {
14293
+ useEffect80(() => {
13750
14294
  return () => {
13751
14295
  if (entityRef.current !== null && engine.ecs.hasEntity(entityRef.current)) {
13752
14296
  engine.ecs.destroyEntity(entityRef.current);
@@ -13757,7 +14301,7 @@ function useCutscene() {
13757
14301
  }
13758
14302
 
13759
14303
  // ../gameplay/src/hooks/useGameStore.ts
13760
- import { useSyncExternalStore as useSyncExternalStore2, useCallback as useCallback32 } from "react";
14304
+ import { useSyncExternalStore as useSyncExternalStore2, useCallback as useCallback35 } from "react";
13761
14305
  function createStore(initialState) {
13762
14306
  let state = { ...initialState };
13763
14307
  const listeners = /* @__PURE__ */ new Set();
@@ -13783,7 +14327,7 @@ function useGameStore(key, initialState) {
13783
14327
  }
13784
14328
  const store = stores.get(key);
13785
14329
  const state = useSyncExternalStore2(store.subscribe, store.getState);
13786
- const setState = useCallback32(
14330
+ const setState = useCallback35(
13787
14331
  (partial) => {
13788
14332
  store.setState(partial);
13789
14333
  },
@@ -13793,21 +14337,21 @@ function useGameStore(key, initialState) {
13793
14337
  }
13794
14338
 
13795
14339
  // ../gameplay/src/hooks/useTween.ts
13796
- import { useRef as useRef46, useCallback as useCallback33, useEffect as useEffect80 } from "react";
14340
+ import { useRef as useRef49, useCallback as useCallback36, useEffect as useEffect81 } from "react";
13797
14341
  function useTween(opts) {
13798
- const rafRef = useRef46(null);
13799
- const startTimeRef = useRef46(0);
13800
- const runningRef = useRef46(false);
13801
- const optsRef = useRef46(opts);
14342
+ const rafRef = useRef49(null);
14343
+ const startTimeRef = useRef49(0);
14344
+ const runningRef = useRef49(false);
14345
+ const optsRef = useRef49(opts);
13802
14346
  optsRef.current = opts;
13803
- const stop = useCallback33(() => {
14347
+ const stop = useCallback36(() => {
13804
14348
  if (rafRef.current !== null) {
13805
14349
  cancelAnimationFrame(rafRef.current);
13806
14350
  rafRef.current = null;
13807
14351
  }
13808
14352
  runningRef.current = false;
13809
14353
  }, []);
13810
- const start2 = useCallback33(() => {
14354
+ const start2 = useCallback36(() => {
13811
14355
  stop();
13812
14356
  runningRef.current = true;
13813
14357
  startTimeRef.current = performance.now();
@@ -13829,12 +14373,12 @@ function useTween(opts) {
13829
14373
  };
13830
14374
  rafRef.current = requestAnimationFrame(tick2);
13831
14375
  }, [stop]);
13832
- useEffect80(() => {
14376
+ useEffect81(() => {
13833
14377
  if (opts.autoStart) {
13834
14378
  start2();
13835
14379
  }
13836
14380
  }, []);
13837
- useEffect80(() => {
14381
+ useEffect81(() => {
13838
14382
  return () => {
13839
14383
  if (rafRef.current !== null) {
13840
14384
  cancelAnimationFrame(rafRef.current);
@@ -13853,15 +14397,15 @@ function useTween(opts) {
13853
14397
  }
13854
14398
 
13855
14399
  // ../gameplay/src/hooks/useObjectPool.ts
13856
- import { useRef as useRef47, useMemo as useMemo17, useEffect as useEffect81 } from "react";
14400
+ import { useRef as useRef50, useMemo as useMemo17, useEffect as useEffect82 } from "react";
13857
14401
  function useObjectPool(factory, reset, initialSize) {
13858
- const poolRef = useRef47([]);
13859
- const activeRef = useRef47(0);
13860
- const factoryRef = useRef47(factory);
14402
+ const poolRef = useRef50([]);
14403
+ const activeRef = useRef50(0);
14404
+ const factoryRef = useRef50(factory);
13861
14405
  factoryRef.current = factory;
13862
- const resetRef = useRef47(reset);
14406
+ const resetRef = useRef50(reset);
13863
14407
  resetRef.current = reset;
13864
- useEffect81(() => {
14408
+ useEffect82(() => {
13865
14409
  if (initialSize != null && initialSize > 0) {
13866
14410
  const pool = poolRef.current;
13867
14411
  for (let i = 0; i < initialSize; i++) {
@@ -14099,7 +14643,7 @@ function HUDBar({
14099
14643
  display: "flex",
14100
14644
  flexDirection: rtl ? "row-reverse" : "row"
14101
14645
  };
14102
- const labelStyle = {
14646
+ const labelStyle2 = {
14103
14647
  fontFamily: "system-ui, sans-serif",
14104
14648
  fontSize: 11,
14105
14649
  letterSpacing: 0.5,
@@ -14111,7 +14655,7 @@ function HUDBar({
14111
14655
  marginBottom: 4
14112
14656
  };
14113
14657
  return /* @__PURE__ */ jsxs11("div", { style: { display: "flex", flexDirection: "column", ...style }, "aria-label": label, children: [
14114
- (label || showValue) && /* @__PURE__ */ jsxs11("div", { style: labelStyle, children: [
14658
+ (label || showValue) && /* @__PURE__ */ jsxs11("div", { style: labelStyle2, children: [
14115
14659
  label && /* @__PURE__ */ jsx22("span", { children: label }),
14116
14660
  showValue && /* @__PURE__ */ jsxs11("span", { style: { fontVariantNumeric: "tabular-nums" }, children: [
14117
14661
  Math.round(value),
@@ -14183,7 +14727,7 @@ function definePrefab(name, defaults, render) {
14183
14727
  }
14184
14728
 
14185
14729
  // src/hooks/useNetworkSync.ts
14186
- import { useEffect as useEffect83, useRef as useRef49 } from "react";
14730
+ import { useEffect as useEffect84, useRef as useRef52 } from "react";
14187
14731
 
14188
14732
  // ../../packages/net/src/transport.ts
14189
14733
  function isBinaryTransport(t) {
@@ -14528,17 +15072,17 @@ function syncEntity(config) {
14528
15072
  }
14529
15073
 
14530
15074
  // ../../packages/net/src/useNetworkInput.ts
14531
- import { useState as useState31, useEffect as useEffect82, useRef as useRef48 } from "react";
15075
+ import { useState as useState32, useEffect as useEffect83, useRef as useRef51 } from "react";
14532
15076
  var INPUT_MSG_TYPE = "input:state";
14533
15077
  function useNetworkInput(config) {
14534
15078
  const { room, keys, input, tickRate = 20 } = config;
14535
15079
  const intervalMs = 1e3 / tickRate;
14536
- const [localInput, setLocalInput] = useState31(
15080
+ const [localInput, setLocalInput] = useState32(
14537
15081
  () => Object.fromEntries(keys.map((k) => [k, false]))
14538
15082
  );
14539
- const [remoteInputs] = useState31(() => /* @__PURE__ */ new Map());
14540
- const localInputRef = useRef48(localInput);
14541
- useEffect82(() => {
15083
+ const [remoteInputs] = useState32(() => /* @__PURE__ */ new Map());
15084
+ const localInputRef = useRef51(localInput);
15085
+ useEffect83(() => {
14542
15086
  let cleanupDom = null;
14543
15087
  if (!input) {
14544
15088
  let handleKeyDown2 = function(e) {
@@ -14752,9 +15296,9 @@ function lerpState(a, b, t) {
14752
15296
 
14753
15297
  // src/hooks/useNetworkSync.ts
14754
15298
  function useNetworkSync(entityId, components, room, world, owner, opts = {}) {
14755
- const optsRef = useRef49(opts);
15299
+ const optsRef = useRef52(opts);
14756
15300
  optsRef.current = opts;
14757
- useEffect83(() => {
15301
+ useEffect84(() => {
14758
15302
  const sync = syncEntity({
14759
15303
  entityId,
14760
15304
  components,
@@ -14769,18 +15313,18 @@ function useNetworkSync(entityId, components, room, world, owner, opts = {}) {
14769
15313
  }
14770
15314
 
14771
15315
  // src/hooks/useRemotePlayer.ts
14772
- import { useEffect as useEffect84, useRef as useRef50, useState as useState32 } from "react";
15316
+ import { useEffect as useEffect85, useRef as useRef53, useState as useState33 } from "react";
14773
15317
  var PEER_JOIN_MSG = "peer:join";
14774
15318
  var PEER_LEAVE_MSG = "peer:leave";
14775
15319
  function useRemotePlayer(config) {
14776
15320
  const { room, world, createEntity, destroyEntity } = config;
14777
- const [players, setPlayers] = useState32(() => /* @__PURE__ */ new Map());
14778
- const playersRef = useRef50(players);
14779
- const createRef = useRef50(createEntity);
15321
+ const [players, setPlayers] = useState33(() => /* @__PURE__ */ new Map());
15322
+ const playersRef = useRef53(players);
15323
+ const createRef = useRef53(createEntity);
14780
15324
  createRef.current = createEntity;
14781
- const destroyRef = useRef50(destroyEntity);
15325
+ const destroyRef = useRef53(destroyEntity);
14782
15326
  destroyRef.current = destroyEntity;
14783
- useEffect84(() => {
15327
+ useEffect85(() => {
14784
15328
  function spawnPeer(peerId) {
14785
15329
  if (playersRef.current.has(peerId)) return;
14786
15330
  const entityId = createRef.current(peerId);
@@ -14819,12 +15363,558 @@ function useRemotePlayer(config) {
14819
15363
  }, [room, world]);
14820
15364
  return { players };
14821
15365
  }
15366
+
15367
+ // ../editor/src/components/SceneHierarchy.tsx
15368
+ import { jsx as jsx23, jsxs as jsxs12 } from "react/jsx-runtime";
15369
+ var panelStyle = {
15370
+ background: "#0d1520",
15371
+ borderRight: "1px solid #1a2a3a",
15372
+ color: "#c0d0e0",
15373
+ fontFamily: "system-ui, sans-serif",
15374
+ fontSize: 12,
15375
+ display: "flex",
15376
+ flexDirection: "column",
15377
+ overflow: "hidden",
15378
+ userSelect: "none"
15379
+ };
15380
+ var headerStyle = {
15381
+ padding: "6px 10px",
15382
+ fontSize: 10,
15383
+ fontWeight: 700,
15384
+ textTransform: "uppercase",
15385
+ letterSpacing: 1,
15386
+ color: "#4fc3f7",
15387
+ borderBottom: "1px solid #1a2a3a",
15388
+ flexShrink: 0
15389
+ };
15390
+ var listStyle = {
15391
+ flex: 1,
15392
+ overflowY: "auto",
15393
+ padding: "4px 0"
15394
+ };
15395
+ function entityRowStyle(selected) {
15396
+ return {
15397
+ display: "flex",
15398
+ alignItems: "center",
15399
+ gap: 6,
15400
+ padding: "3px 10px",
15401
+ cursor: "pointer",
15402
+ background: selected ? "#1a3050" : "transparent",
15403
+ borderLeft: selected ? "2px solid #4fc3f7" : "2px solid transparent",
15404
+ color: selected ? "#e0f0ff" : "#a0b4c8",
15405
+ transition: "background 80ms"
15406
+ };
15407
+ }
15408
+ var componentBadgeStyle = {
15409
+ fontSize: 9,
15410
+ background: "#1a2a3a",
15411
+ color: "#607080",
15412
+ borderRadius: 3,
15413
+ padding: "1px 4px",
15414
+ maxWidth: 60,
15415
+ overflow: "hidden",
15416
+ textOverflow: "ellipsis",
15417
+ whiteSpace: "nowrap"
15418
+ };
15419
+ function SceneHierarchy({ entities, selectedId, onSelect, width = 220, style }) {
15420
+ return /* @__PURE__ */ jsxs12("div", { style: { ...panelStyle, width, ...style }, children: [
15421
+ /* @__PURE__ */ jsx23("div", { style: headerStyle, children: "Scene Hierarchy" }),
15422
+ /* @__PURE__ */ jsxs12("div", { style: { padding: "4px 10px", borderBottom: "1px solid #1a2a3a", color: "#4a5a6a", fontSize: 10 }, children: [
15423
+ entities.length,
15424
+ " ",
15425
+ entities.length === 1 ? "entity" : "entities"
15426
+ ] }),
15427
+ /* @__PURE__ */ jsxs12("div", { style: listStyle, children: [
15428
+ entities.map((e) => /* @__PURE__ */ jsx23(
15429
+ "div",
15430
+ {
15431
+ style: entityRowStyle(e.id === selectedId),
15432
+ onClick: () => onSelect(e.id === selectedId ? null : e.id),
15433
+ children: /* @__PURE__ */ jsxs12("div", { style: { flex: 1, overflow: "hidden" }, children: [
15434
+ /* @__PURE__ */ jsx23("div", { style: { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: e.name }),
15435
+ /* @__PURE__ */ jsxs12("div", { style: { display: "flex", gap: 3, marginTop: 2, flexWrap: "wrap" }, children: [
15436
+ e.componentTypes.slice(0, 3).map((t) => /* @__PURE__ */ jsx23("span", { style: componentBadgeStyle, children: t }, t)),
15437
+ e.componentTypes.length > 3 && /* @__PURE__ */ jsxs12("span", { style: componentBadgeStyle, children: [
15438
+ "+",
15439
+ e.componentTypes.length - 3
15440
+ ] })
15441
+ ] })
15442
+ ] })
15443
+ },
15444
+ e.id
15445
+ )),
15446
+ entities.length === 0 && /* @__PURE__ */ jsx23("div", { style: { padding: "10px", color: "#3a5060", fontSize: 11, textAlign: "center" }, children: "No entities" })
15447
+ ] })
15448
+ ] });
15449
+ }
15450
+
15451
+ // ../editor/src/components/PropertyField.tsx
15452
+ import { jsx as jsx24, jsxs as jsxs13 } from "react/jsx-runtime";
15453
+ var fieldRow = {
15454
+ display: "flex",
15455
+ alignItems: "center",
15456
+ gap: 6,
15457
+ marginBottom: 4,
15458
+ minHeight: 24
15459
+ };
15460
+ var labelStyle = {
15461
+ flex: "0 0 90px",
15462
+ fontSize: 11,
15463
+ color: "#8899aa",
15464
+ overflow: "hidden",
15465
+ textOverflow: "ellipsis",
15466
+ whiteSpace: "nowrap",
15467
+ fontFamily: "system-ui, sans-serif",
15468
+ textTransform: "uppercase",
15469
+ letterSpacing: 0.5
15470
+ };
15471
+ var inputBase = {
15472
+ flex: 1,
15473
+ background: "#1a2030",
15474
+ border: "1px solid #2a3a50",
15475
+ borderRadius: 3,
15476
+ color: "#d0e0f0",
15477
+ padding: "2px 6px",
15478
+ fontSize: 11,
15479
+ fontFamily: "monospace",
15480
+ outline: "none",
15481
+ minWidth: 0
15482
+ };
15483
+ function NumberField({ label, value, onChange, step = 1 }) {
15484
+ return /* @__PURE__ */ jsxs13("div", { style: fieldRow, children: [
15485
+ /* @__PURE__ */ jsx24("span", { style: labelStyle, title: label, children: label }),
15486
+ /* @__PURE__ */ jsx24(
15487
+ "input",
15488
+ {
15489
+ type: "number",
15490
+ style: inputBase,
15491
+ value: isNaN(value) ? "" : value,
15492
+ step,
15493
+ onChange: (e) => {
15494
+ const v = parseFloat(e.target.value);
15495
+ if (!isNaN(v)) onChange(v);
15496
+ }
15497
+ }
15498
+ )
15499
+ ] });
15500
+ }
15501
+ function TextField({ label, value, onChange }) {
15502
+ return /* @__PURE__ */ jsxs13("div", { style: fieldRow, children: [
15503
+ /* @__PURE__ */ jsx24("span", { style: labelStyle, title: label, children: label }),
15504
+ /* @__PURE__ */ jsx24("input", { type: "text", style: inputBase, value, onChange: (e) => onChange(e.target.value) })
15505
+ ] });
15506
+ }
15507
+ function BoolField({ label, value, onChange }) {
15508
+ return /* @__PURE__ */ jsxs13("div", { style: fieldRow, children: [
15509
+ /* @__PURE__ */ jsx24("span", { style: labelStyle, title: label, children: label }),
15510
+ /* @__PURE__ */ jsx24(
15511
+ "input",
15512
+ {
15513
+ type: "checkbox",
15514
+ checked: value,
15515
+ style: { accentColor: "#4fc3f7", cursor: "pointer" },
15516
+ onChange: (e) => onChange(e.target.checked)
15517
+ }
15518
+ )
15519
+ ] });
15520
+ }
15521
+ function ColorField({ label, value, onChange }) {
15522
+ return /* @__PURE__ */ jsxs13("div", { style: fieldRow, children: [
15523
+ /* @__PURE__ */ jsx24("span", { style: labelStyle, title: label, children: label }),
15524
+ /* @__PURE__ */ jsxs13("div", { style: { display: "flex", gap: 4, flex: 1 }, children: [
15525
+ /* @__PURE__ */ jsx24(
15526
+ "input",
15527
+ {
15528
+ type: "color",
15529
+ value: value.startsWith("#") ? value.slice(0, 7) : "#ffffff",
15530
+ style: { width: 28, height: 22, padding: 1, border: "1px solid #2a3a50", borderRadius: 3, cursor: "pointer" },
15531
+ onChange: (e) => onChange(e.target.value)
15532
+ }
15533
+ ),
15534
+ /* @__PURE__ */ jsx24("input", { type: "text", style: { ...inputBase, flex: 1 }, value, onChange: (e) => onChange(e.target.value) })
15535
+ ] })
15536
+ ] });
15537
+ }
15538
+ function Vec2Field({ label, x, y, onChangeX, onChangeY, step = 1 }) {
15539
+ return /* @__PURE__ */ jsxs13("div", { style: fieldRow, children: [
15540
+ /* @__PURE__ */ jsx24("span", { style: labelStyle, title: label, children: label }),
15541
+ /* @__PURE__ */ jsxs13("div", { style: { display: "flex", gap: 4, flex: 1 }, children: [
15542
+ /* @__PURE__ */ jsx24(
15543
+ "input",
15544
+ {
15545
+ type: "number",
15546
+ style: { ...inputBase, flex: 1 },
15547
+ value: isNaN(x) ? "" : x,
15548
+ step,
15549
+ onChange: (e) => {
15550
+ const v = parseFloat(e.target.value);
15551
+ if (!isNaN(v)) onChangeX(v);
15552
+ }
15553
+ }
15554
+ ),
15555
+ /* @__PURE__ */ jsx24(
15556
+ "input",
15557
+ {
15558
+ type: "number",
15559
+ style: { ...inputBase, flex: 1 },
15560
+ value: isNaN(y) ? "" : y,
15561
+ step,
15562
+ onChange: (e) => {
15563
+ const v = parseFloat(e.target.value);
15564
+ if (!isNaN(v)) onChangeY(v);
15565
+ }
15566
+ }
15567
+ )
15568
+ ] })
15569
+ ] });
15570
+ }
15571
+
15572
+ // ../editor/src/components/EntityInspector.tsx
15573
+ import { Fragment as Fragment10, jsx as jsx25, jsxs as jsxs14 } from "react/jsx-runtime";
15574
+ var panelStyle2 = {
15575
+ background: "#0d1520",
15576
+ borderLeft: "1px solid #1a2a3a",
15577
+ color: "#c0d0e0",
15578
+ fontFamily: "system-ui, sans-serif",
15579
+ fontSize: 12,
15580
+ display: "flex",
15581
+ flexDirection: "column",
15582
+ overflow: "hidden",
15583
+ userSelect: "none"
15584
+ };
15585
+ var headerStyle2 = {
15586
+ padding: "6px 10px",
15587
+ fontSize: 10,
15588
+ fontWeight: 700,
15589
+ textTransform: "uppercase",
15590
+ letterSpacing: 1,
15591
+ color: "#4fc3f7",
15592
+ borderBottom: "1px solid #1a2a3a",
15593
+ flexShrink: 0
15594
+ };
15595
+ var scrollStyle = {
15596
+ flex: 1,
15597
+ overflowY: "auto",
15598
+ padding: "6px 0"
15599
+ };
15600
+ var componentSectionStyle = {
15601
+ marginBottom: 2,
15602
+ borderBottom: "1px solid #131d2a"
15603
+ };
15604
+ var componentHeaderStyle = {
15605
+ display: "flex",
15606
+ alignItems: "center",
15607
+ padding: "4px 10px",
15608
+ fontSize: 10,
15609
+ fontWeight: 700,
15610
+ textTransform: "uppercase",
15611
+ letterSpacing: 0.8,
15612
+ color: "#80a8c0",
15613
+ cursor: "default",
15614
+ background: "#0f1a28"
15615
+ };
15616
+ var fieldsStyle = {
15617
+ padding: "4px 10px 6px"
15618
+ };
15619
+ function isColorKey(key) {
15620
+ const lower = key.toLowerCase();
15621
+ return lower === "color" || lower === "background" || lower === "fill" || lower === "stroke" || lower.includes("color");
15622
+ }
15623
+ function ComponentSection({ comp }) {
15624
+ const compRecord = comp;
15625
+ const entries = Object.entries(comp).filter(([k]) => k !== "type");
15626
+ const rendered = /* @__PURE__ */ new Set();
15627
+ return /* @__PURE__ */ jsxs14("div", { style: componentSectionStyle, children: [
15628
+ /* @__PURE__ */ jsx25("div", { style: componentHeaderStyle, children: comp.type }),
15629
+ /* @__PURE__ */ jsxs14("div", { style: fieldsStyle, children: [
15630
+ entries.map(([key, val]) => {
15631
+ if (rendered.has(key)) return null;
15632
+ if (key === "x" && typeof val === "number" && typeof compRecord["y"] === "number") {
15633
+ rendered.add("x");
15634
+ rendered.add("y");
15635
+ return /* @__PURE__ */ jsx25(
15636
+ Vec2Field,
15637
+ {
15638
+ label: "pos",
15639
+ x: val,
15640
+ y: compRecord["y"],
15641
+ step: 0.5,
15642
+ onChangeX: (v) => {
15643
+ compRecord["x"] = v;
15644
+ },
15645
+ onChangeY: (v) => {
15646
+ compRecord["y"] = v;
15647
+ }
15648
+ },
15649
+ "xy"
15650
+ );
15651
+ }
15652
+ if (key === "followOffsetX" && typeof val === "number") {
15653
+ const oy = compRecord["followOffsetY"];
15654
+ if (typeof oy === "number") {
15655
+ rendered.add("followOffsetX");
15656
+ rendered.add("followOffsetY");
15657
+ return /* @__PURE__ */ jsx25(
15658
+ Vec2Field,
15659
+ {
15660
+ label: "offset",
15661
+ x: val,
15662
+ y: oy,
15663
+ step: 1,
15664
+ onChangeX: (v) => {
15665
+ compRecord["followOffsetX"] = v;
15666
+ },
15667
+ onChangeY: (v) => {
15668
+ compRecord["followOffsetY"] = v;
15669
+ }
15670
+ },
15671
+ "followOffset"
15672
+ );
15673
+ }
15674
+ }
15675
+ if (typeof val === "number") {
15676
+ rendered.add(key);
15677
+ return /* @__PURE__ */ jsx25(
15678
+ NumberField,
15679
+ {
15680
+ label: key,
15681
+ value: val,
15682
+ step: Math.abs(val) < 2 ? 0.01 : 1,
15683
+ onChange: (v) => {
15684
+ compRecord[key] = v;
15685
+ }
15686
+ },
15687
+ key
15688
+ );
15689
+ }
15690
+ if (typeof val === "string" && isColorKey(key)) {
15691
+ rendered.add(key);
15692
+ return /* @__PURE__ */ jsx25(
15693
+ ColorField,
15694
+ {
15695
+ label: key,
15696
+ value: val,
15697
+ onChange: (v) => {
15698
+ compRecord[key] = v;
15699
+ }
15700
+ },
15701
+ key
15702
+ );
15703
+ }
15704
+ if (typeof val === "string") {
15705
+ rendered.add(key);
15706
+ return /* @__PURE__ */ jsx25(
15707
+ TextField,
15708
+ {
15709
+ label: key,
15710
+ value: val,
15711
+ onChange: (v) => {
15712
+ compRecord[key] = v;
15713
+ }
15714
+ },
15715
+ key
15716
+ );
15717
+ }
15718
+ if (typeof val === "boolean") {
15719
+ rendered.add(key);
15720
+ return /* @__PURE__ */ jsx25(
15721
+ BoolField,
15722
+ {
15723
+ label: key,
15724
+ value: val,
15725
+ onChange: (v) => {
15726
+ compRecord[key] = v;
15727
+ }
15728
+ },
15729
+ key
15730
+ );
15731
+ }
15732
+ if (val !== null && val !== void 0 && typeof val !== "function") {
15733
+ rendered.add(key);
15734
+ const preview = typeof val === "object" ? JSON.stringify(val).slice(0, 60) : String(val);
15735
+ return /* @__PURE__ */ jsxs14(
15736
+ "div",
15737
+ {
15738
+ style: {
15739
+ display: "flex",
15740
+ gap: 6,
15741
+ marginBottom: 4,
15742
+ fontSize: 11,
15743
+ alignItems: "flex-start"
15744
+ },
15745
+ children: [
15746
+ /* @__PURE__ */ jsx25(
15747
+ "span",
15748
+ {
15749
+ style: {
15750
+ flex: "0 0 90px",
15751
+ color: "#6a7a8a",
15752
+ textTransform: "uppercase",
15753
+ fontSize: 10,
15754
+ letterSpacing: 0.5,
15755
+ paddingTop: 2
15756
+ },
15757
+ children: key
15758
+ }
15759
+ ),
15760
+ /* @__PURE__ */ jsx25(
15761
+ "span",
15762
+ {
15763
+ style: { flex: 1, color: "#506070", fontFamily: "monospace", wordBreak: "break-all", fontSize: 10 },
15764
+ children: preview
15765
+ }
15766
+ )
15767
+ ]
15768
+ },
15769
+ key
15770
+ );
15771
+ }
15772
+ return null;
15773
+ }),
15774
+ entries.length === 0 && /* @__PURE__ */ jsx25("div", { style: { color: "#3a5060", fontSize: 10 }, children: "No fields" })
15775
+ ] })
15776
+ ] });
15777
+ }
15778
+ function EntityInspector({ entity, components, width = 260, style }) {
15779
+ return /* @__PURE__ */ jsxs14("div", { style: { ...panelStyle2, width, ...style }, children: [
15780
+ /* @__PURE__ */ jsx25("div", { style: headerStyle2, children: "Inspector" }),
15781
+ entity ? /* @__PURE__ */ jsxs14(Fragment10, { children: [
15782
+ /* @__PURE__ */ jsxs14(
15783
+ "div",
15784
+ {
15785
+ style: {
15786
+ padding: "6px 10px",
15787
+ borderBottom: "1px solid #1a2a3a",
15788
+ color: "#d0e0f0",
15789
+ fontSize: 12,
15790
+ fontWeight: 600
15791
+ },
15792
+ children: [
15793
+ entity.name,
15794
+ /* @__PURE__ */ jsxs14("span", { style: { color: "#4a6070", fontSize: 10, marginLeft: 6 }, children: [
15795
+ "#",
15796
+ entity.id
15797
+ ] })
15798
+ ]
15799
+ }
15800
+ ),
15801
+ /* @__PURE__ */ jsxs14("div", { style: scrollStyle, children: [
15802
+ components.map((comp) => /* @__PURE__ */ jsx25(ComponentSection, { comp }, comp.type)),
15803
+ components.length === 0 && /* @__PURE__ */ jsx25("div", { style: { padding: "10px", color: "#3a5060", fontSize: 11, textAlign: "center" }, children: "No components" })
15804
+ ] })
15805
+ ] }) : /* @__PURE__ */ jsx25(
15806
+ "div",
15807
+ {
15808
+ style: {
15809
+ flex: 1,
15810
+ display: "flex",
15811
+ alignItems: "center",
15812
+ justifyContent: "center",
15813
+ color: "#2a4050",
15814
+ fontSize: 11
15815
+ },
15816
+ children: "Select an entity"
15817
+ }
15818
+ )
15819
+ ] });
15820
+ }
15821
+
15822
+ // ../editor/src/hooks/useEditorState.ts
15823
+ import { useState as useState34, useCallback as useCallback37, useContext as useContext81, useEffect as useEffect86, useRef as useRef54 } from "react";
15824
+ function buildEntityInfo(engine) {
15825
+ const nameMap = /* @__PURE__ */ new Map();
15826
+ engine.entityIds.forEach((eid, name) => nameMap.set(eid, name));
15827
+ const ids = engine.ecs.getAllEntityIds();
15828
+ return ids.map((id) => {
15829
+ const comps = engine.ecs.getEntityComponents(id);
15830
+ return {
15831
+ id,
15832
+ name: nameMap.get(id) ?? `Entity #${id}`,
15833
+ componentTypes: comps.map((c) => c.type)
15834
+ };
15835
+ });
15836
+ }
15837
+ function useEditorState(refreshHz = 4) {
15838
+ const engine = useContext81(EngineContext);
15839
+ const [entities, setEntities] = useState34([]);
15840
+ const [selectedId, setSelectedId] = useState34(null);
15841
+ const intervalRef = useRef54(null);
15842
+ const refresh = useCallback37(() => {
15843
+ setEntities(buildEntityInfo(engine));
15844
+ }, [engine]);
15845
+ useEffect86(() => {
15846
+ refresh();
15847
+ intervalRef.current = setInterval(refresh, 1e3 / refreshHz);
15848
+ return () => {
15849
+ if (intervalRef.current !== null) clearInterval(intervalRef.current);
15850
+ };
15851
+ }, [refresh, refreshHz]);
15852
+ const select = useCallback37((id) => {
15853
+ setSelectedId(id);
15854
+ }, []);
15855
+ const selectedComponents = selectedId !== null ? engine.ecs.getEntityComponents(selectedId) : [];
15856
+ return { entities, selectedId, selectedComponents, select, refresh };
15857
+ }
15858
+
15859
+ // ../editor/src/components/EditorShell.tsx
15860
+ import { Fragment as Fragment11, jsx as jsx26, jsxs as jsxs15 } from "react/jsx-runtime";
15861
+ function EditorShell({
15862
+ children,
15863
+ active = true,
15864
+ hierarchyWidth = 220,
15865
+ inspectorWidth = 260,
15866
+ style
15867
+ }) {
15868
+ const state = useEditorState();
15869
+ const selectedEntity = state.entities.find((e) => e.id === state.selectedId) ?? null;
15870
+ if (!active) {
15871
+ return /* @__PURE__ */ jsx26(Fragment11, { children });
15872
+ }
15873
+ const shellStyle = {
15874
+ position: "absolute",
15875
+ inset: 0,
15876
+ display: "flex",
15877
+ flexDirection: "row",
15878
+ pointerEvents: "none",
15879
+ zIndex: 200,
15880
+ ...style
15881
+ };
15882
+ const sideStyle = {
15883
+ pointerEvents: "auto",
15884
+ flexShrink: 0,
15885
+ height: "100%",
15886
+ overflow: "hidden"
15887
+ };
15888
+ return /* @__PURE__ */ jsxs15("div", { style: shellStyle, children: [
15889
+ /* @__PURE__ */ jsx26("div", { style: sideStyle, children: /* @__PURE__ */ jsx26(
15890
+ SceneHierarchy,
15891
+ {
15892
+ entities: state.entities,
15893
+ selectedId: state.selectedId,
15894
+ onSelect: state.select,
15895
+ width: hierarchyWidth,
15896
+ style: { height: "100%" }
15897
+ }
15898
+ ) }),
15899
+ /* @__PURE__ */ jsx26("div", { style: { flex: 1, pointerEvents: "none" }, children }),
15900
+ /* @__PURE__ */ jsx26("div", { style: sideStyle, children: /* @__PURE__ */ jsx26(
15901
+ EntityInspector,
15902
+ {
15903
+ entity: selectedEntity,
15904
+ components: state.selectedComponents,
15905
+ width: inspectorWidth,
15906
+ style: { height: "100%" }
15907
+ }
15908
+ ) })
15909
+ ] });
15910
+ }
14822
15911
  export {
14823
15912
  A11yNode,
14824
15913
  AnimatedSprite,
14825
15914
  Animation,
14826
15915
  Animator,
14827
15916
  AssetLoader,
15917
+ BoolField,
14828
15918
  BoxCollider,
14829
15919
  COLLISION_DYNAMIC_DYNAMIC,
14830
15920
  COLLISION_DYNAMIC_KINEMATIC,
@@ -14840,6 +15930,7 @@ export {
14840
15930
  CircleCollider,
14841
15931
  ClientPrediction,
14842
15932
  CollisionPipeline,
15933
+ ColorField,
14843
15934
  ComboDetector,
14844
15935
  CompoundCollider,
14845
15936
  ConvexCollider,
@@ -14848,7 +15939,9 @@ export {
14848
15939
  DialogueBox,
14849
15940
  Ease,
14850
15941
  EditableText,
15942
+ EditorShell,
14851
15943
  Entity,
15944
+ EntityInspector,
14852
15945
  FocusRing,
14853
15946
  Game,
14854
15947
  Gradient,
@@ -14866,6 +15959,7 @@ export {
14866
15959
  Mask,
14867
15960
  MovingPlatform,
14868
15961
  NineSlice,
15962
+ NumberField,
14869
15963
  PARTICLE_PRESETS,
14870
15964
  ParallaxLayer,
14871
15965
  ParticleEmitter,
@@ -14873,6 +15967,7 @@ export {
14873
15967
  RenderSystem,
14874
15968
  RigidBody,
14875
15969
  Room,
15970
+ SceneHierarchy,
14876
15971
  SceneTransitionOverlay,
14877
15972
  ScreenFlash,
14878
15973
  Script,
@@ -14883,6 +15978,7 @@ export {
14883
15978
  SquashStretch,
14884
15979
  Stage,
14885
15980
  Text,
15981
+ TextField,
14886
15982
  TextureFilter,
14887
15983
  Tilemap,
14888
15984
  Trail,
@@ -14890,6 +15986,7 @@ export {
14890
15986
  TransformHandles,
14891
15987
  TriMeshCollider,
14892
15988
  TriangleCollider,
15989
+ Vec2Field,
14893
15990
  VectorPath,
14894
15991
  VirtualCamera,
14895
15992
  VirtualJoystick,
@@ -14905,6 +16002,18 @@ export {
14905
16002
  applyTorqueImpulse,
14906
16003
  arrive,
14907
16004
  boxArea,
16005
+ btAction,
16006
+ btCondition,
16007
+ btCooldown,
16008
+ btFail,
16009
+ btInvert,
16010
+ btParallel,
16011
+ btRepeat,
16012
+ btRetryUntilSuccess,
16013
+ btSelector,
16014
+ btSequence,
16015
+ btSucceed,
16016
+ btWait,
14908
16017
  capsuleArea,
14909
16018
  chromaticAberrationEffect,
14910
16019
  circleArea,
@@ -15031,6 +16140,7 @@ export {
15031
16140
  useAudioAnalyser,
15032
16141
  useAudioListener,
15033
16142
  useAudioScheduler,
16143
+ useBehaviorTree,
15034
16144
  useCamera,
15035
16145
  useCameraBlend,
15036
16146
  useCameraLookahead,
@@ -15050,9 +16160,11 @@ export {
15050
16160
  useDamageZone,
15051
16161
  useDestroyEntity,
15052
16162
  useDialogue,
16163
+ useDialogueTree,
15053
16164
  useDraggable,
15054
16165
  useDropThrough,
15055
16166
  useDroppable,
16167
+ useEditorState,
15056
16168
  useEntity,
15057
16169
  useEvent,
15058
16170
  useEvents,
@@ -15104,6 +16216,7 @@ export {
15104
16216
  useSnap,
15105
16217
  useSnapshot,
15106
16218
  useSound,
16219
+ useSoundscape,
15107
16220
  useSpatialSound,
15108
16221
  useSquashStretch,
15109
16222
  useStreamedMusic,