@zylem/behaviors 0.5.7 → 0.5.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. package/dist/{behavior-system-HEt67el5.d.ts → behavior-system-DkFAwLb_.d.ts} +6 -0
  2. package/dist/{chunk-7LHXAEOZ.js → chunk-3QUECYMT.js} +5 -4
  3. package/dist/chunk-3QUECYMT.js.map +1 -0
  4. package/dist/{chunk-GZ3DQIIZ.js → chunk-4GW6DCYF.js} +1 -0
  5. package/dist/chunk-4GW6DCYF.js.map +1 -0
  6. package/dist/{chunk-F7E23E26.js → chunk-4WH2ZN7P.js} +1 -0
  7. package/dist/chunk-4WH2ZN7P.js.map +1 -0
  8. package/dist/{chunk-LAN7U3AK.js → chunk-52FJIDGL.js} +2 -1
  9. package/dist/chunk-52FJIDGL.js.map +1 -0
  10. package/dist/{chunk-K6CWKFHL.js → chunk-5A5AYP2C.js} +1 -0
  11. package/dist/chunk-5A5AYP2C.js.map +1 -0
  12. package/dist/{chunk-JSBRDJBE.js → chunk-5WRI5ZAA.js} +1 -0
  13. package/dist/chunk-5WRI5ZAA.js.map +1 -0
  14. package/dist/{chunk-UUMH3DC3.js → chunk-5XPPLTC7.js} +2 -1
  15. package/dist/chunk-5XPPLTC7.js.map +1 -0
  16. package/dist/{chunk-OBF6BIA2.js → chunk-AS3HR7AS.js} +2 -1
  17. package/dist/chunk-AS3HR7AS.js.map +1 -0
  18. package/dist/{chunk-E2MOFIDH.js → chunk-BAXJ7XHJ.js} +4 -3
  19. package/dist/chunk-BAXJ7XHJ.js.map +1 -0
  20. package/dist/{chunk-TK3AXXXI.js → chunk-D7N6SC4D.js} +4 -3
  21. package/dist/chunk-D7N6SC4D.js.map +1 -0
  22. package/dist/{chunk-CTSYM56P.js → chunk-DGDNFX43.js} +6 -5
  23. package/dist/chunk-DGDNFX43.js.map +1 -0
  24. package/dist/{chunk-CB3C7CRD.js → chunk-DWVLGXMF.js} +5 -4
  25. package/dist/chunk-DWVLGXMF.js.map +1 -0
  26. package/dist/{chunk-2HKY6WF7.js → chunk-EIWQM6U3.js} +1 -0
  27. package/dist/chunk-EIWQM6U3.js.map +1 -0
  28. package/dist/{chunk-YDLO5M7S.js → chunk-EZNCCO4L.js} +1 -0
  29. package/dist/chunk-EZNCCO4L.js.map +1 -0
  30. package/dist/{chunk-LLDLVVG4.js → chunk-GL5JGXPR.js} +5 -4
  31. package/dist/chunk-GL5JGXPR.js.map +1 -0
  32. package/dist/{chunk-NDJO56BB.js → chunk-GLXEJD2P.js} +4 -3
  33. package/dist/chunk-GLXEJD2P.js.map +1 -0
  34. package/dist/{chunk-QU6GQ657.js → chunk-H4TJ7X4O.js} +3 -2
  35. package/dist/chunk-H4TJ7X4O.js.map +1 -0
  36. package/dist/{chunk-4DVDFCVY.js → chunk-HZMY3TT4.js} +1 -0
  37. package/dist/chunk-HZMY3TT4.js.map +1 -0
  38. package/dist/{chunk-57GLKGEX.js → chunk-IRMJTAIK.js} +4 -3
  39. package/dist/chunk-IRMJTAIK.js.map +1 -0
  40. package/dist/{chunk-2HLZBWGD.js → chunk-IZJFUAXB.js} +1 -0
  41. package/dist/chunk-IZJFUAXB.js.map +1 -0
  42. package/dist/{chunk-M25QJBDN.js → chunk-JACX7ZMJ.js} +5 -4
  43. package/dist/chunk-JACX7ZMJ.js.map +1 -0
  44. package/dist/{chunk-SHZZ2QRV.js → chunk-JVADRLWX.js} +3 -2
  45. package/dist/chunk-JVADRLWX.js.map +1 -0
  46. package/dist/{chunk-RR3XNDKG.js → chunk-KFFETUAL.js} +3 -2
  47. package/dist/chunk-KFFETUAL.js.map +1 -0
  48. package/dist/{chunk-OSPQFWQF.js → chunk-KIYUUSPK.js} +3 -2
  49. package/dist/chunk-KIYUUSPK.js.map +1 -0
  50. package/dist/{chunk-2YF7J3H4.js → chunk-LL4FLHIY.js} +1 -0
  51. package/dist/chunk-LL4FLHIY.js.map +1 -0
  52. package/dist/{chunk-LWM346FW.js → chunk-M3QDKKDF.js} +1 -0
  53. package/dist/chunk-M3QDKKDF.js.map +1 -0
  54. package/dist/{chunk-CVRN7YAI.js → chunk-MUBU2DIB.js} +44 -16
  55. package/dist/chunk-MUBU2DIB.js.map +1 -0
  56. package/dist/{chunk-UKGBQTHL.js → chunk-NQPYMUDF.js} +4 -3
  57. package/dist/chunk-NQPYMUDF.js.map +1 -0
  58. package/dist/{chunk-DD4U42FG.js → chunk-NW4SE5XW.js} +3 -2
  59. package/dist/chunk-NW4SE5XW.js.map +1 -0
  60. package/dist/{chunk-WHKPWIQO.js → chunk-OHCPV2NT.js} +1 -0
  61. package/dist/chunk-OHCPV2NT.js.map +1 -0
  62. package/dist/{chunk-TZQQYJYK.js → chunk-OPZ2LVS2.js} +1 -0
  63. package/dist/chunk-OPZ2LVS2.js.map +1 -0
  64. package/dist/{chunk-7TIIRJKF.js → chunk-PLIXVF7B.js} +4 -3
  65. package/dist/chunk-PLIXVF7B.js.map +1 -0
  66. package/dist/{chunk-4EWASZHB.js → chunk-QVCMJ4Q2.js} +1 -0
  67. package/dist/chunk-QVCMJ4Q2.js.map +1 -0
  68. package/dist/{chunk-55CFXXZH.js → chunk-S5HFWDGM.js} +4 -3
  69. package/dist/chunk-S5HFWDGM.js.map +1 -0
  70. package/dist/{chunk-3X3CL24Z.js → chunk-SGHIGTVZ.js} +1 -0
  71. package/dist/chunk-SGHIGTVZ.js.map +1 -0
  72. package/dist/{chunk-VJ3UA6OD.js → chunk-TBUKJKY6.js} +2 -1
  73. package/dist/chunk-TBUKJKY6.js.map +1 -0
  74. package/dist/{chunk-UF7QPYUX.js → chunk-USFIJUDN.js} +1 -0
  75. package/dist/chunk-USFIJUDN.js.map +1 -0
  76. package/dist/{chunk-ERS6SNA5.js → chunk-WOMHL23C.js} +2 -1
  77. package/dist/chunk-WOMHL23C.js.map +1 -0
  78. package/dist/{chunk-7GGR26YA.js → chunk-WQUPSOFV.js} +4 -3
  79. package/dist/chunk-WQUPSOFV.js.map +1 -0
  80. package/dist/{chunk-OU2SW4U5.js → chunk-ZOYA3TZG.js} +4 -3
  81. package/dist/chunk-ZOYA3TZG.js.map +1 -0
  82. package/dist/{components-JZQoO2sU.d.ts → components--RTwuT4S.d.ts} +1 -1
  83. package/dist/cooldown.d.ts +1 -1
  84. package/dist/cooldown.js +4 -3
  85. package/dist/cooldown.js.map +1 -0
  86. package/dist/coordinators/boundary-ricochet-3d.d.ts +2 -2
  87. package/dist/coordinators/boundary-ricochet-3d.js +5 -4
  88. package/dist/coordinators/boundary-ricochet-3d.js.map +1 -0
  89. package/dist/coordinators/boundary-ricochet.d.ts +2 -2
  90. package/dist/coordinators/boundary-ricochet.js +5 -4
  91. package/dist/coordinators/boundary-ricochet.js.map +1 -0
  92. package/dist/coordinators/first-person-shooter.js +5 -4
  93. package/dist/coordinators/first-person-shooter.js.map +1 -0
  94. package/dist/coordinators/multidirectional-space-shooter.d.ts +1 -1
  95. package/dist/coordinators/multidirectional-space-shooter.js +7 -6
  96. package/dist/coordinators/multidirectional-space-shooter.js.map +1 -0
  97. package/dist/coordinators/top-down-shooter.d.ts +1 -1
  98. package/dist/coordinators/top-down-shooter.js +7 -6
  99. package/dist/coordinators/top-down-shooter.js.map +1 -0
  100. package/dist/core.d.ts +4 -4
  101. package/dist/core.js +7 -6
  102. package/dist/core.js.map +1 -0
  103. package/dist/destructible-3d.d.ts +1 -1
  104. package/dist/destructible-3d.js +5 -4
  105. package/dist/destructible-3d.js.map +1 -0
  106. package/dist/destructible-prebake.js +3 -2
  107. package/dist/destructible-prebake.js.map +1 -0
  108. package/dist/first-person.d.ts +1 -1
  109. package/dist/first-person.js +8 -7
  110. package/dist/first-person.js.map +1 -0
  111. package/dist/index.d.ts +3 -3
  112. package/dist/index.js +41 -40
  113. package/dist/index.js.map +1 -0
  114. package/dist/jumper-2d.d.ts +1 -1
  115. package/dist/jumper-2d.js +6 -5
  116. package/dist/jumper-2d.js.map +1 -0
  117. package/dist/jumper-3d.d.ts +1 -1
  118. package/dist/jumper-3d.js +7 -6
  119. package/dist/jumper-3d.js.map +1 -0
  120. package/dist/{moveable-BdFmI3s1.d.ts → moveable-CFOHmblC.d.ts} +1 -1
  121. package/dist/particle-emitter/presets.js +3 -2
  122. package/dist/particle-emitter/presets.js.map +1 -0
  123. package/dist/particle-emitter.d.ts +1 -1
  124. package/dist/particle-emitter.js +6 -5
  125. package/dist/particle-emitter.js.map +1 -0
  126. package/dist/platformer-2d.d.ts +1 -1
  127. package/dist/platformer-2d.js +6 -5
  128. package/dist/platformer-2d.js.map +1 -0
  129. package/dist/platformer-3d.d.ts +1 -1
  130. package/dist/platformer-3d.js +6 -5
  131. package/dist/platformer-3d.js.map +1 -0
  132. package/dist/ricochet-2d.d.ts +1 -1
  133. package/dist/ricochet-2d.js +6 -5
  134. package/dist/ricochet-2d.js.map +1 -0
  135. package/dist/ricochet-3d.d.ts +1 -1
  136. package/dist/ricochet-3d.js +6 -5
  137. package/dist/ricochet-3d.js.map +1 -0
  138. package/dist/runtime-2d.d.ts +1 -1
  139. package/dist/runtime-2d.js +3 -2
  140. package/dist/runtime-2d.js.map +1 -0
  141. package/dist/screen-visibility.d.ts +1 -1
  142. package/dist/screen-visibility.js +4 -3
  143. package/dist/screen-visibility.js.map +1 -0
  144. package/dist/screen-wrap.d.ts +1 -1
  145. package/dist/screen-wrap.js +6 -5
  146. package/dist/screen-wrap.js.map +1 -0
  147. package/dist/shooter-2d.d.ts +1 -1
  148. package/dist/shooter-2d.js +6 -5
  149. package/dist/shooter-2d.js.map +1 -0
  150. package/dist/thruster.d.ts +1 -1
  151. package/dist/thruster.js +6 -5
  152. package/dist/thruster.js.map +1 -0
  153. package/dist/top-down-movement.d.ts +1 -1
  154. package/dist/top-down-movement.js +8 -7
  155. package/dist/top-down-movement.js.map +1 -0
  156. package/dist/world-boundary-2d.d.ts +1 -1
  157. package/dist/world-boundary-2d.js +7 -6
  158. package/dist/world-boundary-2d.js.map +1 -0
  159. package/dist/world-boundary-3d.d.ts +1 -1
  160. package/dist/world-boundary-3d.js +7 -6
  161. package/dist/world-boundary-3d.js.map +1 -0
  162. package/package.json +160 -159
@@ -854,6 +854,12 @@ interface BehaviorSystem {
854
854
  attach?(link: BehaviorEntityLink): void;
855
855
  /** Called once per frame. The first argument is always `undefined` (reserved legacy slot). */
856
856
  update(ecs: unknown, delta: number): void;
857
+ /**
858
+ * Called once per frame after the simulation has stepped and before the
859
+ * host syncs render poses. Systems that need this frame's post-step state
860
+ * (e.g. wasm-side teleports) run here instead of in `update`.
861
+ */
862
+ postUpdate?(ecs: unknown, delta: number): void;
857
863
  /** Optional cleanup when a behavior link is detached from a live entity */
858
864
  detach?(link: BehaviorEntityLink): void;
859
865
  /** Optional cleanup when stage is destroyed */
@@ -2,16 +2,16 @@ import {
2
2
  createTopDownMovementComponent,
3
3
  createTopDownMovementInputComponent,
4
4
  createTopDownMovementStateComponent
5
- } from "./chunk-2HKY6WF7.js";
5
+ } from "./chunk-EIWQM6U3.js";
6
6
  import {
7
7
  resolveAim2D
8
- } from "./chunk-VJ3UA6OD.js";
8
+ } from "./chunk-TBUKJKY6.js";
9
9
  import {
10
10
  StageTopDownPlane
11
- } from "./chunk-GZ3DQIIZ.js";
11
+ } from "./chunk-4GW6DCYF.js";
12
12
  import {
13
13
  defineBehavior
14
- } from "./chunk-YDLO5M7S.js";
14
+ } from "./chunk-EZNCCO4L.js";
15
15
 
16
16
  // src/lib/behaviors/top-down-movement/top-down-movement.descriptor.ts
