@zylem/game-lib 0.6.2 → 0.6.4

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 (82) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +9 -16
  3. package/dist/actions.d.ts +30 -21
  4. package/dist/actions.js +793 -146
  5. package/dist/actions.js.map +1 -1
  6. package/dist/behavior/jumper-2d.d.ts +114 -0
  7. package/dist/behavior/jumper-2d.js +711 -0
  8. package/dist/behavior/jumper-2d.js.map +1 -0
  9. package/dist/behavior/platformer-3d.d.ts +296 -0
  10. package/dist/behavior/platformer-3d.js +761 -0
  11. package/dist/behavior/platformer-3d.js.map +1 -0
  12. package/dist/behavior/ricochet-2d.d.ts +275 -0
  13. package/dist/behavior/ricochet-2d.js +425 -0
  14. package/dist/behavior/ricochet-2d.js.map +1 -0
  15. package/dist/behavior/ricochet-3d.d.ts +117 -0
  16. package/dist/behavior/ricochet-3d.js +443 -0
  17. package/dist/behavior/ricochet-3d.js.map +1 -0
  18. package/dist/behavior/screen-visibility.d.ts +79 -0
  19. package/dist/behavior/screen-visibility.js +358 -0
  20. package/dist/behavior/screen-visibility.js.map +1 -0
  21. package/dist/behavior/screen-wrap.d.ts +87 -0
  22. package/dist/behavior/screen-wrap.js +246 -0
  23. package/dist/behavior/screen-wrap.js.map +1 -0
  24. package/dist/behavior/shooter-2d.d.ts +79 -0
  25. package/dist/behavior/shooter-2d.js +180 -0
  26. package/dist/behavior/shooter-2d.js.map +1 -0
  27. package/dist/behavior/thruster.d.ts +11 -0
  28. package/dist/behavior/thruster.js +292 -0
  29. package/dist/behavior/thruster.js.map +1 -0
  30. package/dist/behavior/top-down-movement.d.ts +56 -0
  31. package/dist/behavior/top-down-movement.js +125 -0
  32. package/dist/behavior/top-down-movement.js.map +1 -0
  33. package/dist/behavior/world-boundary-2d.d.ts +142 -0
  34. package/dist/behavior/world-boundary-2d.js +235 -0
  35. package/dist/behavior/world-boundary-2d.js.map +1 -0
  36. package/dist/behavior/world-boundary-3d.d.ts +76 -0
  37. package/dist/behavior/world-boundary-3d.js +274 -0
  38. package/dist/behavior/world-boundary-3d.js.map +1 -0
  39. package/dist/behavior-descriptor-BXnVR8Ki.d.ts +159 -0
  40. package/dist/{blueprints-Cq3Ko6_G.d.ts → blueprints-DmbK2dki.d.ts} +2 -2
  41. package/dist/camera-4XO5gbQH.d.ts +905 -0
  42. package/dist/camera.d.ts +3 -2
  43. package/dist/camera.js +1653 -377
  44. package/dist/camera.js.map +1 -1
  45. package/dist/composition-BASvMKrW.d.ts +218 -0
  46. package/dist/{core-bO8TzV7u.d.ts → core-CARRaS55.d.ts} +110 -69
  47. package/dist/core.d.ts +11 -6
  48. package/dist/core.js +10766 -5626
  49. package/dist/core.js.map +1 -1
  50. package/dist/{entities-DvByhMGU.d.ts → entities-ChFirVL9.d.ts} +133 -29
  51. package/dist/entities.d.ts +5 -3
  52. package/dist/entities.js +4679 -3202
  53. package/dist/entities.js.map +1 -1
  54. package/dist/entity-vj-HTjzU.d.ts +1169 -0
  55. package/dist/global-change-2JvMaz44.d.ts +25 -0
  56. package/dist/main.d.ts +1118 -16
  57. package/dist/main.js +17538 -8499
  58. package/dist/main.js.map +1 -1
  59. package/dist/physics-pose-DCc4oE44.d.ts +25 -0
  60. package/dist/physics-protocol-BDD3P5W2.d.ts +200 -0
  61. package/dist/physics-worker.d.ts +21 -0
  62. package/dist/physics-worker.js +306 -0
  63. package/dist/physics-worker.js.map +1 -0
  64. package/dist/physics.d.ts +205 -0
  65. package/dist/physics.js +577 -0
  66. package/dist/physics.js.map +1 -0
  67. package/dist/stage-types-C19IhuzA.d.ts +731 -0
  68. package/dist/stage.d.ts +11 -7
  69. package/dist/stage.js +8024 -3852
  70. package/dist/stage.js.map +1 -1
  71. package/dist/sync-state-machine-CZyspBpj.d.ts +16 -0
  72. package/dist/thruster-23lzoPZd.d.ts +180 -0
  73. package/dist/world-DfgxoNMt.d.ts +105 -0
  74. package/package.json +53 -13
  75. package/dist/behaviors.d.ts +0 -854
  76. package/dist/behaviors.js +0 -1209
  77. package/dist/behaviors.js.map +0 -1
  78. package/dist/camera-CeJPAgGg.d.ts +0 -116
  79. package/dist/moveable-B_vyA6cw.d.ts +0 -67
  80. package/dist/stage-types-Bd-KtcYT.d.ts +0 -375
  81. package/dist/transformable-CUhvyuYO.d.ts +0 -67
  82. package/dist/world-C8tQ7Plj.d.ts +0 -774
package/dist/main.d.ts CHANGED
@@ -1,24 +1,51 @@
1
- import { G as Game } from './core-bO8TzV7u.js';
2
- export { V as Vect3, Z as ZylemGameConfig, c as createGame, g as gameConfig, a as globalChange, b as globalChanges, d as variableChange, e as variableChanges, v as vessel } from './core-bO8TzV7u.js';
3
- export { a as StageOptions, d as createDisk, c as createStage } from './stage-types-Bd-KtcYT.js';
4
- import { S as StageBlueprint } from './blueprints-Cq3Ko6_G.js';
5
- export { e as entitySpawner } from './blueprints-Cq3Ko6_G.js';
6
- export { P as PerspectiveType, d as Perspectives, c as createCamera } from './camera-CeJPAgGg.js';
7
- export { A as ACTOR_TYPE, B as BOX_TYPE, P as PLANE_TYPE, R as RECT_TYPE, a as SPHERE_TYPE, S as SPRITE_TYPE, T as TEXT_TYPE, g as ZONE_TYPE, e as ZylemBox, o as createActor, j as createBox, m as createPlane, q as createRect, k as createSphere, l as createSprite, p as createText, n as createZone } from './entities-DvByhMGU.js';
8
- import { G as GameEntity, g as GameEntityOptions } from './world-C8tQ7Plj.js';
9
- export { q as BehaviorDescriptor, s as BehaviorHandle, r as BehaviorRef, e as BehaviorSystem, f as BehaviorSystemFactory, t as DefineBehaviorConfig, o as EntityConfigPayload, k as EntityEvents, E as EventEmitterDelegate, j as GameEvents, l as GameLoadingPayload, L as LoadingEvent, a as SetupContext, n as StageConfigPayload, h as StageEvents, m as StateDispatchPayload, b as UpdateContext, i as ZylemEvents, Z as ZylemShaderObject, p as defineBehavior, z as zylemEventBus } from './world-C8tQ7Plj.js';
10
- export { Behavior, BoundaryRicochetCoordinator, MovementSequence2DBehavior, MovementSequence2DCurrentStep, MovementSequence2DEvent, MovementSequence2DFSM, MovementSequence2DHandle, MovementSequence2DMovement, MovementSequence2DOptions, MovementSequence2DProgress, MovementSequence2DState, MovementSequence2DStep, PhysicsBodyComponent, PhysicsStepBehavior, PhysicsSyncBehavior, PlayerInput, Ricochet2DBehavior, Ricochet2DCollisionContext, Ricochet2DEvent, Ricochet2DFSM, Ricochet2DHandle, Ricochet2DOptions, Ricochet2DResult, Ricochet2DState, ScreenWrapBehavior, ScreenWrapEvent, ScreenWrapFSM, ScreenWrapOptions, ScreenWrapState, ThrusterBehavior, ThrusterBehaviorOptions, ThrusterEntity, ThrusterEvent, ThrusterFSM, ThrusterFSMContext, ThrusterInputComponent, ThrusterMovementBehavior, ThrusterMovementComponent, ThrusterState, ThrusterStateComponent, TransformComponent, WorldBoundary2DBehavior, WorldBoundary2DBounds, WorldBoundary2DEvent, WorldBoundary2DFSM, WorldBoundary2DHandle, WorldBoundary2DHit, WorldBoundary2DHits, WorldBoundary2DOptions, WorldBoundary2DPosition, WorldBoundary2DState, computeWorldBoundary2DHits, createPhysicsBodyComponent, createThrusterInputComponent, createThrusterMovementComponent, createThrusterStateComponent, createTransformComponent, hasAnyWorldBoundary2DHit, useBehavior } from './behaviors.js';
11
- export { m as makeMoveable, b as move, a as moveable, r as resetVelocity } from './moveable-B_vyA6cw.js';
12
- export { m as makeRotatable, a as makeTransformable, r as rotatable, b as rotateInDirection } from './transformable-CUhvyuYO.js';
13
- export { Howl } from 'howler';
1
+ import { G as Game, D as DeviceProfile } from './core-CARRaS55.js';
2
+ export { A as AspectRatio, e as AspectRatioValue, a as GameConfigLike, b as GameDeviceConfig, R as ResolutionInput, d as ResolveGameConfigRuntime, i as RetroPreset, j as RetroPresetKey, k as RetroResolution, V as Vect3, c as createGame, g as gameConfig, f as getDisplayAspect, h as getPresetResolution, p as parseResolution, v as vessel } from './core-CARRaS55.js';
3
+ import { G as GameInputConfig } from './stage-types-C19IhuzA.js';
4
+ export { a as StageOptions, Z as ZylemGameConfig, d as createDisk, c as createStage } from './stage-types-C19IhuzA.js';
5
+ import { S as StageBlueprint } from './blueprints-DmbK2dki.js';
6
+ export { e as entitySpawner } from './blueprints-DmbK2dki.js';
7
+ import { b as CameraBehavior, a as CameraWrapper, F as FirstPersonPerspective } from './camera-4XO5gbQH.js';
8
+ export { m as CameraAction, k as CameraContext, C as CameraManager, d as CameraOptions, l as CameraPerspective, o as CameraPipeline, n as CameraPipelineState, h as CameraPose, u as FirstPersonOptions, t as Fixed2DOptions, q as Fixed2DPerspective, v as PerspectiveOptions, P as PerspectiveType, e as Perspectives, j as PoseDelta, f as RendererType, s as ThirdPersonOptions, p as ThirdPersonPerspective, T as TransformLike, V as Viewport, g as ZylemRenderer, c as createCamera, r as createPerspective, i as isWebGPUSupported } from './camera-4XO5gbQH.js';
9
+ import { Vector3, Color, Mesh, Euler, Vector2 } from 'three';
14
10
  import * as three from 'three';
