cubeforge 0.5.1 → 0.6.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/advanced.js CHANGED
@@ -30,7 +30,7 @@ import {
30
30
  resolveTOI,
31
31
  setDeterministicMode,
32
32
  sortEntities
33
- } from "./chunk-OT6I5RYW.js";
33
+ } from "./chunk-UMHYQ4EP.js";
34
34
  export {
35
35
  Float64Pool,
36
36
  IslandDetector,
@@ -5261,6 +5261,31 @@ var PhysicsSystem = class {
5261
5261
  bvhCache = /* @__PURE__ */ new Map();
5262
5262
  // Physics hooks for filtering and modifying contacts
5263
5263
  hooks = {};
5264
+ // ── Scratch containers — reused every frame to avoid GC pressure ──────────
5265
+ //
5266
+ // Previously these were allocated fresh inside update() every substep,
5267
+ // producing ~20 Map/Set allocations per frame. Now they live as instance
5268
+ // fields and are cleared at the start of each use. Never escape the class.
5269
+ //
5270
+ // The _current*Pairs fields are double-buffered with their active*Pairs
5271
+ // counterparts: at the end of each substep, the filled "current" is swapped
5272
+ // with "active", and next substep clears the new "current" (which was the
5273
+ // previous "active"). Same enter/stay/exit event semantics, zero allocation.
5274
+ _staticDelta = /* @__PURE__ */ new Map();
5275
+ _preStepPos = /* @__PURE__ */ new Map();
5276
+ _spatialGrid = /* @__PURE__ */ new Map();
5277
+ _jointExcludedPairs = /* @__PURE__ */ new Set();
5278
+ _solverBodies = /* @__PURE__ */ new Map();
5279
+ _triggerNormals = /* @__PURE__ */ new Map();
5280
+ _circleNormals = /* @__PURE__ */ new Map();
5281
+ /** Shared scratch for per-body "checked" neighbor dedup; cleared per iteration. */
5282
+ _checkedScratch = /* @__PURE__ */ new Set();
5283
+ _currentCollisionPairs = /* @__PURE__ */ new Map();
5284
+ _currentTriggerPairs = /* @__PURE__ */ new Map();
5285
+ _currentCirclePairs = /* @__PURE__ */ new Map();
5286
+ _currentCompoundPairs = /* @__PURE__ */ new Map();
5287
+ _currentCapsulePairs = /* @__PURE__ */ new Map();
5288
+ _currentPolygonPairs = /* @__PURE__ */ new Map();
5264
5289
  /** Set physics hooks for contact filtering and modification. */
5265
5290
  setHooks(hooks) {
5266
5291
  this.hooks = hooks;
@@ -5421,7 +5446,8 @@ var PhysicsSystem = class {
5421
5446
  }
5422
5447
  const nonDynamic = [...staticBox, ...kinematicBox];
5423
5448
  this.pruneDeadPairs(world);
5424
- const staticDelta = /* @__PURE__ */ new Map();
5449
+ const staticDelta = this._staticDelta;
5450
+ staticDelta.clear();
5425
5451
  for (const sid of nonDynamic) {
5426
5452
  const st = world.getComponent(sid, "Transform");
5427
5453
  const prev = this.staticPrevPos.get(sid);
@@ -5551,12 +5577,14 @@ var PhysicsSystem = class {
5551
5577
  }
5552
5578
  if (rb.dropThrough > 0) rb.dropThrough--;
5553
5579
  }
5554
- const preStepPos = /* @__PURE__ */ new Map();
5580
+ const preStepPos = this._preStepPos;
5581
+ preStepPos.clear();
5555
5582
  for (const id of dynamicBox) {
5556
5583
  const t = world.getComponent(id, "Transform");
5557
5584
  preStepPos.set(id, { x: t.x, y: t.y });
5558
5585
  }
5559
- const spatialGrid = /* @__PURE__ */ new Map();
5586
+ const spatialGrid = this._spatialGrid;
5587
+ spatialGrid.clear();
5560
5588
  for (const sid of nonDynamic) {
5561
5589
  const st = world.getComponent(sid, "Transform");
5562
5590
  const sc = world.getComponent(sid, "BoxCollider");
@@ -5571,7 +5599,8 @@ var PhysicsSystem = class {
5571
5599
  bucket.push(sid);
5572
5600
  }
5573
5601
  }
5574
- const jointExcludedPairs = /* @__PURE__ */ new Set();
5602
+ const jointExcludedPairs = this._jointExcludedPairs;
5603
+ jointExcludedPairs.clear();
5575
5604
  for (const jid of world.query("Joint")) {
5576
5605
  const j = world.getComponent(jid, "Joint");
5577
5606
  if (!j.enabled || j.broken) continue;
@@ -5581,7 +5610,8 @@ var PhysicsSystem = class {
5581
5610
  }
5582
5611
  }
5583
5612
  const manifolds = [];
5584
- const currentCollisionPairs = /* @__PURE__ */ new Map();
5613
+ const currentCollisionPairs = this._currentCollisionPairs;
5614
+ currentCollisionPairs.clear();
5585
5615
  for (const id of dynamicBox) {
5586
5616
  const rb = world.getComponent(id, "RigidBody");
5587
5617
  if (rb.sleeping) continue;
@@ -5590,7 +5620,8 @@ var PhysicsSystem = class {
5590
5620
  if (!col.enabled || col.isTrigger) continue;
5591
5621
  const dynAABB = getAABB2(transform, col);
5592
5622
  const candidateCells = this.getCells(dynAABB.cx, dynAABB.cy, dynAABB.hw, dynAABB.hh);
5593
- const checked = /* @__PURE__ */ new Set();
5623
+ const checked = this._checkedScratch;
5624
+ checked.clear();
5594
5625
  for (const cell of candidateCells) {
5595
5626
  const bucket = spatialGrid.get(cell);
5596
5627
  if (!bucket) continue;
@@ -5779,7 +5810,8 @@ var PhysicsSystem = class {
5779
5810
  const circleCy = ct.y + cc.offsetY;
5780
5811
  const circleAABB2 = { cx: circleCx, cy: circleCy, hw: cc.radius, hh: cc.radius };
5781
5812
  const candidateCells = this.getCells(circleAABB2.cx, circleAABB2.cy, circleAABB2.hw, circleAABB2.hh);
5782
- const checked = /* @__PURE__ */ new Set();
5813
+ const checked = this._checkedScratch;
5814
+ checked.clear();
5783
5815
  for (const cell of candidateCells) {
5784
5816
  const bucket = spatialGrid.get(cell);
5785
5817
  if (!bucket) continue;
@@ -5963,7 +5995,8 @@ var PhysicsSystem = class {
5963
5995
  const capHw = cc.width / 2;
5964
5996
  const capHh = cc.height / 2;
5965
5997
  const candidateCells = this.getCells(capCx, capCy, capHw, capHh);
5966
- const checked = /* @__PURE__ */ new Set();
5998
+ const checked = this._checkedScratch;
5999
+ checked.clear();
5967
6000
  for (const cell of candidateCells) {
5968
6001
  const bucket = spatialGrid.get(cell);
5969
6002
  if (!bucket) continue;
@@ -6202,7 +6235,8 @@ var PhysicsSystem = class {
6202
6235
  const polyCx = (minX + maxX) / 2;
6203
6236
  const polyCy = (minY + maxY) / 2;
6204
6237
  const candidateCells = this.getCells(polyCx, polyCy, polyHw, polyHh);
6205
- const checked = /* @__PURE__ */ new Set();
6238
+ const checked = this._checkedScratch;
6239
+ checked.clear();
6206
6240
  for (const cell of candidateCells) {
6207
6241
  const bucket = spatialGrid.get(cell);
6208
6242
  if (!bucket) continue;
@@ -6457,7 +6491,8 @@ var PhysicsSystem = class {
6457
6491
  const triCx = (minX + maxX) / 2;
6458
6492
  const triCy = (minY + maxY) / 2;
6459
6493
  const candidateCells = this.getCells(triCx, triCy, triHw, triHh);
6460
- const checked = /* @__PURE__ */ new Set();
6494
+ const checked = this._checkedScratch;
6495
+ checked.clear();
6461
6496
  for (const cell of candidateCells) {
6462
6497
  const bucket = spatialGrid.get(cell);
6463
6498
  if (!bucket) continue;
@@ -6956,7 +6991,8 @@ var PhysicsSystem = class {
6956
6991
  this.hooks.onContactModify(m);
6957
6992
  }
6958
6993
  }
6959
- const solverBodies = /* @__PURE__ */ new Map();
6994
+ const solverBodies = this._solverBodies;
6995
+ solverBodies.clear();
6960
6996
  for (const id of allBox) {
6961
6997
  const rb = world.getComponent(id, "RigidBody");
6962
6998
  const t = world.getComponent(id, "Transform");
@@ -7264,7 +7300,8 @@ var PhysicsSystem = class {
7264
7300
  (Math.max(startCx, endCx) - Math.min(startCx, endCx)) / 2 + hw,
7265
7301
  (Math.max(startCy, endCy) - Math.min(startCy, endCy)) / 2 + hh
7266
7302
  );
7267
- const checked = /* @__PURE__ */ new Set();
7303
+ const checked = this._checkedScratch;
7304
+ checked.clear();
7268
7305
  for (const cell of sweepCells) {
7269
7306
  const bucket = spatialGrid.get(cell);
7270
7307
  if (!bucket) continue;
@@ -7345,7 +7382,8 @@ var PhysicsSystem = class {
7345
7382
  hh: col.height / 2
7346
7383
  };
7347
7384
  const candidateCells = this.getCells(probeAABB.cx, probeAABB.cy, probeAABB.hw, probeAABB.hh);
7348
- const checked = /* @__PURE__ */ new Set();
7385
+ const checked = this._checkedScratch;
7386
+ checked.clear();
7349
7387
  outer: for (const cell of candidateCells) {
7350
7388
  const bucket = spatialGrid.get(cell);
7351
7389
  if (!bucket) continue;
@@ -7379,7 +7417,8 @@ var PhysicsSystem = class {
7379
7417
  hh: cap.height / 2
7380
7418
  };
7381
7419
  const candidateCells = this.getCells(probeAABB.cx, probeAABB.cy, probeAABB.hw, probeAABB.hh);
7382
- const checked = /* @__PURE__ */ new Set();
7420
+ const checked = this._checkedScratch;
7421
+ checked.clear();
7383
7422
  outerCap: for (const cell of candidateCells) {
7384
7423
  const bucket = spatialGrid.get(cell);
7385
7424
  if (!bucket) continue;
@@ -7723,10 +7762,16 @@ var PhysicsSystem = class {
7723
7762
  this.events?.emit("collisionExit", { a, b, normalX: 0, normalY: 0 });
7724
7763
  }
7725
7764
  }
7726
- this.activeCollisionPairs = currentCollisionPairs;
7765
+ {
7766
+ const prev = this.activeCollisionPairs;
7767
+ this.activeCollisionPairs = currentCollisionPairs;
7768
+ this._currentCollisionPairs = prev;
7769
+ }
7727
7770
  const allWithCollider = world.query("Transform", "BoxCollider");
7728
- const currentTriggerPairs = /* @__PURE__ */ new Map();
7729
- const triggerNormals = /* @__PURE__ */ new Map();
7771
+ const currentTriggerPairs = this._currentTriggerPairs;
7772
+ currentTriggerPairs.clear();
7773
+ const triggerNormals = this._triggerNormals;
7774
+ triggerNormals.clear();
7730
7775
  for (let i = 0; i < allWithCollider.length; i++) {
7731
7776
  for (let j = i + 1; j < allWithCollider.length; j++) {
7732
7777
  const ia = allWithCollider[i];
@@ -7762,10 +7807,16 @@ var PhysicsSystem = class {
7762
7807
  for (const [key, [a, b]] of this.activeTriggerPairs) {
7763
7808
  if (!currentTriggerPairs.has(key)) this.events?.emit("triggerExit", { a, b, normalX: 0, normalY: 0 });
7764
7809
  }
7765
- this.activeTriggerPairs = currentTriggerPairs;
7810
+ {
7811
+ const prev = this.activeTriggerPairs;
7812
+ this.activeTriggerPairs = currentTriggerPairs;
7813
+ this._currentTriggerPairs = prev;
7814
+ }
7766
7815
  if (allCircle.length > 0) {
7767
- const currentCirclePairs = /* @__PURE__ */ new Map();
7768
- const circleNormals = /* @__PURE__ */ new Map();
7816
+ const currentCirclePairs = this._currentCirclePairs;
7817
+ currentCirclePairs.clear();
7818
+ const circleNormals = this._circleNormals;
7819
+ circleNormals.clear();
7769
7820
  for (let i = 0; i < allCircle.length; i++) {
7770
7821
  for (let j = i + 1; j < allCircle.length; j++) {
7771
7822
  const ia = allCircle[i];
@@ -7832,14 +7883,19 @@ var PhysicsSystem = class {
7832
7883
  for (const [key, [a, b]] of this.activeCirclePairs) {
7833
7884
  if (!currentCirclePairs.has(key)) this.events?.emit("circleExit", { a, b, normalX: 0, normalY: 0 });
7834
7885
  }
7835
- this.activeCirclePairs = currentCirclePairs;
7886
+ {
7887
+ const prev = this.activeCirclePairs;
7888
+ this.activeCirclePairs = currentCirclePairs;
7889
+ this._currentCirclePairs = prev;
7890
+ }
7836
7891
  } else if (this.activeCirclePairs.size > 0) {
7837
7892
  for (const [, [a, b]] of this.activeCirclePairs) this.events?.emit("circleExit", { a, b, normalX: 0, normalY: 0 });
7838
- this.activeCirclePairs = /* @__PURE__ */ new Map();
7893
+ this.activeCirclePairs.clear();
7839
7894
  }
7840
7895
  const allCompound = world.query("Transform", "CompoundCollider");
7841
7896
  if (allCompound.length > 0) {
7842
- const currentCompoundPairs = /* @__PURE__ */ new Map();
7897
+ const currentCompoundPairs = this._currentCompoundPairs;
7898
+ currentCompoundPairs.clear();
7843
7899
  const allBoxEntities = world.query("Transform", "BoxCollider");
7844
7900
  for (const cid of allCompound) {
7845
7901
  const cc = world.getComponent(cid, "CompoundCollider");
@@ -7914,13 +7970,18 @@ var PhysicsSystem = class {
7914
7970
  for (const [key, [a, b]] of this.activeCompoundPairs) {
7915
7971
  if (!currentCompoundPairs.has(key)) this.events?.emit("compoundExit", { a, b });
7916
7972
  }
7917
- this.activeCompoundPairs = currentCompoundPairs;
7973
+ {
7974
+ const prev = this.activeCompoundPairs;
7975
+ this.activeCompoundPairs = currentCompoundPairs;
7976
+ this._currentCompoundPairs = prev;
7977
+ }
7918
7978
  } else if (this.activeCompoundPairs.size > 0) {
7919
7979
  for (const [, [a, b]] of this.activeCompoundPairs) this.events?.emit("compoundExit", { a, b });
7920
- this.activeCompoundPairs = /* @__PURE__ */ new Map();
7980
+ this.activeCompoundPairs.clear();
7921
7981
  }
7922
7982
  if (allCapsule.length > 0) {
7923
- const currentCapsulePairs = /* @__PURE__ */ new Map();
7983
+ const currentCapsulePairs = this._currentCapsulePairs;
7984
+ currentCapsulePairs.clear();
7924
7985
  const allBoxForCapsule = world.query("Transform", "BoxCollider");
7925
7986
  for (const cid of allCapsule) {
7926
7987
  const cc = world.getComponent(cid, "CapsuleCollider");
@@ -7958,14 +8019,19 @@ var PhysicsSystem = class {
7958
8019
  for (const [key, [a, b]] of this.activeCapsulePairs) {
7959
8020
  if (!currentCapsulePairs.has(key)) this.events?.emit("capsuleExit", { a, b });
7960
8021
  }
7961
- this.activeCapsulePairs = currentCapsulePairs;
8022
+ {
8023
+ const prev = this.activeCapsulePairs;
8024
+ this.activeCapsulePairs = currentCapsulePairs;
8025
+ this._currentCapsulePairs = prev;
8026
+ }
7962
8027
  } else if (this.activeCapsulePairs.size > 0) {
7963
8028
  for (const [, [a, b]] of this.activeCapsulePairs) this.events?.emit("capsuleExit", { a, b });
7964
- this.activeCapsulePairs = /* @__PURE__ */ new Map();
8029
+ this.activeCapsulePairs.clear();
7965
8030
  }
7966
8031
  const allPolygonEntities = [...allPolygon, ...allTriangle];
7967
8032
  if (allPolygonEntities.length > 0) {
7968
- const currentPolyPairs = /* @__PURE__ */ new Map();
8033
+ const currentPolyPairs = this._currentPolygonPairs;
8034
+ currentPolyPairs.clear();
7969
8035
  const allBoxForPoly = world.query("Transform", "BoxCollider");
7970
8036
  for (const pid of allPolygonEntities) {
7971
8037
  const isPoly = world.getComponent(pid, "ConvexPolygonCollider");
@@ -8046,10 +8112,14 @@ var PhysicsSystem = class {
8046
8112
  for (const [key, [a, b]] of this.activePolygonPairs) {
8047
8113
  if (!currentPolyPairs.has(key)) this.events?.emit("polygonExit", { a, b });
8048
8114
  }
8049
- this.activePolygonPairs = currentPolyPairs;
8115
+ {
8116
+ const prev = this.activePolygonPairs;
8117
+ this.activePolygonPairs = currentPolyPairs;
8118
+ this._currentPolygonPairs = prev;
8119
+ }
8050
8120
  } else if (this.activePolygonPairs.size > 0) {
8051
8121
  for (const [, [a, b]] of this.activePolygonPairs) this.events?.emit("polygonExit", { a, b });
8052
- this.activePolygonPairs = /* @__PURE__ */ new Map();
8122
+ this.activePolygonPairs.clear();
8053
8123
  }
8054
8124
  }
8055
8125
  // ── Pair pruning ────────────────────────────────────────────────────────
package/dist/index.d.ts CHANGED
@@ -67,6 +67,10 @@ interface GameProps$1 {
67
67
  * - 'onDemand' — sleeps until input arrives or a component calls markDirty().
68
68
  * Use for puzzle games, turn-based games, visual novels, level editors, or any
69
69
  * scene where nothing changes unless the user acts. Saves battery and CPU.
70
+ *
71
+ * **Captured at mount.** This prop is read once when the Game mounts and
72
+ * baked into the loop. Changing it later has no effect — to switch modes,
73
+ * unmount and remount the Game (e.g. via a `key` change).
70
74
  */
71
75
  mode?: GameLoopMode;
72
76
  style?: CSSProperties;
@@ -499,7 +503,48 @@ interface SquashStretchProps {
499
503
  }
500
504
  declare function SquashStretch({ intensity, recovery }: SquashStretchProps): null;
501
505
 
502
- type ParticlePreset = 'explosion' | 'spark' | 'smoke' | 'coinPickup' | 'jumpDust';
506
+ type ParticlePreset = 'explosion' | 'spark' | 'smoke' | 'coinPickup' | 'jumpDust' | 'fire' | 'magic' | 'rain' | 'snow' | 'confetti' | 'sparkle' | 'heal' | 'damage' | 'pickup' | 'fountain' | 'trail';
507
+ interface ParticleEmitterConfig {
508
+ rate?: number;
509
+ speed?: number;
510
+ spread?: number;
511
+ angle?: number;
512
+ particleLife?: number;
513
+ particleSize?: number;
514
+ color?: string;
515
+ gravity?: number;
516
+ maxParticles?: number;
517
+ /** Colors to interpolate through over particle lifetime. */
518
+ colorOverLife?: string[];
519
+ /** Start/end size ratios for per-particle size curve (end is multiplier of particleSize). */
520
+ sizeOverLife?: {
521
+ start: number;
522
+ end: number;
523
+ };
524
+ /** Blend mode for the emitter (additive for glows, normal for solid). */
525
+ blendMode?: 'normal' | 'additive';
526
+ /** Particle shape: 'soft' gradient, 'circle' hard disc, 'square' quad. */
527
+ particleShape?: 'soft' | 'circle' | 'square';
528
+ }
529
+ /**
530
+ * Ready-made particle configurations. Pass via the `preset` prop on
531
+ * `<ParticleEmitter>`:
532
+ *
533
+ * ```tsx
534
+ * <ParticleEmitter preset="fire" />
535
+ * <ParticleEmitter preset="explosion" color="#8bc34a" /> // overrides
536
+ * ```
537
+ *
538
+ * Individual props always override preset values — presets are defaults.
539
+ *
540
+ * ## Catalog
541
+ *
542
+ * Action / combat: `explosion`, `spark`, `damage`, `heal`, `magic`
543
+ * Environment: `fire`, `smoke`, `rain`, `snow`, `fountain`
544
+ * UI / reward: `coinPickup`, `pickup`, `sparkle`, `confetti`
545
+ * Character: `jumpDust`, `trail`
546
+ */
547
+ declare const PARTICLE_PRESETS: Record<ParticlePreset, ParticleEmitterConfig>;
503
548
 
504
549
  interface ParticleEmitterProps {
505
550
  active?: boolean;
@@ -3096,6 +3141,143 @@ declare function deleteSavedScene(key: string): boolean;
3096
3141
  */
3097
3142
  declare function listSavedScenes(prefix?: string): string[];
3098
3143
 
3144
+ type HUDPosition = 'topLeft' | 'topCenter' | 'topRight' | 'centerLeft' | 'center' | 'centerRight' | 'bottomLeft' | 'bottomCenter' | 'bottomRight';
3145
+ interface HUDProps {
3146
+ /**
3147
+ * Whether the HUD fades out during scene transitions. Default true. When a
3148
+ * `SceneTransitionOverlay` is active or `usePause` is paused, the HUD will
3149
+ * dim to `dimmedOpacity` to get out of the way.
3150
+ */
3151
+ dimDuringTransitions?: boolean;
3152
+ /** Opacity when dimmed. Default 0.25. */
3153
+ dimmedOpacity?: number;
3154
+ /** Whether the HUD is currently visible. Default true. */
3155
+ visible?: boolean;
3156
+ /** Whether to apply CSS `env(safe-area-inset-*)` padding. Default true on touch. */
3157
+ safeArea?: boolean;
3158
+ /** Extra padding around all zones in CSS pixels. Default 12. */
3159
+ padding?: number;
3160
+ /** Additional style for the HUD root. */
3161
+ style?: CSSProperties;
3162
+ /** Additional CSS class. */
3163
+ className?: string;
3164
+ children?: ReactNode;
3165
+ }
3166
+ /**
3167
+ * Heads-up-display root. Positions a full-screen overlay over the game canvas
3168
+ * and provides layout zones via {@link HUDZone}. Integrates automatically with
3169
+ * CubeForge primitives:
3170
+ *
3171
+ * - Fades out during scene transitions (via `dimDuringTransitions`)
3172
+ * - Respects `prefers-reduced-motion` for fade timing
3173
+ * - Honors mobile safe-area insets when `safeArea` is on
3174
+ *
3175
+ * @example
3176
+ * ```tsx
3177
+ * <Stage>
3178
+ * <HUD>
3179
+ * <HUDZone position="topLeft">
3180
+ * <HUDBar value={hp} max={100} label="HP" color="#ef5350" />
3181
+ * </HUDZone>
3182
+ * <HUDZone position="topRight">
3183
+ * <span>Score: {score}</span>
3184
+ * </HUDZone>
3185
+ * <HUDZone position="bottomCenter">
3186
+ * <button onClick={onJump}>Jump</button>
3187
+ * </HUDZone>
3188
+ * </HUD>
3189
+ * </Stage>
3190
+ * ```
3191
+ */
3192
+ declare function HUD({ dimDuringTransitions, dimmedOpacity, visible, safeArea, padding, style, className, children, }: HUDProps): react_jsx_runtime.JSX.Element;
3193
+ interface HUDZoneProps {
3194
+ /** Where to anchor this zone. Default 'topLeft'. */
3195
+ position?: HUDPosition;
3196
+ /** Direction children lay out. Default 'row' for top/bottom, 'column' for left/right/center. */
3197
+ direction?: 'row' | 'column';
3198
+ /** Gap between children in CSS pixels. Default 8. */
3199
+ gap?: number;
3200
+ /** Allow pointer events on zone contents (buttons, sliders). Default true for this zone. */
3201
+ interactive?: boolean;
3202
+ /** Override style for the zone. */
3203
+ style?: CSSProperties;
3204
+ /** Additional CSS class. */
3205
+ className?: string;
3206
+ children?: ReactNode;
3207
+ }
3208
+ /**
3209
+ * Positioned content zone inside a {@link HUD}. Nine anchors available
3210
+ * (topLeft, topCenter, topRight, centerLeft, center, centerRight, bottomLeft,
3211
+ * bottomCenter, bottomRight). Honors the parent HUD's padding and safe-area.
3212
+ */
3213
+ declare function HUDZone({ position, direction, gap, interactive, style, className, children, }: HUDZoneProps): react_jsx_runtime.JSX.Element;
3214
+ interface HUDBarProps {
3215
+ /** Current value. */
3216
+ value: number;
3217
+ /** Maximum value. */
3218
+ max: number;
3219
+ /** Optional label shown on top of the bar. */
3220
+ label?: string;
3221
+ /** Bar color. Default '#4fc3f7'. */
3222
+ color?: string;
3223
+ /** Track (empty) color. Default 'rgba(255,255,255,0.08)'. */
3224
+ trackColor?: string;
3225
+ /** Bar width in CSS pixels. Default 180. */
3226
+ width?: number;
3227
+ /** Bar height in CSS pixels. Default 14. */
3228
+ height?: number;
3229
+ /** Show numeric value as "value / max". Default true. */
3230
+ showValue?: boolean;
3231
+ /** Reverse direction: fills right→left. Default false. */
3232
+ rtl?: boolean;
3233
+ /** Round the bar corners. Default true. */
3234
+ rounded?: boolean;
3235
+ /** Smooth transition when value changes. Default true. */
3236
+ animated?: boolean;
3237
+ /** Additional style. */
3238
+ style?: CSSProperties;
3239
+ }
3240
+ /**
3241
+ * A simple value bar for HP, stamina, XP, progress, etc. Meant to be dropped
3242
+ * inside a {@link HUDZone} without any extra styling. Animates smoothly by
3243
+ * default; respects `prefers-reduced-motion` transparently via CSS.
3244
+ *
3245
+ * @example
3246
+ * ```tsx
3247
+ * <HUDZone position="topLeft">
3248
+ * <HUDBar value={hp} max={100} label="HP" color="#ef5350" />
3249
+ * <HUDBar value={mana} max={50} label="MP" color="#4fc3f7" />
3250
+ * </HUDZone>
3251
+ * ```
3252
+ */
3253
+ declare function HUDBar({ value, max, label, color, trackColor, width, height, showValue, rtl, rounded, animated, style, }: HUDBarProps): react_jsx_runtime.JSX.Element;
3254
+ interface HUDCounterProps {
3255
+ /** Numeric value to display. */
3256
+ value: number;
3257
+ /** Optional icon or emoji shown before the value. */
3258
+ icon?: ReactNode;
3259
+ /** Optional label shown after the value. */
3260
+ label?: string;
3261
+ /** Flash briefly when the value changes. Default true. */
3262
+ pulse?: boolean;
3263
+ /** Value color. Default '#fff'. */
3264
+ color?: string;
3265
+ /** Font size in CSS pixels. Default 18. */
3266
+ fontSize?: number;
3267
+ style?: CSSProperties;
3268
+ }
3269
+ /**
3270
+ * A numeric counter widget for score, coins, ammo, etc.
3271
+ *
3272
+ * @example
3273
+ * ```tsx
3274
+ * <HUDZone position="topRight">
3275
+ * <HUDCounter icon="🪙" value={coins} />
3276
+ * </HUDZone>
3277
+ * ```
3278
+ */
3279
+ declare function HUDCounter({ value, icon, label, pulse, color, fontSize, style, }: HUDCounterProps): react_jsx_runtime.JSX.Element;
3280
+
3099
3281
  declare function playClip(world: ECSWorld, entityId: EntityId, clipName: string): void;
3100
3282
  declare function setAnimationState(world: ECSWorld, entityId: EntityId, stateName: string): void;
3101
3283
  declare function setAnimatorParam(world: ECSWorld, entityId: EntityId, name: string, value: AnimatorParamValue): void;
@@ -3202,4 +3384,4 @@ declare function useRemotePlayer(config: {
3202
3384
  opts?: RemotePlayerOptions;
3203
3385
  }): RemotePlayerControls;
3204
3386
 
3205
- export { A11yNode, type A11yNodeProps, type AccessibilityControls, AnimatedSprite, type AnimatedSpriteProps, Animation, type AnimationSet, Animator, AssetLoader, type BoundInputMap, BoxCollider, Camera2D, type CameraControls, type CameraLookaheadOptions, CameraZone, CapsuleCollider, Checkpoint, Circle, CircleCollider, type ComboDetectorResult, CompoundCollider, ConvexCollider, type CoordinateHelpers, type CoroutineControls, type CoroutineFactory, type CoroutineYield, type DraggableControls, type DraggableOptions, type DroppableControls, type DroppableOptions, EditableText, type EditableTextProps, Entity, type ExportOptions, FocusRing, type FocusRingProps, type FocusableOptions, Game, type GameControls, type GamepadState, type GestureHandlers, type GestureOptions, Gradient, type GridCell, type GridControls, type GridOptions, type HMRControls, HalfSpaceCollider, HeightFieldCollider, type HistoryControls, type HistoryOptions, type HoverableControls, type HoverableOptions, type InputContextControls, Joint, type KeyboardFocusControls, Line, Mask, MovingPlatform, type NetworkSyncOptions, NineSlice, ParallaxLayer, ParticleEmitter, type ParticlePreset, type PauseControls, type PinchEvent, Polygon, type PreloadState, type ProfilerData, type RemotePlayerControls, type RemotePlayerOptions, RigidBody, type SceneManagerControls, type SceneSaveOptions, type SceneTransitionControls, SceneTransitionOverlay, ScreenFlash, type ScreenFlashHandle, Script, SegmentCollider, type SelectOptions, Selection, type SelectionControls, type SelectionProps, type SnapControls, type SnapOptions, type SnapResult, type SnapshotControls, Sprite, type SpriteAtlas, SquashStretch, type SquashStretchControls, Stage, type SwipeEvent, Text, type TiledLayer, type TiledObject, Tilemap, type TimerControls, type TouchControls, Trail, Transform, TransformHandles, type TransformHandlesProps, type TransitionEffect, TriMeshCollider, TriangleCollider, type TurnSystemControls, type TurnSystemOptions, VectorPath, type VectorPathProps, type VirtualInputState, VirtualJoystick, type VirtualJoystickProps, type Waypoint, World, createAtlas, defineAnimations, definePrefab, deleteSavedScene, downloadCanvas, exportToBlob, exportToDataURL, listSavedScenes, loadScene, loadSceneFromLocalStorage, playClip, saveScene, saveSceneToLocalStorage, setAnimationState, setAnimatorParam, useAccessibility, useAudioListener, useCamera, useCameraLookahead, useComboDetector, useCoordinates, useCoroutine, useDestroyEntity, useDraggable, useDroppable, useEntity, useEvent, useEvents, useFocusable, useGame, useGamepad, useGamepadHaptics, useGestures, useGrid, useHMR, useHistory, useHitstop, useHoverable, useInput, useInputBuffer, useInputContext, useInputMap, useInputRecorder, useKeyboardFocus, useLocalMultiplayer, useNetworkSync, useParent, usePause, usePlayerInput, usePostProcess, usePreload, useProfiler, useRemotePlayer, useSceneManager, useSceneTransition, useSelection, useSnap, useSnapshot, useSquashStretch, useTimer, useTouch, useTurnSystem, useVirtualInput, useWebGLPostProcess, useWorldQuery, wait, waitFrames, waitUntil };
3387
+ export { A11yNode, type A11yNodeProps, type AccessibilityControls, AnimatedSprite, type AnimatedSpriteProps, Animation, type AnimationSet, Animator, AssetLoader, type BoundInputMap, BoxCollider, Camera2D, type CameraControls, type CameraLookaheadOptions, CameraZone, CapsuleCollider, Checkpoint, Circle, CircleCollider, type ComboDetectorResult, CompoundCollider, ConvexCollider, type CoordinateHelpers, type CoroutineControls, type CoroutineFactory, type CoroutineYield, type DraggableControls, type DraggableOptions, type DroppableControls, type DroppableOptions, EditableText, type EditableTextProps, Entity, type ExportOptions, FocusRing, type FocusRingProps, type FocusableOptions, Game, type GameControls, type GamepadState, type GestureHandlers, type GestureOptions, Gradient, type GridCell, type GridControls, type GridOptions, type HMRControls, HUD, HUDBar, type HUDBarProps, HUDCounter, type HUDCounterProps, type HUDPosition, type HUDProps, HUDZone, type HUDZoneProps, HalfSpaceCollider, HeightFieldCollider, type HistoryControls, type HistoryOptions, type HoverableControls, type HoverableOptions, type InputContextControls, Joint, type KeyboardFocusControls, Line, Mask, MovingPlatform, type NetworkSyncOptions, NineSlice, PARTICLE_PRESETS, ParallaxLayer, ParticleEmitter, type ParticleEmitterConfig, type ParticlePreset, type PauseControls, type PinchEvent, Polygon, type PreloadState, type ProfilerData, type RemotePlayerControls, type RemotePlayerOptions, RigidBody, type SceneManagerControls, type SceneSaveOptions, type SceneTransitionControls, SceneTransitionOverlay, ScreenFlash, type ScreenFlashHandle, Script, SegmentCollider, type SelectOptions, Selection, type SelectionControls, type SelectionProps, type SnapControls, type SnapOptions, type SnapResult, type SnapshotControls, Sprite, type SpriteAtlas, SquashStretch, type SquashStretchControls, Stage, type SwipeEvent, Text, type TiledLayer, type TiledObject, Tilemap, type TimerControls, type TouchControls, Trail, Transform, TransformHandles, type TransformHandlesProps, type TransitionEffect, TriMeshCollider, TriangleCollider, type TurnSystemControls, type TurnSystemOptions, VectorPath, type VectorPathProps, type VirtualInputState, VirtualJoystick, type VirtualJoystickProps, type Waypoint, World, createAtlas, defineAnimations, definePrefab, deleteSavedScene, downloadCanvas, exportToBlob, exportToDataURL, listSavedScenes, loadScene, loadSceneFromLocalStorage, playClip, saveScene, saveSceneToLocalStorage, setAnimationState, setAnimatorParam, useAccessibility, useAudioListener, useCamera, useCameraLookahead, useComboDetector, useCoordinates, useCoroutine, useDestroyEntity, useDraggable, useDroppable, useEntity, useEvent, useEvents, useFocusable, useGame, useGamepad, useGamepadHaptics, useGestures, useGrid, useHMR, useHistory, useHitstop, useHoverable, useInput, useInputBuffer, useInputContext, useInputMap, useInputRecorder, useKeyboardFocus, useLocalMultiplayer, useNetworkSync, useParent, usePause, usePlayerInput, usePostProcess, usePreload, useProfiler, useRemotePlayer, useSceneManager, useSceneTransition, useSelection, useSnap, useSnapshot, useSquashStretch, useTimer, useTouch, useTurnSystem, useVirtualInput, useWebGLPostProcess, useWorldQuery, wait, waitFrames, waitUntil };