17
17
  var defaultOptions = {
@@ -95,3 +95,4 @@ var TopDownMovementBehavior = defineBehavior({
95
95
  export {
96
96
  TopDownMovementBehavior
97
97
  };
98
+ //# sourceMappingURL=chunk-3QUECYMT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/behaviors/top-down-movement/top-down-movement.descriptor.ts"],"sourcesContent":["import { defineBehavior, type BehaviorRef } from '../behavior-descriptor';\nimport type { BehaviorEntityLink, BehaviorSystem } from '../behavior-system';\nimport {\n\tcreateTopDownMovementComponent,\n\tcreateTopDownMovementInputComponent,\n\tcreateTopDownMovementStateComponent,\n} from './components';\nimport type {\n\tTopDownMovementComponent,\n\tTopDownMovementInputComponent,\n\tTopDownMovementStateComponent,\n} from './components';\nimport {\n\tStageTopDownPlane,\n\ttype BehaviorRuntime,\n} from '../../runtime/wasm-stage-runtime';\nimport { resolveAim2D } from '../../coordinators/shared/top-down-aim';\n\n/**\n * Entity with top-down movement components (input written by the game,\n * simulation owned by the wasm runtime).\n */\nexport interface TopDownMovementEntity {\n\ttopDownMovement: TopDownMovementComponent;\n\t$topDownMovement: TopDownMovementInputComponent;\n\ttopDownMovementState: TopDownMovementStateComponent;\n}\n\nexport interface TopDownMovementBehaviorOptions {\n\tmoveSpeed?: number;\n\t/** When true, WASM rotates toward velocity; default false for twin-stick face axes. */\n\tfaceMovement?: boolean;\n}\n\nexport interface TopDownMovementHandle {\n\tgetFacingAngle(): number;\n}\n\nconst defaultOptions: TopDownMovementBehaviorOptions = {\n\tmoveSpeed: 8,\n\tfaceMovement: false,\n};\n\nconst TOP_DOWN_MOVEMENT_BEHAVIOR_KEY = Symbol.for(\n\t'zylem:behavior:top-down-movement',\n);\n\nfunction createTopDownMovementHandle(\n\tref: BehaviorRef<TopDownMovementBehaviorOptions>,\n): TopDownMovementHandle {\n\treturn {\n\t\tgetFacingAngle: () =>\n\t\t\t(ref as any).__entity?.topDownMovementState?.facingAngle ?? 0,\n\t};\n}\n\nclass TopDownMovementBehaviorSystem implements BehaviorSystem {\n\tprivate attachedRuntimeSlots = new Set<number>();\n\n\tconstructor(\n\t\tprivate wasmStage: BehaviorRuntime | null,\n\t\tprivate getBehaviorLinks?: (key: symbol) => Iterable<BehaviorEntityLink>,\n\t) {}\n\n\tupdate(_ecs: unknown, _delta: number): void {\n\t\tconst links = this.getBehaviorLinks?.(TOP_DOWN_MOVEMENT_BEHAVIOR_KEY);\n\t\tif (!links) return;\n\n\t\tfor (const link of links) {\n\t\t\tconst entity = link.entity as any;\n\t\t\tconst ref = link.ref as any;\n\n\t\t\tif (!entity.topDownMovement) {\n\t\t\t\tentity.topDownMovement = createTopDownMovementComponent(ref.options);\n\t\t\t}\n\t\t\tif (!entity.$topDownMovement) {\n\t\t\t\tentity.$topDownMovement = createTopDownMovementInputComponent();\n\t\t\t}\n\t\t\tif (!entity.topDownMovementState) {\n\t\t\t\tentity.topDownMovementState = createTopDownMovementStateComponent();\n\t\t\t}\n\n\t\t\tref.__entity = entity;\n\n\t\t\tconst handle = (entity.runtimeHandle ?? -1) as number;\n\t\t\tif (!this.wasmStage || handle < 0) continue;\n\n\t\t\tthis.ensureWasmAttached(handle, ref.options as TopDownMovementBehaviorOptions);\n\t\t\tconst input = entity.$topDownMovement;\n\t\t\tconst state = entity.topDownMovementState;\n\t\t\tif (input) {\n\t\t\t\tconst moveX = input.moveX ?? 0;\n\t\t\t\tconst moveY = input.moveY ?? input.moveZ ?? 0;\n\t\t\t\tthis.wasmStage.writeInputAxes(handle, moveX, moveY);\n\t\t\t\tstate.moving = Math.hypot(moveX, moveY) > 0.001;\n\n\t\t\t\tconst aim = resolveAim2D(\n\t\t\t\t\tinput.faceX ?? 0,\n\t\t\t\t\tinput.faceY ?? 0,\n\t\t\t\t\tstate.facingAngle,\n\t\t\t\t);\n\t\t\t\tif (aim.hasAimInput) {\n\t\t\t\t\tstate.facingAngle = aim.angle;\n\t\t\t\t\tentity.setRotationZ?.(aim.angle);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate ensureWasmAttached(handle: number, options: TopDownMovementBehaviorOptions): void {\n\t\tif (!this.wasmStage || this.attachedRuntimeSlots.has(handle)) return;\n\t\tthis.wasmStage.attachTopDown(handle, {\n\t\t\tplane: StageTopDownPlane.Xy,\n\t\t\tspeed: options.moveSpeed ?? defaultOptions.moveSpeed!,\n\t\t\tfaceMovement: options.faceMovement ?? defaultOptions.faceMovement!,\n\t\t});\n\t\tthis.attachedRuntimeSlots.add(handle);\n\t}\n\n\tdestroy(_ecs: unknown): void {\n\t\tthis.attachedRuntimeSlots.clear();\n\t}\n}\n\nexport const TopDownMovementBehavior = defineBehavior<\n\tTopDownMovementBehaviorOptions,\n\tTopDownMovementHandle,\n\tTopDownMovementEntity\n>({\n\tname: 'top-down-movement',\n\tdefaultOptions,\n\tsystemFactory: (ctx) =>\n\t\tnew TopDownMovementBehaviorSystem(ctx.wasmStage ?? null, ctx.getBehaviorLinks),\n\tcreateHandle: createTopDownMovementHandle,\n});\n"],"mappings":";;;;;;;;;;;;;;;;AAsCA,IAAM,iBAAiD;AAAA,EACtD,WAAW;AAAA,EACX,cAAc;AACf;AAEA,IAAM,iCAAiC,uBAAO;AAAA,EAC7C;AACD;AAEA,SAAS,4BACR,KACwB;AACxB,SAAO;AAAA,IACN,gBAAgB,MACd,IAAY,UAAU,sBAAsB,eAAe;AAAA,EAC9D;AACD;AAEA,IAAM,gCAAN,MAA8D;AAAA,EAG7D,YACS,WACA,kBACP;AAFO;AACA;AAAA,EACN;AAAA,EAFM;AAAA,EACA;AAAA,EAJD,uBAAuB,oBAAI,IAAY;AAAA,EAO/C,OAAO,MAAe,QAAsB;AAC3C,UAAM,QAAQ,KAAK,mBAAmB,8BAA8B;AACpE,QAAI,CAAC,MAAO;AAEZ,eAAW,QAAQ,OAAO;AACzB,YAAM,SAAS,KAAK;AACpB,YAAM,MAAM,KAAK;AAEjB,UAAI,CAAC,OAAO,iBAAiB;AAC5B,eAAO,kBAAkB,+BAA+B,IAAI,OAAO;AAAA,MACpE;AACA,UAAI,CAAC,OAAO,kBAAkB;AAC7B,eAAO,mBAAmB,oCAAoC;AAAA,MAC/D;AACA,UAAI,CAAC,OAAO,sBAAsB;AACjC,eAAO,uBAAuB,oCAAoC;AAAA,MACnE;AAEA,UAAI,WAAW;AAEf,YAAM,SAAU,OAAO,iBAAiB;AACxC,UAAI,CAAC,KAAK,aAAa,SAAS,EAAG;AAEnC,WAAK,mBAAmB,QAAQ,IAAI,OAAyC;AAC7E,YAAM,QAAQ,OAAO;AACrB,YAAM,QAAQ,OAAO;AACrB,UAAI,OAAO;AACV,cAAM,QAAQ,MAAM,SAAS;AAC7B,cAAM,QAAQ,MAAM,SAAS,MAAM,SAAS;AAC5C,aAAK,UAAU,eAAe,QAAQ,OAAO,KAAK;AAClD,cAAM,SAAS,KAAK,MAAM,OAAO,KAAK,IAAI;AAE1C,cAAM,MAAM;AAAA,UACX,MAAM,SAAS;AAAA,UACf,MAAM,SAAS;AAAA,UACf,MAAM;AAAA,QACP;AACA,YAAI,IAAI,aAAa;AACpB,gBAAM,cAAc,IAAI;AACxB,iBAAO,eAAe,IAAI,KAAK;AAAA,QAChC;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAAA,EAEQ,mBAAmB,QAAgB,SAA+C;AACzF,QAAI,CAAC,KAAK,aAAa,KAAK,qBAAqB,IAAI,MAAM,EAAG;AAC9D,SAAK,UAAU,cAAc,QAAQ;AAAA,MACpC,OAAO,kBAAkB;AAAA,MACzB,OAAO,QAAQ,aAAa,eAAe;AAAA,MAC3C,cAAc,QAAQ,gBAAgB,eAAe;AAAA,IACtD,CAAC;AACD,SAAK,qBAAqB,IAAI,MAAM;AAAA,EACrC;AAAA,EAEA,QAAQ,MAAqB;AAC5B,SAAK,qBAAqB,MAAM;AAAA,EACjC;AACD;AAEO,IAAM,0BAA0B,eAIrC;AAAA,EACD,MAAM;AAAA,EACN;AAAA,EACA,eAAe,CAAC,QACf,IAAI,8BAA8B,IAAI,aAAa,MAAM,IAAI,gBAAgB;AAAA,EAC9E,cAAc;AACf,CAAC;","names":[]}
@@ -886,3 +886,4 @@ export {
886
886
  WasmStageRuntime,
887
887
  createWasmStageRuntime
888
888
  };
889
+ //# sourceMappingURL=chunk-4GW6DCYF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/runtime/wasm-stage-runtime.ts"],"sourcesContent":["/**\n * `WasmStageRuntime` — owns one wasm `WebAssembly.Instance` of\n * `@zylem/runtime` and exposes the unified-Stage FFI as typed TypeScript\n * methods. This is the single simulation adapter for the whole framework:\n * behavior systems talk to it through the {@link BehaviorRuntime} contract,\n * and hosts (e.g. `@zylem/game-lib`) drive it through\n * {@link createSimulation} in `./simulation`.\n */\n\nimport {\n\tloadStageFfi,\n\ttype StageWasmExports,\n\tSTAGE_RENDER_STRIDE,\n\tSTAGE_INPUT_STRIDE,\n\tSTAGE_SNAPSHOT_STRIDE,\n\tSTAGE_EVENT_STRIDE,\n} from '@zylem/runtime';\n\nexport {\n\tSTAGE_RENDER_STRIDE,\n\tSTAGE_INPUT_STRIDE,\n\tSTAGE_SNAPSHOT_STRIDE,\n\tSTAGE_EVENT_STRIDE,\n};\nexport type { StageWasmExports };\n\n/** Sentinel handle for \"no entity / failed allocation\". Mirrors `INVALID_SLOT` in Rust. */\nexport const STAGE_INVALID_SLOT = 0xffffffff;\n\nexport const StageBodyKind = {\n\tDynamic: 0,\n\tStatic: 1,\n\tKinematicPosition: 2,\n\tKinematicVelocity: 3,\n} as const;\n\nexport type StageBodyKindValue = (typeof StageBodyKind)[keyof typeof StageBodyKind];\n\nexport const StageBoundaryDim = {\n\tTwo: 2,\n\tThree: 3,\n} as const;\n\nexport const StageRicochetDim = {\n\tTwo: 2,\n\tThree: 3,\n} as const;\n\nexport const StageRicochetReflection = {\n\tMirror: 0,\n\tAngled: 1,\n} as const;\n\nexport const StageTopDownPlane = {\n\tXy: 0,\n\tXz: 1,\n} as const;\n\nexport const StageEventType = {\n\tCollisionStarted: 1,\n\tCollisionStopped: 2,\n\tBoundaryHit: 3,\n\tRicochet: 4,\n\tRegionEntered: 5,\n\tJumpStarted: 6,\n\tLanded: 7,\n\tWrapped: 8,\n\tCooldownFired: 9,\n} as const;\n\nexport type StageBoundaryDimValue = (typeof StageBoundaryDim)[keyof typeof StageBoundaryDim];\nexport type StageRicochetDimValue = (typeof StageRicochetDim)[keyof typeof StageRicochetDim];\nexport type StageRicochetReflectionValue =\n\t(typeof StageRicochetReflection)[keyof typeof StageRicochetReflection];\nexport type StageTopDownPlaneValue = (typeof StageTopDownPlane)[keyof typeof StageTopDownPlane];\n\n/** Position + rotation snapshot for one runtime slot. */\nexport interface StagePose {\n\tposition: [number, number, number];\n\trotation: [number, number, number, number];\n}\n\nexport interface StageWorldBoundaryOptions {\n\ttop: number;\n\tbottom: number;\n\tleft: number;\n\tright: number;\n\tfront?: number;\n\tback?: number;\n\tpadding?: number;\n}\n\nexport interface StageScreenWrapOptions {\n\twidth: number;\n\theight: number;\n\tcenterX?: number;\n\tcenterY?: number;\n\tedgeThreshold?: number;\n}\n\nexport interface StageRicochetOptions {\n\tminSpeed: number;\n\tmaxSpeed: number;\n\tspeedMultiplier: number;\n\tmaxAngleDeg: number;\n\treflectionMode: StageRicochetReflectionValue;\n}\n\nexport interface StageThrusterOptions {\n\tmaxSpeed: number;\n\tacceleration: number;\n\tturnRateRadPerSec: number;\n\tlinearDamping: number;\n}\n\nexport interface StageTopDownOptions {\n\tplane: StageTopDownPlaneValue;\n\tspeed: number;\n\tfaceMovement?: boolean;\n}\n\nexport interface StageShooter2DOptions {\n\tfireRateHz: number;\n\tmuzzleOffsetX: number;\n\tmuzzleOffsetY: number;\n\tmuzzleSpeed: number;\n}\n\nexport interface StageJumper2DOptions {\n\tjumpForce: number;\n\tmaxJumps: number;\n\tjumpBufferTime: number;\n\tcoyoteTime: number;\n\tgravity: number;\n}\n\nexport interface StageJumper3DOptions {\n\tjumpForce: number;\n\tmaxJumps: number;\n\tgravity: number;\n\t/** Coyote time in seconds (default 0.1). */\n\tcoyoteTime?: number;\n\t/** Jump buffer window in seconds (default 0.08). */\n\tjumpBufferTime?: number;\n}\n\nexport interface StagePlatformer3DOptions {\n\thalfHeight: number;\n\tradius: number;\n\twalkSpeed: number;\n\trunSpeed: number;\n\tjumpForce: number;\n\tmaxJumps: number;\n\tgravity: number;\n\t/** Coyote time in seconds (default 0.1). */\n\tcoyoteTime?: number;\n\t/** Jump buffer window in seconds (default 0.1). */\n\tjumpBufferTime?: number;\n\t/** Velocity multiplier applied on early jump release (default 0.5). */\n\tjumpCutMultiplier?: number;\n\t/** Seconds before a multi-jump becomes available (default 0.15). */\n\tmultiJumpWindow?: number;\n\t/** Max slope angle in degrees the KCC can climb (default 50). */\n\tslopeClimbAngle?: number;\n\t/** Slope angle in degrees past which the character slides (default 40). */\n\tslopeSlideAngle?: number;\n\t/** Autostep max height in world units; 0 disables (default 0.3). */\n\tautostepHeight?: number;\n\t/** Minimum unobstructed width for an autostep (default 0.1). */\n\tautostepMinWidth?: number;\n\t/** Snap-to-ground distance in world units; 0 disables (default 0.3). */\n\tsnapToGroundDistance?: number;\n\t/** KCC collision offset between collider and environment (default 0.05). */\n\tcharacterOffset?: number;\n\t/** Collider local offset X (fallback / override). */\n\toffsetX?: number;\n\t/** Collider local offset Y (fallback / override). */\n\toffsetY?: number;\n\t/** Collider local offset Z (fallback / override). */\n\toffsetZ?: number;\n\t/** 0 = auto-read attached collider; 1 = use stored shape fields. */\n\tshapeSource?: number;\n}\n\nexport const StagePlatformerShapeSource = {\n\tAuto: 0,\n\tOverride: 1,\n} as const;\n\nexport interface StagePlatformer2DOptions {\n\thalfHeight: number;\n\tradius: number;\n\twalkSpeed: number;\n\trunSpeed: number;\n\tjumpForce: number;\n\tmaxJumps: number;\n\tgravity: number;\n\t/** Coyote time in seconds (default 0.1). */\n\tcoyoteTime?: number;\n\t/** Jump buffer window in seconds (default 0.1). */\n\tjumpBufferTime?: number;\n\t/** Velocity multiplier applied on early jump release (default 0.5). */\n\tjumpCutMultiplier?: number;\n\t/** Seconds before a multi-jump becomes available (default 0.15). */\n\tmultiJumpWindow?: number;\n\t/** Max slope angle in degrees the KCC can climb (default 50). */\n\tslopeClimbAngle?: number;\n\t/** Slope angle in degrees past which the character slides (default 40). */\n\tslopeSlideAngle?: number;\n\t/** Autostep max height in world units; 0 disables (default 0.25). */\n\tautostepHeight?: number;\n\t/** Minimum unobstructed width for an autostep (default 0.05). */\n\tautostepMinWidth?: number;\n\t/** Snap-to-ground distance in world units; 0 disables (default 0.2). */\n\tsnapToGroundDistance?: number;\n\t/** KCC collision offset between collider and environment (default 0.05). */\n\tcharacterOffset?: number;\n\t/** Collider local offset X (fallback / override). */\n\toffsetX?: number;\n\t/** Collider local offset Y (fallback / override). */\n\toffsetY?: number;\n\t/** Collider local offset Z (fallback / override). */\n\toffsetZ?: number;\n\t/** 0 = auto-read attached collider; 1 = use stored shape fields. */\n\tshapeSource?: number;\n}\n\nexport interface StageFirstPersonOptions {\n\twalkSpeed: number;\n\trunSpeed: number;\n\teyeHeight: number;\n\tlookSensitivity: number;\n}\n\nexport interface StageFirstPersonInput {\n\tmoveX: number;\n\tmoveZ: number;\n\tlookYawDelta: number;\n\tlookPitchDelta: number;\n\trun: boolean;\n}\n\n/** Button bits for the slot-indexed input buffer's bitmask field. */\nexport const STAGE_INPUT_BUTTON_JUMP = 1;\nexport const STAGE_INPUT_BUTTON_RUN = 2;\n\n/**\n * Decoded per-slot behavior snapshot written by the runtime after every\n * step: movement fields come from whichever character behavior the entity\n * has (platformer 3D/2D, jumper 3D/2D); first-person fills yaw/pitch.\n * Values reflect the end of the previous `step()` (one-frame read lag).\n */\nexport interface StageBehaviorSnapshot {\n\tgrounded: boolean;\n\tfsmState: number;\n\tjumpCount: number;\n\tverticalVelocity: number;\n\tspeed: number;\n\tyaw: number;\n\tpitch: number;\n}\n\n/**\n * Wasm fast-path backrefs a behavior system stores on its `BehaviorRef` every\n * frame so descriptor handles can read the runtime snapshot buffer instead of\n * a duplicate TS FSM (or hardcoded defaults).\n */\nexport interface WasmSnapshotBackref {\n\t__wasmStage?: BehaviorRuntime | null;\n\t__entity?: { runtimeHandle?: number } | null;\n}\n\n/**\n * Read the behavior snapshot for the entity a `BehaviorRef` is linked to.\n * Returns `null` off the wasm fast path (no stage runtime / no\n * `runtimeHandle` / no snapshot yet), in which case handles should fall back\n * to their TS FSM.\n */\nexport function readBehaviorSnapshot(ref: object): StageBehaviorSnapshot | null {\n\tconst backref = ref as WasmSnapshotBackref;\n\tconst wasmStage = backref.__wasmStage;\n\tconst handle = backref.__entity?.runtimeHandle ?? -1;\n\tif (!wasmStage || handle < 0) return null;\n\treturn wasmStage.readSnapshot(handle);\n}\n\n/**\n * Runtime surface behavior systems rely on. `WasmStageRuntime` is the real\n * wasm-backed implementation; `MockBehaviorRuntime` (see\n * `./mock-behavior-runtime`) implements the same contract for unit tests, so\n * descriptors stay runtime-agnostic.\n */\nexport interface BehaviorRuntime {\n\tgetPose(handle: number, out?: StagePose): StagePose | null;\n\tsetPosition(handle: number, x: number, y: number, z: number): boolean;\n\tsetRotation(handle: number, x: number, y: number, z: number, w: number): boolean;\n\n\t// ─── Batched input / snapshot buffers (preferred fast path) ─────────\n\t// Field-scoped writes into the slot-indexed input buffer, consumed by\n\t// the runtime in one pass at the start of each step. Behaviors composed\n\t// on one entity each write only their part of the slot.\n\twriteInputAxes(handle: number, axisA: number, axisB: number): boolean;\n\twriteInputLook(handle: number, yawDelta: number, pitchDelta: number): boolean;\n\t/** Write reserved input slots (thruster world-space vector X/Y). */\n\twriteInputReserved(handle: number, reservedA: number, reservedB: number): boolean;\n\twriteInputButton(handle: number, buttonMask: number, pressed: boolean): boolean;\n\t/** Read the per-slot behavior snapshot written at the end of the previous step. */\n\treadSnapshot(handle: number, out?: StageBehaviorSnapshot): StageBehaviorSnapshot | null;\n\n\tattachThruster(handle: number, opts: StageThrusterOptions): boolean;\n\tsetThrusterInput(\n\t\thandle: number,\n\t\tthrust: number,\n\t\trotate: number,\n\t\tvectorX?: number,\n\t\tvectorY?: number,\n\t): void;\n\n\tattachTopDown(handle: number, opts: StageTopDownOptions): boolean;\n\tsetTopDownInput(handle: number, moveX: number, moveY: number): void;\n\n\tattachShooter2D(handle: number, opts: StageShooter2DOptions): boolean;\n\n\tattachScreenWrap(handle: number, opts: StageScreenWrapOptions): boolean;\n\tqueryScreenWrap(handle: number): { fsm: number; lastWrappedAxes: number } | null;\n\n\tattachWorldBoundary(\n\t\thandle: number,\n\t\tdim: StageBoundaryDimValue,\n\t\topts: StageWorldBoundaryOptions,\n\t): boolean;\n\tqueryWorldBoundary(handle: number): { hits: number; clamped: [number, number, number] } | null;\n\n\tattachRicochet(handle: number, dim: StageRicochetDimValue, opts: StageRicochetOptions): boolean;\n\n\tattachPlatformer3D(handle: number, opts: StagePlatformer3DOptions): boolean;\n\tsetPlatformer3DInputAxes(handle: number, moveX: number, moveZ: number): void;\n\tsetPlatformer3DInputButtons(handle: number, jump: boolean, run: boolean): void;\n\n\tattachPlatformer2D(handle: number, opts: StagePlatformer2DOptions): boolean;\n\tsetPlatformer2DInputAxes(handle: number, moveX: number): void;\n\tsetPlatformer2DInputButtons(handle: number, jump: boolean, run: boolean): void;\n\n\tattachFirstPerson(handle: number, opts: StageFirstPersonOptions): boolean;\n\tsetFirstPersonInput(handle: number, input: StageFirstPersonInput): void;\n\n\tattachJumper2D(handle: number, opts: StageJumper2DOptions): boolean;\n\tsetJumper2DInput(handle: number, jumpPressed: boolean): void;\n\n\tattachJumper3D(handle: number, opts: StageJumper3DOptions): boolean;\n\tsetJumper3DInput(handle: number, jumpPressed: boolean): void;\n}\n\n/** Default options used when constructing a wasm-backed Stage runtime. */\nexport interface WasmStageRuntimeOptions {\n\tinitialCapacity?: number;\n\tgravity?: readonly [number, number, number];\n\timports?: WebAssembly.Imports;\n\t/**\n\t * Custom wasm source. Defaults to the `zylem_runtime.wasm` bundled with\n\t * `@zylem/runtime`.\n\t */\n\tsource?: RequestInfo | URL | ArrayBuffer | Uint8Array;\n}\n\nexport type StageEventTypeValue = (typeof StageEventType)[keyof typeof StageEventType];\n\n/** One decoded event drained from the runtime's per-step event buffer. */\nexport interface StageEvent {\n\ttype: StageEventTypeValue;\n\tprimarySlot: number | null;\n\tsecondarySlot: number | null;\n\tpayload: [number, number, number];\n}\n\n/**\n * Decoded view of one entity's slot in the unified render buffer.\n *\n * Mirrors the `STAGE_RENDER_STRIDE` (12-float) packing documented in\n * `runtime/stage/render.rs`:\n * `[0..3]` position, `[3..7]` rotation xyzw, `[7]` uniform scale,\n * `[8..11]` custom0..custom2 (shading hints), `[11]` custom3 sleeping flag\n * (1.0 = sleeping).\n */\nexport interface StageRenderSlot {\n\tposition: [number, number, number];\n\trotation: [number, number, number, number];\n\tscale: number;\n\tcustom: [number, number, number, number];\n\t/** True when custom[3] indicates the body is sleeping. */\n\tisSleeping: boolean;\n}\n\n/**\n * Read a single entity slot out of a unified-Stage render buffer view.\n *\n * @param view The `Float32Array` over wasm memory (e.g. `WasmStageRuntime.render`).\n * @param slot The entity's wasm slot id (its `runtimeHandle`).\n * @param out Optional target object to write into (avoids per-call allocation).\n * @returns The decoded slot, or `null` when the slot is out of range.\n */\nexport function readStageRenderSlot(\n\tview: Float32Array,\n\tslot: number,\n\tout?: StageRenderSlot,\n): StageRenderSlot | null {\n\tconst base = slot * STAGE_RENDER_STRIDE;\n\tif (slot < 0 || base + STAGE_RENDER_STRIDE > view.length) {\n\t\treturn null;\n\t}\n\tconst result: StageRenderSlot = out ?? {\n\t\tposition: [0, 0, 0],\n\t\trotation: [0, 0, 0, 1],\n\t\tscale: 1,\n\t\tcustom: [0, 0, 0, 0],\n\t\tisSleeping: false,\n\t};\n\tresult.position[0] = view[base]!;\n\tresult.position[1] = view[base + 1]!;\n\tresult.position[2] = view[base + 2]!;\n\tresult.rotation[0] = view[base + 3]!;\n\tresult.rotation[1] = view[base + 4]!;\n\tresult.rotation[2] = view[base + 5]!;\n\tresult.rotation[3] = view[base + 6]!;\n\t// A freshly-zeroed slot reports scale 0; treat that as the identity scale so\n\t// entities aren't collapsed before the runtime writes a real value.\n\tconst scale = view[base + 7]!;\n\tresult.scale = scale === 0 ? 1 : scale;\n\tresult.custom[0] = view[base + 8]!;\n\tresult.custom[1] = view[base + 9]!;\n\tresult.custom[2] = view[base + 10]!;\n\tresult.custom[3] = view[base + 11]!;\n\tresult.isSleeping = result.custom[3] > 0.5;\n\treturn result;\n}\n\nexport interface StageBodyConfig {\n\tkind: StageBodyKindValue;\n\tposition: readonly [number, number, number];\n\trotation: readonly [number, number, number, number];\n\tlinearDamping: number;\n\tangularDamping: number;\n\tgravityScale: number;\n\tcanSleep: boolean;\n\tccdEnabled: boolean;\n\tlockRotation: readonly [boolean, boolean, boolean];\n\tlockTranslation: readonly [boolean, boolean, boolean];\n}\n\nexport type StageColliderShape =\n\t| { type: 'box'; halfExtents: readonly [number, number, number] }\n\t| { type: 'sphere'; radius: number }\n\t| { type: 'capsule'; halfHeight: number; radius: number }\n\t| { type: 'cylinder'; halfHeight: number; radius: number }\n\t| { type: 'cone'; halfHeight: number; radius: number }\n\t| { type: 'convexHull'; vertices: Float32Array }\n\t| { type: 'trimesh'; vertices: Float32Array; indices: Uint32Array }\n\t| {\n\t\ttype: 'heightfield';\n\t\trows: number;\n\t\tcols: number;\n\t\tscale: readonly [number, number, number];\n\t\theights: Float32Array;\n\t};\n\nexport interface StageColliderConfig {\n\tshape: StageColliderShape;\n\toffset: readonly [number, number, number];\n\tfriction: number;\n\trestitution: number;\n\tsensor: boolean;\n\t/** Packed interaction-groups: high 16 bits = membership, low 16 bits = filter. */\n\tcollisionGroups: number;\n}\n\n/** Result of a physics raycast against the stage. */\nexport interface StageRaycastHit {\n\tslot: number;\n\tdistance: number;\n\tnormal: [number, number, number];\n}\n\n/** Body introspection payload for debug tooling. */\nexport interface StageBodyInfo {\n\tbodyType: number;\n\tmass: number;\n\tisSleeping: boolean;\n\tisEnabled: boolean;\n\tlinearVelocity: [number, number, number];\n}\n\n/** Line-list wireframe for physics debug rendering. */\nexport interface StageDebugRender {\n\t/** `[x, y, z]` per vertex, two vertices per line. */\n\tvertices: Float32Array;\n\t/** RGBA per vertex. */\n\tcolors: Float32Array;\n}\n\n/**\n * Owns the wasm instance plus the live float-views over its render / event /\n * pose / scratch buffers. One instance per logical stage; each stage gets\n * its own `WebAssembly.Instance` so the singleton inside `stage_ffi.rs`\n * stays single-stage scoped (today's `thread_local!` contract).\n */\nexport class WasmStageRuntime implements BehaviorRuntime {\n\treadonly exports: StageWasmExports;\n\tprivate readonly memory: WebAssembly.Memory;\n\tprivate renderView: Float32Array = new Float32Array(0);\n\tprivate inputView: Float32Array = new Float32Array(0);\n\tprivate snapshotView: Float32Array = new Float32Array(0);\n\tprivate eventView: Float32Array = new Float32Array(0);\n\tprivate poseView: Float32Array = new Float32Array(0);\n\tprivate vec3View: Float32Array = new Float32Array(0);\n\tprivate queryView: Float32Array = new Float32Array(0);\n\tprivate scratchView: Float32Array = new Float32Array(0);\n\n\tconstructor(exports: StageWasmExports, options: WasmStageRuntimeOptions = {}) {\n\t\tthis.exports = exports;\n\t\tthis.memory = exports.memory;\n\t\tconst capacity = Math.max(options.initialCapacity ?? 64, 8);\n\t\texports.zylem_stage_create(capacity);\n\t\tif (options.gravity) {\n\t\t\texports.zylem_stage_set_gravity(\n\t\t\t\toptions.gravity[0],\n\t\t\t\toptions.gravity[1],\n\t\t\t\toptions.gravity[2],\n\t\t\t);\n\t\t}\n\t\tthis.refreshViews();\n\t}\n\n\t/** Recreate typed views over wasm memory. Call after step() or whenever memory may have grown. */\n\trefreshViews(): void {\n\t\tconst buffer = this.memory.buffer;\n\t\tconst renderPtr = this.exports.zylem_stage_render_ptr();\n\t\tconst renderLen = this.exports.zylem_stage_render_len();\n\t\tconst inputPtr = this.exports.zylem_stage_input_ptr();\n\t\tconst inputLen = this.exports.zylem_stage_input_len();\n\t\tconst snapshotPtr = this.exports.zylem_stage_snapshot_ptr();\n\t\tconst snapshotLen = this.exports.zylem_stage_snapshot_len();\n\t\tconst eventPtr = this.exports.zylem_stage_event_ptr();\n\t\tconst eventLen = this.exports.zylem_stage_event_len();\n\t\tconst posePtr = this.exports.zylem_stage_pose_ptr();\n\t\tconst poseLen = this.exports.zylem_stage_pose_len();\n\t\tconst vec3Ptr = this.exports.zylem_stage_vec3_ptr();\n\t\tconst queryPtr = this.exports.zylem_stage_query_ptr();\n\t\tconst queryLen = this.exports.zylem_stage_query_len();\n\t\tconst scratchPtr = this.exports.zylem_stage_scratch_ptr();\n\t\tconst scratchCap = this.exports.zylem_stage_scratch_capacity();\n\n\t\tthis.renderView = renderLen > 0 ? new Float32Array(buffer, renderPtr, renderLen) : new Float32Array(0);\n\t\tthis.inputView = inputLen > 0 ? new Float32Array(buffer, inputPtr, inputLen) : new Float32Array(0);\n\t\tthis.snapshotView = snapshotLen > 0 ? new Float32Array(buffer, snapshotPtr, snapshotLen) : new Float32Array(0);\n\t\tthis.eventView = eventLen > 0 ? new Float32Array(buffer, eventPtr, eventLen) : new Float32Array(0);\n\t\tthis.poseView = poseLen > 0 ? new Float32Array(buffer, posePtr, poseLen) : new Float32Array(0);\n\t\tthis.vec3View = vec3Ptr !== 0 ? new Float32Array(buffer, vec3Ptr, 3) : new Float32Array(0);\n\t\tthis.queryView = queryLen > 0 ? new Float32Array(buffer, queryPtr, queryLen) : new Float32Array(0);\n\t\tthis.scratchView = scratchCap > 0 ? new Float32Array(buffer, scratchPtr, scratchCap) : new Float32Array(0);\n\t}\n\n\t/** Step the simulation by `dt` seconds. Refreshes views afterwards. */\n\tstep(dt: number): number {\n\t\tconst active = this.exports.zylem_stage_step(dt);\n\t\tthis.refreshViews();\n\t\treturn active;\n\t}\n\n\tdispose(): void {\n\t\tthis.exports.zylem_stage_destroy();\n\t}\n\n\tget tickCount(): number {\n\t\treturn this.exports.zylem_stage_tick_count() >>> 0;\n\t}\n\n\tget activeCount(): number {\n\t\treturn this.exports.zylem_stage_active_count() >>> 0;\n\t}\n\n\tsetGravity(x: number, y: number, z: number): void {\n\t\tthis.exports.zylem_stage_set_gravity(x, y, z);\n\t}\n\n\t/**\n\t * Toggle per-step collision-event collection in the wasm stage. Hosts\n\t * with no collision listeners should disable it — with thousands of\n\t * touching bodies the per-step contact-pair hashing is a significant\n\t * fraction of `step()`.\n\t */\n\tsetEventsEnabled(enabled: boolean): void {\n\t\tthis.exports.zylem_stage_set_events_enabled(enabled ? 1 : 0);\n\t}\n\n\t/** Cap Rapier contact solver iterations (default 4). */\n\tsetSolverIterations(iterations: number): void {\n\t\tthis.exports.zylem_stage_set_solver_iterations(Math.max(1, iterations | 0));\n\t}\n\n\t/**\n\t * Override sleep activation thresholds for sleep-capable dynamic bodies.\n\t * Higher velocity thresholds / lower `timeUntilSleep` put piles to sleep\n\t * sooner.\n\t */\n\tsetSleepThresholds(\n\t\tnormalizedLinearThreshold: number,\n\t\tangularThreshold: number,\n\t\ttimeUntilSleep: number,\n\t): void {\n\t\tthis.exports.zylem_stage_set_sleep_thresholds(\n\t\t\tnormalizedLinearThreshold,\n\t\t\tangularThreshold,\n\t\t\ttimeUntilSleep,\n\t\t);\n\t}\n\n\t/** Number of awake (non-sleeping) dynamic rigid bodies. */\n\tawakeDynamicCount(): number {\n\t\treturn this.exports.zylem_stage_awake_dynamic_count();\n\t}\n\n\t// ─── Entity lifecycle ───────────────────────────────────────────────\n\n\tcreateEntity(): number {\n\t\tconst slot = this.exports.zylem_stage_create_entity() >>> 0;\n\t\t// The wasm may have grown memory while resizing the slot table; refresh views.\n\t\tthis.refreshViews();\n\t\treturn slot;\n\t}\n\n\tdestroyEntity(slot: number): boolean {\n\t\treturn this.exports.zylem_stage_destroy_entity(slot) !== 0;\n\t}\n\n\t// ─── Body / collider attach ────────────────────────────────────────\n\n\tattachBody(slot: number, config: StageBodyConfig): boolean {\n\t\tconst ok = this.exports.zylem_stage_attach_body(\n\t\t\tslot,\n\t\t\tconfig.kind,\n\t\t\tconfig.position[0], config.position[1], config.position[2],\n\t\t\tconfig.rotation[0], config.rotation[1], config.rotation[2], config.rotation[3],\n\t\t\tconfig.linearDamping,\n\t\t\tconfig.angularDamping,\n\t\t\tconfig.gravityScale,\n\t\t\tconfig.canSleep ? 1 : 0,\n\t\t\tconfig.ccdEnabled ? 1 : 0,\n\t\t\tconfig.lockRotation[0] ? 1 : 0, config.lockRotation[1] ? 1 : 0, config.lockRotation[2] ? 1 : 0,\n\t\t\tconfig.lockTranslation[0] ? 1 : 0, config.lockTranslation[1] ? 1 : 0, config.lockTranslation[2] ? 1 : 0,\n\t\t);\n\t\treturn ok !== 0;\n\t}\n\n\taddCollider(slot: number, config: StageColliderConfig): boolean {\n\t\tconst offset = config.offset;\n\t\tconst sensor = config.sensor ? 1 : 0;\n\t\tconst groups = config.collisionGroups >>> 0;\n\t\tconst friction = config.friction;\n\t\tconst restitution = config.restitution;\n\t\tswitch (config.shape.type) {\n\t\t\tcase 'box': {\n\t\t\t\tconst [hx, hy, hz] = config.shape.halfExtents;\n\t\t\t\treturn (\n\t\t\t\t\tthis.exports.zylem_stage_add_collider_box(\n\t\t\t\t\t\tslot, hx, hy, hz, offset[0], offset[1], offset[2],\n\t\t\t\t\t\tfriction, restitution, sensor, groups,\n\t\t\t\t\t) !== 0\n\t\t\t\t);\n\t\t\t}\n\t\t\tcase 'sphere': {\n\t\t\t\treturn (\n\t\t\t\t\tthis.exports.zylem_stage_add_collider_sphere(\n\t\t\t\t\t\tslot, config.shape.radius, offset[0], offset[1], offset[2],\n\t\t\t\t\t\tfriction, restitution, sensor, groups,\n\t\t\t\t\t) !== 0\n\t\t\t\t);\n\t\t\t}\n\t\t\tcase 'capsule': {\n\t\t\t\treturn (\n\t\t\t\t\tthis.exports.zylem_stage_add_collider_capsule(\n\t\t\t\t\t\tslot, config.shape.halfHeight, config.shape.radius,\n\t\t\t\t\t\toffset[0], offset[1], offset[2], friction, restitution, sensor, groups,\n\t\t\t\t\t) !== 0\n\t\t\t\t);\n\t\t\t}\n\t\t\tcase 'cylinder': {\n\t\t\t\treturn (\n\t\t\t\t\tthis.exports.zylem_stage_add_collider_cylinder(\n\t\t\t\t\t\tslot, config.shape.halfHeight, config.shape.radius,\n\t\t\t\t\t\toffset[0], offset[1], offset[2], friction, restitution, sensor, groups,\n\t\t\t\t\t) !== 0\n\t\t\t\t);\n\t\t\t}\n\t\t\tcase 'cone': {\n\t\t\t\treturn (\n\t\t\t\t\tthis.exports.zylem_stage_add_collider_cone(\n\t\t\t\t\t\tslot, config.shape.halfHeight, config.shape.radius,\n\t\t\t\t\t\toffset[0], offset[1], offset[2], friction, restitution, sensor, groups,\n\t\t\t\t\t) !== 0\n\t\t\t\t);\n\t\t\t}\n\t\t\tcase 'convexHull': {\n\t\t\t\tconst verts = config.shape.vertices;\n\t\t\t\tif (verts.length % 3 !== 0) return false;\n\t\t\t\tconst offsetFloats = this.stageScratch(verts);\n\t\t\t\treturn (\n\t\t\t\t\tthis.exports.zylem_stage_add_collider_convex_hull(\n\t\t\t\t\t\tslot, offsetFloats, verts.length / 3,\n\t\t\t\t\t\toffset[0], offset[1], offset[2], friction, restitution, sensor, groups,\n\t\t\t\t\t) !== 0\n\t\t\t\t);\n\t\t\t}\n\t\t\tcase 'trimesh': {\n\t\t\t\tconst verts = config.shape.vertices;\n\t\t\t\tconst indices = config.shape.indices;\n\t\t\t\tif (verts.length % 3 !== 0 || indices.length % 3 !== 0) return false;\n\t\t\t\tconst vertOffset = this.stageScratch(verts);\n\t\t\t\tconst indexOffset = this.stageScratchIndices(indices, vertOffset + verts.length);\n\t\t\t\treturn (\n\t\t\t\t\tthis.exports.zylem_stage_add_collider_trimesh(\n\t\t\t\t\t\tslot, vertOffset, verts.length / 3, indexOffset, indices.length,\n\t\t\t\t\t\toffset[0], offset[1], offset[2], friction, restitution, sensor, groups,\n\t\t\t\t\t) !== 0\n\t\t\t\t);\n\t\t\t}\n\t\t\tcase 'heightfield': {\n\t\t\t\tconst heights = config.shape.heights;\n\t\t\t\tconst heightOffset = this.stageScratch(heights);\n\t\t\t\treturn (\n\t\t\t\t\tthis.exports.zylem_stage_add_collider_heightfield(\n\t\t\t\t\t\tslot, config.shape.rows, config.shape.cols,\n\t\t\t\t\t\tconfig.shape.scale[0], config.shape.scale[1], config.shape.scale[2],\n\t\t\t\t\t\theightOffset, offset[0], offset[1], offset[2],\n\t\t\t\t\t\tfriction, restitution, sensor, groups,\n\t\t\t\t\t) !== 0\n\t\t\t\t);\n\t\t\t}\n\t\t\tdefault: {\n\t\t\t\tconst _exhaustive: never = config.shape;\n\t\t\t\tvoid _exhaustive;\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate stageScratch(values: Float32Array, baseOffset = 0): number {\n\t\tthis.scratchView.set(values, baseOffset);\n\t\treturn baseOffset;\n\t}\n\n\tprivate stageScratchIndices(indices: Uint32Array, baseOffset: number): number {\n\t\tfor (let i = 0; i < indices.length; i++) {\n\t\t\tthis.scratchView[baseOffset + i] = indices[i]!;\n\t\t}\n\t\treturn baseOffset;\n\t}\n\n\t// ─── Pose / velocity ───────────────────────────────────────────────\n\n\tgetPose(slot: number, out?: StagePose): StagePose | null {\n\t\tconst ok = this.exports.zylem_stage_get_pose(slot) !== 0;\n\t\tif (!ok) return null;\n\t\tconst v = this.poseView;\n\t\tconst result: StagePose = out ?? {\n\t\t\tposition: [0, 0, 0],\n\t\t\trotation: [0, 0, 0, 1],\n\t\t};\n\t\tresult.position[0] = v[0]!;\n\t\tresult.position[1] = v[1]!;\n\t\tresult.position[2] = v[2]!;\n\t\tresult.rotation[0] = v[3]!;\n\t\tresult.rotation[1] = v[4]!;\n\t\tresult.rotation[2] = v[5]!;\n\t\tresult.rotation[3] = v[6]!;\n\t\treturn result;\n\t}\n\n\tsetPosition(slot: number, x: number, y: number, z: number): boolean {\n\t\treturn this.exports.zylem_stage_set_position(slot, x, y, z) !== 0;\n\t}\n\n\tsetRotation(slot: number, x: number, y: number, z: number, w: number): boolean {\n\t\treturn this.exports.zylem_stage_set_rotation(slot, x, y, z, w) !== 0;\n\t}\n\n\tsetLinearVelocity(slot: number, x: number, y: number, z: number): boolean {\n\t\treturn this.exports.zylem_stage_set_linvel(slot, x, y, z) !== 0;\n\t}\n\n\tgetLinearVelocity(slot: number, out?: [number, number, number]): [number, number, number] | null {\n\t\tif (this.exports.zylem_stage_get_linvel(slot) === 0) return null;\n\t\tconst v = this.vec3View;\n\t\tconst result = out ?? ([0, 0, 0] as [number, number, number]);\n\t\tresult[0] = v[0]!;\n\t\tresult[1] = v[1]!;\n\t\tresult[2] = v[2]!;\n\t\treturn result;\n\t}\n\n\tsetAngularVelocity(slot: number, x: number, y: number, z: number): boolean {\n\t\treturn this.exports.zylem_stage_set_angvel(slot, x, y, z) !== 0;\n\t}\n\n\tgetAngularVelocity(slot: number, out?: [number, number, number]): [number, number, number] | null {\n\t\tif (this.exports.zylem_stage_get_angvel(slot) === 0) return null;\n\t\tconst v = this.vec3View;\n\t\tconst result = out ?? ([0, 0, 0] as [number, number, number]);\n\t\tresult[0] = v[0]!;\n\t\tresult[1] = v[1]!;\n\t\tresult[2] = v[2]!;\n\t\treturn result;\n\t}\n\n\tapplyImpulse(slot: number, x: number, y: number, z: number): boolean {\n\t\treturn this.exports.zylem_stage_apply_impulse(slot, x, y, z) !== 0;\n\t}\n\n\t// ─── Queries / diagnostics ─────────────────────────────────────────\n\n\t/** Cast a ray against the physics world. Returns the closest hit or `null`. */\n\tcastRay(\n\t\torigin: readonly [number, number, number],\n\t\tdir: readonly [number, number, number],\n\t\tmaxDistance: number,\n\t\tsolidOnly = true,\n\t): StageRaycastHit | null {\n\t\tconst hit = this.exports.zylem_stage_cast_ray(\n\t\t\torigin[0], origin[1], origin[2],\n\t\t\tdir[0], dir[1], dir[2],\n\t\t\tmaxDistance, solidOnly ? 1 : 0,\n\t\t);\n\t\tif (hit === 0) return null;\n\t\tconst v = this.queryView;\n\t\treturn {\n\t\t\tslot: v[0]! >>> 0,\n\t\t\tdistance: v[1]!,\n\t\t\tnormal: [v[2]!, v[3]!, v[4]!],\n\t\t};\n\t}\n\n\t/** Body introspection for debug tooling. */\n\tgetBodyInfo(slot: number): StageBodyInfo | null {\n\t\tif (this.exports.zylem_stage_body_info(slot) === 0) return null;\n\t\tconst v = this.queryView;\n\t\treturn {\n\t\t\tbodyType: v[0]! | 0,\n\t\t\tmass: v[1]!,\n\t\t\tisSleeping: v[2]! > 0.5,\n\t\t\tisEnabled: v[3]! > 0.5,\n\t\t\tlinearVelocity: [v[4]!, v[5]!, v[6]!],\n\t\t};\n\t}\n\n\t/** Wireframe debug render of every collider (all shapes). */\n\tgetDebugRender(): StageDebugRender | null {\n\t\tconst vertexCount = this.exports.zylem_stage_debug_render() >>> 0;\n\t\tthis.refreshViews();\n\t\tif (vertexCount === 0) return null;\n\t\tconst buffer = this.memory.buffer;\n\t\tconst vertices = new Float32Array(\n\t\t\tbuffer,\n\t\t\tthis.exports.zylem_stage_debug_vertices_ptr(),\n\t\t\tthis.exports.zylem_stage_debug_vertices_len(),\n\t\t);\n\t\tconst colors = new Float32Array(\n\t\t\tbuffer,\n\t\t\tthis.exports.zylem_stage_debug_colors_ptr(),\n\t\t\tthis.exports.zylem_stage_debug_colors_len(),\n\t\t);\n\t\treturn {\n\t\t\tvertices: new Float32Array(vertices),\n\t\t\tcolors: new Float32Array(colors),\n\t\t};\n\t}\n\n\t// ─── Render / event reads ──────────────────────────────────────────\n\n\t/** Read-only view over the render buffer; one slot occupies {@link STAGE_RENDER_STRIDE} floats. */\n\tget render(): Float32Array {\n\t\treturn this.renderView;\n\t}\n\n\tget renderStride(): number {\n\t\treturn STAGE_RENDER_STRIDE;\n\t}\n\n\t/**\n\t * Decode a single entity slot from the live render buffer. Convenience\n\t * wrapper over {@link readStageRenderSlot} bound to this runtime's view.\n\t */\n\treadRenderSlot(slot: number, out?: StageRenderSlot): StageRenderSlot | null {\n\t\treturn readStageRenderSlot(this.renderView, slot, out);\n\t}\n\n\t/** Drain the wasm event buffer into a fresh array of typed events. */\n\tdrainEvents(): StageEvent[] {\n\t\tconst count = this.exports.zylem_stage_event_count() >>> 0;\n\t\tif (count === 0) return [];\n\t\tconst view = this.eventView;\n\t\tconst events: StageEvent[] = new Array(count);\n\t\tfor (let i = 0; i < count; i++) {\n\t\t\tconst base = i * STAGE_EVENT_STRIDE;\n\t\t\tconst primaryRaw = view[base + 1]!;\n\t\t\tconst secondaryRaw = view[base + 2]!;\n\t\t\tevents[i] = {\n\t\t\t\ttype: (view[base]! | 0) as StageEventTypeValue,\n\t\t\t\tprimarySlot: Number.isNaN(primaryRaw) ? null : primaryRaw >>> 0,\n\t\t\t\tsecondarySlot: Number.isNaN(secondaryRaw) ? null : secondaryRaw >>> 0,\n\t\t\t\tpayload: [view[base + 3]!, view[base + 4]!, view[base + 5]!],\n\t\t\t};\n\t\t}\n\t\treturn events;\n\t}\n\n\t// ─── Batched input / snapshot buffers ─────────────────────────────\n\n\t/** Writable view over the slot-indexed input buffer ({@link STAGE_INPUT_STRIDE} floats/slot). */\n\tget input(): Float32Array {\n\t\treturn this.inputView;\n\t}\n\n\tget inputStride(): number {\n\t\treturn STAGE_INPUT_STRIDE;\n\t}\n\n\t/** Read-only view over the per-slot behavior snapshot buffer ({@link STAGE_SNAPSHOT_STRIDE} floats/slot). */\n\tget snapshot(): Float32Array {\n\t\treturn this.snapshotView;\n\t}\n\n\tget snapshotStride(): number {\n\t\treturn STAGE_SNAPSHOT_STRIDE;\n\t}\n\n\t/**\n\t * Write the primary movement axes for a slot into the slot-indexed input\n\t * buffer and mark the slot dirty. Field-scoped (doesn't touch look\n\t * deltas or buttons) so multiple behaviors composed on one entity can\n\t * each write their part.\n\t */\n\twriteInputAxes(slot: number, axisA: number, axisB: number): boolean {\n\t\tconst base = slot * STAGE_INPUT_STRIDE;\n\t\tconst view = this.inputView;\n\t\tif (slot < 0 || base + STAGE_INPUT_STRIDE > view.length) return false;\n\t\tview[base] = axisA;\n\t\tview[base + 1] = axisB;\n\t\tview[base + 7] = 1;\n\t\treturn true;\n\t}\n\n\t/** Write the look deltas (first-person yaw/pitch) for a slot. */\n\twriteInputLook(slot: number, yawDelta: number, pitchDelta: number): boolean {\n\t\tconst base = slot * STAGE_INPUT_STRIDE;\n\t\tconst view = this.inputView;\n\t\tif (slot < 0 || base + STAGE_INPUT_STRIDE > view.length) return false;\n\t\tview[base + 2] = yawDelta;\n\t\tview[base + 3] = pitchDelta;\n\t\tview[base + 7] = 1;\n\t\treturn true;\n\t}\n\n\t/** Write reserved input slots (thruster world-space vector X/Y). */\n\twriteInputReserved(slot: number, reservedA: number, reservedB: number): boolean {\n\t\tconst base = slot * STAGE_INPUT_STRIDE;\n\t\tconst view = this.inputView;\n\t\tif (slot < 0 || base + STAGE_INPUT_STRIDE > view.length) return false;\n\t\tview[base + 5] = reservedA;\n\t\tview[base + 6] = reservedB;\n\t\tview[base + 7] = 1;\n\t\treturn true;\n\t}\n\n\t/**\n\t * Set or clear one button bit ({@link STAGE_INPUT_BUTTON_JUMP} /\n\t * {@link STAGE_INPUT_BUTTON_RUN}) in a slot's input bitmask.\n\t */\n\twriteInputButton(slot: number, buttonMask: number, pressed: boolean): boolean {\n\t\tconst base = slot * STAGE_INPUT_STRIDE;\n\t\tconst view = this.inputView;\n\t\tif (slot < 0 || base + STAGE_INPUT_STRIDE > view.length) return false;\n\t\tconst current = view[base + 4]! | 0;\n\t\tview[base + 4] = pressed ? (current | buttonMask) : (current & ~buttonMask);\n\t\tview[base + 7] = 1;\n\t\treturn true;\n\t}\n\n\t/**\n\t * Decode a slot's behavior snapshot from the buffer written at the end of\n\t * the previous step. Returns `null` when the slot has no behavior data.\n\t */\n\treadSnapshot(slot: number, out?: StageBehaviorSnapshot): StageBehaviorSnapshot | null {\n\t\tconst base = slot * STAGE_SNAPSHOT_STRIDE;\n\t\tconst view = this.snapshotView;\n\t\tif (slot < 0 || base + STAGE_SNAPSHOT_STRIDE > view.length) return null;\n\t\tif (view[base + 7] === 0) return null;\n\t\tconst result: StageBehaviorSnapshot = out ?? {\n\t\t\tgrounded: false,\n\t\t\tfsmState: 0,\n\t\t\tjumpCount: 0,\n\t\t\tverticalVelocity: 0,\n\t\t\tspeed: 0,\n\t\t\tyaw: 0,\n\t\t\tpitch: 0,\n\t\t};\n\t\tresult.grounded = view[base]! > 0.5;\n\t\tresult.fsmState = view[base + 1]! | 0;\n\t\tresult.jumpCount = view[base + 2]! | 0;\n\t\tresult.verticalVelocity = view[base + 3]!;\n\t\tresult.speed = view[base + 4]!;\n\t\tresult.yaw = view[base + 5]!;\n\t\tresult.pitch = view[base + 6]!;\n\t\treturn result;\n\t}\n\n\t// ─── Behavior helpers ─────────────────────────────────────────────\n\n\tget queryScratch(): Float32Array {\n\t\treturn this.queryView;\n\t}\n\n\tattachCooldown(slot: number): boolean {\n\t\treturn this.exports.zylem_stage_attach_cooldown(slot) !== 0;\n\t}\n\n\tregisterCooldown(slot: number, id: number, durationSeconds: number, immediate = false): boolean {\n\t\treturn (\n\t\t\tthis.exports.zylem_stage_cooldown_register(slot, id >>> 0, durationSeconds, immediate ? 1 : 0) !== 0\n\t\t);\n\t}\n\n\tfireCooldown(slot: number, id: number): boolean {\n\t\treturn this.exports.zylem_stage_cooldown_fire(slot, id >>> 0) !== 0;\n\t}\n\n\tresetCooldown(slot: number, id: number): boolean {\n\t\treturn this.exports.zylem_stage_cooldown_reset(slot, id >>> 0) !== 0;\n\t}\n\n\tcooldownRemaining(slot: number, id: number): number {\n\t\treturn this.exports.zylem_stage_cooldown_remaining(slot, id >>> 0);\n\t}\n\n\tattachWorldBoundary(\n\t\tslot: number,\n\t\tdim: StageBoundaryDimValue,\n\t\tbounds: StageWorldBoundaryOptions,\n\t): boolean {\n\t\treturn (\n\t\t\tthis.exports.zylem_stage_attach_world_boundary(\n\t\t\t\tslot,\n\t\t\t\tdim,\n\t\t\t\tbounds.top, bounds.bottom, bounds.left, bounds.right,\n\t\t\t\tbounds.front ?? 0, bounds.back ?? 0, bounds.padding ?? 0,\n\t\t\t) !== 0\n\t\t);\n\t}\n\n\tqueryWorldBoundary(slot: number): { hits: number; clamped: [number, number, number] } | null {\n\t\tif (this.exports.zylem_stage_query_world_boundary(slot) === 0) return null;\n\t\tconst v = this.queryView;\n\t\treturn {\n\t\t\thits: v[0]! | 0,\n\t\t\tclamped: [v[1]!, v[2]!, v[3]!],\n\t\t};\n\t}\n\n\tattachScreenWrap(slot: number, opts: StageScreenWrapOptions): boolean {\n\t\treturn (\n\t\t\tthis.exports.zylem_stage_attach_screen_wrap(\n\t\t\t\tslot, opts.width, opts.height,\n\t\t\t\topts.centerX ?? 0, opts.centerY ?? 0, opts.edgeThreshold ?? 0,\n\t\t\t) !== 0\n\t\t);\n\t}\n\n\tqueryScreenWrap(slot: number): { fsm: number; lastWrappedAxes: number } | null {\n\t\tif (this.exports.zylem_stage_query_screen_wrap(slot) === 0) return null;\n\t\tconst v = this.queryView;\n\t\treturn { fsm: v[0]! | 0, lastWrappedAxes: v[1]! | 0 };\n\t}\n\n\tattachRicochet(\n\t\tslot: number,\n\t\tdim: StageRicochetDimValue,\n\t\topts: StageRicochetOptions,\n\t): boolean {\n\t\treturn (\n\t\t\tthis.exports.zylem_stage_attach_ricochet(\n\t\t\t\tslot, dim, opts.minSpeed, opts.maxSpeed, opts.speedMultiplier,\n\t\t\t\topts.maxAngleDeg, opts.reflectionMode,\n\t\t\t) !== 0\n\t\t);\n\t}\n\n\tqueryRicochet(slot: number): { bounces: number; lastKind: number } | null {\n\t\tif (this.exports.zylem_stage_query_ricochet(slot) === 0) return null;\n\t\tconst v = this.queryView;\n\t\treturn { bounces: v[0]! | 0, lastKind: v[1]! | 0 };\n\t}\n\n\tattachThruster(slot: number, opts: StageThrusterOptions): boolean {\n\t\treturn (\n\t\t\tthis.exports.zylem_stage_attach_thruster(\n\t\t\t\tslot, opts.maxSpeed, opts.acceleration, opts.turnRateRadPerSec, opts.linearDamping,\n\t\t\t) !== 0\n\t\t);\n\t}\n\n\tsetThrusterInput(\n\t\tslot: number,\n\t\tthrust: number,\n\t\tturn: number,\n\t\tvectorX = 0,\n\t\tvectorY = 0,\n\t): void {\n\t\tthis.exports.zylem_stage_set_thruster_input(slot, thrust, turn, vectorX, vectorY);\n\t}\n\n\tqueryThruster(slot: number): { headingRad: number; speed: number } | null {\n\t\tif (this.exports.zylem_stage_query_thruster(slot) === 0) return null;\n\t\tconst v = this.queryView;\n\t\treturn { headingRad: v[0]!, speed: v[1]! };\n\t}\n\n\tattachTopDown(slot: number, opts: StageTopDownOptions): boolean {\n\t\treturn this.exports.zylem_stage_attach_top_down(slot, opts.plane, opts.speed, opts.faceMovement ? 1 : 0) !== 0;\n\t}\n\n\tsetTopDownInput(slot: number, axisA: number, axisB: number): void {\n\t\tthis.exports.zylem_stage_set_top_down_input(slot, axisA, axisB);\n\t}\n\n\tattachJumper2D(slot: number, opts: StageJumper2DOptions): boolean {\n\t\treturn (\n\t\t\tthis.exports.zylem_stage_attach_jumper_2d(\n\t\t\t\tslot, opts.jumpForce, opts.maxJumps >>> 0,\n\t\t\t\topts.jumpBufferTime, opts.coyoteTime, opts.gravity,\n\t\t\t) !== 0\n\t\t);\n\t}\n\n\tsetJumper2DInput(slot: number, jumpPressed: boolean): void {\n\t\tthis.exports.zylem_stage_set_jumper_2d_input(slot, jumpPressed ? 1 : 0);\n\t}\n\n\tqueryJumper2D(slot: number): { grounded: boolean; jumpCount: number; coyote: number; jumpBuffer: number } | null {\n\t\tif (this.exports.zylem_stage_query_jumper_2d(slot) === 0) return null;\n\t\tconst v = this.queryView;\n\t\treturn {\n\t\t\tgrounded: v[0]! > 0.5,\n\t\t\tjumpCount: v[1]! | 0,\n\t\t\tcoyote: v[2]!,\n\t\t\tjumpBuffer: v[3]!,\n\t\t};\n\t}\n\n\tattachJumper3D(slot: number, opts: StageJumper3DOptions): boolean {\n\t\treturn this.exports.zylem_stage_attach_jumper_3d(\n\t\t\tslot, opts.jumpForce, opts.maxJumps >>> 0, opts.gravity,\n\t\t\topts.coyoteTime ?? 0.1, opts.jumpBufferTime ?? 0.08,\n\t\t) !== 0;\n\t}\n\n\tsetJumper3DInput(slot: number, jump: boolean): void {\n\t\tthis.exports.zylem_stage_set_jumper_3d_input(slot, jump ? 1 : 0);\n\t}\n\n\tqueryJumper3D(slot: number): { grounded: boolean; jumpCount: number; verticalVelocity: number } | null {\n\t\tif (this.exports.zylem_stage_query_jumper_3d(slot) === 0) return null;\n\t\tconst v = this.queryView;\n\t\treturn { grounded: v[0]! > 0.5, jumpCount: v[1]! | 0, verticalVelocity: v[2]! };\n\t}\n\n\tattachShooter2D(slot: number, opts: StageShooter2DOptions): boolean {\n\t\treturn (\n\t\t\tthis.exports.zylem_stage_attach_shooter_2d(\n\t\t\t\tslot, opts.fireRateHz, opts.muzzleOffsetX, opts.muzzleOffsetY, opts.muzzleSpeed,\n\t\t\t) !== 0\n\t\t);\n\t}\n\n\tfireShooter2D(slot: number, x: number, y: number, z: number, yaw: number): boolean {\n\t\treturn this.exports.zylem_stage_shooter_2d_fire(slot, x, y, z, yaw) !== 0;\n\t}\n\n\tqueryShooter2D(slot: number): { cooldown: number; firedCount: number } | null {\n\t\tif (this.exports.zylem_stage_query_shooter_2d(slot) === 0) return null;\n\t\tconst v = this.queryView;\n\t\treturn { cooldown: v[0]!, firedCount: v[1]! | 0 };\n\t}\n\n\tattachPlatformer3D(slot: number, opts: StagePlatformer3DOptions): boolean {\n\t\treturn (\n\t\t\tthis.exports.zylem_stage_attach_platformer_3d(\n\t\t\t\tslot, opts.halfHeight, opts.radius,\n\t\t\t\topts.walkSpeed, opts.runSpeed, opts.jumpForce,\n\t\t\t\topts.maxJumps >>> 0, opts.gravity,\n\t\t\t\topts.coyoteTime ?? 0.1, opts.jumpBufferTime ?? 0.1,\n\t\t\t\topts.jumpCutMultiplier ?? 0.5, opts.multiJumpWindow ?? 0.15,\n\t\t\t\topts.slopeClimbAngle ?? 50, opts.slopeSlideAngle ?? 40,\n\t\t\t\topts.autostepHeight ?? 0.3, opts.autostepMinWidth ?? 0.1,\n\t\t\t\topts.snapToGroundDistance ?? 0.3, opts.characterOffset ?? 0.05,\n\t\t\t\topts.offsetX ?? 0, opts.offsetY ?? 0, opts.offsetZ ?? 0,\n\t\t\t\topts.shapeSource ?? StagePlatformerShapeSource.Auto,\n\t\t\t) !== 0\n\t\t);\n\t}\n\n\tsetPlatformer3DInputAxes(slot: number, moveX: number, moveZ: number): void {\n\t\tthis.exports.zylem_stage_set_platformer_3d_input_axes(slot, moveX, moveZ);\n\t}\n\n\tsetPlatformer3DInputButtons(slot: number, jump: boolean, run: boolean): void {\n\t\tthis.exports.zylem_stage_set_platformer_3d_input_buttons(slot, jump ? 1 : 0, run ? 1 : 0);\n\t}\n\n\tqueryPlatformer3D(slot: number): { grounded: boolean; jumpCount: number; fsmState: number; speed: number } | null {\n\t\tif (this.exports.zylem_stage_query_platformer_3d(slot) === 0) return null;\n\t\tconst v = this.queryView;\n\t\treturn {\n\t\t\tgrounded: v[0]! > 0.5,\n\t\t\tjumpCount: v[1]! | 0,\n\t\t\tfsmState: v[2]! | 0,\n\t\t\tspeed: v[3]!,\n\t\t};\n\t}\n\n\tattachPlatformer2D(slot: number, opts: StagePlatformer2DOptions): boolean {\n\t\treturn (\n\t\t\tthis.exports.zylem_stage_attach_platformer_2d(\n\t\t\t\tslot, opts.halfHeight, opts.radius,\n\t\t\t\topts.walkSpeed, opts.runSpeed, opts.jumpForce,\n\t\t\t\topts.maxJumps >>> 0, opts.gravity,\n\t\t\t\topts.coyoteTime ?? 0.1, opts.jumpBufferTime ?? 0.1,\n\t\t\t\topts.jumpCutMultiplier ?? 0.5, opts.multiJumpWindow ?? 0.15,\n\t\t\t\topts.slopeClimbAngle ?? 50, opts.slopeSlideAngle ?? 40,\n\t\t\t\topts.autostepHeight ?? 0.25, opts.autostepMinWidth ?? 0.05,\n\t\t\t\topts.snapToGroundDistance ?? 0.2, opts.characterOffset ?? 0.05,\n\t\t\t\topts.offsetX ?? 0, opts.offsetY ?? 0, opts.offsetZ ?? 0,\n\t\t\t\topts.shapeSource ?? StagePlatformerShapeSource.Auto,\n\t\t\t) !== 0\n\t\t);\n\t}\n\n\tsetPlatformer2DInputAxes(slot: number, moveX: number): void {\n\t\tthis.exports.zylem_stage_set_platformer_2d_input_axes(slot, moveX);\n\t}\n\n\tsetPlatformer2DInputButtons(slot: number, jump: boolean, run: boolean): void {\n\t\tthis.exports.zylem_stage_set_platformer_2d_input_buttons(slot, jump ? 1 : 0, run ? 1 : 0);\n\t}\n\n\tqueryPlatformer2D(slot: number): { grounded: boolean; jumpCount: number; fsmState: number; verticalVelocity: number } | null {\n\t\tif (this.exports.zylem_stage_query_platformer_2d(slot) === 0) return null;\n\t\tconst v = this.queryView;\n\t\treturn {\n\t\t\tgrounded: v[0]! > 0.5,\n\t\t\tjumpCount: v[1]! | 0,\n\t\t\tfsmState: v[2]! | 0,\n\t\t\tverticalVelocity: v[3]!,\n\t\t};\n\t}\n\n\tattachFirstPerson(slot: number, opts: StageFirstPersonOptions): boolean {\n\t\treturn (\n\t\t\tthis.exports.zylem_stage_attach_first_person(\n\t\t\t\tslot, opts.walkSpeed, opts.runSpeed, opts.eyeHeight, opts.lookSensitivity,\n\t\t\t) !== 0\n\t\t);\n\t}\n\n\tsetFirstPersonInput(slot: number, input: StageFirstPersonInput): void {\n\t\tthis.exports.zylem_stage_set_first_person_input(\n\t\t\tslot, input.moveX, input.moveZ, input.lookYawDelta, input.lookPitchDelta, input.run ? 1 : 0,\n\t\t);\n\t}\n\n\tqueryFirstPerson(slot: number): { yaw: number; pitch: number; speed: number; eyeHeight: number } | null {\n\t\tif (this.exports.zylem_stage_query_first_person(slot) === 0) return null;\n\t\tconst v = this.queryView;\n\t\treturn { yaw: v[0]!, pitch: v[1]!, speed: v[2]!, eyeHeight: v[3]! };\n\t}\n}\n\n/**\n * Load the bundled `@zylem/runtime` wasm (or a custom `source`), instantiate\n * it, and construct a `WasmStageRuntime` around the exports.\n */\nexport async function createWasmStageRuntime(\n\toptions: WasmStageRuntimeOptions = {},\n): Promise<WasmStageRuntime> {\n\tconst { exports } = await loadStageFfi({\n\t\tsource: options.source,\n\t\timports: options.imports,\n\t});\n\treturn new WasmStageRuntime(exports, options);\n}\n"],"mappings":"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","names":[]}
@@ -41,3 +41,4 @@ export {
41
41
  createJumpInput3D,
42
42
  createJumpState3D
43
43
  };
44
+ //# sourceMappingURL=chunk-4WH2ZN7P.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/behaviors/jumper-3d/components.ts"],"sourcesContent":["/**\n * Jumper 3D ECS Components\n *\n * Type definitions and factory functions for the 3D jump behavior system.\n *\n * - JumpConfig3D: tunable parameters (stored as the capability component)\n * - JumpInput3D: per-tick intent written by the player/AI controller\n * - JumpContext3D: per-tick snapshot provided by the system adapter\n * - JumpState3D: internal runtime state owned by the behavior\n */\n\nimport type { Vector3 } from 'three';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Vec3-like interface for cross-library compatibility\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface Vec3Like {\n\tx: number;\n\ty: number;\n\tz: number;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// JumpConfig3D (capability / configuration)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface JumpConfig3D {\n\t/** Desired peak height in world units */\n\tjumpHeight: number;\n\t/** Gravity magnitude (positive, e.g. 20) */\n\tgravity: number;\n\t/** Terminal fall speed magnitude (optional) */\n\tmaxFallSpeed?: number;\n\n\t/** 1 = single jump, 2 = double, etc. */\n\tmaxJumps: number;\n\t/** Reset jump counter when grounded (usually true) */\n\tresetJumpsOnGround: boolean;\n\t/** Reset jump counter on wall contact (future wall-jump support) */\n\tresetJumpsOnWall?: boolean;\n\n\t/** Grace period after leaving ground where first jump is still allowed (ms) */\n\tcoyoteTimeMs: number;\n\t/** Queue a jump press this many ms before landing (ms) */\n\tjumpBufferMs: number;\n\t/** Optional cooldown between consecutive jumps (ms) */\n\tminTimeBetweenJumpsMs?: number;\n\n\t/** Variable jump height via early release */\n\tvariableJump?: {\n\t\tenabled: boolean;\n\t\t/** Gravity multiplier applied when jump is released early while ascending */\n\t\tcutGravityMultiplier: number;\n\t\t/** Max hold duration before the cut triggers automatically (ms, optional) */\n\t\tmaxHoldMs?: number;\n\t};\n\n\t/** Optional planar (XZ) launch / air-control overrides */\n\tplanar?: {\n\t\t/** One-time planar speed applied at takeoff */\n\t\tlaunchPlanarSpeed?: number;\n\t\t/** If true, preserve current planar speed instead of replacing it */\n\t\tpreservePlanarSpeed?: boolean;\n\t\tairControl?: {\n\t\t\tmaxPlanarSpeed: number;\n\t\t\t/** Acceleration per second while airborne */\n\t\t\tacceleration: number;\n\t\t\t/** Deceleration per second when no input */\n\t\t\tdeceleration: number;\n\t\t};\n\t};\n\n\t/** Snappier descent tuning */\n\tfall?: {\n\t\t/** Gravity multiplier while falling (e.g. 1.5-2.5) */\n\t\tfallGravityMultiplier: number;\n\t\t/** Additional multiplier when fast-fall input is held */\n\t\tfastFallMultiplier?: number;\n\t};\n}\n\nexport function createJumpConfig3D(\n\toptions: Partial<JumpConfig3D> = {},\n): JumpConfig3D {\n\treturn {\n\t\tjumpHeight: options.jumpHeight ?? 2.5,\n\t\tgravity: options.gravity ?? 20,\n\t\tmaxFallSpeed: options.maxFallSpeed,\n\t\tmaxJumps: options.maxJumps ?? 1,\n\t\tresetJumpsOnGround: options.resetJumpsOnGround ?? true,\n\t\tresetJumpsOnWall: options.resetJumpsOnWall,\n\t\tcoyoteTimeMs: options.coyoteTimeMs ?? 100,\n\t\tjumpBufferMs: options.jumpBufferMs ?? 80,\n\t\tminTimeBetweenJumpsMs: options.minTimeBetweenJumpsMs,\n\t\tvariableJump: options.variableJump,\n\t\tplanar: options.planar,\n\t\tfall: options.fall,\n\t};\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// JumpInput3D (intent)\n// Written by: Player controller, AI controller\n// Read by: Jumper3DSystem\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface JumpInput3D {\n\t/** True on the frame the jump button is first pressed (rising edge) */\n\tjumpPressed: boolean;\n\t/** True while the jump button is held down */\n\tjumpHeld: boolean;\n\t/** True on the frame the jump button is released (falling edge) */\n\tjumpReleased: boolean;\n\t/** Desired planar direction in world space (camera-relative), optional */\n\tmoveDirWorld?: Vec3Like;\n\t/** Hold to drop faster (e.g. crouch / down input) */\n\tfastFall?: boolean;\n}\n\nexport function createJumpInput3D(): JumpInput3D {\n\treturn {\n\t\tjumpPressed: false,\n\t\tjumpHeld: false,\n\t\tjumpReleased: false,\n\t\tmoveDirWorld: undefined,\n\t\tfastFall: false,\n\t};\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// JumpContext3D (per-tick snapshot from entity / controller)\n// Built by the system adapter — never written to by user code.\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface JumpContext3D {\n\t/** Frame delta in seconds */\n\tdt: number;\n\t/** World up direction (usually 0,1,0) */\n\tup: Vec3Like;\n\t/** Current vertical (Y) velocity of the entity */\n\tvelocityY: number;\n\t/** Current horizontal velocity of the entity (read from body) */\n\thorizontalVelocity: { x: number; z: number };\n\t/** Whether the entity is on the ground */\n\tisGrounded: boolean;\n\t/** Surface normal at ground contact (optional) */\n\tgroundNormal?: Vec3Like;\n\t/** Time since entity was last grounded (ms) */\n\ttimeSinceGroundedMs: number;\n\n\t/** Set only the vertical (Y) component of velocity */\n\tsetVerticalVelocity(y: number): void;\n\t/** Set only the horizontal (X/Z) components of velocity */\n\tsetHorizontalVelocity(x: number, z: number): void;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// JumpState3D (internal runtime state)\n// Owned and mutated exclusively by Jumper3DSystem.tick()\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface JumpState3D {\n\t/** Number of jumps consumed since last reset */\n\tjumpsUsed: number;\n\t/** Timestamp (ms) of the most recent jump execution */\n\tlastJumpTimeMs: number;\n\t/** Remaining ms in the jump-buffer window (counts down) */\n\tbufferedJumpMs: number;\n\t/** Remaining ms in the coyote-time window (counts down) */\n\tcoyoteMs: number;\n\t/** True while the entity is in a jump arc (ascending phase) */\n\tisJumping: boolean;\n\t/** Elapsed ms since jump button was first held (for variable jump) */\n\tjumpHoldMs: number;\n\t/** Whether the variable-jump cut has already been applied this jump */\n\tjumpCutApplied: boolean;\n}\n\nexport function createJumpState3D(): JumpState3D {\n\treturn {\n\t\tjumpsUsed: 0,\n\t\tlastJumpTimeMs: 0,\n\t\tbufferedJumpMs: 0,\n\t\tcoyoteMs: 0,\n\t\tisJumping: false,\n\t\tjumpHoldMs: 0,\n\t\tjumpCutApplied: false,\n\t};\n}\n"],"mappings":";AAkFO,SAAS,mBACf,UAAiC,CAAC,GACnB;AACf,SAAO;AAAA,IACN,YAAY,QAAQ,cAAc;AAAA,IAClC,SAAS,QAAQ,WAAW;AAAA,IAC5B,cAAc,QAAQ;AAAA,IACtB,UAAU,QAAQ,YAAY;AAAA,IAC9B,oBAAoB,QAAQ,sBAAsB;AAAA,IAClD,kBAAkB,QAAQ;AAAA,IAC1B,cAAc,QAAQ,gBAAgB;AAAA,IACtC,cAAc,QAAQ,gBAAgB;AAAA,IACtC,uBAAuB,QAAQ;AAAA,IAC/B,cAAc,QAAQ;AAAA,IACtB,QAAQ,QAAQ;AAAA,IAChB,MAAM,QAAQ;AAAA,EACf;AACD;AAqBO,SAAS,oBAAiC;AAChD,SAAO;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,IACV,cAAc;AAAA,IACd,cAAc;AAAA,IACd,UAAU;AAAA,EACX;AACD;AAmDO,SAAS,oBAAiC;AAChD,SAAO;AAAA,IACN,WAAW;AAAA,IACX,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,gBAAgB;AAAA,EACjB;AACD;","names":[]}
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  getEntityFacingAngle2D,
3
3
  resolveAim2D
4
- } from "./chunk-VJ3UA6OD.js";
4
+ } from "./chunk-TBUKJKY6.js";
5
5
 
6
6
  // src/lib/coordinators/shared/shooter-fire.ts
7
7
  function fireShooter2DIfRequested(entity, shooter, stage, input, aim) {
@@ -27,3 +27,4 @@ function fireShooter2DIfRequested(entity, shooter, stage, input, aim) {
27
27
  export {
28
28
  fireShooter2DIfRequested
29
29
  };
30
+ //# sourceMappingURL=chunk-52FJIDGL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/coordinators/shared/shooter-fire.ts"],"sourcesContent":["import type {\n\tShooter2DHandle,\n\tShooter2DSourceEntity,\n\tShooter2DStageLike,\n} from '../../behaviors/shooter-2d/shooter-2d.descriptor';\nimport {\n\tgetEntityFacingAngle2D,\n\tresolveAim2D,\n\ttype ResolvedAim2D,\n} from './top-down-aim';\n\n/**\n * Aim + fire input fields shared by the 2D shooter coordinators\n * (top-down-shooter, multidirectional-space-shooter).\n */\nexport interface Shooter2DAimFireInput {\n\taimX: number;\n\taimY: number;\n\tshootPressed: boolean;\n\tshootHeld: boolean;\n}\n\n/**\n * Fire the entity's Shooter2D behavior when the input requests it.\n *\n * Resolves the 2D aim (explicit aim axes, falling back to the entity's\n * current facing) and fires toward a point one unit along the aim direction.\n * Pass a pre-resolved `aim` to avoid recomputing when the coordinator already\n * resolved it for rotation.\n *\n * @returns true when a fire attempt was issued\n */\nexport function fireShooter2DIfRequested(\n\tentity: Shooter2DSourceEntity,\n\tshooter: Shooter2DHandle,\n\tstage: Shooter2DStageLike,\n\tinput: Shooter2DAimFireInput,\n\taim?: ResolvedAim2D,\n): boolean {\n\tif (!input.shootPressed && !input.shootHeld) {\n\t\treturn false;\n\t}\n\n\tconst sourcePosition = entity.body?.translation();\n\tif (!sourcePosition) {\n\t\treturn false;\n\t}\n\n\tconst resolved =\n\t\taim ?? resolveAim2D(input.aimX, input.aimY, getEntityFacingAngle2D(entity));\n\n\tvoid shooter.fire({\n\t\tsource: entity,\n\t\tstage,\n\t\ttarget: {\n\t\t\tx: sourcePosition.x + resolved.direction.x,\n\t\t\ty: sourcePosition.y + resolved.direction.y,\n\t\t},\n\t});\n\treturn true;\n}\n"],"mappings":";;;;;;AAgCO,SAAS,yBACf,QACA,SACA,OACA,OACA,KACU;AACV,MAAI,CAAC,MAAM,gBAAgB,CAAC,MAAM,WAAW;AAC5C,WAAO;AAAA,EACR;AAEA,QAAM,iBAAiB,OAAO,MAAM,YAAY;AAChD,MAAI,CAAC,gBAAgB;AACpB,WAAO;AAAA,EACR;AAEA,QAAM,WACL,OAAO,aAAa,MAAM,MAAM,MAAM,MAAM,uBAAuB,MAAM,CAAC;AAE3E,OAAK,QAAQ,KAAK;AAAA,IACjB,QAAQ;AAAA,IACR;AAAA,IACA,QAAQ;AAAA,MACP,GAAG,eAAe,IAAI,SAAS,UAAU;AAAA,MACzC,GAAG,eAAe,IAAI,SAAS,UAAU;AAAA,IAC1C;AAAA,EACD,CAAC;AACD,SAAO;AACR;","names":[]}
@@ -21,3 +21,4 @@ export {
21
21
  createTransformComponent,
22
22
  createPhysicsBodyComponent
23
23
  };
24
+ //# sourceMappingURL=chunk-5A5AYP2C.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/behaviors/use-behavior.ts","../src/lib/behaviors/components.ts"],"sourcesContent":["import { GameEntity } from '../entities/entity';\nimport { BehaviorDescriptor } from './behavior-descriptor';\n\n/**\n * Type-safe helper to apply a behavior to an entity and return the entity cast to the behavior's interface.\n * \n * @param entity The entity to apply the behavior to\n * @param descriptor The behavior descriptor\n * @param options Behavior options\n * @returns The entity, cast to E & I (where I is the behavior's interface)\n */\nexport function useBehavior<\n E extends GameEntity<any>,\n O extends Record<string, any>,\n H extends Record<string, any>,\n I // Entity Interface\n>(\n entity: E,\n descriptor: BehaviorDescriptor<O, H, I>,\n options?: Partial<O>\n): E & I {\n entity.use(descriptor, options);\n return entity as unknown as E & I;\n}\n","/**\n * Core behavior helper types\n *\n * Plain data interfaces shared by movement behaviors and coordinators.\n */\n\nimport { Vector3, Quaternion } from 'three';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// TransformComponent (render-facing)\n// Written only by PhysicsSyncBehavior, read by rendering/animation\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface TransformComponent {\n\tposition: Vector3;\n\trotation: Quaternion;\n}\n\nexport function createTransformComponent(): TransformComponent {\n\treturn {\n\t\tposition: new Vector3(),\n\t\trotation: new Quaternion(),\n\t};\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// PhysicsBodyComponent (bridge to the host physics reference, not state)\n// ECS does not store velocity, mass, etc. — the wasm runtime owns all\n// physical truth; `body` is an opaque host-owned reference.\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface PhysicsBodyComponent {\n\tbody: unknown;\n}\n\nexport function createPhysicsBodyComponent(body: unknown): PhysicsBodyComponent {\n\treturn { body };\n}\n"],"mappings":";AAWO,SAAS,YAMZ,QACA,YACA,SACK;AACL,SAAO,IAAI,YAAY,OAAO;AAC9B,SAAO;AACX;;;ACjBA,SAAS,SAAS,kBAAkB;AAY7B,SAAS,2BAA+C;AAC9D,SAAO;AAAA,IACN,UAAU,IAAI,QAAQ;AAAA,IACtB,UAAU,IAAI,WAAW;AAAA,EAC1B;AACD;AAYO,SAAS,2BAA2B,MAAqC;AAC/E,SAAO,EAAE,KAAK;AACf;","names":[]}
@@ -28,3 +28,4 @@ export {
28
28
  __commonJS,
29
29
  __toESM
30
30
  };
31
+ //# sourceMappingURL=chunk-5WRI5ZAA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  defineBehavior
3
- } from "./chunk-YDLO5M7S.js";
3
+ } from "./chunk-EZNCCO4L.js";
4
4
 
5
5
  // src/lib/behaviors/cooldown/cooldown-store.ts
6
6
  import { proxy } from "valtio/vanilla";
@@ -115,3 +115,4 @@ export {
115
115
  getCooldownStore,
116
116
  CooldownBehavior
117
117
  };
118
+ //# sourceMappingURL=chunk-5XPPLTC7.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/behaviors/cooldown/cooldown-store.ts","../src/lib/behaviors/cooldown/cooldown.descriptor.ts"],"sourcesContent":["import { proxy } from 'valtio/vanilla';\n\n/**\n * A single cooldown entry in the global store.\n */\nexport interface CooldownEntry {\n\t/** Identifier for this cooldown */\n\tname: string;\n\t/** Total cooldown time in seconds */\n\tduration: number;\n\t/** Time accumulated since last fire */\n\telapsed: number;\n\t/** Whether the cooldown is ready (elapsed >= duration) */\n\tready: boolean;\n\t/** Normalized progress 0..1 (0 = just fired, 1 = ready) */\n\tprogress: number;\n\t/** Whether this cooldown is currently counting down */\n\tactive: boolean;\n}\n\n/**\n * Global reactive cooldown registry (valtio proxy).\n * Accessible from entities, behaviors, and UI components.\n */\nconst cooldownStore = proxy<Record<string, CooldownEntry>>({});\n\n/**\n * Register a named cooldown in the global store.\n * If a cooldown with the same name already exists, it is overwritten.\n *\n * @param name Unique cooldown identifier\n * @param duration Cooldown duration in seconds\n * @param immediate If true, the cooldown starts ready (default: true)\n */\nexport function registerCooldown(\n\tname: string,\n\tduration: number,\n\timmediate: boolean = true,\n): void {\n\tcooldownStore[name] = {\n\t\tname,\n\t\tduration,\n\t\telapsed: immediate ? duration : 0,\n\t\tready: immediate,\n\t\tprogress: immediate ? 1 : 0,\n\t\tactive: !immediate,\n\t};\n}\n\n/**\n * Get a cooldown entry by name.\n * Returns undefined if the cooldown has not been registered.\n */\nexport function getCooldown(name: string): CooldownEntry | undefined {\n\treturn cooldownStore[name];\n}\n\n/**\n * Fire (trigger) a cooldown, resetting its timer.\n * Sets the cooldown to not-ready and starts the countdown.\n */\nexport function fireCooldown(name: string): void {\n\tconst entry = cooldownStore[name];\n\tif (!entry) return;\n\tentry.elapsed = 0;\n\tentry.ready = false;\n\tentry.progress = 0;\n\tentry.active = true;\n}\n\n/**\n * Force a cooldown to ready immediately.\n */\nexport function resetCooldown(name: string): void {\n\tconst entry = cooldownStore[name];\n\tif (!entry) return;\n\tentry.elapsed = entry.duration;\n\tentry.ready = true;\n\tentry.progress = 1;\n\tentry.active = false;\n}\n\n/**\n * Advance all active cooldowns by delta seconds.\n * Called once per frame by the CooldownBehavior system.\n */\nexport function tickCooldowns(delta: number): void {\n\tfor (const name in cooldownStore) {\n\t\tconst entry = cooldownStore[name];\n\t\tif (!entry.active) continue;\n\n\t\tentry.elapsed += delta;\n\t\tif (entry.elapsed >= entry.duration) {\n\t\t\tentry.elapsed = entry.duration;\n\t\t\tentry.ready = true;\n\t\t\tentry.progress = 1;\n\t\t\tentry.active = false;\n\t\t} else {\n\t\t\tentry.progress = entry.duration > 0 ? entry.elapsed / entry.duration : 1;\n\t\t}\n\t}\n}\n\n/**\n * Get the raw cooldown store (for advanced/debugging use).\n */\nexport function getCooldownStore(): Record<string, CooldownEntry> {\n\treturn cooldownStore;\n}\n","/**\n * CooldownBehavior\n *\n * A stage-scoped behavior that manages named cooldowns via the global CooldownStore.\n * Entities use this to register, check, and fire cooldowns.\n * UI components (CooldownIcon) can read from the same store.\n */\n\nimport { defineBehavior, type BehaviorRef } from '../behavior-descriptor';\nimport type { BehaviorEntityLink, BehaviorSystem } from '../behavior-system';\nimport {\n\tregisterCooldown,\n\tgetCooldown,\n\tfireCooldown,\n\tresetCooldown,\n\ttickCooldowns,\n} from './cooldown-store';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Options\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface CooldownConfig {\n\t/** Duration in seconds */\n\tduration: number;\n\t/** Whether the cooldown starts ready (default: true) */\n\timmediate?: boolean;\n}\n\nexport interface CooldownOptions {\n\t/**\n\t * Named cooldowns to register.\n\t * Keys are the cooldown names, values are their config.\n\t */\n\tcooldowns: Record<string, CooldownConfig>;\n}\n\ninterface CompiledCooldownEntry {\n\tname: string;\n\tduration: number;\n\timmediate: boolean;\n}\n\nconst COOLDOWN_BEHAVIOR_KEY = Symbol.for('zylem:behavior:cooldown');\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Handle\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Handle methods returned by entity.use(CooldownBehavior, ...).\n */\nexport interface CooldownHandle {\n\t/** Check if a named cooldown is ready */\n\tisReady(name: string): boolean;\n\t/** Fire (trigger) a named cooldown, resetting its timer */\n\tfire(name: string): void;\n\t/** Force a cooldown to ready immediately */\n\treset(name: string): void;\n\t/** Get cooldown progress 0..1 (0 = just fired, 1 = ready) */\n\tgetProgress(name: string): number;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// System\n// ─────────────────────────────────────────────────────────────────────────────\n\nclass CooldownSystem implements BehaviorSystem {\n\tconstructor(\n\t\tprivate getBehaviorLinks?: (key: symbol) => Iterable<BehaviorEntityLink>,\n\t) { }\n\n\tupdate(_ecs: unknown, delta: number): void {\n\t\tconst links = this.getBehaviorLinks?.(COOLDOWN_BEHAVIOR_KEY);\n\t\tif (links) {\n\t\t\tfor (const link of links) {\n\t\t\t\tensureCooldownEntriesRegistered(link.ref as BehaviorRef<CooldownOptions>);\n\t\t\t}\n\t\t}\n\n\t\ttickCooldowns(delta);\n\t}\n\n\tdestroy(_ecs: unknown): void { }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Handle factory\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction createCooldownHandle(ref: BehaviorRef<CooldownOptions>): CooldownHandle {\n\tensureCooldownEntriesRegistered(ref);\n\n\treturn {\n\t\tisReady: (name: string) => getCooldown(name)?.ready ?? false,\n\t\tfire: (name: string) => fireCooldown(name),\n\t\treset: (name: string) => resetCooldown(name),\n\t\tgetProgress: (name: string) => getCooldown(name)?.progress ?? 1,\n\t};\n}\n\nfunction getCompiledCooldownEntries(\n\tref: BehaviorRef<CooldownOptions>,\n): CompiledCooldownEntry[] {\n\tconst compiled = (ref as any).__compiledCooldownEntries as CompiledCooldownEntry[] | undefined;\n\tif (compiled) return compiled;\n\n\tconst entries = Object.entries(ref.options.cooldowns).map(([name, config]) => ({\n\t\tname,\n\t\tduration: config.duration,\n\t\timmediate: config.immediate ?? true,\n\t}));\n\t(ref as any).__compiledCooldownEntries = entries;\n\treturn entries;\n}\n\nfunction ensureCooldownEntriesRegistered(ref: BehaviorRef<CooldownOptions>): void {\n\tif ((ref as any).__cooldownsRegistered) return;\n\n\tfor (const entry of getCompiledCooldownEntries(ref)) {\n\t\tregisterCooldown(entry.name, entry.duration, entry.immediate);\n\t}\n\n\t(ref as any).__cooldownsRegistered = true;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Behavior Definition\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * CooldownBehavior\n *\n * @example\n * ```ts\n * import { CooldownBehavior } from '@zylem/game-lib/behavior';\n * import { moveBy } from '@zylem/game-lib/actions';\n *\n * const hero = createBox({ ... });\n * const cd = hero.use(CooldownBehavior, {\n * cooldowns: {\n * attack: { duration: 5 },\n * dash: { duration: 2, immediate: false },\n * },\n * });\n *\n * hero.onUpdate(({ me, inputs }) => {\n * if (cd.isReady('attack') && inputs.p1.buttons.A.pressed) {\n * cd.fire('attack');\n * // perform attack\n * }\n * if (cd.isReady('dash') && inputs.p1.buttons.B.pressed) {\n * cd.fire('dash');\n * me.runAction(moveBy({ x: 10, duration: 0.3 }));\n * }\n * });\n * ```\n */\nexport const CooldownBehavior = defineBehavior<CooldownOptions, CooldownHandle>({\n\tname: 'cooldown',\n\tdefaultOptions: { cooldowns: {} },\n\tsystemFactory: (ctx) =>\n\t\tnew CooldownSystem(ctx.getBehaviorLinks),\n\tcreateHandle: createCooldownHandle,\n});\n"],"mappings":"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","names":[]}
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  __commonJS,
3
3
  __toESM
4
- } from "./chunk-JSBRDJBE.js";
4
+ } from "./chunk-5WRI5ZAA.js";
5
5
 