15
11
  export { three as THREE };
12
+ import { S as StageEntity } from './entity-Bq_eNEDI.js';
13
+ export { A as ACTOR_TYPE, B as BOX_TYPE, C as CONE_TYPE, m as CYLINDER_TYPE, o as PILL_TYPE, P as PLANE_TYPE, k as PYRAMID_TYPE, R as RECT_TYPE, a as SPHERE_TYPE, S as SPRITE_TYPE, T as TEXT_TYPE, g as ZONE_TYPE, e as ZylemBox, v as createActor, q as createBox, y as createCone, D as createCylinder, E as createPill, t as createPlane, z as createPyramid, x as createRect, r as createSphere, s as createSprite, w as createText, u as createZone } from './entities-ChFirVL9.js';
14
+ import { I as GameEntity, P as GameEntityOptions, V as Vec3, R as MaterialOptions, W as MoveableEntity, O as BaseNode, X as InputPlayer } from './entity-vj-HTjzU.js';
15
+ export { A as Action, a6 as CollisionComponent, af as EntityConfigPayload, ab as EntityEvents, a7 as EventEmitterDelegate, aa as GameEvents, ac as GameLoadingPayload, N as LoadingEvent, L as SetupContext, ae as StageConfigPayload, Q as StageEvents, ad as StateDispatchPayload, U as UpdateContext, a9 as ZylemEvents, Z as ZylemShader, ag as ZylemShaderObject, ah as ZylemTSLShader, _ as boxCollision, a0 as coneCollision, Y as create, a2 as cylinderCollision, aj as isGLSLShader, ai as isTSLShader, m as move, a3 as pillCollision, a4 as planeCollision, a1 as pyramidCollision, g as resetVelocity, p as rotateInDirection, $ as sphereCollision, a5 as zoneCollision, a8 as zylemEventBus } from './entity-vj-HTjzU.js';
16
+ import { c as BehaviorDescriptor } from './behavior-descriptor-BXnVR8Ki.js';
17
+ export { d as BehaviorHandle, e as BehaviorRef, B as BehaviorSystem, b as BehaviorSystemFactory, D as DefineBehaviorConfig, f as defineBehavior } from './behavior-descriptor-BXnVR8Ki.js';
18
+ import { T as ThrusterInputComponent } from './thruster-23lzoPZd.js';
19
+ export { B as Behavior, P as PhysicsBodyComponent, m as PlayerInput, p as ThrusterBehavior, q as ThrusterBehaviorOptions, o as ThrusterEntity, j as ThrusterEvent, k as ThrusterFSM, l as ThrusterFSMContext, n as ThrusterMovementBehavior, d as ThrusterMovementComponent, i as ThrusterState, e as ThrusterStateComponent, a as TransformComponent, b as createPhysicsBodyComponent, g as createThrusterInputComponent, f as createThrusterMovementComponent, h as createThrusterStateComponent, c as createTransformComponent } from './thruster-23lzoPZd.js';
20
+ import { TopDownMovementInputComponent } from './behavior/top-down-movement.js';
21
+ export { TopDownMovementBehavior, TopDownMovementBehaviorOptions, TopDownMovementComponent, TopDownMovementEntity, TopDownMovementHandle, TopDownMovementRuntimeBehavior, TopDownMovementStateComponent, createTopDownMovementComponent, createTopDownMovementInputComponent, createTopDownMovementStateComponent } from './behavior/top-down-movement.js';
22
+ import { Shooter2DSourceEntity, Shooter2DHandle, Shooter2DStageLike } from './behavior/shooter-2d.js';
23
+ export { Shooter2DBehavior, Shooter2DBehaviorOptions, Shooter2DFireArgs, Shooter2DProjectileFactory, Shooter2DStateComponent, Shooter2DTarget, createShooter2DStateComponent } from './behavior/shooter-2d.js';
24
+ export { ScreenWrapBehavior, ScreenWrapEvent, ScreenWrapFSM, ScreenWrapOptions, ScreenWrapState } from './behavior/screen-wrap.js';
25
+ export { ScreenVisibilityBehavior, ScreenVisibilityChangeContext, ScreenVisibilityFSM, ScreenVisibilityHandle, ScreenVisibilityOptions, ScreenVisibilitySize, ScreenVisibilitySnapshot } from './behavior/screen-visibility.js';
26
+ import { WorldBoundary2DHandle } from './behavior/world-boundary-2d.js';
27
+ export { WorldBoundary2DBehavior, WorldBoundary2DBounds, WorldBoundary2DEvent, WorldBoundary2DFSM, WorldBoundary2DHit, WorldBoundary2DHits, WorldBoundary2DOptions, WorldBoundary2DPosition, WorldBoundary2DState, computeWorldBoundary2DHits, hasAnyWorldBoundary2DHit } from './behavior/world-boundary-2d.js';
28
+ import { WorldBoundary3DHandle } from './behavior/world-boundary-3d.js';
29
+ export { WorldBoundary3DBehavior, WorldBoundary3DBounds, WorldBoundary3DEvent, WorldBoundary3DFSM, WorldBoundary3DHit, WorldBoundary3DHits, WorldBoundary3DOptions, WorldBoundary3DPosition, WorldBoundary3DState, computeWorldBoundary3DHits, hasAnyWorldBoundary3DHit } from './behavior/world-boundary-3d.js';
30
+ import { Ricochet2DHandle } from './behavior/ricochet-2d.js';
31
+ export { Ricochet2DBehavior, Ricochet2DCollisionContext, Ricochet2DEvent, Ricochet2DFSM, Ricochet2DOptions, Ricochet2DResult, Ricochet2DState, RicochetCallback } from './behavior/ricochet-2d.js';
32
+ import { Ricochet3DHandle } from './behavior/ricochet-3d.js';
33
+ export { Ricochet3DBehavior, Ricochet3DCallback, Ricochet3DCollisionContext, Ricochet3DEvent, Ricochet3DFSM, Ricochet3DOptions, Ricochet3DResult, Ricochet3DState } from './behavior/ricochet-3d.js';
34
+ export { Platformer3DBehavior, Platformer3DBehaviorOptions, Platformer3DContext, Platformer3DEntity, Platformer3DEvent, Platformer3DFSM, Platformer3DInputComponent, Platformer3DMovementBehavior, Platformer3DMovementComponent, Platformer3DState, Platformer3DStateComponent, PlatformerCollisionContext, createPlatformer3DInputComponent, createPlatformer3DMovementComponent, createPlatformer3DStateComponent } from './behavior/platformer-3d.js';
35
+ import { S as SyncStateMachine } from './sync-state-machine-CZyspBpj.js';
36
+ export { JumpConfig2D, JumpContext2D, JumpInput2D, JumpState2D, Jumper2D, Jumper2DBehavior, Jumper2DBehaviorOptions, Jumper2DEntity, Jumper2DEvent, Jumper2DFSM, Jumper2DState, Jumper2DTickEvent, Jumper2DTickResult, createJumpConfig2D, createJumpInput2D, createJumpState2D } from './behavior/jumper-2d.js';
37
+ export { c as callFunc, d as delay, m as moveBy, a as moveTo, o as onPress, b as onRelease, p as parallel, e as repeat, f as repeatForever, r as rotateBy, s as sequence, t as throttle } from './composition-BASvMKrW.js';
38
+ export { Howl } from 'howler';
16
39
  import * as RAPIER from '@dimforge/rapier3d-compat';
