blecsd 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +220 -0
  3. package/dist/3d/index.d.ts +5 -0
  4. package/dist/3d/index.js +1 -0
  5. package/dist/audio/index.d.ts +177 -0
  6. package/dist/audio/index.js +1 -0
  7. package/dist/border-D_Jb4ZJV.d.ts +257 -0
  8. package/dist/cell-DwIu2ryP.d.ts +505 -0
  9. package/dist/chunk-2UBBZFE4.js +1 -0
  10. package/dist/chunk-35LCBY6P.js +1 -0
  11. package/dist/chunk-3B7MIVW6.js +1 -0
  12. package/dist/chunk-3EGGGI5J.js +3 -0
  13. package/dist/chunk-4LWWONFK.js +1 -0
  14. package/dist/chunk-4X4N4HNQ.js +2 -0
  15. package/dist/chunk-5PELJRUQ.js +1 -0
  16. package/dist/chunk-AEJIX2MW.js +1 -0
  17. package/dist/chunk-AQ7LW75B.js +1 -0
  18. package/dist/chunk-AXZQAH4X.js +1 -0
  19. package/dist/chunk-B6Z2JFRY.js +1 -0
  20. package/dist/chunk-BCADUCOZ.js +1 -0
  21. package/dist/chunk-C5PCEQ6G.js +1 -0
  22. package/dist/chunk-CIK4AMUA.js +1 -0
  23. package/dist/chunk-DNRXW56C.js +1 -0
  24. package/dist/chunk-FC5FFAAC.js +12 -0
  25. package/dist/chunk-FGHEFXLK.js +1 -0
  26. package/dist/chunk-FYEBZAWN.js +1 -0
  27. package/dist/chunk-G7GIWWLE.js +1 -0
  28. package/dist/chunk-GYHI26UE.js +1 -0
  29. package/dist/chunk-H2YAOJDW.js +1 -0
  30. package/dist/chunk-J4JZ2NU2.js +1 -0
  31. package/dist/chunk-JKVHO4LH.js +1 -0
  32. package/dist/chunk-K2B2OXQ5.js +5 -0
  33. package/dist/chunk-K37L3G4Z.js +4 -0
  34. package/dist/chunk-KD55INV7.js +1 -0
  35. package/dist/chunk-KFAK4A3G.js +1 -0
  36. package/dist/chunk-LCN2ZITE.js +1 -0
  37. package/dist/chunk-LYSK5S63.js +1 -0
  38. package/dist/chunk-NZ55KBM6.js +1 -0
  39. package/dist/chunk-OMMJ7B5P.js +1 -0
  40. package/dist/chunk-OUXUPF3V.js +33 -0
  41. package/dist/chunk-OVT2PPGW.js +19 -0
  42. package/dist/chunk-P6CJO3BC.js +1 -0
  43. package/dist/chunk-PSXXMBVJ.js +1 -0
  44. package/dist/chunk-PXXGH3BV.js +1 -0
  45. package/dist/chunk-QIKIOVP2.js +1 -0
  46. package/dist/chunk-SHUC6JWA.js +1 -0
  47. package/dist/chunk-TDXJDLY6.js +6 -0
  48. package/dist/chunk-TWSWTBYL.js +1 -0
  49. package/dist/chunk-TYMY2TBR.js +3 -0
  50. package/dist/chunk-VNZ6CWJA.js +2 -0
  51. package/dist/chunk-VOCM5T2G.js +5 -0
  52. package/dist/chunk-W5OU7Z6J.js +1 -0
  53. package/dist/chunk-WNG4A3K7.js +4 -0
  54. package/dist/chunk-XQIGERNI.js +1 -0
  55. package/dist/chunk-XZA63ZPO.js +1 -0
  56. package/dist/chunk-YAMOSPWB.js +4 -0
  57. package/dist/chunk-YD6ULIUR.js +1 -0
  58. package/dist/chunk-Z4EZERNE.js +1 -0
  59. package/dist/cli/init.d.ts +86 -0
  60. package/dist/cli/init.js +179 -0
  61. package/dist/color-B78w3zH-.d.ts +79 -0
  62. package/dist/components/index.d.ts +10298 -0
  63. package/dist/components/index.js +1 -0
  64. package/dist/core/index.d.ts +6700 -0
  65. package/dist/core/index.js +1 -0
  66. package/dist/debug/index.d.ts +711 -0
  67. package/dist/debug/index.js +1 -0
  68. package/dist/doubleBuffer-CKQFmlPN.d.ts +95 -0
  69. package/dist/errors/index.d.ts +1110 -0
  70. package/dist/errors/index.js +1 -0
  71. package/dist/events-BbbxkgvX.d.ts +125 -0
  72. package/dist/game/index.d.ts +486 -0
  73. package/dist/game/index.js +1 -0
  74. package/dist/gameLoop-BIPW7-OY.d.ts +219 -0
  75. package/dist/index-zSGJ2eUk.d.ts +3156 -0
  76. package/dist/index.d.ts +246 -0
  77. package/dist/index.js +1 -0
  78. package/dist/input/index.d.ts +158 -0
  79. package/dist/input/index.js +1 -0
  80. package/dist/inputActions-CefRUBuT.d.ts +2637 -0
  81. package/dist/keyParser-Bwm8-l7v.d.ts +229 -0
  82. package/dist/mouseParser-Cfrbn3AX.d.ts +177 -0
  83. package/dist/parser-iMHmQuUh.d.ts +265 -0
  84. package/dist/program-BZaKqDKH.d.ts +141 -0
  85. package/dist/renderable-jTMOA-GK.d.ts +302 -0
  86. package/dist/scheduler-DcfoFuum.d.ts +86 -0
  87. package/dist/schemas/index.d.ts +936 -0
  88. package/dist/schemas/index.js +1 -0
  89. package/dist/systems/index.d.ts +4036 -0
  90. package/dist/systems/index.js +1 -0
  91. package/dist/terminal/index.d.ts +7357 -0
  92. package/dist/terminal/index.js +1 -0
  93. package/dist/terminus-14-bold-HWSPRLJD.js +1 -0
  94. package/dist/terminus-14-normal-T3SWMH4D.js +1 -0
  95. package/dist/tilemap-D1HJvKy3.d.ts +1211 -0
  96. package/dist/types-BcsvoKzf.d.ts +68 -0
  97. package/dist/utils/index.d.ts +6104 -0
  98. package/dist/utils/index.js +1 -0
  99. package/dist/viewport3d-xI33-_wq.d.ts +182 -0
  100. package/dist/virtualScrollback-DvZTRU8a.d.ts +274 -0
  101. package/dist/virtualViewport-Dx2iJliO.d.ts +2334 -0
  102. package/dist/virtualizedLineStore-DwPEvPkk.d.ts +297 -0
  103. package/dist/widgets/bigText.d.ts +230 -0
  104. package/dist/widgets/bigText.js +1 -0
  105. package/dist/widgets/fonts/index.d.ts +211 -0
  106. package/dist/widgets/fonts/index.js +1 -0
  107. package/dist/widgets/index.d.ts +8591 -0
  108. package/dist/widgets/index.js +1 -0
  109. package/package.json +213 -0
