@zylem/behaviors 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. package/README.md +26 -0
  2. package/dist/behavior-system-DYbx-x_-.d.ts +307 -0
  3. package/dist/chunk-2C3Z5GE7.js +176 -0
  4. package/dist/chunk-2C3Z5GE7.js.map +1 -0
  5. package/dist/chunk-2CLT36VB.js +241 -0
  6. package/dist/chunk-2CLT36VB.js.map +1 -0
  7. package/dist/chunk-3PYGRHAL.js +35 -0
  8. package/dist/chunk-3PYGRHAL.js.map +1 -0
  9. package/dist/chunk-4I6E6DGV.js +212 -0
  10. package/dist/chunk-4I6E6DGV.js.map +1 -0
  11. package/dist/chunk-4URF65BR.js +44 -0
  12. package/dist/chunk-4URF65BR.js.map +1 -0
  13. package/dist/chunk-6C6NXNEW.js +38 -0
  14. package/dist/chunk-6C6NXNEW.js.map +1 -0
  15. package/dist/chunk-ARJWUNRE.js +431 -0
  16. package/dist/chunk-ARJWUNRE.js.map +1 -0
  17. package/dist/chunk-BXP4K7RF.js +1205 -0
  18. package/dist/chunk-BXP4K7RF.js.map +1 -0
  19. package/dist/chunk-DYLH6K7B.js +44 -0
  20. package/dist/chunk-DYLH6K7B.js.map +1 -0
  21. package/dist/chunk-EIWQM6U3.js +27 -0
  22. package/dist/chunk-EIWQM6U3.js.map +1 -0
  23. package/dist/chunk-EZNCCO4L.js +14 -0
  24. package/dist/chunk-EZNCCO4L.js.map +1 -0
  25. package/dist/chunk-F3KRX2V4.js +457 -0
  26. package/dist/chunk-F3KRX2V4.js.map +1 -0
  27. package/dist/chunk-FPTWVCPN.js +53 -0
  28. package/dist/chunk-FPTWVCPN.js.map +1 -0
  29. package/dist/chunk-GCNRXAKH.js +37 -0
  30. package/dist/chunk-GCNRXAKH.js.map +1 -0
  31. package/dist/chunk-GYURWCIQ.js +1985 -0
  32. package/dist/chunk-GYURWCIQ.js.map +1 -0
  33. package/dist/chunk-HZMY3TT4.js +244 -0
  34. package/dist/chunk-HZMY3TT4.js.map +1 -0
  35. package/dist/chunk-ID5QJYF5.js +50 -0
  36. package/dist/chunk-ID5QJYF5.js.map +1 -0
  37. package/dist/chunk-JAN34G6S.js +552 -0
  38. package/dist/chunk-JAN34G6S.js.map +1 -0
  39. package/dist/chunk-K3UNLQ7W.js +118 -0
  40. package/dist/chunk-K3UNLQ7W.js.map +1 -0
  41. package/dist/chunk-KDY5N6J4.js +82 -0
  42. package/dist/chunk-KDY5N6J4.js.map +1 -0
  43. package/dist/chunk-KOZUNIIE.js +413 -0
  44. package/dist/chunk-KOZUNIIE.js.map +1 -0
  45. package/dist/chunk-KS72RZHX.js +30 -0
  46. package/dist/chunk-KS72RZHX.js.map +1 -0
  47. package/dist/chunk-LD5SMIB3.js +32 -0
  48. package/dist/chunk-LD5SMIB3.js.map +1 -0
  49. package/dist/chunk-OHCPV2NT.js +86 -0
  50. package/dist/chunk-OHCPV2NT.js.map +1 -0
  51. package/dist/chunk-OYWFPIHF.js +115 -0
  52. package/dist/chunk-OYWFPIHF.js.map +1 -0
  53. package/dist/chunk-POZER3MQ.js +407 -0
  54. package/dist/chunk-POZER3MQ.js.map +1 -0
  55. package/dist/chunk-RTRVBEIB.js +56 -0
  56. package/dist/chunk-RTRVBEIB.js.map +1 -0
  57. package/dist/chunk-RTVRUNYR.js +29 -0
  58. package/dist/chunk-RTVRUNYR.js.map +1 -0
  59. package/dist/chunk-SS7ELMJ7.js +406 -0
  60. package/dist/chunk-SS7ELMJ7.js.map +1 -0
  61. package/dist/chunk-STCCNLPC.js +160 -0
  62. package/dist/chunk-STCCNLPC.js.map +1 -0
  63. package/dist/chunk-SVLNF434.js +261 -0
  64. package/dist/chunk-SVLNF434.js.map +1 -0
  65. package/dist/chunk-UYFOLI2X.js +24 -0
  66. package/dist/chunk-UYFOLI2X.js.map +1 -0
  67. package/dist/chunk-VAN4WW3F.js +67 -0
  68. package/dist/chunk-VAN4WW3F.js.map +1 -0
  69. package/dist/chunk-WOMHL23C.js +369 -0
  70. package/dist/chunk-WOMHL23C.js.map +1 -0
  71. package/dist/chunk-WWVD5DR5.js +120 -0
  72. package/dist/chunk-WWVD5DR5.js.map +1 -0
  73. package/dist/chunk-XG2YMCJW.js +201 -0
  74. package/dist/chunk-XG2YMCJW.js.map +1 -0
  75. package/dist/chunk-XIJNE67Y.js +210 -0
  76. package/dist/chunk-XIJNE67Y.js.map +1 -0
  77. package/dist/chunk-Y6UJOUE5.js +44 -0
  78. package/dist/chunk-Y6UJOUE5.js.map +1 -0
  79. package/dist/chunk-YUO6SKJD.js +348 -0
  80. package/dist/chunk-YUO6SKJD.js.map +1 -0
  81. package/dist/components--hjBMTnz.d.ts +120 -0
  82. package/dist/components-B29WHGQN.d.ts +39 -0
  83. package/dist/components-BWG1GkZA.d.ts +20 -0
  84. package/dist/components-XCpL6IYt.d.ts +18 -0
  85. package/dist/components-qWwOsvwh.d.ts +43 -0
  86. package/dist/cooldown.d.ts +116 -0
  87. package/dist/cooldown.js +20 -0
  88. package/dist/cooldown.js.map +1 -0
  89. package/dist/coordinators/boundary-ricochet-3d.d.ts +19 -0
  90. package/dist/coordinators/boundary-ricochet-3d.js +8 -0
  91. package/dist/coordinators/boundary-ricochet-3d.js.map +1 -0
  92. package/dist/coordinators/boundary-ricochet.d.ts +34 -0
  93. package/dist/coordinators/boundary-ricochet.js +8 -0
  94. package/dist/coordinators/boundary-ricochet.js.map +1 -0
  95. package/dist/coordinators/first-person-shooter.d.ts +35 -0
  96. package/dist/coordinators/first-person-shooter.js +9 -0
  97. package/dist/coordinators/first-person-shooter.js.map +1 -0
  98. package/dist/coordinators/multidirectional-space-shooter.d.ts +27 -0
  99. package/dist/coordinators/multidirectional-space-shooter.js +10 -0
  100. package/dist/coordinators/multidirectional-space-shooter.js.map +1 -0
  101. package/dist/coordinators/top-down-shooter.d.ts +27 -0
  102. package/dist/coordinators/top-down-shooter.js +10 -0
  103. package/dist/coordinators/top-down-shooter.js.map +1 -0
  104. package/dist/core.d.ts +25 -0
  105. package/dist/core.js +327 -0
  106. package/dist/core.js.map +1 -0
  107. package/dist/destructible-3d.d.ts +42 -0
  108. package/dist/destructible-3d.js +13 -0
  109. package/dist/destructible-3d.js.map +1 -0
  110. package/dist/destructible-prebake.d.ts +28 -0
  111. package/dist/destructible-prebake.js +23 -0
  112. package/dist/destructible-prebake.js.map +1 -0
  113. package/dist/entity-types-CmtQ-IBp.d.ts +15 -0
  114. package/dist/first-person-perspective-C9Mptl0-.d.ts +23 -0
  115. package/dist/first-person.d.ts +204 -0
  116. package/dist/first-person.js +27 -0
  117. package/dist/first-person.js.map +1 -0
  118. package/dist/index.d.ts +40 -0
  119. package/dist/index.js +263 -0
  120. package/dist/index.js.map +1 -0
  121. package/dist/jumper-2d.d.ts +113 -0
  122. package/dist/jumper-2d.js +27 -0
  123. package/dist/jumper-2d.js.map +1 -0
  124. package/dist/jumper-3d.d.ts +164 -0
  125. package/dist/jumper-3d.js +29 -0
  126. package/dist/jumper-3d.js.map +1 -0
  127. package/dist/moveable-BCRpjAQb.d.ts +176 -0
  128. package/dist/particle-emitter/presets.d.ts +46 -0
  129. package/dist/particle-emitter/presets.js +15 -0
  130. package/dist/particle-emitter/presets.js.map +1 -0
  131. package/dist/particle-emitter.d.ts +78 -0
  132. package/dist/particle-emitter.js +15 -0
  133. package/dist/particle-emitter.js.map +1 -0
  134. package/dist/payload-BQzu-oY_.d.ts +89 -0
  135. package/dist/platformer-3d.d.ts +347 -0
  136. package/dist/platformer-3d.js +23 -0
  137. package/dist/platformer-3d.js.map +1 -0
  138. package/dist/ricochet-2d.d.ts +274 -0
  139. package/dist/ricochet-2d.js +16 -0
  140. package/dist/ricochet-2d.js.map +1 -0
  141. package/dist/ricochet-3d.d.ts +116 -0
  142. package/dist/ricochet-3d.js +16 -0
  143. package/dist/ricochet-3d.js.map +1 -0
  144. package/dist/runtime-2d.d.ts +2 -0
  145. package/dist/runtime-2d.js +32 -0
  146. package/dist/runtime-2d.js.map +1 -0
  147. package/dist/runtime-pong.d.ts +92 -0
  148. package/dist/runtime-pong.js +38 -0
  149. package/dist/runtime-pong.js.map +1 -0
  150. package/dist/screen-visibility.d.ts +74 -0
  151. package/dist/screen-visibility.js +10 -0
  152. package/dist/screen-visibility.js.map +1 -0
  153. package/dist/screen-wrap.d.ts +86 -0
  154. package/dist/screen-wrap.js +16 -0
  155. package/dist/screen-wrap.js.map +1 -0
  156. package/dist/shooter-2d.d.ts +77 -0
  157. package/dist/shooter-2d.js +12 -0
  158. package/dist/shooter-2d.js.map +1 -0
  159. package/dist/spark-DDlIg1nM.d.ts +148 -0
  160. package/dist/sync-state-machine-CZyspBpj.d.ts +16 -0
  161. package/dist/thruster.d.ts +132 -0
  162. package/dist/thruster.js +26 -0
  163. package/dist/thruster.js.map +1 -0
  164. package/dist/top-down-movement.d.ts +40 -0
  165. package/dist/top-down-movement.js +20 -0
  166. package/dist/top-down-movement.js.map +1 -0
  167. package/dist/use-behavior-D_82jAL3.d.ts +13 -0
  168. package/dist/vector-Bm65-FOG.d.ts +45 -0
  169. package/dist/world-boundary-2d.d.ts +141 -0
  170. package/dist/world-boundary-2d.js +21 -0
  171. package/dist/world-boundary-2d.js.map +1 -0
  172. package/dist/world-boundary-3d.d.ts +75 -0
  173. package/dist/world-boundary-3d.js +21 -0
  174. package/dist/world-boundary-3d.js.map +1 -0
  175. package/package.json +161 -0