17
40
  export { RAPIER };
18
- export { S as StageEntity } from './entity-Bq_eNEDI.js';
41
+ export { g as globalChange, a as globalChanges, v as variableChange, b as variableChanges } from './global-change-2JvMaz44.js';
42
+ export { Fn, float, time, uniform, uv, vec3, vec4 } from 'three/tsl';
19
43
  import 'bitecs';
44
+ import './world-DfgxoNMt.js';
20
45
  import './entity-types-DAu8sGJH.js';
46
+ import './physics-pose-DCc4oE44.js';
21
47
  import '@sinclair/typebox';
48
+ import 'three/webgpu';
22
49
  import 'three/examples/jsm/postprocessing/EffectComposer.js';
23
50
  import 'mitt';
24
51
  import 'typescript-fsm';
@@ -39,8 +66,8 @@ declare const StageManager: {
39
66
  data?: {
40
67
  [x: string]: any;
41
68
  } | undefined;
42
- type: string;
43
69
  id: string;
70
+ type: string;
44
71
  }[];
45
72
  }>;
46
73
  registerStaticStage(id: string, blueprint: StageBlueprint): void;
@@ -52,6 +79,75 @@ declare const StageManager: {
52
79
  preloadNext(stageId: string, loadStaticStage?: (id: string) => Promise<StageBlueprint>): Promise<void>;
53
80
  };
54
81
 
82
+ /**
83
+ * Options for the followTarget behavior.
84
+ */
85
+ interface FollowTargetOptions {
86
+ /** Key in CameraContext.targets to follow. Default 'primary'. */
87
+ targetKey?: string;
88
+ /** Position offset from the target. Default (0, 0, 0). */
89
+ offset?: Vector3;
90
+ /**
91
+ * Per-frame interpolation factor (0-1). Controls how quickly the
92
+ * pose converges on the target each frame.
93
+ * 1 = instant snap, lower = smoother follow.
94
+ * Default 0.1.
95
+ */
96
+ lerpFactor?: number;
97
+ }
98
+ /**
99
+ * A simple follow behavior that moves the camera pose toward a target's position + offset.
100
+ *
101
+ * This behavior modifies only the position (and lookAt) of the incoming pose,
102
+ * leaving rotation/fov/zoom to the perspective or other behaviors.
103
+ *
104
+ * @example
105
+ * ```ts
106
+ * camera.addBehavior('follow', createFollowTarget({ targetKey: 'player', offset: new Vector3(0, 3, 8) }));
107
+ * ```
108
+ */
109
+ declare function createFollowTarget(options?: FollowTargetOptions): CameraBehavior;
110
+
111
+ /**
112
+ * Options for setCameraFeed.
113
+ */
114
+ interface CameraFeedOptions {
115
+ /** Render target width in pixels. Only used when the camera does not
116
+ * already have a render target. @default 512 */
117
+ width?: number;
118
+ /** Render target height in pixels. Only used when the camera does not
119
+ * already have a render target. @default 512 */
120
+ height?: number;
121
+ }
122
+ /**
123
+ * Display a camera's live feed on an entity's mesh surface.
124
+ *
125
+ * This is the primary user-facing function for "jumbotron", security-camera,
126
+ * or broadcast-style effects. It ensures the camera has an offscreen render
127
+ * target and replaces the entity's mesh material with one that shows the
128
+ * camera's rendered output.
129
+ *
130
+ * @param entity The entity whose mesh will display the camera feed.
131
+ * @param camera The camera whose view will be rendered to the texture.
132
+ * @param options Optional dimensions for the render target.
133
+ *
134
+ * @example
135
+ * ```ts
136
+ * const feedCam = createCamera({
137
+ * perspective: Perspectives.ThirdPerson,
138
+ * position: new Vector3(0, 30, 60),
139
+ * target: new Vector3(0, 0, 0),
140
+ * renderToTexture: { width: 1024, height: 576 },
141
+ * });
142
+ *
143
+ * const screen = createBox({ size: { x: 16, y: 9, z: 0.2 } });
144
+ * screen.onSetup(({ me }) => {
145
+ * setCameraFeed(me, feedCam);
146
+ * });
147
+ * ```
148
+ */
149
+ declare function setCameraFeed(entity: StageEntity, camera: CameraWrapper, options?: CameraFeedOptions): void;
150
+
55
151
  /**
56
152
  * Factory interface for generating entity copies
57
153
  */
@@ -85,6 +181,942 @@ interface TemplateFactory<E extends GameEntity<O>, O extends GameEntityOptions =
85
181
  */
86
182
  declare function createEntityFactory<E extends GameEntity<O>, O extends GameEntityOptions = GameEntityOptions>(template: E): TemplateFactory<E, O>;
87
183
 
