@zylem/behaviors 0.4.0 → 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 (146) hide show
  1. package/README.md +13 -1
  2. package/dist/behavior-system-CeJXzNvr.d.ts +868 -0
  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-64HKCSXD.js → chunk-5EBIIYZD.js} +25 -45
  10. package/dist/chunk-5EBIIYZD.js.map +1 -0
  11. package/dist/{chunk-WXXXJ22R.js → chunk-5NJGASUJ.js} +87 -129
  12. package/dist/chunk-5NJGASUJ.js.map +1 -0
  13. package/dist/{chunk-XLUJDKCT.js → chunk-5UMCWV5A.js} +24 -15
  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-HNESASBB.js → chunk-AEBDZWCP.js} +19 -28
  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-PWF757B6.js → chunk-F6ESSHQK.js} +19 -25
  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-V74N7D6Q.js → chunk-KOWGILCN.js} +24 -15
  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 +492 -19
  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 -7
  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 -8
  79. package/dist/jumper-3d.d.ts +5 -39
  80. package/dist/jumper-3d.js +5 -9
  81. package/dist/{moveable-BLTHO7Jq.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 -4
  87. package/dist/platformer-3d.d.ts +13 -78
  88. package/dist/platformer-3d.js +4 -4
  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 +4 -3
  112. package/dist/behavior-system-DSNek0W9.d.ts +0 -483
  113. package/dist/chunk-4URF65BR.js +0 -44
  114. package/dist/chunk-4URF65BR.js.map +0 -1
  115. package/dist/chunk-4V7TIRO2.js +0 -44
  116. package/dist/chunk-4V7TIRO2.js.map +0 -1
  117. package/dist/chunk-5XZWTFGF.js.map +0 -1
  118. package/dist/chunk-64HKCSXD.js.map +0 -1
  119. package/dist/chunk-BXP4K7RF.js.map +0 -1
  120. package/dist/chunk-FRJDQM23.js +0 -506
  121. package/dist/chunk-FRJDQM23.js.map +0 -1
  122. package/dist/chunk-GFARAJV2.js.map +0 -1
  123. package/dist/chunk-GTLA6LOJ.js +0 -400
  124. package/dist/chunk-GTLA6LOJ.js.map +0 -1
  125. package/dist/chunk-HNESASBB.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-MJFMNRMZ.js +0 -240
  129. package/dist/chunk-MJFMNRMZ.js.map +0 -1
  130. package/dist/chunk-OTLSUYQQ.js +0 -29
  131. package/dist/chunk-OTLSUYQQ.js.map +0 -1
  132. package/dist/chunk-PWF757B6.js.map +0 -1
  133. package/dist/chunk-RONH2KDI.js +0 -455
  134. package/dist/chunk-RONH2KDI.js.map +0 -1
  135. package/dist/chunk-RTRFJVCZ.js +0 -454
  136. package/dist/chunk-RTRFJVCZ.js.map +0 -1
  137. package/dist/chunk-UL6Q5HDP.js.map +0 -1
  138. package/dist/chunk-V74N7D6Q.js.map +0 -1
  139. package/dist/chunk-WWVD5DR5.js.map +0 -1
  140. package/dist/chunk-WXXXJ22R.js.map +0 -1
  141. package/dist/chunk-XLUJDKCT.js.map +0 -1
  142. package/dist/components-BWG1GkZA.d.ts +0 -20
  143. package/dist/use-behavior-h9-T5FSv.d.ts +0 -13
  144. /package/dist/{chunk-5SM5SH5O.js.map → chunk-7JLWZXPA.js.map} +0 -0
  145. /package/dist/{chunk-ZA43LPRM.js.map → chunk-KIYUUSPK.js.map} +0 -0
  146. /package/dist/{chunk-XP3ASVGJ.js.map → chunk-NW4SE5XW.js.map} +0 -0
@@ -0,0 +1,868 @@
1
+ import { StageWasmExports } from '@zylem/runtime';
2
+
3
+ /**
4
+ * BehaviorDescriptor
5
+ *
6
+ * Type-safe behavior descriptors that provide options inference.
7
+ * Used with entity.use() to declaratively attach behaviors to entities.
8
+ *
9
+ * Each behavior can define its own handle type via `createHandle`,
10
+ * providing behavior-specific methods with full type safety.
11
+ */
12
+
13
+ /**
14
+ * Base handle returned by entity.use() for lazy access to behavior runtime.
15
+ * FSM is null until entity is spawned and components are initialized.
16
+ */
17
+ interface BaseBehaviorHandle<O extends Record<string, any> = Record<string, any>> {
18
+ /** Get the FSM instance (null until entity is spawned) */
19
+ getFSM(): any | null;
20
+ /** Get the current options */
21
+ getOptions(): O;
22
+ /** Access the underlying behavior ref */
23
+ readonly ref: BehaviorRef<O>;
24
+ }
25
+ /**
26
+ * Reference to a behavior stored on an entity
27
+ */
28
+ interface BehaviorRef<O extends Record<string, any> = Record<string, any>> {
29
+ /** The behavior descriptor */
30
+ descriptor: BehaviorDescriptor<O, any>;
31
+ /** Merged options (defaults + overrides) */
32
+ options: O;
33
+ /** Optional FSM instance - set lazily when entity is spawned */
34
+ fsm?: any;
35
+ }
36
+ /**
37
+ * A typed behavior descriptor that associates a symbol key with:
38
+ * - Default options (providing type inference)
39
+ * - A system factory to create the behavior system
40
+ * - An optional handle factory for behavior-specific methods
41
+ */
42
+ interface BehaviorDescriptor<O extends Record<string, any> = Record<string, any>, H extends Record<string, any> = Record<string, never>, I = unknown> {
43
+ /** Unique symbol identifying this behavior */
44
+ readonly key: symbol;
45
+ /** Default options (used for type inference) */
46
+ readonly defaultOptions: O;
47
+ /** Factory to create the behavior system */
48
+ readonly systemFactory: any;
49
+ /**
50
+ * Optional factory to create behavior-specific handle methods.
51
+ * These methods are merged into the handle returned by entity.use().
52
+ */
53
+ readonly createHandle?: (ref: any) => H;
54
+ }
55
+ /**
56
+ * The full handle type returned by entity.use().
57
+ * Combines base handle with behavior-specific methods.
58
+ */
59
+ type BehaviorHandle<O extends Record<string, any> = Record<string, any>, H extends Record<string, any> = Record<string, never>> = BaseBehaviorHandle<O> & H;
60
+ /**
61
+ * Configuration for defining a new behavior
62
+ */
63
+ interface DefineBehaviorConfig<O extends Record<string, any>, H extends Record<string, any> = Record<string, never>, I = unknown> {
64
+ /** Human-readable name for debugging */
65
+ name: string;
66
+ /** Default options - these define the type */
67
+ defaultOptions: O;
68
+ /** Factory function to create the system */
69
+ systemFactory: BehaviorSystemFactory;
70
+ /**
71
+ * Optional factory to create behavior-specific handle methods.
72
+ * The returned object is merged into the handle returned by entity.use().
73
+ *
74
+ * @example
75
+ * ```typescript
76
+ * createHandle: (ref) => ({
77
+ * getLastHits: () => ref.fsm?.getLastHits() ?? null,
78
+ * getMovement: (moveX, moveY) => ref.fsm?.getMovement(moveX, moveY) ?? { moveX, moveY },
79
+ * }),
80
+ * ```
81
+ */
82
+ createHandle?: (ref: BehaviorRef<O>) => H;
83
+ }
84
+ /**
85
+ * Define a typed behavior descriptor.
86
+ *
87
+ * @example
88
+ * ```typescript
89
+ * export const WorldBoundary2DBehavior = defineBehavior({
90
+ * name: 'world-boundary-2d',
91
+ * defaultOptions: { boundaries: { top: 0, bottom: 0, left: 0, right: 0 } },
92
+ * systemFactory: (ctx) => new WorldBoundary2DSystem(ctx.world),
93
+ * createHandle: (ref) => ({
94
+ * getLastHits: () => ref.fsm?.getLastHits() ?? null,
95
+ * getMovement: (moveX: number, moveY: number) =>
96
+ * ref.fsm?.getMovement(moveX, moveY) ?? { moveX, moveY },
97
+ * }),
98
+ * });
99
+ *
100
+ * // Usage - handle has getLastHits and getMovement with full types
101
+ * const boundary = ship.use(WorldBoundary2DBehavior, { ... });
102
+ * const hits = boundary.getLastHits(); // Fully typed!
103
+ * ```
104
+ */
105
+ declare function defineBehavior<O extends Record<string, any>, H extends Record<string, any> = Record<string, never>, I = unknown>(config: DefineBehaviorConfig<O, H, I>): BehaviorDescriptor<O, H, I>;
106
+
107
+ type VelocityIntentMode = 'replace' | 'add';
108
+ interface VelocityIntent {
109
+ x?: number;
110
+ y?: number;
111
+ z?: number;
112
+ mode: VelocityIntentMode;
113
+ priority?: number;
114
+ }
115
+ /**
116
+ * Transform state managed by Valtio for batched physics updates.
117
+ *
118
+ * This store accumulates transformation intents during the frame,
119
+ * then applies them all at once after onUpdate() callbacks complete.
120
+ *
121
+ * Design decisions:
122
+ * - Position: Accumulated deltas (additive)
123
+ * - Rotation: Last value wins (replacement)
124
+ * - Velocity: Accumulated deltas (additive)
125
+ * - Angular velocity: Accumulated deltas (additive)
126
+ */
127
+ interface TransformState {
128
+ /** Position deltas to be applied (accumulated) */
129
+ position: {
130
+ x: number;
131
+ y: number;
132
+ z: number;
133
+ };
134
+ /** Rotation quaternion (last value wins) */
135
+ rotation: {
136
+ x: number;
137
+ y: number;
138
+ z: number;
139
+ w: number;
140
+ };
141
+ /** Linear velocity (accumulated) */
142
+ velocity: {
143
+ x: number;
144
+ y: number;
145
+ z: number;
146
+ };
147
+ /** Angular velocity (accumulated) */
148
+ angularVelocity: {
149
+ x: number;
150
+ y: number;
151
+ z: number;
152
+ };
153
+ /** Per-source velocity intents composed once per frame */
154
+ velocityChannels: Record<string, VelocityIntent>;
155
+ /** Dirty flags to track what needs to be applied */
156
+ dirty: {
157
+ position: boolean;
158
+ rotation: boolean;
159
+ velocityX: boolean;
160
+ velocityY: boolean;
161
+ velocityZ: boolean;
162
+ velocityChannels: boolean;
163
+ angularVelocity: boolean;
164
+ };
165
+ }
166
+ /**
167
+ * Create a new transform store with optional initial values.
168
+ * The store is a Valtio proxy, making it reactive for debugging/visualization.
169
+ *
170
+ * @param initial Optional initial state values
171
+ * @returns Reactive transform state
172
+ */
173
+ declare function createTransformStore(initial?: Partial<TransformState>): TransformState;
174
+
175
+ /**
176
+ * Minimal, runtime-agnostic entity options contract.
177
+ *
178
+ * The full engine entity (in `@zylem/game-lib`) provides a richer options type,
179
+ * but behaviors only rely on this loose shape.
180
+ */
181
+ interface GameEntityOptions {
182
+ [key: string]: any;
183
+ name?: string;
184
+ }
185
+ /**
186
+ * Structural stand-in for the engine `GameEntity`.
187
+ *
188
+ * Behaviors annotate against this loose contract so that `@zylem/behaviors`
189
+ * (and its `@zylem/behaviors/core` surface) never has to depend on the concrete
190
+ * `@zylem/game-lib` entity implementation. The real engine entity is
191
+ * structurally assignable to this type.
192
+ */
193
+ declare class GameEntity<TOptions = unknown> {
194
+ [key: string]: any;
195
+ uuid: string;
196
+ name: string;
197
+ type: string;
198
+ options?: TOptions & Record<string, unknown>;
199
+ group: any;
200
+ mesh?: any;
201
+ materials?: any[];
202
+ /** Opaque host-owned physics references (never inspected by behaviors). */
203
+ body: unknown | null;
204
+ collider: unknown | null;
205
+ colliderDesc?: any;
206
+ colliderDescs: any[];
207
+ bodyDesc?: any;
208
+ physicsAttached: boolean;
209
+ runtimeHandle?: number;
210
+ transformStore?: TransformState;
211
+ nodeDestroy?: any;
212
+ isInstanced?: boolean;
213
+ private __behaviorRefs;
214
+ create(): this;
215
+ onCleanup(callback: () => void): this;
216
+ setPosition(_x: number, _y: number, _z: number): void;
217
+ setRotation(_x: number, _y: number, _z: number): void;
218
+ setRotationZ(_z: number): void;
219
+ setScale(_x: number, _y: number, _z: number): void;
220
+ /**
221
+ * Attach a behavior to this entity. The real engine entity does substantially
222
+ * more, but this functional stub stores the merged ref and builds the handle
223
+ * so descriptor/handle logic (and tests that drive behaviors directly) work
224
+ * without the full engine.
225
+ */
226
+ use<O extends Record<string, any>, H extends Record<string, any> = Record<string, never>>(descriptor: BehaviorDescriptor<O, H>, options?: Partial<O>): BehaviorHandle<O, H>;
227
+ /** Live behavior refs attached via {@link use}. */
228
+ getBehaviorRefs(): BehaviorRef<any>[];
229
+ }
230
+ /**
231
+ * Factory contract injected into behavior systems via
232
+ * {@link BehaviorSystemContext.createEntity}. The host engine supplies the real
233
+ * entity factory at stage-construction time.
234
+ */
235
+ type CreateEntityFn = (options?: Partial<GameEntityOptions>) => GameEntity<GameEntityOptions>;
236
+
237
+ /**
238
+ * `WasmStageRuntime` — owns one wasm `WebAssembly.Instance` of
239
+ * `@zylem/runtime` and exposes the unified-Stage FFI as typed TypeScript
240
+ * methods. This is the single simulation adapter for the whole framework:
241
+ * behavior systems talk to it through the {@link BehaviorRuntime} contract,
242
+ * and hosts (e.g. `@zylem/game-lib`) drive it through
243
+ * {@link createSimulation} in `./simulation`.
244
+ */
245
+
246
+ /** Sentinel handle for "no entity / failed allocation". Mirrors `INVALID_SLOT` in Rust. */
247
+ declare const STAGE_INVALID_SLOT = 4294967295;
248
+ declare const StageBodyKind: {
249
+ readonly Dynamic: 0;
250
+ readonly Static: 1;
251
+ readonly KinematicPosition: 2;
252
+ readonly KinematicVelocity: 3;
253
+ };
254
+ type StageBodyKindValue = (typeof StageBodyKind)[keyof typeof StageBodyKind];
255
+ declare const StageBoundaryDim: {
256
+ readonly Two: 2;
257
+ readonly Three: 3;
258
+ };
259
+ declare const StageRicochetDim: {
260
+ readonly Two: 2;
261
+ readonly Three: 3;
262
+ };
263
+ declare const StageRicochetReflection: {
264
+ readonly Mirror: 0;
265
+ readonly Angled: 1;
266
+ };
267
+ declare const StageTopDownPlane: {
268
+ readonly Xy: 0;
269
+ readonly Xz: 1;
270
+ };
271
+ declare const StageEventType: {
272
+ readonly CollisionStarted: 1;
273
+ readonly CollisionStopped: 2;
274
+ readonly BoundaryHit: 3;
275
+ readonly Ricochet: 4;
276
+ readonly RegionEntered: 5;
277
+ readonly JumpStarted: 6;
278
+ readonly Landed: 7;
279
+ readonly Wrapped: 8;
280
+ readonly CooldownFired: 9;
281
+ };
282
+ type StageBoundaryDimValue = (typeof StageBoundaryDim)[keyof typeof StageBoundaryDim];
283
+ type StageRicochetDimValue = (typeof StageRicochetDim)[keyof typeof StageRicochetDim];
284
+ type StageRicochetReflectionValue = (typeof StageRicochetReflection)[keyof typeof StageRicochetReflection];
285
+ type StageTopDownPlaneValue = (typeof StageTopDownPlane)[keyof typeof StageTopDownPlane];
286
+ /** Position + rotation snapshot for one runtime slot. */
287
+ interface StagePose {
288
+ position: [number, number, number];
289
+ rotation: [number, number, number, number];
290
+ }
291
+ interface StageWorldBoundaryOptions {
292
+ top: number;
293
+ bottom: number;
294
+ left: number;
295
+ right: number;
296
+ front?: number;
297
+ back?: number;
298
+ padding?: number;
299
+ }
300
+ interface StageScreenWrapOptions {
301
+ width: number;
302
+ height: number;
303
+ centerX?: number;
304
+ centerY?: number;
305
+ edgeThreshold?: number;
306
+ }
307
+ interface StageRicochetOptions {
308
+ minSpeed: number;
309
+ maxSpeed: number;
310
+ speedMultiplier: number;
311
+ maxAngleDeg: number;
312
+ reflectionMode: StageRicochetReflectionValue;
313
+ }
314
+ interface StageThrusterOptions {
315
+ maxSpeed: number;
316
+ acceleration: number;
317
+ turnRateRadPerSec: number;
318
+ linearDamping: number;
319
+ }
320
+ interface StageTopDownOptions {
321
+ plane: StageTopDownPlaneValue;
322
+ speed: number;
323
+ faceMovement?: boolean;
324
+ }
325
+ interface StageShooter2DOptions {
326
+ fireRateHz: number;
327
+ muzzleOffsetX: number;
328
+ muzzleOffsetY: number;
329
+ muzzleSpeed: number;
330
+ }
331
+ interface StageJumper2DOptions {
332
+ jumpForce: number;
333
+ maxJumps: number;
334
+ jumpBufferTime: number;
335
+ coyoteTime: number;
336
+ gravity: number;
337
+ }
338
+ interface StageJumper3DOptions {
339
+ jumpForce: number;
340
+ maxJumps: number;
341
+ gravity: number;
342
+ /** Coyote time in seconds (default 0.1). */
343
+ coyoteTime?: number;
344
+ /** Jump buffer window in seconds (default 0.08). */
345
+ jumpBufferTime?: number;
346
+ }
347
+ interface StagePlatformer3DOptions {
348
+ halfHeight: number;
349
+ radius: number;
350
+ walkSpeed: number;
351
+ runSpeed: number;
352
+ jumpForce: number;
353
+ maxJumps: number;
354
+ gravity: number;
355
+ /** Coyote time in seconds (default 0.1). */
356
+ coyoteTime?: number;
357
+ /** Jump buffer window in seconds (default 0.1). */
358
+ jumpBufferTime?: number;
359
+ /** Velocity multiplier applied on early jump release (default 0.5). */
360
+ jumpCutMultiplier?: number;
361
+ /** Seconds before a multi-jump becomes available (default 0.15). */
362
+ multiJumpWindow?: number;
363
+ /** Max slope angle in degrees the KCC can climb (default 50). */
364
+ slopeClimbAngle?: number;
365
+ /** Slope angle in degrees past which the character slides (default 40). */
366
+ slopeSlideAngle?: number;
367
+ /** Autostep max height in world units; 0 disables (default 0.3). */
368
+ autostepHeight?: number;
369
+ /** Minimum unobstructed width for an autostep (default 0.1). */
370
+ autostepMinWidth?: number;
371
+ /** Snap-to-ground distance in world units; 0 disables (default 0.3). */
372
+ snapToGroundDistance?: number;
373
+ /** KCC collision offset between collider and environment (default 0.05). */
374
+ characterOffset?: number;
375
+ }
376
+ interface StagePlatformer2DOptions {
377
+ halfHeight: number;
378
+ radius: number;
379
+ walkSpeed: number;
380
+ runSpeed: number;
381
+ jumpForce: number;
382
+ maxJumps: number;
383
+ gravity: number;
384
+ /** Coyote time in seconds (default 0.1). */
385
+ coyoteTime?: number;
386
+ /** Jump buffer window in seconds (default 0.1). */
387
+ jumpBufferTime?: number;
388
+ /** Velocity multiplier applied on early jump release (default 0.5). */
389
+ jumpCutMultiplier?: number;
390
+ /** Seconds before a multi-jump becomes available (default 0.15). */
391
+ multiJumpWindow?: number;
392
+ /** Max slope angle in degrees the KCC can climb (default 50). */
393
+ slopeClimbAngle?: number;
394
+ /** Slope angle in degrees past which the character slides (default 40). */
395
+ slopeSlideAngle?: number;
396
+ /** Autostep max height in world units; 0 disables (default 0.25). */
397
+ autostepHeight?: number;
398
+ /** Minimum unobstructed width for an autostep (default 0.05). */
399
+ autostepMinWidth?: number;
400
+ /** Snap-to-ground distance in world units; 0 disables (default 0.2). */
401
+ snapToGroundDistance?: number;
402
+ /** KCC collision offset between collider and environment (default 0.05). */
403
+ characterOffset?: number;
404
+ }
405
+ interface StageFirstPersonOptions {
406
+ walkSpeed: number;
407
+ runSpeed: number;
408
+ eyeHeight: number;
409
+ lookSensitivity: number;
410
+ }
411
+ interface StageFirstPersonInput {
412
+ moveX: number;
413
+ moveZ: number;
414
+ lookYawDelta: number;
415
+ lookPitchDelta: number;
416
+ run: boolean;
417
+ }
418
+ /** Button bits for the batched input buffer's bitmask field. */
419
+ declare const STAGE_INPUT_BUTTON_JUMP = 1;
420
+ declare const STAGE_INPUT_BUTTON_RUN = 2;
421
+ /**
422
+ * Decoded per-slot behavior snapshot written by the runtime after every
423
+ * step: movement fields come from whichever character behavior the entity
424
+ * has (platformer 3D/2D, jumper 3D/2D); first-person fills yaw/pitch.
425
+ * Values reflect the end of the previous `step()` (one-frame read lag).
426
+ */
427
+ interface StageBehaviorSnapshot {
428
+ grounded: boolean;
429
+ fsmState: number;
430
+ jumpCount: number;
431
+ verticalVelocity: number;
432
+ speed: number;
433
+ yaw: number;
434
+ pitch: number;
435
+ }
436
+ /**
437
+ * Wasm fast-path backrefs a behavior system stores on its `BehaviorRef` every
438
+ * frame so descriptor handles can read the runtime snapshot buffer instead of
439
+ * a duplicate TS FSM (or hardcoded defaults).
440
+ */
441
+ interface WasmSnapshotBackref {
442
+ __wasmStage?: BehaviorRuntime | null;
443
+ __entity?: {
444
+ runtimeHandle?: number;
445
+ } | null;
446
+ }
447
+ /**
448
+ * Read the behavior snapshot for the entity a `BehaviorRef` is linked to.
449
+ * Returns `null` off the wasm fast path (no stage runtime / no
450
+ * `runtimeHandle` / no snapshot yet), in which case handles should fall back
451
+ * to their TS FSM.
452
+ */
453
+ declare function readBehaviorSnapshot(ref: object): StageBehaviorSnapshot | null;
454
+ /**
455
+ * Runtime surface behavior systems rely on. `WasmStageRuntime` is the real
456
+ * wasm-backed implementation; `MockBehaviorRuntime` (see
457
+ * `./mock-behavior-runtime`) implements the same contract for unit tests, so
458
+ * descriptors stay runtime-agnostic.
459
+ */
460
+ interface BehaviorRuntime {
461
+ getPose(handle: number, out?: StagePose): StagePose | null;
462
+ setPosition(handle: number, x: number, y: number, z: number): boolean;
463
+ setRotation(handle: number, x: number, y: number, z: number, w: number): boolean;
464
+ writeInputAxes(handle: number, axisA: number, axisB: number): boolean;
465
+ writeInputLook(handle: number, yawDelta: number, pitchDelta: number): boolean;
466
+ /** Write reserved input slots (thruster world-space vector X/Y). */
467
+ writeInputReserved(handle: number, reservedA: number, reservedB: number): boolean;
468
+ writeInputButton(handle: number, buttonMask: number, pressed: boolean): boolean;
469
+ /** Read the per-slot behavior snapshot written at the end of the previous step. */
470
+ readSnapshot(handle: number, out?: StageBehaviorSnapshot): StageBehaviorSnapshot | null;
471
+ attachThruster(handle: number, opts: StageThrusterOptions): boolean;
472
+ setThrusterInput(handle: number, thrust: number, rotate: number, vectorX?: number, vectorY?: number): void;
473
+ attachTopDown(handle: number, opts: StageTopDownOptions): boolean;
474
+ setTopDownInput(handle: number, moveX: number, moveY: number): void;
475
+ attachShooter2D(handle: number, opts: StageShooter2DOptions): boolean;
476
+ attachScreenWrap(handle: number, opts: StageScreenWrapOptions): boolean;
477
+ queryScreenWrap(handle: number): {
478
+ fsm: number;
479
+ lastWrappedAxes: number;
480
+ } | null;
481
+ attachWorldBoundary(handle: number, dim: StageBoundaryDimValue, opts: StageWorldBoundaryOptions): boolean;
482
+ queryWorldBoundary(handle: number): {
483
+ hits: number;
484
+ clamped: [number, number, number];
485
+ } | null;
486
+ attachRicochet(handle: number, dim: StageRicochetDimValue, opts: StageRicochetOptions): boolean;
487
+ attachPlatformer3D(handle: number, opts: StagePlatformer3DOptions): boolean;
488
+ setPlatformer3DInputAxes(handle: number, moveX: number, moveZ: number): void;
489
+ setPlatformer3DInputButtons(handle: number, jump: boolean, run: boolean): void;
490
+ attachPlatformer2D(handle: number, opts: StagePlatformer2DOptions): boolean;
491
+ setPlatformer2DInputAxes(handle: number, moveX: number): void;
492
+ setPlatformer2DInputButtons(handle: number, jump: boolean, run: boolean): void;
493
+ attachFirstPerson(handle: number, opts: StageFirstPersonOptions): boolean;
494
+ setFirstPersonInput(handle: number, input: StageFirstPersonInput): void;
495
+ attachJumper2D(handle: number, opts: StageJumper2DOptions): boolean;
496
+ setJumper2DInput(handle: number, jumpPressed: boolean): void;
497
+ attachJumper3D(handle: number, opts: StageJumper3DOptions): boolean;
498
+ setJumper3DInput(handle: number, jumpPressed: boolean): void;
499
+ }
500
+ /** Default options used when constructing a wasm-backed Stage runtime. */
501
+ interface WasmStageRuntimeOptions {
502
+ initialCapacity?: number;
503
+ gravity?: readonly [number, number, number];
504
+ imports?: WebAssembly.Imports;
505
+ /**
506
+ * Custom wasm source. Defaults to the `zylem_runtime.wasm` bundled with
507
+ * `@zylem/runtime`.
508
+ */
509
+ source?: RequestInfo | URL | ArrayBuffer | Uint8Array;
510
+ }
511
+ type StageEventTypeValue = (typeof StageEventType)[keyof typeof StageEventType];
512
+ /** One decoded event drained from the runtime's per-step event buffer. */
513
+ interface StageEvent {
514
+ type: StageEventTypeValue;
515
+ primarySlot: number | null;
516
+ secondarySlot: number | null;
517
+ payload: [number, number, number];
518
+ }
519
+ /**
520
+ * Decoded view of one entity's slot in the unified render buffer.
521
+ *
522
+ * Mirrors the `STAGE_RENDER_STRIDE` (12-float) packing documented in
523
+ * `runtime/stage/render.rs`:
524
+ * `[0..3]` position, `[3..7]` rotation xyzw, `[7]` uniform scale,
525
+ * `[8..12]` custom0..custom3 (per-behavior shading hints).
526
+ */
527
+ interface StageRenderSlot {
528
+ position: [number, number, number];
529
+ rotation: [number, number, number, number];
530
+ scale: number;
531
+ custom: [number, number, number, number];
532
+ }
533
+ /**
534
+ * Read a single entity slot out of a unified-Stage render buffer view.
535
+ *
536
+ * @param view The `Float32Array` over wasm memory (e.g. `WasmStageRuntime.render`).
537
+ * @param slot The entity's wasm slot id (its `runtimeHandle`).
538
+ * @param out Optional target object to write into (avoids per-call allocation).
539
+ * @returns The decoded slot, or `null` when the slot is out of range.
540
+ */
541
+ declare function readStageRenderSlot(view: Float32Array, slot: number, out?: StageRenderSlot): StageRenderSlot | null;
542
+ interface StageBodyConfig {
543
+ kind: StageBodyKindValue;
544
+ position: readonly [number, number, number];
545
+ rotation: readonly [number, number, number, number];
546
+ linearDamping: number;
547
+ angularDamping: number;
548
+ gravityScale: number;
549
+ canSleep: boolean;
550
+ ccdEnabled: boolean;
551
+ lockRotation: readonly [boolean, boolean, boolean];
552
+ lockTranslation: readonly [boolean, boolean, boolean];
553
+ }
554
+ type StageColliderShape = {
555
+ type: 'box';
556
+ halfExtents: readonly [number, number, number];
557
+ } | {
558
+ type: 'sphere';
559
+ radius: number;
560
+ } | {
561
+ type: 'capsule';
562
+ halfHeight: number;
563
+ radius: number;
564
+ } | {
565
+ type: 'cylinder';
566
+ halfHeight: number;
567
+ radius: number;
568
+ } | {
569
+ type: 'cone';
570
+ halfHeight: number;
571
+ radius: number;
572
+ } | {
573
+ type: 'convexHull';
574
+ vertices: Float32Array;
575
+ } | {
576
+ type: 'trimesh';
577
+ vertices: Float32Array;
578
+ indices: Uint32Array;
579
+ } | {
580
+ type: 'heightfield';
581
+ rows: number;
582
+ cols: number;
583
+ scale: readonly [number, number, number];
584
+ heights: Float32Array;
585
+ };
586
+ interface StageColliderConfig {
587
+ shape: StageColliderShape;
588
+ offset: readonly [number, number, number];
589
+ friction: number;
590
+ restitution: number;
591
+ sensor: boolean;
592
+ /** Packed interaction-groups: high 16 bits = membership, low 16 bits = filter. */
593
+ collisionGroups: number;
594
+ }
595
+ /** Result of a physics raycast against the stage. */
596
+ interface StageRaycastHit {
597
+ slot: number;
598
+ distance: number;
599
+ normal: [number, number, number];
600
+ }
601
+ /** Body introspection payload for debug tooling. */
602
+ interface StageBodyInfo {
603
+ bodyType: number;
604
+ mass: number;
605
+ isSleeping: boolean;
606
+ isEnabled: boolean;
607
+ linearVelocity: [number, number, number];
608
+ }
609
+ /** Line-list wireframe for physics debug rendering. */
610
+ interface StageDebugRender {
611
+ /** `[x, y, z]` per vertex, two vertices per line. */
612
+ vertices: Float32Array;
613
+ /** RGBA per vertex. */
614
+ colors: Float32Array;
615
+ }
616
+ /**
617
+ * Owns the wasm instance plus the live float-views over its render / event /
618
+ * pose / scratch buffers. One instance per logical stage; each stage gets
619
+ * its own `WebAssembly.Instance` so the singleton inside `stage_ffi.rs`
620
+ * stays single-stage scoped (today's `thread_local!` contract).
621
+ */
622
+ declare class WasmStageRuntime implements BehaviorRuntime {
623
+ readonly exports: StageWasmExports;
624
+ private readonly memory;
625
+ private renderView;
626
+ private inputView;
627
+ private snapshotView;
628
+ private eventView;
629
+ private poseView;
630
+ private vec3View;
631
+ private queryView;
632
+ private scratchView;
633
+ constructor(exports: StageWasmExports, options?: WasmStageRuntimeOptions);
634
+ /** Recreate typed views over wasm memory. Call after step() or whenever memory may have grown. */
635
+ refreshViews(): void;
636
+ /** Step the simulation by `dt` seconds. Refreshes views afterwards. */
637
+ step(dt: number): number;
638
+ dispose(): void;
639
+ get tickCount(): number;
640
+ get activeCount(): number;
641
+ setGravity(x: number, y: number, z: number): void;
642
+ createEntity(): number;
643
+ destroyEntity(slot: number): boolean;
644
+ attachBody(slot: number, config: StageBodyConfig): boolean;
645
+ addCollider(slot: number, config: StageColliderConfig): boolean;
646
+ private stageScratch;
647
+ private stageScratchIndices;
648
+ getPose(slot: number, out?: StagePose): StagePose | null;
649
+ setPosition(slot: number, x: number, y: number, z: number): boolean;
650
+ setRotation(slot: number, x: number, y: number, z: number, w: number): boolean;
651
+ setLinearVelocity(slot: number, x: number, y: number, z: number): boolean;
652
+ getLinearVelocity(slot: number, out?: [number, number, number]): [number, number, number] | null;
653
+ setAngularVelocity(slot: number, x: number, y: number, z: number): boolean;
654
+ getAngularVelocity(slot: number, out?: [number, number, number]): [number, number, number] | null;
655
+ applyImpulse(slot: number, x: number, y: number, z: number): boolean;
656
+ /** Cast a ray against the physics world. Returns the closest hit or `null`. */
657
+ castRay(origin: readonly [number, number, number], dir: readonly [number, number, number], maxDistance: number, solidOnly?: boolean): StageRaycastHit | null;
658
+ /** Body introspection for debug tooling. */
659
+ getBodyInfo(slot: number): StageBodyInfo | null;
660
+ /** Wireframe debug render of every collider (all shapes). */
661
+ getDebugRender(): StageDebugRender | null;
662
+ /** Read-only view over the render buffer; one slot occupies {@link STAGE_RENDER_STRIDE} floats. */
663
+ get render(): Float32Array;
664
+ get renderStride(): number;
665
+ /**
666
+ * Decode a single entity slot from the live render buffer. Convenience
667
+ * wrapper over {@link readStageRenderSlot} bound to this runtime's view.
668
+ */
669
+ readRenderSlot(slot: number, out?: StageRenderSlot): StageRenderSlot | null;
670
+ /** Drain the wasm event buffer into a fresh array of typed events. */
671
+ drainEvents(): StageEvent[];
672
+ /** Writable view over the slot-indexed input buffer ({@link STAGE_INPUT_STRIDE} floats/slot). */
673
+ get input(): Float32Array;
674
+ get inputStride(): number;
675
+ /** Read-only view over the per-slot behavior snapshot buffer ({@link STAGE_SNAPSHOT_STRIDE} floats/slot). */
676
+ get snapshot(): Float32Array;
677
+ get snapshotStride(): number;
678
+ /**
679
+ * Write the primary movement axes for a slot into the batched input
680
+ * buffer and mark the slot dirty. Field-scoped (doesn't touch look
681
+ * deltas or buttons) so multiple behaviors composed on one entity can
682
+ * each write their part.
683
+ */
684
+ writeInputAxes(slot: number, axisA: number, axisB: number): boolean;
685
+ /** Write the look deltas (first-person yaw/pitch) for a slot. */
686
+ writeInputLook(slot: number, yawDelta: number, pitchDelta: number): boolean;
687
+ /** Write reserved input slots (thruster world-space vector X/Y). */
688
+ writeInputReserved(slot: number, reservedA: number, reservedB: number): boolean;
689
+ /**
690
+ * Set or clear one button bit ({@link STAGE_INPUT_BUTTON_JUMP} /
691
+ * {@link STAGE_INPUT_BUTTON_RUN}) in a slot's input bitmask.
692
+ */
693
+ writeInputButton(slot: number, buttonMask: number, pressed: boolean): boolean;
694
+ /**
695
+ * Decode a slot's behavior snapshot from the buffer written at the end of
696
+ * the previous step. Returns `null` when the slot has no behavior data.
697
+ */
698
+ readSnapshot(slot: number, out?: StageBehaviorSnapshot): StageBehaviorSnapshot | null;
699
+ get queryScratch(): Float32Array;
700
+ attachCooldown(slot: number): boolean;
701
+ registerCooldown(slot: number, id: number, durationSeconds: number, immediate?: boolean): boolean;
702
+ fireCooldown(slot: number, id: number): boolean;
703
+ resetCooldown(slot: number, id: number): boolean;
704
+ cooldownRemaining(slot: number, id: number): number;
705
+ attachWorldBoundary(slot: number, dim: StageBoundaryDimValue, bounds: StageWorldBoundaryOptions): boolean;
706
+ queryWorldBoundary(slot: number): {
707
+ hits: number;
708
+ clamped: [number, number, number];
709
+ } | null;
710
+ attachScreenWrap(slot: number, opts: StageScreenWrapOptions): boolean;
711
+ queryScreenWrap(slot: number): {
712
+ fsm: number;
713
+ lastWrappedAxes: number;
714
+ } | null;
715
+ attachRicochet(slot: number, dim: StageRicochetDimValue, opts: StageRicochetOptions): boolean;
716
+ queryRicochet(slot: number): {
717
+ bounces: number;
718
+ lastKind: number;
719
+ } | null;
720
+ attachThruster(slot: number, opts: StageThrusterOptions): boolean;
721
+ setThrusterInput(slot: number, thrust: number, turn: number, vectorX?: number, vectorY?: number): void;
722
+ queryThruster(slot: number): {
723
+ headingRad: number;
724
+ speed: number;
725
+ } | null;
726
+ attachTopDown(slot: number, opts: StageTopDownOptions): boolean;
727
+ setTopDownInput(slot: number, axisA: number, axisB: number): void;
728
+ attachJumper2D(slot: number, opts: StageJumper2DOptions): boolean;
729
+ setJumper2DInput(slot: number, jumpPressed: boolean): void;
730
+ queryJumper2D(slot: number): {
731
+ grounded: boolean;
732
+ jumpCount: number;
733
+ coyote: number;
734
+ jumpBuffer: number;
735
+ } | null;
736
+ attachJumper3D(slot: number, opts: StageJumper3DOptions): boolean;
737
+ setJumper3DInput(slot: number, jump: boolean): void;
738
+ queryJumper3D(slot: number): {
739
+ grounded: boolean;
740
+ jumpCount: number;
741
+ verticalVelocity: number;
742
+ } | null;
743
+ attachShooter2D(slot: number, opts: StageShooter2DOptions): boolean;
744
+ fireShooter2D(slot: number, x: number, y: number, z: number, yaw: number): boolean;
745
+ queryShooter2D(slot: number): {
746
+ cooldown: number;
747
+ firedCount: number;
748
+ } | null;
749
+ attachPlatformer3D(slot: number, opts: StagePlatformer3DOptions): boolean;
750
+ setPlatformer3DInputAxes(slot: number, moveX: number, moveZ: number): void;
751
+ setPlatformer3DInputButtons(slot: number, jump: boolean, run: boolean): void;
752
+ queryPlatformer3D(slot: number): {
753
+ grounded: boolean;
754
+ jumpCount: number;
755
+ fsmState: number;
756
+ speed: number;
757
+ } | null;
758
+ attachPlatformer2D(slot: number, opts: StagePlatformer2DOptions): boolean;
759
+ setPlatformer2DInputAxes(slot: number, moveX: number): void;
760
+ setPlatformer2DInputButtons(slot: number, jump: boolean, run: boolean): void;
761
+ queryPlatformer2D(slot: number): {
762
+ grounded: boolean;
763
+ jumpCount: number;
764
+ fsmState: number;
765
+ verticalVelocity: number;
766
+ } | null;
767
+ attachFirstPerson(slot: number, opts: StageFirstPersonOptions): boolean;
768
+ setFirstPersonInput(slot: number, input: StageFirstPersonInput): void;
769
+ queryFirstPerson(slot: number): {
770
+ yaw: number;
771
+ pitch: number;
772
+ speed: number;
773
+ eyeHeight: number;
774
+ } | null;
775
+ }
776
+ /**
777
+ * Load the bundled `@zylem/runtime` wasm (or a custom `source`), instantiate
778
+ * it, and construct a `WasmStageRuntime` around the exports.
779
+ */
780
+ declare function createWasmStageRuntime(options?: WasmStageRuntimeOptions): Promise<WasmStageRuntime>;
781
+
782
+ /**
783
+ * Structural stand-in for the engine world wrapper. The engine's world
784
+ * delegate exposes an entity lookup map; behaviors only rely on this slice.
785
+ *
786
+ * The map value is intentionally `unknown` (not the `GameEntity` stub class):
787
+ * the engine's concrete entity class is a different nominal type, and systems
788
+ * that iterate the map narrow entities themselves.
789
+ */
790
+ interface ZylemWorld {
791
+ collisionMap?: Map<string, unknown>;
792
+ }
793
+
794
+ /**
795
+ * BehaviorSystem Interface
796
+ *
797
+ * Legacy behavior systems reserved the first `update` argument for an ECS world
798
+ * handle; it is always `undefined` now.
799
+ */
800
+ /**
801
+ * A behavior system that processes entities with specific components.
802
+ *
803
+ * @example
804
+ * ```typescript
805
+ * class ThrusterSystem implements BehaviorSystem {
806
+ * update(_ecs: unknown, delta: number): void {
807
+ * // Iterate behavior links, push intent into wasm runtime, etc.
808
+ * }
809
+ * }
810
+ * ```
811
+ */
812
+ interface BehaviorSystem {
813
+ /** Optional eager initialization when a behavior link is registered on a live entity */
814
+ attach?(link: BehaviorEntityLink): void;
815
+ /** Called once per frame. The first argument is always `undefined` (reserved legacy slot). */
816
+ update(ecs: unknown, delta: number): void;
817
+ /** Optional cleanup when a behavior link is detached from a live entity */
818
+ detach?(link: BehaviorEntityLink): void;
819
+ /** Optional cleanup when stage is destroyed */
820
+ destroy?(ecs?: unknown): void;
821
+ }
822
+ /**
823
+ * Runtime link between a spawned entity and one of its behavior refs.
824
+ * Systems can iterate these links to avoid scanning all world entities.
825
+ */
826
+ interface BehaviorEntityLink {
827
+ entity: any;
828
+ ref: any;
829
+ }
830
+ /**
831
+ * Context provided to behavior-system factories.
832
+ *
833
+ * After the runtime-only stage migration, `wasmStage` is the source of
834
+ * truth — descriptors should call `wasmStage.attach<X>(handle, opts)` /
835
+ * `wasmStage.query<X>(handle)` from inside the system instead of touching
836
+ * `entity.body` directly. The legacy `world` / `scene` fields remain for
837
+ * unmigrated descriptors.
838
+ */
839
+ interface BehaviorSystemContext {
840
+ world: ZylemWorld | null;
841
+ /** Host scene wrapper (engine-specific); behaviors only call `add`/`remove`-style methods on it. */
842
+ scene: any;
843
+ /** Wasm-driven Stage runtime; omitted when the stage has no wasm module. */
844
+ wasmStage?: BehaviorRuntime | null;
845
+ /**
846
+ * Returns live behavior links for a descriptor key.
847
+ * O(1) lookup into a pre-built stage index.
848
+ */
849
+ getBehaviorLinks?: (key: symbol) => Iterable<BehaviorEntityLink>;
850
+ /**
851
+ * Host-injected entity factory. Behaviors that spawn entities at runtime
852
+ * (e.g. destructible-3d fragments) use this instead of importing the engine
853
+ * entity factory directly, keeping the behavior layer decoupled.
854
+ */
855
+ createEntity?: CreateEntityFn;
856
+ /**
857
+ * Host-injected accessor for the global game-state bag, passed to entity
858
+ * lifecycle hooks (e.g. `nodeDestroy`).
859
+ */
860
+ getGlobals?: () => any;
861
+ }
862
+ /**
863
+ * Factory function that creates a BehaviorSystem.
864
+ * Receives the stage for access to world, scene, etc.
865
+ */
866
+ type BehaviorSystemFactory<T extends BehaviorSystem = BehaviorSystem> = (stage: BehaviorSystemContext) => T;
867
+
868
+ export { type WasmSnapshotBackref as $, type StageJumper2DOptions as A, type BaseBehaviorHandle as B, type CreateEntityFn as C, type DefineBehaviorConfig as D, type StageJumper3DOptions as E, type StagePlatformer2DOptions as F, GameEntity as G, type StagePlatformer3DOptions as H, type StagePose as I, type StageRaycastHit as J, type StageRenderSlot as K, StageRicochetDim as L, type StageRicochetDimValue as M, type StageRicochetOptions as N, StageRicochetReflection as O, type StageRicochetReflectionValue as P, type StageScreenWrapOptions as Q, type StageShooter2DOptions as R, STAGE_INPUT_BUTTON_JUMP as S, type StageThrusterOptions as T, type StageTopDownOptions as U, StageTopDownPlane as V, type StageTopDownPlaneValue as W, type StageWorldBoundaryOptions as X, type TransformState as Y, type VelocityIntent as Z, type VelocityIntentMode as _, type BehaviorDescriptor as a, WasmStageRuntime as a0, type WasmStageRuntimeOptions as a1, createTransformStore as a2, createWasmStageRuntime as a3, defineBehavior as a4, readBehaviorSnapshot as a5, readStageRenderSlot as a6, type BehaviorEntityLink as b, type BehaviorHandle as c, type BehaviorRef as d, type BehaviorRuntime as e, type BehaviorSystem as f, type BehaviorSystemContext as g, type BehaviorSystemFactory as h, type GameEntityOptions as i, STAGE_INPUT_BUTTON_RUN as j, STAGE_INVALID_SLOT as k, type StageBehaviorSnapshot as l, type StageBodyConfig as m, type StageBodyInfo as n, StageBodyKind as o, type StageBodyKindValue as p, StageBoundaryDim as q, type StageBoundaryDimValue as r, type StageColliderConfig as s, type StageColliderShape as t, type StageDebugRender as u, type StageEvent as v, StageEventType as w, type StageEventTypeValue as x, type StageFirstPersonInput as y, type StageFirstPersonOptions as z };