@@ -0,0 +1,4036 @@
1
+ import { S as Scheduler } from '../scheduler-DcfoFuum.js';
2
+ import { S as System, W as World, E as Entity, L as LoopPhase } from '../types-BcsvoKzf.js';
3
+ import { d as CollisionPair, f as EmitterAppearance, R as RenderedTileCell } from '../tilemap-D1HJvKy3.js';
4
+ import { E as EventBus, U as UIEventMap } from '../events-BbbxkgvX.js';
5
+ import { b as KeyEvent } from '../keyParser-Bwm8-l7v.js';
6
+ import { M as MouseEvent } from '../mouseParser-Cfrbn3AX.js';
7
+ import { Writable } from 'node:stream';
8
+ import { c as CellChange, S as ScreenBufferData, C as Cell } from '../cell-DwIu2ryP.js';
9
+ import { D as DoubleBufferData } from '../doubleBuffer-CKQFmlPN.js';
10
+ import { z } from 'zod';
11
+ import { V as VirtualizedLineStore } from '../virtualizedLineStore-DwPEvPkk.js';
12
+ import 'bitecs';
13
+
14
+ /**
15
+ * Animation system for updating sprite animations.
16
+ * Processes all entities with Animation component.
17
+ * @module systems/animationSystem
18
+ */
19
+
20
+ /**
21
+ * Query all entities with the Animation component.
22
+ *
23
+ * @param world - The ECS world
24
+ * @returns Array of entity IDs with Animation component
25
+ */
26
+ declare function queryAnimation(world: World): number[];
27
+ /**
28
+ * Checks if an entity has the Animation component (via system store).
29
+ *
30
+ * @param world - The ECS world
31
+ * @param eid - Entity to check
32
+ * @returns true if entity has Animation component
33
+ */
34
+ declare function hasAnimationSystem(world: World, eid: number): boolean;
35
+ /**
36
+ * Animation system that updates all entities with Animation component.
37
+ *
38
+ * This system should be registered in the UPDATE phase of the game loop.
39
+ * It reads delta time from getDeltaTime() which is set by the scheduler.
40
+ *
41
+ * For each playing animation, the system:
42
+ * 1. Adds elapsed time (scaled by speed)
43
+ * 2. Checks if current frame duration exceeded
44
+ * 3. Advances to next frame (respecting direction)
45
+ * 4. Handles loop/stop when animation completes
46
+ * 5. Updates the entity's Sprite component frame
47
+ *
48
+ * @param world - The ECS world to process
49
+ * @returns The world (unchanged reference)
50
+ *
51
+ * @example
52
+ * ```typescript
53
+ * import { createScheduler, LoopPhase, animationSystem } from 'blecsd';
54
+ *
55
+ * const scheduler = createScheduler();
56
+ * scheduler.registerSystem(LoopPhase.UPDATE, animationSystem);
57
+ *
58
+ * // In game loop
59
+ * scheduler.run(world, deltaTime);
60
+ * ```
61
+ */
62
+ declare const animationSystem: System;
63
+ /**
64
+ * Creates a new animation system.
65
+ *
66
+ * Factory function that returns the animationSystem.
67
+ * Useful for cases where you need a fresh reference.
68
+ *
69
+ * @returns The animation system function
70
+ *
71
+ * @example
72
+ * ```typescript
73
+ * import { createAnimationSystem, createScheduler, LoopPhase } from 'blecsd';
74
+ *
75
+ * const scheduler = createScheduler();
76
+ * const system = createAnimationSystem();
77
+ * scheduler.registerSystem(LoopPhase.UPDATE, system);
78
+ * ```
79
+ */
80
+ declare function createAnimationSystem(): System;
81
+ /**
82
+ * Registers the animation system with a scheduler.
83
+ *
84
+ * Convenience function that registers animationSystem in the UPDATE phase.
85
+ *
86
+ * @param scheduler - The scheduler to register with
87
+ * @param priority - Optional priority within the UPDATE phase (default: 0)
88
+ *
89
+ * @example
90
+ * ```typescript
91
+ * import { createScheduler, registerAnimationSystem } from 'blecsd';
92
+ *
93
+ * const scheduler = createScheduler();
94
+ * registerAnimationSystem(scheduler);
95
+ *
96
+ * // Animation updates will now happen in UPDATE phase
97
+ * scheduler.run(world, deltaTime);
98
+ * ```
99
+ */
100
+ declare function registerAnimationSystem(scheduler: Scheduler, priority?: number): void;
101
+ /**
102
+ * Manually update animations for specific entities.
103
+ *
104
+ * Useful when you need to update animations outside of the system,
105
+ * such as in tests or custom update loops.
106
+ *
107
+ * @param world - The ECS world
108
+ * @param entities - Array of entity IDs to update
109
+ * @param deltaTime - Time elapsed in seconds
110
+ *
111
+ * @example
112
+ * ```typescript
113
+ * import { updateAnimations, queryAnimation } from 'blecsd';
114
+ *
115
+ * // Manual update (typically use the system instead)
116
+ * const entities = queryAnimation(world);
117
+ * updateAnimations(world, entities, 0.016); // ~60fps frame
118
+ * ```
119
+ */
120
+ declare function updateAnimations(world: World, entities: readonly number[], deltaTime: number): void;
121
+
122
+ /**
123
+ * Behavior system for processing AI behaviors each frame.
124
+ *
125
+ * Integrates with the Behavior component to update patrol movement,
126
+ * chase/flee logic, custom behaviors, and wait timers.
127
+ *
128
+ * @module systems/behaviorSystem
129
+ */
130
+
131
+ /**
132
+ * Position resolver function for getting entity positions.
133
+ * Allows the behavior system to work with any position storage.
134
+ */
135
+ type PositionResolver = (world: World, eid: Entity) => {
136
+ x: number;
137
+ y: number;
138
+ } | undefined;
139
+ /**
140
+ * Movement applier function for applying computed movement.
141
+ * Allows the behavior system to work with any movement system.
142
+ */
143
+ type MovementApplier = (world: World, eid: Entity, dx: number, dy: number, delta: number) => void;
144
+ /**
145
+ * Configuration for the behavior system.
146
+ */
147
+ interface BehaviorSystemConfig {
148
+ /** Function to resolve entity positions (default: uses Position component) */
149
+ getPosition?: PositionResolver;
150
+ /** Function to apply movement (default: directly modifies Position) */
151
+ applyMovement?: MovementApplier;
152
+ /** Function to get delta time */
153
+ getDelta: () => number;
154
+ }
155
+ /**
156
+ * Creates a behavior system that processes all entities with Behavior components.
157
+ *
158
+ * The system computes movement directions for patrol, chase, and flee behaviors,
159
+ * and applies them via the configured movement applier.
160
+ *
161
+ * @param config - System configuration
162
+ * @param entities - Function returning entity IDs to process
163
+ * @returns A system function
164
+ *
165
+ * @example
166
+ * ```typescript
167
+ * import { createBehaviorSystem } from 'blecsd';
168
+ *
169
+ * const behaviorSystem = createBehaviorSystem({
170
+ * getDelta: () => 1/60,
171
+ * }, () => behaviorEntities);
172
+ *
173
+ * // In update loop
174
+ * behaviorSystem(world);
175
+ * ```
176
+ */
177
+ declare function createBehaviorSystem(config: BehaviorSystemConfig, entities: (world: World) => readonly Entity[]): System;
178
+
179
+ /**
180
+ * Camera system for updating camera positions.
181
+ * Processes all entities with Camera component.
182
+ * @module systems/cameraSystem
183
+ */
184
+
185
+ /**
186
+ * Query all entities with the Camera component.
187
+ *
188
+ * @param world - The ECS world
189
+ * @returns Array of entity IDs with Camera component
190
+ */
191
+ declare function queryCameras(world: World): number[];
192
+ /**
193
+ * Camera system that updates all cameras with follow targets.
194
+ *
195
+ * This system should be registered in the UPDATE phase, after movement.
196
+ * It updates camera positions to follow their targets with smoothing
197
+ * and dead zone support.
198
+ *
199
+ * @param world - The ECS world to process
200
+ * @returns The world (unchanged reference)
201
+ *
202
+ * @example
203
+ * ```typescript
204
+ * import { createScheduler, LoopPhase, cameraSystem } from 'blecsd';
205
+ *
206
+ * const scheduler = createScheduler();
207
+ * scheduler.registerSystem(LoopPhase.UPDATE, cameraSystem, 20); // After movement and collision
208
+ *
209
+ * // In game loop
210
+ * scheduler.run(world, deltaTime);
211
+ * ```
212
+ */
213
+ declare const cameraSystem: System;
214
+ /**
215
+ * Creates a new camera system.
216
+ *
217
+ * Factory function that returns the cameraSystem.
218
+ *
219
+ * @returns The camera system function
220
+ *
221
+ * @example
222
+ * ```typescript
223
+ * import { createCameraSystem, createScheduler, LoopPhase } from 'blecsd';
224
+ *
225
+ * const scheduler = createScheduler();
226
+ * const system = createCameraSystem();
227
+ * scheduler.registerSystem(LoopPhase.UPDATE, system, 20);
228
+ * ```
229
+ */
230
+ declare function createCameraSystem(): System;
231
+ /**
232
+ * Registers the camera system with a scheduler.
233
+ *
234
+ * Convenience function that registers cameraSystem in the UPDATE phase.
235
+ * Uses priority 20 by default to run after movement (priority 0) and collision (priority 10).
236
+ *
237
+ * @param scheduler - The scheduler to register with
238
+ * @param priority - Optional priority within the UPDATE phase (default: 20)
239
+ *
240
+ * @example
241
+ * ```typescript
242
+ * import { createScheduler, registerCameraSystem } from 'blecsd';
243
+ *
244
+ * const scheduler = createScheduler();
245
+ * registerCameraSystem(scheduler);
246
+ *
247
+ * // Camera updates will happen in UPDATE phase after movement
248
+ * scheduler.run(world, deltaTime);
249
+ * ```
250
+ */
251
+ declare function registerCameraSystem(scheduler: Scheduler, priority?: number): void;
252
+ /**
253
+ * Manually updates all cameras.
254
+ *
255
+ * Useful when you need to update cameras outside of the system,
256
+ * such as in tests or custom update loops.
257
+ *
258
+ * @param world - The ECS world
259
+ * @param deltaTime - Time elapsed in seconds
260
+ *
261
+ * @example
262
+ * ```typescript
263
+ * import { updateCameras } from 'blecsd';
264
+ *
265
+ * // Manual camera update (typically use the system instead)
266
+ * updateCameras(world, 0.016);
267
+ * ```
268
+ */
269
+ declare function updateCameras(world: World, deltaTime: number): void;
270
+
271
+ /**
272
+ * Collision system for detecting entity collisions.
273
+ * Processes all entities with Collider component.
274
+ * @module systems/collisionSystem
275
+ */
276
+
277
+ /**
278
+ * Collision event data.
279
+ */
280
+ interface CollisionEventData {
281
+ /** First entity in collision */
282
+ readonly entityA: number;
283
+ /** Second entity in collision */
284
+ readonly entityB: number;
285
+ }
286
+ /**
287
+ * Collision event map for the EventBus.
288
+ */
289
+ interface CollisionEventMap {
290
+ /** Fired when two solid colliders start colliding */
291
+ collisionStart: CollisionEventData;
292
+ /** Fired when two solid colliders stop colliding */
293
+ collisionEnd: CollisionEventData;
294
+ /** Fired when an entity enters a trigger zone */
295
+ triggerEnter: CollisionEventData;
296
+ /** Fired when an entity exits a trigger zone */
297
+ triggerExit: CollisionEventData;
298
+ }
299
+ /**
300
+ * Collision system state.
301
+ */
302
+ interface CollisionSystemState {
303
+ /** Event bus for collision events */
304
+ readonly eventBus: EventBus<CollisionEventMap>;
305
+ /** Currently active collision pairs */
306
+ readonly activePairs: Map<string, CollisionPair>;
307
+ /** Currently active trigger pairs */
308
+ readonly activeTriggers: Map<string, CollisionPair>;
309
+ }
310
+ /**
311
+ * Gets the collision event bus.
312
+ *
313
+ * @returns The collision event bus
314
+ *
315
+ * @example
316
+ * ```typescript
317
+ * import { getCollisionEventBus } from 'blecsd';
318
+ *
319
+ * const bus = getCollisionEventBus();
320
+ * bus.on('collisionStart', ({ entityA, entityB }) => {
321
+ * console.log(`Collision between ${entityA} and ${entityB}`);
322
+ * });
323
+ * ```
324
+ */
325
+ declare function getCollisionEventBus(): EventBus<CollisionEventMap>;
326
+ /**
327
+ * Gets the current active collision pairs.
328
+ *
329
+ * @returns Map of active collision pairs
330
+ */
331
+ declare function getActiveCollisions(): ReadonlyMap<string, CollisionPair>;
332
+ /**
333
+ * Gets the current active trigger pairs.
334
+ *
335
+ * @returns Map of active trigger pairs
336
+ */
337
+ declare function getActiveTriggers(): ReadonlyMap<string, CollisionPair>;
338
+ /**
339
+ * Resets the collision system state.
340
+ * Useful for testing or scene changes.
341
+ */
342
+ declare function resetCollisionState(): void;
343
+ /**
344
+ * Query all entities with the Collider component.
345
+ *
346
+ * @param world - The ECS world
347
+ * @returns Array of entity IDs with Collider component
348
+ */
349
+ declare function queryColliders(world: World): number[];
350
+ /**
351
+ * Detects all collisions between entities in the world.
352
+ * Uses a simple O(n^2) broad phase (suitable for small entity counts).
353
+ *
354
+ * @param world - The ECS world
355
+ * @returns Array of collision pairs
356
+ */
357
+ declare function detectCollisions(world: World): CollisionPair[];
358
+ /**
359
+ * Collision system that detects collisions and emits events.
360
+ *
361
+ * This system should be registered in the UPDATE phase, after movement.
362
+ * It detects all collisions between entities with Collider and Position
363
+ * components, and emits events for collision start/end and trigger enter/exit.
364
+ *
365
+ * @param world - The ECS world to process
366
+ * @returns The world (unchanged reference)
367
+ *
368
+ * @example
369
+ * ```typescript
370
+ * import { createScheduler, LoopPhase, collisionSystem, getCollisionEventBus } from 'blecsd';
371
+ *
372
+ * const scheduler = createScheduler();
373
+ * scheduler.registerSystem(LoopPhase.UPDATE, collisionSystem, 10); // After movement
374
+ *
375
+ * // Listen for collisions
376
+ * const bus = getCollisionEventBus();
377
+ * bus.on('collisionStart', ({ entityA, entityB }) => {
378
+ * console.log(`Collision: ${entityA} hit ${entityB}`);
379
+ * });
380
+ * ```
381
+ */
382
+ declare const collisionSystem: System;
383
+ /**
384
+ * Creates a new collision system.
385
+ *
386
+ * Factory function that returns the collisionSystem.
387
+ *
388
+ * @returns The collision system function
389
+ *
390
+ * @example
391
+ * ```typescript
392
+ * import { createCollisionSystem, createScheduler, LoopPhase } from 'blecsd';
393
+ *
394
+ * const scheduler = createScheduler();
395
+ * const system = createCollisionSystem();
396
+ * scheduler.registerSystem(LoopPhase.UPDATE, system, 10);
397
+ * ```
398
+ */
399
+ declare function createCollisionSystem(): System;
400
+ /**
401
+ * Registers the collision system with a scheduler.
402
+ *
403
+ * Convenience function that registers collisionSystem in the UPDATE phase.
404
+ * Uses priority 10 by default to run after movement (priority 0).
405
+ *
406
+ * @param scheduler - The scheduler to register with
407
+ * @param priority - Optional priority within the UPDATE phase (default: 10)
408
+ *
409
+ * @example
410
+ * ```typescript
411
+ * import { createScheduler, registerCollisionSystem } from 'blecsd';
412
+ *
413
+ * const scheduler = createScheduler();
414
+ * registerCollisionSystem(scheduler);
415
+ *
416
+ * // Collisions will be detected after movement
417
+ * scheduler.run(world, deltaTime);
418
+ * ```
419
+ */
420
+ declare function registerCollisionSystem(scheduler: Scheduler, priority?: number): void;
421
+ /**
422
+ * Checks if an entity is currently colliding with any other entity.
423
+ *
424
+ * @param eid - The entity to check
425
+ * @returns true if entity is in any active collision
426
+ *
427
+ * @example
428
+ * ```typescript
429
+ * import { isColliding } from 'blecsd';
430
+ *
431
+ * if (isColliding(player)) {
432
+ * console.log('Player is touching something!');
433
+ * }
434
+ * ```
435
+ */
436
+ declare function isColliding(eid: number): boolean;
437
+ /**
438
+ * Checks if an entity is currently in any trigger zone.
439
+ *
440
+ * @param eid - The entity to check
441
+ * @returns true if entity is in any active trigger
442
+ *
443
+ * @example
444
+ * ```typescript
445
+ * import { isInTrigger } from 'blecsd';
446
+ *
447
+ * if (isInTrigger(player)) {
448
+ * console.log('Player is in a trigger zone!');
449
+ * }
450
+ * ```
451
+ */
452
+ declare function isInTrigger(eid: number): boolean;
453
+ /**
454
+ * Gets all entities currently colliding with a specific entity.
455
+ *
456
+ * @param eid - The entity to check
457
+ * @returns Array of entity IDs colliding with this entity
458
+ *
459
+ * @example
460
+ * ```typescript
461
+ * import { getCollidingEntities } from 'blecsd';
462
+ *
463
+ * const enemies = getCollidingEntities(player);
464
+ * for (const enemy of enemies) {
465
+ * // Handle collision with each enemy
466
+ * }
467
+ * ```
468
+ */
469
+ declare function getCollidingEntities(eid: number): number[];
470
+ /**
471
+ * Gets all trigger zones an entity is currently in.
472
+ *
473
+ * @param eid - The entity to check
474
+ * @returns Array of entity IDs of triggers this entity is in
475
+ *
476
+ * @example
477
+ * ```typescript
478
+ * import { getTriggerZones } from 'blecsd';
479
+ *
480
+ * const zones = getTriggerZones(player);
481
+ * for (const zone of zones) {
482
+ * // Handle being in each zone
483
+ * }
484
+ * ```
485
+ */
486
+ declare function getTriggerZones(eid: number): number[];
487
+ /**
488
+ * Checks if two specific entities are currently colliding.
489
+ *
490
+ * @param eidA - First entity
491
+ * @param eidB - Second entity
492
+ * @returns true if the entities are colliding
493
+ *
494
+ * @example
495
+ * ```typescript
496
+ * import { areColliding } from 'blecsd';
497
+ *
498
+ * if (areColliding(player, enemy)) {
499
+ * // Handle player-enemy collision
500
+ * }
501
+ * ```
502
+ */
503
+ declare function areColliding(eidA: number, eidB: number): boolean;
504
+
505
+ /**
506
+ * Drag and drop system for interactive entities.
507
+ *
508
+ * Handles drag initiation, position updates during drag, and drop handling.
509
+ * Supports constraints like parent bounds, axis locking, and grid snapping.
510
+ *
511
+ * @module systems/dragSystem
512
+ */
513
+
514
+ /**
515
+ * Drag constraint configuration.
516
+ */
517
+ interface DragConstraints {
518
+ /** Constrain to parent bounds */
519
+ constrainToParent?: boolean;
520
+ /** Lock to a single axis */
521
+ constrainAxis?: 'x' | 'y' | null;
522
+ /** Snap to grid */
523
+ snapToGrid?: {
524
+ x: number;
525
+ y: number;
526
+ } | null;
527
+ /** Minimum X position */
528
+ minX?: number;
529
+ /** Maximum X position */
530
+ maxX?: number;
531
+ /** Minimum Y position */
532
+ minY?: number;
533
+ /** Maximum Y position */
534
+ maxY?: number;
535
+ /** Bring entity to front (highest z-index) when dragging starts */
536
+ bringToFront?: boolean;
537
+ /** Z-index to use when bringing to front */
538
+ frontZIndex?: number;
539
+ }
540
+ /**
541
+ * Drag verification callback.
542
+ * Return false to cancel the drag movement.
543
+ */
544
+ type DragVerifyCallback = (entity: Entity, dx: number, dy: number) => boolean;
545
+ /**
546
+ * Drag start event data.
547
+ */
548
+ interface DragStartEvent {
549
+ /** Entity being dragged */
550
+ entity: Entity;
551
+ /** Starting X position */
552
+ startX: number;
553
+ /** Starting Y position */
554
+ startY: number;
555
+ /** Mouse X at drag start */
556
+ mouseX: number;
557
+ /** Mouse Y at drag start */
558
+ mouseY: number;
559
+ }
560
+ /**
561
+ * Drag move event data.
562
+ */
563
+ interface DragMoveEvent {
564
+ /** Entity being dragged */
565
+ entity: Entity;
566
+ /** Current X position */
567
+ x: number;
568
+ /** Current Y position */
569
+ y: number;
570
+ /** Change in X since last move */
571
+ dx: number;
572
+ /** Change in Y since last move */
573
+ dy: number;
574
+ /** Current mouse X */
575
+ mouseX: number;
576
+ /** Current mouse Y */
577
+ mouseY: number;
578
+ }
579
+ /**
580
+ * Drag end event data.
581
+ */
582
+ interface DragEndEvent {
583
+ /** Entity that was dragged */
584
+ entity: Entity;
585
+ /** Final X position */
586
+ x: number;
587
+ /** Final Y position */
588
+ y: number;
589
+ /** Total change in X */
590
+ totalDx: number;
591
+ /** Total change in Y */
592
+ totalDy: number;
593
+ /** Whether drag was cancelled */
594
+ cancelled: boolean;
595
+ }
596
+ /**
597
+ * Drop event data.
598
+ */
599
+ interface DropEvent {
600
+ /** Entity that was dropped */
601
+ entity: Entity;
602
+ /** Drop X position */
603
+ x: number;
604
+ /** Drop Y position */
605
+ y: number;
606
+ /** Entity under drop point (if any) */
607
+ dropTarget: Entity | null;
608
+ }
609
+ /**
610
+ * Drag system event map.
611
+ */
612
+ interface DragEventMap {
613
+ dragstart: DragStartEvent;
614
+ drag: DragMoveEvent;
615
+ dragend: DragEndEvent;
616
+ drop: DropEvent;
617
+ }
618
+ /**
619
+ * Current drag state.
620
+ */
621
+ interface DragState {
622
+ /** Entity currently being dragged */
623
+ dragging: Entity | null;
624
+ /** Starting position of drag */
625
+ startX: number;
626
+ startY: number;
627
+ /** Mouse offset from entity origin at drag start */
628
+ offsetX: number;
629
+ offsetY: number;
630
+ /** Last known position during drag */
631
+ lastX: number;
632
+ lastY: number;
633
+ /** Constraints for current drag */
634
+ constraints: DragConstraints;
635
+ /** Verification callback */
636
+ verifyCallback: DragVerifyCallback | null;
637
+ }
638
+ /**
639
+ * Sets drag constraints for an entity.
640
+ *
641
+ * @param eid - The entity ID
642
+ * @param constraints - Drag constraints
643
+ *
644
+ * @example
645
+ * ```typescript
646
+ * import { setDragConstraints } from 'blecsd';
647
+ *
648
+ * // Constrain to parent bounds
649
+ * setDragConstraints(entity, { constrainToParent: true });
650
+ *
651
+ * // Lock to horizontal axis with grid snap
652
+ * setDragConstraints(entity, {
653
+ * constrainAxis: 'x',
654
+ * snapToGrid: { x: 10, y: 10 }
655
+ * });
656
+ * ```
657
+ */
658
+ declare function setDragConstraints(eid: Entity, constraints: DragConstraints): void;
659
+ /**
660
+ * Gets drag constraints for an entity.
661
+ *
662
+ * @param eid - The entity ID
663
+ * @returns Drag constraints or empty object
664
+ */
665
+ declare function getDragConstraints(eid: Entity): DragConstraints;
666
+ /**
667
+ * Clears drag constraints for an entity.
668
+ *
669
+ * @param eid - The entity ID
670
+ */
671
+ declare function clearDragConstraints(eid: Entity): void;
672
+ /**
673
+ * Sets a drag verification callback for an entity.
674
+ *
675
+ * @param eid - The entity ID
676
+ * @param callback - Verification callback (return false to cancel movement)
677
+ *
678
+ * @example
679
+ * ```typescript
680
+ * import { setDragVerifyCallback } from 'blecsd';
681
+ *
682
+ * // Prevent dragging into certain areas
683
+ * setDragVerifyCallback(entity, (entity, dx, dy) => {
684
+ * const newX = Position.x[entity] + dx;
685
+ * const newY = Position.y[entity] + dy;
686
+ *
687
+ * // Don't allow dragging into forbidden zone
688
+ * if (newX > 50 && newX < 60) return false;
689
+ *
690
+ * return true;
691
+ * });
692
+ * ```
693
+ */
694
+ declare function setDragVerifyCallback(eid: Entity, callback: DragVerifyCallback | null): void;
695
+ /**
696
+ * Gets the drag verification callback for an entity.
697
+ *
698
+ * @param eid - The entity ID
699
+ * @returns The verification callback or null
700
+ */
701
+ declare function getDragVerifyCallback(eid: Entity): DragVerifyCallback | null;
702
+ /**
703
+ * Creates a drag system with event handling.
704
+ *
705
+ * @param eventBus - Event bus for drag events
706
+ * @returns Drag system API
707
+ *
708
+ * @example
709
+ * ```typescript
710
+ * import { createDragSystem, createEventBus } from 'blecsd';
711
+ *
712
+ * const dragEvents = createEventBus<DragEventMap>();
713
+ * const dragSystem = createDragSystem(dragEvents);
714
+ *
715
+ * // Listen for drag events
716
+ * dragEvents.on('dragstart', (e) => {
717
+ * console.log(`Started dragging entity ${e.entity}`);
718
+ * });
719
+ *
720
+ * dragEvents.on('drag', (e) => {
721
+ * console.log(`Dragged to ${e.x}, ${e.y}`);
722
+ * });
723
+ *
724
+ * dragEvents.on('dragend', (e) => {
725
+ * console.log(`Drag ended, cancelled: ${e.cancelled}`);
726
+ * });
727
+ *
728
+ * // In mouse event handler
729
+ * function onMouseDown(x: number, y: number, entity: Entity) {
730
+ * if (dragSystem.canDrag(world, entity)) {
731
+ * dragSystem.startDrag(world, entity, x, y);
732
+ * }
733
+ * }
734
+ *
735
+ * function onMouseMove(x: number, y: number) {
736
+ * dragSystem.updateDrag(world, x, y);
737
+ * }
738
+ *
739
+ * function onMouseUp(x: number, y: number, dropTarget: Entity | null) {
740
+ * dragSystem.endDrag(world, dropTarget);
741
+ * }
742
+ * ```
743
+ */
744
+ declare function createDragSystem(eventBus: EventBus<DragEventMap>): {
745
+ /**
746
+ * Gets the current drag state.
747
+ */
748
+ getState(): Readonly<DragState>;
749
+ /**
750
+ * Checks if an entity is currently being dragged.
751
+ */
752
+ isDragging(): boolean;
753
+ /**
754
+ * Gets the entity currently being dragged.
755
+ */
756
+ getDraggingEntity(): Entity | null;
757
+ /**
758
+ * Checks if an entity can be dragged.
759
+ *
760
+ * @param world - The ECS world
761
+ * @param eid - The entity to check
762
+ */
763
+ canDrag(world: World, eid: Entity): boolean;
764
+ /**
765
+ * Starts dragging an entity.
766
+ *
767
+ * @param world - The ECS world
768
+ * @param eid - The entity to drag
769
+ * @param mouseX - Current mouse X
770
+ * @param mouseY - Current mouse Y
771
+ * @returns True if drag started successfully
772
+ */
773
+ startDrag(world: World, eid: Entity, mouseX: number, mouseY: number): boolean;
774
+ /**
775
+ * Updates the drag position based on mouse movement.
776
+ *
777
+ * @param world - The ECS world
778
+ * @param mouseX - Current mouse X
779
+ * @param mouseY - Current mouse Y
780
+ * @returns True if position was updated
781
+ */
782
+ updateDrag(world: World, mouseX: number, mouseY: number): boolean;
783
+ /**
784
+ * Ends the current drag operation.
785
+ *
786
+ * @param world - The ECS world
787
+ * @param dropTarget - Entity under the drop point (if any)
788
+ * @param cancelled - Whether the drag was cancelled
789
+ */
790
+ endDrag(world: World, dropTarget?: Entity | null, cancelled?: boolean): void;
791
+ /**
792
+ * Cancels the current drag and restores original position.
793
+ *
794
+ * @param world - The ECS world
795
+ */
796
+ cancelDrag(world: World): void;
797
+ };
798
+ /**
799
+ * Resets all drag-related stores.
800
+ * Useful for testing.
801
+ */
802
+ declare function resetDragStores(): void;
803
+
804
+ /**
805
+ * Focus Management System
806
+ *
807
+ * Handles keyboard focus navigation and focus state management.
808
+ * Tracks which entity is focused and provides tab/arrow navigation.
809
+ *
810
+ * @module systems/focusSystem
811
+ *
812
+ * @example
813
+ * ```typescript
814
+ * import {
815
+ * focusSystem,
816
+ * focusNext,
817
+ * focusPrev,
818
+ * focusEntity,
819
+ * getFocused,
820
+ * blurAll,
821
+ * } from 'blecsd';
822
+ *
823
+ * // Register with scheduler
824
+ * const scheduler = createScheduler();
825
+ * scheduler.registerSystem(LoopPhase.INPUT, focusSystem);
826
+ *
827
+ * // Navigate focus
828
+ * focusNext(world); // Focus next element
829
+ * focusPrev(world); // Focus previous element
830
+ *
831
+ * // Direct focus
832
+ * focusEntity(world, buttonEntity);
833
+ *
834
+ * // Check current focus
835
+ * const focused = getFocused(world);
836
+ * ```
837
+ */
838
+
839
+ /**
840
+ * Focus event types.
841
+ */
842
+ type FocusEventType = 'focus' | 'blur';
843
+ /**
844
+ * Focus event data.
845
+ */
846
+ interface FocusEventData {
847
+ /** The entity gaining/losing focus */
848
+ readonly entity: Entity;
849
+ /** The previously focused entity (for focus events) */
850
+ readonly previousEntity: Entity | null;
851
+ /** The next focused entity (for blur events) */
852
+ readonly nextEntity: Entity | null;
853
+ }
854
+ /**
855
+ * Focus event map for type-safe event handling.
856
+ */
857
+ interface FocusEventMap {
858
+ focus: FocusEventData;
859
+ blur: FocusEventData;
860
+ }
861
+ /**
862
+ * Gets the focus event bus, creating if needed.
863
+ *
864
+ * @returns The focus event bus
865
+ *
866
+ * @example
867
+ * ```typescript
868
+ * const bus = getFocusEventBus();
869
+ * bus.on('focus', (data) => {
870
+ * console.log(`Entity ${data.entity} focused`);
871
+ * });
872
+ * ```
873
+ */
874
+ declare function getFocusEventBus(): EventBus<FocusEventMap>;
875
+ /**
876
+ * Resets the focus event bus. Used for testing.
877
+ * @internal
878
+ */
879
+ declare function resetFocusEventBus(): void;
880
+ /**
881
+ * Gets all focusable entities sorted by tab order.
882
+ *
883
+ * @param world - The ECS world
884
+ * @returns Sorted array of focusable entity IDs
885
+ */
886
+ declare function getFocusableEntities(world: World): Entity[];
887
+ /**
888
+ * Gets the currently focused entity.
889
+ *
890
+ * @param world - The ECS world
891
+ * @returns The focused entity or null if none focused
892
+ *
893
+ * @example
894
+ * ```typescript
895
+ * const focused = getFocused(world);
896
+ * if (focused) {
897
+ * console.log(`Entity ${focused} is focused`);
898
+ * }
899
+ * ```
900
+ */
901
+ declare function getFocused(world: World): Entity | null;
902
+ /**
903
+ * Focuses a specific entity.
904
+ *
905
+ * @param world - The ECS world
906
+ * @param eid - The entity to focus
907
+ * @returns true if focus was set successfully
908
+ *
909
+ * @example
910
+ * ```typescript
911
+ * focusEntity(world, buttonEntity);
912
+ * ```
913
+ */
914
+ declare function focusEntity(world: World, eid: Entity): boolean;
915
+ /**
916
+ * Removes focus from all entities.
917
+ *
918
+ * @param world - The ECS world
919
+ *
920
+ * @example
921
+ * ```typescript
922
+ * blurAll(world);
923
+ * ```
924
+ */
925
+ declare function blurAll(world: World): void;
926
+ /**
927
+ * Focuses the next focusable entity in tab order.
928
+ *
929
+ * @param world - The ECS world
930
+ * @returns The newly focused entity, or null if none available
931
+ *
932
+ * @example
933
+ * ```typescript
934
+ * // Handle Tab key
935
+ * if (key === 'Tab') {
936
+ * focusNext(world);
937
+ * }
938
+ * ```
939
+ */
940
+ declare function focusNext(world: World): Entity | null;
941
+ /**
942
+ * Focuses the previous focusable entity in tab order.
943
+ *
944
+ * @param world - The ECS world
945
+ * @returns The newly focused entity, or null if none available
946
+ *
947
+ * @example
948
+ * ```typescript
949
+ * // Handle Shift+Tab key
950
+ * if (key === 'Tab' && shiftKey) {
951
+ * focusPrev(world);
952
+ * }
953
+ * ```
954
+ */
955
+ declare function focusPrev(world: World): Entity | null;
956
+ /**
957
+ * Focuses the first focusable entity.
958
+ *
959
+ * @param world - The ECS world
960
+ * @returns The focused entity, or null if none available
961
+ */
962
+ declare function focusFirst(world: World): Entity | null;
963
+ /**
964
+ * Focuses the last focusable entity.
965
+ *
966
+ * @param world - The ECS world
967
+ * @returns The focused entity, or null if none available
968
+ */
969
+ declare function focusLast(world: World): Entity | null;
970
+ /**
971
+ * Pushes current focus onto the stack and focuses a new entity.
972
+ *
973
+ * Use this when opening modals or popups to preserve the previous focus
974
+ * state for restoration later.
975
+ *
976
+ * @param world - The ECS world
977
+ * @param eid - The entity to focus (e.g., modal or popup)
978
+ * @returns true if push was successful
979
+ *
980
+ * @example
981
+ * ```typescript
982
+ * import { focusPush, focusPop } from 'blecsd';
983
+ *
984
+ * // Open modal - save current focus and focus modal
985
+ * function openModal(world: World, modalEntity: Entity): void {
986
+ * focusPush(world, modalEntity);
987
+ * }
988
+ *
989
+ * // Close modal - restore previous focus
990
+ * function closeModal(world: World): void {
991
+ * focusPop(world);
992
+ * }
993
+ * ```
994
+ */
995
+ declare function focusPush(world: World, eid: Entity): boolean;
996
+ /**
997
+ * Pops the focus stack and restores the previous focus.
998
+ *
999
+ * Use this when closing modals or popups to restore focus to the
1000
+ * element that was focused before.
1001
+ *
1002
+ * @param world - The ECS world
1003
+ * @returns The restored entity, or null if stack was empty
1004
+ *
1005
+ * @example
1006
+ * ```typescript
1007
+ * import { focusPop } from 'blecsd';
1008
+ *
1009
+ * // Close modal and restore focus
1010
+ * const previousFocus = focusPop(world);
1011
+ * if (previousFocus) {
1012
+ * console.log(`Focus restored to entity ${previousFocus}`);
1013
+ * }
1014
+ * ```
1015
+ */
1016
+ declare function focusPop(world: World): Entity | null;
1017
+ /**
1018
+ * Saves the current focus without affecting the stack.
1019
+ *
1020
+ * Use this for temporary focus changes that need to be restored
1021
+ * without the full stack mechanism.
1022
+ *
1023
+ * @param world - The ECS world
1024
+ *
1025
+ * @example
1026
+ * ```typescript
1027
+ * import { saveFocus, restoreFocus } from 'blecsd';
1028
+ *
1029
+ * // Save current focus before temporary change
1030
+ * saveFocus(world);
1031
+ *
1032
+ * // ... do something that changes focus ...
1033
+ *
1034
+ * // Restore the saved focus
1035
+ * restoreFocus(world);
1036
+ * ```
1037
+ */
1038
+ declare function saveFocus(world: World): void;
1039
+ /**
1040
+ * Restores the previously saved focus.
1041
+ *
1042
+ * @param world - The ECS world
1043
+ * @returns The restored entity, or null if no saved focus or entity invalid
1044
+ *
1045
+ * @example
1046
+ * ```typescript
1047
+ * import { restoreFocus } from 'blecsd';
1048
+ *
1049
+ * const restored = restoreFocus(world);
1050
+ * ```
1051
+ */
1052
+ declare function restoreFocus(world: World): Entity | null;
1053
+ /**
1054
+ * Rewinds focus to the last valid entity in the stack.
1055
+ *
1056
+ * This is useful when the currently focused entity is destroyed or
1057
+ * becomes unfocusable. It searches backwards through the focus stack
1058
+ * to find an entity that still exists and is focusable.
1059
+ *
1060
+ * @param world - The ECS world
1061
+ * @returns The entity that received focus, or null if none found
1062
+ *
1063
+ * @example
1064
+ * ```typescript
1065
+ * import { rewindFocus } from 'blecsd';
1066
+ *
1067
+ * // After destroying a focused entity
1068
+ * rewindFocus(world);
1069
+ * ```
1070
+ */
1071
+ declare function rewindFocus(world: World): Entity | null;
1072
+ /**
1073
+ * Moves focus by a specified offset in the tab order.
1074
+ *
1075
+ * Positive offset moves forward (like Tab), negative moves backward
1076
+ * (like Shift+Tab). The offset wraps around at the ends.
1077
+ *
1078
+ * @param world - The ECS world
1079
+ * @param offset - Number of positions to move (positive=forward, negative=backward)
1080
+ * @returns The newly focused entity, or null if none available
1081
+ *
1082
+ * @example
1083
+ * ```typescript
1084
+ * import { focusOffset } from 'blecsd';
1085
+ *
1086
+ * // Move focus forward by 2
1087
+ * focusOffset(world, 2);
1088
+ *
1089
+ * // Move focus backward by 1
1090
+ * focusOffset(world, -1);
1091
+ * ```
1092
+ */
1093
+ declare function focusOffset(world: World, offset: number): Entity | null;
1094
+ /**
1095
+ * Gets the current focus stack depth.
1096
+ *
1097
+ * @param world - The ECS world
1098
+ * @returns Number of entries in the focus stack
1099
+ */
1100
+ declare function getFocusStackDepth(world: World): number;
1101
+ /**
1102
+ * Clears the focus stack.
1103
+ *
1104
+ * Use with caution - this removes all saved focus states.
1105
+ *
1106
+ * @param world - The ECS world
1107
+ */
1108
+ declare function clearFocusStack(world: World): void;
1109
+ /**
1110
+ * Peeks at the top of the focus stack without popping.
1111
+ *
1112
+ * @param world - The ECS world
1113
+ * @returns The entity at the top of the stack, or null if empty
1114
+ */
1115
+ declare function peekFocusStack(world: World): Entity | null;
1116
+ /**
1117
+ * Focus system that processes focus-related input.
1118
+ *
1119
+ * Currently this system validates focus state (ensuring focused entity
1120
+ * is still focusable and visible). Tab key handling should be done
1121
+ * in the input system or user code.
1122
+ *
1123
+ * @param world - The ECS world
1124
+ * @returns The world
1125
+ *
1126
+ * @example
1127
+ * ```typescript
1128
+ * import { focusSystem, createScheduler, LoopPhase } from 'blecsd';
1129
+ *
1130
+ * const scheduler = createScheduler();
1131
+ * scheduler.registerSystem(LoopPhase.INPUT, focusSystem);
1132
+ * ```
1133
+ */
1134
+ declare const focusSystem: System;
1135
+ /**
1136
+ * Creates a focus system.
1137
+ *
1138
+ * @returns A new focus system function
1139
+ */
1140
+ declare function createFocusSystem(): System;
1141
+
1142
+ /**
1143
+ * Frame budget manager and profiling.
1144
+ *
1145
+ * Measures per-system timing, tracks rolling statistics, and enforces
1146
+ * configurable frame time budgets per phase. Optional on-screen debug overlay.
1147
+ *
1148
+ * @module systems/frameBudget
1149
+ */
1150
+
1151
+ /**
1152
+ * Configuration for the frame budget manager.
1153
+ */
1154
+ interface FrameBudgetConfig {
1155
+ /** Target frame time in ms (default: 16.67 = 60fps) */
1156
+ readonly targetFrameMs: number;
1157
+ /** Per-phase budget overrides in ms (phase -> budget) */
1158
+ readonly phaseBudgets: Readonly<Partial<Record<LoopPhase, number>>>;
1159
+ /** Number of frames to keep in rolling stats (default: 120) */
1160
+ readonly rollingWindowSize: number;
1161
+ /** Whether to emit warnings on budget overruns (default: true) */
1162
+ readonly warnOnOverrun: boolean;
1163
+ }
1164
+ /**
1165
+ * Per-system timing record.
1166
+ */
1167
+ interface SystemTiming {
1168
+ readonly name: string;
1169
+ readonly lastMs: number;
1170
+ readonly avgMs: number;
1171
+ readonly minMs: number;
1172
+ readonly maxMs: number;
1173
+ readonly p50Ms: number;
1174
+ readonly p95Ms: number;
1175
+ readonly p99Ms: number;
1176
+ readonly count: number;
1177
+ }
1178
+ /**
1179
+ * Frame-level statistics.
1180
+ */
1181
+ interface FrameStats {
1182
+ readonly frameTimeMs: number;
1183
+ readonly avgFrameMs: number;
1184
+ readonly p50FrameMs: number;
1185
+ readonly p95FrameMs: number;
1186
+ readonly p99FrameMs: number;
1187
+ readonly fps: number;
1188
+ readonly avgFps: number;
1189
+ readonly totalFrames: number;
1190
+ readonly budgetOverruns: number;
1191
+ readonly systemTimings: readonly SystemTiming[];
1192
+ readonly phaseTimings: Readonly<Record<string, number>>;
1193
+ }
1194
+ /**
1195
+ * Budget alert emitted when a phase exceeds its budget.
1196
+ */
1197
+ interface BudgetAlert {
1198
+ readonly phase: LoopPhase;
1199
+ readonly budgetMs: number;
1200
+ readonly actualMs: number;
1201
+ readonly frame: number;
1202
+ }
1203
+ /**
1204
+ * Frame budget manager state.
1205
+ */
1206
+ interface FrameBudgetManager {
1207
+ readonly config: FrameBudgetConfig;
1208
+ readonly stats: FrameStats;
1209
+ readonly alerts: readonly BudgetAlert[];
1210
+ }
1211
+ /**
1212
+ * Creates and activates the frame budget manager.
1213
+ *
1214
+ * @param config - Optional configuration overrides
1215
+ * @returns The frame budget manager
1216
+ *
1217
+ * @example
1218
+ * ```typescript
1219
+ * import { createFrameBudgetManager } from 'blecsd';
1220
+ *
1221
+ * const manager = createFrameBudgetManager({ targetFrameMs: 16.67 });
1222
+ * ```
1223
+ */
1224
+ declare function createFrameBudgetManager(config?: Partial<FrameBudgetConfig>): FrameBudgetManager;
1225
+ /**
1226
+ * Records the execution time of a named system.
1227
+ *
1228
+ * @param name - The system name
1229
+ * @param timeMs - Execution time in milliseconds
1230
+ */
1231
+ declare function recordFrameBudgetSystemTime(name: string, timeMs: number): void;
1232
+ /**
1233
+ * Records phase completion time and checks budget.
1234
+ *
1235
+ * @param phase - The loop phase
1236
+ * @param timeMs - Phase execution time in milliseconds
1237
+ */
1238
+ declare function recordPhaseTime(phase: LoopPhase, timeMs: number): void;
1239
+ /**
1240
+ * Records a complete frame time.
1241
+ *
1242
+ * @param frameTimeMs - Total frame time in milliseconds
1243
+ */
1244
+ declare function recordFrameTime(frameTimeMs: number): void;
1245
+ /**
1246
+ * Wraps a system with automatic timing.
1247
+ *
1248
+ * @param name - The system name for profiling
1249
+ * @param system - The system function to wrap
1250
+ * @returns A wrapped system that records its execution time
1251
+ *
1252
+ * @example
1253
+ * ```typescript
1254
+ * import { profiledSystem } from 'blecsd';
1255
+ *
1256
+ * const timedMovement = profiledSystem('movement', movementSystem);
1257
+ * scheduler.registerSystem(LoopPhase.UPDATE, timedMovement);
1258
+ * ```
1259
+ */
1260
+ declare function profiledSystem(name: string, system: System): System;
1261
+ /**
1262
+ * Gets current frame budget statistics.
1263
+ *
1264
+ * @returns The current stats snapshot
1265
+ */
1266
+ declare function getFrameBudgetStats(): FrameBudgetManager;
1267
+ /**
1268
+ * Registers a callback for budget overrun alerts.
1269
+ *
1270
+ * @param callback - Alert handler
1271
+ */
1272
+ declare function onBudgetAlert(callback: (alert: BudgetAlert) => void): void;
1273
+ /**
1274
+ * Resets all profiling data.
1275
+ */
1276
+ declare function resetFrameBudget(): void;
1277
+ /**
1278
+ * Destroys the frame budget manager.
1279
+ */
1280
+ declare function destroyFrameBudgetManager(): void;
1281
+ /**
1282
+ * Exports metrics as a JSON-serializable object for external analysis.
1283
+ *
1284
+ * @returns Metrics data
1285
+ */
1286
+ declare function exportFrameBudgetMetrics(): Record<string, unknown>;
1287
+
1288
+ /**
1289
+ * Input system for processing keyboard and mouse events.
1290
+ * Handles hit testing, focus management, and event dispatch.
1291
+ * @module systems/inputSystem
1292
+ */
1293
+
1294
+ /**
1295
+ * Input event types that can be queued.
1296
+ */
1297
+ type InputEventType = 'key' | 'mouse';
1298
+ /**
1299
+ * Queued key event.
1300
+ */
1301
+ interface QueuedKeyEvent {
1302
+ type: 'key';
1303
+ event: KeyEvent;
1304
+ timestamp: number;
1305
+ }
1306
+ /**
1307
+ * Queued mouse event.
1308
+ */
1309
+ interface QueuedMouseEvent {
1310
+ type: 'mouse';
1311
+ event: MouseEvent;
1312
+ timestamp: number;
1313
+ }
1314
+ /**
1315
+ * Union of all queued input events.
1316
+ */
1317
+ type QueuedInputEvent = QueuedKeyEvent | QueuedMouseEvent;
1318
+ /**
1319
+ * Result of hit testing a point.
1320
+ */
1321
+ interface HitTestResult {
1322
+ /** Entity that was hit */
1323
+ entity: Entity;
1324
+ /** Local X coordinate within the entity */
1325
+ localX: number;
1326
+ /** Local Y coordinate within the entity */
1327
+ localY: number;
1328
+ /** Z-index of the entity */
1329
+ zIndex: number;
1330
+ }
1331
+ /**
1332
+ * Input system state and configuration.
1333
+ */
1334
+ interface InputSystemState {
1335
+ /** Queue of pending input events */
1336
+ eventQueue: QueuedInputEvent[];
1337
+ /** Entity that currently has mouse capture (for drag operations) */
1338
+ capturedEntity: Entity | null;
1339
+ /** Last known mouse position */
1340
+ lastMouseX: number;
1341
+ lastMouseY: number;
1342
+ /** Entity under the mouse last frame */
1343
+ lastHoveredEntity: Entity | null;
1344
+ /** Global event bus for dispatching UI events */
1345
+ eventBus: EventBus<UIEventMap>;
1346
+ }
1347
+ /**
1348
+ * Global input system state.
1349
+ * Can be accessed and modified for testing or custom input handling.
1350
+ */
1351
+ declare const inputState: InputSystemState;
1352
+ /**
1353
+ * Resets input system state.
1354
+ * Useful for testing or when reinitializing the input system.
1355
+ *
1356
+ * @example
1357
+ * ```typescript
1358
+ * import { resetInputState } from 'blecsd';
1359
+ *
1360
+ * // Clear all pending events and state
1361
+ * resetInputState();
1362
+ * ```
1363
+ */
1364
+ declare function resetInputState(): void;
1365
+ /**
1366
+ * Queues a keyboard event for processing.
1367
+ *
1368
+ * @param event - The parsed key event from the input stream
1369
+ *
1370
+ * @example
1371
+ * ```typescript
1372
+ * import { queueKeyEvent } from 'blecsd';
1373
+ *
1374
+ * // Queue a key event for next frame
1375
+ * queueKeyEvent({ name: 'a', ctrl: false, meta: false, shift: false, raw: 'a' });
1376
+ * ```
1377
+ */
1378
+ declare function queueKeyEvent(event: KeyEvent): void;
1379
+ /**
1380
+ * Queues a mouse event for processing.
1381
+ *
1382
+ * @param event - The parsed mouse event from the input stream
1383
+ *
1384
+ * @example
1385
+ * ```typescript
1386
+ * import { queueMouseEvent } from 'blecsd';
1387
+ *
1388
+ * // Queue a mouse event for next frame
1389
+ * queueMouseEvent({ x: 10, y: 5, button: 'left', action: 'press', raw: '' });
1390
+ * ```
1391
+ */
1392
+ declare function queueMouseEvent(event: MouseEvent): void;
1393
+ /**
1394
+ * Gets the current event queue.
1395
+ * Mainly useful for debugging and testing.
1396
+ */
1397
+ declare function getEventQueue(): readonly QueuedInputEvent[];
1398
+ /**
1399
+ * Clears all queued events.
1400
+ */
1401
+ declare function clearEventQueue(): void;
1402
+ /**
1403
+ * Gets the global input event bus.
1404
+ * Use this to subscribe to UI events from anywhere.
1405
+ *
1406
+ * @returns The global UI event bus
1407
+ *
1408
+ * @example
1409
+ * ```typescript
1410
+ * import { getInputEventBus } from 'blecsd';
1411
+ *
1412
+ * const eventBus = getInputEventBus();
1413
+ * eventBus.on('click', (event) => {
1414
+ * console.log(`Clicked at ${event.x}, ${event.y}`);
1415
+ * });
1416
+ * ```
1417
+ */
1418
+ declare function getInputEventBus(): EventBus<UIEventMap>;
1419
+ /**
1420
+ * Captures mouse events to a specific entity.
1421
+ * While captured, all mouse events are sent to this entity
1422
+ * regardless of hit testing. Used for drag operations.
1423
+ *
1424
+ * @param entity - Entity to capture events to, or null to release
1425
+ *
1426
+ * @example
1427
+ * ```typescript
1428
+ * import { captureMouseTo, releaseMouse } from 'blecsd';
1429
+ *
1430
+ * // Start drag
1431
+ * captureMouseTo(entityId);
1432
+ *
1433
+ * // End drag
1434
+ * releaseMouse();
1435
+ * ```
1436
+ */
1437
+ declare function captureMouseTo(entity: Entity | null): void;
1438
+ /**
1439
+ * Releases mouse capture.
1440
+ */
1441
+ declare function releaseMouse(): void;
1442
+ /**
1443
+ * Checks if an entity is currently capturing mouse events.
1444
+ */
1445
+ declare function isMouseCaptured(): boolean;
1446
+ /**
1447
+ * Gets the entity currently capturing mouse events.
1448
+ */
1449
+ declare function getMouseCaptureEntity(): Entity | null;
1450
+ /**
1451
+ * Tests if a point is inside an entity's bounding box.
1452
+ * Uses Position and Dimensions components.
1453
+ *
1454
+ * @param world - The ECS world
1455
+ * @param eid - Entity to test
1456
+ * @param x - X coordinate to test
1457
+ * @param y - Y coordinate to test
1458
+ * @returns true if point is inside entity bounds
1459
+ *
1460
+ * @example
1461
+ * ```typescript
1462
+ * import { pointInEntity } from 'blecsd';
1463
+ *
1464
+ * if (pointInEntity(world, entity, mouseX, mouseY)) {
1465
+ * console.log('Mouse is over entity');
1466
+ * }
1467
+ * ```
1468
+ */
1469
+ declare function pointInEntity(world: World, eid: Entity, x: number, y: number): boolean;
1470
+ /**
1471
+ * Performs hit testing at a point to find all entities under it.
1472
+ * Returns entities sorted by z-index (highest first).
1473
+ *
1474
+ * @param world - The ECS world
1475
+ * @param x - X coordinate to test
1476
+ * @param y - Y coordinate to test
1477
+ * @returns Array of hit test results, sorted by z-index (highest first)
1478
+ *
1479
+ * @example
1480
+ * ```typescript
1481
+ * import { hitTest } from 'blecsd';
1482
+ *
1483
+ * const hits = hitTest(world, mouseX, mouseY);
1484
+ * if (hits.length > 0) {
1485
+ * const topEntity = hits[0].entity;
1486
+ * console.log(`Top entity at click: ${topEntity}`);
1487
+ * }
1488
+ * ```
1489
+ */
1490
+ declare function hitTest(world: World, x: number, y: number): HitTestResult[];
1491
+ /**
1492
+ * Gets the topmost interactive entity at a point.
1493
+ * Only returns entities that can receive input.
1494
+ *
1495
+ * @param world - The ECS world
1496
+ * @param x - X coordinate to test
1497
+ * @param y - Y coordinate to test
1498
+ * @returns The topmost interactive entity or null
1499
+ */
1500
+ declare function getInteractiveEntityAt(world: World, x: number, y: number): Entity | null;
1501
+ /**
1502
+ * The input system processes all queued input events.
1503
+ * This system should be registered in the INPUT phase (automatically protected).
1504
+ *
1505
+ * The system:
1506
+ * 1. Processes all queued key and mouse events
1507
+ * 2. Updates KeyboardInput and MouseInput components
1508
+ * 3. Performs hit testing for mouse events
1509
+ * 4. Updates Interactive component state (hovered, pressed)
1510
+ * 5. Manages focus changes (click to focus, Tab navigation)
1511
+ * 6. Dispatches UI events to the event bus
1512
+ *
1513
+ * @param world - The ECS world to process
1514
+ * @returns The world (unchanged reference)
1515
+ *
1516
+ * @example
1517
+ * ```typescript
1518
+ * import { createScheduler, inputSystem, registerInputSystem } from 'blecsd';
1519
+ *
1520
+ * const scheduler = createScheduler();
1521
+ * registerInputSystem(scheduler);
1522
+ *
1523
+ * // In game loop
1524
+ * scheduler.run(world, deltaTime);
1525
+ * ```
1526
+ */
1527
+ declare const inputSystem: System;
1528
+ /**
1529
+ * Creates a new input system.
1530
+ *
1531
+ * Factory function that returns the inputSystem.
1532
+ * Useful for cases where you need a fresh reference.
1533
+ *
1534
+ * @returns The input system function
1535
+ *
1536
+ * @example
1537
+ * ```typescript
1538
+ * import { createInputSystem, createScheduler } from 'blecsd';
1539
+ *
1540
+ * const scheduler = createScheduler();
1541
+ * const system = createInputSystem();
1542
+ * // Note: Use registerInputSystem instead for proper INPUT phase registration
1543
+ * ```
1544
+ */
1545
+ declare function createInputSystem(): System;
1546
+ /**
1547
+ * Registers the input system with a scheduler.
1548
+ *
1549
+ * Registers inputSystem in the protected INPUT phase.
1550
+ * This ensures input is always processed first.
1551
+ *
1552
+ * @param scheduler - The scheduler to register with
1553
+ * @param priority - Optional priority within the INPUT phase (default: 0)
1554
+ *
1555
+ * @example
1556
+ * ```typescript
1557
+ * import { createScheduler, registerInputSystem } from 'blecsd';
1558
+ *
1559
+ * const scheduler = createScheduler();
1560
+ * registerInputSystem(scheduler);
1561
+ *
1562
+ * // Input events will now be processed in INPUT phase
1563
+ * scheduler.run(world, deltaTime);
1564
+ * ```
1565
+ */
1566
+ declare function registerInputSystem(scheduler: Scheduler, priority?: number): void;
1567
+ /**
1568
+ * Clears input state for an entity.
1569
+ * Resets KeyboardInput and MouseInput components to default state.
1570
+ *
1571
+ * @param world - The ECS world
1572
+ * @param eid - Entity to clear input state for
1573
+ *
1574
+ * @example
1575
+ * ```typescript
1576
+ * import { clearEntityInput } from 'blecsd';
1577
+ *
1578
+ * // Clear all input state when entity loses focus
1579
+ * clearEntityInput(world, entity);
1580
+ * ```
1581
+ */
1582
+ declare function clearEntityInput(world: World, eid: Entity): void;
1583
+ /**
1584
+ * Query all entities that can receive input.
1585
+ * Returns entities with either Interactive or Focusable components.
1586
+ *
1587
+ * @param world - The ECS world
1588
+ * @returns Array of entity IDs that can receive input
1589
+ */
1590
+ declare function queryInputReceivers(world: World): number[];
1591
+
1592
+ /**
1593
+ * Layout system for computing entity positions and dimensions.
1594
+ * Runs in the LAYOUT phase to pre-compute absolute positions in tree order.
1595
+ * @module systems/layoutSystem
1596
+ */
1597
+
1598
+ /**
1599
+ * Computed Layout component stores the final computed positions and dimensions.
1600
+ * This component is written by the layout system and read by the render system.
1601
+ *
1602
+ * @example
1603
+ * ```typescript
1604
+ * import { ComputedLayout, getComputedLayout } from 'blecsd';
1605
+ *
1606
+ * // After layout system runs, computed values are available
1607
+ * const layout = getComputedLayout(world, entity);
1608
+ * if (layout) {
1609
+ * console.log(`Absolute: (${layout.x}, ${layout.y})`);
1610
+ * console.log(`Size: ${layout.width}x${layout.height}`);
1611
+ * }
1612
+ * ```
1613
+ */
1614
+ declare const ComputedLayout: {
1615
+ /** Computed absolute X position (screen column) */
1616
+ x: Float32Array<ArrayBuffer>;
1617
+ /** Computed absolute Y position (screen row) */
1618
+ y: Float32Array<ArrayBuffer>;
1619
+ /** Computed width in cells */
1620
+ width: Float32Array<ArrayBuffer>;
1621
+ /** Computed height in cells */
1622
+ height: Float32Array<ArrayBuffer>;
1623
+ /** Whether layout is valid (0 = needs recompute, 1 = valid) */
1624
+ valid: Uint8Array<ArrayBuffer>;
1625
+ };
1626
+ /**
1627
+ * Computed layout data returned by getComputedLayout.
1628
+ */
1629
+ interface ComputedLayoutData {
1630
+ readonly x: number;
1631
+ readonly y: number;
1632
+ readonly width: number;
1633
+ readonly height: number;
1634
+ }
1635
+ /**
1636
+ * Gets the computed layout of an entity.
1637
+ *
1638
+ * @param world - The ECS world
1639
+ * @param eid - The entity ID
1640
+ * @returns Computed layout data or undefined if not available
1641
+ *
1642
+ * @example
1643
+ * ```typescript
1644
+ * const layout = getComputedLayout(world, entity);
1645
+ * if (layout) {
1646
+ * console.log(`Position: (${layout.x}, ${layout.y})`);
1647
+ * }
1648
+ * ```
1649
+ */
1650
+ declare function getComputedLayout(world: World, eid: Entity): ComputedLayoutData | undefined;
1651
+ /**
1652
+ * Checks if an entity has a valid computed layout.
1653
+ *
1654
+ * @param world - The ECS world
1655
+ * @param eid - The entity ID
1656
+ * @returns true if the entity has a valid computed layout
1657
+ */
1658
+ declare function hasComputedLayout(world: World, eid: Entity): boolean;
1659
+ /**
1660
+ * Invalidates the computed layout of an entity.
1661
+ * Call this when position or dimensions change to trigger recalculation.
1662
+ *
1663
+ * @param world - The ECS world
1664
+ * @param eid - The entity ID
1665
+ */
1666
+ declare function invalidateLayout(world: World, eid: Entity): void;
1667
+ /**
1668
+ * Layout system that computes absolute positions for all entities.
1669
+ * Runs in tree order (parents before children) to support relative positioning.
1670
+ *
1671
+ * The system:
1672
+ * 1. Finds all root entities (no parent)
1673
+ * 2. Computes layout for each root and its descendants
1674
+ * 3. Handles percentage dimensions relative to parent
1675
+ * 4. Respects min/max constraints
1676
+ * 5. Stores results in ComputedLayout component
1677
+ *
1678
+ * @param world - The ECS world
1679
+ * @returns The world (unchanged)
1680
+ *
1681
+ * @example
1682
+ * ```typescript
1683
+ * import { layoutSystem, createScheduler, LoopPhase } from 'blecsd';
1684
+ *
1685
+ * const scheduler = createScheduler();
1686
+ * scheduler.registerSystem(LoopPhase.LAYOUT, layoutSystem);
1687
+ * ```
1688
+ */
1689
+ declare const layoutSystem: System;
1690
+ /**
1691
+ * Creates the layout system function.
1692
+ * This is an alternative to using the layoutSystem directly for custom configuration.
1693
+ *
1694
+ * @returns A new layout system function
1695
+ *
1696
+ * @example
1697
+ * ```typescript
1698
+ * import { createLayoutSystem, createScheduler, LoopPhase } from 'blecsd';
1699
+ *
1700
+ * const scheduler = createScheduler();
1701
+ * scheduler.registerSystem(LoopPhase.LAYOUT, createLayoutSystem());
1702
+ * ```
1703
+ */
1704
+ declare function createLayoutSystem(): System;
1705
+ /**
1706
+ * Forces a full layout recalculation for all entities.
1707
+ * Call this after major changes like screen resize.
1708
+ *
1709
+ * @param world - The ECS world
1710
+ *
1711
+ * @example
1712
+ * ```typescript
1713
+ * import { invalidateAllLayouts } from 'blecsd';
1714
+ *
1715
+ * // After terminal resize
1716
+ * invalidateAllLayouts(world);
1717
+ * ```
1718
+ */
1719
+ declare function invalidateAllLayouts(world: World): void;
1720
+ /**
1721
+ * Computes layout for a single entity immediately.
1722
+ * Useful for getting layout outside the normal system loop.
1723
+ *
1724
+ * @param world - The ECS world
1725
+ * @param eid - The entity ID
1726
+ * @returns Computed layout data or undefined if entity lacks Position
1727
+ *
1728
+ * @example
1729
+ * ```typescript
1730
+ * import { computeLayoutNow } from 'blecsd';
1731
+ *
1732
+ * const layout = computeLayoutNow(world, entity);
1733
+ * if (layout) {
1734
+ * console.log(`Position: (${layout.x}, ${layout.y})`);
1735
+ * }
1736
+ * ```
1737
+ */
1738
+ declare function computeLayoutNow(world: World, eid: Entity): ComputedLayoutData | undefined;
1739
+ /**
1740
+ * Gets the computed content bounds for an entity (position + dimensions).
1741
+ * Returns the bounding rectangle in screen coordinates.
1742
+ *
1743
+ * @param world - The ECS world
1744
+ * @param eid - The entity ID
1745
+ * @returns Bounding rectangle or undefined
1746
+ *
1747
+ * @example
1748
+ * ```typescript
1749
+ * import { getComputedBounds } from 'blecsd';
1750
+ *
1751
+ * const bounds = getComputedBounds(world, entity);
1752
+ * if (bounds) {
1753
+ * console.log(`Bounds: (${bounds.left}, ${bounds.top}) to (${bounds.right}, ${bounds.bottom})`);
1754
+ * }
1755
+ * ```
1756
+ */
1757
+ declare function getComputedBounds(world: World, eid: Entity): {
1758
+ left: number;
1759
+ top: number;
1760
+ right: number;
1761
+ bottom: number;
1762
+ } | undefined;
1763
+
1764
+ /**
1765
+ * Movement system for updating entity positions based on velocity.
1766
+ * Processes all entities with Velocity component.
1767
+ * @module systems/movementSystem
1768
+ */
1769
+
1770
+ /**
1771
+ * Query all entities with the Velocity component.
1772
+ *
1773
+ * @param world - The ECS world
1774
+ * @returns Array of entity IDs with Velocity component
1775
+ */
1776
+ declare function queryMovement(world: World): number[];
1777
+ /**
1778
+ * Checks if an entity has the Velocity component (via system store).
1779
+ *
1780
+ * @param world - The ECS world
1781
+ * @param eid - Entity to check
1782
+ * @returns true if entity has Velocity component
1783
+ */
1784
+ declare function hasMovementSystem(world: World, eid: number): boolean;
1785
+ /**
1786
+ * Movement system that updates all entities with Velocity component.
1787
+ *
1788
+ * This system should be registered in the PHYSICS phase of the game loop.
1789
+ * It reads delta time from getDeltaTime() which is set by the scheduler.
1790
+ *
1791
+ * For each entity with Velocity, the system:
1792
+ * 1. Applies acceleration to velocity (if Acceleration component present)
1793
+ * 2. Applies friction to velocity
1794
+ * 3. Clamps velocity to max speed
1795
+ * 4. Applies velocity to position (if Position component present)
1796
+ *
1797
+ * @param world - The ECS world to process
1798
+ * @returns The world (unchanged reference)
1799
+ *
1800
+ * @example
1801
+ * ```typescript
1802
+ * import { createScheduler, LoopPhase, movementSystem } from 'blecsd';
1803
+ *
1804
+ * const scheduler = createScheduler();
1805
+ * scheduler.registerSystem(LoopPhase.PHYSICS, movementSystem);
1806
+ *
1807
+ * // In game loop
1808
+ * scheduler.run(world, deltaTime);
1809
+ * ```
1810
+ */
1811
+ declare const movementSystem: System;
1812
+ /**
1813
+ * Creates a new movement system.
1814
+ *
1815
+ * Factory function that returns the movementSystem.
1816
+ *
1817
+ * @returns The movement system function
1818
+ *
1819
+ * @example
1820
+ * ```typescript
1821
+ * import { createMovementSystem, createScheduler, LoopPhase } from 'blecsd';
1822
+ *
1823
+ * const scheduler = createScheduler();
1824
+ * const system = createMovementSystem();
1825
+ * scheduler.registerSystem(LoopPhase.PHYSICS, system);
1826
+ * ```
1827
+ */
1828
+ declare function createMovementSystem(): System;
1829
+ /**
1830
+ * Registers the movement system with a scheduler.
1831
+ *
1832
+ * Convenience function that registers movementSystem in the PHYSICS phase.
1833
+ *
1834
+ * @param scheduler - The scheduler to register with
1835
+ * @param priority - Optional priority within the PHYSICS phase (default: 0)
1836
+ *
1837
+ * @example
1838
+ * ```typescript
1839
+ * import { createScheduler, registerMovementSystem } from 'blecsd';
1840
+ *
1841
+ * const scheduler = createScheduler();
1842
+ * registerMovementSystem(scheduler);
1843
+ *
1844
+ * // Movement updates will now happen in PHYSICS phase
1845
+ * scheduler.run(world, deltaTime);
1846
+ * ```
1847
+ */
1848
+ declare function registerMovementSystem(scheduler: Scheduler, priority?: number): void;
1849
+ /**
1850
+ * Manually update movement for specific entities.
1851
+ *
1852
+ * Useful when you need to update movement outside of the system,
1853
+ * such as in tests or custom update loops.
1854
+ *
1855
+ * @param world - The ECS world
1856
+ * @param entities - Array of entity IDs to update
1857
+ * @param deltaTime - Time elapsed in seconds
1858
+ *
1859
+ * @example
1860
+ * ```typescript
1861
+ * import { updateMovements, queryMovement } from 'blecsd';
1862
+ *
1863
+ * // Manual update (typically use the system instead)
1864
+ * const entities = queryMovement(world);
1865
+ * updateMovements(world, entities, 0.016);
1866
+ * ```
1867
+ */
1868
+ declare function updateMovements(world: World, entities: readonly number[], deltaTime: number): void;
1869
+
1870
+ /**
1871
+ * Output system for writing rendered buffer to terminal.
1872
+ * Runs in the POST_RENDER phase after all rendering is complete.
1873
+ * @module systems/outputSystem
1874
+ */
1875
+
1876
+ /**
1877
+ * Output state maintained across frames.
1878
+ */
1879
+ interface OutputState {
1880
+ /** Last cursor X position (0-indexed) */
1881
+ lastX: number;
1882
+ /** Last cursor Y position (0-indexed) */
1883
+ lastY: number;
1884
+ /** Last foreground color */
1885
+ lastFg: number;
1886
+ /** Last background color */
1887
+ lastBg: number;
1888
+ /** Last attributes */
1889
+ lastAttrs: number;
1890
+ /** Whether we're in alternate screen mode */
1891
+ alternateScreen: boolean;
1892
+ }
1893
+ /**
1894
+ * Creates initial output state.
1895
+ */
1896
+ declare function createOutputState(): OutputState;
1897
+ /**
1898
+ * Generates optimized output for all cell changes.
1899
+ *
1900
+ * @param state - Output state
1901
+ * @param changes - Array of cell changes
1902
+ * @returns ANSI output string
1903
+ *
1904
+ * @example
1905
+ * ```typescript
1906
+ * import { generateOutput, createOutputState } from 'blecsd';
1907
+ *
1908
+ * const state = createOutputState();
1909
+ * const output = generateOutput(state, changes);
1910
+ * process.stdout.write(output);
1911
+ * ```
1912
+ */
1913
+ declare function generateOutput(state: OutputState, changes: readonly CellChange[]): string;
1914
+ /**
1915
+ * Sets the output stream for the output system.
1916
+ *
1917
+ * @param stream - Writable stream (typically process.stdout)
1918
+ *
1919
+ * @example
1920
+ * ```typescript
1921
+ * import { setOutputStream } from 'blecsd';
1922
+ *
1923
+ * setOutputStream(process.stdout);
1924
+ * ```
1925
+ */
1926
+ declare function setOutputStream(stream: Writable): void;
1927
+ /**
1928
+ * Gets the current output stream.
1929
+ *
1930
+ * @returns The current output stream or null
1931
+ */
1932
+ declare function getOutputStream(): Writable | null;
1933
+ /**
1934
+ * Clears the output stream reference.
1935
+ */
1936
+ declare function clearOutputStream(): void;
1937
+ /**
1938
+ * Sets the double buffer for the output system.
1939
+ *
1940
+ * @param db - The double buffer
1941
+ *
1942
+ * @example
1943
+ * ```typescript
1944
+ * import { setOutputBuffer, createDoubleBuffer } from 'blecsd';
1945
+ *
1946
+ * const db = createDoubleBuffer(80, 24);
1947
+ * setOutputBuffer(db);
1948
+ * ```
1949
+ */
1950
+ declare function setOutputBuffer(db: DoubleBufferData): void;
1951
+ /**
1952
+ * Gets the current output buffer.
1953
+ *
1954
+ * @returns The current double buffer or null
1955
+ */
1956
+ declare function getOutputBuffer(): DoubleBufferData | null;
1957
+ /**
1958
+ * Clears the output buffer reference.
1959
+ */
1960
+ declare function clearOutputBuffer(): void;
1961
+ /**
1962
+ * Gets or creates the output state.
1963
+ *
1964
+ * @returns The output state
1965
+ */
1966
+ declare function getOutputState(): OutputState;
1967
+ /**
1968
+ * Resets the output state.
1969
+ */
1970
+ declare function resetOutputState(): void;
1971
+ /**
1972
+ * Output system that writes rendered content to the terminal.
1973
+ *
1974
+ * The system:
1975
+ * 1. Gets minimal updates from the double buffer
1976
+ * 2. Generates optimized ANSI sequences
1977
+ * 3. Writes to the output stream
1978
+ * 4. Swaps buffers and clears dirty regions
1979
+ *
1980
+ * @param world - The ECS world
1981
+ * @returns The world (unchanged)
1982
+ *
1983
+ * @example
1984
+ * ```typescript
1985
+ * import {
1986
+ * outputSystem,
1987
+ * setOutputStream,
1988
+ * setOutputBuffer,
1989
+ * createScheduler,
1990
+ * LoopPhase,
1991
+ * } from 'blecsd';
1992
+ *
1993
+ * // Setup
1994
+ * setOutputStream(process.stdout);
1995
+ * setOutputBuffer(doubleBuffer);
1996
+ *
1997
+ * // Register in POST_RENDER phase
1998
+ * const scheduler = createScheduler();
1999
+ * scheduler.registerSystem(LoopPhase.POST_RENDER, outputSystem);
2000
+ * ```
2001
+ */
2002
+ declare const outputSystem: System;
2003
+ /**
2004
+ * Creates the output system function.
2005
+ *
2006
+ * @returns A new output system function
2007
+ *
2008
+ * @example
2009
+ * ```typescript
2010
+ * import { createOutputSystem, createScheduler, LoopPhase } from 'blecsd';
2011
+ *
2012
+ * const scheduler = createScheduler();
2013
+ * scheduler.registerSystem(LoopPhase.POST_RENDER, createOutputSystem());
2014
+ * ```
2015
+ */
2016
+ declare function createOutputSystem(): System;
2017
+ /**
2018
+ * Writes raw output to the stream.
2019
+ * Bypasses the double buffer for immediate output.
2020
+ *
2021
+ * @param data - String data to write
2022
+ *
2023
+ * @example
2024
+ * ```typescript
2025
+ * import { writeRaw } from 'blecsd';
2026
+ *
2027
+ * // Write raw ANSI sequence
2028
+ * writeRaw('\x1b[2J'); // Clear screen
2029
+ * ```
2030
+ */
2031
+ declare function writeRaw(data: string): void;
2032
+ /**
2033
+ * Hides the terminal cursor.
2034
+ *
2035
+ * @example
2036
+ * ```typescript
2037
+ * import { hideCursor } from 'blecsd';
2038
+ *
2039
+ * hideCursor();
2040
+ * ```
2041
+ */
2042
+ declare function hideCursor(): void;
2043
+ /**
2044
+ * Shows the terminal cursor.
2045
+ *
2046
+ * @example
2047
+ * ```typescript
2048
+ * import { showCursor } from 'blecsd';
2049
+ *
2050
+ * showCursor();
2051
+ * ```
2052
+ */
2053
+ declare function showCursor(): void;
2054
+ /**
2055
+ * Enters alternate screen buffer mode.
2056
+ *
2057
+ * @example
2058
+ * ```typescript
2059
+ * import { enterAlternateScreen } from 'blecsd';
2060
+ *
2061
+ * enterAlternateScreen();
2062
+ * // ... render application ...
2063
+ * leaveAlternateScreen();
2064
+ * ```
2065
+ */
2066
+ declare function enterAlternateScreen(): void;
2067
+ /**
2068
+ * Leaves alternate screen buffer mode.
2069
+ *
2070
+ * @example
2071
+ * ```typescript
2072
+ * import { leaveAlternateScreen } from 'blecsd';
2073
+ *
2074
+ * leaveAlternateScreen();
2075
+ * ```
2076
+ */
2077
+ declare function leaveAlternateScreen(): void;
2078
+ /**
2079
+ * Clears the entire screen.
2080
+ *
2081
+ * @example
2082
+ * ```typescript
2083
+ * import { clearScreen } from 'blecsd';
2084
+ *
2085
+ * clearScreen();
2086
+ * ```
2087
+ */
2088
+ declare function clearScreen(): void;
2089
+ /**
2090
+ * Moves cursor to home position (0, 0).
2091
+ *
2092
+ * @example
2093
+ * ```typescript
2094
+ * import { cursorHome } from 'blecsd';
2095
+ *
2096
+ * cursorHome();
2097
+ * ```
2098
+ */
2099
+ declare function cursorHome(): void;
2100
+ /**
2101
+ * Resets all terminal attributes.
2102
+ *
2103
+ * @example
2104
+ * ```typescript
2105
+ * import { resetAttributes } from 'blecsd';
2106
+ *
2107
+ * resetAttributes();
2108
+ * ```
2109
+ */
2110
+ declare function resetAttributes(): void;
2111
+ /**
2112
+ * Flushes output and resets terminal state.
2113
+ * Call this before exiting the application.
2114
+ *
2115
+ * @example
2116
+ * ```typescript
2117
+ * import { cleanup } from 'blecsd';
2118
+ *
2119
+ * // Before exiting
2120
+ * cleanup();
2121
+ * ```
2122
+ */
2123
+ declare function cleanup(): void;
2124
+
2125
+ /**
2126
+ * Fast panel movement and resizing system.
2127
+ *
2128
+ * Provides instant panel position updates on input with deferred
2129
+ * content re-layout. Uses dirty rect optimization and optional
2130
+ * content simplification during drag for 60fps movement.
2131
+ *
2132
+ * @module systems/panelMovement
2133
+ */
2134
+
2135
+ /**
2136
+ * Resize handle positions.
2137
+ */
2138
+ type ResizeHandle = 'top' | 'bottom' | 'left' | 'right' | 'topLeft' | 'topRight' | 'bottomLeft' | 'bottomRight';
2139
+ /**
2140
+ * Panel movement constraints.
2141
+ */
2142
+ interface PanelConstraints {
2143
+ /** Minimum panel width (default: 4) */
2144
+ readonly minWidth: number;
2145
+ /** Minimum panel height (default: 2) */
2146
+ readonly minHeight: number;
2147
+ /** Maximum panel width (0 = no limit) */
2148
+ readonly maxWidth: number;
2149
+ /** Maximum panel height (0 = no limit) */
2150
+ readonly maxHeight: number;
2151
+ /** Constrain movement to screen bounds */
2152
+ readonly constrainToScreen: boolean;
2153
+ /** Screen width for constraining */
2154
+ readonly screenWidth: number;
2155
+ /** Screen height for constraining */
2156
+ readonly screenHeight: number;
2157
+ /** Snap to grid size (0 = no snap) */
2158
+ readonly snapGrid: number;
2159
+ }
2160
+ /**
2161
+ * Panel movement/resize state.
2162
+ */
2163
+ interface PanelMoveState {
2164
+ /** Currently moving entity */
2165
+ readonly entity: Entity | undefined;
2166
+ /** Whether a move is in progress */
2167
+ readonly isMoving: boolean;
2168
+ /** Whether a resize is in progress */
2169
+ readonly isResizing: boolean;
2170
+ /** Active resize handle */
2171
+ readonly resizeHandle: ResizeHandle | undefined;
2172
+ /** Starting mouse/cursor position */
2173
+ readonly startX: number;
2174
+ readonly startY: number;
2175
+ /** Starting panel position */
2176
+ readonly panelStartX: number;
2177
+ readonly panelStartY: number;
2178
+ /** Starting panel dimensions */
2179
+ readonly panelStartWidth: number;
2180
+ readonly panelStartHeight: number;
2181
+ /** Whether content layout is deferred (simplified rendering during move) */
2182
+ readonly layoutDeferred: boolean;
2183
+ }
2184
+ /**
2185
+ * Configuration for panel movement behavior.
2186
+ */
2187
+ interface PanelMoveConfig {
2188
+ /** Defer content layout during move for performance (default: true) */
2189
+ readonly deferLayout: boolean;
2190
+ /** Show resize outline instead of live resize (default: false) */
2191
+ readonly outlineResize: boolean;
2192
+ /** Number of pixels to move with keyboard (default: 1) */
2193
+ readonly keyboardStep: number;
2194
+ /** Number of pixels to resize with keyboard (default: 1) */
2195
+ readonly keyboardResizeStep: number;
2196
+ }
2197
+ /**
2198
+ * Dirty rectangle representing changed area.
2199
+ */
2200
+ interface DirtyRect {
2201
+ readonly x: number;
2202
+ readonly y: number;
2203
+ readonly width: number;
2204
+ readonly height: number;
2205
+ }
2206
+ /**
2207
+ * Result of a panel move or resize operation.
2208
+ */
2209
+ interface MoveResult {
2210
+ /** New position X */
2211
+ readonly x: number;
2212
+ /** New position Y */
2213
+ readonly y: number;
2214
+ /** New width (for resize) */
2215
+ readonly width: number;
2216
+ /** New height (for resize) */
2217
+ readonly height: number;
2218
+ /** Dirty rectangles that need redrawing */
2219
+ readonly dirtyRects: readonly DirtyRect[];
2220
+ /** Whether the operation was clamped by constraints */
2221
+ readonly clamped: boolean;
2222
+ }
2223
+ /**
2224
+ * Creates initial panel move state.
2225
+ *
2226
+ * @returns Fresh move state
2227
+ *
2228
+ * @example
2229
+ * ```typescript
2230
+ * import { createPanelMoveState } from 'blecsd';
2231
+ *
2232
+ * const moveState = createPanelMoveState();
2233
+ * ```
2234
+ */
2235
+ declare function createPanelMoveState(): PanelMoveState;
2236
+ /**
2237
+ * Creates panel move configuration with defaults.
2238
+ *
2239
+ * @param config - Partial overrides
2240
+ * @returns Full configuration
2241
+ */
2242
+ declare function createPanelMoveConfig(config?: Partial<PanelMoveConfig>): PanelMoveConfig;
2243
+ /**
2244
+ * Creates panel constraints with defaults.
2245
+ *
2246
+ * @param constraints - Partial overrides
2247
+ * @returns Full constraints
2248
+ */
2249
+ declare function createPanelConstraints(constraints?: Partial<PanelConstraints>): PanelConstraints;
2250
+ /**
2251
+ * Begins a panel move operation.
2252
+ *
2253
+ * @param state - Current move state
2254
+ * @param entity - Entity to move
2255
+ * @param mouseX - Starting mouse X
2256
+ * @param mouseY - Starting mouse Y
2257
+ * @param panelX - Current panel X position
2258
+ * @param panelY - Current panel Y position
2259
+ * @param panelWidth - Current panel width
2260
+ * @param panelHeight - Current panel height
2261
+ * @param config - Move configuration
2262
+ * @returns Updated state
2263
+ *
2264
+ * @example
2265
+ * ```typescript
2266
+ * import { createPanelMoveState, beginMove } from 'blecsd';
2267
+ *
2268
+ * let state = createPanelMoveState();
2269
+ * state = beginMove(state, eid, mouseX, mouseY, panelX, panelY, 30, 10);
2270
+ * ```
2271
+ */
2272
+ declare function beginMove(state: PanelMoveState, entity: Entity, mouseX: number, mouseY: number, panelX: number, panelY: number, panelWidth: number, panelHeight: number, config?: Partial<PanelMoveConfig>): PanelMoveState;
2273
+ /**
2274
+ * Begins a panel resize operation.
2275
+ *
2276
+ * @param state - Current move state
2277
+ * @param entity - Entity to resize
2278
+ * @param handle - Resize handle being dragged
2279
+ * @param mouseX - Starting mouse X
2280
+ * @param mouseY - Starting mouse Y
2281
+ * @param panelX - Current panel X
2282
+ * @param panelY - Current panel Y
2283
+ * @param panelWidth - Current panel width
2284
+ * @param panelHeight - Current panel height
2285
+ * @param config - Move configuration
2286
+ * @returns Updated state
2287
+ */
2288
+ declare function beginResize(state: PanelMoveState, entity: Entity, handle: ResizeHandle, mouseX: number, mouseY: number, panelX: number, panelY: number, panelWidth: number, panelHeight: number, config?: Partial<PanelMoveConfig>): PanelMoveState;
2289
+ /**
2290
+ * Updates a panel move with new cursor position.
2291
+ * Returns the new panel position with constraints applied.
2292
+ *
2293
+ * @param state - Current move state
2294
+ * @param mouseX - Current mouse X
2295
+ * @param mouseY - Current mouse Y
2296
+ * @param constraints - Panel constraints
2297
+ * @returns Move result with new position and dirty rects
2298
+ *
2299
+ * @example
2300
+ * ```typescript
2301
+ * import { updateMove, createPanelConstraints } from 'blecsd';
2302
+ *
2303
+ * const result = updateMove(state, mouseX, mouseY, createPanelConstraints());
2304
+ * setPosition(world, eid, result.x, result.y);
2305
+ * ```
2306
+ */
2307
+ declare function updateMove(state: PanelMoveState, mouseX: number, mouseY: number, constraints?: Partial<PanelConstraints>): MoveResult;
2308
+ declare function updateResize(state: PanelMoveState, mouseX: number, mouseY: number, constraints?: Partial<PanelConstraints>): MoveResult;
2309
+ /**
2310
+ * Ends the current move or resize operation.
2311
+ *
2312
+ * @param state - Current move state
2313
+ * @returns Reset state
2314
+ */
2315
+ declare function endMoveOrResize(state: PanelMoveState): PanelMoveState;
2316
+ /**
2317
+ * Cancels the current move or resize, returning to original position.
2318
+ *
2319
+ * @param state - Current move state
2320
+ * @returns Object with original position and reset state
2321
+ */
2322
+ declare function cancelMoveOrResize(state: PanelMoveState): {
2323
+ state: PanelMoveState;
2324
+ restoreX: number;
2325
+ restoreY: number;
2326
+ restoreWidth: number;
2327
+ restoreHeight: number;
2328
+ };
2329
+ /**
2330
+ * Moves a panel by keyboard step amount.
2331
+ *
2332
+ * @param x - Current X position
2333
+ * @param y - Current Y position
2334
+ * @param width - Panel width
2335
+ * @param height - Panel height
2336
+ * @param direction - Movement direction
2337
+ * @param step - Step amount
2338
+ * @param constraints - Panel constraints
2339
+ * @returns New position
2340
+ */
2341
+ declare function keyboardMove(x: number, y: number, width: number, height: number, direction: 'up' | 'down' | 'left' | 'right', step: number, constraints?: Partial<PanelConstraints>): {
2342
+ x: number;
2343
+ y: number;
2344
+ };
2345
+ /**
2346
+ * Resizes a panel by keyboard step amount.
2347
+ *
2348
+ * @param width - Current width
2349
+ * @param height - Current height
2350
+ * @param direction - Resize direction
2351
+ * @param step - Step amount
2352
+ * @param constraints - Panel constraints
2353
+ * @returns New dimensions
2354
+ */
2355
+ declare function keyboardResize(width: number, height: number, direction: 'grow-horizontal' | 'shrink-horizontal' | 'grow-vertical' | 'shrink-vertical', step: number, constraints?: Partial<PanelConstraints>): {
2356
+ width: number;
2357
+ height: number;
2358
+ };
2359
+ /**
2360
+ * Detects which resize handle a click position corresponds to.
2361
+ *
2362
+ * @param clickX - Click X relative to panel
2363
+ * @param clickY - Click Y relative to panel
2364
+ * @param panelWidth - Panel width
2365
+ * @param panelHeight - Panel height
2366
+ * @param borderSize - Size of the resize border area (default: 1)
2367
+ * @returns The resize handle, or undefined if not on a border
2368
+ */
2369
+ declare function detectResizeHandle(clickX: number, clickY: number, panelWidth: number, panelHeight: number, borderSize?: number): ResizeHandle | undefined;
2370
+ /**
2371
+ * Merges overlapping dirty rectangles for efficient redraw.
2372
+ *
2373
+ * @param rects - Array of dirty rectangles
2374
+ * @returns Merged bounding rectangle
2375
+ */
2376
+ declare function mergeDirtyRects(rects: readonly DirtyRect[]): DirtyRect | undefined;
2377
+
2378
+ /**
2379
+ * Particle system for spawning, updating, and removing particles.
2380
+ *
2381
+ * Processes emitters (rate-based and burst-based spawning) and
2382
+ * updates particle age, position, and velocity each frame.
2383
+ *
2384
+ * @module systems/particleSystem
2385
+ */
2386
+
2387
+ /**
2388
+ * Function that provides entity IDs to iterate over.
2389
+ * User supplies this because blECSd doesn't own a global query registry.
2390
+ */
2391
+ type EntityProvider = (world: World) => ReadonlyArray<Entity>;
2392
+ /**
2393
+ * Configuration for the particle system.
2394
+ */
2395
+ interface ParticleSystemConfig {
2396
+ /** Provides emitter entities each frame */
2397
+ readonly emitters: EntityProvider;
2398
+ /** Provides particle entities each frame */
2399
+ readonly particles: EntityProvider;
2400
+ /** Maximum concurrent particles (default: 1000) */
2401
+ readonly maxParticles?: number;
2402
+ }
2403
+ /**
2404
+ * Spawns a single particle from an emitter at a random angle within the spread.
2405
+ *
2406
+ * @param world - The ECS world
2407
+ * @param emitterId - The emitter entity ID
2408
+ * @param appearance - Visual appearance config
2409
+ * @returns The spawned particle entity ID, or -1 if spawn failed
2410
+ */
2411
+ declare function spawnParticle(world: World, emitterId: Entity, appearance: EmitterAppearance): Entity;
2412
+ /**
2413
+ * Triggers a burst of particles from an emitter.
2414
+ *
2415
+ * @param world - The ECS world
2416
+ * @param emitterId - The emitter entity ID
2417
+ * @param count - Number of particles to emit (default: emitter's burstCount)
2418
+ * @param maxParticles - Maximum total particles allowed (default: 1000)
2419
+ * @param currentCount - Current total particle count
2420
+ * @returns Array of spawned particle entity IDs
2421
+ *
2422
+ * @example
2423
+ * ```typescript
2424
+ * import { burstParticles } from 'blecsd';
2425
+ *
2426
+ * const particles = burstParticles(world, emitterEntity, 20);
2427
+ * ```
2428
+ */
2429
+ declare function burstParticles(world: World, emitterId: Entity, count?: number, maxParticles?: number, currentCount?: number): Entity[];
2430
+ /**
2431
+ * Ages a particle and updates its velocity for gravity.
2432
+ *
2433
+ * @param world - The ECS world
2434
+ * @param eid - The particle entity ID
2435
+ * @param delta - Time elapsed in seconds
2436
+ */
2437
+ declare function ageParticle(world: World, eid: Entity, delta: number): void;
2438
+ /**
2439
+ * Updates a particle's position based on its velocity.
2440
+ *
2441
+ * @param world - The ECS world
2442
+ * @param eid - The particle entity ID
2443
+ * @param delta - Time elapsed in seconds
2444
+ */
2445
+ declare function moveParticle(world: World, eid: Entity, delta: number): void;
2446
+ /**
2447
+ * Removes a dead particle and cleans up tracking.
2448
+ *
2449
+ * @param world - The ECS world
2450
+ * @param eid - The particle entity ID
2451
+ */
2452
+ declare function killParticle(world: World, eid: Entity): void;
2453
+ declare function createParticleSystem(config: ParticleSystemConfig): System;
2454
+
2455
+ /**
2456
+ * Render system for drawing entities to the screen buffer.
2457
+ * Runs in the RENDER phase after layout computation.
2458
+ * @module systems/renderSystem
2459
+ */
2460
+
2461
+ /**
2462
+ * Render context passed to render functions.
2463
+ */
2464
+ interface RenderContext {
2465
+ /** The ECS world */
2466
+ readonly world: World;
2467
+ /** The screen buffer to render to */
2468
+ readonly buffer: ScreenBufferData;
2469
+ /** The double buffer for dirty tracking */
2470
+ readonly doubleBuffer: DoubleBufferData;
2471
+ }
2472
+ /**
2473
+ * Computed bounds for an entity.
2474
+ */
2475
+ interface EntityBounds {
2476
+ readonly x: number;
2477
+ readonly y: number;
2478
+ readonly width: number;
2479
+ readonly height: number;
2480
+ }
2481
+ /**
2482
+ * Renders the background fill for an entity.
2483
+ *
2484
+ * @param ctx - Render context
2485
+ * @param eid - Entity ID
2486
+ * @param bounds - Entity bounds
2487
+ *
2488
+ * @example
2489
+ * ```typescript
2490
+ * import { renderBackground } from 'blecsd';
2491
+ *
2492
+ * renderBackground(ctx, entity, bounds);
2493
+ * ```
2494
+ */
2495
+ declare function renderBackground(ctx: RenderContext, eid: Entity, bounds: EntityBounds): void;
2496
+ /**
2497
+ * Renders the border for an entity.
2498
+ *
2499
+ * @param ctx - Render context
2500
+ * @param eid - Entity ID
2501
+ * @param bounds - Entity bounds
2502
+ *
2503
+ * @example
2504
+ * ```typescript
2505
+ * import { renderBorder } from 'blecsd';
2506
+ *
2507
+ * renderBorder(ctx, entity, bounds);
2508
+ * ```
2509
+ */
2510
+ declare function renderBorder(ctx: RenderContext, eid: Entity, bounds: EntityBounds): void;
2511
+ /**
2512
+ * Renders the content area of an entity.
2513
+ * This is a placeholder that can be extended for specific content types.
2514
+ *
2515
+ * @param ctx - Render context
2516
+ * @param eid - Entity ID
2517
+ * @param contentBounds - Content area bounds (inside border)
2518
+ *
2519
+ * @example
2520
+ * ```typescript
2521
+ * import { renderContent } from 'blecsd';
2522
+ *
2523
+ * renderContent(ctx, entity, contentBounds);
2524
+ * ```
2525
+ */
2526
+ declare function renderContent(_ctx: RenderContext, _eid: Entity, _contentBounds: EntityBounds): void;
2527
+ /**
2528
+ * Renders a scrollbar for an entity.
2529
+ * Currently a placeholder for future scrollable content support.
2530
+ *
2531
+ * @param ctx - Render context
2532
+ * @param eid - Entity ID
2533
+ * @param bounds - Entity bounds
2534
+ *
2535
+ * @example
2536
+ * ```typescript
2537
+ * import { renderScrollbar } from 'blecsd';
2538
+ *
2539
+ * renderScrollbar(ctx, entity, bounds);
2540
+ * ```
2541
+ */
2542
+ declare function renderScrollbar(_ctx: RenderContext, _eid: Entity, _bounds: EntityBounds): void;
2543
+ /**
2544
+ * Sets the double buffer for the render system.
2545
+ * Must be called before running the render system.
2546
+ *
2547
+ * @param db - The double buffer to render to
2548
+ *
2549
+ * @example
2550
+ * ```typescript
2551
+ * import { setRenderBuffer, createDoubleBuffer } from 'blecsd';
2552
+ *
2553
+ * const db = createDoubleBuffer(80, 24);
2554
+ * setRenderBuffer(db);
2555
+ * ```
2556
+ */
2557
+ declare function setRenderBuffer(db: DoubleBufferData): void;
2558
+ /**
2559
+ * Gets the current render buffer.
2560
+ *
2561
+ * @returns The current double buffer or null
2562
+ */
2563
+ declare function getRenderBuffer(): DoubleBufferData | null;
2564
+ /**
2565
+ * Clears the render buffer reference.
2566
+ */
2567
+ declare function clearRenderBuffer(): void;
2568
+ /**
2569
+ * Render system that draws visible, dirty entities to the screen buffer.
2570
+ * Entities are rendered in z-index order (lower z first, higher z on top).
2571
+ *
2572
+ * The system:
2573
+ * 1. Queries all entities with Position and Renderable
2574
+ * 2. Filters to visible, dirty entities
2575
+ * 3. Sorts by z-index
2576
+ * 4. Renders each entity (background, border, content)
2577
+ * 5. Marks entities as clean
2578
+ *
2579
+ * @param world - The ECS world
2580
+ * @returns The world (unchanged)
2581
+ *
2582
+ * @example
2583
+ * ```typescript
2584
+ * import { renderSystem, setRenderBuffer, createScheduler, LoopPhase } from 'blecsd';
2585
+ *
2586
+ * const scheduler = createScheduler();
2587
+ * scheduler.registerSystem(LoopPhase.RENDER, renderSystem);
2588
+ *
2589
+ * // Before running, set the render buffer
2590
+ * setRenderBuffer(doubleBuffer);
2591
+ * scheduler.run(world, deltaTime);
2592
+ * ```
2593
+ */
2594
+ declare const renderSystem: System;
2595
+ /**
2596
+ * Creates the render system function.
2597
+ * This is an alternative to using the renderSystem directly for custom configuration.
2598
+ *
2599
+ * @returns A new render system function
2600
+ *
2601
+ * @example
2602
+ * ```typescript
2603
+ * import { createRenderSystem, createScheduler, LoopPhase } from 'blecsd';
2604
+ *
2605
+ * const scheduler = createScheduler();
2606
+ * scheduler.registerSystem(LoopPhase.RENDER, createRenderSystem());
2607
+ * ```
2608
+ */
2609
+ declare function createRenderSystem(): System;
2610
+ /**
2611
+ * Renders text to a buffer at the specified position.
2612
+ * Utility function for widgets to render text content.
2613
+ *
2614
+ * @param buffer - Screen buffer
2615
+ * @param x - X position
2616
+ * @param y - Y position
2617
+ * @param text - Text to render
2618
+ * @param fg - Foreground color
2619
+ * @param bg - Background color
2620
+ * @param attrs - Text attributes
2621
+ * @returns Number of characters written
2622
+ *
2623
+ * @example
2624
+ * ```typescript
2625
+ * import { renderText, Attr } from 'blecsd';
2626
+ *
2627
+ * renderText(buffer, 10, 5, 'Hello', 0xffffffff, 0x000000ff, Attr.BOLD);
2628
+ * ```
2629
+ */
2630
+ declare function renderText(buffer: ScreenBufferData, x: number, y: number, text: string, fg: number, bg: number, attrs?: number): number;
2631
+ /**
2632
+ * Renders a filled rectangle to a buffer.
2633
+ * Utility function for widgets.
2634
+ *
2635
+ * @param buffer - Screen buffer
2636
+ * @param x - X position
2637
+ * @param y - Y position
2638
+ * @param width - Rectangle width
2639
+ * @param height - Rectangle height
2640
+ * @param cell - Cell to fill with
2641
+ *
2642
+ * @example
2643
+ * ```typescript
2644
+ * import { renderRect, createCell } from 'blecsd';
2645
+ *
2646
+ * renderRect(buffer, 10, 5, 20, 10, createCell(' ', 0xffffffff, 0x0000ffff));
2647
+ * ```
2648
+ */
2649
+ declare function renderRect(buffer: ScreenBufferData, x: number, y: number, width: number, height: number, cell: Cell): void;
2650
+ /**
2651
+ * Marks all entities as dirty, forcing a full re-render.
2652
+ *
2653
+ * @param world - The ECS world
2654
+ *
2655
+ * @example
2656
+ * ```typescript
2657
+ * import { markAllDirty } from 'blecsd';
2658
+ *
2659
+ * // Force re-render of all entities
2660
+ * markAllDirty(world);
2661
+ * ```
2662
+ */
2663
+ declare function markAllDirty(world: World): void;
2664
+
2665
+ /**
2666
+ * Smooth Animated Scrolling
2667
+ *
2668
+ * Provides butter-smooth scroll animations with momentum/inertia physics.
2669
+ * Supports velocity-based scrolling, spring-to-boundary behavior, and
2670
+ * graceful frame skipping under load.
2671
+ *
2672
+ * @module systems/smoothScroll
2673
+ */
2674
+
2675
+ /**
2676
+ * Scroll physics configuration.
2677
+ */
2678
+ interface ScrollPhysicsConfig {
2679
+ /** Friction coefficient (0-1, lower = more momentum, default: 0.92) */
2680
+ readonly friction: number;
2681
+ /** Minimum velocity before stopping (default: 0.1) */
2682
+ readonly minVelocity: number;
2683
+ /** Maximum velocity (default: 200) */
2684
+ readonly maxVelocity: number;
2685
+ /** Velocity multiplier for input (default: 1) */
2686
+ readonly sensitivity: number;
2687
+ /** Spring stiffness for overscroll bounce (default: 0.3) */
2688
+ readonly springStiffness: number;
2689
+ /** Spring damping for overscroll bounce (default: 0.8) */
2690
+ readonly springDamping: number;
2691
+ /** Maximum overscroll distance (default: 50) */
2692
+ readonly maxOverscroll: number;
2693
+ /** Whether to enable momentum scrolling (default: true) */
2694
+ readonly enableMomentum: boolean;
2695
+ /** Whether to enable overscroll bounce (default: true) */
2696
+ readonly enableBounce: boolean;
2697
+ }
2698
+ /**
2699
+ * Scroll animation state for a single entity.
2700
+ */
2701
+ interface ScrollAnimationState {
2702
+ /** Current scroll position */
2703
+ scrollX: number;
2704
+ scrollY: number;
2705
+ /** Current scroll velocity */
2706
+ velocityX: number;
2707
+ velocityY: number;
2708
+ /** Content bounds */
2709
+ contentWidth: number;
2710
+ contentHeight: number;
2711
+ /** Viewport bounds */
2712
+ viewportWidth: number;
2713
+ viewportHeight: number;
2714
+ /** Whether currently animating */
2715
+ isAnimating: boolean;
2716
+ /** Whether user is actively scrolling (input held) */
2717
+ isUserScrolling: boolean;
2718
+ /** Target scroll position (for smooth scrollTo) */
2719
+ targetX: number | null;
2720
+ targetY: number | null;
2721
+ }
2722
+ /**
2723
+ * Scroll event data.
2724
+ */
2725
+ interface ScrollEvent {
2726
+ /** Entity being scrolled */
2727
+ readonly eid: Entity;
2728
+ /** Scroll delta X */
2729
+ readonly deltaX: number;
2730
+ /** Scroll delta Y */
2731
+ readonly deltaY: number;
2732
+ /** Current scroll position X */
2733
+ readonly scrollX: number;
2734
+ /** Current scroll position Y */
2735
+ readonly scrollY: number;
2736
+ /** Whether momentum is active */
2737
+ readonly isMomentum: boolean;
2738
+ }
2739
+ /**
2740
+ * Creates or gets scroll animation state for an entity.
2741
+ *
2742
+ * @param eid - Entity ID
2743
+ * @param contentWidth - Total content width
2744
+ * @param contentHeight - Total content height
2745
+ * @param viewportWidth - Viewport width
2746
+ * @param viewportHeight - Viewport height
2747
+ * @returns Scroll animation state
2748
+ *
2749
+ * @example
2750
+ * ```typescript
2751
+ * const state = getScrollState(entity, 1000, 5000, 80, 24);
2752
+ * ```
2753
+ */
2754
+ declare function getScrollState(eid: Entity, contentWidth: number, contentHeight: number, viewportWidth: number, viewportHeight: number): ScrollAnimationState;
2755
+ /**
2756
+ * Removes scroll state for an entity.
2757
+ *
2758
+ * @param eid - Entity ID
2759
+ */
2760
+ declare function removeScrollState(eid: Entity): void;
2761
+ /**
2762
+ * Clears all scroll states. Used for testing.
2763
+ * @internal
2764
+ */
2765
+ declare function clearAllScrollStates(): void;
2766
+ /**
2767
+ * Applies a scroll impulse (e.g., from mouse wheel or keyboard).
2768
+ *
2769
+ * @param eid - Entity to scroll
2770
+ * @param deltaX - Horizontal scroll amount
2771
+ * @param deltaY - Vertical scroll amount
2772
+ * @param physics - Physics configuration
2773
+ *
2774
+ * @example
2775
+ * ```typescript
2776
+ * // Mouse wheel scroll
2777
+ * applyScrollImpulse(entity, 0, -3, physicsConfig);
2778
+ *
2779
+ * // Page down
2780
+ * applyScrollImpulse(entity, 0, 24, physicsConfig);
2781
+ * ```
2782
+ */
2783
+ declare function applyScrollImpulse(eid: Entity, deltaX: number, deltaY: number, physics?: Partial<ScrollPhysicsConfig>): void;
2784
+ /**
2785
+ * Smoothly scrolls to a target position.
2786
+ *
2787
+ * @param eid - Entity to scroll
2788
+ * @param targetX - Target X scroll position (null = don't change)
2789
+ * @param targetY - Target Y scroll position (null = don't change)
2790
+ *
2791
+ * @example
2792
+ * ```typescript
2793
+ * // Scroll to top
2794
+ * smoothScrollTo(entity, null, 0);
2795
+ *
2796
+ * // Scroll to bottom
2797
+ * smoothScrollTo(entity, null, maxScroll);
2798
+ * ```
2799
+ */
2800
+ declare function smoothScrollTo(eid: Entity, targetX: number | null, targetY: number | null): void;
2801
+ /**
2802
+ * Sets scroll position immediately without animation.
2803
+ *
2804
+ * @param eid - Entity to scroll
2805
+ * @param x - X scroll position
2806
+ * @param y - Y scroll position
2807
+ */
2808
+ declare function setScrollImmediate(eid: Entity, x: number, y: number): void;
2809
+ /**
2810
+ * Marks the start of user scrolling (e.g., mouse drag).
2811
+ *
2812
+ * @param eid - Entity being scrolled
2813
+ */
2814
+ declare function startUserScroll(eid: Entity): void;
2815
+ /**
2816
+ * Marks the end of user scrolling, enabling momentum.
2817
+ *
2818
+ * @param eid - Entity being scrolled
2819
+ * @param velocityX - Release velocity X
2820
+ * @param velocityY - Release velocity Y
2821
+ */
2822
+ declare function endUserScroll(eid: Entity, velocityX: number, velocityY: number): void;
2823
+ declare function updateScrollPhysics(state: ScrollAnimationState, dt: number, physics?: Partial<ScrollPhysicsConfig>): boolean;
2824
+ /**
2825
+ * Checks if an entity has an active scroll animation.
2826
+ *
2827
+ * @param eid - Entity to check
2828
+ * @returns True if the entity is currently scrolling
2829
+ */
2830
+ declare function isScrolling(eid: Entity): boolean;
2831
+ /**
2832
+ * Gets the current scroll position of an entity.
2833
+ *
2834
+ * @param eid - Entity to query
2835
+ * @returns Scroll position or null if no scroll state
2836
+ */
2837
+ declare function getScrollPosition(eid: Entity): {
2838
+ x: number;
2839
+ y: number;
2840
+ } | null;
2841
+ /**
2842
+ * Creates a smooth scroll system that updates all active scroll animations.
2843
+ *
2844
+ * @param physics - Physics configuration
2845
+ * @returns System function
2846
+ *
2847
+ * @example
2848
+ * ```typescript
2849
+ * import { createSmoothScrollSystem } from 'blecsd';
2850
+ *
2851
+ * const scrollSystem = createSmoothScrollSystem({
2852
+ * friction: 0.92,
2853
+ * enableMomentum: true,
2854
+ * enableBounce: true,
2855
+ * });
2856
+ *
2857
+ * scheduler.registerSystem(LoopPhase.ANIMATION, scrollSystem);
2858
+ * ```
2859
+ */
2860
+ declare function createSmoothScrollSystem(physics?: Partial<ScrollPhysicsConfig>): System;
2861
+
2862
+ /**
2863
+ * Spatial hash grid for O(1) collision lookups.
2864
+ *
2865
+ * Partitions 2D space into a uniform grid where each cell tracks
2866
+ * which entities overlap it. Enables efficient broad-phase collision
2867
+ * detection by only checking entities in the same or adjacent cells.
2868
+ *
2869
+ * @module systems/spatialHash
2870
+ */
2871
+
2872
+ /**
2873
+ * Configuration for the spatial hash grid.
2874
+ */
2875
+ interface SpatialHashConfig {
2876
+ /** Width of each cell in world units (default: 8) */
2877
+ readonly cellSize: number;
2878
+ /** Initial number of cells in the grid (default: 256) */
2879
+ readonly initialCapacity: number;
2880
+ }
2881
+ /**
2882
+ * A cell coordinate in the spatial hash grid.
2883
+ */
2884
+ interface CellCoord {
2885
+ readonly cx: number;
2886
+ readonly cy: number;
2887
+ }
2888
+ /**
2889
+ * Spatial hash grid data structure.
2890
+ */
2891
+ interface SpatialHashGrid {
2892
+ /** Cell size in world units */
2893
+ readonly cellSize: number;
2894
+ /** Map from cell key to set of entity IDs */
2895
+ readonly cells: Map<number, Set<number>>;
2896
+ /** Map from entity ID to set of cell keys it occupies */
2897
+ readonly entityCells: Map<number, Set<number>>;
2898
+ }
2899
+ /**
2900
+ * Statistics about the spatial hash grid.
2901
+ */
2902
+ interface SpatialHashStats {
2903
+ readonly cellCount: number;
2904
+ readonly entityCount: number;
2905
+ readonly averageEntitiesPerCell: number;
2906
+ readonly maxEntitiesInCell: number;
2907
+ }
2908
+ /** Default cell size */
2909
+ declare const DEFAULT_CELL_SIZE = 8;
2910
+ /**
2911
+ * Creates a new spatial hash grid.
2912
+ *
2913
+ * @param config - Optional configuration
2914
+ * @returns A new spatial hash grid
2915
+ *
2916
+ * @example
2917
+ * ```typescript
2918
+ * import { createSpatialHash } from 'blecsd';
2919
+ *
2920
+ * const grid = createSpatialHash({ cellSize: 4 });
2921
+ * ```
2922
+ */
2923
+ declare function createSpatialHash(config?: Partial<SpatialHashConfig>): SpatialHashGrid;
2924
+ /**
2925
+ * Gets the cell coordinate for a world position.
2926
+ *
2927
+ * @param grid - The spatial hash grid
2928
+ * @param x - World X coordinate
2929
+ * @param y - World Y coordinate
2930
+ * @returns The cell coordinate
2931
+ *
2932
+ * @example
2933
+ * ```typescript
2934
+ * import { createSpatialHash, worldToCell } from 'blecsd';
2935
+ *
2936
+ * const grid = createSpatialHash({ cellSize: 8 });
2937
+ * const cell = worldToCell(grid, 15, 23);
2938
+ * // cell = { cx: 1, cy: 2 }
2939
+ * ```
2940
+ */
2941
+ declare function worldToCell(grid: SpatialHashGrid, x: number, y: number): CellCoord;
2942
+ /**
2943
+ * Inserts an entity into the spatial hash at the given position and size.
2944
+ *
2945
+ * @param grid - The spatial hash grid
2946
+ * @param eid - Entity ID
2947
+ * @param x - Entity X position
2948
+ * @param y - Entity Y position
2949
+ * @param width - Entity width (default: 1)
2950
+ * @param height - Entity height (default: 1)
2951
+ *
2952
+ * @example
2953
+ * ```typescript
2954
+ * import { createSpatialHash, insertEntity } from 'blecsd';
2955
+ *
2956
+ * const grid = createSpatialHash();
2957
+ * insertEntity(grid, entity, 10, 20, 2, 3);
2958
+ * ```
2959
+ */
2960
+ declare function insertEntity(grid: SpatialHashGrid, eid: Entity, x: number, y: number, width?: number, height?: number): void;
2961
+ /**
2962
+ * Removes an entity from the spatial hash.
2963
+ *
2964
+ * @param grid - The spatial hash grid
2965
+ * @param eid - Entity ID to remove
2966
+ *
2967
+ * @example
2968
+ * ```typescript
2969
+ * import { removeEntityFromGrid } from 'blecsd';
2970
+ *
2971
+ * removeEntityFromGrid(grid, entity);
2972
+ * ```
2973
+ */
2974
+ declare function removeEntityFromGrid(grid: SpatialHashGrid, eid: Entity): void;
2975
+ /**
2976
+ * Gets all entities in the same cell(s) as the given position/area.
2977
+ * This is the core broad-phase query for collision detection.
2978
+ *
2979
+ * @param grid - The spatial hash grid
2980
+ * @param x - Query X position
2981
+ * @param y - Query Y position
2982
+ * @param width - Query width (default: 1)
2983
+ * @param height - Query height (default: 1)
2984
+ * @returns Set of entity IDs that may overlap the query area
2985
+ *
2986
+ * @example
2987
+ * ```typescript
2988
+ * import { createSpatialHash, queryArea } from 'blecsd';
2989
+ *
2990
+ * const nearby = queryArea(grid, playerX, playerY, 2, 2);
2991
+ * for (const eid of nearby) {
2992
+ * // Check narrow-phase collision
2993
+ * }
2994
+ * ```
2995
+ */
2996
+ declare function queryArea(grid: SpatialHashGrid, x: number, y: number, width?: number, height?: number): ReadonlySet<number>;
2997
+ /**
2998
+ * Gets potential collision candidates for an entity.
2999
+ * Returns all entities in the same cells, excluding the entity itself.
3000
+ *
3001
+ * @param grid - The spatial hash grid
3002
+ * @param eid - Entity to find candidates for
3003
+ * @returns Set of entity IDs that may collide with the given entity
3004
+ *
3005
+ * @example
3006
+ * ```typescript
3007
+ * import { getNearbyEntities } from 'blecsd';
3008
+ *
3009
+ * const candidates = getNearbyEntities(grid, player);
3010
+ * for (const other of candidates) {
3011
+ * // Narrow-phase collision check
3012
+ * }
3013
+ * ```
3014
+ */
3015
+ declare function getNearbyEntities(grid: SpatialHashGrid, eid: Entity): ReadonlySet<number>;
3016
+ /**
3017
+ * Gets all entities at a specific cell coordinate.
3018
+ *
3019
+ * @param grid - The spatial hash grid
3020
+ * @param cx - Cell X coordinate
3021
+ * @param cy - Cell Y coordinate
3022
+ * @returns Set of entity IDs in that cell
3023
+ *
3024
+ * @example
3025
+ * ```typescript
3026
+ * import { getEntitiesInCell } from 'blecsd';
3027
+ *
3028
+ * const entities = getEntitiesInCell(grid, 3, 5);
3029
+ * ```
3030
+ */
3031
+ declare function getEntitiesInCell(grid: SpatialHashGrid, cx: number, cy: number): ReadonlySet<number>;
3032
+ /**
3033
+ * Gets all entities at a world position.
3034
+ *
3035
+ * @param grid - The spatial hash grid
3036
+ * @param x - World X coordinate
3037
+ * @param y - World Y coordinate
3038
+ * @returns Set of entity IDs at that position
3039
+ *
3040
+ * @example
3041
+ * ```typescript
3042
+ * import { getEntitiesAtPoint } from 'blecsd';
3043
+ *
3044
+ * const entities = getEntitiesAtPoint(grid, 10, 20);
3045
+ * ```
3046
+ */
3047
+ declare function getEntitiesAtPoint(grid: SpatialHashGrid, x: number, y: number): ReadonlySet<number>;
3048
+ /**
3049
+ * Clears all entities from the spatial hash grid.
3050
+ *
3051
+ * @param grid - The spatial hash grid to clear
3052
+ *
3053
+ * @example
3054
+ * ```typescript
3055
+ * import { clearSpatialHash } from 'blecsd';
3056
+ *
3057
+ * clearSpatialHash(grid);
3058
+ * ```
3059
+ */
3060
+ declare function clearSpatialHash(grid: SpatialHashGrid): void;
3061
+ /**
3062
+ * Gets statistics about the spatial hash grid.
3063
+ *
3064
+ * @param grid - The spatial hash grid
3065
+ * @returns Grid statistics
3066
+ *
3067
+ * @example
3068
+ * ```typescript
3069
+ * import { getSpatialHashStats } from 'blecsd';
3070
+ *
3071
+ * const stats = getSpatialHashStats(grid);
3072
+ * console.log(`Cells: ${stats.cellCount}, Entities: ${stats.entityCount}`);
3073
+ * ```
3074
+ */
3075
+ declare function getSpatialHashStats(grid: SpatialHashGrid): SpatialHashStats;
3076
+ /**
3077
+ * Rebuilds the spatial hash from all entities with Position and Collider components.
3078
+ *
3079
+ * @param grid - The spatial hash grid to rebuild
3080
+ * @param world - The ECS world
3081
+ *
3082
+ * @example
3083
+ * ```typescript
3084
+ * import { createSpatialHash, rebuildSpatialHash } from 'blecsd';
3085
+ *
3086
+ * const grid = createSpatialHash({ cellSize: 4 });
3087
+ * rebuildSpatialHash(grid, world);
3088
+ * ```
3089
+ */
3090
+ declare function rebuildSpatialHash(grid: SpatialHashGrid, world: World): void;
3091
+ /**
3092
+ * Sets the spatial hash grid for the system to use.
3093
+ *
3094
+ * @param grid - The spatial hash grid
3095
+ *
3096
+ * @example
3097
+ * ```typescript
3098
+ * import { createSpatialHash, setSpatialHashGrid } from 'blecsd';
3099
+ *
3100
+ * const grid = createSpatialHash({ cellSize: 4 });
3101
+ * setSpatialHashGrid(grid);
3102
+ * ```
3103
+ */
3104
+ declare function setSpatialHashGrid(grid: SpatialHashGrid): void;
3105
+ /**
3106
+ * Gets the current system spatial hash grid.
3107
+ *
3108
+ * @returns The grid, or null if not set
3109
+ */
3110
+ declare function getSpatialHashGrid(): SpatialHashGrid | null;
3111
+ /**
3112
+ * Spatial hash system that rebuilds the grid each frame.
3113
+ *
3114
+ * Register this in the EARLY_UPDATE phase to ensure collision queries
3115
+ * use up-to-date spatial data.
3116
+ *
3117
+ * @example
3118
+ * ```typescript
3119
+ * import { createSpatialHash, setSpatialHashGrid, spatialHashSystem, createScheduler, LoopPhase } from 'blecsd';
3120
+ *
3121
+ * const grid = createSpatialHash({ cellSize: 4 });
3122
+ * setSpatialHashGrid(grid);
3123
+ *
3124
+ * const scheduler = createScheduler();
3125
+ * scheduler.registerSystem(LoopPhase.EARLY_UPDATE, spatialHashSystem);
3126
+ * ```
3127
+ */
3128
+ declare const spatialHashSystem: System;
3129
+ /**
3130
+ * Creates a new spatial hash system.
3131
+ *
3132
+ * @returns The system function
3133
+ */
3134
+ declare function createSpatialHashSystem(): System;
3135
+
3136
+ /**
3137
+ * State machine system for updating entity state age.
3138
+ * Processes all entities with StateMachine component.
3139
+ * @module systems/stateMachineSystem
3140
+ */
3141
+
3142
+ /**
3143
+ * Query all entities with the StateMachine component.
3144
+ *
3145
+ * @param world - The ECS world
3146
+ * @returns Array of entity IDs with StateMachine component
3147
+ */
3148
+ declare function queryStateMachine(world: World): number[];
3149
+ /**
3150
+ * Gets the state age store for direct access.
3151
+ * Use with caution; primarily for testing.
3152
+ *
3153
+ * @returns The state age array
3154
+ */
3155
+ declare function getStateAgeStore(): Float32Array;
3156
+ /**
3157
+ * State machine system that updates the stateAge for all entities
3158
+ * with a StateMachine component.
3159
+ *
3160
+ * This system should be registered in the UPDATE phase of the game loop.
3161
+ * It reads delta time from getDeltaTime() which is set by the scheduler.
3162
+ *
3163
+ * The system updates each entity's stateAge by adding the frame's delta time.
3164
+ * This allows game logic to check how long an entity has been in its current
3165
+ * state for time-based transitions or animations.
3166
+ *
3167
+ * @param world - The ECS world to process
3168
+ * @returns The world (unchanged reference, but stateAge values updated)
3169
+ *
3170
+ * @example
3171
+ * ```typescript
3172
+ * import { createScheduler, LoopPhase, stateMachineSystem } from 'blecsd';
3173
+ *
3174
+ * const scheduler = createScheduler();
3175
+ * scheduler.registerSystem(LoopPhase.UPDATE, stateMachineSystem);
3176
+ *
3177
+ * // In game loop
3178
+ * scheduler.run(world, deltaTime);
3179
+ * ```
3180
+ */
3181
+ declare const stateMachineSystem: System;
3182
+ /**
3183
+ * Creates a new state machine system.
3184
+ *
3185
+ * Factory function that returns the stateMachineSystem.
3186
+ * Useful for cases where you need a fresh reference or want to
3187
+ * match the factory pattern used elsewhere in the codebase.
3188
+ *
3189
+ * @returns The state machine system function
3190
+ *
3191
+ * @example
3192
+ * ```typescript
3193
+ * import { createStateMachineSystem, createScheduler, LoopPhase } from 'blecsd';
3194
+ *
3195
+ * const scheduler = createScheduler();
3196
+ * const system = createStateMachineSystem();
3197
+ * scheduler.registerSystem(LoopPhase.UPDATE, system);
3198
+ * ```
3199
+ */
3200
+ declare function createStateMachineSystem(): System;
3201
+ /**
3202
+ * Registers the state machine system with a scheduler.
3203
+ *
3204
+ * Convenience function that registers stateMachineSystem in the UPDATE phase.
3205
+ *
3206
+ * @param scheduler - The scheduler to register with
3207
+ * @param priority - Optional priority within the UPDATE phase (default: 0)
3208
+ *
3209
+ * @example
3210
+ * ```typescript
3211
+ * import { createScheduler, registerStateMachineSystem } from 'blecsd';
3212
+ *
3213
+ * const scheduler = createScheduler();
3214
+ * registerStateMachineSystem(scheduler);
3215
+ *
3216
+ * // State machine updates will now happen in UPDATE phase
3217
+ * scheduler.run(world, deltaTime);
3218
+ * ```
3219
+ */
3220
+ declare function registerStateMachineSystem(scheduler: Scheduler, priority?: number): void;
3221
+ /**
3222
+ * Manually update state age for specific entities.
3223
+ *
3224
+ * Useful when you need to update state age outside of the system,
3225
+ * such as in tests or custom update loops.
3226
+ *
3227
+ * @param entities - Array of entity IDs to update
3228
+ * @param deltaTime - Time elapsed in seconds
3229
+ *
3230
+ * @example
3231
+ * ```typescript
3232
+ * import { updateStateAges, queryStateMachine } from 'blecsd';
3233
+ *
3234
+ * // Manual update (typically use the system instead)
3235
+ * const entities = queryStateMachine(world);
3236
+ * updateStateAges(entities, 0.016); // ~60fps frame
3237
+ * ```
3238
+ */
3239
+ declare function updateStateAges(entities: readonly number[], deltaTime: number): void;
3240
+ /**
3241
+ * Resets the state age for an entity to zero.
3242
+ *
3243
+ * Typically called when a state transition occurs (handled by
3244
+ * sendEvent in components/stateMachine.ts), but can be called
3245
+ * manually for custom state management.
3246
+ *
3247
+ * @param eid - Entity ID to reset
3248
+ *
3249
+ * @example
3250
+ * ```typescript
3251
+ * import { resetStateAge } from 'blecsd';
3252
+ *
3253
+ * // After a manual state transition
3254
+ * resetStateAge(entityId);
3255
+ * ```
3256
+ */
3257
+ declare function resetStateAge(eid: number): void;
3258
+ /**
3259
+ * Gets the state age for an entity from the system store.
3260
+ *
3261
+ * @param eid - Entity ID to query
3262
+ * @returns Time in seconds the entity has been in current state
3263
+ *
3264
+ * @example
3265
+ * ```typescript
3266
+ * import { getSystemStateAge } from 'blecsd';
3267
+ *
3268
+ * const age = getSystemStateAge(entityId);
3269
+ * if (age > 5.0) {
3270
+ * // Entity has been in state for over 5 seconds
3271
+ * }
3272
+ * ```
3273
+ */
3274
+ declare function getSystemStateAge(eid: number): number;
3275
+
3276
+ /**
3277
+ * TileMap rendering system for rendering tile maps to a buffer.
3278
+ *
3279
+ * Queries entities with TileMap and Position components, then renders
3280
+ * visible tiles to a 2D buffer. Supports camera offset for scrolling
3281
+ * and dirty region tracking for efficient updates.
3282
+ *
3283
+ * @module systems/tilemapRenderer
3284
+ */
3285
+
3286
+ /**
3287
+ * A rendered tile map buffer.
3288
+ * Stores the final composited output from all tile map entities.
3289
+ */
3290
+ interface TileMapBuffer {
3291
+ /** Buffer width in cells */
3292
+ readonly width: number;
3293
+ /** Buffer height in cells */
3294
+ readonly height: number;
3295
+ /** 2D array of rendered cells (row-major: [y][x]) */
3296
+ readonly cells: RenderedTileCell[][];
3297
+ }
3298
+ /**
3299
+ * Camera offset for tile map rendering.
3300
+ */
3301
+ interface TileMapCamera {
3302
+ /** Camera X offset in world units (pixels/cells) */
3303
+ x: number;
3304
+ /** Camera Y offset in world units (pixels/cells) */
3305
+ y: number;
3306
+ }
3307
+ /**
3308
+ * Configuration for the tile map renderer.
3309
+ */
3310
+ interface TileMapRendererConfig {
3311
+ /** Viewport width in cells */
3312
+ viewportWidth: number;
3313
+ /** Viewport height in cells */
3314
+ viewportHeight: number;
3315
+ /** Camera offset */
3316
+ camera: TileMapCamera;
3317
+ }
3318
+ /**
3319
+ * Sets the tile map renderer configuration.
3320
+ *
3321
+ * @param config - The renderer configuration
3322
+ *
3323
+ * @example
3324
+ * ```typescript
3325
+ * import { setTileMapRendererConfig } from 'blecsd';
3326
+ *
3327
+ * setTileMapRendererConfig({
3328
+ * viewportWidth: 80,
3329
+ * viewportHeight: 24,
3330
+ * camera: { x: 0, y: 0 },
3331
+ * });
3332
+ * ```
3333
+ */
3334
+ declare function setTileMapRendererConfig(config: TileMapRendererConfig): void;
3335
+ /**
3336
+ * Gets the current tile map renderer configuration.
3337
+ *
3338
+ * @returns The renderer config or null if not set
3339
+ */
3340
+ declare function getTileMapRendererConfig(): TileMapRendererConfig | null;
3341
+ /**
3342
+ * Gets the current render buffer.
3343
+ *
3344
+ * @returns The render buffer or null if not rendered yet
3345
+ *
3346
+ * @example
3347
+ * ```typescript
3348
+ * import { getTileMapRenderBuffer } from 'blecsd';
3349
+ *
3350
+ * const buffer = getTileMapRenderBuffer();
3351
+ * if (buffer) {
3352
+ * for (let y = 0; y < buffer.height; y++) {
3353
+ * for (let x = 0; x < buffer.width; x++) {
3354
+ * const cell = buffer.cells[y][x];
3355
+ * // Use cell.char, cell.fg, cell.bg
3356
+ * }
3357
+ * }
3358
+ * }
3359
+ * ```
3360
+ */
3361
+ declare function getTileMapRenderBuffer(): TileMapBuffer | null;
3362
+ /**
3363
+ * Clears the render buffer.
3364
+ */
3365
+ declare function clearTileMapRenderBuffer(): void;
3366
+ /**
3367
+ * Resets the tile map renderer state (config and buffer).
3368
+ * Useful for testing.
3369
+ *
3370
+ * @example
3371
+ * ```typescript
3372
+ * import { resetTileMapRenderer } from 'blecsd';
3373
+ *
3374
+ * resetTileMapRenderer();
3375
+ * ```
3376
+ */
3377
+ declare function resetTileMapRenderer(): void;
3378
+ /**
3379
+ * Creates an empty tile map buffer filled with empty cells.
3380
+ *
3381
+ * @param width - Buffer width in cells
3382
+ * @param height - Buffer height in cells
3383
+ * @returns A new empty buffer
3384
+ */
3385
+ declare function createEmptyBuffer(width: number, height: number): TileMapBuffer;
3386
+ /**
3387
+ * Renders a single tile map entity into a buffer.
3388
+ * Takes into account entity position and camera offset.
3389
+ *
3390
+ * @param buffer - The target buffer
3391
+ * @param eid - The entity ID
3392
+ * @param cameraX - Camera X offset in world units
3393
+ * @param cameraY - Camera Y offset in world units
3394
+ *
3395
+ * @example
3396
+ * ```typescript
3397
+ * import { createEmptyBuffer, renderTileMapToBuffer } from 'blecsd';
3398
+ *
3399
+ * const buffer = createEmptyBuffer(80, 24);
3400
+ * renderTileMapToBuffer(buffer, mapEntity, 0, 0);
3401
+ * ```
3402
+ */
3403
+ declare function renderTileMapToBuffer(buffer: TileMapBuffer, eid: Entity, cameraX: number, cameraY: number): void;
3404
+ /**
3405
+ * Renders all tile map entities in the world to the render buffer.
3406
+ * Uses the configured viewport and camera offset.
3407
+ *
3408
+ * @param world - The ECS world
3409
+ * @returns The render buffer
3410
+ *
3411
+ * @example
3412
+ * ```typescript
3413
+ * import { setTileMapRendererConfig, renderAllTileMaps } from 'blecsd';
3414
+ *
3415
+ * setTileMapRendererConfig({
3416
+ * viewportWidth: 80,
3417
+ * viewportHeight: 24,
3418
+ * camera: { x: 0, y: 0 },
3419
+ * });
3420
+ *
3421
+ * const buffer = renderAllTileMaps(world);
3422
+ * ```
3423
+ */
3424
+ declare function renderAllTileMaps(world: World): TileMapBuffer | null;
3425
+ /**
3426
+ * TileMap rendering system that renders all tile maps each frame.
3427
+ *
3428
+ * Requires renderer config to be set via setTileMapRendererConfig()
3429
+ * before the system runs. Queries all entities with TileMap and Position
3430
+ * components and composites them into a single render buffer.
3431
+ *
3432
+ * Register this in the RENDER phase.
3433
+ *
3434
+ * @example
3435
+ * ```typescript
3436
+ * import {
3437
+ * setTileMapRendererConfig,
3438
+ * tilemapRenderSystem,
3439
+ * createScheduler,
3440
+ * LoopPhase,
3441
+ * } from 'blecsd';
3442
+ *
3443
+ * setTileMapRendererConfig({
3444
+ * viewportWidth: 80,
3445
+ * viewportHeight: 24,
3446
+ * camera: { x: 0, y: 0 },
3447
+ * });
3448
+ *
3449
+ * const scheduler = createScheduler();
3450
+ * scheduler.registerSystem(LoopPhase.RENDER, tilemapRenderSystem);
3451
+ * ```
3452
+ */
3453
+ declare const tilemapRenderSystem: System;
3454
+ /**
3455
+ * Creates a new tilemap render system.
3456
+ *
3457
+ * @returns The system function
3458
+ */
3459
+ declare function createTilemapRenderSystem(): System;
3460
+
3461
+ /**
3462
+ * Virtualized Render System for Large Content
3463
+ *
3464
+ * Renders only visible lines from VirtualViewport-enabled entities.
3465
+ * Achieves 60fps scroll performance with 10M+ lines by skipping off-screen content.
3466
+ *
3467
+ * @module systems/virtualizedRenderSystem
3468
+ *
3469
+ * @example
3470
+ * ```typescript
3471
+ * import {
3472
+ * virtualizedRenderSystem,
3473
+ * setVirtualizedRenderBuffer,
3474
+ * registerLineStore,
3475
+ * } from 'blecsd';
3476
+ *
3477
+ * // Set up the render buffer
3478
+ * setVirtualizedRenderBuffer(doubleBuffer);
3479
+ *
3480
+ * // Associate a line store with an entity
3481
+ * registerLineStore(entity, lineStore);
3482
+ *
3483
+ * // Run the system
3484
+ * virtualizedRenderSystem(world);
3485
+ * ```
3486
+ */
3487
+
3488
+ /**
3489
+ * Schema for line render configuration with defaults (for full config).
3490
+ *
3491
+ * @example
3492
+ * ```typescript
3493
+ * import { LineRenderConfigSchema } from 'blecsd';
3494
+ *
3495
+ * const config = LineRenderConfigSchema.parse({
3496
+ * fg: 0xffffffff,
3497
+ * bg: 0x000000ff,
3498
+ * showLineNumbers: true,
3499
+ * lineNumberWidth: 5,
3500
+ * });
3501
+ * ```
3502
+ */
3503
+ declare const LineRenderConfigSchema: z.ZodObject<{
3504
+ fg: z.ZodDefault<z.ZodNumber>;
3505
+ bg: z.ZodDefault<z.ZodNumber>;
3506
+ selectedFg: z.ZodDefault<z.ZodNumber>;
3507
+ selectedBg: z.ZodDefault<z.ZodNumber>;
3508
+ cursorFg: z.ZodDefault<z.ZodNumber>;
3509
+ cursorBg: z.ZodDefault<z.ZodNumber>;
3510
+ showLineNumbers: z.ZodDefault<z.ZodBoolean>;
3511
+ lineNumberWidth: z.ZodDefault<z.ZodNumber>;
3512
+ attrs: z.ZodDefault<z.ZodNumber>;
3513
+ }, z.core.$strip>;
3514
+ /**
3515
+ * Render context for virtualized rendering.
3516
+ */
3517
+ interface VirtualizedRenderContext {
3518
+ /** The ECS world */
3519
+ readonly world: World;
3520
+ /** The screen buffer to render to */
3521
+ readonly buffer: ScreenBufferData;
3522
+ /** The double buffer for dirty tracking */
3523
+ readonly doubleBuffer: DoubleBufferData;
3524
+ }
3525
+ /**
3526
+ * Line render configuration.
3527
+ */
3528
+ interface LineRenderConfig {
3529
+ /** Foreground color for normal lines */
3530
+ readonly fg: number;
3531
+ /** Background color for normal lines */
3532
+ readonly bg: number;
3533
+ /** Foreground color for selected line */
3534
+ readonly selectedFg: number;
3535
+ /** Background color for selected line */
3536
+ readonly selectedBg: number;
3537
+ /** Foreground color for cursor line */
3538
+ readonly cursorFg: number;
3539
+ /** Background color for cursor line */
3540
+ readonly cursorBg: number;
3541
+ /** Whether to show line numbers */
3542
+ readonly showLineNumbers: boolean;
3543
+ /** Width reserved for line numbers (0 if not shown) */
3544
+ readonly lineNumberWidth: number;
3545
+ /** Attributes for text */
3546
+ readonly attrs: number;
3547
+ }
3548
+ /**
3549
+ * Sets the double buffer for the virtualized render system.
3550
+ *
3551
+ * @param db - The double buffer to render to
3552
+ *
3553
+ * @example
3554
+ * ```typescript
3555
+ * import { setVirtualizedRenderBuffer, createDoubleBuffer } from 'blecsd';
3556
+ *
3557
+ * const db = createDoubleBuffer(80, 24);
3558
+ * setVirtualizedRenderBuffer(db);
3559
+ * ```
3560
+ */
3561
+ declare function setVirtualizedRenderBuffer(db: DoubleBufferData): void;
3562
+ /**
3563
+ * Gets the current virtualized render buffer.
3564
+ *
3565
+ * @returns The current double buffer or null
3566
+ */
3567
+ declare function getVirtualizedRenderBuffer(): DoubleBufferData | null;
3568
+ /**
3569
+ * Clears the virtualized render buffer reference.
3570
+ */
3571
+ declare function clearVirtualizedRenderBuffer(): void;
3572
+ /**
3573
+ * Registers a line store for an entity.
3574
+ * The virtualized render system will use this store to get content.
3575
+ *
3576
+ * @param eid - Entity ID
3577
+ * @param store - The line store containing content
3578
+ *
3579
+ * @example
3580
+ * ```typescript
3581
+ * import { registerLineStore, createLineStore } from 'blecsd';
3582
+ *
3583
+ * const store = createLineStore(largeContent);
3584
+ * registerLineStore(entity, store);
3585
+ * ```
3586
+ */
3587
+ declare function registerLineStore(eid: Entity, store: VirtualizedLineStore): void;
3588
+ /**
3589
+ * Gets the line store for an entity.
3590
+ *
3591
+ * @param eid - Entity ID
3592
+ * @returns The line store or undefined
3593
+ */
3594
+ declare function getLineStore(eid: Entity): VirtualizedLineStore | undefined;
3595
+ /**
3596
+ * Unregisters a line store for an entity.
3597
+ *
3598
+ * @param eid - Entity ID
3599
+ */
3600
+ declare function unregisterLineStore(eid: Entity): void;
3601
+ /**
3602
+ * Updates the line store for an entity.
3603
+ * Use this when content changes (e.g., streaming append).
3604
+ *
3605
+ * @param eid - Entity ID
3606
+ * @param store - The new line store
3607
+ */
3608
+ declare function updateLineStore(eid: Entity, store: VirtualizedLineStore): void;
3609
+ /**
3610
+ * Sets the line render configuration for an entity.
3611
+ * Input is validated against LineRenderConfigSchema.
3612
+ *
3613
+ * @param eid - Entity ID
3614
+ * @param config - Partial config (merged with defaults)
3615
+ * @throws {z.ZodError} If config values are invalid
3616
+ *
3617
+ * @example
3618
+ * ```typescript
3619
+ * import { setLineRenderConfig } from 'blecsd';
3620
+ *
3621
+ * setLineRenderConfig(entity, {
3622
+ * showLineNumbers: true,
3623
+ * lineNumberWidth: 5,
3624
+ * selectedBg: 0x0000ffff, // Blue selection
3625
+ * });
3626
+ * ```
3627
+ */
3628
+ declare function setLineRenderConfig(eid: Entity, config: Partial<LineRenderConfig>): void;
3629
+ /**
3630
+ * Gets the line render configuration for an entity.
3631
+ *
3632
+ * @param eid - Entity ID
3633
+ * @returns The line render config
3634
+ */
3635
+ declare function getLineRenderConfig(eid: Entity): LineRenderConfig;
3636
+ /**
3637
+ * Clears the line render configuration for an entity.
3638
+ *
3639
+ * @param eid - Entity ID
3640
+ */
3641
+ declare function clearLineRenderConfig(eid: Entity): void;
3642
+ /**
3643
+ * Virtualized render system that only renders visible lines.
3644
+ *
3645
+ * The system:
3646
+ * 1. Queries all entities with VirtualViewport
3647
+ * 2. Filters to visible, dirty entities
3648
+ * 3. Gets visible line range from viewport
3649
+ * 4. Retrieves only visible lines from line store
3650
+ * 5. Renders to screen buffer
3651
+ * 6. Marks entities as clean
3652
+ *
3653
+ * @param world - The ECS world
3654
+ * @returns The world (unchanged)
3655
+ *
3656
+ * @example
3657
+ * ```typescript
3658
+ * import {
3659
+ * virtualizedRenderSystem,
3660
+ * setVirtualizedRenderBuffer,
3661
+ * registerLineStore,
3662
+ * createScheduler,
3663
+ * LoopPhase,
3664
+ * } from 'blecsd';
3665
+ *
3666
+ * // Set up
3667
+ * setVirtualizedRenderBuffer(doubleBuffer);
3668
+ * registerLineStore(entity, lineStore);
3669
+ *
3670
+ * // Register system
3671
+ * const scheduler = createScheduler();
3672
+ * scheduler.registerSystem(LoopPhase.RENDER, virtualizedRenderSystem);
3673
+ *
3674
+ * // Run
3675
+ * scheduler.run(world, deltaTime);
3676
+ * ```
3677
+ */
3678
+ declare const virtualizedRenderSystem: System;
3679
+ /**
3680
+ * Creates a new virtualized render system.
3681
+ *
3682
+ * @returns A new render system function
3683
+ */
3684
+ declare function createVirtualizedRenderSystem(): System;
3685
+ /**
3686
+ * Cleans up all resources for the virtualized render system.
3687
+ * Call this when shutting down.
3688
+ */
3689
+ declare function cleanupVirtualizedRenderSystem(): void;
3690
+ /**
3691
+ * Cleans up resources for a specific entity.
3692
+ *
3693
+ * @param eid - Entity ID
3694
+ */
3695
+ declare function cleanupEntityResources(eid: Entity): void;
3696
+
3697
+ /**
3698
+ * Visibility Culling: Efficient entity visibility determination using spatial indexing
3699
+ *
3700
+ * Uses the spatial hash grid for O(1) visibility queries, determining which
3701
+ * entities overlap the current viewport. Supports incremental updates for
3702
+ * moving entities.
3703
+ *
3704
+ * @module systems/visibilityCulling
3705
+ */
3706
+
3707
+ /**
3708
+ * Viewport definition for culling.
3709
+ */
3710
+ interface Viewport {
3711
+ /** Viewport left edge */
3712
+ readonly x: number;
3713
+ /** Viewport top edge */
3714
+ readonly y: number;
3715
+ /** Viewport width */
3716
+ readonly width: number;
3717
+ /** Viewport height */
3718
+ readonly height: number;
3719
+ }
3720
+ /**
3721
+ * Visibility culling result.
3722
+ */
3723
+ interface CullingResult {
3724
+ /** Entities visible in the viewport */
3725
+ readonly visible: readonly Entity[];
3726
+ /** Total entities considered */
3727
+ readonly total: number;
3728
+ /** Number of entities culled (not visible) */
3729
+ readonly culled: number;
3730
+ }
3731
+ /**
3732
+ * Entity position cache for incremental updates.
3733
+ */
3734
+ interface PositionCache {
3735
+ /** Previous x position per entity */
3736
+ readonly prevX: Map<number, number>;
3737
+ /** Previous y position per entity */
3738
+ readonly prevY: Map<number, number>;
3739
+ /** Previous width per entity */
3740
+ readonly prevW: Map<number, number>;
3741
+ /** Previous height per entity */
3742
+ readonly prevH: Map<number, number>;
3743
+ }
3744
+ /**
3745
+ * Creates a position cache for tracking entity movement.
3746
+ *
3747
+ * @returns Empty position cache
3748
+ *
3749
+ * @example
3750
+ * ```typescript
3751
+ * import { createPositionCache } from 'blecsd';
3752
+ *
3753
+ * const cache = createPositionCache();
3754
+ * ```
3755
+ */
3756
+ declare function createPositionCache(): PositionCache;
3757
+ /**
3758
+ * Updates a single entity in the spatial hash only if it has moved.
3759
+ * Returns true if the entity was updated.
3760
+ *
3761
+ * @param grid - Spatial hash grid
3762
+ * @param cache - Position cache
3763
+ * @param eid - Entity to check
3764
+ * @param x - Current x position
3765
+ * @param y - Current y position
3766
+ * @param w - Current width
3767
+ * @param h - Current height
3768
+ * @returns True if entity was updated in the grid
3769
+ */
3770
+ declare function updateEntityIfMoved(grid: SpatialHashGrid, cache: PositionCache, eid: Entity, x: number, y: number, w: number, h: number): boolean;
3771
+ /**
3772
+ * Removes an entity from the position cache.
3773
+ *
3774
+ * @param cache - Position cache
3775
+ * @param eid - Entity to remove
3776
+ */
3777
+ declare function removeFromCache(cache: PositionCache, eid: Entity): void;
3778
+ /**
3779
+ * Clears the entire position cache.
3780
+ *
3781
+ * @param cache - Position cache to clear
3782
+ */
3783
+ declare function clearPositionCache(cache: PositionCache): void;
3784
+ /**
3785
+ * Queries which entities are visible within the given viewport.
3786
+ *
3787
+ * @param grid - Spatial hash grid with entities inserted
3788
+ * @param viewport - Viewport to check visibility against
3789
+ * @returns Set of entity IDs visible in the viewport
3790
+ *
3791
+ * @example
3792
+ * ```typescript
3793
+ * import { createSpatialHash, queryVisibleEntities } from 'blecsd';
3794
+ *
3795
+ * const grid = createSpatialHash({ cellSize: 8 });
3796
+ * // ... insert entities ...
3797
+ *
3798
+ * const visible = queryVisibleEntities(grid, {
3799
+ * x: 0, y: 0, width: 80, height: 24,
3800
+ * });
3801
+ * ```
3802
+ */
3803
+ declare function queryVisibleEntities(grid: SpatialHashGrid, viewport: Viewport): ReadonlySet<number>;
3804
+ /**
3805
+ * Performs full visibility culling: queries the spatial hash and returns
3806
+ * a categorized result of visible vs culled entities.
3807
+ *
3808
+ * @param grid - Spatial hash grid
3809
+ * @param viewport - Current viewport
3810
+ * @param totalEntities - Total entity count for stats
3811
+ * @returns Culling result with visible entities and statistics
3812
+ *
3813
+ * @example
3814
+ * ```typescript
3815
+ * const result = performCulling(grid, viewport, 10000);
3816
+ * console.log(`Visible: ${result.visible.length}, Culled: ${result.culled}`);
3817
+ * ```
3818
+ */
3819
+ declare function performCulling(grid: SpatialHashGrid, viewport: Viewport, totalEntities: number): CullingResult;
3820
+ /**
3821
+ * Creates an incremental spatial hash update system.
3822
+ *
3823
+ * Instead of rebuilding the entire grid each frame, this system only
3824
+ * updates entities that have moved. Much faster for scenes where most
3825
+ * entities are static.
3826
+ *
3827
+ * @param grid - Spatial hash grid to update
3828
+ * @param cache - Position cache for change detection
3829
+ * @returns System function
3830
+ *
3831
+ * @example
3832
+ * ```typescript
3833
+ * import { createSpatialHash, createPositionCache, createIncrementalSpatialSystem } from 'blecsd';
3834
+ *
3835
+ * const grid = createSpatialHash({ cellSize: 4 });
3836
+ * const cache = createPositionCache();
3837
+ * const system = createIncrementalSpatialSystem(grid, cache);
3838
+ *
3839
+ * // Register in scheduler
3840
+ * scheduler.registerSystem(LoopPhase.EARLY_UPDATE, system);
3841
+ * ```
3842
+ */
3843
+ declare function createIncrementalSpatialSystem(grid: SpatialHashGrid, cache: PositionCache): System;
3844
+ /**
3845
+ * Creates a visibility culling system that marks entities as visible/not visible.
3846
+ *
3847
+ * @param grid - Spatial hash grid
3848
+ * @param getViewport - Function to get the current viewport
3849
+ * @returns System function
3850
+ *
3851
+ * @example
3852
+ * ```typescript
3853
+ * const cullSystem = createVisibilityCullingSystem(grid, () => ({
3854
+ * x: scrollX, y: scrollY,
3855
+ * width: terminalCols, height: terminalRows,
3856
+ * }));
3857
+ * ```
3858
+ */
3859
+ declare function createVisibilityCullingSystem(grid: SpatialHashGrid, getViewport: () => Viewport): System;
3860
+
3861
+ /**
3862
+ * Concurrent rendering with worker thread pool.
3863
+ *
3864
+ * Provides a lightweight worker pool abstraction for offloading
3865
+ * heavy text processing (syntax highlighting, search, diffing)
3866
+ * to background threads. Gracefully degrades on single-core systems
3867
+ * or environments without worker support.
3868
+ *
3869
+ * @module systems/workerPool
3870
+ */
3871
+ /**
3872
+ * Configuration for the worker pool.
3873
+ */
3874
+ interface WorkerPoolConfig {
3875
+ /** Maximum number of worker threads (default: navigator.hardwareConcurrency - 1 or 2) */
3876
+ readonly maxWorkers: number;
3877
+ /** Task timeout in milliseconds (default: 5000) */
3878
+ readonly taskTimeout: number;
3879
+ /** Whether to enable the pool (false = run everything synchronously) */
3880
+ readonly enabled: boolean;
3881
+ }
3882
+ /**
3883
+ * Priority levels for tasks.
3884
+ */
3885
+ type TaskPriority = 'high' | 'normal' | 'low';
3886
+ /**
3887
+ * A task to be executed in the pool.
3888
+ */
3889
+ interface PoolTask<TInput = unknown> {
3890
+ /** Unique task ID */
3891
+ readonly id: string;
3892
+ /** Task type identifier */
3893
+ readonly type: string;
3894
+ /** Input data for the task */
3895
+ readonly input: TInput;
3896
+ /** Task priority */
3897
+ readonly priority: TaskPriority;
3898
+ /** Timestamp when task was queued */
3899
+ readonly queuedAt: number;
3900
+ }
3901
+ /**
3902
+ * Result of a completed pool task.
3903
+ */
3904
+ interface TaskResult<TOutput = unknown> {
3905
+ /** Task ID */
3906
+ readonly id: string;
3907
+ /** Task type */
3908
+ readonly type: string;
3909
+ /** Output data (undefined if cancelled or failed) */
3910
+ readonly output: TOutput | undefined;
3911
+ /** Whether the task was cancelled */
3912
+ readonly cancelled: boolean;
3913
+ /** Error message if failed */
3914
+ readonly error: string | undefined;
3915
+ /** Execution time in milliseconds */
3916
+ readonly durationMs: number;
3917
+ }
3918
+ /**
3919
+ * Worker pool statistics.
3920
+ */
3921
+ interface PoolStats {
3922
+ /** Number of active workers */
3923
+ readonly activeWorkers: number;
3924
+ /** Number of idle workers */
3925
+ readonly idleWorkers: number;
3926
+ /** Tasks currently queued */
3927
+ readonly queuedTasks: number;
3928
+ /** Tasks currently running */
3929
+ readonly runningTasks: number;
3930
+ /** Total tasks completed */
3931
+ readonly completedTasks: number;
3932
+ /** Total tasks cancelled */
3933
+ readonly cancelledTasks: number;
3934
+ /** Total tasks failed */
3935
+ readonly failedTasks: number;
3936
+ /** Average task duration in ms */
3937
+ readonly avgDurationMs: number;
3938
+ /** Whether the pool is enabled */
3939
+ readonly enabled: boolean;
3940
+ }
3941
+ /**
3942
+ * A synchronous task handler for fallback execution.
3943
+ */
3944
+ type SyncHandler<TInput = unknown, TOutput = unknown> = (input: TInput) => TOutput;
3945
+ /**
3946
+ * Worker pool state object.
3947
+ */
3948
+ interface WorkerPoolState {
3949
+ /** Pool configuration */
3950
+ readonly config: WorkerPoolConfig;
3951
+ /** Current pool statistics */
3952
+ readonly stats: PoolStats;
3953
+ }
3954
+ /**
3955
+ * Creates and initializes the worker pool.
3956
+ *
3957
+ * In this implementation, the pool uses synchronous fallback handlers
3958
+ * running on the main thread with a priority queue. True worker thread
3959
+ * support can be added when node:worker_threads integration is needed.
3960
+ *
3961
+ * @param config - Optional pool configuration
3962
+ * @returns Pool state
3963
+ *
3964
+ * @example
3965
+ * ```typescript
3966
+ * import { createWorkerPool, registerTaskHandler, submitTask } from 'blecsd';
3967
+ *
3968
+ * createWorkerPool({ maxWorkers: 4 });
3969
+ * registerTaskHandler('highlight', (input) => highlightSync(input));
3970
+ * const result = await submitTask('highlight', sourceCode);
3971
+ * ```
3972
+ */
3973
+ declare function createWorkerPool(config?: Partial<WorkerPoolConfig>): WorkerPoolState;
3974
+ /**
3975
+ * Registers a synchronous handler for a task type.
3976
+ * This handler will be used to process tasks of the given type.
3977
+ *
3978
+ * @param type - Task type identifier
3979
+ * @param handler - Synchronous processing function
3980
+ *
3981
+ * @example
3982
+ * ```typescript
3983
+ * import { registerTaskHandler } from 'blecsd';
3984
+ *
3985
+ * registerTaskHandler('search', (input: { query: string; text: string }) => {
3986
+ * return input.text.indexOf(input.query);
3987
+ * });
3988
+ * ```
3989
+ */
3990
+ declare function registerTaskHandler<TInput = unknown, TOutput = unknown>(type: string, handler: SyncHandler<TInput, TOutput>): void;
3991
+ /**
3992
+ * Submits a task to the worker pool.
3993
+ * Returns a promise that resolves when the task completes.
3994
+ *
3995
+ * @param type - Task type (must have a registered handler)
3996
+ * @param input - Input data for the task
3997
+ * @param priority - Task priority (default: 'normal')
3998
+ * @returns Promise resolving to the task result
3999
+ *
4000
+ * @example
4001
+ * ```typescript
4002
+ * import { submitTask } from 'blecsd';
4003
+ *
4004
+ * const result = await submitTask('highlight', { code: 'const x = 1;', lang: 'js' });
4005
+ * if (!result.cancelled && !result.error) {
4006
+ * console.log(result.output);
4007
+ * }
4008
+ * ```
4009
+ */
4010
+ declare function submitTask<TInput = unknown, TOutput = unknown>(type: string, input: TInput, priority?: TaskPriority): Promise<TaskResult<TOutput>>;
4011
+ /**
4012
+ * Cancels a pending task by ID.
4013
+ *
4014
+ * @param taskId - ID of the task to cancel
4015
+ * @returns Whether the task was found and cancelled
4016
+ */
4017
+ declare function cancelTask(taskId: string): boolean;
4018
+ /**
4019
+ * Cancels all pending tasks of a given type.
4020
+ *
4021
+ * @param type - Task type to cancel
4022
+ * @returns Number of tasks cancelled
4023
+ */
4024
+ declare function cancelAllOfType(type: string): number;
4025
+ /**
4026
+ * Gets the current worker pool state and statistics.
4027
+ *
4028
+ * @returns Current pool state
4029
+ */
4030
+ declare function getWorkerPoolState(): WorkerPoolState;
4031
+ /**
4032
+ * Destroys the worker pool and cancels all pending tasks.
4033
+ */
4034
+ declare function destroyWorkerPool(): void;
4035
+
4036
+ export { type BehaviorSystemConfig, type BudgetAlert, type CellCoord, type CollisionEventData, type CollisionEventMap, type CollisionSystemState, ComputedLayout, type ComputedLayoutData, type CullingResult, DEFAULT_CELL_SIZE, type DirtyRect, type DragConstraints, type DragEndEvent, type DragEventMap, type DragMoveEvent, type DragStartEvent, type DragState, type DragVerifyCallback, type DropEvent, type EntityProvider, type FocusEventData, type FocusEventMap, type FocusEventType, type FrameBudgetConfig, type FrameBudgetManager, type FrameStats, type HitTestResult, type InputEventType, type InputSystemState, type LineRenderConfig, LineRenderConfigSchema, type MoveResult, type MovementApplier, type OutputState, type PanelConstraints, type PanelMoveConfig, type PanelMoveState, type ParticleSystemConfig, type PoolStats, type PoolTask, type PositionCache, type PositionResolver, type QueuedInputEvent, type QueuedKeyEvent, type QueuedMouseEvent, type RenderContext, type ResizeHandle, type ScrollAnimationState, type ScrollEvent, type ScrollPhysicsConfig, type SpatialHashConfig, type SpatialHashGrid, type SpatialHashStats, type SyncHandler, type SystemTiming, type TaskPriority, type TaskResult, type TileMapBuffer, type TileMapCamera, type TileMapRendererConfig, type Viewport, type VirtualizedRenderContext, type WorkerPoolConfig, type WorkerPoolState, ageParticle, animationSystem, applyScrollImpulse, areColliding, beginMove, beginResize, blurAll, burstParticles, cameraSystem, cancelAllOfType, cancelMoveOrResize, cancelTask, captureMouseTo, cleanup, cleanupEntityResources, cleanupVirtualizedRenderSystem, clearAllScrollStates, clearDragConstraints, clearEntityInput, clearEventQueue, clearFocusStack, clearLineRenderConfig, clearOutputBuffer, clearOutputStream, clearPositionCache, clearRenderBuffer, clearScreen, clearSpatialHash, clearTileMapRenderBuffer, clearVirtualizedRenderBuffer, collisionSystem, computeLayoutNow, createAnimationSystem, createBehaviorSystem, createCameraSystem, createCollisionSystem, createDragSystem, createEmptyBuffer, createFocusSystem, createFrameBudgetManager, createIncrementalSpatialSystem, createInputSystem, createLayoutSystem, createMovementSystem, createOutputState, createOutputSystem, createPanelConstraints, createPanelMoveConfig, createPanelMoveState, createParticleSystem, createPositionCache, createRenderSystem, createSmoothScrollSystem, createSpatialHash, createSpatialHashSystem, createStateMachineSystem, createTilemapRenderSystem, createVirtualizedRenderSystem, createVisibilityCullingSystem, createWorkerPool, cursorHome, destroyFrameBudgetManager, destroyWorkerPool, detectCollisions, detectResizeHandle, endMoveOrResize, endUserScroll, enterAlternateScreen, exportFrameBudgetMetrics, focusEntity, focusFirst, focusLast, focusNext, focusOffset, focusPop, focusPrev, focusPush, focusSystem, generateOutput, getActiveCollisions, getActiveTriggers, getCollidingEntities, getCollisionEventBus, getComputedBounds, getComputedLayout, getDragConstraints, getDragVerifyCallback, getEntitiesAtPoint, getEntitiesInCell, getEventQueue, getFocusEventBus, getFocusStackDepth, getFocusableEntities, getFocused, getFrameBudgetStats, getInputEventBus, getInteractiveEntityAt, getLineRenderConfig, getLineStore, getMouseCaptureEntity, getNearbyEntities, getOutputBuffer, getOutputState, getOutputStream, getRenderBuffer, getScrollPosition, getScrollState, getSpatialHashGrid, getSpatialHashStats, getStateAgeStore, getSystemStateAge, getTileMapRenderBuffer, getTileMapRendererConfig, getTriggerZones, getVirtualizedRenderBuffer, getWorkerPoolState, hasAnimationSystem, hasComputedLayout, hasMovementSystem, hideCursor, hitTest, inputState, inputSystem, insertEntity, invalidateAllLayouts, invalidateLayout, isColliding, isInTrigger, isMouseCaptured, isScrolling, keyboardMove, keyboardResize, killParticle, layoutSystem, leaveAlternateScreen, markAllDirty, mergeDirtyRects, moveParticle, movementSystem, onBudgetAlert, outputSystem, peekFocusStack, performCulling, pointInEntity, profiledSystem, queryAnimation, queryArea, queryCameras, queryColliders, queryInputReceivers, queryMovement, queryStateMachine, queryVisibleEntities, queueKeyEvent, queueMouseEvent, rebuildSpatialHash, recordFrameBudgetSystemTime, recordFrameTime, recordPhaseTime, registerAnimationSystem, registerCameraSystem, registerCollisionSystem, registerInputSystem, registerLineStore, registerMovementSystem, registerStateMachineSystem, registerTaskHandler, releaseMouse, removeEntityFromGrid, removeFromCache, removeScrollState, renderAllTileMaps, renderBackground, renderBorder, renderContent, renderRect, renderScrollbar, renderSystem, renderText, renderTileMapToBuffer, resetAttributes, resetCollisionState, resetDragStores, resetFocusEventBus, resetFrameBudget, resetInputState, resetOutputState, resetStateAge, resetTileMapRenderer, restoreFocus, rewindFocus, saveFocus, setDragConstraints, setDragVerifyCallback, setLineRenderConfig, setOutputBuffer, setOutputStream, setRenderBuffer, setScrollImmediate, setSpatialHashGrid, setTileMapRendererConfig, setVirtualizedRenderBuffer, showCursor, smoothScrollTo, spatialHashSystem, spawnParticle, startUserScroll, stateMachineSystem, submitTask, tilemapRenderSystem, unregisterLineStore, updateAnimations, updateCameras, updateEntityIfMoved, updateLineStore, updateMove, updateMovements, updateResize, updateScrollPhysics, updateStateAges, virtualizedRenderSystem, worldToCell, writeRaw };