184
+ /** Shared options that every mesh factory accepts. */
185
+ interface BaseMeshOptions {
186
+ /** Offset position relative to the entity origin */
187
+ position?: Vec3;
188
+ /** Material options (texture, shader, etc.) */
189
+ material?: Partial<MaterialOptions>;
190
+ /** Convenience color override */
191
+ color?: Color;
192
+ }
193
+ interface BoxMeshOptions extends BaseMeshOptions {
194
+ /** Box dimensions (default: 1x1x1) */
195
+ size?: Vec3;
196
+ }
197
+ /**
198
+ * Create a box mesh.
199
+ */
200
+ declare function boxMesh(opts?: BoxMeshOptions): Mesh;
201
+ interface SphereMeshOptions extends BaseMeshOptions {
202
+ /** Sphere radius (default: 1) */
203
+ radius?: number;
204
+ }
205
+ /**
206
+ * Create a sphere mesh.
207
+ */
208
+ declare function sphereMesh(opts?: SphereMeshOptions): Mesh;
209
+ interface ConeMeshOptions extends BaseMeshOptions {
210
+ /** Base radius (default: 1) */
211
+ radius?: number;
212
+ /** Height (default: 2) */
213
+ height?: number;
214
+ /** Radial segments (default: 32) */
215
+ radialSegments?: number;
216
+ }
217
+ /**
218
+ * Create a cone mesh.
219
+ */
220
+ declare function coneMesh(opts?: ConeMeshOptions): Mesh;
221
+ interface PyramidMeshOptions extends BaseMeshOptions {
222
+ /** Base radius (default: 1) */
223
+ radius?: number;
224
+ /** Height (default: 2) */
225
+ height?: number;
226
+ }
227
+ /**
228
+ * Create a pyramid mesh (4-sided cone).
229
+ */
230
+ declare function pyramidMesh(opts?: PyramidMeshOptions): Mesh;
231
+ interface CylinderMeshOptions extends BaseMeshOptions {
232
+ /** Top radius (default: 1) */
233
+ radiusTop?: number;
234
+ /** Bottom radius (default: 1) */
235
+ radiusBottom?: number;
236
+ /** Height (default: 2) */
237
+ height?: number;
238
+ /** Radial segments (default: 32) */
239
+ radialSegments?: number;
240
+ }
241
+ /**
242
+ * Create a cylinder mesh.
243
+ */
244
+ declare function cylinderMesh(opts?: CylinderMeshOptions): Mesh;
245
+ interface PillMeshOptions extends BaseMeshOptions {
246
+ /** Capsule hemisphere radius (default: 0.5) */
247
+ radius?: number;
248
+ /** Cylindrical section length (default: 1) */
249
+ length?: number;
250
+ /** Cap segments (default: 10) */
251
+ capSegments?: number;
252
+ /** Radial segments (default: 20) */
253
+ radialSegments?: number;
254
+ }
255
+ /**
256
+ * Create a pill (capsule) mesh.
257
+ */
258
+ declare function pillMesh(opts?: PillMeshOptions): Mesh;
259
+
260
+ /**
261
+ * Type-safe helper to apply a behavior to an entity and return the entity cast to the behavior's interface.
262
+ *
263
+ * @param entity The entity to apply the behavior to
264
+ * @param descriptor The behavior descriptor
265
+ * @param options Behavior options
266
+ * @returns The entity, cast to E & I (where I is the behavior's interface)
267
+ */
268
+ declare function useBehavior<E extends GameEntity<any>, O extends Record<string, any>, H extends Record<string, any>, I>(entity: E, descriptor: BehaviorDescriptor<O, H, I>, options?: Partial<O>): E & I;
269
+
270
+ /**
271
+ * First Person Controller ECS Components
272
+ *
273
+ * Components for first-person movement and camera control:
274
+ * - Movement configuration (walk/run speed, sensitivity, eye height)
275
+ * - Input intent (WASD movement + mouse look deltas)
276
+ * - Runtime state (yaw, pitch, speed)
277
+ */
278
+ interface FirstPersonMovementComponent {
279
+ /** Base walking speed (units/sec) */
280
+ walkSpeed: number;
281
+ /** Sprint/run speed (units/sec) */
282
+ runSpeed: number;
283
+ /** Look sensitivity multiplier applied to raw input deltas */
284
+ lookSensitivity: number;
285
+ /** Vertical offset above entity position for eye/camera placement */
286
+ eyeHeight: number;
287
+ }
288
+ declare function createFirstPersonMovementComponent(options?: Partial<FirstPersonMovementComponent>): FirstPersonMovementComponent;
289
+ interface FirstPersonInputComponent {
290
+ /** Horizontal movement input (-1 to 1, strafe) */
291
+ moveX: number;
292
+ /** Forward/backward movement input (-1 to 1) */
293
+ moveZ: number;
294
+ /** Horizontal look delta (mouse/stick, raw value before sensitivity) */
295
+ lookX: number;
296
+ /** Vertical look delta (mouse/stick, raw value before sensitivity) */
297
+ lookY: number;
298
+ /** Sprint button held */
299
+ sprint: boolean;
300
+ }
301
+ declare function createFirstPersonInputComponent(): FirstPersonInputComponent;
302
+ interface FirstPersonStateComponent {
303
+ /** Current yaw in radians */
304
+ yaw: number;
305
+ /** Current pitch in radians */
306
+ pitch: number;
307
+ /** Current movement speed being applied */
308
+ currentSpeed: number;
309
+ }
310
+ declare function createFirstPersonStateComponent(): FirstPersonStateComponent;
311
+
312
+ /**
313
+ * First Person Controller Finite State Machine
314
+ *
315
+ * Manages state transitions for first-person movement:
316
+ * - Idle: Standing still
317
+ * - Walking: Moving at walk speed
318
+ * - Running: Moving at run/sprint speed
319
+ */
320
+
321
+ /**
322
+ * First-person movement states
323
+ */
324
+ declare enum FirstPersonState {
325
+ Idle = "idle",
326
+ Walking = "walking",
327
+ Running = "running"
328
+ }
329
+ /**
330
+ * Events that trigger state transitions
331
+ */
332
+ declare enum FirstPersonEvent {
333
+ Walk = "walk",
334
+ Run = "run",
335
+ Stop = "stop"
336
+ }
337
+ /**
338
+ * Context for the FSM
339
+ */
340
+ interface FirstPersonContext {
341
+ input: FirstPersonInputComponent;
342
+ state: FirstPersonStateComponent;
343
+ }
344
+ /**
345
+ * First Person Controller FSM
346
+ */
347
+ declare class FirstPersonFSM {
348
+ private ctx;
349
+ machine: SyncStateMachine<FirstPersonState, FirstPersonEvent, never>;
350
+ constructor(ctx: FirstPersonContext);
351
+ /** Get the current state */
352
+ getState(): FirstPersonState;
353
+ /** Dispatch an event to the FSM */
354
+ dispatch(event: FirstPersonEvent): void;
355
+ /** Get the current yaw from context */
356
+ getYaw(): number;
357
+ /** Get the current pitch from context */
358
+ getPitch(): number;
359
+ /**
360
+ * Update FSM based on current input and state.
361
+ */
362
+ update(input: FirstPersonInputComponent, state: FirstPersonStateComponent): void;
363
+ }
364
+
365
+ /**
366
+ * First Person Controller Behavior System
367
+ *
368
+ * Handles first-person camera control and movement:
369
+ * - Reads input component for WASD movement and mouse look deltas
370
+ * - Drives a FirstPersonPerspective (yaw/pitch accumulation)
371
+ * - Writes velocity to transformStore (physics-based movement)
372
+ * - Syncs camera position from the entity's rigid body each frame
373
+ * - Positions an optional viewmodel entity relative to the camera
374
+ */
375
+
376
+ /**
377
+ * Viewmodel configuration for an entity that follows the camera.
378
+ */
379
+ interface ViewmodelConfig {
380
+ /** The entity whose visual group should be positioned relative to the camera. */
381
+ entity: any;
382
+ /** Offset from the eye position in camera-local space (right, down, forward). */
383
+ offset: Vector3;
384
+ /** Additional rotation applied to the viewmodel in local space (Euler angles in radians). */
385
+ rotation?: Euler;
386
+ }
387
+ /**
388
+ * Entity interface for first-person controller.
389
+ * Entities with this behavior have these components attached.
390
+ */
391
+ interface FirstPersonEntity {
392
+ uuid: string;
393
+ body: any;
394
+ transformStore: any;
395
+ firstPerson: FirstPersonMovementComponent;
396
+ $fps: FirstPersonInputComponent;
397
+ firstPersonState: FirstPersonStateComponent;
398
+ }
399
+ /**
400
+ * First Person Controller Behavior
401
+ *
402
+ * Core movement + look system for first-person cameras.
403
+ * Reads from entity.$fps input component and drives a FirstPersonPerspective.
404
+ */
405
+ declare class FirstPersonControllerBehavior {
406
+ private world;
407
+ private perspectives;
408
+ private viewmodels;
409
+ constructor(world: any);
410
+ /**
411
+ * Associate a FirstPersonPerspective with an entity (by uuid).
412
+ * Called once by the descriptor system when the behavior is initialized.
413
+ */
414
+ setPerspective(entityUuid: string, perspective: FirstPersonPerspective): void;
415
+ hasPerspective(entityUuid: string): boolean;
416
+ /**
417
+ * Attach a viewmodel (weapon/item) to an entity.
418
+ * The viewmodel entity's group will be positioned relative to the camera each frame.
419
+ */
420
+ setViewmodel(entityUuid: string, config: ViewmodelConfig): void;
421
+ hasViewmodel(entityUuid: string): boolean;
422
+ /**
423
+ * Update one first-person entity.
424
+ */
425
+ updateEntity(entity: any, _delta: number): void;
426
+ /**
427
+ * Update all first-person entities.
428
+ */
429
+ update(delta: number): void;
430
+ /**
431
+ * Position a viewmodel entity relative to the camera's eye position and rotation.
432
+ *
433
+ * The physics transform system overwrites group.position from the rigid body
434
+ * each frame, so we must also move the body to keep them in sync.
435
+ */
436
+ private positionViewmodel;
437
+ /** Cleanup */
438
+ destroy(): void;
439
+ }
440
+
441
+ /**
442
+ * First-person controller behavior options (typed for entity.use() autocomplete).
443
+ */
444
+ interface FirstPersonControllerOptions {
445
+ /** Base walking speed (default: 8) */
446
+ walkSpeed?: number;
447
+ /** Sprint/run speed (default: 16) */
448
+ runSpeed?: number;
449
+ /** Look sensitivity multiplier (default: 2) */
450
+ lookSensitivity?: number;
451
+ /** Eye height offset above entity position (default: 1.7) */
452
+ eyeHeight?: number;
453
+ /** The FirstPersonPerspective to drive (from camera.getPerspective()) */
454
+ perspective?: FirstPersonPerspective;
455
+ /** Optional viewmodel (weapon/item) to position relative to the camera */
456
+ viewmodel?: {
457
+ entity: any;
458
+ offset: Vector3;
459
+ rotation?: Euler;
460
+ };
461
+ }
462
+ /**
463
+ * FirstPersonController - typed descriptor for first-person movement and camera control.
464
+ *
465
+ * Provides complete first-person controller including:
466
+ * - WASD movement relative to camera yaw
467
+ * - Mouse look driving a FirstPersonPerspective
468
+ * - Optional viewmodel positioning (weapon/item following camera)
469
+ * - Walk/run state tracking via FSM
470
+ *
471
+ * @example
472
+ * ```typescript
473
+ * import { FirstPersonController, FirstPersonPerspective, createActor, createCamera, Perspectives } from "@zylem/game-lib";
474
+ *
475
+ * const fpsCamera = createCamera({ perspective: Perspectives.FirstPerson, ... });
476
+ * const fps = fpsCamera.getPerspective<FirstPersonPerspective>();
477
+ *
478
+ * const player = createActor({ name: 'player', ... });
479
+ * const controller = player.use(FirstPersonController, {
480
+ * perspective: fps,
481
+ * walkSpeed: 8,
482
+ * runSpeed: 16,
483
+ * lookSensitivity: 2,
484
+ * });
485
+ *
486
+ * // In update loop - write input, behavior handles the rest
487
+ * player.onUpdate(({ inputs }) => {
488
+ * player.$fps.moveX = inputs.p1.axes.Horizontal.value;
489
+ * player.$fps.moveZ = inputs.p1.axes.Vertical.value;
490
+ * player.$fps.lookX = inputs.p1.axes.SecondaryHorizontal.value;
491
+ * player.$fps.lookY = inputs.p1.axes.SecondaryVertical.value;
492
+ * player.$fps.sprint = inputs.p1.shoulders.LTrigger.held > 0;
493
+ * });
494
+ * ```
495
+ */
496
+ declare const FirstPersonController: BehaviorDescriptor<FirstPersonControllerOptions, {
497
+ getState: () => FirstPersonState;
498
+ getYaw: () => number;
499
+ getPitch: () => number;
500
+ attachViewmodel: (entity: any, offset: Vector3) => void;
501
+ }, FirstPersonEntity>;
502
+
503
+ /**
504
+ * Jumper 3D ECS Components
505
+ *
506
+ * Type definitions and factory functions for the 3D jump behavior system.
507
+ *
508
+ * - JumpConfig3D: tunable parameters (stored as the capability component)
509
+ * - JumpInput3D: per-tick intent written by the player/AI controller
510
+ * - JumpContext3D: per-tick snapshot provided by the system adapter
511
+ * - JumpState3D: internal runtime state owned by the behavior
512
+ */
513
+ interface Vec3Like {
514
+ x: number;
515
+ y: number;
516
+ z: number;
517
+ }
518
+ interface JumpConfig3D {
519
+ /** Desired peak height in world units */
520
+ jumpHeight: number;
521
+ /** Gravity magnitude (positive, e.g. 20) */
522
+ gravity: number;
523
+ /** Terminal fall speed magnitude (optional) */
524
+ maxFallSpeed?: number;
525
+ /** 1 = single jump, 2 = double, etc. */
526
+ maxJumps: number;
527
+ /** Reset jump counter when grounded (usually true) */
528
+ resetJumpsOnGround: boolean;
529
+ /** Reset jump counter on wall contact (future wall-jump support) */
530
+ resetJumpsOnWall?: boolean;
531
+ /** Grace period after leaving ground where first jump is still allowed (ms) */
532
+ coyoteTimeMs: number;
533
+ /** Queue a jump press this many ms before landing (ms) */
534
+ jumpBufferMs: number;
535
+ /** Optional cooldown between consecutive jumps (ms) */
536
+ minTimeBetweenJumpsMs?: number;
537
+ /** Variable jump height via early release */
538
+ variableJump?: {
539
+ enabled: boolean;
540
+ /** Gravity multiplier applied when jump is released early while ascending */
541
+ cutGravityMultiplier: number;
542
+ /** Max hold duration before the cut triggers automatically (ms, optional) */
543
+ maxHoldMs?: number;
544
+ };
545
+ /** Optional planar (XZ) launch / air-control overrides */
546
+ planar?: {
547
+ /** One-time planar speed applied at takeoff */
548
+ launchPlanarSpeed?: number;
549
+ /** If true, preserve current planar speed instead of replacing it */
550
+ preservePlanarSpeed?: boolean;
551
+ airControl?: {
552
+ maxPlanarSpeed: number;
553
+ /** Acceleration per second while airborne */
554
+ acceleration: number;
555
+ /** Deceleration per second when no input */
556
+ deceleration: number;
557
+ };
558
+ };
559
+ /** Snappier descent tuning */
560
+ fall?: {
561
+ /** Gravity multiplier while falling (e.g. 1.5-2.5) */
562
+ fallGravityMultiplier: number;
563
+ /** Additional multiplier when fast-fall input is held */
564
+ fastFallMultiplier?: number;
565
+ };
566
+ }
567
+ declare function createJumpConfig3D(options?: Partial<JumpConfig3D>): JumpConfig3D;
568
+ interface JumpInput3D {
569
+ /** True on the frame the jump button is first pressed (rising edge) */
570
+ jumpPressed: boolean;
571
+ /** True while the jump button is held down */
572
+ jumpHeld: boolean;
573
+ /** True on the frame the jump button is released (falling edge) */
574
+ jumpReleased: boolean;
575
+ /** Desired planar direction in world space (camera-relative), optional */
576
+ moveDirWorld?: Vec3Like;
577
+ /** Hold to drop faster (e.g. crouch / down input) */
578
+ fastFall?: boolean;
579
+ }
580
+ declare function createJumpInput3D(): JumpInput3D;
581
+ interface JumpContext3D {
582
+ /** Frame delta in seconds */
583
+ dt: number;
584
+ /** World up direction (usually 0,1,0) */
585
+ up: Vec3Like;
586
+ /** Current vertical (Y) velocity of the entity */
587
+ velocityY: number;
588
+ /** Current horizontal velocity of the entity (read from body) */
589
+ horizontalVelocity: {
590
+ x: number;
591
+ z: number;
592
+ };
593
+ /** Whether the entity is on the ground */
594
+ isGrounded: boolean;
595
+ /** Surface normal at ground contact (optional) */
596
+ groundNormal?: Vec3Like;
597
+ /** Time since entity was last grounded (ms) */
598
+ timeSinceGroundedMs: number;
599
+ /** Set only the vertical (Y) component of velocity */
600
+ setVerticalVelocity(y: number): void;
601
+ /** Set only the horizontal (X/Z) components of velocity */
602
+ setHorizontalVelocity(x: number, z: number): void;
603
+ }
604
+ interface JumpState3D {
605
+ /** Number of jumps consumed since last reset */
606
+ jumpsUsed: number;
607
+ /** Timestamp (ms) of the most recent jump execution */
608
+ lastJumpTimeMs: number;
609
+ /** Remaining ms in the jump-buffer window (counts down) */
610
+ bufferedJumpMs: number;
611
+ /** Remaining ms in the coyote-time window (counts down) */
612
+ coyoteMs: number;
613
+ /** True while the entity is in a jump arc (ascending phase) */
614
+ isJumping: boolean;
615
+ /** Elapsed ms since jump button was first held (for variable jump) */
616
+ jumpHoldMs: number;
617
+ /** Whether the variable-jump cut has already been applied this jump */
618
+ jumpCutApplied: boolean;
619
+ }
620
+ declare function createJumpState3D(): JumpState3D;
621
+
622
+ /**
623
+ * Jumper 3D Behavior — Pure Jump Physics
624
+ *
625
+ * A stateless tick function that receives configuration, input, context, and
626
+ * state, then applies jump physics through the context's velocity helpers.
627
+ *
628
+ * Vertical velocity (Y) is owned exclusively by this behavior.
629
+ * Horizontal velocity (X/Z) is only touched when airborne planar control
630
+ * is configured; otherwise the movement controller owns X/Z.
631
+ */
632
+
633
+ declare class Jumper3DBehavior {
634
+ /**
635
+ * Advance the jump system by one frame.
636
+ *
637
+ * Call order within a frame:
638
+ * 1. Movement controller writes X/Z via transformStore.dirty.velocityX/Z.
639
+ * 2. `tick()` writes Y via ctx.setVerticalVelocity().
640
+ * (Optionally writes X/Z when airborne planar control is active.)
641
+ */
642
+ tick(config: JumpConfig3D, input: JumpInput3D, ctx: JumpContext3D, state: JumpState3D): JumperTickResult;
643
+ }
644
+ /** Events emitted by a single tick (used by FSM). */
645
+ declare enum JumperTickEvent {
646
+ None = "none",
647
+ Jump = "jump",
648
+ Fall = "fall",
649
+ Land = "land"
650
+ }
651
+ interface JumperTickResult {
652
+ event: JumperTickEvent;
653
+ }
654
+
655
+ /**
656
+ * Jumper 3D Finite State Machine
657
+ *
658
+ * Three high-level states driven by events emitted from the behavior tick:
659
+ * Grounded ──Jump──▶ Jumping
660
+ * Grounded ──Fall──▶ Falling (walked off a ledge)
661
+ * Jumping ──Fall──▶ Falling (apex / descending)
662
+ * Jumping ──Jump──▶ Jumping (multi-jump)
663
+ * Jumping ──Land──▶ Grounded (rare — very short hop)
664
+ * Falling ──Land──▶ Grounded
665
+ * Falling ──Jump──▶ Jumping (air-jump while falling)
666
+ */
667
+
668
+ declare enum Jumper3DState {
669
+ Grounded = "grounded",
670
+ Jumping = "jumping",
671
+ Falling = "falling"
672
+ }
673
+ declare enum Jumper3DEvent {
674
+ Jump = "jump",
675
+ Fall = "fall",
676
+ Land = "land"
677
+ }
678
+ interface Jumper3DFSMContext {
679
+ state: JumpState3D;
680
+ }
681
+ declare class Jumper3DFSM {
682
+ private ctx;
683
+ machine: SyncStateMachine<Jumper3DState, Jumper3DEvent, never>;
684
+ constructor(ctx: Jumper3DFSMContext);
685
+ getState(): Jumper3DState;
686
+ dispatch(event: Jumper3DEvent): void;
687
+ isJumping(): boolean;
688
+ isFalling(): boolean;
689
+ isGrounded(): boolean;
690
+ getJumpsUsed(): number;
691
+ /**
692
+ * Translate a tick event into an FSM dispatch.
693
+ * Also handles the implicit Grounded→Falling transition when the entity
694
+ * is no longer grounded but no explicit event was emitted (e.g. walked
695
+ * off a ledge without jumping).
696
+ */
697
+ applyTickEvent(tickEvent: string, isGrounded: boolean): void;
698
+ }
699
+
700
+ interface Jumper3DBehaviorOptions {
701
+ /** Desired peak height in world units (default: 2.5) */
702
+ jumpHeight?: number;
703
+ /** Gravity magnitude applied by the behavior (default: 20) */
704
+ gravity?: number;
705
+ /** Terminal fall speed (optional) */
706
+ maxFallSpeed?: number;
707
+ /** Max concurrent jumps, 1 = single, 2 = double, etc. (default: 1) */
708
+ maxJumps?: number;
709
+ /** Reset jump counter on ground (default: true) */
710
+ resetJumpsOnGround?: boolean;
711
+ /** Reset jump counter on wall contact (default: undefined) */
712
+ resetJumpsOnWall?: boolean;
713
+ /** Coyote time in ms (default: 100) */
714
+ coyoteTimeMs?: number;
715
+ /** Jump buffer in ms (default: 80) */
716
+ jumpBufferMs?: number;
717
+ /** Min cooldown between jumps in ms (optional) */
718
+ minTimeBetweenJumpsMs?: number;
719
+ /** Variable jump height config (optional) */
720
+ variableJump?: JumpConfig3D['variableJump'];
721
+ /** Planar control config (optional) */
722
+ planar?: JumpConfig3D['planar'];
723
+ /** Fall tuning (optional) */
724
+ fall?: JumpConfig3D['fall'];
725
+ /** Ground-detection ray length (default: 1.0) */
726
+ groundRayLength?: number;
727
+ /** Max support distance that counts as grounded and can snap to ground */
728
+ snapToGroundDistance?: number;
729
+ /** Enable debug visualization for ground probe rays (default: false) */
730
+ debugGroundProbe?: boolean;
731
+ }
732
+ interface Jumper3DEntity {
733
+ uuid: string;
734
+ body: any;
735
+ transformStore: any;
736
+ jumper: JumpConfig3D;
737
+ $jumper: JumpInput3D;
738
+ jumperState: JumpState3D;
739
+ }
740
+ /**
741
+ * Jumper3D — composable 3D jump behavior.
742
+ *
743
+ * Provides height-based jumping, multi-jump, coyote time, jump buffering,
744
+ * variable jump height, configurable fall gravity, and optional air control.
745
+ *
746
+ * Designed to compose with any movement controller (e.g. FirstPersonController)
747
+ * — the controller writes X/Z velocity and Jumper3D writes Y velocity.
748
+ *
749
+ * @example
750
+ * ```typescript
751
+ * import { Jumper3D } from "@zylem/game-lib";
752
+ *
753
+ * const jumper = player.use(Jumper3D, {
754
+ * jumpHeight: 2.5,
755
+ * gravity: 20,
756
+ * maxJumps: 2,
757
+ * coyoteTimeMs: 100,
758
+ * jumpBufferMs: 80,
759
+ * variableJump: { enabled: true, cutGravityMultiplier: 3 },
760
+ * fall: { fallGravityMultiplier: 1.5 },
761
+ * });
762
+ *
763
+ * player.onUpdate(({ inputs }) => {
764
+ * player.$jumper.jumpPressed = inputs.p1.buttons.A.pressed;
765
+ * player.$jumper.jumpHeld = inputs.p1.buttons.A.held > 0;
766
+ * player.$jumper.jumpReleased = inputs.p1.buttons.A.released;
767
+ *
768
+ * const state = jumper.getState(); // Grounded | Jumping | Falling
769
+ * });
770
+ * ```
771
+ */
772
+ declare const Jumper3D: BehaviorDescriptor<Jumper3DBehaviorOptions, {
773
+ getState: () => Jumper3DState;
774
+ isJumping: () => boolean;
775
+ getJumpsUsed: () => number;
776
+ getJumpsRemaining: () => number;
777
+ }, Jumper3DEntity>;
778
+
779
+ /**
780
+ * CooldownBehavior
781
+ *
782
+ * A stage-scoped behavior that manages named cooldowns via the global CooldownStore.
783
+ * Entities use this to register, check, and fire cooldowns.
784
+ * UI components (CooldownIcon) can read from the same store.
785
+ */
786
+ interface CooldownConfig {
787
+ /** Duration in seconds */
788
+ duration: number;
789
+ /** Whether the cooldown starts ready (default: true) */
790
+ immediate?: boolean;
791
+ }
792
+ interface CooldownOptions {
793
+ /**
794
+ * Named cooldowns to register.
795
+ * Keys are the cooldown names, values are their config.
796
+ */
797
+ cooldowns: Record<string, CooldownConfig>;
798
+ }
799
+ /**
800
+ * Handle methods returned by entity.use(CooldownBehavior, ...).
801
+ */
802
+ interface CooldownHandle {
803
+ /** Check if a named cooldown is ready */
804
+ isReady(name: string): boolean;
805
+ /** Fire (trigger) a named cooldown, resetting its timer */
806
+ fire(name: string): void;
807
+ /** Force a cooldown to ready immediately */
808
+ reset(name: string): void;
809
+ /** Get cooldown progress 0..1 (0 = just fired, 1 = ready) */
810
+ getProgress(name: string): number;
811
+ }
812
+ /**
813
+ * CooldownBehavior
814
+ *
815
+ * @example
816
+ * ```ts
817
+ * import { CooldownBehavior, moveBy } from '@zylem/game-lib';
818
+ *
819
+ * const hero = createBox({ ... });
820
+ * const cd = hero.use(CooldownBehavior, {
821
+ * cooldowns: {
822
+ * attack: { duration: 5 },
823
+ * dash: { duration: 2, immediate: false },
824
+ * },
825
+ * });
826
+ *
827
+ * hero.onUpdate(({ me, inputs }) => {
828
+ * if (cd.isReady('attack') && inputs.p1.buttons.A.pressed) {
829
+ * cd.fire('attack');
830
+ * // perform attack
831
+ * }
832
+ * if (cd.isReady('dash') && inputs.p1.buttons.B.pressed) {
833
+ * cd.fire('dash');
834
+ * me.runAction(moveBy({ x: 10, duration: 0.3 }));
835
+ * }
836
+ * });
837
+ * ```
838
+ */
839
+ declare const CooldownBehavior: BehaviorDescriptor<CooldownOptions, CooldownHandle, unknown>;
840
+
841
+ /**
842
+ * A single cooldown entry in the global store.
843
+ */
844
+ interface CooldownEntry {
845
+ /** Identifier for this cooldown */
846
+ name: string;
847
+ /** Total cooldown time in seconds */
848
+ duration: number;
849
+ /** Time accumulated since last fire */
850
+ elapsed: number;
851
+ /** Whether the cooldown is ready (elapsed >= duration) */
852
+ ready: boolean;
853
+ /** Normalized progress 0..1 (0 = just fired, 1 = ready) */
854
+ progress: number;
855
+ /** Whether this cooldown is currently counting down */
856
+ active: boolean;
857
+ }
858
+ /**
859
+ * Register a named cooldown in the global store.
860
+ * If a cooldown with the same name already exists, it is overwritten.
861
+ *
862
+ * @param name Unique cooldown identifier
863
+ * @param duration Cooldown duration in seconds
864
+ * @param immediate If true, the cooldown starts ready (default: true)
865
+ */
866
+ declare function registerCooldown(name: string, duration: number, immediate?: boolean): void;
867
+ /**
868
+ * Get a cooldown entry by name.
869
+ * Returns undefined if the cooldown has not been registered.
870
+ */
871
+ declare function getCooldown(name: string): CooldownEntry | undefined;
872
+ /**
873
+ * Fire (trigger) a cooldown, resetting its timer.
874
+ * Sets the cooldown to not-ready and starts the countdown.
875
+ */
876
+ declare function fireCooldown(name: string): void;
877
+ /**
878
+ * Force a cooldown to ready immediately.
879
+ */
880
+ declare function resetCooldown(name: string): void;
881
+ /**
882
+ * Advance all active cooldowns by delta seconds.
883
+ * Called once per frame by the CooldownBehavior system.
884
+ */
885
+ declare function tickCooldowns(delta: number): void;
886
+ /**
887
+ * Get the raw cooldown store (for advanced/debugging use).
888
+ */
889
+ declare function getCooldownStore(): Record<string, CooldownEntry>;
890
+
891
+ /**
892
+ * Coordinator that bridges WorldBoundary2DBehavior and Ricochet2DBehavior.
893
+ *
894
+ * Automatically handles:
895
+ * 1. Checking boundary hits
896
+ * 2. Computing collision normals
897
+ * 3. Requesting ricochet result
898
+ * 4. Applying movement
899
+ */
900
+ declare class BoundaryRicochetCoordinator {
901
+ private entity;
902
+ private boundary;
903
+ private ricochet;
904
+ constructor(entity: GameEntity<any> & MoveableEntity, boundary: WorldBoundary2DHandle, ricochet: Ricochet2DHandle);
905
+ /**
906
+ * Update loop - call this every frame.
907
+ * Applies ricochet via transformStore and notifies listeners.
908
+ *
909
+ * @returns true if ricochet was applied, false otherwise
910
+ */
911
+ update(): boolean;
912
+ }
913
+
914
+ declare class BoundaryRicochet3DCoordinator {
915
+ private entity;
916
+ private boundary;
917
+ private ricochet;
918
+ constructor(entity: GameEntity<any> & MoveableEntity, boundary: WorldBoundary3DHandle, ricochet: Ricochet3DHandle);
919
+ update(): boolean;
920
+ }
921
+
922
+ interface FirstPersonShooterInput {
923
+ moveX: number;
924
+ moveZ: number;
925
+ lookX: number;
926
+ lookY: number;
927
+ sprint: boolean;
928
+ jumpPressed: boolean;
929
+ jumpHeld: boolean;
930
+ jumpReleased: boolean;
931
+ fastFall?: boolean;
932
+ }
933
+ interface FirstPersonShooterControllerHandle {
934
+ getYaw(): number;
935
+ }
936
+ interface FirstPersonShooterJumperHandle {
937
+ getState(): unknown;
938
+ }
939
+ type FirstPersonShooterEntity = GameEntity<any> & {
940
+ $fps?: FirstPersonInputComponent;
941
+ $jumper?: JumpInput3D;
942
+ };
943
+ declare class FirstPersonShooterCoordinator {
944
+ private entity;
945
+ private fpsController;
946
+ private jumper;
947
+ constructor(entity: FirstPersonShooterEntity, fpsController: FirstPersonShooterControllerHandle, jumper: FirstPersonShooterJumperHandle);
948
+ update(input: FirstPersonShooterInput): void;
949
+ private getMoveDirWorld;
950
+ }
951
+
952
+ interface TopDownShooterInput {
953
+ moveX: number;
954
+ moveY: number;
955
+ aimX: number;
956
+ aimY: number;
957
+ shootPressed: boolean;
958
+ shootHeld: boolean;
959
+ }
960
+ type TopDownShooterEntity = Shooter2DSourceEntity & {
961
+ $topDownMovement?: TopDownMovementInputComponent;
962
+ };
963
+ declare class TopDownShooterCoordinator {
964
+ private entity;
965
+ private shooter;
966
+ private stage;
967
+ constructor(entity: TopDownShooterEntity, shooter: Shooter2DHandle, stage: Shooter2DStageLike);
968
+ update(input: TopDownShooterInput): void;
969
+ }
970
+
971
+ interface MultidirectionalSpaceShooterInput {
972
+ moveX: number;
973
+ moveY: number;
974
+ aimX: number;
975
+ aimY: number;
976
+ shootPressed: boolean;
977
+ shootHeld: boolean;
978
+ }
979
+ type MultidirectionalSpaceShooterEntity = GameEntity<any> & Shooter2DSourceEntity & {
980
+ $thruster?: ThrusterInputComponent;
981
+ };
982
+ declare class MultidirectionalSpaceShooterCoordinator {
983
+ private entity;
984
+ private shooter;
985
+ private stage;
986
+ constructor(entity: MultidirectionalSpaceShooterEntity, shooter: Shooter2DHandle, stage: Shooter2DStageLike);
987
+ update(input: MultidirectionalSpaceShooterInput): void;
988
+ }
989
+
990
+ /**
991
+ * CooldownIcon -- a WoW-style cooldown icon UI entity.
992
+ *
993
+ * Renders a square icon with a semi-transparent clockwise sweep overlay
994
+ * that reflects cooldown progress from the CooldownStore. Optionally shows
995
+ * remaining time text in the center.
996
+ *
997
+ * Modeled after ZylemRect's canvas-based viewport-attached sprite pattern.
998
+ */
999
+
1000
+ /**
1001
+ * Reference point on the viewport for positioning UI elements.
1002
+ * The offset in `screenPosition` is applied relative to this anchor.
1003
+ */
1004
+ type ScreenAnchor = 'top-left' | 'top-center' | 'top-right' | 'center-left' | 'center' | 'center-right' | 'bottom-left' | 'bottom-center' | 'bottom-right';
1005
+ /** Preset icon sizes in view units. */
1006
+ declare const ICON_SIZE_PRESETS: {
1007
+ readonly xs: 8;
1008
+ readonly sm: 16;
1009
+ readonly md: 32;
1010
+ readonly lg: 48;
1011
+ readonly xl: 64;
1012
+ };
1013
+ /** Named size preset. */
1014
+ type IconSizePreset = keyof typeof ICON_SIZE_PRESETS;
1015
+ /**
1016
+ * Icon size expressed as a named preset, a square unit value, or
1017
+ * a `{ width, height }` object for non-square icons.
1018
+ *
1019
+ * All numeric values are in **view units** (viewport height = 192 units).
1020
+ */
1021
+ type IconSize = IconSizePreset | number | {
1022
+ width: number;
1023
+ height: number;
1024
+ };
1025
+ type ZylemCooldownIconOptions = GameEntityOptions & {
1026
+ /** Name of the cooldown in the CooldownStore */
1027
+ cooldown: string;
1028
+ /** Texture path for the icon background (optional) */
1029
+ icon?: string;
1030
+ /** Solid fill color when no icon texture is provided */
1031
+ fillColor?: Color | string;
1032
+ /**
1033
+ * Size of the icon in view units, a named preset, or a `{ width, height }` object.
1034
+ *
1035
+ * Presets: `'xs'` (8), `'sm'` (16), `'md'` (32), `'lg'` (48), `'xl'` (64).
1036
+ * A bare number creates a square icon of that many units.
1037
+ * The viewport height equals 192 units; width scales with aspect ratio.
1038
+ *
1039
+ * @default 'md'
1040
+ */
1041
+ iconSize?: IconSize;
1042
+ /** Whether to show remaining time text */
1043
+ showTimer?: boolean;
1044
+ /** Whether to attach to the camera viewport (default: true) */
1045
+ stickToViewport?: boolean;
1046
+ /**
1047
+ * Viewport anchor the icon is positioned relative to.
1048
+ * @default 'top-left'
1049
+ */
1050
+ screenAnchor?: ScreenAnchor;
1051
+ /**
1052
+ * Offset from the {@link screenAnchor} in **view units**.
1053
+ * Positive x = right, positive y = down.
1054
+ * Accepts a `Vector2` or a plain `{ x, y }` object.
1055
+ * @default { x: 0, y: 0 }
1056
+ */
1057
+ screenPosition?: Vector2 | {
1058
+ x: number;
1059
+ y: number;
1060
+ };
1061
+ /** Distance from camera (default: 1) */
1062
+ zDistance?: number;
1063
+ /** Color of the sweep overlay (default: semi-transparent black) */
1064
+ overlayColor?: string;
1065
+ };
1066
+ declare class ZylemCooldownIcon extends GameEntity<ZylemCooldownIconOptions> {
1067
+ static type: symbol;
1068
+ private _sprite;
1069
+ private _texture;
1070
+ private _canvas;
1071
+ private _ctx;
1072
+ private _cameraRef;
1073
+ private _iconTexture;
1074
+ private _iconImage;
1075
+ private _lastRenderedProgress;
1076
+ constructor(options?: ZylemCooldownIconOptions);
1077
+ private createSprite;
1078
+ private redraw;
1079
+ private toCssColor;
1080
+ private getResolution;
1081
+ private iconSetup;
1082
+ private iconUpdate;
1083
+ /**
1084
+ * Resolve screen position to pixels.
1085
+ * Computes the anchor point in pixels, then adds the view-unit offset.
1086
+ */
1087
+ private resolveScreenPosition;
1088
+ /**
1089
+ * Resolve `iconSize` to screen pixels using the view-unit grid.
1090
+ * Viewport height = {@link VIEW_UNITS_HEIGHT} units; width scales with aspect ratio.
1091
+ */
1092
+ private resolveIconSize;
1093
+ /** Compute the world-space half-extents at a given distance from the camera. */
1094
+ private computeWorldExtents;
1095
+ private updateStickyTransform;
1096
+ /**
1097
+ * Dispose Three.js / DOM resources when the entity is destroyed.
1098
+ */
1099
+ private iconDestroy;
1100
+ }
1101
+ type CooldownIconOptions = BaseNode | Partial<ZylemCooldownIconOptions>;
1102
+ /**
1103
+ * Create a WoW-style cooldown icon UI entity.
1104
+ *
1105
+ * @example
1106
+ * ```ts
1107
+ * const attackIcon = createCooldownIcon({
1108
+ * cooldown: 'attack',
1109
+ * icon: swordIconPath,
1110
+ * screenAnchor: 'top-center', // reference point on the viewport
1111
+ * screenPosition: { x: 0, y: 10 }, // offset in view units from anchor
1112
+ * iconSize: 'sm', // preset (16 × 16 view units)
1113
+ * // iconSize: 24, // square (24 × 24 view units)
1114
+ * // iconSize: { width: 16, height: 24 }, // custom rectangle
1115
+ * });
1116
+ * ```
1117
+ */
1118
+ declare function createCooldownIcon(...args: Array<CooldownIconOptions>): ZylemCooldownIcon;
1119
+
88
1120
  declare function destroy(entity: any, globals?: any): void;
