cubeforge 0.4.7 → 0.4.8

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
@@ -713,6 +713,47 @@ function findPath(grid, start, goal) {
713
713
  }
714
714
  return [];
715
715
  }
716
+ function smoothPath(grid, path) {
717
+ if (path.length <= 2) return path.slice();
718
+ const result = [path[0]];
719
+ let anchor = 0;
720
+ while (anchor < path.length - 1) {
721
+ let farthest = anchor + 1;
722
+ for (let probe = anchor + 2; probe < path.length; probe++) {
723
+ if (hasLineOfSight(grid, path[anchor], path[probe])) {
724
+ farthest = probe;
725
+ }
726
+ }
727
+ result.push(path[farthest]);
728
+ anchor = farthest;
729
+ }
730
+ return result;
731
+ }
732
+ function hasLineOfSight(grid, a, b) {
733
+ let c0 = Math.floor(a.x / grid.cellSize);
734
+ let r0 = Math.floor(a.y / grid.cellSize);
735
+ const c1 = Math.floor(b.x / grid.cellSize);
736
+ const r1 = Math.floor(b.y / grid.cellSize);
737
+ const dc = Math.abs(c1 - c0);
738
+ const dr = Math.abs(r1 - r0);
739
+ const sc = c0 < c1 ? 1 : -1;
740
+ const sr = r0 < r1 ? 1 : -1;
741
+ let err = dc - dr;
742
+ while (true) {
743
+ if (!isWalkable(grid, c0, r0)) return false;
744
+ if (c0 === c1 && r0 === r1) break;
745
+ const e2 = 2 * err;
746
+ if (e2 > -dr) {
747
+ err -= dr;
748
+ c0 += sc;
749
+ }
750
+ if (e2 < dc) {
751
+ err += dc;
752
+ r0 += sr;
753
+ }
754
+ }
755
+ return true;
756
+ }
716
757
  var MinHeap = class {
717
758
  constructor(compare) {
718
759
  this.compare = compare;
@@ -800,6 +841,60 @@ function wander(_pos, angle, speed, jitter) {
800
841
  newAngle
801
842
  };
802
843
  }
844
+ function pursuit(pos, targetPos, targetVel, speed, lookAhead = 0.5) {
845
+ const predicted = {
846
+ x: targetPos.x + targetVel.x * lookAhead,
847
+ y: targetPos.y + targetVel.y * lookAhead
848
+ };
849
+ return seek(pos, predicted, speed);
850
+ }
851
+ function evade(pos, threatPos, threatVel, speed, lookAhead = 0.5) {
852
+ const predicted = {
853
+ x: threatPos.x + threatVel.x * lookAhead,
854
+ y: threatPos.y + threatVel.y * lookAhead
855
+ };
856
+ return flee(pos, predicted, speed);
857
+ }
858
+ function separation(pos, neighbors, speed, radius) {
859
+ let sx = 0;
860
+ let sy = 0;
861
+ let count = 0;
862
+ for (const n of neighbors) {
863
+ const dx = pos.x - n.x;
864
+ const dy = pos.y - n.y;
865
+ const dist = Math.hypot(dx, dy);
866
+ if (dist > 0 && dist < radius) {
867
+ const weight = 1 - dist / radius;
868
+ sx += dx / dist * weight;
869
+ sy += dy / dist * weight;
870
+ count++;
871
+ }
872
+ }
873
+ if (count === 0) return { x: 0, y: 0 };
874
+ return normalize({ x: sx, y: sy }, speed);
875
+ }
876
+ function cohesion(pos, neighbors, speed) {
877
+ if (neighbors.length === 0) return { x: 0, y: 0 };
878
+ let cx = 0;
879
+ let cy = 0;
880
+ for (const n of neighbors) {
881
+ cx += n.x;
882
+ cy += n.y;
883
+ }
884
+ cx /= neighbors.length;
885
+ cy /= neighbors.length;
886
+ return seek(pos, { x: cx, y: cy }, speed);
887
+ }
888
+ function alignment(neighborVelocities, speed) {
889
+ if (neighborVelocities.length === 0) return { x: 0, y: 0 };
890
+ let ax = 0;
891
+ let ay = 0;
892
+ for (const v of neighborVelocities) {
893
+ ax += v.x;
894
+ ay += v.y;
895
+ }
896
+ return normalize({ x: ax, y: ay }, speed);
897
+ }
803
898
 
804
899
  // ../../packages/core/src/components/transform.ts
805
900
  function createTransform(x = 0, y = 0, rotation = 0, scaleX = 1, scaleY = 1) {
@@ -930,10 +1025,15 @@ var Ease = {
930
1025
  easeInBounce: (t) => 1 - Ease.easeOutBounce(1 - t),
931
1026
  easeInOutBounce: (t) => t < 0.5 ? (1 - Ease.easeOutBounce(1 - 2 * t)) / 2 : (1 + Ease.easeOutBounce(2 * t - 1)) / 2
932
1027
  };
933
- function tween(from, to, duration, ease = Ease.linear, onUpdate, onComplete) {
1028
+ function tween(from, to, duration, ease = Ease.linear, onUpdate, onComplete, opts) {
934
1029
  let elapsed = 0;
935
1030
  let stopped = false;
936
1031
  let complete = false;
1032
+ let delayRemaining = opts?.delay ?? 0;
1033
+ const maxRepeats = opts?.repeat ?? 0;
1034
+ const yoyo = opts?.yoyo ?? false;
1035
+ let repeatsDone = 0;
1036
+ let forward = true;
937
1037
  return {
938
1038
  get isComplete() {
939
1039
  return complete;
@@ -943,13 +1043,32 @@ function tween(from, to, duration, ease = Ease.linear, onUpdate, onComplete) {
943
1043
  },
944
1044
  update(dt) {
945
1045
  if (stopped || complete) return;
946
- elapsed = Math.min(elapsed + dt, duration);
947
- const t = duration > 0 ? elapsed / duration : 1;
948
- onUpdate(from + (to - from) * ease(t));
1046
+ if (delayRemaining > 0) {
1047
+ delayRemaining -= dt;
1048
+ if (delayRemaining > 0) return;
1049
+ dt = -delayRemaining;
1050
+ delayRemaining = 0;
1051
+ }
1052
+ elapsed += dt;
949
1053
  if (elapsed >= duration) {
950
- complete = true;
951
- onComplete?.();
1054
+ const overshoot = elapsed - duration;
1055
+ const end2 = forward ? to : from;
1056
+ onUpdate(end2);
1057
+ if (repeatsDone < maxRepeats) {
1058
+ repeatsDone++;
1059
+ if (yoyo) forward = !forward;
1060
+ elapsed = Math.min(overshoot, duration);
1061
+ } else {
1062
+ complete = true;
1063
+ onComplete?.();
1064
+ return;
1065
+ }
952
1066
  }
1067
+ const t = duration > 0 ? elapsed / duration : 1;
1068
+ const easedT = ease(t);
1069
+ const start = forward ? from : to;
1070
+ const end = forward ? to : from;
1071
+ onUpdate(start + (end - start) * easedT);
953
1072
  }
954
1073
  };
955
1074
  }
@@ -2225,7 +2344,14 @@ function createWhiteTexture(gl) {
2225
2344
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
2226
2345
  return tex;
2227
2346
  }
2228
- var SHAPE_TEX_SIZE = 128;
2347
+ function shapeTexSize(spriteW, spriteH) {
2348
+ const maxDim = Math.max(spriteW, spriteH);
2349
+ if (maxDim <= 32) return 32;
2350
+ if (maxDim <= 64) return 64;
2351
+ if (maxDim <= 128) return 128;
2352
+ if (maxDim <= 256) return 256;
2353
+ return 512;
2354
+ }
2229
2355
  function drawShapeOnCanvas(ctx, shape, w, h, borderRadius, starPoints, starInnerRadius) {
2230
2356
  const cx = w / 2;
2231
2357
  const cy = h / 2;
@@ -2305,7 +2431,8 @@ function getShapeKey(sprite) {
2305
2431
  const sp = shape === "star" ? sprite.starPoints ?? 5 : 0;
2306
2432
  const sir = shape === "star" ? sprite.starInnerRadius ?? 0.4 : 0;
2307
2433
  const stroke = sprite.strokeColor && (sprite.strokeWidth ?? 0) > 0 ? `|s:${sprite.strokeColor}:${sprite.strokeWidth}` : "";
2308
- return `__shape__:${shape}:${br}:${sp}:${sir}${stroke}`;
2434
+ const res = shapeTexSize(sprite.width, sprite.height);
2435
+ return `__shape__:${shape}:${br}:${sp}:${sir}${stroke}:r${res}`;
2309
2436
  }
2310
2437
  function getSamplingKey(sampling) {
2311
2438
  if (!sampling) return "";
@@ -2633,7 +2760,7 @@ var RenderSystem = class {
2633
2760
  const key = getShapeKey(sprite);
2634
2761
  const cached = this.shapeTextures.get(key);
2635
2762
  if (cached) return cached;
2636
- const size = SHAPE_TEX_SIZE;
2763
+ const size = shapeTexSize(sprite.width, sprite.height);
2637
2764
  const offscreen = document.createElement("canvas");
2638
2765
  offscreen.width = size;
2639
2766
  offscreen.height = size;
@@ -2876,12 +3003,21 @@ var RenderSystem = class {
2876
3003
  }
2877
3004
  sprite.frameIndex = anim.frames[anim.currentIndex];
2878
3005
  }
2879
- for (const id of world.query("SquashStretch", "RigidBody")) {
3006
+ for (const id of world.query("SquashStretch")) {
2880
3007
  const ss = world.getComponent(id, "SquashStretch");
2881
- const rb = world.getComponent(id, "RigidBody");
2882
- const spd = Math.sqrt(rb.vx * rb.vx + rb.vy * rb.vy);
2883
- const tScX = rb.vy < -100 ? 1 + ss.intensity * 0.4 : spd > 50 ? 1 - ss.intensity * 0.3 : 1;
2884
- const tScY = rb.vy < -100 ? 1 - ss.intensity * 0.4 : spd > 50 ? 1 + ss.intensity * 0.3 : 1;
3008
+ let tScX;
3009
+ let tScY;
3010
+ if (ss._manualTargetX !== void 0 && ss._manualTargetY !== void 0) {
3011
+ tScX = ss._manualTargetX;
3012
+ tScY = ss._manualTargetY;
3013
+ ss._manualTargetX = void 0;
3014
+ ss._manualTargetY = void 0;
3015
+ } else {
3016
+ const rb = world.getComponent(id, "RigidBody");
3017
+ const spd = rb ? Math.sqrt(rb.vx * rb.vx + rb.vy * rb.vy) : 0;
3018
+ tScX = rb && rb.vy < -100 ? 1 + ss.intensity * 0.4 : spd > 50 ? 1 - ss.intensity * 0.3 : 1;
3019
+ tScY = rb && rb.vy < -100 ? 1 - ss.intensity * 0.4 : spd > 50 ? 1 + ss.intensity * 0.3 : 1;
3020
+ }
2885
3021
  ss.currentScaleX += (tScX - ss.currentScaleX) * ss.recovery * dt;
2886
3022
  ss.currentScaleY += (tScY - ss.currentScaleY) * ss.recovery * dt;
2887
3023
  }
@@ -3013,7 +3149,16 @@ var RenderSystem = class {
3013
3149
  const scaleXMod = ss ? ss.currentScaleX : 1;
3014
3150
  const scaleYMod = ss ? ss.currentScaleY : 1;
3015
3151
  const hasTexture = sprite.image && sprite.image.complete && sprite.image.naturalWidth > 0;
3016
- const [r, g, b, a] = hasTexture ? [1, 1, 1, 1] : parseCSSColor(sprite.color);
3152
+ const opacity = sprite.opacity ?? 1;
3153
+ let [r, g, b, a] = hasTexture ? [1, 1, 1, 1] : parseCSSColor(sprite.color);
3154
+ a *= opacity;
3155
+ if (sprite.tint && (sprite.tintOpacity ?? 0) > 0) {
3156
+ const [tr, tg, tb] = parseCSSColor(sprite.tint);
3157
+ const t = sprite.tintOpacity ?? 0.3;
3158
+ r = r * (1 - t) + tr * t;
3159
+ g = g * (1 - t) + tg * t;
3160
+ b = b * (1 - t) + tb * t;
3161
+ }
3017
3162
  const uv = getUVRect(sprite);
3018
3163
  this.writeInstance(
3019
3164
  batchCount * FLOATS_PER_INSTANCE,
@@ -3093,6 +3238,7 @@ var RenderSystem = class {
3093
3238
  p.x += p.vx * dt;
3094
3239
  p.y += p.vy * dt;
3095
3240
  p.vy += p.gravity * dt;
3241
+ if (p.rotationSpeed !== void 0) p.rotation = (p.rotation ?? 0) + p.rotationSpeed * dt;
3096
3242
  return p.life > 0;
3097
3243
  });
3098
3244
  if (pool.active && pool.particles.length < pool.maxParticles) {
@@ -3120,6 +3266,13 @@ var RenderSystem = class {
3120
3266
  ox = (world.rng() - 0.5) * (pool.emitWidth ?? 0);
3121
3267
  oy = (world.rng() - 0.5) * (pool.emitHeight ?? 0);
3122
3268
  }
3269
+ const startSize = pool.sizeOverLife?.start ?? pool.particleSize;
3270
+ const endSize = pool.sizeOverLife?.end ?? pool.particleSize;
3271
+ let rotSpeed;
3272
+ if (pool.enableRotation && pool.rotationSpeedRange) {
3273
+ const [mn, mx] = pool.rotationSpeedRange;
3274
+ rotSpeed = mn + world.rng() * (mx - mn);
3275
+ }
3123
3276
  pool.particles.push({
3124
3277
  x: t.x + ox,
3125
3278
  y: t.y + oy,
@@ -3127,9 +3280,13 @@ var RenderSystem = class {
3127
3280
  vy: Math.sin(angle) * speed,
3128
3281
  life: pool.particleLife,
3129
3282
  maxLife: pool.particleLife,
3130
- size: pool.particleSize,
3283
+ size: startSize,
3284
+ startSize,
3285
+ endSize,
3131
3286
  color: pool.color,
3132
- gravity: pool.gravity
3287
+ gravity: pool.gravity,
3288
+ rotation: pool.enableRotation ? world.rng() * Math.PI * 2 : 0,
3289
+ rotationSpeed: rotSpeed
3133
3290
  });
3134
3291
  }
3135
3292
  }
@@ -3140,15 +3297,33 @@ var RenderSystem = class {
3140
3297
  this.flush(pCount, pKey);
3141
3298
  pCount = 0;
3142
3299
  }
3143
- const alpha = p.life / p.maxLife;
3144
- const [r, g, b] = parseCSSColor(p.color);
3300
+ const lifeFrac = p.life / p.maxLife;
3301
+ const alpha = lifeFrac;
3302
+ const sz = p.startSize !== void 0 && p.endSize !== void 0 ? p.endSize + (p.startSize - p.endSize) * lifeFrac : p.size;
3303
+ let r, g, b;
3304
+ if (pool.colorOverLife && pool.colorOverLife.length >= 2) {
3305
+ const palette = pool.colorOverLife;
3306
+ const frac = 1 - lifeFrac;
3307
+ const scaled = frac * (palette.length - 1);
3308
+ const lo = Math.floor(scaled);
3309
+ const hi = Math.min(lo + 1, palette.length - 1);
3310
+ const lf = scaled - lo;
3311
+ const [r0, g0, b0] = parseCSSColor(palette[lo]);
3312
+ const [r1, g1, b1] = parseCSSColor(palette[hi]);
3313
+ r = r0 + (r1 - r0) * lf;
3314
+ g = g0 + (g1 - g0) * lf;
3315
+ b = b0 + (b1 - b0) * lf;
3316
+ } else {
3317
+ ;
3318
+ [r, g, b] = parseCSSColor(p.color);
3319
+ }
3145
3320
  this.writeInstance(
3146
3321
  pCount * FLOATS_PER_INSTANCE,
3147
3322
  p.x,
3148
3323
  p.y,
3149
- p.size,
3150
- p.size,
3151
- 0,
3324
+ sz,
3325
+ sz,
3326
+ p.rotation ?? 0,
3152
3327
  0.5,
3153
3328
  0.5,
3154
3329
  0,
@@ -3174,21 +3349,38 @@ var RenderSystem = class {
3174
3349
  trail.points.unshift({ x: t.x, y: t.y });
3175
3350
  if (trail.points.length > trail.length) trail.points.length = trail.length;
3176
3351
  if (trail.points.length < 1) continue;
3177
- const [tr, tg, tb] = parseCSSColor(trail.color);
3178
- const trailW = trail.width > 0 ? trail.width : 1;
3352
+ const baseColor = parseCSSColor(trail.color);
3179
3353
  let tCount = 0;
3180
3354
  for (let i = 0; i < trail.points.length; i++) {
3181
3355
  if (tCount >= MAX_INSTANCES) {
3182
3356
  this.flush(tCount, "__color__");
3183
3357
  tCount = 0;
3184
3358
  }
3185
- const alpha = 1 - i / trail.points.length;
3359
+ const frac = trail.points.length > 1 ? i / (trail.points.length - 1) : 0;
3360
+ let tr, tg, tb;
3361
+ if (trail.colorOverLife && trail.colorOverLife.length >= 2) {
3362
+ const palette = trail.colorOverLife;
3363
+ const scaled = frac * (palette.length - 1);
3364
+ const lo = Math.floor(scaled);
3365
+ const hi = Math.min(lo + 1, palette.length - 1);
3366
+ const lf = scaled - lo;
3367
+ const [r0, g0, b0] = parseCSSColor(palette[lo]);
3368
+ const [r1, g1, b1] = parseCSSColor(palette[hi]);
3369
+ tr = r0 + (r1 - r0) * lf;
3370
+ tg = g0 + (g1 - g0) * lf;
3371
+ tb = b0 + (b1 - b0) * lf;
3372
+ } else {
3373
+ ;
3374
+ [tr, tg, tb] = baseColor;
3375
+ }
3376
+ const segW = trail.widthOverLife ? trail.widthOverLife.start + (trail.widthOverLife.end - trail.widthOverLife.start) * frac : trail.width > 0 ? trail.width : 1;
3377
+ const alpha = 1 - frac;
3186
3378
  this.writeInstance(
3187
3379
  tCount * FLOATS_PER_INSTANCE,
3188
3380
  trail.points[i].x,
3189
3381
  trail.points[i].y,
3190
- trailW,
3191
- trailW,
3382
+ segW,
3383
+ segW,
3192
3384
  0,
3193
3385
  0.5,
3194
3386
  0.5,
@@ -4395,9 +4587,9 @@ function generatePolygonPolygonManifoldFromPolys(polyA, polyB) {
4395
4587
  bCy /= polyB.vertices.length;
4396
4588
  const contacts = [];
4397
4589
  for (const cp of clipPoints) {
4398
- const separation = dot(refNx, refNy, cp.x, cp.y) - refFaceOffset;
4399
- if (separation > 0) continue;
4400
- const penetration = -separation;
4590
+ const separation2 = dot(refNx, refNy, cp.x, cp.y) - refFaceOffset;
4591
+ if (separation2 > 0) continue;
4592
+ const penetration = -separation2;
4401
4593
  let worldAx, worldAy, worldBx, worldBy;
4402
4594
  if (!flip) {
4403
4595
  worldBx = cp.x;
@@ -5371,8 +5563,8 @@ function solvePositions(constraints, iterations, beta, slop) {
5371
5563
  const rAy = pd.point.worldAy - bodyA.y;
5372
5564
  const rBx = pd.point.worldBx - bodyB.x;
5373
5565
  const rBy = pd.point.worldBy - bodyB.y;
5374
- const separation = (bodyB.x + rBx - (bodyA.x + rAx)) * manifold.normalX + (bodyB.y + rBy - (bodyA.y + rAy)) * manifold.normalY - pd.point.penetration;
5375
- const posError = Math.max(0, -separation - slop);
5566
+ const separation2 = (bodyB.x + rBx - (bodyA.x + rAx)) * manifold.normalX + (bodyB.y + rBy - (bodyA.y + rAy)) * manifold.normalY - pd.point.penetration;
5567
+ const posError = Math.max(0, -separation2 - slop);
5376
5568
  if (posError <= 0) continue;
5377
5569
  const rAxN = cross(rAx, rAy, manifold.normalX, manifold.normalY);
5378
5570
  const rBxN = cross(rBx, rBy, manifold.normalX, manifold.normalY);
@@ -14940,6 +15132,18 @@ function useCamera() {
14940
15132
  if (camId === void 0) return;
14941
15133
  const cam = engine.ecs.getComponent(camId, "Camera2D");
14942
15134
  if (cam) cam.zoom = zoom;
15135
+ },
15136
+ getPosition() {
15137
+ const camId = engine.ecs.queryOne("Camera2D");
15138
+ if (camId === void 0) return { x: 0, y: 0 };
15139
+ const cam = engine.ecs.getComponent(camId, "Camera2D");
15140
+ return cam ? { x: cam.x, y: cam.y } : { x: 0, y: 0 };
15141
+ },
15142
+ getZoom() {
15143
+ const camId = engine.ecs.queryOne("Camera2D");
15144
+ if (camId === void 0) return 1;
15145
+ const cam = engine.ecs.getComponent(camId, "Camera2D");
15146
+ return cam?.zoom ?? 1;
14943
15147
  }
14944
15148
  }),
14945
15149
  [engine]
@@ -15057,10 +15261,39 @@ function useCoordinates() {
15057
15261
  return { worldToScreen, screenToWorld };
15058
15262
  }
15059
15263
 
15264
+ // src/hooks/useWorldQuery.ts
15265
+ import { useEffect as useEffect42, useRef as useRef10, useState as useState7 } from "react";
15266
+ function useWorldQuery(...components) {
15267
+ const engine = useGame();
15268
+ const [result, setResult] = useState7(() => engine.ecs.query(...components));
15269
+ const prevRef = useRef10([]);
15270
+ const rafRef = useRef10(0);
15271
+ const mountedRef = useRef10(true);
15272
+ useEffect42(() => {
15273
+ mountedRef.current = true;
15274
+ const tick = () => {
15275
+ if (!mountedRef.current) return;
15276
+ const next = engine.ecs.query(...components);
15277
+ const prev = prevRef.current;
15278
+ if (next.length !== prev.length || next.some((id, i) => id !== prev[i])) {
15279
+ prevRef.current = next;
15280
+ setResult([...next]);
15281
+ }
15282
+ rafRef.current = requestAnimationFrame(tick);
15283
+ };
15284
+ rafRef.current = requestAnimationFrame(tick);
15285
+ return () => {
15286
+ mountedRef.current = false;
15287
+ cancelAnimationFrame(rafRef.current);
15288
+ };
15289
+ }, [engine, ...components]);
15290
+ return result;
15291
+ }
15292
+
15060
15293
  // src/hooks/useInputContext.ts
15061
- import { useEffect as useEffect42, useMemo as useMemo4 } from "react";
15294
+ import { useEffect as useEffect43, useMemo as useMemo4 } from "react";
15062
15295
  function useInputContext(ctx) {
15063
- useEffect42(() => {
15296
+ useEffect43(() => {
15064
15297
  if (!ctx) return;
15065
15298
  globalInputContext.push(ctx);
15066
15299
  return () => globalInputContext.pop(ctx);
@@ -15102,12 +15335,12 @@ function useInputRecorder() {
15102
15335
  }
15103
15336
 
15104
15337
  // src/hooks/useGamepad.ts
15105
- import { useEffect as useEffect43, useRef as useRef10, useState as useState7 } from "react";
15338
+ import { useEffect as useEffect44, useRef as useRef11, useState as useState8 } from "react";
15106
15339
  var EMPTY_STATE = { connected: false, axes: [], buttons: [] };
15107
15340
  function useGamepad(playerIndex = 0) {
15108
- const [state, setState] = useState7(EMPTY_STATE);
15109
- const rafRef = useRef10(0);
15110
- useEffect43(() => {
15341
+ const [state, setState] = useState8(EMPTY_STATE);
15342
+ const rafRef = useRef11(0);
15343
+ useEffect44(() => {
15111
15344
  const poll = () => {
15112
15345
  const gp = navigator.getGamepads()[playerIndex];
15113
15346
  if (gp) {
@@ -15128,10 +15361,10 @@ function useGamepad(playerIndex = 0) {
15128
15361
  }
15129
15362
 
15130
15363
  // src/hooks/usePause.ts
15131
- import { useContext as useContext44, useState as useState8, useCallback as useCallback4 } from "react";
15364
+ import { useContext as useContext44, useState as useState9, useCallback as useCallback4 } from "react";
15132
15365
  function usePause() {
15133
15366
  const engine = useContext44(EngineContext);
15134
- const [paused, setPaused] = useState8(false);
15367
+ const [paused, setPaused] = useState9(false);
15135
15368
  const pause = useCallback4(() => {
15136
15369
  engine.loop.pause();
15137
15370
  setPaused(true);
@@ -15148,7 +15381,7 @@ function usePause() {
15148
15381
  }
15149
15382
 
15150
15383
  // src/hooks/useProfiler.ts
15151
- import { useContext as useContext45, useEffect as useEffect44, useRef as useRef11, useState as useState9 } from "react";
15384
+ import { useContext as useContext45, useEffect as useEffect45, useRef as useRef12, useState as useState10 } from "react";
15152
15385
  var EMPTY = {
15153
15386
  fps: 0,
15154
15387
  frameTime: 0,
@@ -15157,11 +15390,11 @@ var EMPTY = {
15157
15390
  };
15158
15391
  function useProfiler() {
15159
15392
  const engine = useContext45(EngineContext);
15160
- const [data, setData] = useState9(EMPTY);
15161
- const frameTimesRef = useRef11([]);
15162
- const lastUpdateRef = useRef11(0);
15163
- const prevTimeRef = useRef11(0);
15164
- useEffect44(() => {
15393
+ const [data, setData] = useState10(EMPTY);
15394
+ const frameTimesRef = useRef12([]);
15395
+ const lastUpdateRef = useRef12(0);
15396
+ const prevTimeRef = useRef12(0);
15397
+ useEffect45(() => {
15165
15398
  if (!engine) return;
15166
15399
  let rafId;
15167
15400
  const frameTimes = frameTimesRef.current;
@@ -15201,10 +15434,10 @@ function useProfiler() {
15201
15434
  }
15202
15435
 
15203
15436
  // src/hooks/usePostProcess.ts
15204
- import { useEffect as useEffect45 } from "react";
15437
+ import { useEffect as useEffect46 } from "react";
15205
15438
  function usePostProcess(effect) {
15206
15439
  const engine = useGame();
15207
- useEffect45(() => {
15440
+ useEffect46(() => {
15208
15441
  engine.postProcessStack.add(effect);
15209
15442
  return () => {
15210
15443
  engine.postProcessStack.remove(effect);
@@ -15238,14 +15471,14 @@ function useTouch() {
15238
15471
  }
15239
15472
 
15240
15473
  // src/hooks/useTimer.ts
15241
- import { useRef as useRef12, useCallback as useCallback5, useEffect as useEffect46, useContext as useContext47 } from "react";
15474
+ import { useRef as useRef13, useCallback as useCallback5, useEffect as useEffect47, useContext as useContext47 } from "react";
15242
15475
  function useTimer(duration, onComplete, opts) {
15243
15476
  const engine = useContext47(EngineContext);
15244
- const onCompleteRef = useRef12(onComplete);
15477
+ const onCompleteRef = useRef13(onComplete);
15245
15478
  onCompleteRef.current = onComplete;
15246
- const loopRef = useRef12(opts?.loop ?? false);
15479
+ const loopRef = useRef13(opts?.loop ?? false);
15247
15480
  loopRef.current = opts?.loop ?? false;
15248
- const timerRef = useRef12(null);
15481
+ const timerRef = useRef13(null);
15249
15482
  if (!timerRef.current) {
15250
15483
  timerRef.current = createTimer(
15251
15484
  duration,
@@ -15258,7 +15491,7 @@ function useTimer(duration, onComplete, opts) {
15258
15491
  opts?.autoStart ?? false
15259
15492
  );
15260
15493
  }
15261
- useEffect46(() => {
15494
+ useEffect47(() => {
15262
15495
  const eid = engine.ecs.createEntity();
15263
15496
  engine.ecs.addComponent(
15264
15497
  eid,
@@ -15299,15 +15532,15 @@ function useTimer(duration, onComplete, opts) {
15299
15532
  }
15300
15533
 
15301
15534
  // src/hooks/useCoroutine.ts
15302
- import { useRef as useRef13, useEffect as useEffect47, useContext as useContext48 } from "react";
15535
+ import { useRef as useRef14, useEffect as useEffect48, useContext as useContext48 } from "react";
15303
15536
  var wait = (seconds) => ({ type: "wait", seconds });
15304
15537
  var waitFrames = (frames) => ({ type: "waitFrames", frames });
15305
15538
  var waitUntil = (condition) => ({ type: "waitUntil", condition });
15306
15539
  var nextCoroutineId = 1;
15307
15540
  function useCoroutine() {
15308
15541
  const engine = useContext48(EngineContext);
15309
- const coroutinesRef = useRef13(/* @__PURE__ */ new Map());
15310
- useEffect47(() => {
15542
+ const coroutinesRef = useRef14(/* @__PURE__ */ new Map());
15543
+ useEffect48(() => {
15311
15544
  const eid = engine.ecs.createEntity();
15312
15545
  engine.ecs.addComponent(
15313
15546
  eid,
@@ -15372,15 +15605,15 @@ function useCoroutine() {
15372
15605
  return coroutinesRef.current.size;
15373
15606
  }
15374
15607
  };
15375
- const controlsRef = useRef13(controls);
15608
+ const controlsRef = useRef14(controls);
15376
15609
  return controlsRef.current;
15377
15610
  }
15378
15611
 
15379
15612
  // src/hooks/useSceneManager.ts
15380
- import { useState as useState10, useCallback as useCallback6, useRef as useRef14 } from "react";
15613
+ import { useState as useState11, useCallback as useCallback6, useRef as useRef15 } from "react";
15381
15614
  function useSceneManager(initialScene) {
15382
- const [stack, setStack] = useState10([initialScene]);
15383
- const stackRef = useRef14(stack);
15615
+ const [stack, setStack] = useState11([initialScene]);
15616
+ const stackRef = useRef15(stack);
15384
15617
  stackRef.current = stack;
15385
15618
  const push = useCallback6((scene) => {
15386
15619
  setStack((prev) => [...prev, scene]);
@@ -15422,9 +15655,9 @@ function useInputBuffer(opts) {
15422
15655
  }
15423
15656
 
15424
15657
  // src/hooks/useComboDetector.ts
15425
- import { useMemo as useMemo9, useRef as useRef15 } from "react";
15658
+ import { useMemo as useMemo9, useRef as useRef16 } from "react";
15426
15659
  function useComboDetector(combos) {
15427
- const lastComboRef = useRef15(null);
15660
+ const lastComboRef = useRef16(null);
15428
15661
  const result = useMemo9(() => {
15429
15662
  const detector = new ComboDetector({ combos });
15430
15663
  const api = {
@@ -15447,11 +15680,11 @@ function useComboDetector(combos) {
15447
15680
  }
15448
15681
 
15449
15682
  // src/hooks/useParent.ts
15450
- import { useEffect as useEffect48, useContext as useContext49 } from "react";
15683
+ import { useEffect as useEffect49, useContext as useContext49 } from "react";
15451
15684
  function useParent(childEntityId, parentEntityId) {
15452
15685
  const engine = useContext49(EngineContext);
15453
15686
  if (!engine) throw new Error("useParent must be used inside <Game>");
15454
- useEffect48(() => {
15687
+ useEffect49(() => {
15455
15688
  setParent(engine.ecs, childEntityId, parentEntityId);
15456
15689
  return () => {
15457
15690
  removeParent(engine.ecs, childEntityId);
@@ -15488,18 +15721,18 @@ function useAccessibility() {
15488
15721
  }
15489
15722
 
15490
15723
  // src/hooks/useHMR.ts
15491
- import { useEffect as useEffect49, useRef as useRef16, useMemo as useMemo10 } from "react";
15724
+ import { useEffect as useEffect50, useRef as useRef17, useMemo as useMemo10 } from "react";
15492
15725
  var idCounter = 0;
15493
15726
  function useHMR(hmrKey) {
15494
- const idRef = useRef16(null);
15727
+ const idRef = useRef17(null);
15495
15728
  if (idRef.current === null) {
15496
15729
  idRef.current = hmrKey ?? `__hmr_${idCounter++}`;
15497
15730
  }
15498
15731
  const key = idRef.current;
15499
15732
  const isHotReload = hmrLoadState(key) !== void 0;
15500
- const disposeRef = useRef16(null);
15501
- const acceptRef = useRef16(null);
15502
- useEffect49(() => {
15733
+ const disposeRef = useRef17(null);
15734
+ const acceptRef = useRef17(null);
15735
+ useEffect50(() => {
15503
15736
  const hot = import.meta.hot;
15504
15737
  if (!hot) return;
15505
15738
  hot.dispose(() => {
@@ -15531,11 +15764,28 @@ function useHMR(hmrKey) {
15531
15764
  );
15532
15765
  }
15533
15766
 
15767
+ // src/hooks/useSquashStretch.ts
15768
+ import { useCallback as useCallback8, useContext as useContext50 } from "react";
15769
+ function useSquashStretch() {
15770
+ const engine = useContext50(EngineContext);
15771
+ const entityId = useContext50(EntityContext);
15772
+ const trigger = useCallback8(
15773
+ (scaleX, scaleY) => {
15774
+ const ss = engine.ecs.getComponent(entityId, "SquashStretch");
15775
+ if (!ss) return;
15776
+ ss._manualTargetX = scaleX;
15777
+ ss._manualTargetY = scaleY;
15778
+ },
15779
+ [engine, entityId]
15780
+ );
15781
+ return { trigger };
15782
+ }
15783
+
15534
15784
  // ../gameplay/src/hooks/useAnimationController.ts
15535
- import { useState as useState11, useCallback as useCallback8 } from "react";
15785
+ import { useState as useState12, useCallback as useCallback9 } from "react";
15536
15786
  function useAnimationController(states, initial) {
15537
- const [stateName, setStateName] = useState11(initial);
15538
- const setState = useCallback8((next) => {
15787
+ const [stateName, setStateName] = useState12(initial);
15788
+ const setState = useCallback9((next) => {
15539
15789
  setStateName((prev) => prev === next ? prev : next);
15540
15790
  }, []);
15541
15791
  const clip = states[stateName] ?? states[initial];
@@ -15557,29 +15807,60 @@ function useAnimationController(states, initial) {
15557
15807
  }
15558
15808
 
15559
15809
  // ../gameplay/src/hooks/useAISteering.ts
15560
- import { useCallback as useCallback9 } from "react";
15810
+ import { useCallback as useCallback10 } from "react";
15561
15811
  function useAISteering() {
15562
- const seek$ = useCallback9((pos, target, speed) => seek(pos, target, speed), []);
15563
- const flee$ = useCallback9((pos, threat, speed) => flee(pos, threat, speed), []);
15564
- const arrive$ = useCallback9(
15812
+ const seek$ = useCallback10((pos, target, speed) => seek(pos, target, speed), []);
15813
+ const flee$ = useCallback10((pos, threat, speed) => flee(pos, threat, speed), []);
15814
+ const arrive$ = useCallback10(
15565
15815
  (pos, target, speed, slowRadius) => arrive(pos, target, speed, slowRadius),
15566
15816
  []
15567
15817
  );
15568
- const patrol$ = useCallback9(
15818
+ const patrol$ = useCallback10(
15569
15819
  (pos, waypoints, speed, currentIdx, arriveThreshold) => patrol(pos, waypoints, speed, currentIdx, arriveThreshold),
15570
15820
  []
15571
15821
  );
15572
- const wander$ = useCallback9(
15822
+ const wander$ = useCallback10(
15573
15823
  (pos, angle, speed, jitter) => wander(pos, angle, speed, jitter),
15574
15824
  []
15575
15825
  );
15576
- return { seek: seek$, flee: flee$, arrive: arrive$, patrol: patrol$, wander: wander$ };
15826
+ const pursuit$ = useCallback10(
15827
+ (pos, targetPos, targetVel, speed, lookAhead) => pursuit(pos, targetPos, targetVel, speed, lookAhead),
15828
+ []
15829
+ );
15830
+ const evade$ = useCallback10(
15831
+ (pos, threatPos, threatVel, speed, lookAhead) => evade(pos, threatPos, threatVel, speed, lookAhead),
15832
+ []
15833
+ );
15834
+ const separation$ = useCallback10(
15835
+ (pos, neighbors, speed, radius) => separation(pos, neighbors, speed, radius),
15836
+ []
15837
+ );
15838
+ const cohesion$ = useCallback10(
15839
+ (pos, neighbors, speed) => cohesion(pos, neighbors, speed),
15840
+ []
15841
+ );
15842
+ const alignment$ = useCallback10(
15843
+ (neighborVelocities, speed) => alignment(neighborVelocities, speed),
15844
+ []
15845
+ );
15846
+ return {
15847
+ seek: seek$,
15848
+ flee: flee$,
15849
+ arrive: arrive$,
15850
+ patrol: patrol$,
15851
+ wander: wander$,
15852
+ pursuit: pursuit$,
15853
+ evade: evade$,
15854
+ separation: separation$,
15855
+ cohesion: cohesion$,
15856
+ alignment: alignment$
15857
+ };
15577
15858
  }
15578
15859
 
15579
15860
  // ../gameplay/src/hooks/useDamageZone.ts
15580
- import { useContext as useContext50 } from "react";
15861
+ import { useContext as useContext51 } from "react";
15581
15862
  function useDamageZone(damage, opts = {}) {
15582
- const engine = useContext50(EngineContext);
15863
+ const engine = useContext51(EngineContext);
15583
15864
  useTriggerEnter(
15584
15865
  (other) => {
15585
15866
  engine.events.emit(`damage:${other}`, { amount: damage });
@@ -15589,11 +15870,11 @@ function useDamageZone(damage, opts = {}) {
15589
15870
  }
15590
15871
 
15591
15872
  // ../gameplay/src/hooks/useDropThrough.ts
15592
- import { useContext as useContext51, useCallback as useCallback10 } from "react";
15873
+ import { useContext as useContext52, useCallback as useCallback11 } from "react";
15593
15874
  function useDropThrough(frames = 8) {
15594
- const engine = useContext51(EngineContext);
15595
- const entityId = useContext51(EntityContext);
15596
- const dropThrough = useCallback10(() => {
15875
+ const engine = useContext52(EngineContext);
15876
+ const entityId = useContext52(EntityContext);
15877
+ const dropThrough = useCallback11(() => {
15597
15878
  const rb = engine.ecs.getComponent(entityId, "RigidBody");
15598
15879
  if (rb) rb.dropThrough = frames;
15599
15880
  }, [engine.ecs, entityId, frames]);
@@ -15601,17 +15882,17 @@ function useDropThrough(frames = 8) {
15601
15882
  }
15602
15883
 
15603
15884
  // ../gameplay/src/hooks/useGameStateMachine.ts
15604
- import { useState as useState12, useRef as useRef17, useCallback as useCallback11, useEffect as useEffect50, useContext as useContext52 } from "react";
15885
+ import { useState as useState13, useRef as useRef18, useCallback as useCallback12, useEffect as useEffect51, useContext as useContext53 } from "react";
15605
15886
  function useGameStateMachine(states, initial) {
15606
- const engine = useContext52(EngineContext);
15607
- const [state, setState] = useState12(initial);
15608
- const stateRef = useRef17(initial);
15609
- const statesRef = useRef17(states);
15887
+ const engine = useContext53(EngineContext);
15888
+ const [state, setState] = useState13(initial);
15889
+ const stateRef = useRef18(initial);
15890
+ const statesRef = useRef18(states);
15610
15891
  statesRef.current = states;
15611
- useEffect50(() => {
15892
+ useEffect51(() => {
15612
15893
  statesRef.current[initial]?.onEnter?.();
15613
15894
  }, []);
15614
- const transition = useCallback11((to) => {
15895
+ const transition = useCallback12((to) => {
15615
15896
  const current = stateRef.current;
15616
15897
  if (current === to) return;
15617
15898
  statesRef.current[current]?.onExit?.();
@@ -15619,7 +15900,7 @@ function useGameStateMachine(states, initial) {
15619
15900
  setState(to);
15620
15901
  statesRef.current[to]?.onEnter?.();
15621
15902
  }, []);
15622
- useEffect50(() => {
15903
+ useEffect51(() => {
15623
15904
  const eid = engine.ecs.createEntity();
15624
15905
  engine.ecs.addComponent(
15625
15906
  eid,
@@ -15635,27 +15916,27 @@ function useGameStateMachine(states, initial) {
15635
15916
  }
15636
15917
 
15637
15918
  // ../gameplay/src/hooks/useHealth.ts
15638
- import { useRef as useRef18, useEffect as useEffect51, useContext as useContext53, useCallback as useCallback12 } from "react";
15919
+ import { useRef as useRef19, useEffect as useEffect52, useContext as useContext54, useCallback as useCallback13 } from "react";
15639
15920
  function useHealth(maxHp, opts = {}) {
15640
- const engine = useContext53(EngineContext);
15641
- const entityId = useContext53(EntityContext);
15642
- const hpRef = useRef18(maxHp);
15643
- const invincibleRef = useRef18(false);
15921
+ const engine = useContext54(EngineContext);
15922
+ const entityId = useContext54(EntityContext);
15923
+ const hpRef = useRef19(maxHp);
15924
+ const invincibleRef = useRef19(false);
15644
15925
  const iFrameDuration = opts.iFrames ?? 1;
15645
- const onDeathRef = useRef18(opts.onDeath);
15646
- const onDamageRef = useRef18(opts.onDamage);
15647
- useEffect51(() => {
15926
+ const onDeathRef = useRef19(opts.onDeath);
15927
+ const onDamageRef = useRef19(opts.onDamage);
15928
+ useEffect52(() => {
15648
15929
  onDeathRef.current = opts.onDeath;
15649
15930
  });
15650
- useEffect51(() => {
15931
+ useEffect52(() => {
15651
15932
  onDamageRef.current = opts.onDamage;
15652
15933
  });
15653
- const timerRef = useRef18(
15934
+ const timerRef = useRef19(
15654
15935
  createTimer(iFrameDuration, () => {
15655
15936
  invincibleRef.current = false;
15656
15937
  })
15657
15938
  );
15658
- const takeDamage = useCallback12(
15939
+ const takeDamage = useCallback13(
15659
15940
  (amount = 1) => {
15660
15941
  if (invincibleRef.current || hpRef.current <= 0) return;
15661
15942
  hpRef.current = Math.max(0, hpRef.current - amount);
@@ -15668,28 +15949,28 @@ function useHealth(maxHp, opts = {}) {
15668
15949
  },
15669
15950
  [iFrameDuration]
15670
15951
  );
15671
- const takeDamageRef = useRef18(takeDamage);
15672
- useEffect51(() => {
15952
+ const takeDamageRef = useRef19(takeDamage);
15953
+ useEffect52(() => {
15673
15954
  takeDamageRef.current = takeDamage;
15674
15955
  }, [takeDamage]);
15675
- useEffect51(() => {
15956
+ useEffect52(() => {
15676
15957
  return engine.events.on(`damage:${entityId}`, ({ amount }) => {
15677
15958
  takeDamageRef.current(amount);
15678
15959
  });
15679
15960
  }, [engine.events, entityId]);
15680
- const heal = useCallback12(
15961
+ const heal = useCallback13(
15681
15962
  (amount) => {
15682
15963
  hpRef.current = Math.min(maxHp, hpRef.current + amount);
15683
15964
  },
15684
15965
  [maxHp]
15685
15966
  );
15686
- const setHp = useCallback12(
15967
+ const setHp = useCallback13(
15687
15968
  (hp) => {
15688
15969
  hpRef.current = Math.min(maxHp, Math.max(0, hp));
15689
15970
  },
15690
15971
  [maxHp]
15691
15972
  );
15692
- const update = useCallback12((dt) => {
15973
+ const update = useCallback13((dt) => {
15693
15974
  timerRef.current.update(dt);
15694
15975
  }, []);
15695
15976
  return {
@@ -15713,11 +15994,11 @@ function useHealth(maxHp, opts = {}) {
15713
15994
  }
15714
15995
 
15715
15996
  // ../gameplay/src/hooks/useKinematicBody.ts
15716
- import { useContext as useContext54, useCallback as useCallback13 } from "react";
15997
+ import { useContext as useContext55, useCallback as useCallback14 } from "react";
15717
15998
  function useKinematicBody() {
15718
- const engine = useContext54(EngineContext);
15719
- const entityId = useContext54(EntityContext);
15720
- const moveAndCollide = useCallback13(
15999
+ const engine = useContext55(EngineContext);
16000
+ const entityId = useContext55(EntityContext);
16001
+ const moveAndCollide = useCallback14(
15721
16002
  (dx, dy) => {
15722
16003
  const transform = engine.ecs.getComponent(entityId, "Transform");
15723
16004
  if (!transform) return { dx: 0, dy: 0 };
@@ -15753,7 +16034,7 @@ function useKinematicBody() {
15753
16034
  },
15754
16035
  [engine.ecs, entityId]
15755
16036
  );
15756
- const setVelocity = useCallback13(
16037
+ const setVelocity = useCallback14(
15757
16038
  (vx, vy) => {
15758
16039
  const rb = engine.ecs.getComponent(entityId, "RigidBody");
15759
16040
  if (rb) {
@@ -15763,7 +16044,7 @@ function useKinematicBody() {
15763
16044
  },
15764
16045
  [engine.ecs, entityId]
15765
16046
  );
15766
- const setAngularVelocity = useCallback13(
16047
+ const setAngularVelocity = useCallback14(
15767
16048
  (w) => {
15768
16049
  const rb = engine.ecs.getComponent(entityId, "RigidBody");
15769
16050
  if (rb) rb.angularVelocity = w;
@@ -15774,12 +16055,12 @@ function useKinematicBody() {
15774
16055
  }
15775
16056
 
15776
16057
  // ../gameplay/src/hooks/useLevelTransition.ts
15777
- import { useState as useState13, useRef as useRef19, useCallback as useCallback14 } from "react";
16058
+ import { useState as useState14, useRef as useRef20, useCallback as useCallback15 } from "react";
15778
16059
  function useLevelTransition(initial) {
15779
- const [currentLevel, setCurrentLevel] = useState13(initial);
15780
- const [isTransitioning, setIsTransitioning] = useState13(false);
15781
- const overlayRef = useRef19(null);
15782
- const transitionTo = useCallback14((level, opts = {}) => {
16060
+ const [currentLevel, setCurrentLevel] = useState14(initial);
16061
+ const [isTransitioning, setIsTransitioning] = useState14(false);
16062
+ const overlayRef = useRef20(null);
16063
+ const transitionTo = useCallback15((level, opts = {}) => {
15783
16064
  const { duration = 0.4, type = "fade" } = opts;
15784
16065
  if (type === "instant") {
15785
16066
  setCurrentLevel(level);
@@ -15816,13 +16097,13 @@ function useLevelTransition(initial) {
15816
16097
  }
15817
16098
 
15818
16099
  // ../gameplay/src/hooks/usePlatformerController.ts
15819
- import { useContext as useContext55, useEffect as useEffect52 } from "react";
16100
+ import { useContext as useContext56, useEffect as useEffect53 } from "react";
15820
16101
  function normalizeKeys(val, defaults) {
15821
16102
  if (!val) return defaults;
15822
16103
  return Array.isArray(val) ? val : [val];
15823
16104
  }
15824
16105
  function usePlatformerController(entityId, opts = {}) {
15825
- const engine = useContext55(EngineContext);
16106
+ const engine = useContext56(EngineContext);
15826
16107
  const {
15827
16108
  speed = 200,
15828
16109
  jumpForce = -500,
@@ -15835,7 +16116,7 @@ function usePlatformerController(entityId, opts = {}) {
15835
16116
  const leftKeys = normalizeKeys(bindings?.left, ["ArrowLeft", "KeyA", "a"]);
15836
16117
  const rightKeys = normalizeKeys(bindings?.right, ["ArrowRight", "KeyD", "d"]);
15837
16118
  const jumpKeys = normalizeKeys(bindings?.jump, ["Space", "ArrowUp", "KeyW", "w"]);
15838
- useEffect52(() => {
16119
+ useEffect53(() => {
15839
16120
  const state = {
15840
16121
  coyoteTimer: 0,
15841
16122
  jumpBuffer: 0,
@@ -15882,26 +16163,26 @@ function usePlatformerController(entityId, opts = {}) {
15882
16163
  }
15883
16164
 
15884
16165
  // ../gameplay/src/hooks/usePathfinding.ts
15885
- import { useCallback as useCallback15 } from "react";
16166
+ import { useCallback as useCallback16 } from "react";
15886
16167
  function usePathfinding() {
15887
- const createGrid$ = useCallback15(
16168
+ const createGrid$ = useCallback16(
15888
16169
  (cols, rows, cellSize) => createNavGrid(cols, rows, cellSize),
15889
16170
  []
15890
16171
  );
15891
- const setWalkable$ = useCallback15(
16172
+ const setWalkable$ = useCallback16(
15892
16173
  (grid, col, row, walkable) => setWalkable(grid, col, row, walkable),
15893
16174
  []
15894
16175
  );
15895
- const findPath$ = useCallback15((grid, start, goal) => findPath(grid, start, goal), []);
16176
+ const findPath$ = useCallback16((grid, start, goal) => findPath(grid, start, goal), []);
15896
16177
  return { createGrid: createGrid$, setWalkable: setWalkable$, findPath: findPath$ };
15897
16178
  }
15898
16179
 
15899
16180
  // ../gameplay/src/hooks/usePersistedBindings.ts
15900
- import { useState as useState14, useCallback as useCallback16, useMemo as useMemo11, useContext as useContext56 } from "react";
16181
+ import { useState as useState15, useCallback as useCallback17, useMemo as useMemo11, useContext as useContext57 } from "react";
15901
16182
  function usePersistedBindings(storageKey, defaults) {
15902
- const engine = useContext56(EngineContext);
16183
+ const engine = useContext57(EngineContext);
15903
16184
  const input = engine.input;
15904
- const [bindings, setBindings] = useState14(() => {
16185
+ const [bindings, setBindings] = useState15(() => {
15905
16186
  try {
15906
16187
  const stored = localStorage.getItem(storageKey);
15907
16188
  if (stored) return { ...defaults, ...JSON.parse(stored) };
@@ -15917,7 +16198,7 @@ function usePersistedBindings(storageKey, defaults) {
15917
16198
  }
15918
16199
  return out;
15919
16200
  }, [bindings]);
15920
- const rebind = useCallback16(
16201
+ const rebind = useCallback17(
15921
16202
  (action, keys) => {
15922
16203
  setBindings((prev) => {
15923
16204
  const next = { ...prev, [action]: Array.isArray(keys) ? keys : [keys] };
@@ -15930,7 +16211,7 @@ function usePersistedBindings(storageKey, defaults) {
15930
16211
  },
15931
16212
  [storageKey]
15932
16213
  );
15933
- const reset = useCallback16(() => {
16214
+ const reset = useCallback17(() => {
15934
16215
  try {
15935
16216
  localStorage.removeItem(storageKey);
15936
16217
  } catch {
@@ -15951,21 +16232,21 @@ function usePersistedBindings(storageKey, defaults) {
15951
16232
  }
15952
16233
 
15953
16234
  // ../gameplay/src/hooks/useRestart.ts
15954
- import { useState as useState15, useCallback as useCallback17 } from "react";
16235
+ import { useState as useState16, useCallback as useCallback18 } from "react";
15955
16236
  function useRestart() {
15956
- const [restartKey, setRestartKey] = useState15(0);
15957
- const restart = useCallback17(() => {
16237
+ const [restartKey, setRestartKey] = useState16(0);
16238
+ const restart = useCallback18(() => {
15958
16239
  setRestartKey((k) => k + 1);
15959
16240
  }, []);
15960
16241
  return { restartKey, restart };
15961
16242
  }
15962
16243
 
15963
16244
  // ../gameplay/src/hooks/useSave.ts
15964
- import { useCallback as useCallback18, useRef as useRef20 } from "react";
16245
+ import { useCallback as useCallback19, useRef as useRef21 } from "react";
15965
16246
  function useSave(key, defaultValue, opts = {}) {
15966
16247
  const version = opts.version ?? 1;
15967
- const dataRef = useRef20(defaultValue);
15968
- const save = useCallback18(
16248
+ const dataRef = useRef21(defaultValue);
16249
+ const save = useCallback19(
15969
16250
  (value) => {
15970
16251
  dataRef.current = value;
15971
16252
  const slot = { version, data: value };
@@ -15977,7 +16258,7 @@ function useSave(key, defaultValue, opts = {}) {
15977
16258
  },
15978
16259
  [key, version]
15979
16260
  );
15980
- const load = useCallback18(() => {
16261
+ const load = useCallback19(() => {
15981
16262
  try {
15982
16263
  const raw = localStorage.getItem(key);
15983
16264
  if (!raw) return defaultValue;
@@ -15997,11 +16278,11 @@ function useSave(key, defaultValue, opts = {}) {
15997
16278
  return defaultValue;
15998
16279
  }
15999
16280
  }, [key, version]);
16000
- const clear = useCallback18(() => {
16281
+ const clear = useCallback19(() => {
16001
16282
  localStorage.removeItem(key);
16002
16283
  dataRef.current = defaultValue;
16003
16284
  }, [key]);
16004
- const exists = useCallback18(() => {
16285
+ const exists = useCallback19(() => {
16005
16286
  return localStorage.getItem(key) !== null;
16006
16287
  }, [key]);
16007
16288
  return {
@@ -16016,11 +16297,11 @@ function useSave(key, defaultValue, opts = {}) {
16016
16297
  }
16017
16298
 
16018
16299
  // ../gameplay/src/hooks/useTopDownMovement.ts
16019
- import { useContext as useContext57, useEffect as useEffect53 } from "react";
16300
+ import { useContext as useContext58, useEffect as useEffect54 } from "react";
16020
16301
  function useTopDownMovement(entityId, opts = {}) {
16021
- const engine = useContext57(EngineContext);
16302
+ const engine = useContext58(EngineContext);
16022
16303
  const { speed = 200, normalizeDiagonal = true } = opts;
16023
- useEffect53(() => {
16304
+ useEffect54(() => {
16024
16305
  const updateFn = (id, world, input) => {
16025
16306
  if (!world.hasEntity(id)) return;
16026
16307
  const rb = world.getComponent(id, "RigidBody");
@@ -16045,18 +16326,18 @@ function useTopDownMovement(entityId, opts = {}) {
16045
16326
  }
16046
16327
 
16047
16328
  // ../gameplay/src/hooks/useDialogue.ts
16048
- import { useState as useState16, useCallback as useCallback19, useRef as useRef21 } from "react";
16329
+ import { useState as useState17, useCallback as useCallback20, useRef as useRef22 } from "react";
16049
16330
  function useDialogue() {
16050
- const [active, setActive] = useState16(false);
16051
- const [currentId, setCurrentId] = useState16(null);
16052
- const scriptRef = useRef21(null);
16053
- const start = useCallback19((script, startId) => {
16331
+ const [active, setActive] = useState17(false);
16332
+ const [currentId, setCurrentId] = useState17(null);
16333
+ const scriptRef = useRef22(null);
16334
+ const start = useCallback20((script, startId) => {
16054
16335
  scriptRef.current = script;
16055
16336
  const id = startId ?? Object.keys(script)[0];
16056
16337
  setCurrentId(id);
16057
16338
  setActive(true);
16058
16339
  }, []);
16059
- const advance = useCallback19(
16340
+ const advance = useCallback20(
16060
16341
  (choiceIndex) => {
16061
16342
  if (!scriptRef.current || !currentId) return;
16062
16343
  const line = scriptRef.current[currentId];
@@ -16086,7 +16367,7 @@ function useDialogue() {
16086
16367
  },
16087
16368
  [currentId]
16088
16369
  );
16089
- const close = useCallback19(() => {
16370
+ const close = useCallback20(() => {
16090
16371
  setActive(false);
16091
16372
  setCurrentId(null);
16092
16373
  scriptRef.current = null;
@@ -16096,17 +16377,17 @@ function useDialogue() {
16096
16377
  }
16097
16378
 
16098
16379
  // ../gameplay/src/hooks/useCutscene.ts
16099
- import { useState as useState17, useCallback as useCallback20, useRef as useRef22, useEffect as useEffect54, useContext as useContext58 } from "react";
16380
+ import { useState as useState18, useCallback as useCallback21, useRef as useRef23, useEffect as useEffect55, useContext as useContext59 } from "react";
16100
16381
  function useCutscene() {
16101
- const engine = useContext58(EngineContext);
16102
- const [playing, setPlaying] = useState17(false);
16103
- const [stepIndex, setStepIndex] = useState17(0);
16104
- const stepsRef = useRef22([]);
16105
- const timerRef = useRef22(0);
16106
- const idxRef = useRef22(0);
16107
- const playingRef = useRef22(false);
16108
- const entityRef = useRef22(null);
16109
- const finish = useCallback20(() => {
16382
+ const engine = useContext59(EngineContext);
16383
+ const [playing, setPlaying] = useState18(false);
16384
+ const [stepIndex, setStepIndex] = useState18(0);
16385
+ const stepsRef = useRef23([]);
16386
+ const timerRef = useRef23(0);
16387
+ const idxRef = useRef23(0);
16388
+ const playingRef = useRef23(false);
16389
+ const entityRef = useRef23(null);
16390
+ const finish = useCallback21(() => {
16110
16391
  playingRef.current = false;
16111
16392
  setPlaying(false);
16112
16393
  setStepIndex(0);
@@ -16116,14 +16397,14 @@ function useCutscene() {
16116
16397
  entityRef.current = null;
16117
16398
  }
16118
16399
  }, [engine.ecs]);
16119
- const fireStep = useCallback20((step) => {
16400
+ const fireStep = useCallback21((step) => {
16120
16401
  if (step.type === "call") step.fn();
16121
16402
  if (step.type === "parallel")
16122
16403
  step.steps.forEach((s2) => {
16123
16404
  if (s2.type === "call") s2.fn();
16124
16405
  });
16125
16406
  }, []);
16126
- const play = useCallback20(
16407
+ const play = useCallback21(
16127
16408
  (steps) => {
16128
16409
  stepsRef.current = steps;
16129
16410
  idxRef.current = 0;
@@ -16180,7 +16461,7 @@ function useCutscene() {
16180
16461
  },
16181
16462
  [engine.ecs, finish, fireStep]
16182
16463
  );
16183
- const skip = useCallback20(() => {
16464
+ const skip = useCallback21(() => {
16184
16465
  for (let i = idxRef.current; i < stepsRef.current.length; i++) {
16185
16466
  const step = stepsRef.current[i];
16186
16467
  if (step.type === "call") step.fn();
@@ -16191,7 +16472,7 @@ function useCutscene() {
16191
16472
  }
16192
16473
  finish();
16193
16474
  }, [finish]);
16194
- useEffect54(() => {
16475
+ useEffect55(() => {
16195
16476
  return () => {
16196
16477
  if (entityRef.current !== null && engine.ecs.hasEntity(entityRef.current)) {
16197
16478
  engine.ecs.destroyEntity(entityRef.current);
@@ -16202,7 +16483,7 @@ function useCutscene() {
16202
16483
  }
16203
16484
 
16204
16485
  // ../gameplay/src/hooks/useGameStore.ts
16205
- import { useSyncExternalStore as useSyncExternalStore2, useCallback as useCallback21 } from "react";
16486
+ import { useSyncExternalStore as useSyncExternalStore2, useCallback as useCallback22 } from "react";
16206
16487
  function createStore(initialState) {
16207
16488
  let state = { ...initialState };
16208
16489
  const listeners = /* @__PURE__ */ new Set();
@@ -16228,7 +16509,7 @@ function useGameStore(key, initialState) {
16228
16509
  }
16229
16510
  const store = stores.get(key);
16230
16511
  const state = useSyncExternalStore2(store.subscribe, store.getState);
16231
- const setState = useCallback21(
16512
+ const setState = useCallback22(
16232
16513
  (partial) => {
16233
16514
  store.setState(partial);
16234
16515
  },
@@ -16238,21 +16519,21 @@ function useGameStore(key, initialState) {
16238
16519
  }
16239
16520
 
16240
16521
  // ../gameplay/src/hooks/useTween.ts
16241
- import { useRef as useRef23, useCallback as useCallback22, useEffect as useEffect55 } from "react";
16522
+ import { useRef as useRef24, useCallback as useCallback23, useEffect as useEffect56 } from "react";
16242
16523
  function useTween(opts) {
16243
- const rafRef = useRef23(null);
16244
- const startTimeRef = useRef23(0);
16245
- const runningRef = useRef23(false);
16246
- const optsRef = useRef23(opts);
16524
+ const rafRef = useRef24(null);
16525
+ const startTimeRef = useRef24(0);
16526
+ const runningRef = useRef24(false);
16527
+ const optsRef = useRef24(opts);
16247
16528
  optsRef.current = opts;
16248
- const stop = useCallback22(() => {
16529
+ const stop = useCallback23(() => {
16249
16530
  if (rafRef.current !== null) {
16250
16531
  cancelAnimationFrame(rafRef.current);
16251
16532
  rafRef.current = null;
16252
16533
  }
16253
16534
  runningRef.current = false;
16254
16535
  }, []);
16255
- const start = useCallback22(() => {
16536
+ const start = useCallback23(() => {
16256
16537
  stop();
16257
16538
  runningRef.current = true;
16258
16539
  startTimeRef.current = performance.now();
@@ -16274,12 +16555,12 @@ function useTween(opts) {
16274
16555
  };
16275
16556
  rafRef.current = requestAnimationFrame(tick);
16276
16557
  }, [stop]);
16277
- useEffect55(() => {
16558
+ useEffect56(() => {
16278
16559
  if (opts.autoStart) {
16279
16560
  start();
16280
16561
  }
16281
16562
  }, []);
16282
- useEffect55(() => {
16563
+ useEffect56(() => {
16283
16564
  return () => {
16284
16565
  if (rafRef.current !== null) {
16285
16566
  cancelAnimationFrame(rafRef.current);
@@ -16298,15 +16579,15 @@ function useTween(opts) {
16298
16579
  }
16299
16580
 
16300
16581
  // ../gameplay/src/hooks/useObjectPool.ts
16301
- import { useRef as useRef24, useMemo as useMemo12, useEffect as useEffect56 } from "react";
16582
+ import { useRef as useRef25, useMemo as useMemo12, useEffect as useEffect57 } from "react";
16302
16583
  function useObjectPool(factory, reset, initialSize) {
16303
- const poolRef = useRef24([]);
16304
- const activeRef = useRef24(0);
16305
- const factoryRef = useRef24(factory);
16584
+ const poolRef = useRef25([]);
16585
+ const activeRef = useRef25(0);
16586
+ const factoryRef = useRef25(factory);
16306
16587
  factoryRef.current = factory;
16307
- const resetRef = useRef24(reset);
16588
+ const resetRef = useRef25(reset);
16308
16589
  resetRef.current = reset;
16309
- useEffect56(() => {
16590
+ useEffect57(() => {
16310
16591
  if (initialSize != null && initialSize > 0) {
16311
16592
  const pool = poolRef.current;
16312
16593
  for (let i = 0; i < initialSize; i++) {
@@ -16345,10 +16626,10 @@ function useObjectPool(factory, reset, initialSize) {
16345
16626
  }
16346
16627
 
16347
16628
  // ../gameplay/src/hooks/useForces.ts
16348
- import { useContext as useContext59, useMemo as useMemo13 } from "react";
16629
+ import { useContext as useContext60, useMemo as useMemo13 } from "react";
16349
16630
  function useForces() {
16350
- const engine = useContext59(EngineContext);
16351
- const entityId = useContext59(EntityContext);
16631
+ const engine = useContext60(EngineContext);
16632
+ const entityId = useContext60(EntityContext);
16352
16633
  return useMemo13(() => {
16353
16634
  const getRb = () => engine.ecs.getComponent(entityId, "RigidBody");
16354
16635
  const getTransform = () => engine.ecs.getComponent(entityId, "Transform");
@@ -16417,10 +16698,10 @@ function useForces() {
16417
16698
  }
16418
16699
 
16419
16700
  // ../gameplay/src/hooks/useCharacterController.ts
16420
- import { useContext as useContext60, useMemo as useMemo14 } from "react";
16701
+ import { useContext as useContext61, useMemo as useMemo14 } from "react";
16421
16702
  function useCharacterController(config = {}) {
16422
- const engine = useContext60(EngineContext);
16423
- const entityId = useContext60(EntityContext);
16703
+ const engine = useContext61(EngineContext);
16704
+ const entityId = useContext61(EntityContext);
16424
16705
  return useMemo14(() => {
16425
16706
  const controller = new CharacterController(config);
16426
16707
  return {
@@ -16433,7 +16714,7 @@ function useCharacterController(config = {}) {
16433
16714
  }
16434
16715
 
16435
16716
  // ../../packages/audio/src/useSound.ts
16436
- import { useEffect as useEffect57, useRef as useRef25 } from "react";
16717
+ import { useEffect as useEffect58, useRef as useRef26 } from "react";
16437
16718
 
16438
16719
  // ../../packages/audio/src/audioContext.ts
16439
16720
  var _audioCtx = null;
@@ -16531,13 +16812,13 @@ function createPoolEntry(ctx, buffer, loop, volume, destination) {
16531
16812
  return { source, gain };
16532
16813
  }
16533
16814
  function useSound(src, opts = {}) {
16534
- const bufferRef = useRef25(null);
16535
- const activeInstances = useRef25([]);
16536
- const volRef = useRef25(opts.volume ?? 1);
16537
- const loopRef = useRef25(opts.loop ?? false);
16538
- const groupRef = useRef25(opts.group);
16815
+ const bufferRef = useRef26(null);
16816
+ const activeInstances = useRef26([]);
16817
+ const volRef = useRef26(opts.volume ?? 1);
16818
+ const loopRef = useRef26(opts.loop ?? false);
16819
+ const groupRef = useRef26(opts.group);
16539
16820
  const maxInstances = opts.maxInstances ?? 4;
16540
- useEffect57(() => {
16821
+ useEffect58(() => {
16541
16822
  let cancelled = false;
16542
16823
  loadBuffer(src).then((buf) => {
16543
16824
  if (!cancelled) bufferRef.current = buf;
@@ -16665,7 +16946,7 @@ function useSound(src, opts = {}) {
16665
16946
  }
16666
16947
 
16667
16948
  // ../../packages/audio/src/useSpatialSound.ts
16668
- import { useEffect as useEffect58, useRef as useRef26 } from "react";
16949
+ import { useEffect as useEffect59, useRef as useRef27 } from "react";
16669
16950
  async function loadBuffer2(src) {
16670
16951
  const bufferCache2 = _getBufferCache();
16671
16952
  const bufferRefCount2 = _getBufferRefCount();
@@ -16690,18 +16971,18 @@ function releaseBuffer2(src) {
16690
16971
  }
16691
16972
  }
16692
16973
  function useSpatialSound(src, opts = {}) {
16693
- const bufferRef = useRef26(null);
16694
- const sourceRef = useRef26(null);
16695
- const gainRef = useRef26(null);
16696
- const pannerRef = useRef26(null);
16697
- const volRef = useRef26(opts.volume ?? 1);
16698
- const loopRef = useRef26(opts.loop ?? false);
16699
- const groupRef = useRef26(opts.group);
16974
+ const bufferRef = useRef27(null);
16975
+ const sourceRef = useRef27(null);
16976
+ const gainRef = useRef27(null);
16977
+ const pannerRef = useRef27(null);
16978
+ const volRef = useRef27(opts.volume ?? 1);
16979
+ const loopRef = useRef27(opts.loop ?? false);
16980
+ const groupRef = useRef27(opts.group);
16700
16981
  const maxDistance = opts.maxDistance ?? 1e3;
16701
16982
  const distModel = opts.distanceModel ?? "linear";
16702
16983
  const refDistance = opts.refDistance ?? 1;
16703
16984
  const rolloffFactor = opts.rolloffFactor ?? 1;
16704
- useEffect58(() => {
16985
+ useEffect59(() => {
16705
16986
  let cancelled = false;
16706
16987
  loadBuffer2(src).then((buf) => {
16707
16988
  if (!cancelled) bufferRef.current = buf;
@@ -16919,6 +17200,7 @@ export {
16919
17200
  addForce,
16920
17201
  addForceAtPoint,
16921
17202
  addTorque,
17203
+ alignment,
16922
17204
  announceToScreenReader,
16923
17205
  applyImpulse,
16924
17206
  applyImpulseAtPoint,
@@ -16932,6 +17214,7 @@ export {
16932
17214
  chromaticAberrationEffect,
16933
17215
  circleArea,
16934
17216
  circleShape,
17217
+ cohesion,
16935
17218
  computeTOI,
16936
17219
  containsPoint,
16937
17220
  createAtlas,
@@ -16973,6 +17256,7 @@ export {
16973
17256
  deterministicSqrt,
16974
17257
  duck,
16975
17258
  epa,
17259
+ evade,
16976
17260
  findByTag,
16977
17261
  flee,
16978
17262
  generateDeterministicPairs,
@@ -17005,6 +17289,7 @@ export {
17005
17289
  predictPosition,
17006
17290
  preloadManifest,
17007
17291
  projectPoint,
17292
+ pursuit,
17008
17293
  queryBVH,
17009
17294
  queryBVHCircle,
17010
17295
  raycast,
@@ -17018,6 +17303,7 @@ export {
17018
17303
  restoreSnapshot,
17019
17304
  scanlineEffect,
17020
17305
  seek,
17306
+ separation,
17021
17307
  setAccessibilityOptions,
17022
17308
  setAdditionalMass,
17023
17309
  setAnimationState,
@@ -17032,6 +17318,7 @@ export {
17032
17318
  setNextKinematicRotation,
17033
17319
  setParent,
17034
17320
  shapeCast,
17321
+ smoothPath,
17035
17322
  snapshotFromBytes,
17036
17323
  snapshotFromJSON,
17037
17324
  snapshotHash,
@@ -17098,6 +17385,7 @@ export {
17098
17385
  useSnapshot,
17099
17386
  useSound,
17100
17387
  useSpatialSound,
17388
+ useSquashStretch,
17101
17389
  useTimer,
17102
17390
  useTopDownMovement,
17103
17391
  useTouch,
@@ -17106,6 +17394,7 @@ export {
17106
17394
  useTriggerStay,
17107
17395
  useTween,
17108
17396
  useVirtualInput,
17397
+ useWorldQuery,
17109
17398
  velocityAtPoint,
17110
17399
  vignetteEffect,
17111
17400
  wait,