@zylem/behaviors 0.4.1 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (145) hide show
  1. package/README.md +13 -1
  2. package/dist/{behavior-system-y8SGrGWy.d.ts → behavior-system-CeJXzNvr.d.ts} +305 -17
  3. package/dist/{chunk-GFARAJV2.js → chunk-2PAHQZZD.js} +44 -73
  4. package/dist/chunk-2PAHQZZD.js.map +1 -0
  5. package/dist/chunk-52FJIDGL.js +30 -0
  6. package/dist/chunk-52FJIDGL.js.map +1 -0
  7. package/dist/{chunk-UYFOLI2X.js → chunk-5A5AYP2C.js} +1 -1
  8. package/dist/{chunk-UYFOLI2X.js.map → chunk-5A5AYP2C.js.map} +1 -1
  9. package/dist/{chunk-A4CA35DQ.js → chunk-5EBIIYZD.js} +25 -45
  10. package/dist/chunk-5EBIIYZD.js.map +1 -0
  11. package/dist/{chunk-4L36OPY2.js → chunk-5NJGASUJ.js} +81 -135
  12. package/dist/chunk-5NJGASUJ.js.map +1 -0
  13. package/dist/{chunk-27UPCP5B.js → chunk-5UMCWV5A.js} +22 -13
  14. package/dist/chunk-5UMCWV5A.js.map +1 -0
  15. package/dist/chunk-5WRI5ZAA.js +31 -0
  16. package/dist/chunk-5WRI5ZAA.js.map +1 -0
  17. package/dist/{chunk-5SM5SH5O.js → chunk-7JLWZXPA.js} +2 -2
  18. package/dist/{chunk-Z72F2ENM.js → chunk-AEBDZWCP.js} +17 -26
  19. package/dist/chunk-AEBDZWCP.js.map +1 -0
  20. package/dist/chunk-AS3HR7AS.js +188 -0
  21. package/dist/chunk-AS3HR7AS.js.map +1 -0
  22. package/dist/chunk-E4X4YJZB.js +841 -0
  23. package/dist/chunk-E4X4YJZB.js.map +1 -0
  24. package/dist/{chunk-VMQHNJJI.js → chunk-F6ESSHQK.js} +17 -23
  25. package/dist/chunk-F6ESSHQK.js.map +1 -0
  26. package/dist/chunk-GQAPBNGT.js +210 -0
  27. package/dist/chunk-GQAPBNGT.js.map +1 -0
  28. package/dist/chunk-JGXRQUTC.js +191 -0
  29. package/dist/chunk-JGXRQUTC.js.map +1 -0
  30. package/dist/{chunk-BXP4K7RF.js → chunk-JVADRLWX.js} +57 -186
  31. package/dist/chunk-JVADRLWX.js.map +1 -0
  32. package/dist/{chunk-ZA43LPRM.js → chunk-KIYUUSPK.js} +2 -2
  33. package/dist/{chunk-QDCJLJUV.js → chunk-KOWGILCN.js} +22 -13
  34. package/dist/chunk-KOWGILCN.js.map +1 -0
  35. package/dist/{chunk-WWVD5DR5.js → chunk-M3QDKKDF.js} +2 -8
  36. package/dist/chunk-M3QDKKDF.js.map +1 -0
  37. package/dist/{chunk-FTDZAKZW.js → chunk-NQPYMUDF.js} +7 -5
  38. package/dist/{chunk-FTDZAKZW.js.map → chunk-NQPYMUDF.js.map} +1 -1
  39. package/dist/{chunk-XP3ASVGJ.js → chunk-NW4SE5XW.js} +2 -2
  40. package/dist/{chunk-KDY5N6J4.js → chunk-OPZ2LVS2.js} +1 -22
  41. package/dist/{chunk-KDY5N6J4.js.map → chunk-OPZ2LVS2.js.map} +1 -1
  42. package/dist/{chunk-5XZWTFGF.js → chunk-PLIXVF7B.js} +3 -3
  43. package/dist/chunk-PLIXVF7B.js.map +1 -0
  44. package/dist/{chunk-Y7YIAWPW.js → chunk-SGHIGTVZ.js} +1 -11
  45. package/dist/{chunk-Y7YIAWPW.js.map → chunk-SGHIGTVZ.js.map} +1 -1
  46. package/dist/{chunk-UL6Q5HDP.js → chunk-TBUKJKY6.js} +3 -25
  47. package/dist/chunk-TBUKJKY6.js.map +1 -0
  48. package/dist/chunk-VFDUKGRZ.js +155 -0
  49. package/dist/chunk-VFDUKGRZ.js.map +1 -0
  50. package/dist/chunk-VT3H43QA.js +288 -0
  51. package/dist/chunk-VT3H43QA.js.map +1 -0
  52. package/dist/chunk-W26PHBME.js +309 -0
  53. package/dist/chunk-W26PHBME.js.map +1 -0
  54. package/dist/components-BANNjAZP.d.ts +30 -0
  55. package/dist/cooldown.d.ts +2 -2
  56. package/dist/cooldown.js +1 -0
  57. package/dist/coordinators/boundary-ricochet-3d.d.ts +4 -4
  58. package/dist/coordinators/boundary-ricochet-3d.js +1 -0
  59. package/dist/coordinators/boundary-ricochet.d.ts +4 -4
  60. package/dist/coordinators/boundary-ricochet.js +3 -2
  61. package/dist/coordinators/first-person-shooter.js +1 -0
  62. package/dist/coordinators/multidirectional-space-shooter.d.ts +3 -3
  63. package/dist/coordinators/multidirectional-space-shooter.js +5 -3
  64. package/dist/coordinators/top-down-shooter.d.ts +3 -3
  65. package/dist/coordinators/top-down-shooter.js +5 -3
  66. package/dist/core.d.ts +288 -8
  67. package/dist/core.js +480 -13
  68. package/dist/core.js.map +1 -1
  69. package/dist/destructible-3d.d.ts +32 -4
  70. package/dist/destructible-3d.js +2 -1
  71. package/dist/destructible-prebake.js +1 -0
  72. package/dist/{entity-types-CmtQ-IBp.d.ts → entity-types-DhfsZbSK.d.ts} +5 -3
  73. package/dist/first-person.d.ts +27 -38
  74. package/dist/first-person.js +8 -8
  75. package/dist/index.d.ts +14 -15
  76. package/dist/index.js +37 -52
  77. package/dist/jumper-2d.d.ts +3 -17
  78. package/dist/jumper-2d.js +4 -9
  79. package/dist/jumper-3d.d.ts +5 -39
  80. package/dist/jumper-3d.js +5 -10
  81. package/dist/{moveable-Cl9h-_w7.d.ts → moveable-XhzWPAw5.d.ts} +21 -4
  82. package/dist/particle-emitter/presets.js +1 -0
  83. package/dist/particle-emitter.d.ts +3 -3
  84. package/dist/particle-emitter.js +3 -2
  85. package/dist/platformer-2d.d.ts +13 -82
  86. package/dist/platformer-2d.js +4 -5
  87. package/dist/platformer-3d.d.ts +13 -78
  88. package/dist/platformer-3d.js +4 -5
  89. package/dist/ricochet-2d.d.ts +3 -3
  90. package/dist/ricochet-2d.js +4 -3
  91. package/dist/ricochet-3d.d.ts +3 -3
  92. package/dist/ricochet-3d.js +4 -3
  93. package/dist/runtime-2d.d.ts +2 -2
  94. package/dist/runtime-2d.js +1 -0
  95. package/dist/runtime-2d.js.map +1 -1
  96. package/dist/screen-visibility.d.ts +2 -2
  97. package/dist/screen-visibility.js +1 -0
  98. package/dist/screen-wrap.d.ts +2 -2
  99. package/dist/screen-wrap.js +4 -3
  100. package/dist/shooter-2d.d.ts +3 -3
  101. package/dist/shooter-2d.js +4 -3
  102. package/dist/thruster.d.ts +5 -34
  103. package/dist/thruster.js +4 -6
  104. package/dist/top-down-movement.d.ts +9 -27
  105. package/dist/top-down-movement.js +6 -6
  106. package/dist/{vector-Bm65-FOG.d.ts → vector-DjhLUrak.d.ts} +2 -4
  107. package/dist/world-boundary-2d.d.ts +2 -2
  108. package/dist/world-boundary-2d.js +5 -4
  109. package/dist/world-boundary-3d.d.ts +2 -2
  110. package/dist/world-boundary-3d.js +4 -3
  111. package/package.json +2 -3
  112. package/dist/chunk-27UPCP5B.js.map +0 -1
  113. package/dist/chunk-4L36OPY2.js.map +0 -1
  114. package/dist/chunk-4URF65BR.js +0 -44
  115. package/dist/chunk-4URF65BR.js.map +0 -1
  116. package/dist/chunk-5XZWTFGF.js.map +0 -1
  117. package/dist/chunk-67XLJ26X.js +0 -536
  118. package/dist/chunk-67XLJ26X.js.map +0 -1
  119. package/dist/chunk-75FJIUIG.js +0 -240
  120. package/dist/chunk-75FJIUIG.js.map +0 -1
  121. package/dist/chunk-A4CA35DQ.js.map +0 -1
  122. package/dist/chunk-BXP4K7RF.js.map +0 -1
  123. package/dist/chunk-F72WX4MH.js +0 -422
  124. package/dist/chunk-F72WX4MH.js.map +0 -1
  125. package/dist/chunk-GFARAJV2.js.map +0 -1
  126. package/dist/chunk-JXMF4NUI.js +0 -309
  127. package/dist/chunk-JXMF4NUI.js.map +0 -1
  128. package/dist/chunk-OTLSUYQQ.js +0 -29
  129. package/dist/chunk-OTLSUYQQ.js.map +0 -1
  130. package/dist/chunk-Q75LKHDF.js +0 -56
  131. package/dist/chunk-Q75LKHDF.js.map +0 -1
  132. package/dist/chunk-QDCJLJUV.js.map +0 -1
  133. package/dist/chunk-RDHSHEZM.js +0 -479
  134. package/dist/chunk-RDHSHEZM.js.map +0 -1
  135. package/dist/chunk-UIG7MWS2.js +0 -518
  136. package/dist/chunk-UIG7MWS2.js.map +0 -1
  137. package/dist/chunk-UL6Q5HDP.js.map +0 -1
  138. package/dist/chunk-VMQHNJJI.js.map +0 -1
  139. package/dist/chunk-WWVD5DR5.js.map +0 -1
  140. package/dist/chunk-Z72F2ENM.js.map +0 -1
  141. package/dist/components-BWG1GkZA.d.ts +0 -20
  142. package/dist/use-behavior-B85d5u7-.d.ts +0 -13
  143. /package/dist/{chunk-5SM5SH5O.js.map → chunk-7JLWZXPA.js.map} +0 -0
  144. /package/dist/{chunk-ZA43LPRM.js.map → chunk-KIYUUSPK.js.map} +0 -0
  145. /package/dist/{chunk-XP3ASVGJ.js.map → chunk-NW4SE5XW.js.map} +0 -0