6
6
  // node_modules/.pnpm/typescript-fsm@1.6.0/node_modules/typescript-fsm/dist/stateMachine.js
7
7
  var require_stateMachine = __commonJS({
@@ -185,3 +185,4 @@ export {
185
185
  SyncStateMachine,
186
186
  import_typescript_fsm2 as import_typescript_fsm
187
187
  };
188
+ //# sourceMappingURL=chunk-AS3HR7AS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../node_modules/.pnpm/typescript-fsm@1.6.0/node_modules/typescript-fsm/src/stateMachine.ts","../src/lib/core/utility/sync-state-machine.ts"],"sourcesContent":[null,"import {\n\tStateMachine as BaseStateMachine,\n\ttype ILogger,\n\ttype ITransition,\n\ttype SyncCallback,\n} from 'typescript-fsm';\n\nexport { t } from 'typescript-fsm';\nexport type { ILogger, ITransition, SyncCallback };\n\n/**\n * Local wrapper around typescript-fsm's SyncStateMachine.\n *\n * typescript-fsm@1.6.0 incorrectly reports callback-less transitions as\n * unhandled even after moving to the next state, which causes noisy\n * `No transition...` console errors for valid FSM dispatches.\n */\nexport class SyncStateMachine<\n\tSTATE extends string | number | symbol,\n\tEVENT extends string | number | symbol,\n\tCALLBACK extends Record<EVENT, SyncCallback> = Record<EVENT, SyncCallback>,\n> extends BaseStateMachine<STATE, EVENT, CALLBACK> {\n\tconstructor(\n\t\tinit: STATE,\n\t\ttransitions: ITransition<STATE, EVENT, CALLBACK[EVENT]>[] = [],\n\t\tlogger: ILogger = console,\n\t) {\n\t\tsuper(init, transitions, logger);\n\t}\n\n\tdispatch<E extends EVENT>(_event: E, ..._args: unknown[]): Promise<void> {\n\t\tthrow new Error('SyncStateMachine does not support async dispatch.');\n\t}\n\n\tsyncDispatch<E extends EVENT>(event: E, ...args: unknown[]): boolean {\n\t\tconst found = this.transitions.some((transition) => {\n\t\t\tif (transition.fromState !== this._current || transition.event !== event) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tconst current = this._current;\n\t\t\tthis._current = transition.toState;\n\n\t\t\tif (!transition.cb) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\ttransition.cb(...args);\n\t\t\t\treturn true;\n\t\t\t} catch (error) {\n\t\t\t\tthis._current = current;\n\t\t\t\tthis.logger.error('Exception in callback', error);\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t});\n\n\t\tif (!found) {\n\t\t\tconst errorMessage = this.formatErr(this._current, event);\n\t\t\tthis.logger.error(errorMessage);\n\t\t}\n\n\t\treturn found;\n\t}\n}\n"],"mappings":"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","names":["t","SyncStateMachine","import_typescript_fsm","BaseStateMachine"]}
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  createThrusterInputComponent,
3
3
  createThrusterMovementComponent
4
- } from "./chunk-2HLZBWGD.js";
4
+ } from "./chunk-IZJFUAXB.js";
5
5
  import {
6
6
  SyncStateMachine,
7
7
  import_typescript_fsm
8
- } from "./chunk-OBF6BIA2.js";
8
+ } from "./chunk-AS3HR7AS.js";
9
9
  import {
10
10
  defineBehavior
11
- } from "./chunk-YDLO5M7S.js";
11
+ } from "./chunk-EZNCCO4L.js";
12
12
 