@@ -0,0 +1,348 @@
1
+ import {
2
+ createFirstPersonInputComponent,
3
+ createFirstPersonMovementComponent,
4
+ createFirstPersonStateComponent
5
+ } from "./chunk-LD5SMIB3.js";
6
+ import {
7
+ VEC3_ZERO,
8
+ toThreeVector3
9
+ } from "./chunk-WWVD5DR5.js";
10
+ import {
11
+ setVelocityIntent
12
+ } from "./chunk-RTVRUNYR.js";
13
+ import {
14
+ SyncStateMachine,
15
+ t
16
+ } from "./chunk-4URF65BR.js";
17
+ import {
18
+ defineBehavior
19
+ } from "./chunk-EZNCCO4L.js";
20
+
21
+ // src/lib/behaviors/first-person/first-person-fsm.ts
22
+ var FirstPersonState = /* @__PURE__ */ ((FirstPersonState2) => {
23
+ FirstPersonState2["Idle"] = "idle";
24
+ FirstPersonState2["Walking"] = "walking";
25
+ FirstPersonState2["Running"] = "running";
26
+ return FirstPersonState2;
27
+ })(FirstPersonState || {});
28
+ var FirstPersonEvent = /* @__PURE__ */ ((FirstPersonEvent2) => {
29
+ FirstPersonEvent2["Walk"] = "walk";
30
+ FirstPersonEvent2["Run"] = "run";
31
+ FirstPersonEvent2["Stop"] = "stop";
32
+ return FirstPersonEvent2;
33
+ })(FirstPersonEvent || {});
34
+ var FirstPersonFSM = class {
35
+ constructor(ctx) {
36
+ this.ctx = ctx;
37
+ this.machine = new SyncStateMachine(
38
+ "idle" /* Idle */,
39
+ [
40
+ // Idle transitions
41
+ t("idle" /* Idle */, "walk" /* Walk */, "walking" /* Walking */),
42
+ t("idle" /* Idle */, "run" /* Run */, "running" /* Running */),
43
+ t("idle" /* Idle */, "stop" /* Stop */, "idle" /* Idle */),
44
+ // Walking transitions
45
+ t("walking" /* Walking */, "run" /* Run */, "running" /* Running */),
46
+ t("walking" /* Walking */, "stop" /* Stop */, "idle" /* Idle */),
47
+ t("walking" /* Walking */, "walk" /* Walk */, "walking" /* Walking */),
48
+ // Running transitions
49
+ t("running" /* Running */, "walk" /* Walk */, "walking" /* Walking */),
50
+ t("running" /* Running */, "stop" /* Stop */, "idle" /* Idle */),
51
+ t("running" /* Running */, "run" /* Run */, "running" /* Running */)
52
+ ]
53
+ );
54
+ }
55
+ ctx;
56
+ machine;
57
+ /** Get the current state */
58
+ getState() {
59
+ return this.machine.getState();
60
+ }
61
+ /** Dispatch an event to the FSM */
62
+ dispatch(event) {
63
+ if (this.machine.can(event)) {
64
+ this.machine.syncDispatch(event);
65
+ }
66
+ }
67
+ /** Get the current yaw from context */
68
+ getYaw() {
69
+ return this.ctx.state.yaw;
70
+ }
71
+ /** Get the current pitch from context */
72
+ getPitch() {
73
+ return this.ctx.state.pitch;
74
+ }
75
+ /**
76
+ * Update FSM based on current input and state.
77
+ */
78
+ update(input, state) {
79
+ this.ctx.input = input;
80
+ this.ctx.state = state;
81
+ const hasMovement = Math.abs(input.moveX) > 0.1 || Math.abs(input.moveZ) > 0.1;
82
+ if (hasMovement) {
83
+ if (input.sprint) {
84
+ this.dispatch("run" /* Run */);
85
+ } else {
86
+ this.dispatch("walk" /* Walk */);
87
+ }
88
+ } else {
89
+ this.dispatch("stop" /* Stop */);
90
+ }
91
+ }
92
+ };
93
+
94
+ // src/lib/behaviors/first-person/first-person.behavior.ts
95
+ import { Vector3, Quaternion, Euler } from "three";
96
+ var _forward = new Vector3();
97
+ var _right = new Vector3();
98
+ var _up = new Vector3(0, 1, 0);
99
+ var _viewmodelQuat = new Quaternion();
100
+ var _viewmodelLocalQuat = new Quaternion();
101
+ var _viewmodelEuler = new Euler();
102
+ var _offset = new Vector3();
103
+ var FirstPersonControllerBehavior = class {
104
+ world;
105
+ perspectives = /* @__PURE__ */ new Map();
106
+ viewmodels = /* @__PURE__ */ new Map();
107
+ constructor(world) {
108
+ this.world = world;
109
+ }
110
+ /**
111
+ * Associate a FirstPersonPerspective with an entity (by uuid).
112
+ * Called once by the descriptor system when the behavior is initialized.
113
+ */
114
+ setPerspective(entityUuid, perspective) {
115
+ this.perspectives.set(entityUuid, perspective);
116
+ }
117
+ hasPerspective(entityUuid) {
118
+ return this.perspectives.has(entityUuid);
119
+ }
120
+ /**
121
+ * Attach a viewmodel (weapon/item) to an entity.
122
+ * The viewmodel entity's group will be positioned relative to the camera each frame.
123
+ */
124
+ setViewmodel(entityUuid, config) {
125
+ this.viewmodels.set(entityUuid, config);
126
+ }
127
+ hasViewmodel(entityUuid) {
128
+ return this.viewmodels.has(entityUuid);
129
+ }
130
+ /**
131
+ * Update one first-person entity.
132
+ */
133
+ updateEntity(entity, _delta) {
134
+ const fpEntity = entity;
135
+ if (!fpEntity.firstPerson || !fpEntity.$fps || !fpEntity.firstPersonState) {
136
+ return;
137
+ }
138
+ const input = fpEntity.$fps;
139
+ const movement = fpEntity.firstPerson;
140
+ const state = fpEntity.firstPersonState;
141
+ const perspective = this.perspectives.get(fpEntity.uuid);
142
+ if (perspective?.initialPosition && fpEntity.body) {
143
+ const pos = fpEntity.body.translation();
144
+ perspective.initialPosition.set(
145
+ pos.x,
146
+ pos.y + movement.eyeHeight,
147
+ pos.z
148
+ );
149
+ }
150
+ if (perspective) {
151
+ perspective.look(
152
+ -input.lookX * movement.lookSensitivity,
153
+ -input.lookY * movement.lookSensitivity
154
+ );
155
+ state.yaw = perspective.yaw;
156
+ state.pitch = perspective.pitch;
157
+ }
158
+ const speed = input.sprint ? movement.runSpeed : movement.walkSpeed;
159
+ state.currentSpeed = speed;
160
+ const hasMovement = Math.abs(input.moveX) > 0.1 || Math.abs(input.moveZ) > 0.1;
161
+ if (fpEntity.transformStore) {
162
+ if (hasMovement) {
163
+ _forward.set(0, 0, -1).applyAxisAngle(_up, state.yaw);
164
+ _right.set(1, 0, 0).applyAxisAngle(_up, state.yaw);
165
+ const vx = _right.x * input.moveX * speed + _forward.x * -input.moveZ * speed;
166
+ const vz = _right.z * input.moveX * speed + _forward.z * -input.moveZ * speed;
167
+ setVelocityIntent(
168
+ fpEntity.transformStore,
169
+ "first-person",
170
+ { x: vx, z: vz },
171
+ { mode: "replace", priority: 10 }
172
+ );
173
+ } else {
174
+ setVelocityIntent(
175
+ fpEntity.transformStore,
176
+ "first-person",
177
+ { x: 0, z: 0 },
178
+ { mode: "replace", priority: 10 }
179
+ );
180
+ }
181
+ }
182
+ const vm = this.viewmodels.get(fpEntity.uuid);
183
+ if (vm && perspective?.initialPosition) {
184
+ this.positionViewmodel(vm, perspective, state);
185
+ }
186
+ }
187
+ /**
188
+ * Update all first-person entities.
189
+ */
190
+ update(delta) {
191
+ if (!this.world?.collisionMap) return;
192
+ for (const [, entity] of this.world.collisionMap) {
193
+ this.updateEntity(entity, delta);
194
+ }
195
+ }
196
+ /**
197
+ * Position a viewmodel entity relative to the camera's eye position and rotation.
198
+ *
199
+ * The physics transform system overwrites group.position from the rigid body
200
+ * each frame, so we must also move the body to keep them in sync.
201
+ */
202
+ positionViewmodel(vm, perspective, state) {
203
+ const eyePos = perspective.initialPosition;
204
+ if (!eyePos) return;
205
+ _viewmodelQuat.setFromEuler(
206
+ _viewmodelEuler.set(state.pitch, state.yaw, 0, "YXZ")
207
+ );
208
+ if (vm.rotation) {
209
+ _viewmodelLocalQuat.setFromEuler(vm.rotation);
210
+ _viewmodelQuat.multiply(_viewmodelLocalQuat);
211
+ }
212
+ _offset.copy(vm.offset).applyQuaternion(_viewmodelQuat);
213
+ const wx = eyePos.x + _offset.x;
214
+ const wy = eyePos.y + _offset.y;
215
+ const wz = eyePos.z + _offset.z;
216
+ const entity = vm.entity;
217
+ if (entity?.body) {
218
+ entity.body.setTranslation({ x: wx, y: wy, z: wz }, true);
219
+ entity.body.setRotation(
220
+ { x: _viewmodelQuat.x, y: _viewmodelQuat.y, z: _viewmodelQuat.z, w: _viewmodelQuat.w },
221
+ true
222
+ );
223
+ }
224
+ if (entity?.group) {
225
+ entity.group.position.set(wx, wy, wz);
226
+ entity.group.quaternion.copy(_viewmodelQuat);
227
+ }
228
+ }
229
+ /** Cleanup */
230
+ destroy() {
231
+ this.perspectives.clear();
232
+ this.viewmodels.clear();
233
+ }
234
+ };
235
+
236
+ // src/lib/behaviors/first-person/first-person.descriptor.ts
237
+ var defaultOptions = {
238
+ walkSpeed: 8,
239
+ runSpeed: 16,
240
+ lookSensitivity: 2,
241
+ eyeHeight: 1.7
242
+ };
243
+ var FIRST_PERSON_BEHAVIOR_KEY = /* @__PURE__ */ Symbol.for(
244
+ "zylem:behavior:first-person-controller"
245
+ );
246
+ var FirstPersonControllerSystem = class {
247
+ constructor(world, wasmStage, getBehaviorLinks) {
248
+ this.world = world;
249
+ this.wasmStage = wasmStage;
250
+ this.getBehaviorLinks = getBehaviorLinks;
251
+ this.behavior = new FirstPersonControllerBehavior(world);
252
+ }
253
+ world;
254
+ wasmStage;
255
+ getBehaviorLinks;
256
+ behavior;
257
+ attachedRuntimeSlots = /* @__PURE__ */ new Set();
258
+ update(_ecs, delta) {
259
+ const links = this.getBehaviorLinks?.(FIRST_PERSON_BEHAVIOR_KEY);
260
+ if (!links) return;
261
+ for (const link of links) {
262
+ const gameEntity = link.entity;
263
+ const fpsRef = link.ref;
264
+ const options = fpsRef.options;
265
+ const handle = gameEntity.runtimeHandle ?? -1;
266
+ if (this.wasmStage && handle >= 0) {
267
+ this.ensureWasmAttached(handle, options);
268
+ const input = gameEntity.$fps;
269
+ if (input) {
270
+ this.wasmStage.setFirstPersonInput(handle, {
271
+ moveX: input.moveX ?? 0,
272
+ moveZ: input.moveZ ?? 0,
273
+ lookYawDelta: input.lookX ?? 0,
274
+ lookPitchDelta: input.lookY ?? 0,
275
+ run: !!input.sprint
276
+ });
277
+ }
278
+ continue;
279
+ }
280
+ if (!gameEntity.firstPerson) {
281
+ gameEntity.firstPerson = createFirstPersonMovementComponent(options);
282
+ }
283
+ if (!gameEntity.$fps) {
284
+ gameEntity.$fps = createFirstPersonInputComponent();
285
+ }
286
+ if (!gameEntity.firstPersonState) {
287
+ gameEntity.firstPersonState = createFirstPersonStateComponent();
288
+ }
289
+ if (options.perspective && !this.behavior.hasPerspective(gameEntity.uuid)) {
290
+ this.behavior.setPerspective(gameEntity.uuid, options.perspective);
291
+ }
292
+ if (options.viewmodel && !this.behavior.hasViewmodel(gameEntity.uuid)) {
293
+ this.behavior.setViewmodel(gameEntity.uuid, {
294
+ ...options.viewmodel,
295
+ offset: toThreeVector3(options.viewmodel.offset, VEC3_ZERO)
296
+ });
297
+ }
298
+ if (!fpsRef.fsm && gameEntity.$fps && gameEntity.firstPersonState) {
299
+ fpsRef.fsm = new FirstPersonFSM({
300
+ input: gameEntity.$fps,
301
+ state: gameEntity.firstPersonState
302
+ });
303
+ }
304
+ if (fpsRef.fsm && gameEntity.$fps && gameEntity.firstPersonState) {
305
+ fpsRef.fsm.update(gameEntity.$fps, gameEntity.firstPersonState);
306
+ }
307
+ this.behavior.updateEntity(gameEntity, delta);
308
+ }
309
+ }
310
+ ensureWasmAttached(handle, options) {
311
+ if (!this.wasmStage || this.attachedRuntimeSlots.has(handle)) return;
312
+ this.wasmStage.attachFirstPerson(handle, {
313
+ walkSpeed: options.walkSpeed ?? defaultOptions.walkSpeed,
314
+ runSpeed: options.runSpeed ?? defaultOptions.runSpeed,
315
+ eyeHeight: options.eyeHeight ?? defaultOptions.eyeHeight,
316
+ lookSensitivity: options.lookSensitivity ?? defaultOptions.lookSensitivity
317
+ });
318
+ this.attachedRuntimeSlots.add(handle);
319
+ }
320
+ destroy(_ecs) {
321
+ this.behavior.destroy();
322
+ this.attachedRuntimeSlots.clear();
323
+ }
324
+ };
325
+ var FirstPersonController = defineBehavior({
326
+ name: "first-person-controller",
327
+ defaultOptions,
328
+ systemFactory: (ctx) => new FirstPersonControllerSystem(ctx.world, ctx.wasmStage ?? null, ctx.getBehaviorLinks),
329
+ createHandle: (ref) => ({
330
+ getState: () => ref.fsm?.getState() ?? "idle" /* Idle */,
331
+ getYaw: () => ref.fsm?.getYaw() ?? 0,
332
+ getPitch: () => ref.fsm?.getPitch() ?? 0,
333
+ attachViewmodel: (entity, offset) => {
334
+ if (ref.options) {
335
+ ref.options.viewmodel = { entity, offset };
336
+ }
337
+ }
338
+ })
339
+ });
340
+
341
+ export {
342
+ FirstPersonState,
343
+ FirstPersonEvent,
344
+ FirstPersonFSM,
345
+ FirstPersonControllerBehavior,
346
+ FirstPersonController
347
+ };
348
+ //# sourceMappingURL=chunk-YUO6SKJD.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/behaviors/first-person/first-person-fsm.ts","../src/lib/behaviors/first-person/first-person.behavior.ts","../src/lib/behaviors/first-person/first-person.descriptor.ts"],"sourcesContent":["/**\n * First Person Controller Finite State Machine\n *\n * Manages state transitions for first-person movement:\n * - Idle: Standing still\n * - Walking: Moving at walk speed\n * - Running: Moving at run/sprint speed\n */\n\nimport { SyncStateMachine, t } from '../../core/utility/sync-state-machine';\nimport type { FirstPersonInputComponent, FirstPersonStateComponent } from './components';\n\n/**\n * First-person movement states\n */\nexport enum FirstPersonState {\n\tIdle = 'idle',\n\tWalking = 'walking',\n\tRunning = 'running',\n}\n\n/**\n * Events that trigger state transitions\n */\nexport enum FirstPersonEvent {\n\tWalk = 'walk',\n\tRun = 'run',\n\tStop = 'stop',\n}\n\n/**\n * Context for the FSM\n */\nexport interface FirstPersonContext {\n\tinput: FirstPersonInputComponent;\n\tstate: FirstPersonStateComponent;\n}\n\n/**\n * First Person Controller FSM\n */\nexport class FirstPersonFSM {\n\tmachine: SyncStateMachine<FirstPersonState, FirstPersonEvent, never>;\n\n\tconstructor(private ctx: FirstPersonContext) {\n\t\tthis.machine = new SyncStateMachine<FirstPersonState, FirstPersonEvent, never>(\n\t\t\tFirstPersonState.Idle,\n\t\t\t[\n\t\t\t\t// Idle transitions\n\t\t\t\tt(FirstPersonState.Idle, FirstPersonEvent.Walk, FirstPersonState.Walking),\n\t\t\t\tt(FirstPersonState.Idle, FirstPersonEvent.Run, FirstPersonState.Running),\n\t\t\t\tt(FirstPersonState.Idle, FirstPersonEvent.Stop, FirstPersonState.Idle),\n\n\t\t\t\t// Walking transitions\n\t\t\t\tt(FirstPersonState.Walking, FirstPersonEvent.Run, FirstPersonState.Running),\n\t\t\t\tt(FirstPersonState.Walking, FirstPersonEvent.Stop, FirstPersonState.Idle),\n\t\t\t\tt(FirstPersonState.Walking, FirstPersonEvent.Walk, FirstPersonState.Walking),\n\n\t\t\t\t// Running transitions\n\t\t\t\tt(FirstPersonState.Running, FirstPersonEvent.Walk, FirstPersonState.Walking),\n\t\t\t\tt(FirstPersonState.Running, FirstPersonEvent.Stop, FirstPersonState.Idle),\n\t\t\t\tt(FirstPersonState.Running, FirstPersonEvent.Run, FirstPersonState.Running),\n\t\t\t],\n\t\t);\n\t}\n\n\t/** Get the current state */\n\tgetState(): FirstPersonState {\n\t\treturn this.machine.getState();\n\t}\n\n\t/** Dispatch an event to the FSM */\n\tdispatch(event: FirstPersonEvent): void {\n\t\tif (this.machine.can(event)) {\n\t\t\tthis.machine.syncDispatch(event);\n\t\t}\n\t}\n\n\t/** Get the current yaw from context */\n\tgetYaw(): number {\n\t\treturn this.ctx.state.yaw;\n\t}\n\n\t/** Get the current pitch from context */\n\tgetPitch(): number {\n\t\treturn this.ctx.state.pitch;\n\t}\n\n\t/**\n\t * Update FSM based on current input and state.\n\t */\n\tupdate(input: FirstPersonInputComponent, state: FirstPersonStateComponent): void {\n\t\tthis.ctx.input = input;\n\t\tthis.ctx.state = state;\n\n\t\tconst hasMovement = Math.abs(input.moveX) > 0.1 || Math.abs(input.moveZ) > 0.1;\n\n\t\tif (hasMovement) {\n\t\t\tif (input.sprint) {\n\t\t\t\tthis.dispatch(FirstPersonEvent.Run);\n\t\t\t} else {\n\t\t\t\tthis.dispatch(FirstPersonEvent.Walk);\n\t\t\t}\n\t\t} else {\n\t\t\tthis.dispatch(FirstPersonEvent.Stop);\n\t\t}\n\t}\n}\n","/**\n * First Person Controller Behavior System\n *\n * Handles first-person camera control and movement:\n * - Reads input component for WASD movement and mouse look deltas\n * - Drives a FirstPersonPerspective (yaw/pitch accumulation)\n * - Writes velocity to transformStore (physics-based movement)\n * - Syncs camera position from the entity's rigid body each frame\n * - Positions an optional viewmodel entity relative to the camera\n */\n\nimport { Vector3, Quaternion, Euler } from 'three';\nimport type { FirstPersonPerspective } from '../../camera/perspectives/first-person-perspective';\nimport { setVelocityIntent } from '../../actions/capabilities/velocity-intents';\nimport type {\n\tFirstPersonMovementComponent,\n\tFirstPersonInputComponent,\n\tFirstPersonStateComponent,\n} from './components';\n\n/**\n * Viewmodel configuration for an entity that follows the camera.\n */\nexport interface ViewmodelConfig {\n\t/** The entity whose visual group should be positioned relative to the camera. */\n\tentity: any;\n\t/** Offset from the eye position in camera-local space (right, down, forward). */\n\toffset: Vector3;\n\t/** Additional rotation applied to the viewmodel in local space (Euler angles in radians). */\n\trotation?: Euler;\n}\n\n/**\n * Entity interface for first-person controller.\n * Entities with this behavior have these components attached.\n */\nexport interface FirstPersonEntity {\n\tuuid: string;\n\tbody: any;\n\ttransformStore: any;\n\tfirstPerson: FirstPersonMovementComponent;\n\t$fps: FirstPersonInputComponent;\n\tfirstPersonState: FirstPersonStateComponent;\n}\n\n// Reusable temporaries (avoid per-frame allocations)\nconst _forward = new Vector3();\nconst _right = new Vector3();\nconst _up = new Vector3(0, 1, 0);\nconst _viewmodelQuat = new Quaternion();\nconst _viewmodelLocalQuat = new Quaternion();\nconst _viewmodelEuler = new Euler();\nconst _offset = new Vector3();\n\n/**\n * First Person Controller Behavior\n *\n * Core movement + look system for first-person cameras.\n * Reads from entity.$fps input component and drives a FirstPersonPerspective.\n */\nexport class FirstPersonControllerBehavior {\n\tprivate world: any;\n\tprivate perspectives = new Map<string, FirstPersonPerspective>();\n\tprivate viewmodels = new Map<string, ViewmodelConfig>();\n\n\tconstructor(world: any) {\n\t\tthis.world = world;\n\t}\n\n\t/**\n\t * Associate a FirstPersonPerspective with an entity (by uuid).\n\t * Called once by the descriptor system when the behavior is initialized.\n\t */\n\tsetPerspective(entityUuid: string, perspective: FirstPersonPerspective): void {\n\t\tthis.perspectives.set(entityUuid, perspective);\n\t}\n\n\thasPerspective(entityUuid: string): boolean {\n\t\treturn this.perspectives.has(entityUuid);\n\t}\n\n\t/**\n\t * Attach a viewmodel (weapon/item) to an entity.\n\t * The viewmodel entity's group will be positioned relative to the camera each frame.\n\t */\n\tsetViewmodel(entityUuid: string, config: ViewmodelConfig): void {\n\t\tthis.viewmodels.set(entityUuid, config);\n\t}\n\n\thasViewmodel(entityUuid: string): boolean {\n\t\treturn this.viewmodels.has(entityUuid);\n\t}\n\n\t/**\n\t * Update one first-person entity.\n\t */\n\tupdateEntity(entity: any, _delta: number): void {\n\t\tconst fpEntity = entity as any;\n\t\tif (!fpEntity.firstPerson || !fpEntity.$fps || !fpEntity.firstPersonState) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst input: FirstPersonInputComponent = fpEntity.$fps;\n\t\tconst movement: FirstPersonMovementComponent = fpEntity.firstPerson;\n\t\tconst state: FirstPersonStateComponent = fpEntity.firstPersonState;\n\t\tconst perspective = this.perspectives.get(fpEntity.uuid);\n\n\t\t// 1. Sync camera position from physics body\n\t\tif (perspective?.initialPosition && fpEntity.body) {\n\t\t\tconst pos = fpEntity.body.translation();\n\t\t\tperspective.initialPosition.set(\n\t\t\t\tpos.x,\n\t\t\t\tpos.y + movement.eyeHeight,\n\t\t\t\tpos.z,\n\t\t\t);\n\t\t}\n\n\t\t// 2. Apply look\n\t\tif (perspective) {\n\t\t\tperspective.look(\n\t\t\t\t-input.lookX * movement.lookSensitivity,\n\t\t\t\t-input.lookY * movement.lookSensitivity,\n\t\t\t);\n\n\t\t\tstate.yaw = perspective.yaw;\n\t\t\tstate.pitch = perspective.pitch;\n\t\t}\n\n\t\t// 3. Compute velocity-based movement and write to transformStore\n\t\tconst speed = input.sprint ? movement.runSpeed : movement.walkSpeed;\n\t\tstate.currentSpeed = speed;\n\n\t\tconst hasMovement = Math.abs(input.moveX) > 0.1 || Math.abs(input.moveZ) > 0.1;\n\n\t\tif (fpEntity.transformStore) {\n\t\t\tif (hasMovement) {\n\t\t\t\t_forward.set(0, 0, -1).applyAxisAngle(_up, state.yaw);\n\t\t\t\t_right.set(1, 0, 0).applyAxisAngle(_up, state.yaw);\n\n\t\t\t\tconst vx =\n\t\t\t\t\t_right.x * input.moveX * speed +\n\t\t\t\t\t_forward.x * (-input.moveZ) * speed;\n\t\t\t\tconst vz =\n\t\t\t\t\t_right.z * input.moveX * speed +\n\t\t\t\t\t_forward.z * (-input.moveZ) * speed;\n\t\t\t\tsetVelocityIntent(\n\t\t\t\t\tfpEntity.transformStore,\n\t\t\t\t\t'first-person',\n\t\t\t\t\t{ x: vx, z: vz },\n\t\t\t\t\t{ mode: 'replace', priority: 10 },\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tsetVelocityIntent(\n\t\t\t\t\tfpEntity.transformStore,\n\t\t\t\t\t'first-person',\n\t\t\t\t\t{ x: 0, z: 0 },\n\t\t\t\t\t{ mode: 'replace', priority: 10 },\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// 4. Position viewmodel\n\t\tconst vm = this.viewmodels.get(fpEntity.uuid);\n\t\tif (vm && perspective?.initialPosition) {\n\t\t\tthis.positionViewmodel(vm, perspective, state);\n\t\t}\n\t}\n\n\t/**\n\t * Update all first-person entities.\n\t */\n\tupdate(delta: number): void {\n\t\tif (!this.world?.collisionMap) return;\n\t\tfor (const [, entity] of this.world.collisionMap) {\n\t\t\tthis.updateEntity(entity, delta);\n\t\t}\n\t}\n\n\t/**\n\t * Position a viewmodel entity relative to the camera's eye position and rotation.\n\t *\n\t * The physics transform system overwrites group.position from the rigid body\n\t * each frame, so we must also move the body to keep them in sync.\n\t */\n\tprivate positionViewmodel(\n\t\tvm: ViewmodelConfig,\n\t\tperspective: FirstPersonPerspective,\n\t\tstate: FirstPersonStateComponent,\n\t): void {\n\t\tconst eyePos = perspective.initialPosition;\n\t\tif (!eyePos) return;\n\n\t\t// Build camera rotation quaternion\n\t\t_viewmodelQuat.setFromEuler(\n\t\t\t_viewmodelEuler.set(state.pitch, state.yaw, 0, 'YXZ'),\n\t\t);\n\n\t\t// Compose with the viewmodel's local rotation (model orientation fix)\n\t\tif (vm.rotation) {\n\t\t\t_viewmodelLocalQuat.setFromEuler(vm.rotation);\n\t\t\t_viewmodelQuat.multiply(_viewmodelLocalQuat);\n\t\t}\n\n\t\t// Transform the local offset into world space (use camera rotation, not the composed one)\n\t\t_offset.copy(vm.offset).applyQuaternion(_viewmodelQuat);\n\n\t\tconst wx = eyePos.x + _offset.x;\n\t\tconst wy = eyePos.y + _offset.y;\n\t\tconst wz = eyePos.z + _offset.z;\n\n\t\tconst entity = vm.entity;\n\n\t\t// Move the physics body so the transform system stays in sync\n\t\tif (entity?.body) {\n\t\t\tentity.body.setTranslation({ x: wx, y: wy, z: wz }, true);\n\t\t\tentity.body.setRotation(\n\t\t\t\t{ x: _viewmodelQuat.x, y: _viewmodelQuat.y, z: _viewmodelQuat.z, w: _viewmodelQuat.w },\n\t\t\t\ttrue,\n\t\t\t);\n\t\t}\n\n\t\t// Also set the group directly for immediate visual update\n\t\tif (entity?.group) {\n\t\t\tentity.group.position.set(wx, wy, wz);\n\t\t\tentity.group.quaternion.copy(_viewmodelQuat);\n\t\t}\n\t}\n\n\t/** Cleanup */\n\tdestroy(): void {\n\t\tthis.perspectives.clear();\n\t\tthis.viewmodels.clear();\n\t}\n}\n","/**\n * First Person Controller Behavior Descriptor\n *\n * Type-safe descriptor for the first-person controller behavior system.\n * Provides entity.use() API for FPS movement and camera control.\n */\n\nimport { Vector3, Euler } from 'three';\nimport { defineBehavior } from '../behavior-descriptor';\nimport type { BehaviorEntityLink, BehaviorSystem } from '../behavior-system';\nimport type { FirstPersonPerspective } from '../../camera/perspectives/first-person-perspective';\nimport { Vec3Input, VEC3_ZERO, toThreeVector3 } from '../../core/vector';\nimport {\n\tFirstPersonControllerBehavior,\n\ttype FirstPersonEntity,\n\ttype ViewmodelConfig,\n} from './first-person.behavior';\nimport { FirstPersonFSM, FirstPersonState } from './first-person-fsm';\nimport {\n\tcreateFirstPersonMovementComponent,\n\tcreateFirstPersonInputComponent,\n\tcreateFirstPersonStateComponent,\n} from './components';\nimport type { WasmStageRuntime } from '../../runtime/wasm-stage-runtime';\n\n/**\n * First-person controller behavior options (typed for entity.use() autocomplete).\n */\nexport interface FirstPersonControllerOptions {\n\t/** Base walking speed (default: 8) */\n\twalkSpeed?: number;\n\t/** Sprint/run speed (default: 16) */\n\trunSpeed?: number;\n\t/** Look sensitivity multiplier (default: 2) */\n\tlookSensitivity?: number;\n\t/** Eye height offset above entity position (default: 1.7) */\n\teyeHeight?: number;\n\t/** The FirstPersonPerspective to drive (from camera.getPerspective()) */\n\tperspective?: FirstPersonPerspective;\n\t/** Optional viewmodel (weapon/item) to position relative to the camera */\n\tviewmodel?: { entity: any; offset: Vec3Input; rotation?: Euler };\n}\n\nconst defaultOptions: FirstPersonControllerOptions = {\n\twalkSpeed: 8,\n\trunSpeed: 16,\n\tlookSensitivity: 2,\n\teyeHeight: 1.7,\n};\n\nconst FIRST_PERSON_BEHAVIOR_KEY = Symbol.for(\n\t'zylem:behavior:first-person-controller',\n);\n\n/**\n * Adapter that wraps FirstPersonControllerBehavior as a BehaviorSystem.\n */\nclass FirstPersonControllerSystem implements BehaviorSystem {\n\tprivate behavior: FirstPersonControllerBehavior;\n\tprivate attachedRuntimeSlots = new Set<number>();\n\n\tconstructor(\n\t\tprivate world: any,\n\t\tprivate wasmStage: WasmStageRuntime | null,\n\t\tprivate getBehaviorLinks?: (key: symbol) => Iterable<BehaviorEntityLink>,\n\t) {\n\t\tthis.behavior = new FirstPersonControllerBehavior(world);\n\t}\n\n\tupdate(_ecs: unknown, delta: number): void {\n\t\tconst links = this.getBehaviorLinks?.(FIRST_PERSON_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 fpsRef = link.ref as any;\n\n\t\t\tconst options = fpsRef.options as FirstPersonControllerOptions;\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\tconst input = gameEntity.$fps;\n\t\t\t\tif (input) {\n\t\t\t\t\tthis.wasmStage.setFirstPersonInput(handle, {\n\t\t\t\t\t\tmoveX: input.moveX ?? 0,\n\t\t\t\t\t\tmoveZ: input.moveZ ?? 0,\n\t\t\t\t\t\tlookYawDelta: input.lookX ?? 0,\n\t\t\t\t\t\tlookPitchDelta: input.lookY ?? 0,\n\t\t\t\t\t\trun: !!input.sprint,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Initialize components (once)\n\t\t\tif (!gameEntity.firstPerson) {\n\t\t\t\tgameEntity.firstPerson = createFirstPersonMovementComponent(options);\n\t\t\t}\n\n\t\t\tif (!gameEntity.$fps) {\n\t\t\t\tgameEntity.$fps = createFirstPersonInputComponent();\n\t\t\t}\n\n\t\t\tif (!gameEntity.firstPersonState) {\n\t\t\t\tgameEntity.firstPersonState = createFirstPersonStateComponent();\n\t\t\t}\n\n\t\t\t// Wire up perspective (once)\n\t\t\tif (options.perspective && !this.behavior.hasPerspective(gameEntity.uuid)) {\n\t\t\t\tthis.behavior.setPerspective(gameEntity.uuid, options.perspective);\n\t\t\t}\n\n\t\t\t// Wire up viewmodel (once)\n\t\t\tif (options.viewmodel && !this.behavior.hasViewmodel(gameEntity.uuid)) {\n\t\t\t\tthis.behavior.setViewmodel(gameEntity.uuid, {\n\t\t\t\t\t...options.viewmodel,\n\t\t\t\t\toffset: toThreeVector3(options.viewmodel.offset, VEC3_ZERO),\n\t\t\t\t} as ViewmodelConfig);\n\t\t\t}\n\n\t\t\t// Create FSM lazily\n\t\t\tif (!fpsRef.fsm && gameEntity.$fps && gameEntity.firstPersonState) {\n\t\t\t\tfpsRef.fsm = new FirstPersonFSM({\n\t\t\t\t\tinput: gameEntity.$fps,\n\t\t\t\t\tstate: gameEntity.firstPersonState,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Update FSM\n\t\t\tif (fpsRef.fsm && gameEntity.$fps && gameEntity.firstPersonState) {\n\t\t\t\tfpsRef.fsm.update(gameEntity.$fps, gameEntity.firstPersonState);\n\t\t\t}\n\n\t\t\tthis.behavior.updateEntity(gameEntity, delta);\n\t\t}\n\t}\n\n\tprivate ensureWasmAttached(handle: number, options: FirstPersonControllerOptions): void {\n\t\tif (!this.wasmStage || this.attachedRuntimeSlots.has(handle)) return;\n\t\tthis.wasmStage.attachFirstPerson(handle, {\n\t\t\twalkSpeed: options.walkSpeed ?? defaultOptions.walkSpeed!,\n\t\t\trunSpeed: options.runSpeed ?? defaultOptions.runSpeed!,\n\t\t\teyeHeight: options.eyeHeight ?? defaultOptions.eyeHeight!,\n\t\t\tlookSensitivity: options.lookSensitivity ?? defaultOptions.lookSensitivity!,\n\t\t});\n\t\tthis.attachedRuntimeSlots.add(handle);\n\t}\n\n\tdestroy(_ecs: unknown): void {\n\t\tthis.behavior.destroy();\n\t\tthis.attachedRuntimeSlots.clear();\n\t}\n}\n\n/**\n * FirstPersonController - typed descriptor for first-person movement and camera control.\n *\n * Provides complete first-person controller including:\n * - WASD movement relative to camera yaw\n * - Mouse look driving a FirstPersonPerspective\n * - Optional viewmodel positioning (weapon/item following camera)\n * - Walk/run state tracking via FSM\n *\n * @example\n * ```typescript\n * import { FirstPersonController } from \"@zylem/game-lib/behavior\";\n * import { createCamera, Perspectives, FirstPersonPerspective } from \"@zylem/game-lib/core\";\n * import { createActor } from \"@zylem/game-lib/entity\";\n *\n * const fpsCamera = createCamera({ perspective: Perspectives.FirstPerson, ... });\n * const fps = fpsCamera.getPerspective<FirstPersonPerspective>();\n *\n * const player = createActor({ name: 'player', ... });\n * const controller = player.use(FirstPersonController, {\n * perspective: fps,\n * walkSpeed: 8,\n * runSpeed: 16,\n * lookSensitivity: 2,\n * });\n *\n * // In update loop - write input, behavior handles the rest\n * player.onUpdate(({ inputs }) => {\n * player.$fps.moveX = inputs.p1.axes.Horizontal.value;\n * player.$fps.moveZ = inputs.p1.axes.Vertical.value;\n * player.$fps.lookX = inputs.p1.axes.SecondaryHorizontal.value;\n * player.$fps.lookY = inputs.p1.axes.SecondaryVertical.value;\n * player.$fps.sprint = inputs.p1.shoulders.LTrigger.held > 0;\n * });\n * ```\n */\nexport const FirstPersonController = defineBehavior<\n\tFirstPersonControllerOptions,\n\t{\n\t\tgetState: () => FirstPersonState;\n\t\tgetYaw: () => number;\n\t\tgetPitch: () => number;\n\t\tattachViewmodel: (entity: any, offset: Vec3Input) => void;\n\t},\n\tFirstPersonEntity\n>({\n\tname: 'first-person-controller',\n\tdefaultOptions,\n\tsystemFactory: (ctx) =>\n\t\tnew FirstPersonControllerSystem(ctx.world, ctx.wasmStage ?? null, ctx.getBehaviorLinks),\n\tcreateHandle: (ref) => ({\n\t\tgetState: () => ref.fsm?.getState() ?? FirstPersonState.Idle,\n\t\tgetYaw: () => ref.fsm?.getYaw() ?? 0,\n\t\tgetPitch: () => ref.fsm?.getPitch() ?? 0,\n\t\tattachViewmodel: (entity: any, offset: Vec3Input) => {\n\t\t\tif (ref.options) {\n\t\t\t\tref.options.viewmodel = { entity, offset };\n\t\t\t}\n\t\t},\n\t}),\n});\n"],"mappings":"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","names":["FirstPersonState","FirstPersonEvent"]}
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Jumper 3D ECS Components
3
+ *
4
+ * Type definitions and factory functions for the 3D jump behavior system.
5
+ *
6
+ * - JumpConfig3D: tunable parameters (stored as the capability component)
7
+ * - JumpInput3D: per-tick intent written by the player/AI controller
8
+ * - JumpContext3D: per-tick snapshot provided by the system adapter
9
+ * - JumpState3D: internal runtime state owned by the behavior
10
+ */
11
+ interface Vec3Like {
12
+ x: number;
13
+ y: number;
14
+ z: number;
15
+ }
16
+ interface JumpConfig3D {
17
+ /** Desired peak height in world units */
18
+ jumpHeight: number;
19
+ /** Gravity magnitude (positive, e.g. 20) */
20
+ gravity: number;
21
+ /** Terminal fall speed magnitude (optional) */
22
+ maxFallSpeed?: number;
23
+ /** 1 = single jump, 2 = double, etc. */
24
+ maxJumps: number;
25
+ /** Reset jump counter when grounded (usually true) */
26
+ resetJumpsOnGround: boolean;
27
+ /** Reset jump counter on wall contact (future wall-jump support) */
28
+ resetJumpsOnWall?: boolean;
29
+ /** Grace period after leaving ground where first jump is still allowed (ms) */
30
+ coyoteTimeMs: number;
31
+ /** Queue a jump press this many ms before landing (ms) */
32
+ jumpBufferMs: number;
33
+ /** Optional cooldown between consecutive jumps (ms) */
34
+ minTimeBetweenJumpsMs?: number;
35
+ /** Variable jump height via early release */
36
+ variableJump?: {
37
+ enabled: boolean;
38
+ /** Gravity multiplier applied when jump is released early while ascending */
39
+ cutGravityMultiplier: number;
40
+ /** Max hold duration before the cut triggers automatically (ms, optional) */
41
+ maxHoldMs?: number;
42
+ };
43
+ /** Optional planar (XZ) launch / air-control overrides */
44
+ planar?: {
45
+ /** One-time planar speed applied at takeoff */
46
+ launchPlanarSpeed?: number;
47
+ /** If true, preserve current planar speed instead of replacing it */
48
+ preservePlanarSpeed?: boolean;
49
+ airControl?: {
50
+ maxPlanarSpeed: number;
51
+ /** Acceleration per second while airborne */
52
+ acceleration: number;
53
+ /** Deceleration per second when no input */
54
+ deceleration: number;
55
+ };
56
+ };
57
+ /** Snappier descent tuning */
58
+ fall?: {
59
+ /** Gravity multiplier while falling (e.g. 1.5-2.5) */
60
+ fallGravityMultiplier: number;
61
+ /** Additional multiplier when fast-fall input is held */
62
+ fastFallMultiplier?: number;
63
+ };
64
+ }
65
+ declare function createJumpConfig3D(options?: Partial<JumpConfig3D>): JumpConfig3D;
66
+ interface JumpInput3D {
67
+ /** True on the frame the jump button is first pressed (rising edge) */
68
+ jumpPressed: boolean;
69
+ /** True while the jump button is held down */
70
+ jumpHeld: boolean;
71
+ /** True on the frame the jump button is released (falling edge) */
72
+ jumpReleased: boolean;
73
+ /** Desired planar direction in world space (camera-relative), optional */
74
+ moveDirWorld?: Vec3Like;
75
+ /** Hold to drop faster (e.g. crouch / down input) */
76
+ fastFall?: boolean;
77
+ }
78
+ declare function createJumpInput3D(): JumpInput3D;
79
+ interface JumpContext3D {
80
+ /** Frame delta in seconds */
81
+ dt: number;
82
+ /** World up direction (usually 0,1,0) */
83
+ up: Vec3Like;
84
+ /** Current vertical (Y) velocity of the entity */
85
+ velocityY: number;
86
+ /** Current horizontal velocity of the entity (read from body) */
87
+ horizontalVelocity: {
88
+ x: number;
89
+ z: number;
90
+ };
91
+ /** Whether the entity is on the ground */
92
+ isGrounded: boolean;
93
+ /** Surface normal at ground contact (optional) */
94
+ groundNormal?: Vec3Like;
95
+ /** Time since entity was last grounded (ms) */
96
+ timeSinceGroundedMs: number;
97
+ /** Set only the vertical (Y) component of velocity */
98
+ setVerticalVelocity(y: number): void;
99
+ /** Set only the horizontal (X/Z) components of velocity */
100
+ setHorizontalVelocity(x: number, z: number): void;
101
+ }
102
+ interface JumpState3D {
103
+ /** Number of jumps consumed since last reset */
104
+ jumpsUsed: number;
105
+ /** Timestamp (ms) of the most recent jump execution */
106
+ lastJumpTimeMs: number;
107
+ /** Remaining ms in the jump-buffer window (counts down) */
108
+ bufferedJumpMs: number;
109
+ /** Remaining ms in the coyote-time window (counts down) */
110
+ coyoteMs: number;
111
+ /** True while the entity is in a jump arc (ascending phase) */
112
+ isJumping: boolean;
113
+ /** Elapsed ms since jump button was first held (for variable jump) */
114
+ jumpHoldMs: number;
115
+ /** Whether the variable-jump cut has already been applied this jump */
116
+ jumpCutApplied: boolean;
117
+ }
118
+ declare function createJumpState3D(): JumpState3D;
119
+
120
+ export { type JumpConfig3D as J, type Vec3Like as V, type JumpContext3D as a, type JumpInput3D as b, type JumpState3D as c, createJumpConfig3D as d, createJumpInput3D as e, createJumpState3D as f };
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Thruster-specific ECS Components
3
+ *
4
+ * These components are specific to the thruster movement system.
5
+ */
6
+ interface ThrusterMovementComponent {
7
+ /** Linear thrust force in Newtons (or scaled units) */
8
+ linearThrust: number;
9
+ /** Angular thrust torque scalar */
10
+ angularThrust: number;
11
+ /** Optional linear damping override */
12
+ linearDamping?: number;
13
+ /** Optional angular damping override */
14
+ angularDamping?: number;
15
+ }
16
+ declare function createThrusterMovementComponent(linearThrust: number, angularThrust: number, options?: {
17
+ linearDamping?: number;
18
+ angularDamping?: number;
19
+ }): ThrusterMovementComponent;
20
+ interface ThrusterInputComponent {
21
+ /** Forward thrust intent: 0..1 */
22
+ thrust: number;
23
+ /** Rotation intent: -1..1 */
24
+ rotate: number;
25
+ /** World-space X thrust intent: -1..1 */
26
+ thrustX: number;
27
+ /** World-space Y thrust intent: -1..1 */
28
+ thrustY: number;
29
+ }
30
+ declare function createThrusterInputComponent(): ThrusterInputComponent;
31
+ interface ThrusterStateComponent {
32
+ /** Whether the thruster is enabled */
33
+ enabled: boolean;
34
+ /** Current thrust after FSM/gating */
35
+ currentThrust: number;
36
+ }
37
+ declare function createThrusterStateComponent(): ThrusterStateComponent;
38
+
39
+ export { type ThrusterInputComponent as T, type ThrusterMovementComponent as a, type ThrusterStateComponent as b, createThrusterInputComponent as c, createThrusterMovementComponent as d, createThrusterStateComponent as e };
@@ -0,0 +1,20 @@
1
+ import { RigidBody } from '@dimforge/rapier3d-compat';
2
+ import { Vector3, Quaternion } from 'three';
3
+
4
+ /**
5
+ * Core behavior helper types
6
+ *
7
+ * Plain data interfaces shared by movement behaviors and coordinators.
8
+ */
9
+
10
+ interface TransformComponent {
11
+ position: Vector3;
12
+ rotation: Quaternion;
13
+ }
14
+ declare function createTransformComponent(): TransformComponent;
15
+ interface PhysicsBodyComponent {
16
+ body: RigidBody;
17
+ }
18
+ declare function createPhysicsBodyComponent(body: RigidBody): PhysicsBodyComponent;
19
+
20
+ export { type PhysicsBodyComponent as P, type TransformComponent as T, createTransformComponent as a, createPhysicsBodyComponent as c };
@@ -0,0 +1,18 @@
1
+ interface TopDownMovementComponent {
2
+ moveSpeed: number;
3
+ }
4
+ declare function createTopDownMovementComponent(options?: Partial<TopDownMovementComponent>): TopDownMovementComponent;
5
+ interface TopDownMovementInputComponent {
6
+ moveX: number;
7
+ moveY: number;
8
+ faceX: number;
9
+ faceY: number;
10
+ }
11
+ declare function createTopDownMovementInputComponent(): TopDownMovementInputComponent;
12
+ interface TopDownMovementStateComponent {
13
+ facingAngle: number;
14
+ moving: boolean;
15
+ }
16
+ declare function createTopDownMovementStateComponent(): TopDownMovementStateComponent;
17
+
18
+ export { type TopDownMovementComponent as T, type TopDownMovementInputComponent as a, type TopDownMovementStateComponent as b, createTopDownMovementComponent as c, createTopDownMovementInputComponent as d, createTopDownMovementStateComponent as e };
@@ -0,0 +1,43 @@
1
+ /**
2
+ * First Person Controller ECS Components
3
+ *
4
+ * Components for first-person movement and camera control:
5
+ * - Movement configuration (walk/run speed, sensitivity, eye height)
6
+ * - Input intent (WASD movement + mouse look deltas)
7
+ * - Runtime state (yaw, pitch, speed)
8
+ */
9
+ interface FirstPersonMovementComponent {
10
+ /** Base walking speed (units/sec) */
11
+ walkSpeed: number;
12
+ /** Sprint/run speed (units/sec) */
13
+ runSpeed: number;
14
+ /** Look sensitivity multiplier applied to raw input deltas */
15
+ lookSensitivity: number;
16
+ /** Vertical offset above entity position for eye/camera placement */
17
+ eyeHeight: number;
18
+ }
19
+ declare function createFirstPersonMovementComponent(options?: Partial<FirstPersonMovementComponent>): FirstPersonMovementComponent;
20
+ interface FirstPersonInputComponent {
21
+ /** Horizontal movement input (-1 to 1, strafe) */
22
+ moveX: number;
23
+ /** Forward/backward movement input (-1 to 1) */
24
+ moveZ: number;
25
+ /** Horizontal look delta (mouse/stick, raw value before sensitivity) */
26
+ lookX: number;
27
+ /** Vertical look delta (mouse/stick, raw value before sensitivity) */
28
+ lookY: number;
29
+ /** Sprint button held */
30
+ sprint: boolean;
31
+ }
32
+ declare function createFirstPersonInputComponent(): FirstPersonInputComponent;
33
+ interface FirstPersonStateComponent {
34
+ /** Current yaw in radians */
35
+ yaw: number;
36
+ /** Current pitch in radians */
37
+ pitch: number;
38
+ /** Current movement speed being applied */
39
+ currentSpeed: number;
40
+ }
41
+ declare function createFirstPersonStateComponent(): FirstPersonStateComponent;
42
+
43
+ export { type FirstPersonInputComponent as F, type FirstPersonMovementComponent as a, type FirstPersonStateComponent as b, createFirstPersonInputComponent as c, createFirstPersonMovementComponent as d, createFirstPersonStateComponent as e };