@zylem/game-lib 0.6.0 → 0.6.3

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 (54) hide show
  1. package/README.md +9 -16
  2. package/dist/actions.d.ts +30 -21
  3. package/dist/actions.js +628 -145
  4. package/dist/actions.js.map +1 -1
  5. package/dist/behavior/platformer-3d.d.ts +296 -0
  6. package/dist/behavior/platformer-3d.js +518 -0
  7. package/dist/behavior/platformer-3d.js.map +1 -0
  8. package/dist/behavior/ricochet-2d.d.ts +274 -0
  9. package/dist/behavior/ricochet-2d.js +394 -0
  10. package/dist/behavior/ricochet-2d.js.map +1 -0
  11. package/dist/behavior/screen-wrap.d.ts +86 -0
  12. package/dist/behavior/screen-wrap.js +195 -0
  13. package/dist/behavior/screen-wrap.js.map +1 -0
  14. package/dist/behavior/thruster.d.ts +10 -0
  15. package/dist/behavior/thruster.js +234 -0
  16. package/dist/behavior/thruster.js.map +1 -0
  17. package/dist/behavior/world-boundary-2d.d.ts +141 -0
  18. package/dist/behavior/world-boundary-2d.js +181 -0
  19. package/dist/behavior/world-boundary-2d.js.map +1 -0
  20. package/dist/behavior-descriptor-BWNWmIjv.d.ts +142 -0
  21. package/dist/{blueprints-BOCc3Wve.d.ts → blueprints-BWGz8fII.d.ts} +2 -2
  22. package/dist/camera-B5e4c78l.d.ts +468 -0
  23. package/dist/camera.d.ts +3 -2
  24. package/dist/camera.js +962 -166
  25. package/dist/camera.js.map +1 -1
  26. package/dist/composition-DrzFrbqI.d.ts +218 -0
  27. package/dist/{core-CZhozNRH.d.ts → core-DAkskq6Y.d.ts} +97 -65
  28. package/dist/core.d.ts +12 -6
  29. package/dist/core.js +4449 -1052
  30. package/dist/core.js.map +1 -1
  31. package/dist/{entities-BAxfJOkk.d.ts → entities-DC9ce_vx.d.ts} +154 -45
  32. package/dist/entities.d.ts +5 -2
  33. package/dist/entities.js +2505 -722
  34. package/dist/entities.js.map +1 -1
  35. package/dist/entity-BpbZqg19.d.ts +1100 -0
  36. package/dist/entity-types-DAu8sGJH.d.ts +26 -0
  37. package/dist/global-change-Dc8uCKi2.d.ts +25 -0
  38. package/dist/main.d.ts +472 -29
  39. package/dist/main.js +11877 -6124
  40. package/dist/main.js.map +1 -1
  41. package/dist/{stage-types-CD21XoIU.d.ts → stage-types-BFsm3qsZ.d.ts} +255 -26
  42. package/dist/stage.d.ts +11 -6
  43. package/dist/stage.js +3462 -491
  44. package/dist/stage.js.map +1 -1
  45. package/dist/thruster-DhRaJnoL.d.ts +172 -0
  46. package/dist/world-Be5m1XC1.d.ts +31 -0
  47. package/package.json +21 -4
  48. package/dist/behaviors.d.ts +0 -106
  49. package/dist/behaviors.js +0 -398
  50. package/dist/behaviors.js.map +0 -1
  51. package/dist/camera-CpbDr4-V.d.ts +0 -116
  52. package/dist/entity-COvRtFNG.d.ts +0 -395
  53. package/dist/moveable-B_vyA6cw.d.ts +0 -67
  54. package/dist/transformable-CUhvyuYO.d.ts +0 -67
