cubeforge 0.6.2 → 0.7.0

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) {
@@ -4583,7 +4583,7 @@ function useCollidingWith() {
4583
4583
  // ../devtools/src/DevTools.tsx
4584
4584
  import React from "react";
4585
4585
  import { createPortal } from "react-dom";
4586
- import { useState as useState2, useEffect as useEffect10, useCallback, useRef as useRef10 } from "react";
4586
+ import { useState as useState2, useEffect as useEffect11, useCallback as useCallback2, useRef as useRef11 } from "react";
4587
4587
 
4588
4588
  // ../../packages/audio/src/useSound.ts
4589
4589
  import { useEffect as useEffect3, useRef as useRef3 } from "react";
@@ -4905,24 +4905,24 @@ function useSound(src, opts = {}) {
4905
4905
  // ../../packages/audio/src/useSpatialSound.ts
4906
4906
  import { useEffect as useEffect4, useRef as useRef4 } from "react";
4907
4907
  async function loadBuffer2(src) {
4908
- const bufferCache2 = _getBufferCache();
4908
+ const bufferCache3 = _getBufferCache();
4909
4909
  const bufferRefCount2 = _getBufferRefCount();
4910
4910
  bufferRefCount2.set(src, (bufferRefCount2.get(src) ?? 0) + 1);
4911
- const cached = bufferCache2.get(src);
4911
+ const cached = bufferCache3.get(src);
4912
4912
  if (cached) return cached;
4913
4913
  const res = await fetch(src);
4914
4914
  const data = await res.arrayBuffer();
4915
4915
  const buf = await getAudioCtx().decodeAudioData(data);
4916
- bufferCache2.set(src, buf);
4916
+ bufferCache3.set(src, buf);
4917
4917
  return buf;
4918
4918
  }
4919
4919
  function releaseBuffer2(src) {
4920
- const bufferCache2 = _getBufferCache();
4920
+ const bufferCache3 = _getBufferCache();
4921
4921
  const bufferRefCount2 = _getBufferRefCount();
4922
4922
  const count = bufferRefCount2.get(src) ?? 0;
4923
4923
  if (count <= 1) {
4924
4924
  bufferRefCount2.delete(src);
4925
- bufferCache2.delete(src);
4925
+ bufferCache3.delete(src);
4926
4926
  } else {
4927
4927
  bufferRefCount2.set(src, count - 1);
4928
4928
  }
@@ -5492,20 +5492,20 @@ function usePreloadAudio(srcs) {
5492
5492
  cancelledRef.current = false;
5493
5493
  if (srcs.length === 0) return;
5494
5494
  const unique = [...new Set(srcs)];
5495
- const bufferCache2 = _getBufferCache();
5495
+ const bufferCache3 = _getBufferCache();
5496
5496
  const bufferRefCount2 = _getBufferRefCount();
5497
5497
  const ctx = getAudioCtx();
5498
5498
  const loadOne = async (src) => {
5499
5499
  try {
5500
- if (!preloadCache.has(src) && !bufferCache2.has(src)) {
5500
+ if (!preloadCache.has(src) && !bufferCache3.has(src)) {
5501
5501
  const res = await fetch(src);
5502
5502
  const data = await res.arrayBuffer();
5503
5503
  const buf = await ctx.decodeAudioData(data);
5504
5504
  preloadCache.set(src, buf);
5505
- bufferCache2.set(src, buf);
5505
+ bufferCache3.set(src, buf);
5506
5506
  bufferRefCount2.set(src, (bufferRefCount2.get(src) ?? 0) + 1);
5507
- } else if (!preloadCache.has(src) && bufferCache2.has(src)) {
5508
- preloadCache.set(src, bufferCache2.get(src));
5507
+ } else if (!preloadCache.has(src) && bufferCache3.has(src)) {
5508
+ preloadCache.set(src, bufferCache3.get(src));
5509
5509
  }
5510
5510
  } catch {
5511
5511
  if (!cancelledRef.current) {
@@ -5533,6 +5533,156 @@ function usePreloadAudio(srcs) {
5533
5533
  };
5534
5534
  }
5535
5535
 
5536
+ // ../../packages/audio/src/useSoundscape.ts
5537
+ import { useEffect as useEffect10, useRef as useRef10, useCallback } from "react";
5538
+ var bufferCache2 = /* @__PURE__ */ new Map();
5539
+ async function loadBuffer3(src) {
5540
+ const cached = bufferCache2.get(src);
5541
+ if (cached) return cached;
5542
+ const res = await fetch(src);
5543
+ const data = await res.arrayBuffer();
5544
+ const buf = await getAudioCtx().decodeAudioData(data);
5545
+ bufferCache2.set(src, buf);
5546
+ return buf;
5547
+ }
5548
+ function useSoundscape(layers, opts = {}) {
5549
+ const { volume: masterVolume = 1, fadeIn = 1, fadeOut = 1, group = "ambient", active = true } = opts;
5550
+ const masterGainRef = useRef10(null);
5551
+ const layerStatesRef = useRef10(/* @__PURE__ */ new Map());
5552
+ const activeRef = useRef10(active);
5553
+ useEffect10(() => {
5554
+ const ctx = getAudioCtx();
5555
+ const masterGain = ctx.createGain();
5556
+ masterGain.gain.setValueAtTime(0, ctx.currentTime);
5557
+ masterGain.connect(getGroupGainNode(group));
5558
+ masterGainRef.current = masterGain;
5559
+ const destroyed = { current: false };
5560
+ const layerStates = layerStatesRef.current;
5561
+ const loadPromises = [];
5562
+ for (const layer of layers) {
5563
+ const layerGain = ctx.createGain();
5564
+ const targetVol = layer.active === false ? 0 : layer.volume ?? 1;
5565
+ layerGain.gain.setValueAtTime(targetVol, ctx.currentTime);
5566
+ layerGain.connect(masterGain);
5567
+ const state = {
5568
+ src: layer.src,
5569
+ gainNode: layerGain,
5570
+ source: null,
5571
+ targetVolume: targetVol,
5572
+ unregister: null
5573
+ };
5574
+ layerStates.set(layer.src, state);
5575
+ const p = loadBuffer3(layer.src).then((buf) => {
5576
+ if (destroyed.current) return;
5577
+ const source = ctx.createBufferSource();
5578
+ source.buffer = buf;
5579
+ source.loop = true;
5580
+ source.connect(layerGain);
5581
+ const offset = layer.randomOffset && layer.randomOffset > 0 ? Math.random() * layer.randomOffset : 0;
5582
+ source.start(0, offset % buf.duration);
5583
+ state.source = source;
5584
+ state.unregister = registerGroupSource(group, () => {
5585
+ try {
5586
+ source.stop();
5587
+ } catch {
5588
+ }
5589
+ });
5590
+ });
5591
+ loadPromises.push(p);
5592
+ }
5593
+ Promise.all(loadPromises).then(() => {
5594
+ if (destroyed.current) return;
5595
+ if (!activeRef.current) return;
5596
+ const now = ctx.currentTime;
5597
+ if (fadeIn > 0) {
5598
+ masterGain.gain.cancelScheduledValues(now);
5599
+ masterGain.gain.setValueAtTime(0, now);
5600
+ masterGain.gain.linearRampToValueAtTime(masterVolume, now + fadeIn);
5601
+ } else {
5602
+ masterGain.gain.setValueAtTime(masterVolume, now);
5603
+ }
5604
+ });
5605
+ return () => {
5606
+ destroyed.current = true;
5607
+ const now = ctx.currentTime;
5608
+ const stopAll = () => {
5609
+ for (const state of layerStates.values()) {
5610
+ state.unregister?.();
5611
+ if (state.source) {
5612
+ try {
5613
+ state.source.stop();
5614
+ } catch {
5615
+ }
5616
+ }
5617
+ state.gainNode.disconnect();
5618
+ }
5619
+ layerStates.clear();
5620
+ masterGain.disconnect();
5621
+ };
5622
+ if (fadeOut > 0) {
5623
+ masterGain.gain.cancelScheduledValues(now);
5624
+ masterGain.gain.setValueAtTime(masterGain.gain.value, now);
5625
+ masterGain.gain.linearRampToValueAtTime(0, now + fadeOut);
5626
+ setTimeout(stopAll, fadeOut * 1e3 + 50);
5627
+ } else {
5628
+ stopAll();
5629
+ }
5630
+ };
5631
+ }, []);
5632
+ useEffect10(() => {
5633
+ activeRef.current = active;
5634
+ const masterGain = masterGainRef.current;
5635
+ if (!masterGain) return;
5636
+ const ctx = getAudioCtx();
5637
+ const now = ctx.currentTime;
5638
+ const target = active ? masterVolume : 0;
5639
+ const duration = active ? fadeIn : fadeOut;
5640
+ masterGain.gain.cancelScheduledValues(now);
5641
+ masterGain.gain.setValueAtTime(masterGain.gain.value, now);
5642
+ if (duration > 0) {
5643
+ masterGain.gain.linearRampToValueAtTime(target, now + duration);
5644
+ } else {
5645
+ masterGain.gain.setValueAtTime(target, now);
5646
+ }
5647
+ }, [active, masterVolume, fadeIn, fadeOut]);
5648
+ const setVolume = useCallback((volume, duration = 0) => {
5649
+ const masterGain = masterGainRef.current;
5650
+ if (!masterGain) return;
5651
+ const ctx = getAudioCtx();
5652
+ const now = ctx.currentTime;
5653
+ const clamped = Math.max(0, Math.min(1, volume));
5654
+ masterGain.gain.cancelScheduledValues(now);
5655
+ masterGain.gain.setValueAtTime(masterGain.gain.value, now);
5656
+ if (duration > 0) {
5657
+ masterGain.gain.linearRampToValueAtTime(clamped, now + duration);
5658
+ } else {
5659
+ masterGain.gain.setValueAtTime(clamped, now);
5660
+ }
5661
+ }, []);
5662
+ const setLayerVolume = useCallback((src, volume, duration = 0) => {
5663
+ const state = layerStatesRef.current.get(src);
5664
+ if (!state) return;
5665
+ const ctx = getAudioCtx();
5666
+ const now = ctx.currentTime;
5667
+ const clamped = Math.max(0, Math.min(1, volume));
5668
+ state.targetVolume = clamped;
5669
+ state.gainNode.gain.cancelScheduledValues(now);
5670
+ state.gainNode.gain.setValueAtTime(state.gainNode.gain.value, now);
5671
+ if (duration > 0) {
5672
+ state.gainNode.gain.linearRampToValueAtTime(clamped, now + duration);
5673
+ } else {
5674
+ state.gainNode.gain.setValueAtTime(clamped, now);
5675
+ }
5676
+ }, []);
5677
+ const fadeLayer = useCallback(
5678
+ (src, targetVolume, duration) => {
5679
+ setLayerVolume(src, targetVolume, duration);
5680
+ },
5681
+ [setLayerVolume]
5682
+ );
5683
+ return { setVolume, setLayerVolume, fadeLayer };
5684
+ }
5685
+
5536
5686
  // ../../packages/audio/src/listener.ts
5537
5687
  function setListenerPosition(x, y) {
5538
5688
  const ctx = getAudioCtx();
@@ -5720,8 +5870,8 @@ function DevToolsOverlay({ handle, loop, ecs, engine }) {
5720
5870
  const [showNavGrid, setShowNavGrid] = useState2(false);
5721
5871
  const [showContactFlash, setShowContactFlash] = useState2(false);
5722
5872
  const [hidden, setHidden] = useState2(false);
5723
- const frameRef = useRef10(0);
5724
- useEffect10(() => {
5873
+ const frameRef = useRef11(0);
5874
+ useEffect11(() => {
5725
5875
  const onKey = (e) => {
5726
5876
  if (e.key === "`" && !e.ctrlKey && !e.metaKey && !e.altKey) {
5727
5877
  setHidden((v) => !v);
@@ -5730,7 +5880,7 @@ function DevToolsOverlay({ handle, loop, ecs, engine }) {
5730
5880
  window.addEventListener("keydown", onKey);
5731
5881
  return () => window.removeEventListener("keydown", onKey);
5732
5882
  }, []);
5733
- useEffect10(() => {
5883
+ useEffect11(() => {
5734
5884
  handle.onFrame = () => {
5735
5885
  frameRef.current++;
5736
5886
  if (!paused) {
@@ -5742,14 +5892,14 @@ function DevToolsOverlay({ handle, loop, ecs, engine }) {
5742
5892
  handle.onFrame = void 0;
5743
5893
  };
5744
5894
  }, [handle, paused]);
5745
- useEffect10(() => {
5895
+ useEffect11(() => {
5746
5896
  const rs = engine?.activeRenderSystem;
5747
5897
  rs?.setEntityHighlight?.(selectedEntity);
5748
5898
  return () => {
5749
5899
  rs?.setEntityHighlight?.(null);
5750
5900
  };
5751
5901
  }, [engine, selectedEntity]);
5752
- useEffect10(() => {
5902
+ useEffect11(() => {
5753
5903
  if (!engine) return;
5754
5904
  const events = engine.events;
5755
5905
  const types = ["triggerEnter", "triggerExit", "collisionEnter", "collisionExit", "circleEnter", "circleExit"];
@@ -5781,7 +5931,7 @@ function DevToolsOverlay({ handle, loop, ecs, engine }) {
5781
5931
  }, [engine, showContactFlash]);
5782
5932
  const totalFrames = handle.buffer.length;
5783
5933
  const currentSnap = handle.buffer[selectedIdx];
5784
- const handlePauseResume = useCallback(() => {
5934
+ const handlePauseResume = useCallback2(() => {
5785
5935
  if (paused) {
5786
5936
  if (currentSnap) ecs.restoreSnapshot(currentSnap);
5787
5937
  loop.resume();
@@ -5793,15 +5943,15 @@ function DevToolsOverlay({ handle, loop, ecs, engine }) {
5793
5943
  setSelectedIdx(Math.max(0, handle.buffer.length - 1));
5794
5944
  }
5795
5945
  }, [paused, currentSnap, ecs, loop, handle]);
5796
- const stepBack = useCallback(() => {
5946
+ const stepBack = useCallback2(() => {
5797
5947
  setSelectedIdx((i) => Math.max(0, i - 1));
5798
5948
  setSelectedEntity(null);
5799
5949
  }, []);
5800
- const stepForward = useCallback(() => {
5950
+ const stepForward = useCallback2(() => {
5801
5951
  setSelectedIdx((i) => Math.min(handle.buffer.length - 1, i + 1));
5802
5952
  setSelectedEntity(null);
5803
5953
  }, [handle]);
5804
- const handleToggleNavGrid = useCallback(() => {
5954
+ const handleToggleNavGrid = useCallback2(() => {
5805
5955
  if (!engine) return;
5806
5956
  const renderer = engine.activeRenderSystem;
5807
5957
  if (!renderer?.setDebugNavGrid) return;
@@ -6668,14 +6818,14 @@ function Game({
6668
6818
  className,
6669
6819
  children
6670
6820
  }) {
6671
- const canvasRef = useRef11(null);
6672
- const debugCanvasRef = useRef11(null);
6673
- const wrapperRef = useRef11(null);
6821
+ const canvasRef = useRef12(null);
6822
+ const debugCanvasRef = useRef12(null);
6823
+ const wrapperRef = useRef12(null);
6674
6824
  const [engine, setEngine] = useState3(null);
6675
6825
  const [assetsReady, setAssetsReady] = useState3(asyncAssets);
6676
6826
  const [webglError, setWebglError] = useState3(null);
6677
- const devtoolsHandle = useRef11({ buffer: [] });
6678
- useEffect11(() => {
6827
+ const devtoolsHandle = useRef12({ buffer: [] });
6828
+ useEffect12(() => {
6679
6829
  const canvas = canvasRef.current;
6680
6830
  const ecs = new ECSWorld();
6681
6831
  if (deterministic) ecs.setDeterministicSeed(seed);
@@ -6829,7 +6979,7 @@ function Game({
6829
6979
  }
6830
6980
  };
6831
6981
  }, []);
6832
- useEffect11(() => {
6982
+ useEffect12(() => {
6833
6983
  if (!engine) return;
6834
6984
  let cancelled = false;
6835
6985
  if (asyncAssets) {
@@ -6847,7 +6997,7 @@ function Game({
6847
6997
  cancelled = true;
6848
6998
  };
6849
6999
  }, [engine]);
6850
- useEffect11(() => {
7000
+ useEffect12(() => {
6851
7001
  if (!engine) return;
6852
7002
  const dpr = window.devicePixelRatio || 1;
6853
7003
  const physW = Math.round(width * dpr);
@@ -6858,7 +7008,7 @@ function Game({
6858
7008
  canvas.style.width = `${width}px`;
6859
7009
  canvas.style.height = `${height}px`;
6860
7010
  }, [width, height, engine]);
6861
- useEffect11(() => {
7011
+ useEffect12(() => {
6862
7012
  engine?.physics.setGravity(gravity);
6863
7013
  }, [gravity, engine]);
6864
7014
  const canvasStyle = {
@@ -6974,15 +7124,15 @@ function Stage(props) {
6974
7124
  }
6975
7125
 
6976
7126
  // src/components/World.tsx
6977
- import { useEffect as useEffect12, useContext as useContext3 } from "react";
7127
+ import { useEffect as useEffect13, useContext as useContext3 } from "react";
6978
7128
  import { Fragment as Fragment2, jsx as jsx4 } from "react/jsx-runtime";
6979
7129
  function World({ gravity, background = "#1a1a2e", children }) {
6980
7130
  const engine = useContext3(EngineContext);
6981
- useEffect12(() => {
7131
+ useEffect13(() => {
6982
7132
  if (!engine) return;
6983
7133
  if (gravity !== void 0) engine.physics.setGravity(gravity);
6984
7134
  }, [gravity, engine]);
6985
- useEffect12(() => {
7135
+ useEffect13(() => {
6986
7136
  if (!engine) return;
6987
7137
  const camId = engine.ecs.queryOne("Camera2D");
6988
7138
  if (camId !== void 0) {
@@ -6996,7 +7146,7 @@ function World({ gravity, background = "#1a1a2e", children }) {
6996
7146
  }
6997
7147
 
6998
7148
  // src/components/Entity.tsx
6999
- import { useEffect as useEffect13, useContext as useContext4, useState as useState4 } from "react";
7149
+ import { useEffect as useEffect14, useContext as useContext4, useState as useState4 } from "react";
7000
7150
  import { jsx as jsx5 } from "react/jsx-runtime";
7001
7151
  function Entity({ id, tags = [], children }) {
7002
7152
  const engine = useContext4(EngineContext);
@@ -7006,7 +7156,7 @@ function Entity({ id, tags = [], children }) {
7006
7156
  console.warn("[Cubeforge] <Entity> must be inside a <World>. No EngineContext found.");
7007
7157
  }
7008
7158
  }
7009
- useEffect13(() => {
7159
+ useEffect14(() => {
7010
7160
  const eid = engine.ecs.createEntity();
7011
7161
  if (id) {
7012
7162
  if (engine.entityIds.has(id)) {
@@ -7028,15 +7178,15 @@ function Entity({ id, tags = [], children }) {
7028
7178
  }
7029
7179
 
7030
7180
  // src/components/Transform.tsx
7031
- import { useEffect as useEffect14, useContext as useContext5 } from "react";
7181
+ import { useEffect as useEffect15, useContext as useContext5 } from "react";
7032
7182
  function Transform({ x = 0, y = 0, rotation = 0, scaleX = 1, scaleY = 1 }) {
7033
7183
  const engine = useContext5(EngineContext);
7034
7184
  const entityId = useContext5(EntityContext);
7035
- useEffect14(() => {
7185
+ useEffect15(() => {
7036
7186
  engine.ecs.addComponent(entityId, createTransform(x, y, rotation, scaleX, scaleY));
7037
7187
  return () => engine.ecs.removeComponent(entityId, "Transform");
7038
7188
  }, []);
7039
- useEffect14(() => {
7189
+ useEffect15(() => {
7040
7190
  const comp = engine.ecs.getComponent(entityId, "Transform");
7041
7191
  if (comp) {
7042
7192
  comp.x = x;
@@ -7050,7 +7200,7 @@ function Transform({ x = 0, y = 0, rotation = 0, scaleX = 1, scaleY = 1 }) {
7050
7200
  }
7051
7201
 
7052
7202
  // src/components/Sprite.tsx
7053
- import { useEffect as useEffect15, useContext as useContext6, useRef as useRef12 } from "react";
7203
+ import { useEffect as useEffect16, useContext as useContext6, useRef as useRef13 } from "react";
7054
7204
  function Sprite({
7055
7205
  width,
7056
7206
  height,
@@ -7101,7 +7251,7 @@ function Sprite({
7101
7251
  );
7102
7252
  }
7103
7253
  }
7104
- useEffect15(() => {
7254
+ useEffect16(() => {
7105
7255
  const comp = createSprite({
7106
7256
  width,
7107
7257
  height,
@@ -7153,8 +7303,8 @@ function Sprite({
7153
7303
  }
7154
7304
  return () => engine.ecs.removeComponent(entityId, "Sprite");
7155
7305
  }, []);
7156
- const didMount = useRef12(false);
7157
- useEffect15(() => {
7306
+ const didMount = useRef13(false);
7307
+ useEffect16(() => {
7158
7308
  if (!didMount.current) {
7159
7309
  didMount.current = true;
7160
7310
  return;
@@ -7184,7 +7334,7 @@ function Sprite({
7184
7334
  cancelled = true;
7185
7335
  };
7186
7336
  }, [src, engine, entityId]);
7187
- useEffect15(() => {
7337
+ useEffect16(() => {
7188
7338
  const comp = engine.ecs.getComponent(entityId, "Sprite");
7189
7339
  if (!comp) return;
7190
7340
  comp.color = color;
@@ -7231,7 +7381,7 @@ function Sprite({
7231
7381
  }
7232
7382
 
7233
7383
  // src/components/Text.tsx
7234
- import { useEffect as useEffect16, useContext as useContext7 } from "react";
7384
+ import { useEffect as useEffect17, useContext as useContext7 } from "react";
7235
7385
  function Text({
7236
7386
  text,
7237
7387
  fontSize = 16,
@@ -7256,7 +7406,7 @@ function Text({
7256
7406
  }) {
7257
7407
  const engine = useContext7(EngineContext);
7258
7408
  const entityId = useContext7(EntityContext);
7259
- useEffect16(() => {
7409
+ useEffect17(() => {
7260
7410
  const comp = createText({
7261
7411
  text,
7262
7412
  fontSize,
@@ -7282,7 +7432,7 @@ function Text({
7282
7432
  engine.ecs.addComponent(entityId, comp);
7283
7433
  return () => engine.ecs.removeComponent(entityId, "Text");
7284
7434
  }, []);
7285
- useEffect16(() => {
7435
+ useEffect17(() => {
7286
7436
  const comp = engine.ecs.getComponent(entityId, "Text");
7287
7437
  if (!comp) return;
7288
7438
  comp.text = text;
@@ -7319,7 +7469,7 @@ function Text({
7319
7469
  }
7320
7470
 
7321
7471
  // src/components/RigidBody.tsx
7322
- import { useEffect as useEffect17, useContext as useContext8 } from "react";
7472
+ import { useEffect as useEffect18, useContext as useContext8 } from "react";
7323
7473
  function RigidBody({
7324
7474
  mass = 0,
7325
7475
  gravityScale = 1,
@@ -7349,7 +7499,7 @@ function RigidBody({
7349
7499
  console.warn("[Cubeforge] <RigidBody> must be inside an <Entity>. No EntityContext found.");
7350
7500
  }
7351
7501
  }
7352
- useEffect17(() => {
7502
+ useEffect18(() => {
7353
7503
  engine.ecs.addComponent(
7354
7504
  entityId,
7355
7505
  createRigidBody({
@@ -7381,7 +7531,7 @@ function RigidBody({
7381
7531
  }
7382
7532
 
7383
7533
  // src/components/BoxCollider.tsx
7384
- import { useEffect as useEffect18, useContext as useContext9 } from "react";
7534
+ import { useEffect as useEffect19, useContext as useContext9 } from "react";
7385
7535
  function BoxCollider({
7386
7536
  width,
7387
7537
  height,
@@ -7399,7 +7549,7 @@ function BoxCollider({
7399
7549
  }) {
7400
7550
  const engine = useContext9(EngineContext);
7401
7551
  const entityId = useContext9(EntityContext);
7402
- useEffect18(() => {
7552
+ useEffect19(() => {
7403
7553
  engine.ecs.addComponent(
7404
7554
  entityId,
7405
7555
  createBoxCollider(width, height, {
@@ -7437,7 +7587,7 @@ function BoxCollider({
7437
7587
  }
7438
7588
 
7439
7589
  // src/components/CircleCollider.tsx
7440
- import { useEffect as useEffect19, useContext as useContext10 } from "react";
7590
+ import { useEffect as useEffect20, useContext as useContext10 } from "react";
7441
7591
  function CircleCollider({
7442
7592
  radius,
7443
7593
  offsetX = 0,
@@ -7453,7 +7603,7 @@ function CircleCollider({
7453
7603
  }) {
7454
7604
  const engine = useContext10(EngineContext);
7455
7605
  const entityId = useContext10(EntityContext);
7456
- useEffect19(() => {
7606
+ useEffect20(() => {
7457
7607
  engine.ecs.addComponent(
7458
7608
  entityId,
7459
7609
  createCircleCollider(radius, {
@@ -7475,7 +7625,7 @@ function CircleCollider({
7475
7625
  }
7476
7626
 
7477
7627
  // src/components/CapsuleCollider.tsx
7478
- import { useEffect as useEffect20, useContext as useContext11 } from "react";
7628
+ import { useEffect as useEffect21, useContext as useContext11 } from "react";
7479
7629
  function CapsuleCollider({
7480
7630
  width,
7481
7631
  height,
@@ -7492,7 +7642,7 @@ function CapsuleCollider({
7492
7642
  }) {
7493
7643
  const engine = useContext11(EngineContext);
7494
7644
  const entityId = useContext11(EntityContext);
7495
- useEffect20(() => {
7645
+ useEffect21(() => {
7496
7646
  engine.ecs.addComponent(
7497
7647
  entityId,
7498
7648
  createCapsuleCollider(width, height, {
@@ -7514,11 +7664,11 @@ function CapsuleCollider({
7514
7664
  }
7515
7665
 
7516
7666
  // src/components/CompoundCollider.tsx
7517
- import { useEffect as useEffect21, useContext as useContext12 } from "react";
7667
+ import { useEffect as useEffect22, useContext as useContext12 } from "react";
7518
7668
  function CompoundCollider({ shapes, isTrigger = false, layer = "default", mask = "*" }) {
7519
7669
  const engine = useContext12(EngineContext);
7520
7670
  const entityId = useContext12(EntityContext);
7521
- useEffect21(() => {
7671
+ useEffect22(() => {
7522
7672
  engine.ecs.addComponent(entityId, createCompoundCollider(shapes, { isTrigger, layer, mask }));
7523
7673
  const checkId = setTimeout(() => {
7524
7674
  if (engine.ecs.hasEntity(entityId) && !engine.ecs.hasComponent(entityId, "Transform")) {
@@ -7534,7 +7684,7 @@ function CompoundCollider({ shapes, isTrigger = false, layer = "default", mask =
7534
7684
  }
7535
7685
 
7536
7686
  // src/components/Script.tsx
7537
- import { useEffect as useEffect22, useContext as useContext13, useRef as useRef13 } from "react";
7687
+ import { useEffect as useEffect23, useContext as useContext13, useRef as useRef14 } from "react";
7538
7688
  function Script({ init, update }) {
7539
7689
  const engine = useContext13(EngineContext);
7540
7690
  const entityId = useContext13(EntityContext);
@@ -7543,11 +7693,11 @@ function Script({ init, update }) {
7543
7693
  console.warn("[Cubeforge] <Script> must be inside an <Entity>. No EntityContext found.");
7544
7694
  }
7545
7695
  }
7546
- const initRef = useRef13(init);
7696
+ const initRef = useRef14(init);
7547
7697
  initRef.current = init;
7548
- const updateRef = useRef13(update);
7698
+ const updateRef = useRef14(update);
7549
7699
  updateRef.current = update;
7550
- useEffect22(() => {
7700
+ useEffect23(() => {
7551
7701
  if (initRef.current) {
7552
7702
  try {
7553
7703
  initRef.current(entityId, engine.ecs);
@@ -7563,7 +7713,7 @@ function Script({ init, update }) {
7563
7713
  }
7564
7714
 
7565
7715
  // src/components/Camera2D.tsx
7566
- import { useEffect as useEffect23, useContext as useContext14 } from "react";
7716
+ import { useEffect as useEffect24, useContext as useContext14 } from "react";
7567
7717
  function Camera2D({
7568
7718
  followEntity,
7569
7719
  x = 0,
@@ -7577,7 +7727,7 @@ function Camera2D({
7577
7727
  followOffsetY = 0
7578
7728
  }) {
7579
7729
  const engine = useContext14(EngineContext);
7580
- useEffect23(() => {
7730
+ useEffect24(() => {
7581
7731
  const entityId = engine.ecs.createEntity();
7582
7732
  engine.ecs.addComponent(
7583
7733
  entityId,
@@ -7596,7 +7746,7 @@ function Camera2D({
7596
7746
  );
7597
7747
  return () => engine.ecs.destroyEntity(entityId);
7598
7748
  }, []);
7599
- useEffect23(() => {
7749
+ useEffect24(() => {
7600
7750
  const camId = engine.ecs.queryOne("Camera2D");
7601
7751
  if (camId === void 0) return;
7602
7752
  const cam = engine.ecs.getComponent(camId, "Camera2D");
@@ -7615,11 +7765,11 @@ function Camera2D({
7615
7765
  }
7616
7766
 
7617
7767
  // src/components/Animation.tsx
7618
- import { useEffect as useEffect24, useContext as useContext15 } from "react";
7768
+ import { useEffect as useEffect25, useContext as useContext15 } from "react";
7619
7769
  function Animation({ frames, fps = 12, loop = true, playing = true, onComplete, frameEvents }) {
7620
7770
  const engine = useContext15(EngineContext);
7621
7771
  const entityId = useContext15(EntityContext);
7622
- useEffect24(() => {
7772
+ useEffect25(() => {
7623
7773
  const state = {
7624
7774
  type: "AnimationState",
7625
7775
  frames,
@@ -7637,7 +7787,7 @@ function Animation({ frames, fps = 12, loop = true, playing = true, onComplete,
7637
7787
  engine.ecs.removeComponent(entityId, "AnimationState");
7638
7788
  };
7639
7789
  }, []);
7640
- useEffect24(() => {
7790
+ useEffect25(() => {
7641
7791
  const anim = engine.ecs.getComponent(entityId, "AnimationState");
7642
7792
  if (!anim) return;
7643
7793
  const wasFramesChanged = anim.frames !== frames;
@@ -7657,7 +7807,7 @@ function Animation({ frames, fps = 12, loop = true, playing = true, onComplete,
7657
7807
  }
7658
7808
 
7659
7809
  // src/components/AnimatedSprite.tsx
7660
- import { useEffect as useEffect25, useContext as useContext16 } from "react";
7810
+ import { useEffect as useEffect26, useContext as useContext16 } from "react";
7661
7811
  import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
7662
7812
  function defineAnimations(clips) {
7663
7813
  return clips;
@@ -7746,7 +7896,7 @@ function AnimatedSprite(props) {
7746
7896
  function MultiClipAnimation({ animations, current }) {
7747
7897
  const engine = useContext16(EngineContext);
7748
7898
  const entityId = useContext16(EntityContext);
7749
- useEffect25(() => {
7899
+ useEffect26(() => {
7750
7900
  const clip = animations[current] ?? Object.values(animations)[0];
7751
7901
  const state = {
7752
7902
  type: "AnimationState",
@@ -7765,7 +7915,7 @@ function MultiClipAnimation({ animations, current }) {
7765
7915
  engine.ecs.addComponent(entityId, state);
7766
7916
  return () => engine.ecs.removeComponent(entityId, "AnimationState");
7767
7917
  }, []);
7768
- useEffect25(() => {
7918
+ useEffect26(() => {
7769
7919
  const anim = engine.ecs.getComponent(entityId, "AnimationState");
7770
7920
  if (!anim) return;
7771
7921
  anim.clips = animations;
@@ -7775,11 +7925,11 @@ function MultiClipAnimation({ animations, current }) {
7775
7925
  }
7776
7926
 
7777
7927
  // src/components/Animator.tsx
7778
- import { useEffect as useEffect26, useContext as useContext17 } from "react";
7928
+ import { useEffect as useEffect27, useContext as useContext17 } from "react";
7779
7929
  function Animator({ initial, states, params = {}, playing = true }) {
7780
7930
  const engine = useContext17(EngineContext);
7781
7931
  const entityId = useContext17(EntityContext);
7782
- useEffect26(() => {
7932
+ useEffect27(() => {
7783
7933
  const comp = {
7784
7934
  type: "Animator",
7785
7935
  initialState: initial,
@@ -7792,13 +7942,13 @@ function Animator({ initial, states, params = {}, playing = true }) {
7792
7942
  engine.ecs.addComponent(entityId, comp);
7793
7943
  return () => engine.ecs.removeComponent(entityId, "Animator");
7794
7944
  }, []);
7795
- useEffect26(() => {
7945
+ useEffect27(() => {
7796
7946
  const comp = engine.ecs.getComponent(entityId, "Animator");
7797
7947
  if (!comp) return;
7798
7948
  Object.assign(comp.params, params);
7799
7949
  comp.playing = playing;
7800
7950
  }, [params, playing, engine, entityId]);
7801
- useEffect26(() => {
7951
+ useEffect27(() => {
7802
7952
  const comp = engine.ecs.getComponent(entityId, "Animator");
7803
7953
  if (!comp) return;
7804
7954
  comp.states = states;
@@ -7807,11 +7957,11 @@ function Animator({ initial, states, params = {}, playing = true }) {
7807
7957
  }
7808
7958
 
7809
7959
  // src/components/SquashStretch.tsx
7810
- import { useEffect as useEffect27, useContext as useContext18 } from "react";
7960
+ import { useEffect as useEffect28, useContext as useContext18 } from "react";
7811
7961
  function SquashStretch({ intensity = 0.2, recovery = 8 }) {
7812
7962
  const engine = useContext18(EngineContext);
7813
7963
  const entityId = useContext18(EntityContext);
7814
- useEffect27(() => {
7964
+ useEffect28(() => {
7815
7965
  engine.ecs.addComponent(entityId, {
7816
7966
  type: "SquashStretch",
7817
7967
  intensity,
@@ -7825,7 +7975,7 @@ function SquashStretch({ intensity = 0.2, recovery = 8 }) {
7825
7975
  }
7826
7976
 
7827
7977
  // src/components/ParticleEmitter.tsx
7828
- import { useEffect as useEffect28, useContext as useContext19 } from "react";
7978
+ import { useEffect as useEffect29, useContext as useContext19 } from "react";
7829
7979
 
7830
7980
  // src/components/particlePresets.ts
7831
7981
  var PARTICLE_PRESETS = {
@@ -8109,7 +8259,7 @@ function ParticleEmitter({
8109
8259
  const resolvedSizeOverLife = sizeOverLife ?? presetConfig.sizeOverLife;
8110
8260
  const engine = useContext19(EngineContext);
8111
8261
  const entityId = useContext19(EntityContext);
8112
- useEffect28(() => {
8262
+ useEffect29(() => {
8113
8263
  engine.ecs.addComponent(entityId, {
8114
8264
  type: "ParticlePool",
8115
8265
  particles: [],
@@ -8144,23 +8294,23 @@ function ParticleEmitter({
8144
8294
  });
8145
8295
  return () => engine.ecs.removeComponent(entityId, "ParticlePool");
8146
8296
  }, []);
8147
- useEffect28(() => {
8297
+ useEffect29(() => {
8148
8298
  const pool = engine.ecs.getComponent(entityId, "ParticlePool");
8149
8299
  if (!pool) return;
8150
8300
  pool.active = active;
8151
8301
  }, [active, engine, entityId]);
8152
- useEffect28(() => {
8302
+ useEffect29(() => {
8153
8303
  const pool = engine.ecs.getComponent(entityId, "ParticlePool");
8154
8304
  if (!pool) return;
8155
8305
  pool.blendMode = resolvedBlendMode;
8156
8306
  pool.particleShape = resolvedParticleShape;
8157
8307
  }, [resolvedBlendMode, resolvedParticleShape, engine, entityId]);
8158
- useEffect28(() => {
8308
+ useEffect29(() => {
8159
8309
  const pool = engine.ecs.getComponent(entityId, "ParticlePool");
8160
8310
  if (!pool) return;
8161
8311
  pool.attractors = attractors;
8162
8312
  }, [attractors, engine, entityId]);
8163
- useEffect28(() => {
8313
+ useEffect29(() => {
8164
8314
  const pool = engine.ecs.getComponent(entityId, "ParticlePool");
8165
8315
  if (!pool || pool.mode !== "formation" || !formationPoints) return;
8166
8316
  pool.formationPoints = formationPoints;
@@ -8172,7 +8322,7 @@ function ParticleEmitter({
8172
8322
  }
8173
8323
  });
8174
8324
  }, [formationPoints, engine, entityId]);
8175
- useEffect28(() => {
8325
+ useEffect29(() => {
8176
8326
  const pool = engine.ecs.getComponent(entityId, "ParticlePool");
8177
8327
  if (!pool || !targetColor) return;
8178
8328
  pool._colorTransitionFrom = pool.color;
@@ -8184,7 +8334,7 @@ function ParticleEmitter({
8184
8334
  }
8185
8335
 
8186
8336
  // src/components/VirtualJoystick.tsx
8187
- import { useRef as useRef14 } from "react";
8337
+ import { useRef as useRef15 } from "react";
8188
8338
 
8189
8339
  // src/hooks/useVirtualInput.ts
8190
8340
  var _axes = { x: 0, y: 0 };
@@ -8218,10 +8368,10 @@ function VirtualJoystick({
8218
8368
  actionLabel = "A",
8219
8369
  actionName = "action"
8220
8370
  }) {
8221
- const baseRef = useRef14(null);
8222
- const stickRef = useRef14(null);
8223
- const activePtr = useRef14(null);
8224
- const baseCenterRef = useRef14({ x: 0, y: 0 });
8371
+ const baseRef = useRef15(null);
8372
+ const stickRef = useRef15(null);
8373
+ const activePtr = useRef15(null);
8374
+ const baseCenterRef = useRef15({ x: 0, y: 0 });
8225
8375
  const radius = size / 2 - 16;
8226
8376
  const applyStickPosition = (dx, dy) => {
8227
8377
  if (!stickRef.current) return;
@@ -8445,7 +8595,7 @@ function Checkpoint({
8445
8595
  }
8446
8596
 
8447
8597
  // src/components/Tilemap.tsx
8448
- import { useEffect as useEffect29, useState as useState6, useContext as useContext20 } from "react";
8598
+ import { useEffect as useEffect30, useState as useState6, useContext as useContext20 } from "react";
8449
8599
  import { Fragment as Fragment5, jsx as jsx10 } from "react/jsx-runtime";
8450
8600
  var animatedTiles = /* @__PURE__ */ new Map();
8451
8601
  function getProperty(props, name) {
@@ -8476,7 +8626,7 @@ function Tilemap({
8476
8626
  }) {
8477
8627
  const engine = useContext20(EngineContext);
8478
8628
  const [spawnedNodes, setSpawnedNodes] = useState6([]);
8479
- useEffect29(() => {
8629
+ useEffect30(() => {
8480
8630
  if (!engine) return;
8481
8631
  const createdEntities = [];
8482
8632
  async function load() {
@@ -8696,7 +8846,7 @@ function Tilemap({
8696
8846
  }
8697
8847
 
8698
8848
  // src/components/ParallaxLayer.tsx
8699
- import { useEffect as useEffect30, useContext as useContext21 } from "react";
8849
+ import { useEffect as useEffect31, useContext as useContext21 } from "react";
8700
8850
  import { jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
8701
8851
  function ParallaxLayerInner({
8702
8852
  src,
@@ -8710,7 +8860,7 @@ function ParallaxLayerInner({
8710
8860
  }) {
8711
8861
  const engine = useContext21(EngineContext);
8712
8862
  const entityId = useContext21(EntityContext);
8713
- useEffect30(() => {
8863
+ useEffect31(() => {
8714
8864
  engine.ecs.addComponent(entityId, {
8715
8865
  type: "ParallaxLayer",
8716
8866
  src,
@@ -8726,7 +8876,7 @@ function ParallaxLayerInner({
8726
8876
  });
8727
8877
  return () => engine.ecs.removeComponent(entityId, "ParallaxLayer");
8728
8878
  }, []);
8729
- useEffect30(() => {
8879
+ useEffect31(() => {
8730
8880
  const layer = engine.ecs.getComponent(entityId, "ParallaxLayer");
8731
8881
  if (!layer) return;
8732
8882
  layer.src = src;
@@ -8769,10 +8919,10 @@ function ParallaxLayer({
8769
8919
  }
8770
8920
 
8771
8921
  // src/components/ScreenFlash.tsx
8772
- import { forwardRef, useImperativeHandle, useRef as useRef15 } from "react";
8922
+ import { forwardRef, useImperativeHandle, useRef as useRef16 } from "react";
8773
8923
  import { jsx as jsx12 } from "react/jsx-runtime";
8774
8924
  var ScreenFlash = forwardRef((_, ref) => {
8775
- const divRef = useRef15(null);
8925
+ const divRef = useRef16(null);
8776
8926
  useImperativeHandle(ref, () => ({
8777
8927
  flash(color, duration) {
8778
8928
  const el = divRef.current;
@@ -8808,13 +8958,13 @@ var ScreenFlash = forwardRef((_, ref) => {
8808
8958
  ScreenFlash.displayName = "ScreenFlash";
8809
8959
 
8810
8960
  // src/components/CameraZone.tsx
8811
- import { useEffect as useEffect31, useContext as useContext22, useRef as useRef16 } from "react";
8961
+ import { useEffect as useEffect32, useContext as useContext22, useRef as useRef17 } from "react";
8812
8962
  import { Fragment as Fragment6, jsx as jsx13 } from "react/jsx-runtime";
8813
8963
  function CameraZone({ x, y, width, height, watchTag = "player", targetX, targetY, children }) {
8814
8964
  const engine = useContext22(EngineContext);
8815
- const prevFollowRef = useRef16(void 0);
8816
- const activeRef = useRef16(false);
8817
- useEffect31(() => {
8965
+ const prevFollowRef = useRef17(void 0);
8966
+ const activeRef = useRef17(false);
8967
+ useEffect32(() => {
8818
8968
  const eid = engine.ecs.createEntity();
8819
8969
  engine.ecs.addComponent(
8820
8970
  eid,
@@ -8864,7 +9014,7 @@ function CameraZone({ x, y, width, height, watchTag = "player", targetX, targetY
8864
9014
  }
8865
9015
 
8866
9016
  // src/components/VirtualCamera.tsx
8867
- import { useEffect as useEffect32, useContext as useContext23 } from "react";
9017
+ import { useEffect as useEffect33, useContext as useContext23 } from "react";
8868
9018
  var registries = /* @__PURE__ */ new WeakMap();
8869
9019
  var driverEids = /* @__PURE__ */ new WeakMap();
8870
9020
  var driverRefs = /* @__PURE__ */ new WeakMap();
@@ -8966,7 +9116,7 @@ function VirtualCamera({
8966
9116
  blendDuration = 0.4
8967
9117
  }) {
8968
9118
  const engine = useContext23(EngineContext);
8969
- useEffect32(() => {
9119
+ useEffect33(() => {
8970
9120
  acquireDriver(engine);
8971
9121
  const registry2 = getRegistry(engine);
8972
9122
  registry2.set(id, {
@@ -8986,7 +9136,7 @@ function VirtualCamera({
8986
9136
  releaseDriver(engine);
8987
9137
  };
8988
9138
  }, []);
8989
- useEffect32(() => {
9139
+ useEffect33(() => {
8990
9140
  const entry = getRegistry(engine).get(id);
8991
9141
  if (!entry) return;
8992
9142
  entry.priority = priority;
@@ -9003,11 +9153,11 @@ function VirtualCamera({
9003
9153
  }
9004
9154
 
9005
9155
  // src/components/Trail.tsx
9006
- import { useEffect as useEffect33, useContext as useContext24 } from "react";
9156
+ import { useEffect as useEffect34, useContext as useContext24 } from "react";
9007
9157
  function Trail({ length = 20, color = "#ffffff", width = 3 }) {
9008
9158
  const engine = useContext24(EngineContext);
9009
9159
  const entityId = useContext24(EntityContext);
9010
- useEffect33(() => {
9160
+ useEffect34(() => {
9011
9161
  engine.ecs.addComponent(entityId, createTrail({ length, color, width }));
9012
9162
  return () => engine.ecs.removeComponent(entityId, "Trail");
9013
9163
  }, []);
@@ -9015,7 +9165,7 @@ function Trail({ length = 20, color = "#ffffff", width = 3 }) {
9015
9165
  }
9016
9166
 
9017
9167
  // src/components/NineSlice.tsx
9018
- import { useEffect as useEffect34, useContext as useContext25 } from "react";
9168
+ import { useEffect as useEffect35, useContext as useContext25 } from "react";
9019
9169
  function NineSlice({
9020
9170
  src,
9021
9171
  width,
@@ -9028,7 +9178,7 @@ function NineSlice({
9028
9178
  }) {
9029
9179
  const engine = useContext25(EngineContext);
9030
9180
  const entityId = useContext25(EntityContext);
9031
- useEffect34(() => {
9181
+ useEffect35(() => {
9032
9182
  engine.ecs.addComponent(
9033
9183
  entityId,
9034
9184
  createNineSlice(src, width, height, {
@@ -9045,10 +9195,10 @@ function NineSlice({
9045
9195
  }
9046
9196
 
9047
9197
  // src/components/AssetLoader.tsx
9048
- import { useEffect as useEffect36 } from "react";
9198
+ import { useEffect as useEffect37 } from "react";
9049
9199
 
9050
9200
  // src/hooks/usePreload.ts
9051
- import { useState as useState7, useEffect as useEffect35, useContext as useContext26 } from "react";
9201
+ import { useState as useState7, useEffect as useEffect36, useContext as useContext26 } from "react";
9052
9202
  function usePreload(assets) {
9053
9203
  const engine = useContext26(EngineContext);
9054
9204
  const [state, setState] = useState7({
@@ -9056,7 +9206,7 @@ function usePreload(assets) {
9056
9206
  loaded: assets.length === 0,
9057
9207
  error: null
9058
9208
  });
9059
- useEffect35(() => {
9209
+ useEffect36(() => {
9060
9210
  if (assets.length === 0) {
9061
9211
  setState({ progress: 1, loaded: true, error: null });
9062
9212
  return;
@@ -9093,7 +9243,7 @@ function usePreload(assets) {
9093
9243
  import { Fragment as Fragment7, jsx as jsx14 } from "react/jsx-runtime";
9094
9244
  function AssetLoader({ assets, fallback = null, onError, children }) {
9095
9245
  const { loaded, error } = usePreload(assets);
9096
- useEffect36(() => {
9246
+ useEffect37(() => {
9097
9247
  if (error && onError) onError(error);
9098
9248
  }, [error, onError]);
9099
9249
  if (!loaded) {
@@ -9103,7 +9253,7 @@ function AssetLoader({ assets, fallback = null, onError, children }) {
9103
9253
  }
9104
9254
 
9105
9255
  // src/components/Circle.tsx
9106
- import { useEffect as useEffect37, useContext as useContext27 } from "react";
9256
+ import { useEffect as useEffect38, useContext as useContext27 } from "react";
9107
9257
  function Circle({
9108
9258
  radius = 16,
9109
9259
  color = "#ffffff",
@@ -9114,7 +9264,7 @@ function Circle({
9114
9264
  }) {
9115
9265
  const engine = useContext27(EngineContext);
9116
9266
  const entityId = useContext27(EntityContext);
9117
- useEffect37(() => {
9267
+ useEffect38(() => {
9118
9268
  const comp = createCircleShape({
9119
9269
  radius,
9120
9270
  color,
@@ -9126,7 +9276,7 @@ function Circle({
9126
9276
  engine.ecs.addComponent(entityId, comp);
9127
9277
  return () => engine.ecs.removeComponent(entityId, "CircleShape");
9128
9278
  }, []);
9129
- useEffect37(() => {
9279
+ useEffect38(() => {
9130
9280
  const comp = engine.ecs.getComponent(entityId, "CircleShape");
9131
9281
  if (!comp) return;
9132
9282
  comp.radius = radius;
@@ -9140,7 +9290,7 @@ function Circle({
9140
9290
  }
9141
9291
 
9142
9292
  // src/components/Line.tsx
9143
- import { useEffect as useEffect38, useContext as useContext28 } from "react";
9293
+ import { useEffect as useEffect39, useContext as useContext28 } from "react";
9144
9294
  function Line({
9145
9295
  endX,
9146
9296
  endY,
@@ -9152,7 +9302,7 @@ function Line({
9152
9302
  }) {
9153
9303
  const engine = useContext28(EngineContext);
9154
9304
  const entityId = useContext28(EntityContext);
9155
- useEffect38(() => {
9305
+ useEffect39(() => {
9156
9306
  const comp = createLineShape({
9157
9307
  endX,
9158
9308
  endY,
@@ -9165,7 +9315,7 @@ function Line({
9165
9315
  engine.ecs.addComponent(entityId, comp);
9166
9316
  return () => engine.ecs.removeComponent(entityId, "LineShape");
9167
9317
  }, []);
9168
- useEffect38(() => {
9318
+ useEffect39(() => {
9169
9319
  const comp = engine.ecs.getComponent(entityId, "LineShape");
9170
9320
  if (!comp) return;
9171
9321
  comp.endX = endX;
@@ -9180,7 +9330,7 @@ function Line({
9180
9330
  }
9181
9331
 
9182
9332
  // src/components/Polygon.tsx
9183
- import { useEffect as useEffect39, useContext as useContext29 } from "react";
9333
+ import { useEffect as useEffect40, useContext as useContext29 } from "react";
9184
9334
  function Polygon({
9185
9335
  points,
9186
9336
  color = "#ffffff",
@@ -9192,7 +9342,7 @@ function Polygon({
9192
9342
  }) {
9193
9343
  const engine = useContext29(EngineContext);
9194
9344
  const entityId = useContext29(EntityContext);
9195
- useEffect39(() => {
9345
+ useEffect40(() => {
9196
9346
  const comp = createPolygonShape({
9197
9347
  points,
9198
9348
  color,
@@ -9205,7 +9355,7 @@ function Polygon({
9205
9355
  engine.ecs.addComponent(entityId, comp);
9206
9356
  return () => engine.ecs.removeComponent(entityId, "PolygonShape");
9207
9357
  }, []);
9208
- useEffect39(() => {
9358
+ useEffect40(() => {
9209
9359
  const comp = engine.ecs.getComponent(entityId, "PolygonShape");
9210
9360
  if (!comp) return;
9211
9361
  comp.points = points;
@@ -9220,7 +9370,7 @@ function Polygon({
9220
9370
  }
9221
9371
 
9222
9372
  // src/components/Gradient.tsx
9223
- import { useEffect as useEffect40, useContext as useContext30 } from "react";
9373
+ import { useEffect as useEffect41, useContext as useContext30 } from "react";
9224
9374
  function Gradient({
9225
9375
  gradientType = "linear",
9226
9376
  stops,
@@ -9235,7 +9385,7 @@ function Gradient({
9235
9385
  }) {
9236
9386
  const engine = useContext30(EngineContext);
9237
9387
  const entityId = useContext30(EntityContext);
9238
- useEffect40(() => {
9388
+ useEffect41(() => {
9239
9389
  const comp = createGradient({
9240
9390
  gradientType,
9241
9391
  stops,
@@ -9251,7 +9401,7 @@ function Gradient({
9251
9401
  engine.ecs.addComponent(entityId, comp);
9252
9402
  return () => engine.ecs.removeComponent(entityId, "Gradient");
9253
9403
  }, []);
9254
- useEffect40(() => {
9404
+ useEffect41(() => {
9255
9405
  const comp = engine.ecs.getComponent(entityId, "Gradient");
9256
9406
  if (!comp) return;
9257
9407
  comp.gradientType = gradientType;
@@ -9265,16 +9415,16 @@ function Gradient({
9265
9415
  }
9266
9416
 
9267
9417
  // src/components/Mask.tsx
9268
- import { useEffect as useEffect41, useContext as useContext31 } from "react";
9418
+ import { useEffect as useEffect42, useContext as useContext31 } from "react";
9269
9419
  function Mask({ shape = "rect", width = 64, height = 64, radius = 32, inverted = false }) {
9270
9420
  const engine = useContext31(EngineContext);
9271
9421
  const entityId = useContext31(EntityContext);
9272
- useEffect41(() => {
9422
+ useEffect42(() => {
9273
9423
  const comp = createMask({ shape, width, height, radius, inverted });
9274
9424
  engine.ecs.addComponent(entityId, comp);
9275
9425
  return () => engine.ecs.removeComponent(entityId, "Mask");
9276
9426
  }, []);
9277
- useEffect41(() => {
9427
+ useEffect42(() => {
9278
9428
  const comp = engine.ecs.getComponent(entityId, "Mask");
9279
9429
  if (!comp) return;
9280
9430
  comp.shape = shape;
@@ -9287,11 +9437,11 @@ function Mask({ shape = "rect", width = 64, height = 64, radius = 32, inverted =
9287
9437
  }
9288
9438
 
9289
9439
  // src/components/Joint.tsx
9290
- import { useEffect as useEffect42, useContext as useContext32 } from "react";
9440
+ import { useEffect as useEffect43, useContext as useContext32 } from "react";
9291
9441
  function Joint({ type, target, anchorA, anchorB, length, stiffness, damping, maxLength }) {
9292
9442
  const engine = useContext32(EngineContext);
9293
9443
  const entityId = useContext32(EntityContext);
9294
- useEffect42(() => {
9444
+ useEffect43(() => {
9295
9445
  const checkId = setTimeout(() => {
9296
9446
  const targetEntityId = engine.entityIds.get(target);
9297
9447
  if (!targetEntityId) {
@@ -9326,7 +9476,7 @@ function Joint({ type, target, anchorA, anchorB, length, stiffness, damping, max
9326
9476
  }
9327
9477
 
9328
9478
  // src/components/ConvexCollider.tsx
9329
- import { useEffect as useEffect43, useContext as useContext33 } from "react";
9479
+ import { useEffect as useEffect44, useContext as useContext33 } from "react";
9330
9480
  function ConvexCollider({
9331
9481
  vertices,
9332
9482
  offsetX = 0,
@@ -9342,7 +9492,7 @@ function ConvexCollider({
9342
9492
  }) {
9343
9493
  const engine = useContext33(EngineContext);
9344
9494
  const entityId = useContext33(EntityContext);
9345
- useEffect43(() => {
9495
+ useEffect44(() => {
9346
9496
  engine.ecs.addComponent(
9347
9497
  entityId,
9348
9498
  createConvexPolygonCollider(vertices, {
@@ -9364,7 +9514,7 @@ function ConvexCollider({
9364
9514
  }
9365
9515
 
9366
9516
  // src/components/TriangleCollider.tsx
9367
- import { useEffect as useEffect44, useContext as useContext34 } from "react";
9517
+ import { useEffect as useEffect45, useContext as useContext34 } from "react";
9368
9518
  function TriangleCollider({
9369
9519
  a,
9370
9520
  b,
@@ -9382,7 +9532,7 @@ function TriangleCollider({
9382
9532
  }) {
9383
9533
  const engine = useContext34(EngineContext);
9384
9534
  const entityId = useContext34(EntityContext);
9385
- useEffect44(() => {
9535
+ useEffect45(() => {
9386
9536
  engine.ecs.addComponent(
9387
9537
  entityId,
9388
9538
  createTriangleCollider(a, b, c, {
@@ -9404,7 +9554,7 @@ function TriangleCollider({
9404
9554
  }
9405
9555
 
9406
9556
  // src/components/SegmentCollider.tsx
9407
- import { useEffect as useEffect45, useContext as useContext35 } from "react";
9557
+ import { useEffect as useEffect46, useContext as useContext35 } from "react";
9408
9558
  function SegmentCollider({
9409
9559
  start: start2,
9410
9560
  end,
@@ -9420,7 +9570,7 @@ function SegmentCollider({
9420
9570
  }) {
9421
9571
  const engine = useContext35(EngineContext);
9422
9572
  const entityId = useContext35(EntityContext);
9423
- useEffect45(() => {
9573
+ useEffect46(() => {
9424
9574
  engine.ecs.addComponent(
9425
9575
  entityId,
9426
9576
  createSegmentCollider(start2, end, {
@@ -9441,7 +9591,7 @@ function SegmentCollider({
9441
9591
  }
9442
9592
 
9443
9593
  // src/components/HeightFieldCollider.tsx
9444
- import { useEffect as useEffect46, useContext as useContext36 } from "react";
9594
+ import { useEffect as useEffect47, useContext as useContext36 } from "react";
9445
9595
  function HeightFieldCollider({
9446
9596
  heights,
9447
9597
  scaleX = 1,
@@ -9456,7 +9606,7 @@ function HeightFieldCollider({
9456
9606
  }) {
9457
9607
  const engine = useContext36(EngineContext);
9458
9608
  const entityId = useContext36(EntityContext);
9459
- useEffect46(() => {
9609
+ useEffect47(() => {
9460
9610
  engine.ecs.addComponent(
9461
9611
  entityId,
9462
9612
  createHeightFieldCollider(heights, {
@@ -9477,7 +9627,7 @@ function HeightFieldCollider({
9477
9627
  }
9478
9628
 
9479
9629
  // src/components/HalfSpaceCollider.tsx
9480
- import { useEffect as useEffect47, useContext as useContext37 } from "react";
9630
+ import { useEffect as useEffect48, useContext as useContext37 } from "react";
9481
9631
  function HalfSpaceCollider({
9482
9632
  normalX = 0,
9483
9633
  normalY = -1,
@@ -9491,7 +9641,7 @@ function HalfSpaceCollider({
9491
9641
  }) {
9492
9642
  const engine = useContext37(EngineContext);
9493
9643
  const entityId = useContext37(EntityContext);
9494
- useEffect47(() => {
9644
+ useEffect48(() => {
9495
9645
  engine.ecs.addComponent(
9496
9646
  entityId,
9497
9647
  createHalfSpaceCollider({
@@ -9512,7 +9662,7 @@ function HalfSpaceCollider({
9512
9662
  }
9513
9663
 
9514
9664
  // src/components/TriMeshCollider.tsx
9515
- import { useEffect as useEffect48, useContext as useContext38 } from "react";
9665
+ import { useEffect as useEffect49, useContext as useContext38 } from "react";
9516
9666
  function TriMeshCollider({
9517
9667
  vertices,
9518
9668
  indices,
@@ -9526,7 +9676,7 @@ function TriMeshCollider({
9526
9676
  }) {
9527
9677
  const engine = useContext38(EngineContext);
9528
9678
  const entityId = useContext38(EntityContext);
9529
- useEffect48(() => {
9679
+ useEffect49(() => {
9530
9680
  engine.ecs.addComponent(
9531
9681
  entityId,
9532
9682
  createTriMeshCollider(vertices, indices, {
@@ -9609,11 +9759,11 @@ function useCamera() {
9609
9759
  }
9610
9760
 
9611
9761
  // src/hooks/useCameraLookahead.ts
9612
- import { useContext as useContext40, useEffect as useEffect49 } from "react";
9762
+ import { useContext as useContext40, useEffect as useEffect50 } from "react";
9613
9763
  function useCameraLookahead(entityId, opts = {}) {
9614
9764
  const engine = useContext40(EngineContext);
9615
9765
  const { distance = 100, smoothing = 3, vertical = false } = opts;
9616
- useEffect49(() => {
9766
+ useEffect50(() => {
9617
9767
  let offsetX = 0;
9618
9768
  let offsetY = 0;
9619
9769
  const script = createScript((id, world, _input, dt) => {
@@ -9699,17 +9849,17 @@ function useCameraBlend() {
9699
9849
  }
9700
9850
 
9701
9851
  // src/hooks/useCinematicSequence.ts
9702
- import { useEffect as useEffect50, useRef as useRef17, useCallback as useCallback2, useState as useState8, useContext as useContext41 } from "react";
9852
+ import { useEffect as useEffect51, useRef as useRef18, useCallback as useCallback3, useState as useState8, useContext as useContext41 } from "react";
9703
9853
  function useCinematicSequence(steps, opts) {
9704
9854
  const engine = useContext41(EngineContext);
9705
- const stepsRef = useRef17(steps);
9855
+ const stepsRef = useRef18(steps);
9706
9856
  stepsRef.current = steps;
9707
- const optsRef = useRef17(opts);
9857
+ const optsRef = useRef18(opts);
9708
9858
  optsRef.current = opts;
9709
9859
  const [isPlaying, setIsPlaying] = useState8(false);
9710
9860
  const [currentStep, setCurrentStep] = useState8(-1);
9711
- const stateRef = useRef17({ playing: false, step: -1, elapsed: 0, scriptEid: null });
9712
- const activateStep = useCallback2(
9861
+ const stateRef = useRef18({ playing: false, step: -1, elapsed: 0, scriptEid: null });
9862
+ const activateStep = useCallback3(
9713
9863
  (idx) => {
9714
9864
  const steps2 = stepsRef.current;
9715
9865
  if (idx < 0 || idx >= steps2.length) return;
@@ -9729,7 +9879,7 @@ function useCinematicSequence(steps, opts) {
9729
9879
  },
9730
9880
  [engine]
9731
9881
  );
9732
- const play = useCallback2(() => {
9882
+ const play = useCallback3(() => {
9733
9883
  const state = stateRef.current;
9734
9884
  state.playing = true;
9735
9885
  state.step = 0;
@@ -9738,7 +9888,7 @@ function useCinematicSequence(steps, opts) {
9738
9888
  setCurrentStep(0);
9739
9889
  activateStep(0);
9740
9890
  }, [activateStep]);
9741
- const stop = useCallback2(() => {
9891
+ const stop = useCallback3(() => {
9742
9892
  const state = stateRef.current;
9743
9893
  if (!state.playing) return;
9744
9894
  state.playing = false;
@@ -9750,7 +9900,7 @@ function useCinematicSequence(steps, opts) {
9750
9900
  if (entry) entry.active = false;
9751
9901
  }
9752
9902
  }, [engine]);
9753
- useEffect50(() => {
9903
+ useEffect51(() => {
9754
9904
  const state = stateRef.current;
9755
9905
  const eid = engine.ecs.createEntity();
9756
9906
  state.scriptEid = eid;
@@ -9819,13 +9969,13 @@ function useEntity() {
9819
9969
  }
9820
9970
 
9821
9971
  // src/hooks/useDestroyEntity.ts
9822
- import { useCallback as useCallback3, useContext as useContext43 } from "react";
9972
+ import { useCallback as useCallback4, useContext as useContext43 } from "react";
9823
9973
  function useDestroyEntity() {
9824
9974
  const engine = useContext43(EngineContext);
9825
9975
  const entityId = useContext43(EntityContext);
9826
9976
  if (!engine) throw new Error("useDestroyEntity must be used inside <Game>");
9827
9977
  if (entityId === null) throw new Error("useDestroyEntity must be used inside <Entity>");
9828
- return useCallback3(() => {
9978
+ return useCallback4(() => {
9829
9979
  if (engine.ecs.hasEntity(entityId)) {
9830
9980
  engine.ecs.destroyEntity(entityId);
9831
9981
  }
@@ -9858,7 +10008,7 @@ function useInputMap(bindings) {
9858
10008
  }
9859
10009
 
9860
10010
  // src/hooks/useEvents.ts
9861
- import { useContext as useContext45, useEffect as useEffect51, useRef as useRef18 } from "react";
10011
+ import { useContext as useContext45, useEffect as useEffect52, useRef as useRef19 } from "react";
9862
10012
  function useEvents() {
9863
10013
  const engine = useContext45(EngineContext);
9864
10014
  if (!engine) throw new Error("useEvents must be used inside <Game>");
@@ -9866,18 +10016,18 @@ function useEvents() {
9866
10016
  }
9867
10017
  function useEvent(event, handler) {
9868
10018
  const events = useEvents();
9869
- const handlerRef = useRef18(handler);
10019
+ const handlerRef = useRef19(handler);
9870
10020
  handlerRef.current = handler;
9871
- useEffect51(() => {
10021
+ useEffect52(() => {
9872
10022
  return events.on(event, (data) => handlerRef.current(data));
9873
10023
  }, [events, event]);
9874
10024
  }
9875
10025
 
9876
10026
  // src/hooks/useCoordinates.ts
9877
- import { useCallback as useCallback4, useContext as useContext46 } from "react";
10027
+ import { useCallback as useCallback5, useContext as useContext46 } from "react";
9878
10028
  function useCoordinates() {
9879
10029
  const engine = useContext46(EngineContext);
9880
- const worldToScreen = useCallback4(
10030
+ const worldToScreen = useCallback5(
9881
10031
  (wx, wy) => {
9882
10032
  const canvas = engine.canvas;
9883
10033
  const camId = engine.ecs.queryOne("Camera2D");
@@ -9891,7 +10041,7 @@ function useCoordinates() {
9891
10041
  },
9892
10042
  [engine.ecs, engine.canvas]
9893
10043
  );
9894
- const screenToWorld3 = useCallback4(
10044
+ const screenToWorld3 = useCallback5(
9895
10045
  (sx, sy) => {
9896
10046
  const canvas = engine.canvas;
9897
10047
  const camId = engine.ecs.queryOne("Camera2D");
@@ -9909,14 +10059,14 @@ function useCoordinates() {
9909
10059
  }
9910
10060
 
9911
10061
  // src/hooks/useWorldQuery.ts
9912
- import { useEffect as useEffect52, useRef as useRef19, useState as useState9 } from "react";
10062
+ import { useEffect as useEffect53, useRef as useRef20, useState as useState9 } from "react";
9913
10063
  function useWorldQuery(...components) {
9914
10064
  const engine = useGame();
9915
10065
  const [result, setResult] = useState9(() => engine.ecs.query(...components));
9916
- const prevRef = useRef19([]);
9917
- const rafRef = useRef19(0);
9918
- const mountedRef = useRef19(true);
9919
- useEffect52(() => {
10066
+ const prevRef = useRef20([]);
10067
+ const rafRef = useRef20(0);
10068
+ const mountedRef = useRef20(true);
10069
+ useEffect53(() => {
9920
10070
  mountedRef.current = true;
9921
10071
  const tick2 = () => {
9922
10072
  if (!mountedRef.current) return;
@@ -9938,9 +10088,9 @@ function useWorldQuery(...components) {
9938
10088
  }
9939
10089
 
9940
10090
  // src/hooks/useInputContext.ts
9941
- import { useEffect as useEffect53, useMemo as useMemo5 } from "react";
10091
+ import { useEffect as useEffect54, useMemo as useMemo5 } from "react";
9942
10092
  function useInputContext(ctx) {
9943
- useEffect53(() => {
10093
+ useEffect54(() => {
9944
10094
  if (!ctx) return;
9945
10095
  globalInputContext.push(ctx);
9946
10096
  return () => globalInputContext.pop(ctx);
@@ -9982,12 +10132,12 @@ function useInputRecorder() {
9982
10132
  }
9983
10133
 
9984
10134
  // src/hooks/useGamepad.ts
9985
- import { useEffect as useEffect54, useRef as useRef20, useState as useState10 } from "react";
10135
+ import { useEffect as useEffect55, useRef as useRef21, useState as useState10 } from "react";
9986
10136
  var EMPTY_STATE = { connected: false, axes: [], buttons: [] };
9987
10137
  function useGamepad(playerIndex = 0) {
9988
10138
  const [state, setState] = useState10(EMPTY_STATE);
9989
- const rafRef = useRef20(0);
9990
- useEffect54(() => {
10139
+ const rafRef = useRef21(0);
10140
+ useEffect55(() => {
9991
10141
  const poll = () => {
9992
10142
  const gp = navigator.getGamepads()[playerIndex];
9993
10143
  if (gp) {
@@ -10008,19 +10158,19 @@ function useGamepad(playerIndex = 0) {
10008
10158
  }
10009
10159
 
10010
10160
  // src/hooks/usePause.ts
10011
- import { useContext as useContext47, useState as useState11, useCallback as useCallback5 } from "react";
10161
+ import { useContext as useContext47, useState as useState11, useCallback as useCallback6 } from "react";
10012
10162
  function usePause() {
10013
10163
  const engine = useContext47(EngineContext);
10014
10164
  const [paused, setPaused] = useState11(false);
10015
- const pause = useCallback5(() => {
10165
+ const pause = useCallback6(() => {
10016
10166
  engine.loop.pause();
10017
10167
  setPaused(true);
10018
10168
  }, [engine]);
10019
- const resume = useCallback5(() => {
10169
+ const resume = useCallback6(() => {
10020
10170
  engine.loop.resume();
10021
10171
  setPaused(false);
10022
10172
  }, [engine]);
10023
- const toggle = useCallback5(() => {
10173
+ const toggle = useCallback6(() => {
10024
10174
  if (engine.loop.isPaused) resume();
10025
10175
  else pause();
10026
10176
  }, [engine, pause, resume]);
@@ -10028,7 +10178,7 @@ function usePause() {
10028
10178
  }
10029
10179
 
10030
10180
  // src/hooks/useProfiler.ts
10031
- import { useContext as useContext48, useEffect as useEffect55, useRef as useRef21, useState as useState12 } from "react";
10181
+ import { useContext as useContext48, useEffect as useEffect56, useRef as useRef22, useState as useState12 } from "react";
10032
10182
  var EMPTY = {
10033
10183
  fps: 0,
10034
10184
  frameTime: 0,
@@ -10038,10 +10188,10 @@ var EMPTY = {
10038
10188
  function useProfiler() {
10039
10189
  const engine = useContext48(EngineContext);
10040
10190
  const [data, setData] = useState12(EMPTY);
10041
- const frameTimesRef = useRef21([]);
10042
- const lastUpdateRef = useRef21(0);
10043
- const prevTimeRef = useRef21(0);
10044
- useEffect55(() => {
10191
+ const frameTimesRef = useRef22([]);
10192
+ const lastUpdateRef = useRef22(0);
10193
+ const prevTimeRef = useRef22(0);
10194
+ useEffect56(() => {
10045
10195
  if (!engine) return;
10046
10196
  let rafId2;
10047
10197
  const frameTimes = frameTimesRef.current;
@@ -10081,10 +10231,10 @@ function useProfiler() {
10081
10231
  }
10082
10232
 
10083
10233
  // src/hooks/usePostProcess.ts
10084
- import { useEffect as useEffect56 } from "react";
10234
+ import { useEffect as useEffect57 } from "react";
10085
10235
  function usePostProcess(effect) {
10086
10236
  const engine = useGame();
10087
- useEffect56(() => {
10237
+ useEffect57(() => {
10088
10238
  engine.postProcessStack.add(effect);
10089
10239
  return () => {
10090
10240
  engine.postProcessStack.remove(effect);
@@ -10093,11 +10243,11 @@ function usePostProcess(effect) {
10093
10243
  }
10094
10244
 
10095
10245
  // src/hooks/useWebGLPostProcess.ts
10096
- import { useEffect as useEffect57, useMemo as useMemo9 } from "react";
10246
+ import { useEffect as useEffect58, useMemo as useMemo9 } from "react";
10097
10247
  function useWebGLPostProcess(opts) {
10098
10248
  const engine = useGame();
10099
10249
  const optsKey = useMemo9(() => JSON.stringify(opts), [JSON.stringify(opts)]);
10100
- useEffect57(() => {
10250
+ useEffect58(() => {
10101
10251
  const rs = engine.activeRenderSystem;
10102
10252
  rs.setPostProcessOptions?.(opts);
10103
10253
  return () => {
@@ -10107,10 +10257,10 @@ function useWebGLPostProcess(opts) {
10107
10257
  }
10108
10258
 
10109
10259
  // src/hooks/useAudioListener.ts
10110
- import { useEffect as useEffect58, useContext as useContext49 } from "react";
10260
+ import { useEffect as useEffect59, useContext as useContext49 } from "react";
10111
10261
  function useAudioListener() {
10112
10262
  const engine = useContext49(EngineContext);
10113
- useEffect58(() => {
10263
+ useEffect59(() => {
10114
10264
  const eid = engine.ecs.createEntity();
10115
10265
  engine.ecs.addComponent(
10116
10266
  eid,
@@ -10154,13 +10304,13 @@ function useTouch() {
10154
10304
  }
10155
10305
 
10156
10306
  // src/hooks/useGestures.ts
10157
- import { useEffect as useEffect59, useRef as useRef22 } from "react";
10307
+ import { useEffect as useEffect60, useRef as useRef23 } from "react";
10158
10308
  function useGestures(handlers, opts = {}) {
10159
- const handlersRef = useRef22(handlers);
10309
+ const handlersRef = useRef23(handlers);
10160
10310
  handlersRef.current = handlers;
10161
- const optsRef = useRef22(opts);
10311
+ const optsRef = useRef23(opts);
10162
10312
  optsRef.current = opts;
10163
- useEffect59(() => {
10313
+ useEffect60(() => {
10164
10314
  const target = optsRef.current.target ?? window;
10165
10315
  let starts = [];
10166
10316
  let longPressTimer = null;
@@ -10320,14 +10470,14 @@ var touchHapticsControls = {
10320
10470
  };
10321
10471
 
10322
10472
  // src/hooks/useTimer.ts
10323
- import { useRef as useRef23, useCallback as useCallback6, useEffect as useEffect60, useContext as useContext51 } from "react";
10473
+ import { useRef as useRef24, useCallback as useCallback7, useEffect as useEffect61, useContext as useContext51 } from "react";
10324
10474
  function useTimer(duration, onComplete, opts) {
10325
10475
  const engine = useContext51(EngineContext);
10326
- const onCompleteRef = useRef23(onComplete);
10476
+ const onCompleteRef = useRef24(onComplete);
10327
10477
  onCompleteRef.current = onComplete;
10328
- const loopRef = useRef23(opts?.loop ?? false);
10478
+ const loopRef = useRef24(opts?.loop ?? false);
10329
10479
  loopRef.current = opts?.loop ?? false;
10330
- const timerRef = useRef23(null);
10480
+ const timerRef = useRef24(null);
10331
10481
  if (!timerRef.current) {
10332
10482
  timerRef.current = createTimer(
10333
10483
  duration,
@@ -10340,7 +10490,7 @@ function useTimer(duration, onComplete, opts) {
10340
10490
  opts?.autoStart ?? false
10341
10491
  );
10342
10492
  }
10343
- useEffect60(() => {
10493
+ useEffect61(() => {
10344
10494
  const eid = engine.ecs.createEntity();
10345
10495
  engine.ecs.addComponent(
10346
10496
  eid,
@@ -10352,13 +10502,13 @@ function useTimer(duration, onComplete, opts) {
10352
10502
  if (engine.ecs.hasEntity(eid)) engine.ecs.destroyEntity(eid);
10353
10503
  };
10354
10504
  }, [engine.ecs]);
10355
- const start2 = useCallback6(() => {
10505
+ const start2 = useCallback7(() => {
10356
10506
  timerRef.current.start();
10357
10507
  }, []);
10358
- const stop = useCallback6(() => {
10508
+ const stop = useCallback7(() => {
10359
10509
  timerRef.current.stop();
10360
10510
  }, []);
10361
- const reset = useCallback6(() => {
10511
+ const reset = useCallback7(() => {
10362
10512
  timerRef.current.reset();
10363
10513
  }, []);
10364
10514
  return {
@@ -10381,15 +10531,15 @@ function useTimer(duration, onComplete, opts) {
10381
10531
  }
10382
10532
 
10383
10533
  // src/hooks/useCoroutine.ts
10384
- import { useRef as useRef24, useEffect as useEffect61, useContext as useContext52 } from "react";
10534
+ import { useRef as useRef25, useEffect as useEffect62, useContext as useContext52 } from "react";
10385
10535
  var wait = (seconds) => ({ type: "wait", seconds });
10386
10536
  var waitFrames = (frames) => ({ type: "waitFrames", frames });
10387
10537
  var waitUntil = (condition) => ({ type: "waitUntil", condition });
10388
10538
  var nextCoroutineId = 1;
10389
10539
  function useCoroutine() {
10390
10540
  const engine = useContext52(EngineContext);
10391
- const coroutinesRef = useRef24(/* @__PURE__ */ new Map());
10392
- useEffect61(() => {
10541
+ const coroutinesRef = useRef25(/* @__PURE__ */ new Map());
10542
+ useEffect62(() => {
10393
10543
  const eid = engine.ecs.createEntity();
10394
10544
  engine.ecs.addComponent(
10395
10545
  eid,
@@ -10454,33 +10604,33 @@ function useCoroutine() {
10454
10604
  return coroutinesRef.current.size;
10455
10605
  }
10456
10606
  };
10457
- const controlsRef = useRef24(controls);
10607
+ const controlsRef = useRef25(controls);
10458
10608
  return controlsRef.current;
10459
10609
  }
10460
10610
 
10461
10611
  // src/hooks/useSceneManager.ts
10462
- import { useState as useState13, useCallback as useCallback7, useRef as useRef25 } from "react";
10612
+ import { useState as useState13, useCallback as useCallback8, useRef as useRef26 } from "react";
10463
10613
  function useSceneManager(initialScene) {
10464
10614
  const [stack, setStack] = useState13([initialScene]);
10465
- const stackRef = useRef25(stack);
10615
+ const stackRef = useRef26(stack);
10466
10616
  stackRef.current = stack;
10467
- const push = useCallback7((scene) => {
10617
+ const push = useCallback8((scene) => {
10468
10618
  setStack((prev) => [...prev, scene]);
10469
10619
  }, []);
10470
- const pop = useCallback7(() => {
10620
+ const pop = useCallback8(() => {
10471
10621
  const prev = stackRef.current;
10472
10622
  if (prev.length <= 1) return void 0;
10473
10623
  const popped = prev[prev.length - 1];
10474
10624
  setStack(prev.slice(0, -1));
10475
10625
  return popped;
10476
10626
  }, []);
10477
- const replace = useCallback7((scene) => {
10627
+ const replace = useCallback8((scene) => {
10478
10628
  setStack((prev) => [...prev.slice(0, -1), scene]);
10479
10629
  }, []);
10480
- const reset = useCallback7((scene) => {
10630
+ const reset = useCallback8((scene) => {
10481
10631
  setStack([scene]);
10482
10632
  }, []);
10483
- const has = useCallback7(
10633
+ const has = useCallback8(
10484
10634
  (scene) => {
10485
10635
  return stack.includes(scene);
10486
10636
  },
@@ -10498,7 +10648,7 @@ function useSceneManager(initialScene) {
10498
10648
  }
10499
10649
 
10500
10650
  // src/hooks/useSceneTransition.ts
10501
- import { useState as useState14, useCallback as useCallback8, useRef as useRef26, useEffect as useEffect62 } from "react";
10651
+ import { useState as useState14, useCallback as useCallback9, useRef as useRef27, useEffect as useEffect63 } from "react";
10502
10652
  function useSceneTransition(initialScene, defaultTransition) {
10503
10653
  const [stack, setStack] = useState14([initialScene]);
10504
10654
  const [transState, setTransState] = useState14({
@@ -10507,11 +10657,11 @@ function useSceneTransition(initialScene, defaultTransition) {
10507
10657
  effect: null,
10508
10658
  pendingAction: null
10509
10659
  });
10510
- const stackRef = useRef26(stack);
10660
+ const stackRef = useRef27(stack);
10511
10661
  stackRef.current = stack;
10512
- const transRef = useRef26(transState);
10662
+ const transRef = useRef27(transState);
10513
10663
  transRef.current = transState;
10514
- useEffect62(() => {
10664
+ useEffect63(() => {
10515
10665
  if (transState.phase === "idle") return;
10516
10666
  const effect = transState.effect;
10517
10667
  if (!effect || effect.type === "instant") return;
@@ -10540,7 +10690,7 @@ function useSceneTransition(initialScene, defaultTransition) {
10540
10690
  rafId2 = requestAnimationFrame(animate);
10541
10691
  return () => cancelAnimationFrame(rafId2);
10542
10692
  }, [transState.phase, transState.effect]);
10543
- const startTransition = useCallback8(
10693
+ const startTransition = useCallback9(
10544
10694
  (effect, action) => {
10545
10695
  const eff = effect ?? defaultTransition ?? { type: "instant" };
10546
10696
  if (eff.type === "instant" || isReducedMotionPreferred()) {
@@ -10556,13 +10706,13 @@ function useSceneTransition(initialScene, defaultTransition) {
10556
10706
  },
10557
10707
  [defaultTransition]
10558
10708
  );
10559
- const push = useCallback8(
10709
+ const push = useCallback9(
10560
10710
  (scene, transition) => {
10561
10711
  startTransition(transition, () => setStack((prev) => [...prev, scene]));
10562
10712
  },
10563
10713
  [startTransition]
10564
10714
  );
10565
- const pop = useCallback8(
10715
+ const pop = useCallback9(
10566
10716
  (transition) => {
10567
10717
  const prev = stackRef.current;
10568
10718
  if (prev.length <= 1) return void 0;
@@ -10572,13 +10722,13 @@ function useSceneTransition(initialScene, defaultTransition) {
10572
10722
  },
10573
10723
  [startTransition]
10574
10724
  );
10575
- const replace = useCallback8(
10725
+ const replace = useCallback9(
10576
10726
  (scene, transition) => {
10577
10727
  startTransition(transition, () => setStack((prev) => [...prev.slice(0, -1), scene]));
10578
10728
  },
10579
10729
  [startTransition]
10580
10730
  );
10581
- const reset = useCallback8(
10731
+ const reset = useCallback9(
10582
10732
  (scene, transition) => {
10583
10733
  startTransition(transition, () => setStack([scene]));
10584
10734
  },
@@ -10679,10 +10829,10 @@ function SceneTransitionOverlay({ controls }) {
10679
10829
  }
10680
10830
 
10681
10831
  // src/hooks/useHitstop.ts
10682
- import { useContext as useContext53, useCallback as useCallback9 } from "react";
10832
+ import { useContext as useContext53, useCallback as useCallback10 } from "react";
10683
10833
  function useHitstop() {
10684
10834
  const engine = useContext53(EngineContext);
10685
- const freeze = useCallback9(
10835
+ const freeze = useCallback10(
10686
10836
  (seconds) => {
10687
10837
  engine.loop.hitPause(seconds);
10688
10838
  },
@@ -10698,9 +10848,9 @@ function useInputBuffer(opts) {
10698
10848
  }
10699
10849
 
10700
10850
  // src/hooks/useComboDetector.ts
10701
- import { useMemo as useMemo11, useRef as useRef27 } from "react";
10851
+ import { useMemo as useMemo11, useRef as useRef28 } from "react";
10702
10852
  function useComboDetector(combos) {
10703
- const lastComboRef = useRef27(null);
10853
+ const lastComboRef = useRef28(null);
10704
10854
  const result = useMemo11(() => {
10705
10855
  const detector = new ComboDetector({ combos });
10706
10856
  const api = {
@@ -10723,11 +10873,11 @@ function useComboDetector(combos) {
10723
10873
  }
10724
10874
 
10725
10875
  // src/hooks/useParent.ts
10726
- import { useEffect as useEffect63, useContext as useContext54 } from "react";
10876
+ import { useEffect as useEffect64, useContext as useContext54 } from "react";
10727
10877
  function useParent(childEntityId, parentEntityId) {
10728
10878
  const engine = useContext54(EngineContext);
10729
10879
  if (!engine) throw new Error("useParent must be used inside <Game>");
10730
- useEffect63(() => {
10880
+ useEffect64(() => {
10731
10881
  setParent(engine.ecs, childEntityId, parentEntityId);
10732
10882
  return () => {
10733
10883
  removeParent(engine.ecs, childEntityId);
@@ -10736,7 +10886,7 @@ function useParent(childEntityId, parentEntityId) {
10736
10886
  }
10737
10887
 
10738
10888
  // src/hooks/useAccessibility.ts
10739
- import { useCallback as useCallback10, useSyncExternalStore } from "react";
10889
+ import { useCallback as useCallback11, useSyncExternalStore } from "react";
10740
10890
  var _version = 0;
10741
10891
  var _listeners = /* @__PURE__ */ new Set();
10742
10892
  function subscribe(cb) {
@@ -10748,12 +10898,12 @@ function getSnapshot() {
10748
10898
  }
10749
10899
  function useAccessibility() {
10750
10900
  useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
10751
- const setOptions = useCallback10((opts) => {
10901
+ const setOptions = useCallback11((opts) => {
10752
10902
  setAccessibilityOptions(opts);
10753
10903
  _version++;
10754
10904
  for (const cb of _listeners) cb();
10755
10905
  }, []);
10756
- const announce = useCallback10((text, priority) => {
10906
+ const announce = useCallback11((text, priority) => {
10757
10907
  announceToScreenReader(text, priority);
10758
10908
  }, []);
10759
10909
  return {
@@ -10764,18 +10914,18 @@ function useAccessibility() {
10764
10914
  }
10765
10915
 
10766
10916
  // src/hooks/useHMR.ts
10767
- import { useEffect as useEffect64, useRef as useRef28, useMemo as useMemo12 } from "react";
10917
+ import { useEffect as useEffect65, useRef as useRef29, useMemo as useMemo12 } from "react";
10768
10918
  var idCounter = 0;
10769
10919
  function useHMR(hmrKey) {
10770
- const idRef = useRef28(null);
10920
+ const idRef = useRef29(null);
10771
10921
  if (idRef.current === null) {
10772
10922
  idRef.current = hmrKey ?? `__hmr_${idCounter++}`;
10773
10923
  }
10774
10924
  const key = idRef.current;
10775
10925
  const isHotReload = hmrLoadState(key) !== void 0;
10776
- const disposeRef = useRef28(null);
10777
- const acceptRef = useRef28(null);
10778
- useEffect64(() => {
10926
+ const disposeRef = useRef29(null);
10927
+ const acceptRef = useRef29(null);
10928
+ useEffect65(() => {
10779
10929
  const hot = import.meta.hot;
10780
10930
  if (!hot) return;
10781
10931
  hot.dispose(() => {
@@ -10808,11 +10958,11 @@ function useHMR(hmrKey) {
10808
10958
  }
10809
10959
 
10810
10960
  // src/hooks/useSquashStretch.ts
10811
- import { useCallback as useCallback11, useContext as useContext55 } from "react";
10961
+ import { useCallback as useCallback12, useContext as useContext55 } from "react";
10812
10962
  function useSquashStretch() {
10813
10963
  const engine = useContext55(EngineContext);
10814
10964
  const entityId = useContext55(EntityContext);
10815
- const trigger = useCallback11(
10965
+ const trigger = useCallback12(
10816
10966
  (scaleX, scaleY) => {
10817
10967
  const ss = engine.ecs.getComponent(entityId, "SquashStretch");
10818
10968
  if (!ss) return;
@@ -10825,16 +10975,16 @@ function useSquashStretch() {
10825
10975
  }
10826
10976
 
10827
10977
  // src/hooks/useHistory.ts
10828
- import { useCallback as useCallback12, useContext as useContext56, useEffect as useEffect65, useRef as useRef29, useState as useState15 } from "react";
10978
+ import { useCallback as useCallback13, useContext as useContext56, useEffect as useEffect66, useRef as useRef30, useState as useState15 } from "react";
10829
10979
  function useHistory(options) {
10830
10980
  const engine = useContext56(EngineContext);
10831
10981
  const capacity = options?.capacity ?? 50;
10832
10982
  const bindKeys = options?.bindKeyboardShortcuts ?? false;
10833
- const stackRef = useRef29([]);
10834
- const indexRef = useRef29(-1);
10983
+ const stackRef = useRef30([]);
10984
+ const indexRef = useRef30(-1);
10835
10985
  const [version, setVersion] = useState15(0);
10836
- const bump = useCallback12(() => setVersion((v) => v + 1), []);
10837
- const push = useCallback12(() => {
10986
+ const bump = useCallback13(() => setVersion((v) => v + 1), []);
10987
+ const push = useCallback13(() => {
10838
10988
  const snap = engine.ecs.getSnapshot();
10839
10989
  const stack = stackRef.current;
10840
10990
  if (indexRef.current < stack.length - 1) {
@@ -10845,14 +10995,14 @@ function useHistory(options) {
10845
10995
  indexRef.current = stack.length - 1;
10846
10996
  bump();
10847
10997
  }, [engine, capacity, bump]);
10848
- const undo = useCallback12(() => {
10998
+ const undo = useCallback13(() => {
10849
10999
  if (indexRef.current <= 0) return;
10850
11000
  indexRef.current -= 1;
10851
11001
  engine.ecs.restoreSnapshot(stackRef.current[indexRef.current]);
10852
11002
  engine.loop.markDirty();
10853
11003
  bump();
10854
11004
  }, [engine, bump]);
10855
- const redo = useCallback12(() => {
11005
+ const redo = useCallback13(() => {
10856
11006
  const stack = stackRef.current;
10857
11007
  if (indexRef.current >= stack.length - 1) return;
10858
11008
  indexRef.current += 1;
@@ -10860,12 +11010,12 @@ function useHistory(options) {
10860
11010
  engine.loop.markDirty();
10861
11011
  bump();
10862
11012
  }, [engine, bump]);
10863
- const clear = useCallback12(() => {
11013
+ const clear = useCallback13(() => {
10864
11014
  stackRef.current = [];
10865
11015
  indexRef.current = -1;
10866
11016
  bump();
10867
11017
  }, [bump]);
10868
- useEffect65(() => {
11018
+ useEffect66(() => {
10869
11019
  if (!bindKeys) return;
10870
11020
  const onKey = (e) => {
10871
11021
  const mod = e.ctrlKey || e.metaKey;
@@ -10890,13 +11040,13 @@ function useHistory(options) {
10890
11040
  }
10891
11041
 
10892
11042
  // 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";
11043
+ import { createContext as createContext2, useCallback as useCallback14, useContext as useContext57, useEffect as useEffect67, useMemo as useMemo13, useState as useState16 } from "react";
10894
11044
  import { jsx as jsx15 } from "react/jsx-runtime";
10895
11045
  var SelectionContext = createContext2(null);
10896
11046
  function Selection({ initial, onChange, children }) {
10897
11047
  const engine = useContext57(EngineContext);
10898
11048
  const [selected, setSelected] = useState16(initial ?? []);
10899
- useEffect66(() => {
11049
+ useEffect67(() => {
10900
11050
  if (!engine) return;
10901
11051
  return engine.ecs.onDestroyEntity((destroyedId) => {
10902
11052
  setSelected((prev) => {
@@ -10907,14 +11057,14 @@ function Selection({ initial, onChange, children }) {
10907
11057
  });
10908
11058
  });
10909
11059
  }, [engine, onChange]);
10910
- const commit = useCallback13(
11060
+ const commit = useCallback14(
10911
11061
  (next) => {
10912
11062
  setSelected(next);
10913
11063
  onChange?.(next);
10914
11064
  },
10915
11065
  [onChange]
10916
11066
  );
10917
- const select = useCallback13(
11067
+ const select = useCallback14(
10918
11068
  (id, opts) => {
10919
11069
  if (opts?.additive) {
10920
11070
  setSelected((prev) => {
@@ -10929,7 +11079,7 @@ function Selection({ initial, onChange, children }) {
10929
11079
  },
10930
11080
  [commit, onChange]
10931
11081
  );
10932
- const deselect = useCallback13(
11082
+ const deselect = useCallback14(
10933
11083
  (id) => {
10934
11084
  setSelected((prev) => {
10935
11085
  if (!prev.includes(id)) return prev;
@@ -10940,7 +11090,7 @@ function Selection({ initial, onChange, children }) {
10940
11090
  },
10941
11091
  [onChange]
10942
11092
  );
10943
- const toggle = useCallback13(
11093
+ const toggle = useCallback14(
10944
11094
  (id) => {
10945
11095
  setSelected((prev) => {
10946
11096
  const next = prev.includes(id) ? prev.filter((x) => x !== id) : [...prev, id];
@@ -10950,8 +11100,8 @@ function Selection({ initial, onChange, children }) {
10950
11100
  },
10951
11101
  [onChange]
10952
11102
  );
10953
- const clear = useCallback13(() => commit([]), [commit]);
10954
- const isSelected = useCallback13((id) => selected.includes(id), [selected]);
11103
+ const clear = useCallback14(() => commit([]), [commit]);
11104
+ const isSelected = useCallback14((id) => selected.includes(id), [selected]);
10955
11105
  const value = useMemo13(
10956
11106
  () => ({ selected, select, deselect, toggle, clear, isSelected }),
10957
11107
  [selected, select, deselect, toggle, clear, isSelected]
@@ -10965,10 +11115,10 @@ function useSelection() {
10965
11115
  }
10966
11116
 
10967
11117
  // src/components/TransformHandles.tsx
10968
- import { useContext as useContext58, useEffect as useEffect68, useRef as useRef30 } from "react";
11118
+ import { useContext as useContext58, useEffect as useEffect69, useRef as useRef31 } from "react";
10969
11119
 
10970
11120
  // src/hooks/useOverlayTick.ts
10971
- import { useEffect as useEffect67 } from "react";
11121
+ import { useEffect as useEffect68 } from "react";
10972
11122
  var callbacks = /* @__PURE__ */ new Set();
10973
11123
  var rafId = 0;
10974
11124
  function tick() {
@@ -10991,7 +11141,7 @@ function register(cb) {
10991
11141
  };
10992
11142
  }
10993
11143
  function useOverlayTick(callback, deps = []) {
10994
- useEffect67(() => {
11144
+ useEffect68(() => {
10995
11145
  return register(callback);
10996
11146
  }, deps);
10997
11147
  }
@@ -11007,8 +11157,8 @@ function TransformHandles({
11007
11157
  }) {
11008
11158
  const engine = useContext58(EngineContext);
11009
11159
  const selection = useSelection();
11010
- const overlayRef = useRef30(null);
11011
- const dragRef = useRef30(null);
11160
+ const overlayRef = useRef31(null);
11161
+ const dragRef = useRef31(null);
11012
11162
  useOverlayTick(() => {
11013
11163
  if (!engine) return;
11014
11164
  const overlay = overlayRef.current;
@@ -11043,7 +11193,7 @@ function TransformHandles({
11043
11193
  node.style.transform = `translate(-50%, -50%) rotate(${t.rotation}rad)`;
11044
11194
  }
11045
11195
  }, [engine, selection.selected]);
11046
- useEffect68(() => {
11196
+ useEffect69(() => {
11047
11197
  if (!engine) return;
11048
11198
  const onMove = (e) => {
11049
11199
  const drag = dragRef.current;
@@ -11267,7 +11417,7 @@ function worldToScreenCss(engine, wx, wy) {
11267
11417
  }
11268
11418
 
11269
11419
  // src/hooks/useSnap.ts
11270
- import { useCallback as useCallback14, useContext as useContext59 } from "react";
11420
+ import { useCallback as useCallback15, useContext as useContext59 } from "react";
11271
11421
  function useSnap(options) {
11272
11422
  const engine = useContext59(EngineContext);
11273
11423
  const gridX = typeof options?.grid === "number" ? options.grid : options?.grid?.x ?? 0;
@@ -11275,7 +11425,7 @@ function useSnap(options) {
11275
11425
  const snapToEntities = options?.snapToEntities ?? false;
11276
11426
  const threshold = options?.threshold ?? 8;
11277
11427
  const exclude = options?.exclude;
11278
- const snapToGrid = useCallback14(
11428
+ const snapToGrid = useCallback15(
11279
11429
  (x, y) => {
11280
11430
  const sx = gridX > 0 ? Math.round(x / gridX) * gridX : x;
11281
11431
  const sy = gridY > 0 ? Math.round(y / gridY) * gridY : y;
@@ -11283,7 +11433,7 @@ function useSnap(options) {
11283
11433
  },
11284
11434
  [gridX, gridY]
11285
11435
  );
11286
- const snap = useCallback14(
11436
+ const snap = useCallback15(
11287
11437
  (x, y) => {
11288
11438
  let outX = x;
11289
11439
  let outY = y;
@@ -11358,7 +11508,7 @@ function getBounds(ecs, id) {
11358
11508
  }
11359
11509
 
11360
11510
  // src/components/EditableText.tsx
11361
- import { useContext as useContext60, useEffect as useEffect69, useRef as useRef31 } from "react";
11511
+ import { useContext as useContext60, useEffect as useEffect70, useRef as useRef32 } from "react";
11362
11512
  import { jsx as jsx17 } from "react/jsx-runtime";
11363
11513
  function EditableText({
11364
11514
  value,
@@ -11382,8 +11532,8 @@ function EditableText({
11382
11532
  }) {
11383
11533
  const engine = useContext60(EngineContext);
11384
11534
  const entityId = useContext60(EntityContext);
11385
- const containerRef = useRef31(null);
11386
- const inputRef = useRef31(null);
11535
+ const containerRef = useRef32(null);
11536
+ const inputRef = useRef32(null);
11387
11537
  useOverlayTick(() => {
11388
11538
  if (!engine || entityId === null || entityId === void 0) return;
11389
11539
  const container = containerRef.current;
@@ -11410,7 +11560,7 @@ function EditableText({
11410
11560
  container.style.setProperty("--cubeforge-canvas-left", `${rect.left + window.scrollX}px`);
11411
11561
  container.style.setProperty("--cubeforge-canvas-top", `${rect.top + window.scrollY}px`);
11412
11562
  }, [engine, entityId, width, height, fontSize]);
11413
- useEffect69(() => {
11563
+ useEffect70(() => {
11414
11564
  if (autoFocus) inputRef.current?.focus();
11415
11565
  }, [autoFocus]);
11416
11566
  if (!engine) return null;
@@ -11541,7 +11691,7 @@ function copyRegion(source, region, scale) {
11541
11691
  }
11542
11692
 
11543
11693
  // src/components/A11yNode.tsx
11544
- import { useContext as useContext61, useRef as useRef32 } from "react";
11694
+ import { useContext as useContext61, useRef as useRef33 } from "react";
11545
11695
  import { jsx as jsx18 } from "react/jsx-runtime";
11546
11696
  function A11yNode({
11547
11697
  label,
@@ -11557,7 +11707,7 @@ function A11yNode({
11557
11707
  }) {
11558
11708
  const engine = useContext61(EngineContext);
11559
11709
  const entityId = useContext61(EntityContext);
11560
- const nodeRef = useRef32(null);
11710
+ const nodeRef = useRef33(null);
11561
11711
  useOverlayTick(() => {
11562
11712
  if (!engine || entityId === null || entityId === void 0) return;
11563
11713
  const node = nodeRef.current;
@@ -11646,7 +11796,7 @@ function worldToScreenCss3(engine, wx, wy) {
11646
11796
  }
11647
11797
 
11648
11798
  // src/components/VectorPath.tsx
11649
- import { useContext as useContext62, useRef as useRef33 } from "react";
11799
+ import { useContext as useContext62, useRef as useRef34 } from "react";
11650
11800
  import { jsx as jsx19 } from "react/jsx-runtime";
11651
11801
  function VectorPath({
11652
11802
  d,
@@ -11662,7 +11812,7 @@ function VectorPath({
11662
11812
  }) {
11663
11813
  const engine = useContext62(EngineContext);
11664
11814
  const entityId = useContext62(EntityContext);
11665
- const svgRef = useRef33(null);
11815
+ const svgRef = useRef34(null);
11666
11816
  useOverlayTick(() => {
11667
11817
  if (!engine || entityId === null || entityId === void 0) return;
11668
11818
  const svg = svgRef.current;
@@ -11723,12 +11873,12 @@ function worldToScreenCss4(engine, wx, wy) {
11723
11873
  }
11724
11874
 
11725
11875
  // src/hooks/useGrid.ts
11726
- import { useCallback as useCallback15, useContext as useContext63, useMemo as useMemo14, useRef as useRef34, useState as useState17 } from "react";
11876
+ import { useCallback as useCallback16, useContext as useContext63, useMemo as useMemo14, useRef as useRef35, useState as useState17 } from "react";
11727
11877
  function useGrid({ width, height, fill }) {
11728
11878
  const engine = useContext63(EngineContext);
11729
11879
  const [version, setVersion] = useState17(0);
11730
- const bump = useCallback15(() => setVersion((v) => v + 1), []);
11731
- const dataRef = useRef34(null);
11880
+ const bump = useCallback16(() => setVersion((v) => v + 1), []);
11881
+ const dataRef = useRef35(null);
11732
11882
  if (dataRef.current === null) {
11733
11883
  const arr = new Array(width * height);
11734
11884
  if (typeof fill === "function") {
@@ -11743,19 +11893,19 @@ function useGrid({ width, height, fill }) {
11743
11893
  }
11744
11894
  dataRef.current = arr;
11745
11895
  }
11746
- const markChanged = useCallback15(() => {
11896
+ const markChanged = useCallback16(() => {
11747
11897
  engine?.loop.markDirty();
11748
11898
  bump();
11749
11899
  }, [engine, bump]);
11750
- const inBounds = useCallback15((x, y) => x >= 0 && y >= 0 && x < width && y < height, [width, height]);
11751
- const get = useCallback15(
11900
+ const inBounds = useCallback16((x, y) => x >= 0 && y >= 0 && x < width && y < height, [width, height]);
11901
+ const get = useCallback16(
11752
11902
  (x, y) => {
11753
11903
  if (!inBounds(x, y)) return void 0;
11754
11904
  return dataRef.current[y * width + x];
11755
11905
  },
11756
11906
  [width, inBounds]
11757
11907
  );
11758
- const set = useCallback15(
11908
+ const set = useCallback16(
11759
11909
  (x, y, value) => {
11760
11910
  if (!inBounds(x, y)) return;
11761
11911
  const data = dataRef.current;
@@ -11766,7 +11916,7 @@ function useGrid({ width, height, fill }) {
11766
11916
  },
11767
11917
  [width, inBounds, markChanged]
11768
11918
  );
11769
- const swap = useCallback15(
11919
+ const swap = useCallback16(
11770
11920
  (ax, ay, bx, by) => {
11771
11921
  if (!inBounds(ax, ay) || !inBounds(bx, by)) return;
11772
11922
  const data = dataRef.current;
@@ -11780,7 +11930,7 @@ function useGrid({ width, height, fill }) {
11780
11930
  },
11781
11931
  [width, inBounds, markChanged]
11782
11932
  );
11783
- const forEach = useCallback15(
11933
+ const forEach = useCallback16(
11784
11934
  (cb) => {
11785
11935
  const data = dataRef.current;
11786
11936
  for (let y = 0; y < height; y++) {
@@ -11791,7 +11941,7 @@ function useGrid({ width, height, fill }) {
11791
11941
  },
11792
11942
  [width, height]
11793
11943
  );
11794
- const find = useCallback15(
11944
+ const find = useCallback16(
11795
11945
  (pred) => {
11796
11946
  const data = dataRef.current;
11797
11947
  for (let y = 0; y < height; y++) {
@@ -11804,7 +11954,7 @@ function useGrid({ width, height, fill }) {
11804
11954
  },
11805
11955
  [width, height]
11806
11956
  );
11807
- const count = useCallback15(
11957
+ const count = useCallback16(
11808
11958
  (pred) => {
11809
11959
  const data = dataRef.current;
11810
11960
  let n = 0;
@@ -11817,7 +11967,7 @@ function useGrid({ width, height, fill }) {
11817
11967
  },
11818
11968
  [width, height]
11819
11969
  );
11820
- const neighbors = useCallback15(
11970
+ const neighbors = useCallback16(
11821
11971
  (x, y, diagonal = false) => {
11822
11972
  const data = dataRef.current;
11823
11973
  const result = [];
@@ -11845,7 +11995,7 @@ function useGrid({ width, height, fill }) {
11845
11995
  },
11846
11996
  [width, inBounds]
11847
11997
  );
11848
- const fillAll = useCallback15(
11998
+ const fillAll = useCallback16(
11849
11999
  (value) => {
11850
12000
  const data = dataRef.current;
11851
12001
  if (typeof value === "function") {
@@ -11862,7 +12012,7 @@ function useGrid({ width, height, fill }) {
11862
12012
  },
11863
12013
  [width, height, markChanged]
11864
12014
  );
11865
- const toArray = useCallback15(() => {
12015
+ const toArray = useCallback16(() => {
11866
12016
  const data = dataRef.current;
11867
12017
  const out = new Array(height);
11868
12018
  for (let y = 0; y < height; y++) {
@@ -11872,7 +12022,7 @@ function useGrid({ width, height, fill }) {
11872
12022
  }
11873
12023
  return out;
11874
12024
  }, [width, height]);
11875
- const fromArray = useCallback15(
12025
+ const fromArray = useCallback16(
11876
12026
  (arr) => {
11877
12027
  const data = dataRef.current;
11878
12028
  for (let y = 0; y < height; y++) {
@@ -11908,7 +12058,7 @@ function useGrid({ width, height, fill }) {
11908
12058
  }
11909
12059
 
11910
12060
  // 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";
12061
+ import { useCallback as useCallback17, useContext as useContext64, useEffect as useEffect71, useMemo as useMemo15, useRef as useRef36, useState as useState18 } from "react";
11912
12062
  function useTurnSystem({
11913
12063
  players,
11914
12064
  initialIndex = 0,
@@ -11921,11 +12071,11 @@ function useTurnSystem({
11921
12071
  const [activeIndex, setActiveIndex] = useState18(initialIndex % players.length);
11922
12072
  const [turn, setTurn] = useState18(0);
11923
12073
  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(() => {
12074
+ const pendingRafId = useRef36(null);
12075
+ const pendingRemaining = useRef36(0);
12076
+ const pendingTarget = useRef36(null);
12077
+ const pendingLastTime = useRef36(0);
12078
+ const clearPending = useCallback17(() => {
11929
12079
  if (pendingRafId.current !== null) {
11930
12080
  cancelAnimationFrame(pendingRafId.current);
11931
12081
  pendingRafId.current = null;
@@ -11933,13 +12083,13 @@ function useTurnSystem({
11933
12083
  pendingTarget.current = null;
11934
12084
  setIsPending(false);
11935
12085
  }, []);
11936
- const startedOnce = useRef35(false);
11937
- useEffect70(() => {
12086
+ const startedOnce = useRef36(false);
12087
+ useEffect71(() => {
11938
12088
  if (startedOnce.current) return;
11939
12089
  startedOnce.current = true;
11940
12090
  onTurnStart?.({ player: players[activeIndex], index: activeIndex, turn: 0 });
11941
12091
  }, []);
11942
- const applyChange = useCallback16(
12092
+ const applyChange = useCallback17(
11943
12093
  (nextIndex) => {
11944
12094
  const curr = players[activeIndex];
11945
12095
  onTurnEnd?.({ player: curr, index: activeIndex, turn });
@@ -11952,7 +12102,7 @@ function useTurnSystem({
11952
12102
  },
11953
12103
  [players, activeIndex, turn, onTurnStart, onTurnEnd, engine]
11954
12104
  );
11955
- const scheduleChange = useCallback16(
12105
+ const scheduleChange = useCallback17(
11956
12106
  (nextIndex) => {
11957
12107
  clearPending();
11958
12108
  if (aiDelay <= 0) {
@@ -11984,9 +12134,9 @@ function useTurnSystem({
11984
12134
  },
11985
12135
  [aiDelay, applyChange, clearPending, engine]
11986
12136
  );
11987
- const nextTurn = useCallback16(() => scheduleChange(activeIndex + 1), [scheduleChange, activeIndex]);
11988
- const prevTurn = useCallback16(() => scheduleChange(activeIndex - 1), [scheduleChange, activeIndex]);
11989
- const skipTo = useCallback16(
12137
+ const nextTurn = useCallback17(() => scheduleChange(activeIndex + 1), [scheduleChange, activeIndex]);
12138
+ const prevTurn = useCallback17(() => scheduleChange(activeIndex - 1), [scheduleChange, activeIndex]);
12139
+ const skipTo = useCallback17(
11990
12140
  (target) => {
11991
12141
  let idx;
11992
12142
  if (typeof target === "number") {
@@ -11999,13 +12149,13 @@ function useTurnSystem({
11999
12149
  },
12000
12150
  [players, scheduleChange]
12001
12151
  );
12002
- const reset = useCallback16(() => {
12152
+ const reset = useCallback17(() => {
12003
12153
  clearPending();
12004
12154
  setActiveIndex(initialIndex % players.length);
12005
12155
  setTurn(0);
12006
12156
  engine?.loop.markDirty();
12007
12157
  }, [players.length, initialIndex, clearPending, engine]);
12008
- useEffect70(
12158
+ useEffect71(
12009
12159
  () => () => {
12010
12160
  if (pendingRafId.current !== null) cancelAnimationFrame(pendingRafId.current);
12011
12161
  },
@@ -12027,13 +12177,13 @@ function useTurnSystem({
12027
12177
  }
12028
12178
 
12029
12179
  // src/hooks/useHoverable.ts
12030
- import { useContext as useContext65, useEffect as useEffect71, useState as useState19 } from "react";
12180
+ import { useContext as useContext65, useEffect as useEffect72, useState as useState19 } from "react";
12031
12181
  function useHoverable(options) {
12032
12182
  const engine = useContext65(EngineContext);
12033
12183
  const ctxEntityId = useContext65(EntityContext);
12034
12184
  const entityId = options?.entityId ?? ctxEntityId;
12035
12185
  const [isHovered, setIsHovered] = useState19(false);
12036
- useEffect71(() => {
12186
+ useEffect72(() => {
12037
12187
  if (!engine || entityId === null || entityId === void 0 || options?.disabled) return;
12038
12188
  const canvas = engine.canvas;
12039
12189
  let hovered = false;
@@ -12110,7 +12260,7 @@ function screenToWorld(engine, cssX, cssY) {
12110
12260
  }
12111
12261
 
12112
12262
  // src/hooks/useDragDrop.ts
12113
- import { useContext as useContext66, useEffect as useEffect72, useRef as useRef36, useState as useState20 } from "react";
12263
+ import { useContext as useContext66, useEffect as useEffect73, useRef as useRef37, useState as useState20 } from "react";
12114
12264
  var dragStateByEngine = /* @__PURE__ */ new WeakMap();
12115
12265
  function getActiveDrag(engine) {
12116
12266
  return dragStateByEngine.get(engine) ?? null;
@@ -12135,9 +12285,9 @@ function useDraggable(options) {
12135
12285
  const entityId = options?.entityId ?? ctxEntityId;
12136
12286
  const [isDragging, setIsDragging] = useState20(false);
12137
12287
  const [position, setPosition] = useState20({ x: 0, y: 0 });
12138
- const optsRef = useRef36(options);
12288
+ const optsRef = useRef37(options);
12139
12289
  optsRef.current = options;
12140
- useEffect72(() => {
12290
+ useEffect73(() => {
12141
12291
  if (!engine || entityId === null || entityId === void 0 || options?.disabled) return;
12142
12292
  const canvas = engine.canvas;
12143
12293
  let dragging = false;
@@ -12247,9 +12397,9 @@ function useDroppable(options) {
12247
12397
  const entityId = options?.entityId ?? ctxEntityId;
12248
12398
  const [isOver, setIsOver] = useState20(false);
12249
12399
  const [hoveredBy, setHoveredBy] = useState20(null);
12250
- const optsRef = useRef36(options);
12400
+ const optsRef = useRef37(options);
12251
12401
  optsRef.current = options;
12252
- useEffect72(() => {
12402
+ useEffect73(() => {
12253
12403
  if (!engine || entityId === null || entityId === void 0 || options?.disabled) return;
12254
12404
  let currentlyOver = false;
12255
12405
  const check = () => {
@@ -12351,7 +12501,7 @@ function findDroppableUnder(engine, drag) {
12351
12501
  }
12352
12502
 
12353
12503
  // src/hooks/useKeyboardFocus.ts
12354
- import { useContext as useContext67, useEffect as useEffect73, useRef as useRef37, useState as useState21 } from "react";
12504
+ import { useContext as useContext67, useEffect as useEffect74, useRef as useRef38, useState as useState21 } from "react";
12355
12505
  var registry = /* @__PURE__ */ new Map();
12356
12506
  var focusedId = null;
12357
12507
  var subscribers = /* @__PURE__ */ new Set();
@@ -12368,9 +12518,9 @@ function setFocused(id) {
12368
12518
  }
12369
12519
  function useFocusable(options) {
12370
12520
  const entityIdCtx = useContext67(EntityContext);
12371
- const optsRef = useRef37(options);
12521
+ const optsRef = useRef38(options);
12372
12522
  optsRef.current = options;
12373
- useEffect73(() => {
12523
+ useEffect74(() => {
12374
12524
  if (entityIdCtx === null || entityIdCtx === void 0) return;
12375
12525
  const id = entityIdCtx;
12376
12526
  const entry = {
@@ -12390,14 +12540,14 @@ function useFocusable(options) {
12390
12540
  function useKeyboardFocus() {
12391
12541
  const engine = useContext67(EngineContext);
12392
12542
  const [focused, setFocusedState] = useState21(focusedId);
12393
- useEffect73(() => {
12543
+ useEffect74(() => {
12394
12544
  const cb = () => setFocusedState(focusedId);
12395
12545
  subscribers.add(cb);
12396
12546
  return () => {
12397
12547
  subscribers.delete(cb);
12398
12548
  };
12399
12549
  }, []);
12400
- useEffect73(() => {
12550
+ useEffect74(() => {
12401
12551
  if (!engine) return;
12402
12552
  const onKey = (e) => {
12403
12553
  const target = e.target;
@@ -12523,7 +12673,7 @@ function subscribeFocus(cb) {
12523
12673
  }
12524
12674
 
12525
12675
  // src/components/FocusRing.tsx
12526
- import { useContext as useContext68, useEffect as useEffect74, useRef as useRef38, useState as useState22 } from "react";
12676
+ import { useContext as useContext68, useEffect as useEffect75, useRef as useRef39, useState as useState22 } from "react";
12527
12677
  import { Fragment as Fragment9, jsx as jsx20, jsxs as jsxs9 } from "react/jsx-runtime";
12528
12678
  function FocusRing({
12529
12679
  color = "#4fc3f7",
@@ -12533,14 +12683,14 @@ function FocusRing({
12533
12683
  pulse = true
12534
12684
  }) {
12535
12685
  const engine = useContext68(EngineContext);
12536
- const ringRef = useRef38(null);
12686
+ const ringRef = useRef39(null);
12537
12687
  const [focused, setFocused2] = useState22(getFocusedEntityId());
12538
12688
  const [reducedMotion, setReducedMotion] = useState22(false);
12539
- useEffect74(() => {
12689
+ useEffect75(() => {
12540
12690
  const unsub = subscribeFocus(() => setFocused2(getFocusedEntityId()));
12541
12691
  return unsub;
12542
12692
  }, []);
12543
- useEffect74(() => {
12693
+ useEffect75(() => {
12544
12694
  if (typeof window === "undefined" || !window.matchMedia) return;
12545
12695
  const mq = window.matchMedia("(prefers-reduced-motion: reduce)");
12546
12696
  setReducedMotion(mq.matches);
@@ -12677,10 +12827,10 @@ function listSavedScenes(prefix = "") {
12677
12827
  }
12678
12828
 
12679
12829
  // ../gameplay/src/hooks/useAnimationController.ts
12680
- import { useState as useState23, useCallback as useCallback17 } from "react";
12830
+ import { useState as useState23, useCallback as useCallback18 } from "react";
12681
12831
  function useAnimationController(states, initial) {
12682
12832
  const [stateName, setStateName] = useState23(initial);
12683
- const setState = useCallback17((next) => {
12833
+ const setState = useCallback18((next) => {
12684
12834
  setStateName((prev) => prev === next ? prev : next);
12685
12835
  }, []);
12686
12836
  const clip = states[stateName] ?? states[initial];
@@ -12702,39 +12852,39 @@ function useAnimationController(states, initial) {
12702
12852
  }
12703
12853
 
12704
12854
  // ../gameplay/src/hooks/useAISteering.ts
12705
- import { useCallback as useCallback18 } from "react";
12855
+ import { useCallback as useCallback19 } from "react";
12706
12856
  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(
12857
+ const seek$ = useCallback19((pos, target, speed) => seek(pos, target, speed), []);
12858
+ const flee$ = useCallback19((pos, threat, speed) => flee(pos, threat, speed), []);
12859
+ const arrive$ = useCallback19(
12710
12860
  (pos, target, speed, slowRadius) => arrive(pos, target, speed, slowRadius),
12711
12861
  []
12712
12862
  );
12713
- const patrol$ = useCallback18(
12863
+ const patrol$ = useCallback19(
12714
12864
  (pos, waypoints, speed, currentIdx, arriveThreshold) => patrol(pos, waypoints, speed, currentIdx, arriveThreshold),
12715
12865
  []
12716
12866
  );
12717
- const wander$ = useCallback18(
12867
+ const wander$ = useCallback19(
12718
12868
  (pos, angle, speed, jitter) => wander(pos, angle, speed, jitter),
12719
12869
  []
12720
12870
  );
12721
- const pursuit$ = useCallback18(
12871
+ const pursuit$ = useCallback19(
12722
12872
  (pos, targetPos, targetVel, speed, lookAhead) => pursuit(pos, targetPos, targetVel, speed, lookAhead),
12723
12873
  []
12724
12874
  );
12725
- const evade$ = useCallback18(
12875
+ const evade$ = useCallback19(
12726
12876
  (pos, threatPos, threatVel, speed, lookAhead) => evade(pos, threatPos, threatVel, speed, lookAhead),
12727
12877
  []
12728
12878
  );
12729
- const separation$ = useCallback18(
12879
+ const separation$ = useCallback19(
12730
12880
  (pos, neighbors, speed, radius) => separation(pos, neighbors, speed, radius),
12731
12881
  []
12732
12882
  );
12733
- const cohesion$ = useCallback18(
12883
+ const cohesion$ = useCallback19(
12734
12884
  (pos, neighbors, speed) => cohesion(pos, neighbors, speed),
12735
12885
  []
12736
12886
  );
12737
- const alignment$ = useCallback18(
12887
+ const alignment$ = useCallback19(
12738
12888
  (neighborVelocities, speed) => alignment(neighborVelocities, speed),
12739
12889
  []
12740
12890
  );
@@ -12765,11 +12915,11 @@ function useDamageZone(damage, opts = {}) {
12765
12915
  }
12766
12916
 
12767
12917
  // ../gameplay/src/hooks/useDropThrough.ts
12768
- import { useContext as useContext70, useCallback as useCallback19 } from "react";
12918
+ import { useContext as useContext70, useCallback as useCallback20 } from "react";
12769
12919
  function useDropThrough(frames = 8) {
12770
12920
  const engine = useContext70(EngineContext);
12771
12921
  const entityId = useContext70(EntityContext);
12772
- const dropThrough = useCallback19(() => {
12922
+ const dropThrough = useCallback20(() => {
12773
12923
  const rb = engine.ecs.getComponent(entityId, "RigidBody");
12774
12924
  if (rb) rb.dropThrough = frames;
12775
12925
  }, [engine.ecs, entityId, frames]);
@@ -12777,17 +12927,17 @@ function useDropThrough(frames = 8) {
12777
12927
  }
12778
12928
 
12779
12929
  // ../gameplay/src/hooks/useGameStateMachine.ts
12780
- import { useState as useState24, useRef as useRef39, useCallback as useCallback20, useEffect as useEffect75, useContext as useContext71 } from "react";
12930
+ import { useState as useState24, useRef as useRef40, useCallback as useCallback21, useEffect as useEffect76, useContext as useContext71 } from "react";
12781
12931
  function useGameStateMachine(states, initial) {
12782
12932
  const engine = useContext71(EngineContext);
12783
12933
  const [state, setState] = useState24(initial);
12784
- const stateRef = useRef39(initial);
12785
- const statesRef = useRef39(states);
12934
+ const stateRef = useRef40(initial);
12935
+ const statesRef = useRef40(states);
12786
12936
  statesRef.current = states;
12787
- useEffect75(() => {
12937
+ useEffect76(() => {
12788
12938
  statesRef.current[initial]?.onEnter?.();
12789
12939
  }, []);
12790
- const transition = useCallback20((to) => {
12940
+ const transition = useCallback21((to) => {
12791
12941
  const current = stateRef.current;
12792
12942
  if (current === to) return;
12793
12943
  statesRef.current[current]?.onExit?.();
@@ -12795,7 +12945,7 @@ function useGameStateMachine(states, initial) {
12795
12945
  setState(to);
12796
12946
  statesRef.current[to]?.onEnter?.();
12797
12947
  }, []);
12798
- useEffect75(() => {
12948
+ useEffect76(() => {
12799
12949
  const eid = engine.ecs.createEntity();
12800
12950
  engine.ecs.addComponent(
12801
12951
  eid,
@@ -12811,27 +12961,27 @@ function useGameStateMachine(states, initial) {
12811
12961
  }
12812
12962
 
12813
12963
  // ../gameplay/src/hooks/useHealth.ts
12814
- import { useRef as useRef40, useEffect as useEffect76, useContext as useContext72, useCallback as useCallback21 } from "react";
12964
+ import { useRef as useRef41, useEffect as useEffect77, useContext as useContext72, useCallback as useCallback22 } from "react";
12815
12965
  function useHealth(maxHp, opts = {}) {
12816
12966
  const engine = useContext72(EngineContext);
12817
12967
  const entityId = useContext72(EntityContext);
12818
- const hpRef = useRef40(maxHp);
12819
- const invincibleRef = useRef40(false);
12968
+ const hpRef = useRef41(maxHp);
12969
+ const invincibleRef = useRef41(false);
12820
12970
  const iFrameDuration = opts.iFrames ?? 1;
12821
- const onDeathRef = useRef40(opts.onDeath);
12822
- const onDamageRef = useRef40(opts.onDamage);
12823
- useEffect76(() => {
12971
+ const onDeathRef = useRef41(opts.onDeath);
12972
+ const onDamageRef = useRef41(opts.onDamage);
12973
+ useEffect77(() => {
12824
12974
  onDeathRef.current = opts.onDeath;
12825
12975
  });
12826
- useEffect76(() => {
12976
+ useEffect77(() => {
12827
12977
  onDamageRef.current = opts.onDamage;
12828
12978
  });
12829
- const timerRef = useRef40(
12979
+ const timerRef = useRef41(
12830
12980
  createTimer(iFrameDuration, () => {
12831
12981
  invincibleRef.current = false;
12832
12982
  })
12833
12983
  );
12834
- const takeDamage = useCallback21(
12984
+ const takeDamage = useCallback22(
12835
12985
  (amount = 1) => {
12836
12986
  if (invincibleRef.current || hpRef.current <= 0) return;
12837
12987
  hpRef.current = Math.max(0, hpRef.current - amount);
@@ -12844,28 +12994,28 @@ function useHealth(maxHp, opts = {}) {
12844
12994
  },
12845
12995
  [iFrameDuration]
12846
12996
  );
12847
- const takeDamageRef = useRef40(takeDamage);
12848
- useEffect76(() => {
12997
+ const takeDamageRef = useRef41(takeDamage);
12998
+ useEffect77(() => {
12849
12999
  takeDamageRef.current = takeDamage;
12850
13000
  }, [takeDamage]);
12851
- useEffect76(() => {
13001
+ useEffect77(() => {
12852
13002
  return engine.events.on(`damage:${entityId}`, ({ amount }) => {
12853
13003
  takeDamageRef.current(amount);
12854
13004
  });
12855
13005
  }, [engine.events, entityId]);
12856
- const heal = useCallback21(
13006
+ const heal = useCallback22(
12857
13007
  (amount) => {
12858
13008
  hpRef.current = Math.min(maxHp, hpRef.current + amount);
12859
13009
  },
12860
13010
  [maxHp]
12861
13011
  );
12862
- const setHp = useCallback21(
13012
+ const setHp = useCallback22(
12863
13013
  (hp) => {
12864
13014
  hpRef.current = Math.min(maxHp, Math.max(0, hp));
12865
13015
  },
12866
13016
  [maxHp]
12867
13017
  );
12868
- const update = useCallback21((dt) => {
13018
+ const update = useCallback22((dt) => {
12869
13019
  timerRef.current.update(dt);
12870
13020
  }, []);
12871
13021
  return {
@@ -12889,11 +13039,11 @@ function useHealth(maxHp, opts = {}) {
12889
13039
  }
12890
13040
 
12891
13041
  // ../gameplay/src/hooks/useKinematicBody.ts
12892
- import { useContext as useContext73, useCallback as useCallback22 } from "react";
13042
+ import { useContext as useContext73, useCallback as useCallback23 } from "react";
12893
13043
  function useKinematicBody() {
12894
13044
  const engine = useContext73(EngineContext);
12895
13045
  const entityId = useContext73(EntityContext);
12896
- const moveAndCollide = useCallback22(
13046
+ const moveAndCollide = useCallback23(
12897
13047
  (dx, dy) => {
12898
13048
  const transform = engine.ecs.getComponent(entityId, "Transform");
12899
13049
  if (!transform) return { dx: 0, dy: 0 };
@@ -12929,7 +13079,7 @@ function useKinematicBody() {
12929
13079
  },
12930
13080
  [engine.ecs, entityId]
12931
13081
  );
12932
- const setVelocity = useCallback22(
13082
+ const setVelocity = useCallback23(
12933
13083
  (vx, vy) => {
12934
13084
  const rb = engine.ecs.getComponent(entityId, "RigidBody");
12935
13085
  if (rb) {
@@ -12939,7 +13089,7 @@ function useKinematicBody() {
12939
13089
  },
12940
13090
  [engine.ecs, entityId]
12941
13091
  );
12942
- const setAngularVelocity = useCallback22(
13092
+ const setAngularVelocity = useCallback23(
12943
13093
  (w) => {
12944
13094
  const rb = engine.ecs.getComponent(entityId, "RigidBody");
12945
13095
  if (rb) rb.angularVelocity = w;
@@ -12950,12 +13100,12 @@ function useKinematicBody() {
12950
13100
  }
12951
13101
 
12952
13102
  // ../gameplay/src/hooks/useLevelTransition.ts
12953
- import { useState as useState25, useRef as useRef41, useCallback as useCallback23 } from "react";
13103
+ import { useState as useState25, useRef as useRef42, useCallback as useCallback24 } from "react";
12954
13104
  function useLevelTransition(initial) {
12955
13105
  const [currentLevel, setCurrentLevel] = useState25(initial);
12956
13106
  const [isTransitioning, setIsTransitioning] = useState25(false);
12957
- const overlayRef = useRef41(null);
12958
- const transitionTo = useCallback23((level, opts = {}) => {
13107
+ const overlayRef = useRef42(null);
13108
+ const transitionTo = useCallback24((level, opts = {}) => {
12959
13109
  const { duration = 0.4, type = "fade" } = opts;
12960
13110
  if (type === "instant") {
12961
13111
  setCurrentLevel(level);
@@ -12992,7 +13142,7 @@ function useLevelTransition(initial) {
12992
13142
  }
12993
13143
 
12994
13144
  // ../gameplay/src/hooks/usePlatformerController.ts
12995
- import { useContext as useContext74, useEffect as useEffect77 } from "react";
13145
+ import { useContext as useContext74, useEffect as useEffect78 } from "react";
12996
13146
  function normalizeKeys(val, defaults) {
12997
13147
  if (!val) return defaults;
12998
13148
  return Array.isArray(val) ? val : [val];
@@ -13016,7 +13166,7 @@ function usePlatformerController(entityId, opts = {}) {
13016
13166
  const leftKeys = normalizeKeys(bindings?.left, ["ArrowLeft", "KeyA", "a"]);
13017
13167
  const rightKeys = normalizeKeys(bindings?.right, ["ArrowRight", "KeyD", "d"]);
13018
13168
  const jumpKeys = normalizeKeys(bindings?.jump, ["Space", "ArrowUp", "KeyW", "w"]);
13019
- useEffect77(() => {
13169
+ useEffect78(() => {
13020
13170
  const state = {
13021
13171
  coyoteTimer: 0,
13022
13172
  jumpBuffer: 0,
@@ -13080,22 +13230,22 @@ function usePlatformerController(entityId, opts = {}) {
13080
13230
  }
13081
13231
 
13082
13232
  // ../gameplay/src/hooks/usePathfinding.ts
13083
- import { useCallback as useCallback24 } from "react";
13233
+ import { useCallback as useCallback25 } from "react";
13084
13234
  function usePathfinding() {
13085
- const createGrid$ = useCallback24(
13235
+ const createGrid$ = useCallback25(
13086
13236
  (cols, rows, cellSize) => createNavGrid(cols, rows, cellSize),
13087
13237
  []
13088
13238
  );
13089
- const setWalkable$ = useCallback24(
13239
+ const setWalkable$ = useCallback25(
13090
13240
  (grid, col, row, walkable) => setWalkable(grid, col, row, walkable),
13091
13241
  []
13092
13242
  );
13093
- const findPath$ = useCallback24((grid, start2, goal) => findPath(grid, start2, goal), []);
13243
+ const findPath$ = useCallback25((grid, start2, goal) => findPath(grid, start2, goal), []);
13094
13244
  return { createGrid: createGrid$, setWalkable: setWalkable$, findPath: findPath$ };
13095
13245
  }
13096
13246
 
13097
13247
  // ../gameplay/src/hooks/usePersistedBindings.ts
13098
- import { useState as useState26, useCallback as useCallback25, useMemo as useMemo16, useContext as useContext75 } from "react";
13248
+ import { useState as useState26, useCallback as useCallback26, useMemo as useMemo16, useContext as useContext75 } from "react";
13099
13249
  function usePersistedBindings(storageKey, defaults) {
13100
13250
  const engine = useContext75(EngineContext);
13101
13251
  const input = engine.input;
@@ -13115,7 +13265,7 @@ function usePersistedBindings(storageKey, defaults) {
13115
13265
  }
13116
13266
  return out;
13117
13267
  }, [bindings]);
13118
- const rebind = useCallback25(
13268
+ const rebind = useCallback26(
13119
13269
  (action, keys) => {
13120
13270
  setBindings((prev) => {
13121
13271
  const next = { ...prev, [action]: Array.isArray(keys) ? keys : [keys] };
@@ -13128,7 +13278,7 @@ function usePersistedBindings(storageKey, defaults) {
13128
13278
  },
13129
13279
  [storageKey]
13130
13280
  );
13131
- const reset = useCallback25(() => {
13281
+ const reset = useCallback26(() => {
13132
13282
  try {
13133
13283
  localStorage.removeItem(storageKey);
13134
13284
  } catch {
@@ -13149,21 +13299,21 @@ function usePersistedBindings(storageKey, defaults) {
13149
13299
  }
13150
13300
 
13151
13301
  // ../gameplay/src/hooks/useRestart.ts
13152
- import { useState as useState27, useCallback as useCallback26 } from "react";
13302
+ import { useState as useState27, useCallback as useCallback27 } from "react";
13153
13303
  function useRestart() {
13154
13304
  const [restartKey, setRestartKey] = useState27(0);
13155
- const restart = useCallback26(() => {
13305
+ const restart = useCallback27(() => {
13156
13306
  setRestartKey((k) => k + 1);
13157
13307
  }, []);
13158
13308
  return { restartKey, restart };
13159
13309
  }
13160
13310
 
13161
13311
  // ../gameplay/src/hooks/useSave.ts
13162
- import { useCallback as useCallback27, useRef as useRef42 } from "react";
13312
+ import { useCallback as useCallback28, useRef as useRef43 } from "react";
13163
13313
  function useSave(key, defaultValue, opts = {}) {
13164
13314
  const version = opts.version ?? 1;
13165
- const dataRef = useRef42(defaultValue);
13166
- const save = useCallback27(
13315
+ const dataRef = useRef43(defaultValue);
13316
+ const save = useCallback28(
13167
13317
  (value) => {
13168
13318
  dataRef.current = value;
13169
13319
  const slot = { version, data: value };
@@ -13175,7 +13325,7 @@ function useSave(key, defaultValue, opts = {}) {
13175
13325
  },
13176
13326
  [key, version]
13177
13327
  );
13178
- const load = useCallback27(() => {
13328
+ const load = useCallback28(() => {
13179
13329
  try {
13180
13330
  const raw = localStorage.getItem(key);
13181
13331
  if (!raw) return defaultValue;
@@ -13195,11 +13345,11 @@ function useSave(key, defaultValue, opts = {}) {
13195
13345
  return defaultValue;
13196
13346
  }
13197
13347
  }, [key, version]);
13198
- const clear = useCallback27(() => {
13348
+ const clear = useCallback28(() => {
13199
13349
  localStorage.removeItem(key);
13200
13350
  dataRef.current = defaultValue;
13201
13351
  }, [key]);
13202
- const exists = useCallback27(() => {
13352
+ const exists = useCallback28(() => {
13203
13353
  return localStorage.getItem(key) !== null;
13204
13354
  }, [key]);
13205
13355
  return {
@@ -13214,7 +13364,7 @@ function useSave(key, defaultValue, opts = {}) {
13214
13364
  }
13215
13365
 
13216
13366
  // ../gameplay/src/hooks/useIDBSave.ts
13217
- import { useCallback as useCallback28, useRef as useRef43 } from "react";
13367
+ import { useCallback as useCallback29, useRef as useRef44 } from "react";
13218
13368
  var DB_NAME = "cubeforge-saves";
13219
13369
  var STORE_NAME = "saves";
13220
13370
  function openDB() {
@@ -13232,12 +13382,12 @@ function openDB() {
13232
13382
  }
13233
13383
  function useIDBSave(key, defaultValue, opts = {}) {
13234
13384
  const version = opts.version ?? 1;
13235
- const dbRef = useRef43(null);
13236
- const getDB = useCallback28(() => {
13385
+ const dbRef = useRef44(null);
13386
+ const getDB = useCallback29(() => {
13237
13387
  if (!dbRef.current) dbRef.current = openDB();
13238
13388
  return dbRef.current;
13239
13389
  }, []);
13240
- const save = useCallback28(
13390
+ const save = useCallback29(
13241
13391
  async (value) => {
13242
13392
  const db = await getDB();
13243
13393
  const slot = { version, data: value };
@@ -13250,7 +13400,7 @@ function useIDBSave(key, defaultValue, opts = {}) {
13250
13400
  },
13251
13401
  [getDB, key, version]
13252
13402
  );
13253
- const load = useCallback28(async () => {
13403
+ const load = useCallback29(async () => {
13254
13404
  const db = await getDB();
13255
13405
  return new Promise((resolve, reject) => {
13256
13406
  const tx = db.transaction(STORE_NAME, "readonly");
@@ -13276,7 +13426,7 @@ function useIDBSave(key, defaultValue, opts = {}) {
13276
13426
  req.onerror = () => reject(req.error);
13277
13427
  });
13278
13428
  }, [getDB, key, version]);
13279
- const clear = useCallback28(async () => {
13429
+ const clear = useCallback29(async () => {
13280
13430
  const db = await getDB();
13281
13431
  return new Promise((resolve, reject) => {
13282
13432
  const tx = db.transaction(STORE_NAME, "readwrite");
@@ -13285,7 +13435,7 @@ function useIDBSave(key, defaultValue, opts = {}) {
13285
13435
  req.onerror = () => reject(req.error);
13286
13436
  });
13287
13437
  }, [getDB, key]);
13288
- const exists = useCallback28(async () => {
13438
+ const exists = useCallback29(async () => {
13289
13439
  const db = await getDB();
13290
13440
  return new Promise((resolve, reject) => {
13291
13441
  const tx = db.transaction(STORE_NAME, "readonly");
@@ -13298,7 +13448,7 @@ function useIDBSave(key, defaultValue, opts = {}) {
13298
13448
  }
13299
13449
 
13300
13450
  // ../gameplay/src/hooks/useSaveSlots.ts
13301
- import { useCallback as useCallback29, useState as useState28 } from "react";
13451
+ import { useCallback as useCallback30, useState as useState28 } from "react";
13302
13452
  function useSaveSlots(namespace, opts = {}) {
13303
13453
  const version = opts.version ?? 1;
13304
13454
  const indexKey = `cubeforge-saves:${namespace}:__index`;
@@ -13352,7 +13502,7 @@ function useSaveSlots(namespace, opts = {}) {
13352
13502
  const metas = readIndex().map((id) => readSlot(id)?.meta).filter((m) => m !== void 0).sort((a, b) => a.savedAt < b.savedAt ? 1 : -1);
13353
13503
  setSlots(metas);
13354
13504
  }
13355
- const save = useCallback29(
13505
+ const save = useCallback30(
13356
13506
  (id, data, label, thumbnail) => {
13357
13507
  const meta = {
13358
13508
  id,
@@ -13367,7 +13517,7 @@ function useSaveSlots(namespace, opts = {}) {
13367
13517
  // eslint-disable-next-line react-hooks/exhaustive-deps
13368
13518
  [namespace, version]
13369
13519
  );
13370
- const load = useCallback29(
13520
+ const load = useCallback30(
13371
13521
  (id) => {
13372
13522
  const entry = readSlot(id);
13373
13523
  if (!entry) return null;
@@ -13383,7 +13533,7 @@ function useSaveSlots(namespace, opts = {}) {
13383
13533
  // eslint-disable-next-line react-hooks/exhaustive-deps
13384
13534
  [namespace, version]
13385
13535
  );
13386
- const deleteFn = useCallback29(
13536
+ const deleteFn = useCallback30(
13387
13537
  (id) => {
13388
13538
  try {
13389
13539
  localStorage.removeItem(slotKey(id));
@@ -13395,7 +13545,7 @@ function useSaveSlots(namespace, opts = {}) {
13395
13545
  // eslint-disable-next-line react-hooks/exhaustive-deps
13396
13546
  [namespace]
13397
13547
  );
13398
- const copy = useCallback29(
13548
+ const copy = useCallback30(
13399
13549
  (fromId, toId) => {
13400
13550
  const entry = readSlot(fromId);
13401
13551
  if (!entry) return false;
@@ -13408,7 +13558,7 @@ function useSaveSlots(namespace, opts = {}) {
13408
13558
  // eslint-disable-next-line react-hooks/exhaustive-deps
13409
13559
  [namespace, version]
13410
13560
  );
13411
- const rename = useCallback29(
13561
+ const rename = useCallback30(
13412
13562
  (id, label) => {
13413
13563
  const entry = readSlot(id);
13414
13564
  if (!entry) return;
@@ -13418,10 +13568,10 @@ function useSaveSlots(namespace, opts = {}) {
13418
13568
  // eslint-disable-next-line react-hooks/exhaustive-deps
13419
13569
  [namespace]
13420
13570
  );
13421
- const listSlots = useCallback29(() => {
13571
+ const listSlots = useCallback30(() => {
13422
13572
  return readIndex().map((id) => readSlot(id)?.meta).filter((m) => m !== void 0).sort((a, b) => a.savedAt < b.savedAt ? 1 : -1);
13423
13573
  }, [namespace]);
13424
- const exists = useCallback29(
13574
+ const exists = useCallback30(
13425
13575
  (id) => {
13426
13576
  return readSlot(id) !== null;
13427
13577
  },
@@ -13443,7 +13593,7 @@ function useSaveSlots(namespace, opts = {}) {
13443
13593
  }
13444
13594
 
13445
13595
  // ../gameplay/src/hooks/useTopDownMovement.ts
13446
- import { useContext as useContext76, useEffect as useEffect78 } from "react";
13596
+ import { useContext as useContext76, useEffect as useEffect79 } from "react";
13447
13597
  function moveToward(current, target, maxDelta) {
13448
13598
  const diff = target - current;
13449
13599
  if (Math.abs(diff) <= maxDelta) return target;
@@ -13452,7 +13602,7 @@ function moveToward(current, target, maxDelta) {
13452
13602
  function useTopDownMovement(entityId, opts = {}) {
13453
13603
  const engine = useContext76(EngineContext);
13454
13604
  const { speed = 200, normalizeDiagonal = true, acceleration = Infinity, deceleration = acceleration } = opts;
13455
- useEffect78(() => {
13605
+ useEffect79(() => {
13456
13606
  const updateFn = (id, world, input, dt) => {
13457
13607
  if (!world.hasEntity(id)) return;
13458
13608
  const rb = world.getComponent(id, "RigidBody");
@@ -13492,18 +13642,18 @@ function useTopDownMovement(entityId, opts = {}) {
13492
13642
  }
13493
13643
 
13494
13644
  // ../gameplay/src/hooks/useDialogue.ts
13495
- import { useState as useState29, useCallback as useCallback30, useRef as useRef44 } from "react";
13645
+ import { useState as useState29, useCallback as useCallback31, useRef as useRef45 } from "react";
13496
13646
  function useDialogue() {
13497
13647
  const [active, setActive] = useState29(false);
13498
13648
  const [currentId, setCurrentId] = useState29(null);
13499
- const scriptRef = useRef44(null);
13500
- const start2 = useCallback30((script, startId) => {
13649
+ const scriptRef = useRef45(null);
13650
+ const start2 = useCallback31((script, startId) => {
13501
13651
  scriptRef.current = script;
13502
13652
  const id = startId ?? Object.keys(script)[0];
13503
13653
  setCurrentId(id);
13504
13654
  setActive(true);
13505
13655
  }, []);
13506
- const advance = useCallback30(
13656
+ const advance = useCallback31(
13507
13657
  (choiceIndex) => {
13508
13658
  if (!scriptRef.current || !currentId) return;
13509
13659
  const line = scriptRef.current[currentId];
@@ -13533,7 +13683,7 @@ function useDialogue() {
13533
13683
  },
13534
13684
  [currentId]
13535
13685
  );
13536
- const close = useCallback30(() => {
13686
+ const close = useCallback31(() => {
13537
13687
  setActive(false);
13538
13688
  setCurrentId(null);
13539
13689
  scriptRef.current = null;
@@ -13542,6 +13692,367 @@ function useDialogue() {
13542
13692
  return { active, current, currentId, start: start2, advance, close };
13543
13693
  }
13544
13694
 
13695
+ // ../gameplay/src/hooks/useDialogueTree.ts
13696
+ import { useState as useState30, useCallback as useCallback32, useRef as useRef46 } from "react";
13697
+ function interpolate(text, vars) {
13698
+ return text.replace(/\{(\w+)\}/g, (_, key) => {
13699
+ const val = vars[key];
13700
+ return val !== void 0 ? String(val) : `{${key}}`;
13701
+ });
13702
+ }
13703
+ function applyVars(node, vars) {
13704
+ return {
13705
+ ...node,
13706
+ text: interpolate(node.text, vars),
13707
+ speaker: node.speaker ? interpolate(node.speaker, vars) : node.speaker
13708
+ };
13709
+ }
13710
+ function useDialogueTree() {
13711
+ const [active, setActive] = useState30(false);
13712
+ const [currentId, setCurrentId] = useState30(null);
13713
+ const [variables, setVariables] = useState30({});
13714
+ const scriptRef = useRef46(null);
13715
+ const varsRef = useRef46({});
13716
+ function setCurrentNode(id) {
13717
+ if (!id || !scriptRef.current) {
13718
+ setActive(false);
13719
+ setCurrentId(null);
13720
+ return;
13721
+ }
13722
+ const node = scriptRef.current[id];
13723
+ if (!node) {
13724
+ setActive(false);
13725
+ setCurrentId(null);
13726
+ return;
13727
+ }
13728
+ node.onEnter?.(varsRef.current);
13729
+ setCurrentId(id);
13730
+ }
13731
+ const start2 = useCallback32(
13732
+ (script, startId, initialVars) => {
13733
+ scriptRef.current = script;
13734
+ const newVars = { ...varsRef.current, ...initialVars };
13735
+ varsRef.current = newVars;
13736
+ setVariables(newVars);
13737
+ const id = startId ?? Object.keys(script)[0];
13738
+ setActive(true);
13739
+ setCurrentNode(id);
13740
+ },
13741
+ // eslint-disable-next-line react-hooks/exhaustive-deps
13742
+ []
13743
+ );
13744
+ const advance = useCallback32(
13745
+ (choiceIndex) => {
13746
+ if (!scriptRef.current || !currentId) return;
13747
+ const node = scriptRef.current[currentId];
13748
+ if (!node) {
13749
+ setActive(false);
13750
+ setCurrentId(null);
13751
+ return;
13752
+ }
13753
+ node.onExit?.(varsRef.current);
13754
+ if (node.choices && node.choices.length > 0 && choiceIndex !== void 0) {
13755
+ const visible = node.choices.filter((c) => !c.condition || c.condition(varsRef.current));
13756
+ const choice = visible[choiceIndex];
13757
+ if (choice) {
13758
+ choice.onSelect?.(varsRef.current);
13759
+ if (choice.next && scriptRef.current[choice.next]) {
13760
+ setCurrentNode(choice.next);
13761
+ } else {
13762
+ setActive(false);
13763
+ setCurrentId(null);
13764
+ }
13765
+ }
13766
+ return;
13767
+ }
13768
+ if (node.next && scriptRef.current[node.next]) {
13769
+ setCurrentNode(node.next);
13770
+ } else {
13771
+ const keys = Object.keys(scriptRef.current);
13772
+ const idx = keys.indexOf(currentId);
13773
+ if (idx >= 0 && idx + 1 < keys.length) {
13774
+ setCurrentNode(keys[idx + 1]);
13775
+ } else {
13776
+ setActive(false);
13777
+ setCurrentId(null);
13778
+ }
13779
+ }
13780
+ },
13781
+ [currentId]
13782
+ );
13783
+ const jumpTo = useCallback32(
13784
+ (id) => {
13785
+ if (!scriptRef.current?.[id]) return;
13786
+ const current2 = scriptRef.current[currentId ?? ""];
13787
+ current2?.onExit?.(varsRef.current);
13788
+ setCurrentNode(id);
13789
+ },
13790
+ [currentId]
13791
+ );
13792
+ const setVar = useCallback32((key, value) => {
13793
+ varsRef.current = { ...varsRef.current, [key]: value };
13794
+ setVariables({ ...varsRef.current });
13795
+ }, []);
13796
+ const close = useCallback32(() => {
13797
+ if (scriptRef.current && currentId) {
13798
+ scriptRef.current[currentId]?.onExit?.(varsRef.current);
13799
+ }
13800
+ setActive(false);
13801
+ setCurrentId(null);
13802
+ scriptRef.current = null;
13803
+ }, [currentId]);
13804
+ const rawNode = scriptRef.current && currentId ? scriptRef.current[currentId] ?? null : null;
13805
+ const current = rawNode ? applyVars(rawNode, varsRef.current) : null;
13806
+ const visibleChoices = rawNode?.choices ? rawNode.choices.filter((c) => !c.condition || c.condition(varsRef.current)) : [];
13807
+ return {
13808
+ active,
13809
+ current,
13810
+ currentId,
13811
+ visibleChoices,
13812
+ variables,
13813
+ start: start2,
13814
+ advance,
13815
+ jumpTo,
13816
+ setVar,
13817
+ close
13818
+ };
13819
+ }
13820
+
13821
+ // ../gameplay/src/hooks/useBehaviorTree.ts
13822
+ import { useRef as useRef47, useCallback as useCallback33 } from "react";
13823
+ function btAction(fn) {
13824
+ return {
13825
+ tick(dt) {
13826
+ const result = fn(dt);
13827
+ if (result === void 0 || result === null) return "success";
13828
+ if (typeof result === "boolean") return result ? "success" : "failure";
13829
+ return result;
13830
+ },
13831
+ reset() {
13832
+ }
13833
+ };
13834
+ }
13835
+ function btCondition(fn) {
13836
+ return {
13837
+ tick() {
13838
+ return fn() ? "success" : "failure";
13839
+ },
13840
+ reset() {
13841
+ }
13842
+ };
13843
+ }
13844
+ function btWait(duration) {
13845
+ let elapsed = 0;
13846
+ return {
13847
+ tick(dt) {
13848
+ elapsed += dt;
13849
+ if (elapsed >= duration) {
13850
+ elapsed = 0;
13851
+ return "success";
13852
+ }
13853
+ return "running";
13854
+ },
13855
+ reset() {
13856
+ elapsed = 0;
13857
+ }
13858
+ };
13859
+ }
13860
+ function btSequence(...children) {
13861
+ let idx = 0;
13862
+ return {
13863
+ tick(dt) {
13864
+ while (idx < children.length) {
13865
+ const s2 = children[idx].tick(dt);
13866
+ if (s2 === "running") return "running";
13867
+ if (s2 === "failure") {
13868
+ idx = 0;
13869
+ return "failure";
13870
+ }
13871
+ idx++;
13872
+ }
13873
+ idx = 0;
13874
+ return "success";
13875
+ },
13876
+ reset() {
13877
+ idx = 0;
13878
+ children.forEach((c) => c.reset());
13879
+ }
13880
+ };
13881
+ }
13882
+ function btSelector(...children) {
13883
+ let idx = 0;
13884
+ return {
13885
+ tick(dt) {
13886
+ while (idx < children.length) {
13887
+ const s2 = children[idx].tick(dt);
13888
+ if (s2 === "running") return "running";
13889
+ if (s2 === "success") {
13890
+ idx = 0;
13891
+ return "success";
13892
+ }
13893
+ idx++;
13894
+ }
13895
+ idx = 0;
13896
+ return "failure";
13897
+ },
13898
+ reset() {
13899
+ idx = 0;
13900
+ children.forEach((c) => c.reset());
13901
+ }
13902
+ };
13903
+ }
13904
+ function btParallel(successPolicy, failPolicy, ...children) {
13905
+ return {
13906
+ tick(dt) {
13907
+ let successCount = 0;
13908
+ let failCount = 0;
13909
+ for (const child of children) {
13910
+ const s2 = child.tick(dt);
13911
+ if (s2 === "success") successCount++;
13912
+ else if (s2 === "failure") failCount++;
13913
+ }
13914
+ if (successPolicy === "any" && successCount > 0) {
13915
+ children.forEach((c) => c.reset());
13916
+ return "success";
13917
+ }
13918
+ if (failPolicy === "any" && failCount > 0) {
13919
+ children.forEach((c) => c.reset());
13920
+ return "failure";
13921
+ }
13922
+ if (successPolicy === "all" && successCount === children.length) return "success";
13923
+ if (failPolicy === "all" && failCount === children.length) return "failure";
13924
+ return "running";
13925
+ },
13926
+ reset() {
13927
+ children.forEach((c) => c.reset());
13928
+ }
13929
+ };
13930
+ }
13931
+ function btInvert(child) {
13932
+ return {
13933
+ tick(dt) {
13934
+ const s2 = child.tick(dt);
13935
+ if (s2 === "success") return "failure";
13936
+ if (s2 === "failure") return "success";
13937
+ return "running";
13938
+ },
13939
+ reset() {
13940
+ child.reset();
13941
+ }
13942
+ };
13943
+ }
13944
+ function btRepeat(count, child) {
13945
+ let done = 0;
13946
+ return {
13947
+ tick(dt) {
13948
+ while (count === "forever" || done < count) {
13949
+ const s2 = child.tick(dt);
13950
+ if (s2 === "running") return "running";
13951
+ if (s2 === "failure") {
13952
+ done = 0;
13953
+ child.reset();
13954
+ return "failure";
13955
+ }
13956
+ done++;
13957
+ child.reset();
13958
+ }
13959
+ done = 0;
13960
+ return "success";
13961
+ },
13962
+ reset() {
13963
+ done = 0;
13964
+ child.reset();
13965
+ }
13966
+ };
13967
+ }
13968
+ function btRetryUntilSuccess(maxAttempts, child) {
13969
+ let attempts = 0;
13970
+ return {
13971
+ tick(dt) {
13972
+ while (attempts < maxAttempts) {
13973
+ const s2 = child.tick(dt);
13974
+ if (s2 === "running") return "running";
13975
+ if (s2 === "success") {
13976
+ attempts = 0;
13977
+ return "success";
13978
+ }
13979
+ attempts++;
13980
+ child.reset();
13981
+ }
13982
+ attempts = 0;
13983
+ return "failure";
13984
+ },
13985
+ reset() {
13986
+ attempts = 0;
13987
+ child.reset();
13988
+ }
13989
+ };
13990
+ }
13991
+ function btCooldown(duration, child) {
13992
+ let remaining = 0;
13993
+ return {
13994
+ tick(dt) {
13995
+ if (remaining > 0) {
13996
+ remaining = Math.max(0, remaining - dt);
13997
+ return "failure";
13998
+ }
13999
+ const s2 = child.tick(dt);
14000
+ if (s2 !== "running") {
14001
+ remaining = duration;
14002
+ child.reset();
14003
+ }
14004
+ return s2;
14005
+ },
14006
+ reset() {
14007
+ remaining = 0;
14008
+ child.reset();
14009
+ }
14010
+ };
14011
+ }
14012
+ function btSucceed(child) {
14013
+ return {
14014
+ tick(dt) {
14015
+ const s2 = child.tick(dt);
14016
+ return s2 === "running" ? "running" : "success";
14017
+ },
14018
+ reset() {
14019
+ child.reset();
14020
+ }
14021
+ };
14022
+ }
14023
+ function btFail(child) {
14024
+ return {
14025
+ tick(dt) {
14026
+ const s2 = child.tick(dt);
14027
+ return s2 === "running" ? "running" : "failure";
14028
+ },
14029
+ reset() {
14030
+ child.reset();
14031
+ }
14032
+ };
14033
+ }
14034
+ function useBehaviorTree(rootFactory) {
14035
+ const rootRef = useRef47(null);
14036
+ if (!rootRef.current) rootRef.current = rootFactory();
14037
+ const statusRef = useRef47("failure");
14038
+ const tick2 = useCallback33((dt) => {
14039
+ if (!rootRef.current) return "failure";
14040
+ const s2 = rootRef.current.tick(dt);
14041
+ statusRef.current = s2;
14042
+ return s2;
14043
+ }, []);
14044
+ const reset = useCallback33(() => {
14045
+ rootRef.current?.reset();
14046
+ }, []);
14047
+ return {
14048
+ tick: tick2,
14049
+ reset,
14050
+ get lastStatus() {
14051
+ return statusRef.current;
14052
+ }
14053
+ };
14054
+ }
14055
+
13545
14056
  // ../gameplay/src/components/DialogueBox.tsx
13546
14057
  import { jsx as jsx21, jsxs as jsxs10 } from "react/jsx-runtime";
13547
14058
  function DialogueBox({ dialogue, onAdvance, onClose, style = {} }) {
@@ -13651,17 +14162,17 @@ function DialogueBox({ dialogue, onAdvance, onClose, style = {} }) {
13651
14162
  }
13652
14163
 
13653
14164
  // ../gameplay/src/hooks/useCutscene.ts
13654
- import { useState as useState30, useCallback as useCallback31, useRef as useRef45, useEffect as useEffect79, useContext as useContext77 } from "react";
14165
+ import { useState as useState31, useCallback as useCallback34, useRef as useRef48, useEffect as useEffect80, useContext as useContext77 } from "react";
13655
14166
  function useCutscene() {
13656
14167
  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(() => {
14168
+ const [playing, setPlaying] = useState31(false);
14169
+ const [stepIndex, setStepIndex] = useState31(0);
14170
+ const stepsRef = useRef48([]);
14171
+ const timerRef = useRef48(0);
14172
+ const idxRef = useRef48(0);
14173
+ const playingRef = useRef48(false);
14174
+ const entityRef = useRef48(null);
14175
+ const finish = useCallback34(() => {
13665
14176
  playingRef.current = false;
13666
14177
  setPlaying(false);
13667
14178
  setStepIndex(0);
@@ -13671,14 +14182,14 @@ function useCutscene() {
13671
14182
  entityRef.current = null;
13672
14183
  }
13673
14184
  }, [engine.ecs]);
13674
- const fireStep = useCallback31((step) => {
14185
+ const fireStep = useCallback34((step) => {
13675
14186
  if (step.type === "call") step.fn();
13676
14187
  if (step.type === "parallel")
13677
14188
  step.steps.forEach((s2) => {
13678
14189
  if (s2.type === "call") s2.fn();
13679
14190
  });
13680
14191
  }, []);
13681
- const play = useCallback31(
14192
+ const play = useCallback34(
13682
14193
  (steps) => {
13683
14194
  stepsRef.current = steps;
13684
14195
  idxRef.current = 0;
@@ -13735,7 +14246,7 @@ function useCutscene() {
13735
14246
  },
13736
14247
  [engine.ecs, finish, fireStep]
13737
14248
  );
13738
- const skip = useCallback31(() => {
14249
+ const skip = useCallback34(() => {
13739
14250
  for (let i = idxRef.current; i < stepsRef.current.length; i++) {
13740
14251
  const step = stepsRef.current[i];
13741
14252
  if (step.type === "call") step.fn();
@@ -13746,7 +14257,7 @@ function useCutscene() {
13746
14257
  }
13747
14258
  finish();
13748
14259
  }, [finish]);
13749
- useEffect79(() => {
14260
+ useEffect80(() => {
13750
14261
  return () => {
13751
14262
  if (entityRef.current !== null && engine.ecs.hasEntity(entityRef.current)) {
13752
14263
  engine.ecs.destroyEntity(entityRef.current);
@@ -13757,7 +14268,7 @@ function useCutscene() {
13757
14268
  }
13758
14269
 
13759
14270
  // ../gameplay/src/hooks/useGameStore.ts
13760
- import { useSyncExternalStore as useSyncExternalStore2, useCallback as useCallback32 } from "react";
14271
+ import { useSyncExternalStore as useSyncExternalStore2, useCallback as useCallback35 } from "react";
13761
14272
  function createStore(initialState) {
13762
14273
  let state = { ...initialState };
13763
14274
  const listeners = /* @__PURE__ */ new Set();
@@ -13783,7 +14294,7 @@ function useGameStore(key, initialState) {
13783
14294
  }
13784
14295
  const store = stores.get(key);
13785
14296
  const state = useSyncExternalStore2(store.subscribe, store.getState);
13786
- const setState = useCallback32(
14297
+ const setState = useCallback35(
13787
14298
  (partial) => {
13788
14299
  store.setState(partial);
13789
14300
  },
@@ -13793,21 +14304,21 @@ function useGameStore(key, initialState) {
13793
14304
  }
13794
14305
 
13795
14306
  // ../gameplay/src/hooks/useTween.ts
13796
- import { useRef as useRef46, useCallback as useCallback33, useEffect as useEffect80 } from "react";
14307
+ import { useRef as useRef49, useCallback as useCallback36, useEffect as useEffect81 } from "react";
13797
14308
  function useTween(opts) {
13798
- const rafRef = useRef46(null);
13799
- const startTimeRef = useRef46(0);
13800
- const runningRef = useRef46(false);
13801
- const optsRef = useRef46(opts);
14309
+ const rafRef = useRef49(null);
14310
+ const startTimeRef = useRef49(0);
14311
+ const runningRef = useRef49(false);
14312
+ const optsRef = useRef49(opts);
13802
14313
  optsRef.current = opts;
13803
- const stop = useCallback33(() => {
14314
+ const stop = useCallback36(() => {
13804
14315
  if (rafRef.current !== null) {
13805
14316
  cancelAnimationFrame(rafRef.current);
13806
14317
  rafRef.current = null;
13807
14318
  }
13808
14319
  runningRef.current = false;
13809
14320
  }, []);
13810
- const start2 = useCallback33(() => {
14321
+ const start2 = useCallback36(() => {
13811
14322
  stop();
13812
14323
  runningRef.current = true;
13813
14324
  startTimeRef.current = performance.now();
@@ -13829,12 +14340,12 @@ function useTween(opts) {
13829
14340
  };
13830
14341
  rafRef.current = requestAnimationFrame(tick2);
13831
14342
  }, [stop]);
13832
- useEffect80(() => {
14343
+ useEffect81(() => {
13833
14344
  if (opts.autoStart) {
13834
14345
  start2();
13835
14346
  }
13836
14347
  }, []);
13837
- useEffect80(() => {
14348
+ useEffect81(() => {
13838
14349
  return () => {
13839
14350
  if (rafRef.current !== null) {
13840
14351
  cancelAnimationFrame(rafRef.current);
@@ -13853,15 +14364,15 @@ function useTween(opts) {
13853
14364
  }
13854
14365
 
13855
14366
  // ../gameplay/src/hooks/useObjectPool.ts
13856
- import { useRef as useRef47, useMemo as useMemo17, useEffect as useEffect81 } from "react";
14367
+ import { useRef as useRef50, useMemo as useMemo17, useEffect as useEffect82 } from "react";
13857
14368
  function useObjectPool(factory, reset, initialSize) {
13858
- const poolRef = useRef47([]);
13859
- const activeRef = useRef47(0);
13860
- const factoryRef = useRef47(factory);
14369
+ const poolRef = useRef50([]);
14370
+ const activeRef = useRef50(0);
14371
+ const factoryRef = useRef50(factory);
13861
14372
  factoryRef.current = factory;
13862
- const resetRef = useRef47(reset);
14373
+ const resetRef = useRef50(reset);
13863
14374
  resetRef.current = reset;
13864
- useEffect81(() => {
14375
+ useEffect82(() => {
13865
14376
  if (initialSize != null && initialSize > 0) {
13866
14377
  const pool = poolRef.current;
13867
14378
  for (let i = 0; i < initialSize; i++) {
@@ -14183,7 +14694,7 @@ function definePrefab(name, defaults, render) {
14183
14694
  }
14184
14695
 
14185
14696
  // src/hooks/useNetworkSync.ts
14186
- import { useEffect as useEffect83, useRef as useRef49 } from "react";
14697
+ import { useEffect as useEffect84, useRef as useRef52 } from "react";
14187
14698
 
14188
14699
  // ../../packages/net/src/transport.ts
14189
14700
  function isBinaryTransport(t) {
@@ -14528,17 +15039,17 @@ function syncEntity(config) {
14528
15039
  }
14529
15040
 
14530
15041
  // ../../packages/net/src/useNetworkInput.ts
14531
- import { useState as useState31, useEffect as useEffect82, useRef as useRef48 } from "react";
15042
+ import { useState as useState32, useEffect as useEffect83, useRef as useRef51 } from "react";
14532
15043
  var INPUT_MSG_TYPE = "input:state";
14533
15044
  function useNetworkInput(config) {
14534
15045
  const { room, keys, input, tickRate = 20 } = config;
14535
15046
  const intervalMs = 1e3 / tickRate;
14536
- const [localInput, setLocalInput] = useState31(
15047
+ const [localInput, setLocalInput] = useState32(
14537
15048
  () => Object.fromEntries(keys.map((k) => [k, false]))
14538
15049
  );
14539
- const [remoteInputs] = useState31(() => /* @__PURE__ */ new Map());
14540
- const localInputRef = useRef48(localInput);
14541
- useEffect82(() => {
15050
+ const [remoteInputs] = useState32(() => /* @__PURE__ */ new Map());
15051
+ const localInputRef = useRef51(localInput);
15052
+ useEffect83(() => {
14542
15053
  let cleanupDom = null;
14543
15054
  if (!input) {
14544
15055
  let handleKeyDown2 = function(e) {
@@ -14752,9 +15263,9 @@ function lerpState(a, b, t) {
14752
15263
 
14753
15264
  // src/hooks/useNetworkSync.ts
14754
15265
  function useNetworkSync(entityId, components, room, world, owner, opts = {}) {
14755
- const optsRef = useRef49(opts);
15266
+ const optsRef = useRef52(opts);
14756
15267
  optsRef.current = opts;
14757
- useEffect83(() => {
15268
+ useEffect84(() => {
14758
15269
  const sync = syncEntity({
14759
15270
  entityId,
14760
15271
  components,
@@ -14769,18 +15280,18 @@ function useNetworkSync(entityId, components, room, world, owner, opts = {}) {
14769
15280
  }
14770
15281
 
14771
15282
  // src/hooks/useRemotePlayer.ts
14772
- import { useEffect as useEffect84, useRef as useRef50, useState as useState32 } from "react";
15283
+ import { useEffect as useEffect85, useRef as useRef53, useState as useState33 } from "react";
14773
15284
  var PEER_JOIN_MSG = "peer:join";
14774
15285
  var PEER_LEAVE_MSG = "peer:leave";
14775
15286
  function useRemotePlayer(config) {
14776
15287
  const { room, world, createEntity, destroyEntity } = config;
14777
- const [players, setPlayers] = useState32(() => /* @__PURE__ */ new Map());
14778
- const playersRef = useRef50(players);
14779
- const createRef = useRef50(createEntity);
15288
+ const [players, setPlayers] = useState33(() => /* @__PURE__ */ new Map());
15289
+ const playersRef = useRef53(players);
15290
+ const createRef = useRef53(createEntity);
14780
15291
  createRef.current = createEntity;
14781
- const destroyRef = useRef50(destroyEntity);
15292
+ const destroyRef = useRef53(destroyEntity);
14782
15293
  destroyRef.current = destroyEntity;
14783
- useEffect84(() => {
15294
+ useEffect85(() => {
14784
15295
  function spawnPeer(peerId) {
14785
15296
  if (playersRef.current.has(peerId)) return;
14786
15297
  const entityId = createRef.current(peerId);
@@ -14905,6 +15416,18 @@ export {
14905
15416
  applyTorqueImpulse,
14906
15417
  arrive,
14907
15418
  boxArea,
15419
+ btAction,
15420
+ btCondition,
15421
+ btCooldown,
15422
+ btFail,
15423
+ btInvert,
15424
+ btParallel,
15425
+ btRepeat,
15426
+ btRetryUntilSuccess,
15427
+ btSelector,
15428
+ btSequence,
15429
+ btSucceed,
15430
+ btWait,
14908
15431
  capsuleArea,
14909
15432
  chromaticAberrationEffect,
14910
15433
  circleArea,
@@ -15031,6 +15554,7 @@ export {
15031
15554
  useAudioAnalyser,
15032
15555
  useAudioListener,
15033
15556
  useAudioScheduler,
15557
+ useBehaviorTree,
15034
15558
  useCamera,
15035
15559
  useCameraBlend,
15036
15560
  useCameraLookahead,
@@ -15050,6 +15574,7 @@ export {
15050
15574
  useDamageZone,
15051
15575
  useDestroyEntity,
15052
15576
  useDialogue,
15577
+ useDialogueTree,
15053
15578
  useDraggable,
15054
15579
  useDropThrough,
15055
15580
  useDroppable,
@@ -15104,6 +15629,7 @@ export {
15104
15629
  useSnap,
15105
15630
  useSnapshot,
15106
15631
  useSound,
15632
+ useSoundscape,
15107
15633
  useSpatialSound,
15108
15634
  useSquashStretch,
15109
15635
  useStreamedMusic,