@@ -1,479 +0,0 @@
1
- import {
2
- createJumpConfig3D,
3
- createJumpInput3D,
4
- createJumpState3D
5
- } from "./chunk-4WH2ZN7P.js";
6
- import {
7
- GroundProbe3D,
8
- getGroundAnchorOffsetY,
9
- getGroundSnapTargetY
10
- } from "./chunk-JXMF4NUI.js";
11
- import {
12
- setVelocityIntent
13
- } from "./chunk-OTLSUYQQ.js";
14
- import {
15
- SyncStateMachine,
16
- t
17
- } from "./chunk-4URF65BR.js";
18
- import {
19
- STAGE_INPUT_BUTTON_JUMP,
20
- readBehaviorSnapshot
21
- } from "./chunk-Q75LKHDF.js";
22
- import {
23
- defineBehavior
24
- } from "./chunk-EZNCCO4L.js";
25
-
26
- // src/lib/behaviors/jumper-3d/jumper-3d.system.ts
27
- function jumpVelocityFromHeight(gravity, height) {
28
- return Math.sqrt(2 * gravity * height);
29
- }
30
- function planarSpeed(x, z) {
31
- return Math.sqrt(x * x + z * z);
32
- }
33
- function normalizeMut(v) {
34
- const len = Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
35
- if (len > 1e-6) {
36
- v.x /= len;
37
- v.y /= len;
38
- v.z /= len;
39
- }
40
- return len;
41
- }
42
- var Jumper3DSystem = class {
43
- /**
44
- * Advance the jump system by one frame.
45
- *
46
- * Call order within a frame:
47
- * 1. Movement controller writes X/Z via transformStore.dirty.velocityX/Z.
48
- * 2. `tick()` writes Y via ctx.setVerticalVelocity().
49
- * (Optionally writes X/Z when airborne planar control is active.)
50
- */
51
- tick(config, input, ctx, state) {
52
- const dtMs = ctx.dt * 1e3;
53
- const now = performance.now();
54
- let event = "none" /* None */;
55
- let jumpedThisFrame = false;
56
- if (ctx.isGrounded) {
57
- state.coyoteMs = config.coyoteTimeMs;
58
- if (config.resetJumpsOnGround) {
59
- state.jumpsUsed = 0;
60
- }
61
- if (state.isJumping) {
62
- state.isJumping = false;
63
- state.jumpCutApplied = false;
64
- event = "land" /* Land */;
65
- }
66
- } else {
67
- state.coyoteMs = Math.max(0, state.coyoteMs - dtMs);
68
- }
69
- if (input.jumpPressed) {
70
- state.bufferedJumpMs = config.jumpBufferMs;
71
- } else {
72
- state.bufferedJumpMs = Math.max(0, state.bufferedJumpMs - dtMs);
73
- }
74
- if (state.isJumping && input.jumpHeld) {
75
- state.jumpHoldMs += dtMs;
76
- }
77
- const wantsJump = state.bufferedJumpMs > 0;
78
- const isFirstJump = ctx.isGrounded || state.coyoteMs > 0 && state.jumpsUsed === 0;
79
- const hasAirJumps = state.jumpsUsed > 0 && state.jumpsUsed < config.maxJumps;
80
- const canJump = isFirstJump || hasAirJumps;
81
- const cooldownOk = config.minTimeBetweenJumpsMs == null || now - state.lastJumpTimeMs >= config.minTimeBetweenJumpsMs;
82
- if (wantsJump && canJump && cooldownOk) {
83
- const vy = jumpVelocityFromHeight(config.gravity, config.jumpHeight);
84
- ctx.setVerticalVelocity(vy);
85
- jumpedThisFrame = true;
86
- if (config.planar?.launchPlanarSpeed != null && !config.planar.preservePlanarSpeed) {
87
- const dir = input.moveDirWorld;
88
- if (dir && (Math.abs(dir.x) > 1e-6 || Math.abs(dir.z) > 1e-6)) {
89
- const d = { x: dir.x, y: 0, z: dir.z };
90
- normalizeMut(d);
91
- ctx.setHorizontalVelocity(
92
- d.x * config.planar.launchPlanarSpeed,
93
- d.z * config.planar.launchPlanarSpeed
94
- );
95
- }
96
- }
97
- state.jumpsUsed++;
98
- state.lastJumpTimeMs = now;
99
- state.bufferedJumpMs = 0;
100
- state.coyoteMs = 0;
101
- state.isJumping = true;
102
- state.jumpHoldMs = 0;
103
- state.jumpCutApplied = false;
104
- event = "jump" /* Jump */;
105
- }
106
- if (!ctx.isGrounded || jumpedThisFrame) {
107
- let gravityMul = 1;
108
- const vy = ctx.velocityY;
109
- const isFalling = vy < 0;
110
- if (isFalling) {
111
- gravityMul = config.fall?.fallGravityMultiplier ?? 1;
112
- if (input.fastFall && config.fall?.fastFallMultiplier != null) {
113
- gravityMul *= config.fall.fastFallMultiplier;
114
- }
115
- if (event !== "land" /* Land */) {
116
- event = "fall" /* Fall */;
117
- }
118
- } else if (state.isJumping) {
119
- const vj = config.variableJump;
120
- if (vj?.enabled && !state.jumpCutApplied) {
121
- const holdExpired = vj.maxHoldMs != null && state.jumpHoldMs >= vj.maxHoldMs;
122
- if (!input.jumpHeld || holdExpired) {
123
- gravityMul = vj.cutGravityMultiplier;
124
- state.jumpCutApplied = true;
125
- }
126
- }
127
- }
128
- let newVy = ctx.velocityY - config.gravity * gravityMul * ctx.dt;
129
- if (config.maxFallSpeed != null) {
130
- newVy = Math.max(-config.maxFallSpeed, newVy);
131
- }
132
- ctx.setVerticalVelocity(newVy);
133
- } else {
134
- ctx.setVerticalVelocity(0);
135
- }
136
- const airCtrl = config.planar?.airControl;
137
- if (airCtrl && !ctx.isGrounded) {
138
- const dir = input.moveDirWorld;
139
- const hasDir = dir && (Math.abs(dir.x) > 1e-6 || Math.abs(dir.z) > 1e-6);
140
- let vx = ctx.horizontalVelocity.x;
141
- let vz = ctx.horizontalVelocity.z;
142
- if (hasDir) {
143
- const d = { x: dir.x, y: 0, z: dir.z };
144
- normalizeMut(d);
145
- vx += d.x * airCtrl.acceleration * ctx.dt;
146
- vz += d.z * airCtrl.acceleration * ctx.dt;
147
- const speed = Math.sqrt(vx * vx + vz * vz);
148
- if (speed > airCtrl.maxPlanarSpeed) {
149
- const scale = airCtrl.maxPlanarSpeed / speed;
150
- vx *= scale;
151
- vz *= scale;
152
- }
153
- } else {
154
- const speed = planarSpeed(vx, vz);
155
- if (speed > 1e-6) {
156
- const decel = Math.min(airCtrl.deceleration * ctx.dt, speed);
157
- const scale = (speed - decel) / speed;
158
- vx *= scale;
159
- vz *= scale;
160
- }
161
- }
162
- ctx.setHorizontalVelocity(vx, vz);
163
- }
164
- return { event };
165
- }
166
- };
167
- var JumperTickEvent = /* @__PURE__ */ ((JumperTickEvent2) => {
168
- JumperTickEvent2["None"] = "none";
169
- JumperTickEvent2["Jump"] = "jump";
170
- JumperTickEvent2["Fall"] = "fall";
171
- JumperTickEvent2["Land"] = "land";
172
- return JumperTickEvent2;
173
- })(JumperTickEvent || {});
174
-
175
- // src/lib/behaviors/jumper-3d/jumper-3d-fsm.ts
176
- var Jumper3DState = /* @__PURE__ */ ((Jumper3DState2) => {
177
- Jumper3DState2["Grounded"] = "grounded";
178
- Jumper3DState2["Jumping"] = "jumping";
179
- Jumper3DState2["Falling"] = "falling";
180
- return Jumper3DState2;
181
- })(Jumper3DState || {});
182
- var Jumper3DEvent = /* @__PURE__ */ ((Jumper3DEvent2) => {
183
- Jumper3DEvent2["Jump"] = "jump";
184
- Jumper3DEvent2["Fall"] = "fall";
185
- Jumper3DEvent2["Land"] = "land";
186
- return Jumper3DEvent2;
187
- })(Jumper3DEvent || {});
188
- var Jumper3DFSM = class {
189
- constructor(ctx) {
190
- this.ctx = ctx;
191
- this.machine = new SyncStateMachine(
192
- "grounded" /* Grounded */,
193
- [
194
- // Grounded
195
- t("grounded" /* Grounded */, "jump" /* Jump */, "jumping" /* Jumping */),
196
- t("grounded" /* Grounded */, "fall" /* Fall */, "falling" /* Falling */),
197
- t("grounded" /* Grounded */, "land" /* Land */, "grounded" /* Grounded */),
198
- // Jumping
199
- t("jumping" /* Jumping */, "fall" /* Fall */, "falling" /* Falling */),
200
- t("jumping" /* Jumping */, "land" /* Land */, "grounded" /* Grounded */),
201
- t("jumping" /* Jumping */, "jump" /* Jump */, "jumping" /* Jumping */),
202
- // Falling
203
- t("falling" /* Falling */, "land" /* Land */, "grounded" /* Grounded */),
204
- t("falling" /* Falling */, "jump" /* Jump */, "jumping" /* Jumping */),
205
- t("falling" /* Falling */, "fall" /* Fall */, "falling" /* Falling */)
206
- ]
207
- );
208
- }
209
- ctx;
210
- machine;
211
- getState() {
212
- return this.machine.getState();
213
- }
214
- dispatch(event) {
215
- if (this.machine.can(event)) {
216
- this.machine.syncDispatch(event);
217
- }
218
- }
219
- isJumping() {
220
- return this.getState() === "jumping" /* Jumping */;
221
- }
222
- isFalling() {
223
- return this.getState() === "falling" /* Falling */;
224
- }
225
- isGrounded() {
226
- return this.getState() === "grounded" /* Grounded */;
227
- }
228
- getJumpsUsed() {
229
- return this.ctx.state.jumpsUsed;
230
- }
231
- /**
232
- * Translate a tick event into an FSM dispatch.
233
- * Also handles the implicit Grounded→Falling transition when the entity
234
- * is no longer grounded but no explicit event was emitted (e.g. walked
235
- * off a ledge without jumping).
236
- */
237
- applyTickEvent(tickEvent, isGrounded) {
238
- switch (tickEvent) {
239
- case "jump":
240
- this.dispatch("jump" /* Jump */);
241
- break;
242
- case "fall":
243
- this.dispatch("fall" /* Fall */);
244
- break;
245
- case "land":
246
- this.dispatch("land" /* Land */);
247
- break;
248
- default:
249
- if (!isGrounded && this.getState() === "grounded" /* Grounded */) {
250
- this.dispatch("fall" /* Fall */);
251
- }
252
- if (isGrounded && this.getState() !== "grounded" /* Grounded */) {
253
- this.dispatch("land" /* Land */);
254
- }
255
- break;
256
- }
257
- }
258
- };
259
-
260
- // src/lib/behaviors/jumper-3d/jumper-3d.descriptor.ts
261
- var defaultOptions = {
262
- jumpHeight: 2.5,
263
- gravity: 20,
264
- maxJumps: 1,
265
- resetJumpsOnGround: true,
266
- coyoteTimeMs: 100,
267
- jumpBufferMs: 80,
268
- groundRayLength: 1,
269
- debugGroundProbe: false
270
- };
271
- var JUMPER_BEHAVIOR_KEY = /* @__PURE__ */ Symbol.for("zylem:behavior:jumper-3d");
272
- function isJumper3DGrounded(params) {
273
- if (params.snapToGroundDistance != null) {
274
- return params.supportToi != null && params.supportToi <= params.snapToGroundDistance && params.velocityY <= 0.25;
275
- }
276
- return params.supportToi != null && params.velocityY > -2 && params.velocityY < 2;
277
- }
278
- function shouldSnapJumper3DToGround(support, options, velocityY) {
279
- return support != null && options.snapToGroundDistance != null && velocityY <= 0.25 && support.toi <= options.snapToGroundDistance;
280
- }
281
- var Jumper3DBehaviorSystem = class {
282
- constructor(world, scene, wasmStage, getBehaviorLinks) {
283
- this.scene = scene;
284
- this.wasmStage = wasmStage;
285
- this.getBehaviorLinks = getBehaviorLinks;
286
- this.groundProbe = new GroundProbe3D(world);
287
- }
288
- scene;
289
- wasmStage;
290
- getBehaviorLinks;
291
- behavior = new Jumper3DSystem();
292
- groundProbe;
293
- initializedEntities = /* @__PURE__ */ new Set();
294
- timeSinceGroundedMs = /* @__PURE__ */ new Map();
295
- wasJumpHeld = /* @__PURE__ */ new Map();
296
- attachedRuntimeSlots = /* @__PURE__ */ new Set();
297
- update(_ecs, delta) {
298
- const links = this.getBehaviorLinks?.(JUMPER_BEHAVIOR_KEY);
299
- if (!links) return;
300
- for (const link of links) {
301
- const gameEntity = link.entity;
302
- const jumperRef = link.ref;
303
- const options = jumperRef.options;
304
- const handle = gameEntity.runtimeHandle ?? -1;
305
- if (this.wasmStage && handle >= 0) {
306
- this.ensureWasmAttached(handle, options);
307
- jumperRef.__wasmStage = this.wasmStage;
308
- jumperRef.__entity = gameEntity;
309
- const input2 = gameEntity.$jumper;
310
- const jumpPressed = !!(input2?.jumpPressed || input2?.jumpHeld);
311
- this.wasmStage.writeInputButton(handle, STAGE_INPUT_BUTTON_JUMP, jumpPressed);
312
- continue;
313
- }
314
- if (!gameEntity.body) continue;
315
- if (!gameEntity.jumper) {
316
- gameEntity.jumper = createJumpConfig3D(options);
317
- }
318
- if (!gameEntity.$jumper) {
319
- gameEntity.$jumper = createJumpInput3D();
320
- }
321
- if (!gameEntity.jumperState) {
322
- gameEntity.jumperState = createJumpState3D();
323
- }
324
- if (!this.initializedEntities.has(gameEntity.uuid)) {
325
- this.initializedEntities.add(gameEntity.uuid);
326
- gameEntity.body.setGravityScale(0, true);
327
- }
328
- if (!jumperRef.fsm && gameEntity.jumperState) {
329
- jumperRef.fsm = new Jumper3DFSM({
330
- state: gameEntity.jumperState
331
- });
332
- }
333
- const rayLength = options.groundRayLength ?? 1;
334
- const bodyVel = gameEntity.body.linvel();
335
- const probeOriginYOffset = 0.05 - getGroundAnchorOffsetY(gameEntity);
336
- const support = this.groundProbe.probeSupport(gameEntity, {
337
- rayLength,
338
- mode: "center",
339
- debug: options.debugGroundProbe ?? false,
340
- scene: this.scene,
341
- originYOffset: probeOriginYOffset
342
- });
343
- const isGrounded = isJumper3DGrounded({
344
- supportToi: support?.toi ?? null,
345
- velocityY: bodyVel.y,
346
- snapToGroundDistance: options.snapToGroundDistance
347
- });
348
- if (shouldSnapJumper3DToGround(support, options, bodyVel.y)) {
349
- const currentPosition = gameEntity.body.translation();
350
- gameEntity.body.setTranslation(
351
- {
352
- x: currentPosition.x,
353
- y: getGroundSnapTargetY(gameEntity, support),
354
- z: currentPosition.z
355
- },
356
- true
357
- );
358
- }
359
- let tsg = this.timeSinceGroundedMs.get(gameEntity.uuid) ?? 0;
360
- if (isGrounded) {
361
- tsg = 0;
362
- } else {
363
- tsg += delta * 1e3;
364
- }
365
- this.timeSinceGroundedMs.set(gameEntity.uuid, tsg);
366
- const config = gameEntity.jumper;
367
- const input = gameEntity.$jumper;
368
- const state = gameEntity.jumperState;
369
- const prevHeld = this.wasJumpHeld.get(gameEntity.uuid) ?? false;
370
- const held = input.jumpHeld === true;
371
- const effectiveInput = {
372
- ...input,
373
- jumpPressed: input.jumpPressed || held && !prevHeld,
374
- jumpReleased: input.jumpReleased || !held && prevHeld
375
- };
376
- const store = gameEntity.transformStore;
377
- const ctx = {
378
- dt: delta,
379
- up: { x: 0, y: 1, z: 0 },
380
- velocityY: bodyVel.y,
381
- horizontalVelocity: { x: bodyVel.x, z: bodyVel.z },
382
- isGrounded,
383
- timeSinceGroundedMs: tsg,
384
- setVerticalVelocity: (y) => {
385
- setVelocityIntent(
386
- store,
387
- "jumper-3d",
388
- { y },
389
- { mode: "replace", priority: 20 }
390
- );
391
- ctx.velocityY = y;
392
- },
393
- setHorizontalVelocity: (x, z) => {
394
- setVelocityIntent(
395
- store,
396
- "jumper-3d",
397
- { x, z },
398
- { mode: "replace", priority: 20 }
399
- );
400
- ctx.horizontalVelocity.x = x;
401
- ctx.horizontalVelocity.z = z;
402
- }
403
- };
404
- const result = this.behavior.tick(config, effectiveInput, ctx, state);
405
- this.wasJumpHeld.set(gameEntity.uuid, held);
406
- if (jumperRef.fsm) {
407
- jumperRef.fsm.applyTickEvent(
408
- result.event,
409
- isGrounded
410
- );
411
- }
412
- }
413
- }
414
- ensureWasmAttached(handle, options) {
415
- if (!this.wasmStage || this.attachedRuntimeSlots.has(handle)) return;
416
- const jumpForce = Math.sqrt(2 * (options.gravity ?? 20) * (options.jumpHeight ?? 2.5));
417
- this.wasmStage.attachJumper3D(handle, {
418
- jumpForce,
419
- maxJumps: options.maxJumps ?? 1,
420
- gravity: options.gravity ?? 20,
421
- coyoteTime: (options.coyoteTimeMs ?? 100) / 1e3,
422
- jumpBufferTime: (options.jumpBufferMs ?? 80) / 1e3
423
- });
424
- this.attachedRuntimeSlots.add(handle);
425
- }
426
- destroy(_ecs) {
427
- this.groundProbe.destroy();
428
- this.initializedEntities.clear();
429
- this.timeSinceGroundedMs.clear();
430
- this.wasJumpHeld.clear();
431
- this.attachedRuntimeSlots.clear();
432
- }
433
- };
434
- var Jumper3DBehavior = defineBehavior({
435
- name: "jumper-3d",
436
- defaultOptions,
437
- systemFactory: (ctx) => new Jumper3DBehaviorSystem(
438
- ctx.world,
439
- ctx.scene,
440
- ctx.wasmStage ?? null,
441
- ctx.getBehaviorLinks
442
- ),
443
- // On the wasm fast path the handle reads the runtime snapshot buffer
444
- // (previous-step values); the TS FSM only backs the no-wasm fallback.
445
- createHandle: (ref) => {
446
- const jumpsUsed = () => {
447
- const snapshot = readBehaviorSnapshot(ref);
448
- if (snapshot) return snapshot.jumpCount;
449
- return ref.fsm?.getJumpsUsed() ?? 0;
450
- };
451
- return {
452
- getState: () => {
453
- const snapshot = readBehaviorSnapshot(ref);
454
- if (snapshot) {
455
- if (snapshot.grounded) return "grounded" /* Grounded */;
456
- return snapshot.verticalVelocity > 0 ? "jumping" /* Jumping */ : "falling" /* Falling */;
457
- }
458
- return ref.fsm?.getState() ?? "grounded" /* Grounded */;
459
- },
460
- isJumping: () => {
461
- const snapshot = readBehaviorSnapshot(ref);
462
- if (snapshot) return !snapshot.grounded && snapshot.verticalVelocity > 0;
463
- return ref.fsm?.isJumping() ?? false;
464
- },
465
- getJumpsUsed: jumpsUsed,
466
- getJumpsRemaining: () => (ref.options.maxJumps ?? 1) - jumpsUsed()
467
- };
468
- }
469
- });
470
-
471
- export {
472
- Jumper3DSystem,
473
- JumperTickEvent,
474
- Jumper3DState,
475
- Jumper3DEvent,
476
- Jumper3DFSM,
477
- Jumper3DBehavior
478
- };
479
- //# sourceMappingURL=chunk-RDHSHEZM.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/lib/behaviors/jumper-3d/jumper-3d.system.ts","../src/lib/behaviors/jumper-3d/jumper-3d-fsm.ts","../src/lib/behaviors/jumper-3d/jumper-3d.descriptor.ts"],"sourcesContent":["/**\n * Jumper 3D Behavior — Pure Jump Physics\n *\n * A stateless tick function that receives configuration, input, context, and\n * state, then applies jump physics through the context's velocity helpers.\n *\n * Vertical velocity (Y) is owned exclusively by this behavior.\n * Horizontal velocity (X/Z) is only touched when airborne planar control\n * is configured; otherwise the movement controller owns X/Z.\n */\n\nimport type {\n\tJumpConfig3D,\n\tJumpInput3D,\n\tJumpContext3D,\n\tJumpState3D,\n} from './components';\n\n/** v = sqrt(2 * g * h) */\nfunction jumpVelocityFromHeight(gravity: number, height: number): number {\n\treturn Math.sqrt(2 * gravity * height);\n}\n\nfunction planarSpeed(x: number, z: number): number {\n\treturn Math.sqrt(x * x + z * z);\n}\n\nfunction normalizeMut(v: { x: number; y: number; z: number }): number {\n\tconst len = Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z);\n\tif (len > 1e-6) {\n\t\tv.x /= len;\n\t\tv.y /= len;\n\t\tv.z /= len;\n\t}\n\treturn len;\n}\n\nexport class Jumper3DSystem {\n\t/**\n\t * Advance the jump system by one frame.\n\t *\n\t * Call order within a frame:\n\t * 1. Movement controller writes X/Z via transformStore.dirty.velocityX/Z.\n\t * 2. `tick()` writes Y via ctx.setVerticalVelocity().\n\t * (Optionally writes X/Z when airborne planar control is active.)\n\t */\n\ttick(\n\t\tconfig: JumpConfig3D,\n\t\tinput: JumpInput3D,\n\t\tctx: JumpContext3D,\n\t\tstate: JumpState3D,\n\t): JumperTickResult {\n\t\tconst dtMs = ctx.dt * 1000;\n\t\tconst now = performance.now();\n\t\tlet event: JumperTickEvent = JumperTickEvent.None;\n\t\tlet jumpedThisFrame = false;\n\n\t\t// ── 1. Ground-contact bookkeeping ──────────────────────────────────\n\t\tif (ctx.isGrounded) {\n\t\t\tstate.coyoteMs = config.coyoteTimeMs;\n\t\t\tif (config.resetJumpsOnGround) {\n\t\t\t\tstate.jumpsUsed = 0;\n\t\t\t}\n\t\t\tif (state.isJumping) {\n\t\t\t\tstate.isJumping = false;\n\t\t\t\tstate.jumpCutApplied = false;\n\t\t\t\tevent = JumperTickEvent.Land;\n\t\t\t}\n\t\t} else {\n\t\t\tstate.coyoteMs = Math.max(0, state.coyoteMs - dtMs);\n\t\t}\n\n\t\t// ── 2. Jump buffer ─────────────────────────────────────────────────\n\t\tif (input.jumpPressed) {\n\t\t\tstate.bufferedJumpMs = config.jumpBufferMs;\n\t\t} else {\n\t\t\tstate.bufferedJumpMs = Math.max(0, state.bufferedJumpMs - dtMs);\n\t\t}\n\n\t\t// ── 3. Variable-jump hold tracking ─────────────────────────────────\n\t\tif (state.isJumping && input.jumpHeld) {\n\t\t\tstate.jumpHoldMs += dtMs;\n\t\t}\n\n\t\t// ── 4. Jump eligibility & execution ────────────────────────────────\n\t\tconst wantsJump = state.bufferedJumpMs > 0;\n\n\t\tconst isFirstJump =\n\t\t\tctx.isGrounded || (state.coyoteMs > 0 && state.jumpsUsed === 0);\n\t\tconst hasAirJumps = state.jumpsUsed > 0 && state.jumpsUsed < config.maxJumps;\n\t\tconst canJump = isFirstJump || hasAirJumps;\n\n\t\t\tconst cooldownOk =\n\t\t\t\tconfig.minTimeBetweenJumpsMs == null ||\n\t\t\t\tnow - state.lastJumpTimeMs >= config.minTimeBetweenJumpsMs;\n\n\t\t\tif (wantsJump && canJump && cooldownOk) {\n\t\t\t\tconst vy = jumpVelocityFromHeight(config.gravity, config.jumpHeight);\n\n\t\t\t\tctx.setVerticalVelocity(vy);\n\t\t\t\tjumpedThisFrame = true;\n\n\t\t\tif (config.planar?.launchPlanarSpeed != null && !config.planar.preservePlanarSpeed) {\n\t\t\t\tconst dir = input.moveDirWorld;\n\t\t\t\tif (dir && (Math.abs(dir.x) > 1e-6 || Math.abs(dir.z) > 1e-6)) {\n\t\t\t\t\tconst d = { x: dir.x, y: 0, z: dir.z };\n\t\t\t\t\tnormalizeMut(d);\n\t\t\t\t\tctx.setHorizontalVelocity(\n\t\t\t\t\t\td.x * config.planar.launchPlanarSpeed,\n\t\t\t\t\t\td.z * config.planar.launchPlanarSpeed,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tstate.jumpsUsed++;\n\t\t\tstate.lastJumpTimeMs = now;\n\t\t\tstate.bufferedJumpMs = 0;\n\t\t\tstate.coyoteMs = 0;\n\t\t\tstate.isJumping = true;\n\t\t\tstate.jumpHoldMs = 0;\n\t\t\tstate.jumpCutApplied = false;\n\n\t\t\tevent = JumperTickEvent.Jump;\n\t\t}\n\n\t\t// ── 5. Gravity (with variable-jump and fall multipliers) ───────────\n\t\t// Treat a jump-launch frame as airborne so we don't immediately clamp\n\t\t// the freshly applied jump velocity back to zero.\n\t\tif (!ctx.isGrounded || jumpedThisFrame) {\n\t\t\tlet gravityMul = 1;\n\t\t\tconst vy = ctx.velocityY;\n\t\t\tconst isFalling = vy < 0;\n\n\t\t\tif (isFalling) {\n\t\t\t\tgravityMul = config.fall?.fallGravityMultiplier ?? 1;\n\t\t\t\tif (input.fastFall && config.fall?.fastFallMultiplier != null) {\n\t\t\t\t\tgravityMul *= config.fall.fastFallMultiplier;\n\t\t\t\t}\n\t\t\t\tif (event !== JumperTickEvent.Land) {\n\t\t\t\t\tevent = JumperTickEvent.Fall;\n\t\t\t\t}\n\t\t\t} else if (state.isJumping) {\n\t\t\t\tconst vj = config.variableJump;\n\t\t\t\tif (vj?.enabled && !state.jumpCutApplied) {\n\t\t\t\t\tconst holdExpired =\n\t\t\t\t\t\tvj.maxHoldMs != null && state.jumpHoldMs >= vj.maxHoldMs;\n\t\t\t\t\tif (!input.jumpHeld || holdExpired) {\n\t\t\t\t\t\tgravityMul = vj.cutGravityMultiplier;\n\t\t\t\t\t\tstate.jumpCutApplied = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet newVy = ctx.velocityY - config.gravity * gravityMul * ctx.dt;\n\n\t\t\tif (config.maxFallSpeed != null) {\n\t\t\t\tnewVy = Math.max(-config.maxFallSpeed, newVy);\n\t\t\t}\n\n\t\t\tctx.setVerticalVelocity(newVy);\n\t\t} else {\n\t\t\t// Grounded: clamp Y to 0 so the entity doesn't drift\n\t\t\tctx.setVerticalVelocity(0);\n\t\t}\n\n\t\t// ── 6. Airborne planar control ─────────────────────────────────────\n\t\tconst airCtrl = config.planar?.airControl;\n\t\tif (airCtrl && !ctx.isGrounded) {\n\t\t\tconst dir = input.moveDirWorld;\n\t\t\tconst hasDir = dir && (Math.abs(dir.x) > 1e-6 || Math.abs(dir.z) > 1e-6);\n\n\t\t\tlet vx = ctx.horizontalVelocity.x;\n\t\t\tlet vz = ctx.horizontalVelocity.z;\n\n\t\t\tif (hasDir) {\n\t\t\t\tconst d = { x: dir!.x, y: 0, z: dir!.z };\n\t\t\t\tnormalizeMut(d);\n\n\t\t\t\tvx += d.x * airCtrl.acceleration * ctx.dt;\n\t\t\t\tvz += d.z * airCtrl.acceleration * ctx.dt;\n\n\t\t\t\tconst speed = Math.sqrt(vx * vx + vz * vz);\n\t\t\t\tif (speed > airCtrl.maxPlanarSpeed) {\n\t\t\t\t\tconst scale = airCtrl.maxPlanarSpeed / speed;\n\t\t\t\t\tvx *= scale;\n\t\t\t\t\tvz *= scale;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst speed = planarSpeed(vx, vz);\n\t\t\t\tif (speed > 1e-6) {\n\t\t\t\t\tconst decel = Math.min(airCtrl.deceleration * ctx.dt, speed);\n\t\t\t\t\tconst scale = (speed - decel) / speed;\n\t\t\t\t\tvx *= scale;\n\t\t\t\t\tvz *= scale;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tctx.setHorizontalVelocity(vx, vz);\n\t\t}\n\n\t\treturn { event };\n\t}\n}\n\n/** Events emitted by a single tick (used by FSM). */\nexport enum JumperTickEvent {\n\tNone = 'none',\n\tJump = 'jump',\n\tFall = 'fall',\n\tLand = 'land',\n}\n\nexport interface JumperTickResult {\n\tevent: JumperTickEvent;\n}\n","/**\n * Jumper 3D Finite State Machine\n *\n * Three high-level states driven by events emitted from the behavior tick:\n * Grounded ──Jump──▶ Jumping\n * Grounded ──Fall──▶ Falling (walked off a ledge)\n * Jumping ──Fall──▶ Falling (apex / descending)\n * Jumping ──Jump──▶ Jumping (multi-jump)\n * Jumping ──Land──▶ Grounded (rare — very short hop)\n * Falling ──Land──▶ Grounded\n * Falling ──Jump──▶ Jumping (air-jump while falling)\n */\n\nimport { SyncStateMachine, t } from '../../core/utility/sync-state-machine';\nimport type { JumpState3D } from './components';\n\nexport enum Jumper3DState {\n\tGrounded = 'grounded',\n\tJumping = 'jumping',\n\tFalling = 'falling',\n}\n\nexport enum Jumper3DEvent {\n\tJump = 'jump',\n\tFall = 'fall',\n\tLand = 'land',\n}\n\nexport interface Jumper3DFSMContext {\n\tstate: JumpState3D;\n}\n\nexport class Jumper3DFSM {\n\tmachine: SyncStateMachine<Jumper3DState, Jumper3DEvent, never>;\n\n\tconstructor(private ctx: Jumper3DFSMContext) {\n\t\tthis.machine = new SyncStateMachine<Jumper3DState, Jumper3DEvent, never>(\n\t\t\tJumper3DState.Grounded,\n\t\t\t[\n\t\t\t\t// Grounded\n\t\t\t\tt(Jumper3DState.Grounded, Jumper3DEvent.Jump, Jumper3DState.Jumping),\n\t\t\t\tt(Jumper3DState.Grounded, Jumper3DEvent.Fall, Jumper3DState.Falling),\n\t\t\t\tt(Jumper3DState.Grounded, Jumper3DEvent.Land, Jumper3DState.Grounded),\n\n\t\t\t\t// Jumping\n\t\t\t\tt(Jumper3DState.Jumping, Jumper3DEvent.Fall, Jumper3DState.Falling),\n\t\t\t\tt(Jumper3DState.Jumping, Jumper3DEvent.Land, Jumper3DState.Grounded),\n\t\t\t\tt(Jumper3DState.Jumping, Jumper3DEvent.Jump, Jumper3DState.Jumping),\n\n\t\t\t\t// Falling\n\t\t\t\tt(Jumper3DState.Falling, Jumper3DEvent.Land, Jumper3DState.Grounded),\n\t\t\t\tt(Jumper3DState.Falling, Jumper3DEvent.Jump, Jumper3DState.Jumping),\n\t\t\t\tt(Jumper3DState.Falling, Jumper3DEvent.Fall, Jumper3DState.Falling),\n\t\t\t],\n\t\t);\n\t}\n\n\tgetState(): Jumper3DState {\n\t\treturn this.machine.getState();\n\t}\n\n\tdispatch(event: Jumper3DEvent): void {\n\t\tif (this.machine.can(event)) {\n\t\t\tthis.machine.syncDispatch(event);\n\t\t}\n\t}\n\n\tisJumping(): boolean {\n\t\treturn this.getState() === Jumper3DState.Jumping;\n\t}\n\n\tisFalling(): boolean {\n\t\treturn this.getState() === Jumper3DState.Falling;\n\t}\n\n\tisGrounded(): boolean {\n\t\treturn this.getState() === Jumper3DState.Grounded;\n\t}\n\n\tgetJumpsUsed(): number {\n\t\treturn this.ctx.state.jumpsUsed;\n\t}\n\n\t/**\n\t * Translate a tick event into an FSM dispatch.\n\t * Also handles the implicit Grounded→Falling transition when the entity\n\t * is no longer grounded but no explicit event was emitted (e.g. walked\n\t * off a ledge without jumping).\n\t */\n\tapplyTickEvent(tickEvent: string, isGrounded: boolean): void {\n\t\tswitch (tickEvent) {\n\t\t\tcase 'jump':\n\t\t\t\tthis.dispatch(Jumper3DEvent.Jump);\n\t\t\t\tbreak;\n\t\t\tcase 'fall':\n\t\t\t\tthis.dispatch(Jumper3DEvent.Fall);\n\t\t\t\tbreak;\n\t\t\tcase 'land':\n\t\t\t\tthis.dispatch(Jumper3DEvent.Land);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\t// No explicit event — detect implicit fall\n\t\t\t\tif (!isGrounded && this.getState() === Jumper3DState.Grounded) {\n\t\t\t\t\tthis.dispatch(Jumper3DEvent.Fall);\n\t\t\t\t}\n\t\t\t\tif (isGrounded && this.getState() !== Jumper3DState.Grounded) {\n\t\t\t\t\tthis.dispatch(Jumper3DEvent.Land);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t}\n\t}\n}\n","/**\n * Jumper 3D Behavior Descriptor\n *\n * Type-safe descriptor for the jumper-3d behavior system.\n * Provides `entity.use()` API for composable 3D jumping.\n */\n\nimport { defineBehavior } from '../behavior-descriptor';\nimport type { BehaviorEntityLink, BehaviorSystem } from '../behavior-system';\nimport { setVelocityIntent } from '../../capabilities/velocity-intents';\nimport { Jumper3DSystem } from './jumper-3d.system';\nimport { Jumper3DFSM, Jumper3DState } from './jumper-3d-fsm';\nimport {\n\tGroundProbe3D,\n\tgetGroundAnchorOffsetY,\n\tgetGroundSnapTargetY,\n\ttype GroundProbeSupportHit,\n} from '../shared/ground-probe-3d';\nimport {\n\tcreateJumpConfig3D,\n\tcreateJumpInput3D,\n\tcreateJumpState3D,\n\ttype JumpConfig3D,\n\ttype JumpInput3D,\n\ttype JumpState3D,\n\ttype JumpContext3D,\n} from './components';\nimport {\n\tSTAGE_INPUT_BUTTON_JUMP,\n\treadBehaviorSnapshot,\n\ttype WasmStageRuntime,\n} from '../../runtime/wasm-stage-runtime';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Options exposed through entity.use()\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface Jumper3DBehaviorOptions {\n\t/** Desired peak height in world units (default: 2.5) */\n\tjumpHeight?: number;\n\t/** Gravity magnitude applied by the behavior (default: 20) */\n\tgravity?: number;\n\t/** Terminal fall speed (optional) */\n\tmaxFallSpeed?: number;\n\t/** Max concurrent jumps, 1 = single, 2 = double, etc. (default: 1) */\n\tmaxJumps?: number;\n\t/** Reset jump counter on ground (default: true) */\n\tresetJumpsOnGround?: boolean;\n\t/** Reset jump counter on wall contact (default: undefined) */\n\tresetJumpsOnWall?: boolean;\n\t/** Coyote time in ms (default: 100) */\n\tcoyoteTimeMs?: number;\n\t/** Jump buffer in ms (default: 80) */\n\tjumpBufferMs?: number;\n\t/** Min cooldown between jumps in ms (optional) */\n\tminTimeBetweenJumpsMs?: number;\n\t/** Variable jump height config (optional) */\n\tvariableJump?: JumpConfig3D['variableJump'];\n\t/** Planar control config (optional) */\n\tplanar?: JumpConfig3D['planar'];\n\t/** Fall tuning (optional) */\n\tfall?: JumpConfig3D['fall'];\n\t/** Ground-detection ray length (default: 1.0) */\n\tgroundRayLength?: number;\n\t/** Max support distance that counts as grounded and can snap to ground */\n\tsnapToGroundDistance?: number;\n\t/** Enable debug visualization for ground probe rays (default: false) */\n\tdebugGroundProbe?: boolean;\n}\n\nconst defaultOptions: Jumper3DBehaviorOptions = {\n\tjumpHeight: 2.5,\n\tgravity: 20,\n\tmaxJumps: 1,\n\tresetJumpsOnGround: true,\n\tcoyoteTimeMs: 100,\n\tjumpBufferMs: 80,\n\tgroundRayLength: 1.0,\n\tdebugGroundProbe: false,\n};\n\nconst JUMPER_BEHAVIOR_KEY = Symbol.for('zylem:behavior:jumper-3d');\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Entity shape expected by the system\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface Jumper3DEntity {\n\tuuid: string;\n\tbody: import('@dimforge/rapier3d-compat').RigidBody | null;\n\ttransformStore: import('../../capabilities/transform-store').TransformState;\n\tjumper: JumpConfig3D;\n\t$jumper: JumpInput3D;\n\tjumperState: JumpState3D;\n}\n\nexport function isJumper3DGrounded(params: {\n\tsupportToi?: number | null;\n\tvelocityY: number;\n\tsnapToGroundDistance?: number;\n}): boolean {\n\tif (params.snapToGroundDistance != null) {\n\t\treturn (\n\t\t\tparams.supportToi != null &&\n\t\t\tparams.supportToi <= params.snapToGroundDistance &&\n\t\t\tparams.velocityY <= 0.25\n\t\t);\n\t}\n\n\treturn (\n\t\tparams.supportToi != null &&\n\t\tparams.velocityY > -2.0 &&\n\t\tparams.velocityY < 2.0\n\t);\n}\n\nfunction shouldSnapJumper3DToGround(\n\tsupport: GroundProbeSupportHit | null,\n\toptions: Jumper3DBehaviorOptions,\n\tvelocityY: number,\n): support is GroundProbeSupportHit {\n\treturn (\n\t\tsupport != null &&\n\t\toptions.snapToGroundDistance != null &&\n\t\tvelocityY <= 0.25 &&\n\t\tsupport.toi <= options.snapToGroundDistance\n\t);\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Behavior System adapter\n// ─────────────────────────────────────────────────────────────────────────────\n\nclass Jumper3DBehaviorSystem implements BehaviorSystem {\n\tprivate behavior = new Jumper3DSystem();\n\tprivate groundProbe: GroundProbe3D;\n\tprivate initializedEntities = new Set<string>();\n\tprivate timeSinceGroundedMs = new Map<string, number>();\n\tprivate wasJumpHeld = new Map<string, boolean>();\n\tprivate attachedRuntimeSlots = new Set<number>();\n\n\tconstructor(\n\t\tworld: import('../../collision/world').ZylemWorld | null,\n\t\tprivate scene: any,\n\t\tprivate wasmStage: WasmStageRuntime | null,\n\t\tprivate getBehaviorLinks?: (key: symbol) => Iterable<BehaviorEntityLink>,\n\t) {\n\t\tthis.groundProbe = new GroundProbe3D(world);\n\t}\n\n\tupdate(_ecs: unknown, delta: number): void {\n\t\tconst links = this.getBehaviorLinks?.(JUMPER_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 jumperRef = link.ref as any;\n\n\t\t\tconst options = jumperRef.options as Jumper3DBehaviorOptions;\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, options);\n\t\t\t\tjumperRef.__wasmStage = this.wasmStage;\n\t\t\t\tjumperRef.__entity = gameEntity;\n\t\t\t\tconst input = gameEntity.$jumper as JumpInput3D | undefined;\n\t\t\t\tconst jumpPressed = !!(input?.jumpPressed || input?.jumpHeld);\n\t\t\t\tthis.wasmStage.writeInputButton(handle, STAGE_INPUT_BUTTON_JUMP, jumpPressed);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (!gameEntity.body) continue;\n\n\t\t\t// ── Lazy component init ────────────────────────────────────────\n\t\t\tif (!gameEntity.jumper) {\n\t\t\t\tgameEntity.jumper = createJumpConfig3D(options);\n\t\t\t}\n\t\t\tif (!gameEntity.$jumper) {\n\t\t\t\tgameEntity.$jumper = createJumpInput3D();\n\t\t\t}\n\t\t\tif (!gameEntity.jumperState) {\n\t\t\t\tgameEntity.jumperState = createJumpState3D();\n\t\t\t}\n\n\t\t\tif (!this.initializedEntities.has(gameEntity.uuid)) {\n\t\t\t\tthis.initializedEntities.add(gameEntity.uuid);\n\t\t\t\tgameEntity.body.setGravityScale(0, true);\n\t\t\t}\n\n\t\t\t// ── Lazy FSM init ──────────────────────────────────────────────\n\t\t\tif (!jumperRef.fsm && gameEntity.jumperState) {\n\t\t\t\tjumperRef.fsm = new Jumper3DFSM({\n\t\t\t\t\tstate: gameEntity.jumperState,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// ── Ground detection ───────────────────────────────────────────\n\t\t\tconst rayLength = options.groundRayLength ?? 1.0;\n\t\t\tconst bodyVel = gameEntity.body.linvel();\n\t\t\tconst probeOriginYOffset = 0.05 - getGroundAnchorOffsetY(gameEntity);\n\t\t\tconst support = this.groundProbe.probeSupport(gameEntity, {\n\t\t\t\trayLength,\n\t\t\t\tmode: 'center',\n\t\t\t\tdebug: options.debugGroundProbe ?? false,\n\t\t\t\tscene: this.scene,\n\t\t\t\toriginYOffset: probeOriginYOffset,\n\t\t\t});\n\t\t\tconst isGrounded = isJumper3DGrounded({\n\t\t\t\tsupportToi: support?.toi ?? null,\n\t\t\t\tvelocityY: bodyVel.y,\n\t\t\t\tsnapToGroundDistance: options.snapToGroundDistance,\n\t\t\t});\n\t\t\tif (shouldSnapJumper3DToGround(support, options, bodyVel.y)) {\n\t\t\t\tconst currentPosition = gameEntity.body.translation();\n\t\t\t\tgameEntity.body.setTranslation(\n\t\t\t\t\t{\n\t\t\t\t\t\tx: currentPosition.x,\n\t\t\t\t\t\ty: getGroundSnapTargetY(gameEntity, support),\n\t\t\t\t\t\tz: currentPosition.z,\n\t\t\t\t\t},\n\t\t\t\t\ttrue,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tlet tsg = this.timeSinceGroundedMs.get(gameEntity.uuid) ?? 0;\n\t\t\tif (isGrounded) {\n\t\t\t\ttsg = 0;\n\t\t\t} else {\n\t\t\t\ttsg += delta * 1000;\n\t\t\t}\n\t\t\tthis.timeSinceGroundedMs.set(gameEntity.uuid, tsg);\n\n\t\t\t// ── Build context ──────────────────────────────────────────────\n\t\t\t// Each behavior owns its own velocity axes. The jumper only\n\t\t\t// reads/writes Y; horizontal axes are left to the movement\n\t\t\t// controller. We read the current Y from the physics body\n\t\t\t// (post-step) so the jumper always sees the real vertical state.\n\t\t\tconst config: JumpConfig3D = gameEntity.jumper;\n\t\t\tconst input: JumpInput3D = gameEntity.$jumper;\n\t\t\tconst state: JumpState3D = gameEntity.jumperState;\n\t\t\tconst prevHeld = this.wasJumpHeld.get(gameEntity.uuid) ?? false;\n\t\t\tconst held = input.jumpHeld === true;\n\n\t\t\t// Input callbacks run after behavior systems in the frame loop.\n\t\t\t// Reconstruct button edges from held-state history so one-frame\n\t\t\t// `pressed`/`released` pulses are not missed by the jumper tick.\n\t\t\tconst effectiveInput: JumpInput3D = {\n\t\t\t\t...input,\n\t\t\t\tjumpPressed: input.jumpPressed || (held && !prevHeld),\n\t\t\t\tjumpReleased: input.jumpReleased || (!held && prevHeld),\n\t\t\t};\n\n\t\t\tconst store = gameEntity.transformStore;\n\n\t\t\tconst ctx: JumpContext3D = {\n\t\t\t\tdt: delta,\n\t\t\t\tup: { x: 0, y: 1, z: 0 },\n\t\t\t\tvelocityY: bodyVel.y,\n\t\t\t\thorizontalVelocity: { x: bodyVel.x, z: bodyVel.z },\n\t\t\t\tisGrounded,\n\t\t\t\ttimeSinceGroundedMs: tsg,\n\t\t\t\tsetVerticalVelocity: (y: number) => {\n\t\t\t\t\tsetVelocityIntent(\n\t\t\t\t\t\tstore,\n\t\t\t\t\t\t'jumper-3d',\n\t\t\t\t\t\t{ y },\n\t\t\t\t\t\t{ mode: 'replace', priority: 20 },\n\t\t\t\t\t);\n\t\t\t\t\tctx.velocityY = y;\n\t\t\t\t},\n\t\t\t\tsetHorizontalVelocity: (x: number, z: number) => {\n\t\t\t\t\tsetVelocityIntent(\n\t\t\t\t\t\tstore,\n\t\t\t\t\t\t'jumper-3d',\n\t\t\t\t\t\t{ x, z },\n\t\t\t\t\t\t{ mode: 'replace', priority: 20 },\n\t\t\t\t\t);\n\t\t\t\t\tctx.horizontalVelocity.x = x;\n\t\t\t\t\tctx.horizontalVelocity.z = z;\n\t\t\t\t},\n\t\t\t};\n\n\t\t\t// ── Tick ───────────────────────────────────────────────────────\n\t\t\tconst result = this.behavior.tick(config, effectiveInput, ctx, state);\n\t\t\tthis.wasJumpHeld.set(gameEntity.uuid, held);\n\n\t\t\t// ── FSM sync ───────────────────────────────────────────────────\n\t\t\tif (jumperRef.fsm) {\n\t\t\t\t(jumperRef.fsm as Jumper3DFSM).applyTickEvent(\n\t\t\t\t\tresult.event,\n\t\t\t\t\tisGrounded,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate ensureWasmAttached(handle: number, options: Jumper3DBehaviorOptions): void {\n\t\tif (!this.wasmStage || this.attachedRuntimeSlots.has(handle)) return;\n\t\tconst jumpForce = Math.sqrt(2 * (options.gravity ?? 20) * (options.jumpHeight ?? 2.5));\n\t\tthis.wasmStage.attachJumper3D(handle, {\n\t\t\tjumpForce,\n\t\t\tmaxJumps: options.maxJumps ?? 1,\n\t\t\tgravity: options.gravity ?? 20,\n\t\t\tcoyoteTime: (options.coyoteTimeMs ?? 100) / 1000,\n\t\t\tjumpBufferTime: (options.jumpBufferMs ?? 80) / 1000,\n\t\t});\n\t\tthis.attachedRuntimeSlots.add(handle);\n\t}\n\n\tdestroy(_ecs: unknown): void {\n\t\tthis.groundProbe.destroy();\n\t\tthis.initializedEntities.clear();\n\t\tthis.timeSinceGroundedMs.clear();\n\t\tthis.wasJumpHeld.clear();\n\t\tthis.attachedRuntimeSlots.clear();\n\t}\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Public descriptor\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Jumper3DBehavior — composable 3D jump behavior.\n *\n * Provides height-based jumping, multi-jump, coyote time, jump buffering,\n * variable jump height, configurable fall gravity, and optional air control.\n *\n * Designed to compose with any movement controller (e.g. FirstPersonBehavior)\n * — the controller writes X/Z velocity and Jumper3DBehavior writes Y velocity.\n *\n * @example\n * ```typescript\n * import { Jumper3DBehavior } from \"@zylem/game-lib/behavior\";\n *\n * const jumper = player.use(Jumper3DBehavior, {\n * jumpHeight: 2.5,\n * gravity: 20,\n * maxJumps: 2,\n * coyoteTimeMs: 100,\n * jumpBufferMs: 80,\n * variableJump: { enabled: true, cutGravityMultiplier: 3 },\n * fall: { fallGravityMultiplier: 1.5 },\n * });\n *\n * player.onUpdate(({ inputs }) => {\n * player.$jumper.jumpPressed = inputs.p1.buttons.A.pressed;\n * player.$jumper.jumpHeld = inputs.p1.buttons.A.held > 0;\n * player.$jumper.jumpReleased = inputs.p1.buttons.A.released;\n *\n * const state = jumper.getState(); // Grounded | Jumping | Falling\n * });\n * ```\n */\nexport const Jumper3DBehavior = defineBehavior<\n\tJumper3DBehaviorOptions,\n\t{\n\t\tgetState: () => Jumper3DState;\n\t\tisJumping: () => boolean;\n\t\tgetJumpsUsed: () => number;\n\t\tgetJumpsRemaining: () => number;\n\t},\n\tJumper3DEntity\n>({\n\tname: 'jumper-3d',\n\tdefaultOptions,\n\tsystemFactory: (ctx) =>\n\t\tnew Jumper3DBehaviorSystem(\n\t\t\tctx.world,\n\t\t\tctx.scene,\n\t\t\tctx.wasmStage ?? null,\n\t\t\tctx.getBehaviorLinks,\n\t\t),\n\t// On the wasm fast path the handle reads the runtime snapshot buffer\n\t// (previous-step values); the TS FSM only backs the no-wasm fallback.\n\tcreateHandle: (ref) => {\n\t\tconst jumpsUsed = () => {\n\t\t\tconst snapshot = readBehaviorSnapshot(ref);\n\t\t\tif (snapshot) return snapshot.jumpCount;\n\t\t\treturn (ref.fsm as Jumper3DFSM | undefined)?.getJumpsUsed() ?? 0;\n\t\t};\n\t\treturn {\n\t\t\tgetState: () => {\n\t\t\t\tconst snapshot = readBehaviorSnapshot(ref);\n\t\t\t\tif (snapshot) {\n\t\t\t\t\tif (snapshot.grounded) return Jumper3DState.Grounded;\n\t\t\t\t\treturn snapshot.verticalVelocity > 0\n\t\t\t\t\t\t? Jumper3DState.Jumping\n\t\t\t\t\t\t: Jumper3DState.Falling;\n\t\t\t\t}\n\t\t\t\treturn (\n\t\t\t\t\t(ref.fsm as Jumper3DFSM | undefined)?.getState() ??\n\t\t\t\t\tJumper3DState.Grounded\n\t\t\t\t);\n\t\t\t},\n\t\t\tisJumping: () => {\n\t\t\t\tconst snapshot = readBehaviorSnapshot(ref);\n\t\t\t\tif (snapshot) return !snapshot.grounded && snapshot.verticalVelocity > 0;\n\t\t\t\treturn (ref.fsm as Jumper3DFSM | undefined)?.isJumping() ?? false;\n\t\t\t},\n\t\t\tgetJumpsUsed: jumpsUsed,\n\t\t\tgetJumpsRemaining: () => (ref.options.maxJumps ?? 1) - jumpsUsed(),\n\t\t};\n\t},\n});\n"],"mappings":"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","names":["JumperTickEvent","Jumper3DState","Jumper3DEvent","input"]}