13
13
  // src/lib/behaviors/thruster/thruster-fsm.ts
14
14
  var ThrusterState = /* @__PURE__ */ ((ThrusterState2) => {
@@ -152,3 +152,4 @@ export {
152
152
  ThrusterFSM,
153
153
  ThrusterBehavior
154
154
  };
155
+ //# sourceMappingURL=chunk-BAXJ7XHJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/behaviors/thruster/thruster-fsm.ts","../src/lib/behaviors/thruster/thruster.descriptor.ts"],"sourcesContent":["/**\n * ThrusterFSM\n * \n * State machine controller for thruster behavior.\n * FSM does NOT touch physics or ThrusterSystem - it only writes ThrusterInputComponent.\n */\n\nimport { SyncStateMachine, t } from '../../core/utility/sync-state-machine';\nimport type { ThrusterInputComponent } from './components';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// FSM State Model\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport enum ThrusterState {\n\tIdle = 'idle',\n\tActive = 'active',\n\tBoosting = 'boosting',\n\tDisabled = 'disabled',\n\tDocked = 'docked',\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// FSM Events\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport enum ThrusterEvent {\n\tActivate = 'activate',\n\tDeactivate = 'deactivate',\n\tBoost = 'boost',\n\tEndBoost = 'endBoost',\n\tDisable = 'disable',\n\tEnable = 'enable',\n\tDock = 'dock',\n\tUndock = 'undock',\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// FSM Context Object\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface ThrusterFSMContext {\n\tinput: ThrusterInputComponent;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Player Input (raw input from controller/keyboard)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface PlayerInput {\n\tthrust: number;\n\trotate: number;\n\tthrustX?: number;\n\tthrustY?: number;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// ThrusterFSM Controller\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport class ThrusterFSM {\n\tmachine: SyncStateMachine<ThrusterState, ThrusterEvent, never>;\n\n\tconstructor(private ctx: ThrusterFSMContext) {\n\t\tthis.machine = new SyncStateMachine<ThrusterState, ThrusterEvent, never>(\n\t\t\tThrusterState.Idle,\n\t\t\t[\n\t\t\t\t// Core transitions\n\t\t\t\tt(ThrusterState.Idle, ThrusterEvent.Activate, ThrusterState.Active),\n\t\t\t\tt(ThrusterState.Active, ThrusterEvent.Deactivate, ThrusterState.Idle),\n\t\t\t\tt(ThrusterState.Active, ThrusterEvent.Boost, ThrusterState.Boosting),\n\t\t\t\tt(ThrusterState.Active, ThrusterEvent.Disable, ThrusterState.Disabled),\n\t\t\t\tt(ThrusterState.Active, ThrusterEvent.Dock, ThrusterState.Docked),\n\t\t\t\tt(ThrusterState.Boosting, ThrusterEvent.EndBoost, ThrusterState.Active),\n\t\t\t\tt(ThrusterState.Boosting, ThrusterEvent.Disable, ThrusterState.Disabled),\n\t\t\t\tt(ThrusterState.Disabled, ThrusterEvent.Enable, ThrusterState.Idle),\n\t\t\t\tt(ThrusterState.Docked, ThrusterEvent.Undock, ThrusterState.Idle),\n\t\t\t\t// Self-transitions (no-ops for redundant events)\n\t\t\t\tt(ThrusterState.Idle, ThrusterEvent.Deactivate, ThrusterState.Idle),\n\t\t\t\tt(ThrusterState.Active, ThrusterEvent.Activate, ThrusterState.Active),\n\t\t\t]\n\t\t);\n\t}\n\n\t/**\n\t * Get current state\n\t */\n\tgetState(): ThrusterState {\n\t\treturn this.machine.getState();\n\t}\n\n\t/**\n\t * Dispatch an event to transition state\n\t */\n\tdispatch(event: ThrusterEvent): void {\n\t\tif (this.machine.can(event)) {\n\t\t\tthis.machine.syncDispatch(event);\n\t\t}\n\t}\n\n\t/**\n\t * Update FSM state based on player input.\n\t * Auto-transitions between Idle/Active to report current state.\n\t * Does NOT modify input - just observes and reports.\n\t */\n\tupdate(playerInput: PlayerInput): void {\n\t\tconst state = this.machine.getState();\n\t\tconst hasInput =\n\t\t\tMath.abs(playerInput.thrust) > 0.01\n\t\t\t|| Math.abs(playerInput.rotate) > 0.01\n\t\t\t|| Math.abs(playerInput.thrustX ?? 0) > 0.01\n\t\t\t|| Math.abs(playerInput.thrustY ?? 0) > 0.01;\n\n\t\t// Auto-transition to report state based on input\n\t\tif (hasInput && state === ThrusterState.Idle) {\n\t\t\tthis.dispatch(ThrusterEvent.Activate);\n\t\t} else if (!hasInput && state === ThrusterState.Active) {\n\t\t\tthis.dispatch(ThrusterEvent.Deactivate);\n\t\t}\n\t}\n}\n","/**\n * Thruster Behavior Descriptor\n *\n * Type-safe descriptor for the thruster behavior using the entity.use() API.\n * The wasm runtime owns the thruster simulation; this system attaches the\n * Rust behavior and forwards input into the slot-indexed input buffer.\n */\n\nimport { defineBehavior } from '../behavior-descriptor';\nimport type { BehaviorEntityLink, BehaviorSystem } from '../behavior-system';\nimport {\n\tcreateThrusterInputComponent,\n\tcreateThrusterMovementComponent,\n\ttype ThrusterMovementComponent,\n\ttype ThrusterInputComponent,\n} from './components';\nimport type { BehaviorRuntime } from '../../runtime/wasm-stage-runtime';\n\n/**\n * Entity with thruster components (input written by the game, state owned by\n * the wasm runtime).\n */\nexport interface ThrusterEntity {\n\tthruster: ThrusterMovementComponent;\n\t$thruster: ThrusterInputComponent;\n}\n\n/**\n * Thruster behavior options (typed for entity.use() autocomplete)\n */\nexport interface ThrusterBehaviorOptions {\n\t/** Forward thrust force (default: 10) */\n\tlinearThrust: number;\n\t/** Rotation torque (default: 5) */\n\tangularThrust: number;\n\t/** Optional linear damping override */\n\tlinearDamping?: number;\n}\n\nconst defaultOptions: ThrusterBehaviorOptions = {\n\tlinearThrust: 10,\n\tangularThrust: 5,\n\tlinearDamping: undefined,\n};\n\nconst THRUSTER_BEHAVIOR_KEY = Symbol.for('zylem:behavior:thruster');\n\n/**\n * Adapter that forwards thruster input into the wasm runtime.\n *\n * The Rust `thruster` Stage behavior is the single simulation path: this\n * system attaches it once per entity and writes `$thruster` input into the\n * slot-indexed input buffer each frame.\n */\nclass ThrusterBehaviorSystem implements BehaviorSystem {\n\tprivate attachedRuntimeSlots = new Set<number>();\n\n\tconstructor(\n\t\tprivate wasmStage: BehaviorRuntime | null,\n\t\tprivate getBehaviorLinks?: (key: symbol) => Iterable<BehaviorEntityLink>,\n\t) {}\n\n\tupdate(_ecs: unknown, _delta: number): void {\n\t\tconst links = this.getBehaviorLinks?.(THRUSTER_BEHAVIOR_KEY);\n\t\tif (!links) return;\n\n\t\tfor (const link of links) {\n\t\t\tconst gameEntity = link.entity as any;\n\t\t\tconst thrusterRef = link.ref as any;\n\n\t\t\tconst options = thrusterRef.options as ThrusterBehaviorOptions;\n\n\t\t\tif (!gameEntity.thruster) {\n\t\t\t\tgameEntity.thruster = createThrusterMovementComponent(\n\t\t\t\t\toptions.linearThrust,\n\t\t\t\t\toptions.angularThrust,\n\t\t\t\t\t{ linearDamping: options.linearDamping },\n\t\t\t\t) as ThrusterMovementComponent;\n\t\t\t}\n\n\t\t\tif (!gameEntity.$thruster) {\n\t\t\t\tgameEntity.$thruster = createThrusterInputComponent() as ThrusterInputComponent;\n\t\t\t}\n\n\t\t\tconst handle = (gameEntity.runtimeHandle ?? -1) as number;\n\t\t\tif (!this.wasmStage || handle < 0) continue;\n\n\t\t\tthis.ensureWasmAttached(handle, options);\n\t\t\tconst input = gameEntity.$thruster as ThrusterInputComponent | undefined;\n\t\t\tif (input) {\n\t\t\t\tthis.wasmStage.writeInputAxes(handle, input.thrust, input.rotate);\n\t\t\t\tthis.wasmStage.writeInputReserved(handle, input.thrustX, input.thrustY);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate ensureWasmAttached(handle: number, options: ThrusterBehaviorOptions): void {\n\t\tif (!this.wasmStage || this.attachedRuntimeSlots.has(handle)) return;\n\t\tthis.wasmStage.attachThruster(handle, {\n\t\t\tmaxSpeed: 50,\n\t\t\tacceleration: options.linearThrust,\n\t\t\tturnRateRadPerSec: options.angularThrust,\n\t\t\tlinearDamping: options.linearDamping ?? 0,\n\t\t});\n\t\tthis.attachedRuntimeSlots.add(handle);\n\t}\n\n\tdestroy(_ecs: unknown): void {\n\t\tthis.attachedRuntimeSlots.clear();\n\t}\n}\n\n/**\n * ThrusterBehavior - typed descriptor for thruster movement.\n *\n * @example\n * ```typescript\n * import { ThrusterBehavior } from \"@zylem/game-lib/behavior\";\n *\n * const ship = createSprite({ ... });\n * ship.use(ThrusterBehavior, { linearThrust: 15, angularThrust: 8 });\n * ```\n */\nexport const ThrusterBehavior = defineBehavior<ThrusterBehaviorOptions, Record<string, never>, ThrusterEntity>({\n\tname: 'thruster',\n\tdefaultOptions,\n\tsystemFactory: (ctx) =>\n\t\tnew ThrusterBehaviorSystem(ctx.wasmStage ?? null, ctx.getBehaviorLinks),\n});\n"],"mappings":"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","names":["ThrusterState","ThrusterEvent"]}
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  SyncStateMachine,
3
3
  import_typescript_fsm
4
- } from "./chunk-OBF6BIA2.js";
4
+ } from "./chunk-AS3HR7AS.js";
5
5
  import {
6
6
  StageRicochetDim,
7
7
  StageRicochetReflection
8
- } from "./chunk-GZ3DQIIZ.js";
8
+ } from "./chunk-4GW6DCYF.js";
9
9
  import {
10
10
  defineBehavior
11
- } from "./chunk-YDLO5M7S.js";
11
+ } from "./chunk-EZNCCO4L.js";
12
12
 