89
1121
 
90
1122
  /**
@@ -97,6 +1129,66 @@ declare function ricochetSound(frequency?: number, duration?: number): void;
97
1129
  */
98
1130
  declare function pingPongBeep(frequency?: number, duration?: number): void;
99
1131
 
1132
+ /**
1133
+ * Maps arrow keys to axes (Horizontal/Vertical) for the given player.
1134
+ * @example stage.setInputConfiguration(useArrowsForAxes('p1'));
1135
+ */
1136
+ declare function useArrowsForAxes(player: InputPlayer): GameInputConfig;
1137
+ /**
1138
+ * Maps arrow keys to secondary axes for the given player.
1139
+ * @example stage.setInputConfiguration(useArrowsForSecondaryAxes('p1'));
1140
+ */
1141
+ declare function useArrowsForSecondaryAxes(player: InputPlayer): GameInputConfig;
1142
+ /**
1143
+ * Maps arrow keys to directions (Up/Down/Left/Right) for the given player.
1144
+ * Useful when `includeDefaults` is false and you still want arrow-key directions.
1145
+ * @example stage.setInputConfiguration(useArrowsForDirections('p1'));
1146
+ */
1147
+ declare function useArrowsForDirections(player: InputPlayer): GameInputConfig;
1148
+ /**
1149
+ * Maps W/A/S/D keys to directions (Up/Down/Left/Right) for the given player.
1150
+ * @example stage.setInputConfiguration(useWASDForDirections('p1'));
1151
+ */
1152
+ declare function useWASDForDirections(player: InputPlayer): GameInputConfig;
1153
+ /**
1154
+ * Maps W/A/S/D keys to axes (Horizontal/Vertical) for the given player.
1155
+ * @example stage.setInputConfiguration(useWASDForAxes('p1'));
1156
+ */
1157
+ declare function useWASDForAxes(player: InputPlayer): GameInputConfig;
1158
+ /**
1159
+ * Maps I/J/K/L keys to axes (Horizontal/Vertical) for the given player.
1160
+ * @example stage.setInputConfiguration(useIJKLForAxes('p1'));
1161
+ */
1162
+ declare function useIJKLForAxes(player: InputPlayer): GameInputConfig;
1163
+ /**
1164
+ * Maps I/J/K/L keys to directions (Up/Down/Left/Right) for the given player.
1165
+ * @example stage.setInputConfiguration(useIJKLForDirections('p1'));
1166
+ */
1167
+ declare function useIJKLForDirections(player: InputPlayer): GameInputConfig;
1168
+ /**
1169
+ * Enables mouse-look with pointer lock for the given player.
1170
+ * Mouse movement maps to SecondaryHorizontal/SecondaryVertical axes;
1171
+ * left click maps to LTrigger, right click to RTrigger.
1172
+ * @example stage.setInputConfiguration(useMouseLook('p1'));
1173
+ */
1174
+ declare function useMouseLook(player: InputPlayer, options?: {
1175
+ sensitivity?: number;
1176
+ }): GameInputConfig;
1177
+ /**
1178
+ * Enables basic mouse input (no pointer lock) for the given player.
1179
+ * @example stage.setInputConfiguration(useMouse('p1'));
1180
+ */
1181
+ declare function useMouse(player: InputPlayer, options?: {
1182
+ sensitivity?: number;
1183
+ }): GameInputConfig;
1184
+ /**
1185
+ * Deep-merges multiple GameInputConfig objects into one.
1186
+ * At the player level, configs are merged (both apply).
1187
+ * At the key level, later configs win on conflict.
1188
+ * @example mergeInputConfigs(useArrowsForAxes('p1'), useWASDForDirections('p1'));
1189
+ */
1190
+ declare function mergeInputConfigs(...configs: GameInputConfig[]): GameInputConfig;
1191
+
100
1192
  /**
101
1193
  * Set a global value by path.
102
1194
  * Emits a 'game:state:updated' event when the value changes.
@@ -206,15 +1298,23 @@ declare class ZylemGameElement extends HTMLElement {
206
1298
  private _game;
207
1299
  private _state;
208
1300
  private container;
1301
+ private resizeObserver;
1302
+ private _viewportProfile;
1303
+ private static readonly HOST_CONFIG_MARKER;
209
1304
  constructor();
210
1305
  /**
211
1306
  * Focus the game container for keyboard input
212
1307
  */