@@ -0,0 +1,26 @@
1
+ import { Group } from 'three';
2
+ import { RigidBody, Collider } from '@dimforge/rapier3d-compat';
3
+
4
+ /**
5
+ * Base entity interface - shared across modules to prevent circular dependencies
6
+ */
7
+ interface BaseEntityInterface {
8
+ uuid: string;
9
+ name: string;
10
+ eid: number;
11
+ group: Group | null | undefined;
12
+ body: RigidBody | null | undefined;
13
+ collider: Collider | null | undefined;
14
+ }
15
+ /**
16
+ * Game entity interface - minimal interface to break circular dependencies
17
+ */
18
+ interface GameEntityInterface extends BaseEntityInterface {
19
+ type: string;
20
+ isStatic: boolean;
21
+ setPosition(x: number, y: number, z: number): void;
22
+ setRotation(x: number, y: number, z: number): void;
23
+ setScale(x: number, y: number, z: number): void;
24
+ }
25
+
26
+ export type { BaseEntityInterface as B, GameEntityInterface as G };
@@ -0,0 +1,25 @@
1
+ import { U as UpdateContext } from './entity-BpbZqg19.js';
2
+
3
+ /**
4
+ * Listen for a single global key change inside an onUpdate pipeline.
5
+ * Usage: onUpdate(globalChange('p1Score', (value) => { ... }))
6
+ */
7
+ declare function globalChange<T = any>(key: string, callback: (value: T, ctx: UpdateContext<any>) => void): (ctx: UpdateContext<any>) => void;
8
+ /**
9
+ * Listen for multiple global key changes inside an onUpdate pipeline.
10
+ * Calls back when any of the provided keys changes.
11
+ * Usage: onUpdate(globalChanges(['p1Score','p2Score'], ([p1,p2]) => { ... }))
12
+ */
13
+ declare function globalChanges<T = any>(keys: string[], callback: (values: T[], ctx: UpdateContext<any>) => void): (ctx: UpdateContext<any>) => void;
14
+ /**
15
+ * Listen for a single stage variable change inside an onUpdate pipeline.
16
+ * Usage: onUpdate(variableChange('score', (value, ctx) => { ... }))
17
+ */
18
+ declare function variableChange<T = any>(key: string, callback: (value: T, ctx: UpdateContext<any>) => void): (ctx: UpdateContext<any>) => void;
19
+ /**
20
+ * Listen for multiple stage variable changes; fires when any changes.
21
+ * Usage: onUpdate(variableChanges(['a','b'], ([a,b], ctx) => { ... }))
22
+ */
23
+ declare function variableChanges<T = any>(keys: string[], callback: (values: T[], ctx: UpdateContext<any>) => void): (ctx: UpdateContext<any>) => void;
24
+
25
+ export { globalChanges as a, variableChanges as b, globalChange as g, variableChange as v };
package/dist/main.d.ts CHANGED
@@ -1,25 +1,40 @@
1
- import { G as Game } from './core-CZhozNRH.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-CZhozNRH.js';
3
- export { a as StageOptions, c as createStage } from './stage-types-CD21XoIU.js';
4
- import { S as StageBlueprint } from './blueprints-BOCc3Wve.js';
5
- export { e as entitySpawner } from './blueprints-BOCc3Wve.js';
6
- export { P as PerspectiveType, a as Perspectives, c as camera } from './camera-CpbDr4-V.js';
7
- export { A as ACTOR_TYPE, B as BOX_TYPE, P as PLANE_TYPE, R as RECT_TYPE, d as SPHERE_TYPE, S as SPRITE_TYPE, T as TEXT_TYPE, e as ZONE_TYPE, Z as ZylemBox, c as actor, b as box, p as plane, r as rect, s as sphere, a as sprite, t as text, z as zone } from './entities-BAxfJOkk.js';
8
- import { U as UpdateContext, B as BehaviorCallbackType, G as GameEntity } from './entity-COvRtFNG.js';
9
- export { a as Behavior, L as LoadingEvent, S as SetupContext } from './entity-COvRtFNG.js';
10
- export { boundary2d, ricochet2DCollision, ricochet2DInBounds } from './behaviors.js';
11
- import { M as MoveableEntity } from './moveable-B_vyA6cw.js';
12
- export { m as makeMoveable, b as move, a as moveable, r as resetVelocity } from './moveable-B_vyA6cw.js';
13
- export { m as makeRotatable, a as makeTransformable, r as rotatable, b as rotateInDirection } from './transformable-CUhvyuYO.js';
14
- export { Howl } from 'howler';
1
+ import { G as Game } from './core-DAkskq6Y.js';
2
+ export { V as Vect3, c as createGame, g as gameConfig, v as vessel } from './core-DAkskq6Y.js';
3
+ import { G as GameInputConfig } from './stage-types-BFsm3qsZ.js';
4
+ export { a as StageOptions, Z as ZylemGameConfig, d as createDisk, c as createStage } from './stage-types-BFsm3qsZ.js';
5
+ import { S as StageBlueprint } from './blueprints-BWGz8fII.js';
6
+ export { e as entitySpawner } from './blueprints-BWGz8fII.js';
7
+ export { C as CameraManager, e as CameraOptions, c as CameraWrapper, P as PerspectiveType, f as Perspectives, g as RendererType, V as Viewport, h as ZylemRenderer, d as createCamera, i as isWebGPUSupported } from './camera-B5e4c78l.js';
8
+ 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-DC9ce_vx.js';
9
+ import { I as GameEntity, P as GameEntityOptions, V as Vec3, R as MaterialOptions, W as MoveableEntity, N as BaseNode, X as InputPlayer } from './entity-BpbZqg19.js';
10
+ export { A as Action, a6 as CollisionComponent, af as EntityConfigPayload, ab as EntityEvents, a7 as EventEmitterDelegate, aa as GameEvents, ac as GameLoadingPayload, O 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-BpbZqg19.js';
11
+ import { Color, Mesh, Vector2 } from 'three';
15
12
  import * as three from 'three';
16
13
  export { three as THREE };
14
+ import { b as BehaviorDescriptor } from './behavior-descriptor-BWNWmIjv.js';
15
+ export { c as BehaviorHandle, d as BehaviorRef, B as BehaviorSystem, a as BehaviorSystemFactory, D as DefineBehaviorConfig, e as defineBehavior } from './behavior-descriptor-BWNWmIjv.js';
16
+ 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, d as ThrusterInputComponent, n as ThrusterMovementBehavior, b as ThrusterMovementComponent, i as ThrusterState, e as ThrusterStateComponent, T as TransformComponent, a as createPhysicsBodyComponent, g as createThrusterInputComponent, f as createThrusterMovementComponent, h as createThrusterStateComponent, c as createTransformComponent } from './thruster-DhRaJnoL.js';
17
+ export { ScreenWrapBehavior, ScreenWrapEvent, ScreenWrapFSM, ScreenWrapOptions, ScreenWrapState } from './behavior/screen-wrap.js';
18
+ import { WorldBoundary2DHandle } from './behavior/world-boundary-2d.js';
19
+ export { WorldBoundary2DBehavior, WorldBoundary2DBounds, WorldBoundary2DEvent, WorldBoundary2DFSM, WorldBoundary2DHit, WorldBoundary2DHits, WorldBoundary2DOptions, WorldBoundary2DPosition, WorldBoundary2DState, computeWorldBoundary2DHits, hasAnyWorldBoundary2DHit } from './behavior/world-boundary-2d.js';
20
+ import { Ricochet2DHandle } from './behavior/ricochet-2d.js';
21
+ export { Ricochet2DBehavior, Ricochet2DCollisionContext, Ricochet2DEvent, Ricochet2DFSM, Ricochet2DOptions, Ricochet2DResult, Ricochet2DState, RicochetCallback } from './behavior/ricochet-2d.js';
22
+ export { Platformer3DBehavior, Platformer3DBehaviorOptions, Platformer3DContext, Platformer3DEntity, Platformer3DEvent, Platformer3DFSM, Platformer3DInputComponent, Platformer3DMovementBehavior, Platformer3DMovementComponent, Platformer3DState, Platformer3DStateComponent, PlatformerCollisionContext, createPlatformer3DInputComponent, createPlatformer3DMovementComponent, createPlatformer3DStateComponent } from './behavior/platformer-3d.js';
23
+ 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-DrzFrbqI.js';
24
+ export { Howl } from 'howler';
17
25
  import * as RAPIER from '@dimforge/rapier3d-compat';