13
13
  // src/lib/behaviors/ricochet-2d/ricochet-2d-fsm.ts
14
14
  function bodyOf(entity) {
@@ -419,3 +419,4 @@ export {
419
419
  Ricochet2DFSM,
420
420
  Ricochet2DBehavior
421
421
  };
422
+ //# sourceMappingURL=chunk-D7N6SC4D.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/behaviors/ricochet-2d/ricochet-2d-fsm.ts","../src/lib/behaviors/ricochet-2d/ricochet-2d.descriptor.ts"],"sourcesContent":["/**\n * Ricochet2DFSM\n *\n * FSM + extended state to track ricochet events and results.\n * The FSM state tracks whether a ricochet is currently occurring.\n */\nimport { BaseEntityInterface } from \"../../types/entity-types\";\nimport { SyncStateMachine, t } from '../../core/utility/sync-state-machine';\n\nexport interface Ricochet2DResult {\n\t/** The reflected velocity vector */\n\tvelocity: { x: number; y: number; z?: number };\n\t/** The resulting speed after reflection */\n\tspeed: number;\n\t/** The collision normal used for reflection */\n\tnormal: { x: number; y: number; z?: number };\n}\n\nexport interface Ricochet2DCollisionContext {\n\tentity?: BaseEntityInterface;\n\totherEntity?: BaseEntityInterface;\n\t/** Current velocity of the entity (optional if entity is provided) */\n\tselfVelocity?: { x: number; y: number; z?: number };\n\t/** Contact information from the collision */\n\tcontact: {\n\t\t/** The collision normal */\n\t\tnormal?: { x: number; y: number; z?: number };\n\t\t/**\n\t\t * Optional position where the collision occurred.\n\t\t * If provided, used for precise offset calculation.\n\t\t */\n\t\tposition?: { x: number; y: number; z?: number };\n\t};\n\t/**\n\t * Optional position of the entity that owns this behavior.\n\t * Used with contact.position for offset calculations.\n\t */\n\tselfPosition?: { x: number; y: number; z?: number };\n\t/**\n\t * Optional position of the other entity in the collision.\n\t * Used for paddle-style deflection: offset = (contactY - otherY) / halfHeight.\n\t */\n\totherPosition?: { x: number; y: number; z?: number };\n\t/**\n\t * Optional size of the other entity (e.g., paddle size).\n\t * If provided, used to normalize the offset based on the collision face.\n\t */\n\totherSize?: { x: number; y: number; z?: number };\n}\n\n/** Structural view of a host-attached body (harness/simulation facade). */\ninterface RicochetBodyLike {\n\tlinvel(): { x: number; y: number; z: number };\n\ttranslation(): { x: number; y: number; z: number };\n}\n\nfunction bodyOf(entity: BaseEntityInterface | undefined): RicochetBodyLike | null {\n\tconst body = entity?.body as Partial<RicochetBodyLike> | null | undefined;\n\tif (body && typeof body.linvel === 'function' && typeof body.translation === 'function') {\n\t\treturn body as RicochetBodyLike;\n\t}\n\treturn null;\n}\n\nexport enum Ricochet2DState {\n\tIdle = 'idle',\n\tRicocheting = 'ricocheting',\n}\n\nexport enum Ricochet2DEvent {\n\tStartRicochet = 'start-ricochet',\n\tEndRicochet = 'end-ricochet',\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n\treturn Math.max(min, Math.min(max, value));\n}\n\n/**\n * Callback type for ricochet event listeners.\n */\nexport type RicochetCallback = (result: Ricochet2DResult) => void;\n\n/**\n * FSM wrapper with extended state (lastResult).\n * Systems or consumers call `computeRicochet(...)` when a collision occurs.\n */\nexport class Ricochet2DFSM {\n\tpublic readonly machine: SyncStateMachine<Ricochet2DState, Ricochet2DEvent, never>;\n\n\tprivate lastResult: Ricochet2DResult | null = null;\n\tprivate lastUpdatedAtMs: number | null = null;\n\tprivate currentTimeMs: number = 0;\n\tprivate listeners: Set<RicochetCallback> = new Set();\n\n\tconstructor() {\n\t\tthis.machine = new SyncStateMachine<Ricochet2DState, Ricochet2DEvent, never>(\n\t\t\tRicochet2DState.Idle,\n\t\t\t[\n\t\t\t\tt(Ricochet2DState.Idle, Ricochet2DEvent.StartRicochet, Ricochet2DState.Ricocheting),\n\t\t\t\tt(Ricochet2DState.Ricocheting, Ricochet2DEvent.EndRicochet, Ricochet2DState.Idle),\n\n\t\t\t\t// Self transitions (no-ops)\n\t\t\t\tt(Ricochet2DState.Idle, Ricochet2DEvent.EndRicochet, Ricochet2DState.Idle),\n\t\t\t\tt(Ricochet2DState.Ricocheting, Ricochet2DEvent.StartRicochet, Ricochet2DState.Ricocheting),\n\t\t\t]\n\t\t);\n\t}\n\n\t/**\n\t * Add a listener for ricochet events.\n\t * @returns Unsubscribe function\n\t */\n\taddListener(callback: RicochetCallback): () => void {\n\t\tthis.listeners.add(callback);\n\t\treturn () => this.listeners.delete(callback);\n\t}\n\n\t/**\n\t * Emit result to all listeners.\n\t */\n\tprivate emitToListeners(result: Ricochet2DResult): void {\n\t\tfor (const callback of this.listeners) {\n\t\t\ttry {\n\t\t\t\tcallback(result);\n\t\t\t} catch (e) {\n\t\t\t\tconsole.error('[Ricochet2DFSM] Listener error:', e);\n\t\t\t}\n\t\t}\n\t}\n\n\tgetState(): Ricochet2DState {\n\t\treturn this.machine.getState();\n\t}\n\n\t/**\n\t * Returns the last computed ricochet result, or null if none.\n\t */\n\tgetLastResult(): Ricochet2DResult | null {\n\t\treturn this.lastResult;\n\t}\n\n\t/**\n\t * Best-effort timestamp (ms) of the last computation.\n\t */\n\tgetLastUpdatedAtMs(): number | null {\n\t\treturn this.lastUpdatedAtMs;\n\t}\n\n\t/**\n\t * Set current game time (called by system each frame).\n\t * Used for cooldown calculations.\n\t */\n\tsetCurrentTimeMs(timeMs: number): void {\n\t\tthis.currentTimeMs = timeMs;\n\t}\n\n\t/**\n\t * Check if ricochet is on cooldown (to prevent rapid duplicate applications).\n\t * @param cooldownMs Cooldown duration in milliseconds (default: 50ms)\n\t */\n\tisOnCooldown(cooldownMs: number = 50): boolean {\n\t\tif (this.lastUpdatedAtMs === null) return false;\n\t\treturn (this.currentTimeMs - this.lastUpdatedAtMs) < cooldownMs;\n\t}\n\n\t/**\n\t * Reset cooldown state (e.g., on entity respawn).\n\t */\n\tresetCooldown(): void {\n\t\tthis.lastUpdatedAtMs = null;\n\t}\n\n\t/**\n\t * Compute a ricochet result from collision context.\n\t * Returns the result for the consumer to apply, or null if invalid input.\n\t */\n\tcomputeRicochet(\n\t\tctx: Ricochet2DCollisionContext,\n\t\toptions: {\n\t\t\tminSpeed?: number;\n\t\t\tmaxSpeed?: number;\n\t\t\tspeedMultiplier?: number;\n\t\t\treflectionMode?: 'simple' | 'angled';\n\t\t\tmaxAngleDeg?: number;\n\t\t} = {}\n\t): Ricochet2DResult | null {\n\t\tconst {\n\t\t\tminSpeed = 2,\n\t\t\tmaxSpeed = 20,\n\t\t\tspeedMultiplier = 1.05,\n\t\t\treflectionMode = 'angled',\n\t\t\tmaxAngleDeg = 60,\n\t\t} = options;\n\n\t\t// Extract data from entities if provided\n\t\tconst { selfVelocity, selfPosition, otherPosition, otherSize } = this.extractDataFromEntities(ctx);\n\n\t\tif (!selfVelocity) {\n\t\t\tthis.dispatch(Ricochet2DEvent.EndRicochet);\n\t\t\treturn null;\n\t\t}\n\n\t\tconst speed = Math.hypot(selfVelocity.x, selfVelocity.y);\n\t\tif (speed === 0) {\n\t\t\tthis.dispatch(Ricochet2DEvent.EndRicochet);\n\t\t\treturn null;\n\t\t}\n\n\t\t// Compute or extract collision normal\n\t\tconst normal = ctx.contact.normal ?? this.computeNormalFromPositions(selfPosition, otherPosition);\n\t\tif (!normal) {\n\t\t\tthis.dispatch(Ricochet2DEvent.EndRicochet);\n\t\t\treturn null;\n\t\t}\n\n\t\t// Compute basic reflection\n\t\tlet reflected = this.computeBasicReflection(selfVelocity, normal);\n\n\t\t// Apply angled deflection if requested\n\t\tif (reflectionMode === 'angled') {\n\t\t\treflected = this.computeAngledDeflection(\n\t\t\t\tselfVelocity,\n\t\t\t\tnormal,\n\t\t\t\tspeed,\n\t\t\t\tmaxAngleDeg,\n\t\t\t\tspeedMultiplier,\n\t\t\t\tselfPosition,\n\t\t\t\totherPosition,\n\t\t\t\totherSize,\n\t\t\t\tctx.contact.position\n\t\t\t);\n\t\t}\n\n\t\t// Apply final speed constraints\n\t\treflected = this.applySpeedClamp(reflected, minSpeed, maxSpeed);\n\n\t\tconst result: Ricochet2DResult = {\n\t\t\tvelocity: { x: reflected.x, y: reflected.y, z: 0 },\n\t\t\tspeed: Math.hypot(reflected.x, reflected.y),\n\t\t\tnormal: { x: normal.x, y: normal.y, z: 0 },\n\t\t};\n\n\t\tthis.lastResult = result;\n\t\tthis.lastUpdatedAtMs = this.currentTimeMs;\n\t\tthis.dispatch(Ricochet2DEvent.StartRicochet);\n\t\tthis.emitToListeners(result);\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Extract velocity, position, and size data from entities or context.\n\t */\n\tprivate extractDataFromEntities(ctx: Ricochet2DCollisionContext) {\n\t\tlet selfVelocity = ctx.selfVelocity;\n\t\tlet selfPosition = ctx.selfPosition;\n\t\tlet otherPosition = ctx.otherPosition;\n\t\tlet otherSize = ctx.otherSize;\n\n\t\tconst selfBody = bodyOf(ctx.entity);\n\t\tif (selfBody) {\n\t\t\tconst vel = selfBody.linvel();\n\t\t\tselfVelocity = selfVelocity ?? { x: vel.x, y: vel.y, z: vel.z };\n\t\t\tconst pos = selfBody.translation();\n\t\t\tselfPosition = selfPosition ?? { x: pos.x, y: pos.y, z: pos.z };\n\t\t}\n\n\t\tconst otherBody = bodyOf(ctx.otherEntity);\n\t\tif (otherBody) {\n\t\t\tconst pos = otherBody.translation();\n\t\t\totherPosition = otherPosition ?? { x: pos.x, y: pos.y, z: pos.z };\n\t\t}\n\n\t\tif (ctx.otherEntity && 'size' in ctx.otherEntity) {\n\t\t\tconst size = (ctx.otherEntity as any).size;\n\t\t\tif (size && typeof size.x === 'number') {\n\t\t\t\totherSize = otherSize ?? { x: size.x, y: size.y, z: size.z };\n\t\t\t}\n\t\t}\n\n\t\treturn { selfVelocity, selfPosition, otherPosition, otherSize };\n\t}\n\n\t/**\n\t * Compute collision normal from entity positions using AABB heuristic.\n\t */\n\tprivate computeNormalFromPositions(\n\t\tselfPosition?: { x: number; y: number; z?: number },\n\t\totherPosition?: { x: number; y: number; z?: number }\n\t): { x: number; y: number; z?: number } | null {\n\t\tif (!selfPosition || !otherPosition) return null;\n\n\t\tconst dx = selfPosition.x - otherPosition.x;\n\t\tconst dy = selfPosition.y - otherPosition.y;\n\n\t\t// Simple \"which face was hit\" logic for box collisions\n\t\tif (Math.abs(dx) > Math.abs(dy)) {\n\t\t\treturn { x: dx > 0 ? 1 : -1, y: 0, z: 0 };\n\t\t} else {\n\t\t\treturn { x: 0, y: dy > 0 ? 1 : -1, z: 0 };\n\t\t}\n\t}\n\n\t/**\n\t * Compute basic reflection using the formula: v' = v - 2(v·n)n\n\t */\n\tprivate computeBasicReflection(\n\t\tvelocity: { x: number; y: number },\n\t\tnormal: { x: number; y: number; z?: number }\n\t): { x: number; y: number } {\n\t\tconst vx = velocity.x;\n\t\tconst vy = velocity.y;\n\t\tconst dotProduct = vx * normal.x + vy * normal.y;\n\n\t\treturn {\n\t\t\tx: vx - 2 * dotProduct * normal.x,\n\t\t\ty: vy - 2 * dotProduct * normal.y,\n\t\t};\n\t}\n\n\t/**\n\t * Compute angled deflection for paddle-style reflections.\n\t */\n\tprivate computeAngledDeflection(\n\t\tvelocity: { x: number; y: number },\n\t\tnormal: { x: number; y: number; z?: number },\n\t\tspeed: number,\n\t\tmaxAngleDeg: number,\n\t\tspeedMultiplier: number,\n\t\tselfPosition?: { x: number; y: number; z?: number },\n\t\totherPosition?: { x: number; y: number; z?: number },\n\t\totherSize?: { x: number; y: number; z?: number },\n\t\tcontactPosition?: { x: number; y: number; z?: number }\n\t): { x: number; y: number } {\n\t\tconst maxAngleRad = (maxAngleDeg * Math.PI) / 180;\n\n\t\t// Tangent vector (perpendicular to normal)\n\t\tlet tx = -normal.y;\n\t\tlet ty = normal.x;\n\n\t\t// Ensure tangent points in positive direction of the deflection axis\n\t\t// so that positive offset (right/top) results in positive deflection\n\t\tif (Math.abs(normal.x) > Math.abs(normal.y)) {\n\t\t\t// Vertical face (Normal is X-aligned). Deflection axis is Y.\n\t\t\t// We want ty > 0.\n\t\t\tif (ty < 0) {\n\t\t\t\ttx = -tx;\n\t\t\t\tty = -ty;\n\t\t\t}\n\t\t} else {\n\t\t\t// Horizontal face (Normal is Y-aligned). Deflection axis is X.\n\t\t\t// We want tx > 0.\n\t\t\tif (tx < 0) {\n\t\t\t\ttx = -tx;\n\t\t\t\tty = -ty;\n\t\t\t}\n\t\t}\n\n\t\t// Compute offset based on hit position\n\t\tconst offset = this.computeHitOffset(\n\t\t\tvelocity,\n\t\t\tnormal,\n\t\t\tspeed,\n\t\t\ttx,\n\t\t\tty,\n\t\t\tselfPosition,\n\t\t\totherPosition,\n\t\t\totherSize,\n\t\t\tcontactPosition\n\t\t);\n\n\t\tconst angle = clamp(offset, -1, 1) * maxAngleRad;\n\n\t\tconst cosA = Math.cos(angle);\n\t\tconst sinA = Math.sin(angle);\n\n\t\tconst newSpeed = speed * speedMultiplier;\n\n\t\treturn {\n\t\t\tx: newSpeed * (normal.x * cosA + tx * sinA),\n\t\t\ty: newSpeed * (normal.y * cosA + ty * sinA),\n\t\t};\n\t}\n\n\t/**\n\t * Compute hit offset for angled deflection (-1 to 1).\n\t */\n\tprivate computeHitOffset(\n\t\tvelocity: { x: number; y: number },\n\t\tnormal: { x: number; y: number; z?: number },\n\t\tspeed: number,\n\t\ttx: number,\n\t\tty: number,\n\t\tselfPosition?: { x: number; y: number; z?: number },\n\t\totherPosition?: { x: number; y: number; z?: number },\n\t\totherSize?: { x: number; y: number; z?: number },\n\t\tcontactPosition?: { x: number; y: number; z?: number }\n\t): number {\n\t\t// Use position-based offset if available\n\t\tif (otherPosition && otherSize) {\n\t\t\tconst useY = Math.abs(normal.x) > Math.abs(normal.y);\n\t\t\tconst halfExtent = useY ? otherSize.y / 2 : otherSize.x / 2;\n\n\t\t\tif (useY) {\n\t\t\t\tconst selfY = selfPosition?.y ?? contactPosition?.y ?? 0;\n\t\t\t\tconst paddleY = otherPosition.y;\n\t\t\t\treturn (selfY - paddleY) / halfExtent;\n\t\t\t} else {\n\t\t\t\tconst selfX = selfPosition?.x ?? contactPosition?.x ?? 0;\n\t\t\t\tconst paddleX = otherPosition.x;\n\t\t\t\treturn (selfX - paddleX) / halfExtent;\n\t\t\t}\n\t\t}\n\n\t\t// Fallback: use velocity-based offset\n\t\treturn (velocity.x * tx + velocity.y * ty) / speed;\n\t}\n\n\t/**\n\t * Apply speed constraints to the reflected velocity.\n\t */\n\tprivate applySpeedClamp(\n\t\tvelocity: { x: number; y: number },\n\t\tminSpeed: number,\n\t\tmaxSpeed: number\n\t): { x: number; y: number } {\n\t\tconst currentSpeed = Math.hypot(velocity.x, velocity.y);\n\t\tif (currentSpeed === 0) return velocity;\n\n\t\tconst targetSpeed = clamp(currentSpeed, minSpeed, maxSpeed);\n\t\tconst scale = targetSpeed / currentSpeed;\n\n\t\treturn {\n\t\t\tx: velocity.x * scale,\n\t\t\ty: velocity.y * scale,\n\t\t};\n\t}\n\n\t/**\n\t * Clear the ricochet state (call after consumer has applied the result).\n\t */\n\tclearRicochet(): void {\n\t\tthis.dispatch(Ricochet2DEvent.EndRicochet);\n\t}\n\n\tprivate dispatch(event: Ricochet2DEvent): void {\n\t\tif (this.machine.can(event)) {\n\t\t\tthis.machine.syncDispatch(event);\n\t\t}\n\t}\n}\n","/**\n * Ricochet2DBehavior\n *\n * Computes 2D ricochet/reflection results for entities during collisions.\n * The behavior computes the result; the consumer decides how to apply it.\n *\n * Use `getRicochet(ctx)` on the behavior handle to compute reflection results.\n */\n\nimport { defineBehavior, type BehaviorRef } from '../behavior-descriptor';\nimport type { BehaviorEntityLink, BehaviorSystem } from '../behavior-system';\nimport { Ricochet2DFSM, type Ricochet2DResult, type Ricochet2DCollisionContext, type RicochetCallback } from './ricochet-2d-fsm';\nimport {\n\tStageRicochetDim,\n\tStageRicochetReflection,\n\ttype BehaviorRuntime,\n} from '../../runtime/wasm-stage-runtime';\nexport type { Ricochet2DResult };\n\nexport interface Ricochet2DOptions {\n\t/**\n\t * Minimum speed after reflection.\n\t * Default: 2\n\t */\n\tminSpeed: number;\n\n\t/**\n\t * Maximum speed after reflection.\n\t * Default: 20\n\t */\n\tmaxSpeed: number;\n\n\t/**\n\t * Speed multiplier applied during angled reflection.\n\t * Default: 1.05\n\t */\n\tspeedMultiplier: number;\n\n\t/**\n\t * Reflection mode:\n\t * - 'simple': Basic axis inversion\n\t * - 'angled': Paddle-style deflection based on contact point\n\t * Default: 'angled'\n\t */\n\treflectionMode: 'simple' | 'angled';\n\n\t/**\n\t * Maximum deflection angle in degrees for angled mode.\n\t * Default: 60\n\t */\n\tmaxAngleDeg: number;\n}\n\n/**\n * Handle methods provided by Ricochet2DBehavior\n */\nexport interface Ricochet2DHandle {\n\t/**\n\t * Compute a ricochet/reflection result from collision context.\n\t * Returns the result for the consumer to apply, or null if invalid input.\n\t *\n\t * @param ctx - Collision context with selfVelocity and contact normal\n\t * @returns Ricochet result with velocity, speed, and normal, or null\n\t */\n\tgetRicochet(ctx: Ricochet2DCollisionContext): Ricochet2DResult | null;\n\n\t/**\n\t * Compute ricochet and apply velocity directly via transformStore.\n\t * Emits to onRicochet listeners if successful.\n\t *\n\t * @param ctx - Collision context with entity and contact normal\n\t * @returns true if ricochet was computed and applied, false otherwise\n\t */\n\tapplyRicochet(ctx: Ricochet2DCollisionContext): boolean;\n\n\t/**\n\t * Get the last computed ricochet result, or null if none.\n\t */\n\tgetLastResult(): Ricochet2DResult | null;\n\n\t/**\n\t * Register a listener for ricochet events.\n\t * Called whenever a ricochet is computed (from getRicochet or applyRicochet).\n\t *\n\t * @param callback - Function to call with ricochet result\n\t * @returns Unsubscribe function\n\t */\n\tonRicochet(callback: RicochetCallback): () => void;\n}\n\nconst defaultOptions: Ricochet2DOptions = {\n\tminSpeed: 2,\n\tmaxSpeed: 20,\n\tspeedMultiplier: 1.05,\n\treflectionMode: 'angled',\n\tmaxAngleDeg: 60,\n};\n\nconst RICOCHET_BEHAVIOR_KEY = Symbol.for('zylem:behavior:ricochet-2d');\n\n/**\n * Creates behavior-specific handle methods for Ricochet2DBehavior.\n */\nfunction createRicochet2DHandle(\n\tref: BehaviorRef<Ricochet2DOptions>\n): Ricochet2DHandle {\n\treturn {\n\t\tgetRicochet: (ctx: Ricochet2DCollisionContext) => {\n\t\t\tconst fsm = ref.fsm as Ricochet2DFSM | undefined;\n\t\t\tif (!fsm) return null;\n\t\t\treturn fsm.computeRicochet(ctx, ref.options);\n\t\t},\n\t\tapplyRicochet: (ctx: Ricochet2DCollisionContext): boolean => {\n\t\t\tconst fsm = ref.fsm as Ricochet2DFSM | undefined;\n\t\t\tif (!fsm) return false;\n\n\t\t\t// Skip if on cooldown (prevents rapid duplicate applications)\n\t\t\tif (fsm.isOnCooldown()) return false;\n\n\t\t\tconst result = fsm.computeRicochet(ctx, ref.options);\n\t\t\tif (!result) return false;\n\n\t\t\t// Apply velocity via transformStore\n\t\t\tconst entity = ctx.entity as any;\n\t\t\tif (entity?.transformStore) {\n\t\t\t\tentity.transformStore.velocity.x = result.velocity.x;\n\t\t\t\tentity.transformStore.velocity.y = result.velocity.y;\n\t\t\t\tentity.transformStore.velocity.z = result.velocity.z ?? 0;\n\t\t\t\tentity.transformStore.dirty.velocityX = true;\n\t\t\t\tentity.transformStore.dirty.velocityY = true;\n\t\t\t\tentity.transformStore.dirty.velocityZ = true;\n\t\t\t}\n\n\t\t\treturn true;\n\t\t},\n\t\tgetLastResult: () => {\n\t\t\tconst fsm = ref.fsm as Ricochet2DFSM | undefined;\n\t\t\treturn fsm?.getLastResult() ?? null;\n\t\t},\n\t\tonRicochet: (callback: RicochetCallback): (() => void) => {\n\t\t\tconst fsm = ref.fsm as Ricochet2DFSM | undefined;\n\t\t\tif (!fsm) {\n\t\t\t\t// FSM not ready yet - queue callback for later\n\t\t\t\t// System will apply pending callbacks when FSM is created\n\t\t\t\tif (!(ref as any).pendingListeners) {\n\t\t\t\t\t(ref as any).pendingListeners = [];\n\t\t\t\t}\n\t\t\t\t(ref as any).pendingListeners.push(callback);\n\t\t\t\t\n\t\t\t\t// Return unsubscribe that removes from pending queue\n\t\t\t\treturn () => {\n\t\t\t\t\tconst pending = (ref as any).pendingListeners as RicochetCallback[];\n\t\t\t\t\tconst idx = pending.indexOf(callback);\n\t\t\t\t\tif (idx >= 0) pending.splice(idx, 1);\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn fsm.addListener(callback);\n\t\t},\n\t};\n}\n\n/**\n * Ricochet2DSystem\n *\n * Stage-level system that:\n * - finds entities with this behavior attached\n * - lazily creates FSM instances for each entity\n *\n * Note: This behavior is consumer-driven. The system only manages FSM lifecycle.\n * Consumers call `getRicochet(ctx)` during collision callbacks to compute results.\n */\nclass Ricochet2DSystem implements BehaviorSystem {\n\tprivate elapsedMs: number = 0;\n\tprivate attachedRuntimeSlots = new Set<number>();\n\n\tconstructor(\n\t\tprivate wasmStage: BehaviorRuntime | null,\n\t\tprivate getBehaviorLinks?: (key: symbol) => Iterable<BehaviorEntityLink>,\n\t) {}\n\n\tupdate(_ecs: unknown, delta: number): void {\n\t\tthis.elapsedMs += delta * 1000;\n\n\t\tconst links = this.getBehaviorLinks?.(RICOCHET_BEHAVIOR_KEY);\n\t\tif (!links) return;\n\n\t\tfor (const link of links) {\n\t\t\tconst ricochetRef = link.ref as any;\n\t\t\tconst gameEntity = link.entity as any;\n\n\t\t\tif (!ricochetRef.fsm) {\n\t\t\t\tricochetRef.fsm = new Ricochet2DFSM();\n\n\t\t\t\tconst pending = (ricochetRef as any).pendingListeners as RicochetCallback[] | undefined;\n\t\t\t\tif (pending) {\n\t\t\t\t\tfor (const cb of pending) {\n\t\t\t\t\t\tricochetRef.fsm.addListener(cb);\n\t\t\t\t\t}\n\t\t\t\t\t(ricochetRef as any).pendingListeners = [];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tricochetRef.fsm.setCurrentTimeMs(this.elapsedMs);\n\n\t\t\tconst handle = (gameEntity?.runtimeHandle ?? -1) as number;\n\t\t\tif (this.wasmStage && handle >= 0) {\n\t\t\t\tthis.ensureWasmAttached(handle, ricochetRef.options as Ricochet2DOptions);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate ensureWasmAttached(handle: number, options: Ricochet2DOptions): void {\n\t\tif (!this.wasmStage || this.attachedRuntimeSlots.has(handle)) return;\n\t\tconst reflectionMode = options.reflectionMode === 'simple'\n\t\t\t? StageRicochetReflection.Mirror\n\t\t\t: StageRicochetReflection.Angled;\n\t\tthis.wasmStage.attachRicochet(handle, StageRicochetDim.Two, {\n\t\t\tminSpeed: options.minSpeed,\n\t\t\tmaxSpeed: options.maxSpeed,\n\t\t\tspeedMultiplier: options.speedMultiplier,\n\t\t\tmaxAngleDeg: options.maxAngleDeg,\n\t\t\treflectionMode,\n\t\t});\n\t\tthis.attachedRuntimeSlots.add(handle);\n\t}\n\n\tdestroy(_ecs: unknown): void {\n\t\tconst links = this.getBehaviorLinks?.(RICOCHET_BEHAVIOR_KEY);\n\t\tif (links) {\n\t\t\tfor (const link of links) {\n\t\t\t\tconst ricochetRef = link.ref as any;\n\t\t\t\tif (ricochetRef?.fsm) {\n\t\t\t\t\tricochetRef.fsm.resetCooldown();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthis.attachedRuntimeSlots.clear();\n\t}\n}\n\n/**\n * Ricochet2DBehavior\n *\n * @example\n * ```ts\n * import { Ricochet2DBehavior } from \"@zylem/game-lib/behavior\";\n *\n * const ball = createSphere({ ... });\n * const ricochet = ball.use(Ricochet2DBehavior, {\n * minSpeed: 3,\n * maxSpeed: 15,\n * reflectionMode: 'angled',\n * });\n *\n * ball.onCollision(({ entity, other }) => {\n * const velocity = entity.body.linvel();\n * const result = ricochet.getRicochet({\n * selfVelocity: velocity,\n * contact: { normal: { x: 1, y: 0 } }, // from collision data\n * });\n *\n * if (result) {\n * entity.body.setLinvel(result.velocity, true);\n * }\n * });\n * ```\n */\nexport const Ricochet2DBehavior = defineBehavior({\n\tname: 'ricochet-2d',\n\tdefaultOptions,\n\tsystemFactory: (ctx) =>\n\t\tnew Ricochet2DSystem(ctx.wasmStage ?? null, ctx.getBehaviorLinks),\n\tcreateHandle: createRicochet2DHandle,\n});\n"],"mappings":"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","names":["Ricochet2DState","Ricochet2DEvent"]}
@@ -2,22 +2,22 @@ import {
2
2
  createFirstPersonInputComponent,
3
3
  createFirstPersonMovementComponent,
4
4
  createFirstPersonStateComponent
5
- } from "./chunk-4EWASZHB.js";
5
+ } from "./chunk-QVCMJ4Q2.js";
6
6
  import {
7
7
  VEC3_ZERO,
8
8
  toThreeVector3
9
- } from "./chunk-LWM346FW.js";
9
+ } from "./chunk-M3QDKKDF.js";
10
10
  import {
11
11
  SyncStateMachine,
12
12
  import_typescript_fsm
13
- } from "./chunk-OBF6BIA2.js";
13
+ } from "./chunk-AS3HR7AS.js";
14
14
  import {
15
15
  STAGE_INPUT_BUTTON_RUN,
16
16
  readBehaviorSnapshot
17
- } from "./chunk-GZ3DQIIZ.js";
17
+ } from "./chunk-4GW6DCYF.js";
18
18
  import {
19
19
  defineBehavior
20
- } from "./chunk-YDLO5M7S.js";
20
+ } from "./chunk-EZNCCO4L.js";
21
21
 
22
22
  // src/lib/behaviors/first-person/first-person-fsm.ts
23
23
  var FirstPersonState = /* @__PURE__ */ ((FirstPersonState2) => {
@@ -320,3 +320,4 @@ export {
320
320
  FirstPersonPresentation,
321
321
  FirstPersonBehavior
322
322
  };
323
+ //# sourceMappingURL=chunk-DGDNFX43.js.map