213
1308
  focus(): void;
1309
+ connectedCallback(): void;
214
1310
  set game(game: Game<any>);
215
1311
  get game(): Game<any> | null;
216
1312
  set state(value: ZylemGameState);
217
1313
  get state(): ZylemGameState;
1314
+ set viewportProfile(value: DeviceProfile);
1315
+ get viewportProfile(): DeviceProfile;
1316
+ static get observedAttributes(): string[];
1317
+ attributeChangedCallback(name: string, _oldValue: string | null, newValue: string | null): void;
218
1318
  /**
219
1319
  * Sync the web component's state with the game-lib's internal debug state
220
1320
  */
@@ -224,6 +1324,8 @@ declare class ZylemGameElement extends HTMLElement {
224
1324
  */
225
1325
  private syncToolbarState;
226
1326
  disconnectedCallback(): void;
1327
+ private attachHostContainer;
1328
+ private syncDisplayRuntime;
227
1329
  }
228
1330
 
229
1331
  declare const fireShader: {
@@ -248,4 +1350,4 @@ declare const debugShader: {
248
1350
 
249
1351
  declare const objectVertexShader = "\nuniform vec2 uvScale;\nvarying vec2 vUv;\n\nvoid main() {\n\tvUv = uv;\n\tvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\n\tgl_Position = projectionMatrix * mvPosition;\n}\n";
250
1352
 
251
- export { type DebugTools, Game, StageBlueprint, StageManager, type TemplateFactory, ZylemGameElement, type ZylemGameState, clearGlobalSubscriptions, createEntityFactory, createGlobal, createVariable, debugShader, debugState, destroy, fireShader, getGlobal, getGlobals, getVariable, objectVertexShader, onGlobalChange, onGlobalChanges, onVariableChange, onVariableChanges, pingPongBeep, ricochetSound, setDebugTool, setGlobal, setPaused, setVariable, stageState, standardShader, starShader };
1353
+ export { BehaviorDescriptor, BoundaryRicochet3DCoordinator, BoundaryRicochetCoordinator, CameraBehavior, type CameraFeedOptions, CameraWrapper, CooldownBehavior, type CooldownConfig, type CooldownEntry, type CooldownHandle, type CooldownOptions, type DebugTools, DeviceProfile, type FirstPersonContext, FirstPersonController, FirstPersonControllerBehavior, type FirstPersonControllerOptions, type FirstPersonEntity, FirstPersonEvent, FirstPersonFSM, type FirstPersonInputComponent, type FirstPersonMovementComponent, FirstPersonPerspective, FirstPersonShooterCoordinator, type FirstPersonShooterInput, FirstPersonState, type FirstPersonStateComponent, type FollowTargetOptions, Game, type IconSize, type IconSizePreset, type JumpConfig3D, type JumpContext3D, type JumpInput3D, type JumpState3D, Jumper3D, Jumper3DBehavior, type Jumper3DBehaviorOptions, type Jumper3DEntity, Jumper3DEvent, Jumper3DFSM, Jumper3DState, JumperTickEvent, type JumperTickResult, MultidirectionalSpaceShooterCoordinator, type MultidirectionalSpaceShooterInput, Ricochet2DHandle, Ricochet3DHandle, type ScreenAnchor, Shooter2DHandle, Shooter2DSourceEntity, Shooter2DStageLike, StageBlueprint, StageEntity, StageManager, type TemplateFactory, ThrusterInputComponent, TopDownMovementInputComponent, TopDownShooterCoordinator, type TopDownShooterInput, type Vec3Like, type ViewmodelConfig, WorldBoundary2DHandle, WorldBoundary3DHandle, ZylemGameElement, type ZylemGameState, boxMesh, clearGlobalSubscriptions, coneMesh, createCooldownIcon, createEntityFactory, createFirstPersonInputComponent, createFirstPersonMovementComponent, createFirstPersonStateComponent, createFollowTarget, createGlobal, createJumpConfig3D, createJumpInput3D, createJumpState3D, createVariable, cylinderMesh, debugShader, debugState, destroy, fireCooldown, fireShader, getCooldown, getCooldownStore, getGlobal, getGlobals, getVariable, mergeInputConfigs, objectVertexShader, onGlobalChange, onGlobalChanges, onVariableChange, onVariableChanges, pillMesh, pingPongBeep, pyramidMesh, registerCooldown, resetCooldown, ricochetSound, setCameraFeed, setDebugTool, setGlobal, setPaused, setVariable, sphereMesh, stageState, standardShader, starShader, tickCooldowns, useArrowsForAxes, useArrowsForDirections, useArrowsForSecondaryAxes, useBehavior, useIJKLForAxes, useIJKLForDirections, useMouse, useMouseLook, useWASDForAxes, useWASDForDirections };