18
26
  export { RAPIER };
27
+ export { g as globalChange, a as globalChanges, v as variableChange, b as variableChanges } from './global-change-Dc8uCKi2.js';
19
28
  export { S as StageEntity } from './entity-Bq_eNEDI.js';
29
+ export { Fn, float, time, uniform, uv, vec3, vec4 } from 'three/tsl';
20
30
  import 'bitecs';
31
+ import './world-Be5m1XC1.js';
32
+ import './entity-types-DAu8sGJH.js';
21
33
  import '@sinclair/typebox';
34
+ import 'three/webgpu';
22
35
  import 'three/examples/jsm/postprocessing/EffectComposer.js';
36
+ import 'mitt';
37
+ import 'typescript-fsm';
23
38
 
24
39
  declare const stageState: {
25
40
  previous: StageBlueprint | null;
@@ -50,26 +65,389 @@ declare const StageManager: {
50
65
  preloadNext(stageId: string, loadStaticStage?: (id: string) => Promise<StageBlueprint>): Promise<void>;
51
66
  };
52
67
 
53
- interface MovementSequence2DStep {
68
+ /**
69
+ * Factory interface for generating entity copies
70
+ */
71
+ interface TemplateFactory<E extends GameEntity<O>, O extends GameEntityOptions = GameEntityOptions> {
72
+ /** The template entity used for cloning */
73
+ readonly template: E;
74
+ /**
75
+ * Generate multiple copies of the template entity
76
+ * @param count Number of copies to generate
77
+ * @returns Array of new entity instances
78
+ */
79
+ generate(count: number): E[];
80
+ }
81
+ /**
82
+ * Create an entity factory from a template entity.
83
+ *
84
+ * @param template The entity to use as a template for cloning
85
+ * @returns Factory object with generate() method
86
+ *
87
+ * @example
88
+ * ```typescript
89
+ * const asteroidTemplate = createSprite({ images: [{ name: 'asteroid', file: asteroidImg }] });
90
+ * const asteroidFactory = createEntityFactory(asteroidTemplate);
91
+ * const asteroids = asteroidFactory.generate(10);
92
+ *
93
+ * asteroids.forEach((asteroid, i) => {
94
+ * asteroid.setPosition(Math.random() * 20 - 10, Math.random() * 15 - 7.5, 0);
95
+ * stage.add(asteroid);
96
+ * });
97
+ * ```
98
+ */
99
+ declare function createEntityFactory<E extends GameEntity<O>, O extends GameEntityOptions = GameEntityOptions>(template: E): TemplateFactory<E, O>;
100
+
101
+ /** Shared options that every mesh factory accepts. */
102
+ interface BaseMeshOptions {
103
+ /** Offset position relative to the entity origin */
104
+ position?: Vec3;
105
+ /** Material options (texture, shader, etc.) */
106
+ material?: Partial<MaterialOptions>;
107
+ /** Convenience color override */
108
+ color?: Color;
109
+ }
110
+ interface BoxMeshOptions extends BaseMeshOptions {
111
+ /** Box dimensions (default: 1x1x1) */
112
+ size?: Vec3;
113
+ }
114
+ /**
115
+ * Create a box mesh.
116
+ */
117
+ declare function boxMesh(opts?: BoxMeshOptions): Mesh;
118
+ interface SphereMeshOptions extends BaseMeshOptions {
119
+ /** Sphere radius (default: 1) */
120
+ radius?: number;
121
+ }
122
+ /**
123
+ * Create a sphere mesh.
124
+ */
125
+ declare function sphereMesh(opts?: SphereMeshOptions): Mesh;
126
+ interface ConeMeshOptions extends BaseMeshOptions {
127
+ /** Base radius (default: 1) */
128
+ radius?: number;
129
+ /** Height (default: 2) */
130
+ height?: number;
131
+ /** Radial segments (default: 32) */
132
+ radialSegments?: number;
133
+ }
134
+ /**
135
+ * Create a cone mesh.
136
+ */
137
+ declare function coneMesh(opts?: ConeMeshOptions): Mesh;
138
+ interface PyramidMeshOptions extends BaseMeshOptions {
139
+ /** Base radius (default: 1) */
140
+ radius?: number;
141
+ /** Height (default: 2) */
142
+ height?: number;
143
+ }
144
+ /**
145
+ * Create a pyramid mesh (4-sided cone).
146
+ */
147
+ declare function pyramidMesh(opts?: PyramidMeshOptions): Mesh;
148
+ interface CylinderMeshOptions extends BaseMeshOptions {
149
+ /** Top radius (default: 1) */
150
+ radiusTop?: number;
151
+ /** Bottom radius (default: 1) */
152
+ radiusBottom?: number;
153
+ /** Height (default: 2) */
154
+ height?: number;
155
+ /** Radial segments (default: 32) */
156
+ radialSegments?: number;
157
+ }
158
+ /**
159
+ * Create a cylinder mesh.
160
+ */
161
+ declare function cylinderMesh(opts?: CylinderMeshOptions): Mesh;
162
+ interface PillMeshOptions extends BaseMeshOptions {
163
+ /** Capsule hemisphere radius (default: 0.5) */
164
+ radius?: number;
165
+ /** Cylindrical section length (default: 1) */
166
+ length?: number;
167
+ /** Cap segments (default: 10) */
168
+ capSegments?: number;
169
+ /** Radial segments (default: 20) */
170
+ radialSegments?: number;
171
+ }
172
+ /**
173
+ * Create a pill (capsule) mesh.
174
+ */
175
+ declare function pillMesh(opts?: PillMeshOptions): Mesh;
176
+
177
+ /**
178
+ * Type-safe helper to apply a behavior to an entity and return the entity cast to the behavior's interface.
179
+ *
180
+ * @param entity The entity to apply the behavior to
181
+ * @param descriptor The behavior descriptor
182
+ * @param options Behavior options
183
+ * @returns The entity, cast to E & I (where I is the behavior's interface)
184
+ */
185
+ 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;
186
+
187
+ /**
188
+ * CooldownBehavior
189
+ *
190
+ * A stage-scoped behavior that manages named cooldowns via the global CooldownStore.
191
+ * Entities use this to register, check, and fire cooldowns.
192
+ * UI components (CooldownIcon) can read from the same store.
193
+ */
194
+ interface CooldownConfig {
195
+ /** Duration in seconds */
196
+ duration: number;
197
+ /** Whether the cooldown starts ready (default: true) */
198
+ immediate?: boolean;
199
+ }
200
+ interface CooldownOptions {
201
+ /**
202
+ * Named cooldowns to register.
203
+ * Keys are the cooldown names, values are their config.
204
+ */
205
+ cooldowns: Record<string, CooldownConfig>;
206
+ }
207
+ /**
208
+ * Handle methods returned by entity.use(CooldownBehavior, ...).
209
+ */
210
+ interface CooldownHandle {
211
+ /** Check if a named cooldown is ready */
212
+ isReady(name: string): boolean;
213
+ /** Fire (trigger) a named cooldown, resetting its timer */
214
+ fire(name: string): void;
215
+ /** Force a cooldown to ready immediately */
216
+ reset(name: string): void;
217
+ /** Get cooldown progress 0..1 (0 = just fired, 1 = ready) */
218
+ getProgress(name: string): number;
219
+ }
220
+ /**
221
+ * CooldownBehavior
222
+ *
223
+ * @example
224
+ * ```ts
225
+ * import { CooldownBehavior, moveBy } from '@zylem/game-lib';
226
+ *
227
+ * const hero = createBox({ ... });
228
+ * const cd = hero.use(CooldownBehavior, {
229
+ * cooldowns: {
230
+ * attack: { duration: 5 },
231
+ * dash: { duration: 2, immediate: false },
232
+ * },
233
+ * });
234
+ *
235
+ * hero.onUpdate(({ me, inputs }) => {
236
+ * if (cd.isReady('attack') && inputs.p1.buttons.A.pressed) {
237
+ * cd.fire('attack');
238
+ * // perform attack
239
+ * }
240
+ * if (cd.isReady('dash') && inputs.p1.buttons.B.pressed) {
241
+ * cd.fire('dash');
242
+ * me.runAction(moveBy({ x: 10, duration: 0.3 }));
243
+ * }
244
+ * });
245
+ * ```
246
+ */
247
+ declare const CooldownBehavior: BehaviorDescriptor<CooldownOptions, CooldownHandle, unknown>;
248
+
249
+ /**
250
+ * A single cooldown entry in the global store.
251
+ */
252
+ interface CooldownEntry {
253
+ /** Identifier for this cooldown */
54
254
  name: string;
55
- moveX?: number;
56
- moveY?: number;
57
- timeInSeconds: number;
255
+ /** Total cooldown time in seconds */
256
+ duration: number;
257
+ /** Time accumulated since last fire */
258
+ elapsed: number;
259
+ /** Whether the cooldown is ready (elapsed >= duration) */
260
+ ready: boolean;
261
+ /** Normalized progress 0..1 (0 = just fired, 1 = ready) */
262
+ progress: number;
263
+ /** Whether this cooldown is currently counting down */
264
+ active: boolean;
58
265
  }
59
- interface MovementSequence2DOptions {
60
- sequence: MovementSequence2DStep[];
61
- loop?: boolean;
266
+ /**
267
+ * Register a named cooldown in the global store.
268
+ * If a cooldown with the same name already exists, it is overwritten.
269
+ *
270
+ * @param name Unique cooldown identifier
271
+ * @param duration Cooldown duration in seconds
272
+ * @param immediate If true, the cooldown starts ready (default: true)
273
+ */
274
+ declare function registerCooldown(name: string, duration: number, immediate?: boolean): void;
275
+ /**
276
+ * Get a cooldown entry by name.
277
+ * Returns undefined if the cooldown has not been registered.
278
+ */
279
+ declare function getCooldown(name: string): CooldownEntry | undefined;
280
+ /**
281
+ * Fire (trigger) a cooldown, resetting its timer.
282
+ * Sets the cooldown to not-ready and starts the countdown.
283
+ */
284
+ declare function fireCooldown(name: string): void;
285
+ /**
286
+ * Force a cooldown to ready immediately.
287
+ */
288
+ declare function resetCooldown(name: string): void;
289
+ /**
290
+ * Advance all active cooldowns by delta seconds.
291
+ * Called once per frame by the CooldownBehavior system.
292
+ */
293
+ declare function tickCooldowns(delta: number): void;
294
+ /**
295
+ * Get the raw cooldown store (for advanced/debugging use).
296
+ */
297
+ declare function getCooldownStore(): Record<string, CooldownEntry>;
298
+
299
+ /**
300
+ * Coordinator that bridges WorldBoundary2DBehavior and Ricochet2DBehavior.
301
+ *
302
+ * Automatically handles:
303
+ * 1. Checking boundary hits
304
+ * 2. Computing collision normals
305
+ * 3. Requesting ricochet result
306
+ * 4. Applying movement
307
+ */
308
+ declare class BoundaryRicochetCoordinator {
309
+ private entity;
310
+ private boundary;
311
+ private ricochet;
312
+ constructor(entity: GameEntity<any> & MoveableEntity, boundary: WorldBoundary2DHandle, ricochet: Ricochet2DHandle);
313
+ /**
314
+ * Update loop - call this every frame.
315
+ * Applies ricochet via transformStore and notifies listeners.
316
+ *
317
+ * @returns true if ricochet was applied, false otherwise
318
+ */
319
+ update(): boolean;
62
320
  }
63
- type MovementSequence2DCallback = (current: MovementSequence2DStep, index: number, ctx: UpdateContext<MoveableEntity>) => void;
321
+
64
322
  /**
65
- * Behavior that sequences 2D movements over time.
66
- * Each step sets linear velocity via `moveXY` for a duration, then advances.
67
- * Defaults to looping when the end is reached.
323
+ * CooldownIcon -- a WoW-style cooldown icon UI entity.
324
+ *
325
+ * Renders a square icon with a semi-transparent clockwise sweep overlay
326
+ * that reflects cooldown progress from the CooldownStore. Optionally shows
327
+ * remaining time text in the center.
328
+ *
329
+ * Modeled after ZylemRect's canvas-based viewport-attached sprite pattern.
68
330
  */
69
- declare function movementSequence2D(opts: MovementSequence2DOptions, onStep?: MovementSequence2DCallback): {
70
- type: BehaviorCallbackType;
71
- handler: (ctx: UpdateContext<MoveableEntity>) => void;
331
+
332
+ /**
333
+ * Reference point on the viewport for positioning UI elements.
334
+ * The offset in `screenPosition` is applied relative to this anchor.
335
+ */
336
+ type ScreenAnchor = 'top-left' | 'top-center' | 'top-right' | 'center-left' | 'center' | 'center-right' | 'bottom-left' | 'bottom-center' | 'bottom-right';
337
+ /** Preset icon sizes in view units. */
338
+ declare const ICON_SIZE_PRESETS: {
339
+ readonly xs: 8;
340
+ readonly sm: 16;
341
+ readonly md: 32;
342
+ readonly lg: 48;
343
+ readonly xl: 64;
72
344
  };
345
+ /** Named size preset. */
346
+ type IconSizePreset = keyof typeof ICON_SIZE_PRESETS;
347
+ /**
348
+ * Icon size expressed as a named preset, a square unit value, or
349
+ * a `{ width, height }` object for non-square icons.
350
+ *
351
+ * All numeric values are in **view units** (viewport height = 192 units).
352
+ */
353
+ type IconSize = IconSizePreset | number | {
354
+ width: number;
355
+ height: number;
356
+ };
357
+ type ZylemCooldownIconOptions = GameEntityOptions & {
358
+ /** Name of the cooldown in the CooldownStore */
359
+ cooldown: string;
360
+ /** Texture path for the icon background (optional) */
361
+ icon?: string;
362
+ /** Solid fill color when no icon texture is provided */
363
+ fillColor?: Color | string;
364
+ /**
365
+ * Size of the icon in view units, a named preset, or a `{ width, height }` object.
366
+ *
367
+ * Presets: `'xs'` (8), `'sm'` (16), `'md'` (32), `'lg'` (48), `'xl'` (64).
368
+ * A bare number creates a square icon of that many units.
369
+ * The viewport height equals 192 units; width scales with aspect ratio.
370
+ *
371
+ * @default 'md'
372
+ */
373
+ iconSize?: IconSize;
374
+ /** Whether to show remaining time text */
375
+ showTimer?: boolean;
376
+ /** Whether to attach to the camera viewport (default: true) */
377
+ stickToViewport?: boolean;
378
+ /**
379
+ * Viewport anchor the icon is positioned relative to.
380
+ * @default 'top-left'
381
+ */
382
+ screenAnchor?: ScreenAnchor;
383
+ /**
384
+ * Offset from the {@link screenAnchor} in **view units**.
385
+ * Positive x = right, positive y = down.
386
+ * Accepts a `Vector2` or a plain `{ x, y }` object.
387
+ * @default { x: 0, y: 0 }
388
+ */
389
+ screenPosition?: Vector2 | {
390
+ x: number;
391
+ y: number;
392
+ };
393
+ /** Distance from camera (default: 1) */
394
+ zDistance?: number;
395
+ /** Color of the sweep overlay (default: semi-transparent black) */
396
+ overlayColor?: string;
397
+ };
398
+ declare class ZylemCooldownIcon extends GameEntity<ZylemCooldownIconOptions> {
399
+ static type: symbol;
400
+ private _sprite;
401
+ private _texture;
402
+ private _canvas;
403
+ private _ctx;
404
+ private _cameraRef;
405
+ private _iconTexture;
406
+ private _iconImage;
407
+ private _lastRenderedProgress;
408
+ constructor(options?: ZylemCooldownIconOptions);
409
+ private createSprite;
410
+ private redraw;
411
+ private toCssColor;
412
+ private getResolution;
413
+ private iconSetup;
414
+ private iconUpdate;
415
+ /**
416
+ * Resolve screen position to pixels.
417
+ * Computes the anchor point in pixels, then adds the view-unit offset.
418
+ */
419
+ private resolveScreenPosition;
420
+ /**
421
+ * Resolve `iconSize` to screen pixels using the view-unit grid.
422
+ * Viewport height = {@link VIEW_UNITS_HEIGHT} units; width scales with aspect ratio.
423
+ */
424
+ private resolveIconSize;
425
+ /** Compute the world-space half-extents at a given distance from the camera. */
426
+ private computeWorldExtents;
427
+ private updateStickyTransform;
428
+ /**
429
+ * Dispose Three.js / DOM resources when the entity is destroyed.
430
+ */
431
+ private iconDestroy;
432
+ }
433
+ type CooldownIconOptions = BaseNode | Partial<ZylemCooldownIconOptions>;
434
+ /**
435
+ * Create a WoW-style cooldown icon UI entity.
436
+ *
437
+ * @example
438
+ * ```ts
439
+ * const attackIcon = createCooldownIcon({
440
+ * cooldown: 'attack',
441
+ * icon: swordIconPath,
442
+ * screenAnchor: 'top-center', // reference point on the viewport
443
+ * screenPosition: { x: 0, y: 10 }, // offset in view units from anchor
444
+ * iconSize: 'sm', // preset (16 × 16 view units)
445
+ * // iconSize: 24, // square (24 × 24 view units)
446
+ * // iconSize: { width: 16, height: 24 }, // custom rectangle
447
+ * });
448
+ * ```
449
+ */
450
+ declare function createCooldownIcon(...args: Array<CooldownIconOptions>): ZylemCooldownIcon;
73
451
 
74
452
  declare function destroy(entity: any, globals?: any): void;
75
453
 
@@ -83,6 +461,45 @@ declare function ricochetSound(frequency?: number, duration?: number): void;
83
461
  */
84
462
  declare function pingPongBeep(frequency?: number, duration?: number): void;
85
463
 
464
+ /**
465
+ * Maps arrow keys to axes (Horizontal/Vertical) for the given player.
466
+ * @example stage.setInputConfiguration(useArrowsForAxes('p1'));
467
+ */
468
+ declare function useArrowsForAxes(player: InputPlayer): GameInputConfig;
469
+ /**
470
+ * Maps arrow keys to directions (Up/Down/Left/Right) for the given player.
471
+ * Useful when `includeDefaults` is false and you still want arrow-key directions.
472
+ * @example stage.setInputConfiguration(useArrowsForDirections('p1'));
473
+ */
474
+ declare function useArrowsForDirections(player: InputPlayer): GameInputConfig;
475
+ /**
476
+ * Maps W/A/S/D keys to directions (Up/Down/Left/Right) for the given player.
477
+ * @example stage.setInputConfiguration(useWASDForDirections('p1'));
478
+ */
479
+ declare function useWASDForDirections(player: InputPlayer): GameInputConfig;
480
+ /**
481
+ * Maps W/A/S/D keys to axes (Horizontal/Vertical) for the given player.
482
+ * @example stage.setInputConfiguration(useWASDForAxes('p1'));
483
+ */
484
+ declare function useWASDForAxes(player: InputPlayer): GameInputConfig;
485
+ /**
486
+ * Maps I/J/K/L keys to axes (Horizontal/Vertical) for the given player.
487
+ * @example stage.setInputConfiguration(useIJKLForAxes('p1'));
488
+ */
489
+ declare function useIJKLForAxes(player: InputPlayer): GameInputConfig;
490
+ /**
491
+ * Maps I/J/K/L keys to directions (Up/Down/Left/Right) for the given player.
492
+ * @example stage.setInputConfiguration(useIJKLForDirections('p1'));
493
+ */
494
+ declare function useIJKLForDirections(player: InputPlayer): GameInputConfig;
495
+ /**
496
+ * Deep-merges multiple GameInputConfig objects into one.
497
+ * At the player level, configs are merged (both apply).
498
+ * At the key level, later configs win on conflict.
499
+ * @example mergeInputConfigs(useArrowsForAxes('p1'), useWASDForDirections('p1'));
500
+ */
501
+ declare function mergeInputConfigs(...configs: GameInputConfig[]): GameInputConfig;
502
+
86
503
  /**
87
504
  * Set a global value by path.
88
505
  * Emits a 'game:state:updated' event when the value changes.
@@ -193,6 +610,10 @@ declare class ZylemGameElement extends HTMLElement {
193
610
  private _state;
194
611
  private container;
195
612
  constructor();
613
+ /**
614
+ * Focus the game container for keyboard input
615
+ */
616
+ focus(): void;
196
617
  set game(game: Game<any>);
197
618
  get game(): Game<any> | null;
198
619
  set state(value: ZylemGameState);
@@ -208,4 +629,26 @@ declare class ZylemGameElement extends HTMLElement {
208
629
  disconnectedCallback(): void;
209
630
  }
210
631
 
211
- export { type DebugTools, Game, StageBlueprint, StageManager, UpdateContext, ZylemGameElement, type ZylemGameState, clearGlobalSubscriptions, createGlobal, createVariable, debugState, destroy, getGlobal, getGlobals, getVariable, movementSequence2D, onGlobalChange, onGlobalChanges, onVariableChange, onVariableChanges, pingPongBeep, ricochetSound, setDebugTool, setGlobal, setPaused, setVariable, stageState };
632
+ declare const fireShader: {
633
+ vertex: string;
634
+ fragment: string;
635
+ };
636
+
637
+ declare const starShader: {
638
+ vertex: string;
639
+ fragment: string;
640
+ };
641
+
642
+ declare const standardShader: {
643
+ vertex: string;
644
+ fragment: string;
645
+ };
646
+
647
+ declare const debugShader: {
648
+ vertex: string;
649
+ fragment: string;
650
+ };
651
+
652
+ 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";
653
+
654
+ export { BehaviorDescriptor, BoundaryRicochetCoordinator, CooldownBehavior, type CooldownConfig, type CooldownEntry, type CooldownHandle, type CooldownOptions, type DebugTools, Game, type IconSize, type IconSizePreset, Ricochet2DHandle, type ScreenAnchor, StageBlueprint, StageManager, type TemplateFactory, WorldBoundary2DHandle, ZylemGameElement, type ZylemGameState, boxMesh, clearGlobalSubscriptions, coneMesh, createCooldownIcon, createEntityFactory, createGlobal, createVariable, cylinderMesh, debugShader, debugState, destroy, fireCooldown, fireShader, getCooldown, getCooldownStore, getGlobal, getGlobals, getVariable, mergeInputConfigs, objectVertexShader, onGlobalChange, onGlobalChanges, onVariableChange, onVariableChanges, pillMesh, pingPongBeep, pyramidMesh, registerCooldown, resetCooldown, ricochetSound, setDebugTool, setGlobal, setPaused, setVariable, sphereMesh, stageState, standardShader, starShader, tickCooldowns, useArrowsForAxes, useArrowsForDirections, useBehavior, useIJKLForAxes, useIJKLForDirections, useWASDForAxes, useWASDForDirections };