@ue-too/ecs 0.12.0 → 0.13.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.
package/README.md CHANGED
@@ -291,7 +291,7 @@ const entityManager = new EntityManager(5000); // Custom max entities
291
291
 
292
292
  ## API Reference
293
293
 
294
- For complete API documentation with detailed type information, see the [TypeDoc-generated documentation](../../docs/ecs).
294
+ For complete API documentation with detailed type information, see the [TypeDoc-generated documentation](/ecs/).
295
295
 
296
296
  ## TypeScript Support
297
297
 
@@ -345,9 +345,9 @@ This ECS implementation follows these principles:
345
345
 
346
346
  ## Related Packages
347
347
 
348
- - **[@ue-too/being](../being)**: State machine library for entity AI and behavior
349
- - **[@ue-too/math](../math)**: Vector and transformation utilities for component data
350
- - **[@ue-too/board](../board)**: Canvas rendering system that can integrate with ECS
348
+ - **[@ue-too/being](/being/)**: State machine library for entity AI and behavior
349
+ - **[@ue-too/math](/math/)**: Vector and transformation utilities for component data
350
+ - **[@ue-too/board](/board/)**: Canvas rendering system that can integrate with ECS
351
351
 
352
352
  ## Further Reading
353
353
 
package/index.d.ts CHANGED
@@ -69,13 +69,16 @@
69
69
  * entities: new Set()
70
70
  * };
71
71
  *
72
- * coordinator.registerSystem('Movement', movementSystem);
72
+ * const Movement = createSystemName('Movement');
73
+ * coordinator.registerSystem(Movement, movementSystem);
73
74
  *
74
75
  * // Set signature (entities with Position AND Velocity)
75
- * const posType = coordinator.getComponentType('Position')!;
76
- * const velType = coordinator.getComponentType('Velocity')!;
76
+ * const Position = createComponentName('Position');
77
+ * const Velocity = createComponentName('Velocity');
78
+ * const posType = coordinator.getComponentType(Position)!;
79
+ * const velType = coordinator.getComponentType(Velocity)!;
77
80
  * const signature = (1 << posType) | (1 << velType);
78
- * coordinator.setSystemSignature('Movement', signature);
81
+ * coordinator.setSystemSignature(Movement, signature);
79
82
  *
80
83
  * // Update loop
81
84
  * function update(deltaTime: number) {
@@ -115,6 +118,242 @@ export type ComponentType = number;
115
118
  * @category Types
116
119
  */
117
120
  export type Entity = number;
121
+ /**
122
+ * Component name identifier using Symbol for type safety and uniqueness.
123
+ * Use {@link createComponentName} to create component names, or {@link Symbol.for} for global symbols.
124
+ * @category Types
125
+ */
126
+ export type ComponentName = symbol;
127
+ /**
128
+ * System name identifier using Symbol for type safety and uniqueness.
129
+ * Use {@link createSystemName} to create system names, or {@link Symbol.for} for global symbols.
130
+ * @category Types
131
+ */
132
+ export type SystemName = symbol;
133
+ /**
134
+ * Supported field types for runtime-defined component schemas.
135
+ * @category Types
136
+ */
137
+ export type ComponentFieldType = 'string' | 'number' | 'boolean' | 'object' | 'array' | 'entity';
138
+ /**
139
+ * Discriminated union for array element types.
140
+ * Supports both built-in types and custom component types.
141
+ * @category Types
142
+ */
143
+ export type ArrayElementType = {
144
+ kind: 'builtin';
145
+ type: Exclude<ComponentFieldType, 'array'>;
146
+ } | {
147
+ kind: 'custom';
148
+ typeName: ComponentName;
149
+ };
150
+ /**
151
+ * Base properties shared by all field definitions.
152
+ * @category Types
153
+ */
154
+ interface BaseComponentField {
155
+ /** The name of the field */
156
+ name: string;
157
+ /** Whether the field is optional (default: false) */
158
+ optional?: boolean;
159
+ /** Default value for the field (used when creating new instances) */
160
+ defaultValue?: unknown;
161
+ }
162
+ /**
163
+ * Definition for a primitive (non-array) field in a component schema.
164
+ * @category Types
165
+ */
166
+ export interface ComponentPrimitiveField extends BaseComponentField {
167
+ /** Discriminator for the union type */
168
+ type: Exclude<ComponentFieldType, 'array'>;
169
+ }
170
+ /**
171
+ * Definition for an array field in a component schema.
172
+ * @category Types
173
+ */
174
+ export interface ComponentArrayField extends BaseComponentField {
175
+ /** Discriminator for the union type */
176
+ type: 'array';
177
+ /**
178
+ * The element type for array fields (required).
179
+ * Specifies what type each element in the array should be.
180
+ * Can be a built-in type or a custom component type name.
181
+ */
182
+ arrayElementType: ArrayElementType;
183
+ }
184
+ /**
185
+ * Discriminated union for field definitions in a component schema.
186
+ * Use type guards to distinguish between primitive and array fields.
187
+ * @category Types
188
+ */
189
+ export type ComponentFieldDefinition = ComponentPrimitiveField | ComponentArrayField;
190
+ /**
191
+ * Schema definition for a component type that can be defined at runtime.
192
+ * @category Types
193
+ */
194
+ export interface ComponentSchema {
195
+ /** The name of the component type (using Symbol for type safety) */
196
+ componentName: ComponentName;
197
+ /** Array of field definitions */
198
+ fields: ComponentFieldDefinition[];
199
+ }
200
+ /**
201
+ * Helper function to create a component name from a string.
202
+ * This creates a unique symbol for the component name.
203
+ *
204
+ * @param name - The string name for the component
205
+ * @returns A unique symbol for the component name
206
+ *
207
+ * @example
208
+ * ```typescript
209
+ * const Position = createComponentName('Position');
210
+ * coordinator.registerComponent<Position>(Position);
211
+ * ```
212
+ *
213
+ * @category Utilities
214
+ */
215
+ export declare function createComponentName(name: string): ComponentName;
216
+ /**
217
+ * Helper function to get the string description from a component name symbol.
218
+ * Useful for debugging and serialization.
219
+ *
220
+ * @param componentName - The component name symbol
221
+ * @returns The string description of the symbol
222
+ *
223
+ * @category Utilities
224
+ */
225
+ export declare function getComponentNameString(componentName: ComponentName): string;
226
+ /**
227
+ * Helper function to create a component name using Symbol.for().
228
+ * This creates a global symbol that can be looked up by string key,
229
+ * which is useful for serialization and cross-module access.
230
+ *
231
+ * @param key - The string key for the global symbol
232
+ * @returns A global symbol for the component name
233
+ *
234
+ * @example
235
+ * ```typescript
236
+ * const Position = createGlobalComponentName('Position');
237
+ * coordinator.registerComponent<Position>(Position);
238
+ * // Can be retrieved later with Symbol.for('Position')
239
+ * ```
240
+ *
241
+ * @category Utilities
242
+ */
243
+ export declare function createGlobalComponentName(key: string): ComponentName;
244
+ /**
245
+ * Helper function to create a system name from a string.
246
+ * This creates a unique symbol for the system name.
247
+ *
248
+ * @param name - The string name for the system
249
+ * @returns A unique symbol for the system name
250
+ *
251
+ * @example
252
+ * ```typescript
253
+ * const Movement = createSystemName('Movement');
254
+ * coordinator.registerSystem(Movement, movementSystem);
255
+ * ```
256
+ *
257
+ * @category Utilities
258
+ */
259
+ export declare function createSystemName(name: string): SystemName;
260
+ /**
261
+ * Helper function to get the string description from a system name symbol.
262
+ * Useful for debugging and serialization.
263
+ *
264
+ * @param systemName - The system name symbol
265
+ * @returns The string description of the symbol
266
+ *
267
+ * @category Utilities
268
+ */
269
+ export declare function getSystemNameString(systemName: SystemName): string;
270
+ /**
271
+ * Helper function to create a system name using Symbol.for().
272
+ * This creates a global symbol that can be looked up by string key,
273
+ * which is useful for serialization and cross-module access.
274
+ *
275
+ * @param key - The string key for the global symbol
276
+ * @returns A global symbol for the system name
277
+ *
278
+ * @example
279
+ * ```typescript
280
+ * const Movement = createGlobalSystemName('Movement');
281
+ * coordinator.registerSystem(Movement, movementSystem);
282
+ * // Can be retrieved later with Symbol.for('Movement')
283
+ * ```
284
+ *
285
+ * @category Utilities
286
+ */
287
+ export declare function createGlobalSystemName(key: string): SystemName;
288
+ /**
289
+ * Serialized representation of an array element type for JSON storage.
290
+ * @category Types
291
+ */
292
+ type SerializedArrayElementType = {
293
+ kind: 'builtin';
294
+ type: Exclude<ComponentFieldType, 'array'>;
295
+ } | {
296
+ kind: 'custom';
297
+ typeName: string;
298
+ };
299
+ /**
300
+ * Serialized representation of a component field for JSON storage.
301
+ * @category Types
302
+ */
303
+ type SerializedComponentField = (Omit<ComponentPrimitiveField, 'type'> & {
304
+ type: Exclude<ComponentFieldType, 'array'>;
305
+ }) | (Omit<ComponentArrayField, 'arrayElementType'> & {
306
+ arrayElementType: SerializedArrayElementType;
307
+ });
308
+ /**
309
+ * Serialized representation of a component schema for JSON storage.
310
+ * Component names are stored as strings (using Symbol.for keys for global symbols).
311
+ * @category Types
312
+ */
313
+ export interface SerializedComponentSchema {
314
+ componentName: string;
315
+ fields: SerializedComponentField[];
316
+ }
317
+ /**
318
+ * Serialized representation of an entity's component data.
319
+ * @category Types
320
+ */
321
+ export interface SerializedEntity {
322
+ /** The entity ID */
323
+ entity: Entity;
324
+ /** Map of component names (as strings) to their serialized data */
325
+ components: Record<string, unknown>;
326
+ }
327
+ /**
328
+ * Serialized representation of the entire ECS state.
329
+ * @category Types
330
+ */
331
+ export interface SerializedECSState {
332
+ /** Array of all entities with their component data */
333
+ entities: SerializedEntity[];
334
+ /** Optional: Array of component schemas (if using schema-based components) */
335
+ schemas?: SerializedComponentSchema[];
336
+ }
337
+ /**
338
+ * Serialize a component schema to a JSON-compatible format.
339
+ * Note: Only works with global symbols (created via Symbol.for).
340
+ *
341
+ * @param schema - The component schema to serialize
342
+ * @returns A serializable representation of the schema
343
+ * @throws Error if component name is not a global symbol
344
+ *
345
+ * @category Utilities
346
+ */
347
+ export declare function serializeComponentSchema(schema: ComponentSchema): SerializedComponentSchema;
348
+ /**
349
+ * Deserialize a component schema from a JSON-compatible format.
350
+ *
351
+ * @param serialized - The serialized schema
352
+ * @returns The component schema with symbols restored
353
+ *
354
+ * @category Utilities
355
+ */
356
+ export declare function deserializeComponentSchema(serialized: SerializedComponentSchema): ComponentSchema;
118
357
  /**
119
358
  * Manages entity lifecycle and signatures.
120
359
  *
@@ -139,6 +378,17 @@ export declare class EntityManager {
139
378
  destroyEntity(entity: Entity): void;
140
379
  setSignature(entity: Entity, signature: ComponentSignature): void;
141
380
  getSignature(entity: Entity): ComponentSignature | null;
381
+ /**
382
+ * Get all living entities (entities that are currently active, not in the available pool).
383
+ * @returns Array of all living entity IDs
384
+ */
385
+ getAllLivingEntities(): Entity[];
386
+ /**
387
+ * Check if an entity exists (is currently active, not in the available pool).
388
+ * @param entity - The entity ID to check
389
+ * @returns true if the entity exists, false otherwise
390
+ */
391
+ entityExists(entity: Entity): boolean;
142
392
  }
143
393
  /**
144
394
  * Internal interface for component array lifecycle hooks.
@@ -176,6 +426,16 @@ export declare class ComponentArray<T> implements CArray {
176
426
  getData(entity: Entity): T | null;
177
427
  removeData(entity: Entity): void;
178
428
  entityDestroyed(entity: Entity): void;
429
+ /**
430
+ * Get all entities that have this component.
431
+ * @returns Array of entity IDs that have this component
432
+ */
433
+ getAllEntities(): Entity[];
434
+ /**
435
+ * Get the count of entities with this component.
436
+ * @returns Number of entities with this component
437
+ */
438
+ getCount(): number;
179
439
  }
180
440
  /**
181
441
  * Manages component registration and component data storage.
@@ -195,13 +455,81 @@ export declare class ComponentArray<T> implements CArray {
195
455
  export declare class ComponentManager {
196
456
  private _componentNameToTypeMap;
197
457
  private _nextAvailableComponentType;
198
- registerComponent<T>(componentName: string): void;
199
- getComponentType(componentName: string): ComponentType | null;
200
- addComponentToEntity<T>(componentName: string, entity: Entity, component: T): void;
201
- removeComponentFromEntity<T>(componentName: string, entity: Entity): void;
202
- getComponentFromEntity<T>(componentName: string, entity: Entity): T | null;
458
+ private _schemas;
459
+ getRegisteredComponentNames(): ComponentName[];
460
+ /**
461
+ * Get all entities that have a specific component.
462
+ * @param componentName - The name of the component type
463
+ * @returns Array of entity IDs that have this component, or empty array if component not registered
464
+ */
465
+ getAllEntitiesWithComponent(componentName: ComponentName): Entity[];
466
+ /**
467
+ * Get the schema for a component type, if it was registered with a schema.
468
+ * @param componentName - The name of the component type
469
+ * @returns The component schema or null if not found
470
+ */
471
+ getComponentSchema(componentName: ComponentName): ComponentSchema | null;
472
+ /**
473
+ * Get all registered component schemas.
474
+ * @returns Array of all component schemas
475
+ */
476
+ getAllComponentSchemas(): ComponentSchema[];
477
+ registerComponent<T>(componentName: ComponentName): void;
478
+ getComponentType(componentName: ComponentName): ComponentType | null;
479
+ addComponentToEntity<T>(componentName: ComponentName, entity: Entity, component: T): void;
480
+ removeComponentFromEntity<T>(componentName: ComponentName, entity: Entity): void;
481
+ getComponentFromEntity<T>(componentName: ComponentName, entity: Entity): T | null;
203
482
  entityDestroyed(entity: Entity): void;
204
483
  private _getComponentArray;
484
+ componentIsCustomSchema(componentName: ComponentName): boolean;
485
+ /**
486
+ * Register a component with a runtime-defined schema.
487
+ * This allows components to be defined dynamically (e.g., through a GUI).
488
+ *
489
+ * @param schema - The component schema definition
490
+ * @throws Error if schema validation fails
491
+ */
492
+ registerComponentWithSchema(schema: ComponentSchema): void;
493
+ /**
494
+ * Create a component instance from a schema with default values.
495
+ *
496
+ * @param componentName - The name of the component type
497
+ * @param overrides - Optional values to override defaults
498
+ * @returns A component instance with all fields initialized
499
+ * @throws Error if component is not registered with a schema
500
+ */
501
+ createComponentFromSchema(componentName: ComponentName, overrides?: Record<string, unknown>): Record<string, unknown>;
502
+ /**
503
+ * Validate component data against its schema.
504
+ *
505
+ * @param componentName - The name of the component type
506
+ * @param data - The component data to validate
507
+ * @returns true if valid, false otherwise
508
+ */
509
+ validateComponentData(componentName: ComponentName, data: unknown): boolean;
510
+ /**
511
+ * Get default value for a field type.
512
+ */
513
+ private _getDefaultValueForType;
514
+ /**
515
+ * Validate that a value matches the expected field type.
516
+ *
517
+ * @param type - The field type
518
+ * @param value - The value to validate
519
+ * @param arrayElementType - The element type for array fields
520
+ * @returns true if the value matches the expected type
521
+ */
522
+ private _validateFieldType;
523
+ /**
524
+ * Add a component to an entity with schema validation.
525
+ *
526
+ * @param componentName - The name of the component type
527
+ * @param entity - The entity to add the component to
528
+ * @param component - The component data
529
+ * @param validate - Whether to validate against schema (default: true)
530
+ * @throws Error if validation fails
531
+ */
532
+ addComponentToEntityWithSchema(componentName: ComponentName, entity: Entity, component: Record<string, unknown>, validate?: boolean): void;
205
533
  }
206
534
  /**
207
535
  * System interface for processing entities with specific component combinations.
@@ -216,6 +544,8 @@ export declare class ComponentManager {
216
544
  *
217
545
  * @example
218
546
  * ```typescript
547
+ * const Position = createComponentName('Position');
548
+ * const Velocity = createComponentName('Velocity');
219
549
  * const movementSystem: System = {
220
550
  * entities: new Set()
221
551
  * };
@@ -223,8 +553,8 @@ export declare class ComponentManager {
223
553
  * // System logic (called in game loop)
224
554
  * function updateMovement(deltaTime: number) {
225
555
  * movementSystem.entities.forEach(entity => {
226
- * const pos = ecs.getComponentFromEntity<Position>('Position', entity);
227
- * const vel = ecs.getComponentFromEntity<Velocity>('Velocity', entity);
556
+ * const pos = ecs.getComponentFromEntity<Position>(Position, entity);
557
+ * const vel = ecs.getComponentFromEntity<Velocity>(Velocity, entity);
228
558
  * if (pos && vel) {
229
559
  * pos.x += vel.x * deltaTime;
230
560
  * pos.y += vel.y * deltaTime;
@@ -257,10 +587,11 @@ export interface System {
257
587
  */
258
588
  export declare class SystemManager {
259
589
  private _systems;
260
- registerSystem(systemName: string, system: System): void;
261
- setSignature(systemName: string, signature: ComponentSignature): void;
590
+ registerSystem(systemName: SystemName, system: System): void;
591
+ setSignature(systemName: SystemName, signature: ComponentSignature): void;
262
592
  entityDestroyed(entity: Entity): void;
263
593
  entitySignatureChanged(entity: Entity, signature: ComponentSignature): void;
594
+ getSystem<T extends System>(systemName: SystemName): T | null;
264
595
  }
265
596
  /**
266
597
  * Main ECS coordinator that manages entities, components, and systems.
@@ -311,11 +642,231 @@ export declare class Coordinator {
311
642
  constructor();
312
643
  createEntity(): Entity;
313
644
  destroyEntity(entity: Entity): void;
314
- registerComponent<T>(componentName: string): void;
315
- addComponentToEntity<T>(componentName: string, entity: Entity, component: T): void;
316
- removeComponentFromEntity<T>(componentName: string, entity: Entity): void;
317
- getComponentFromEntity<T>(componentName: string, entity: Entity): T | null;
318
- getComponentType(componentName: string): ComponentType | null;
319
- registerSystem(systemName: string, system: System): void;
320
- setSystemSignature(systemName: string, signature: ComponentSignature): void;
645
+ registerComponent<T>(componentName: ComponentName): void;
646
+ addComponentToEntity<T>(componentName: ComponentName, entity: Entity, component: T): void;
647
+ removeComponentFromEntity<T>(componentName: ComponentName, entity: Entity): void;
648
+ getComponentFromEntity<T>(componentName: ComponentName, entity: Entity): T | null;
649
+ getComponentType(componentName: ComponentName): ComponentType | null;
650
+ registerSystem(systemName: SystemName, system: System): void;
651
+ setSystemSignature(systemName: SystemName, signature: ComponentSignature): void;
652
+ getSystem<T extends System>(systemName: SystemName): T | null;
653
+ /**
654
+ * Register a component with a runtime-defined schema.
655
+ * This allows components to be defined dynamically (e.g., through a GUI).
656
+ *
657
+ * @param schema - The component schema definition
658
+ * @throws Error if schema validation fails
659
+ *
660
+ * @example
661
+ * ```typescript
662
+ * const coordinator = new Coordinator();
663
+ *
664
+ * // Define a component schema at runtime
665
+ * coordinator.registerComponentWithSchema({
666
+ * componentName: 'PlayerStats',
667
+ * fields: [
668
+ * { name: 'health', type: 'number', defaultValue: 100 },
669
+ * { name: 'name', type: 'string', defaultValue: 'Player' },
670
+ * { name: 'isAlive', type: 'boolean', defaultValue: true },
671
+ * { name: 'inventory', type: 'array', defaultValue: [] }
672
+ * ]
673
+ * });
674
+ *
675
+ * // Create an entity with the component
676
+ * const entity = coordinator.createEntity();
677
+ * const component = coordinator.createComponentFromSchema('PlayerStats', { health: 150 });
678
+ * coordinator.addComponentToEntityWithSchema('PlayerStats', entity, component);
679
+ * ```
680
+ */
681
+ registerComponentWithSchema(schema: ComponentSchema): void;
682
+ /**
683
+ * Get the schema for a component type, if it was registered with a schema.
684
+ *
685
+ * @param componentName - The name of the component type
686
+ * @returns The component schema or null if not found
687
+ */
688
+ getComponentSchema(componentName: ComponentName): ComponentSchema | null;
689
+ /**
690
+ * Get the property field names of a component.
691
+ *
692
+ * This method works in two ways:
693
+ * 1. If the component was registered with a schema, returns field names from the schema
694
+ * 2. If no schema exists, attempts to extract property names from an actual component instance
695
+ * (requires at least one entity to have an instance of the component)
696
+ *
697
+ * @param componentName - The name of the component type
698
+ * @returns Array of property field names, or empty array if component has no schema and no instances exist
699
+ *
700
+ * @example
701
+ * ```typescript
702
+ * const coordinator = new Coordinator();
703
+ *
704
+ * // Method 1: Using schema
705
+ * coordinator.registerComponentWithSchema({
706
+ * componentName: 'PlayerStats',
707
+ * fields: [
708
+ * { name: 'health', type: 'number', defaultValue: 100 },
709
+ * { name: 'name', type: 'string', defaultValue: 'Player' },
710
+ * { name: 'isAlive', type: 'boolean', defaultValue: true }
711
+ * ]
712
+ * });
713
+ * const fieldNames1 = coordinator.getComponentPropertyNames('PlayerStats');
714
+ * console.log(fieldNames1); // ['health', 'name', 'isAlive']
715
+ *
716
+ * // Method 2: From component instance
717
+ * type LocationComponent = { location: Entity; sortIndex: number };
718
+ * coordinator.registerComponent<LocationComponent>('LocationComponent');
719
+ * const entity = coordinator.createEntity();
720
+ * coordinator.addComponentToEntity('LocationComponent', entity, {
721
+ * location: otherEntity,
722
+ * sortIndex: 0
723
+ * });
724
+ * const fieldNames2 = coordinator.getComponentPropertyNames('LocationComponent');
725
+ * console.log(fieldNames2); // ['location', 'sortIndex']
726
+ * ```
727
+ */
728
+ getComponentPropertyNames(componentName: ComponentName): string[];
729
+ /**
730
+ * Get all registered component schemas.
731
+ *
732
+ * @returns Array of all component schemas
733
+ */
734
+ getAllComponentSchemas(): ComponentSchema[];
735
+ /**
736
+ * Create a component instance from a schema with default values.
737
+ *
738
+ * @param componentName - The name of the component type
739
+ * @param overrides - Optional values to override defaults
740
+ * @returns A component instance with all fields initialized
741
+ * @throws Error if component is not registered with a schema
742
+ *
743
+ * @example
744
+ * ```typescript
745
+ * // Create component with all defaults
746
+ * const component1 = coordinator.createComponentFromSchema('PlayerStats');
747
+ *
748
+ * // Create component with some overrides
749
+ * const component2 = coordinator.createComponentFromSchema('PlayerStats', {
750
+ * health: 200,
751
+ * name: 'SuperPlayer'
752
+ * });
753
+ * ```
754
+ */
755
+ createComponentFromSchema(componentName: ComponentName, overrides?: Record<string, unknown>): Record<string, unknown>;
756
+ /**
757
+ * Validate component data against its schema.
758
+ *
759
+ * @param componentName - The name of the component type
760
+ * @param data - The component data to validate
761
+ * @returns true if valid, false otherwise
762
+ */
763
+ validateComponentData(componentName: ComponentName, data: unknown): boolean;
764
+ /**
765
+ * Add a component to an entity with schema validation.
766
+ *
767
+ * @param componentName - The name of the component type
768
+ * @param entity - The entity to add the component to
769
+ * @param component - The component data
770
+ * @param validate - Whether to validate against schema (default: true)
771
+ * @throws Error if validation fails
772
+ */
773
+ addComponentToEntityWithSchema(componentName: ComponentName, entity: Entity, component: Record<string, unknown>, validate?: boolean): void;
774
+ /**
775
+ * Get all living entities in the ECS.
776
+ * @returns Array of all entity IDs that are currently active
777
+ *
778
+ * @example
779
+ * ```typescript
780
+ * const entities = coordinator.getAllEntities();
781
+ * console.log(`Total entities: ${entities.length}`);
782
+ * ```
783
+ */
784
+ getAllEntities(): Entity[];
785
+ /**
786
+ * Check if an entity exists in the coordinator.
787
+ * @param entity - The entity ID to check
788
+ * @returns true if the entity exists, false otherwise
789
+ *
790
+ * @example
791
+ * ```typescript
792
+ * const entity = coordinator.createEntity();
793
+ * if (coordinator.entityExists(entity)) {
794
+ * console.log('Entity exists');
795
+ * }
796
+ *
797
+ * coordinator.destroyEntity(entity);
798
+ * if (!coordinator.entityExists(entity)) {
799
+ * console.log('Entity no longer exists');
800
+ * }
801
+ * ```
802
+ */
803
+ entityExists(entity: Entity): boolean;
804
+ /**
805
+ * Get all components for a specific entity.
806
+ * @param entity - The entity ID
807
+ * @returns Map of component names to their data, or null if entity doesn't exist
808
+ *
809
+ * @example
810
+ * ```typescript
811
+ * const components = coordinator.getEntityComponents(entity);
812
+ * if (components) {
813
+ * console.log('Entity components:', components);
814
+ * }
815
+ * ```
816
+ */
817
+ getEntityComponents(entity: Entity): Map<ComponentName, unknown> | null;
818
+ /**
819
+ * Get the entire state of the ECS: all entities with all their component values.
820
+ * @returns Object containing all entities and their components
821
+ *
822
+ * @example
823
+ * ```typescript
824
+ * const state = coordinator.getFullState();
825
+ * console.log(`Total entities: ${state.entities.length}`);
826
+ * state.entities.forEach(entityData => {
827
+ * console.log(`Entity ${entityData.entity} has ${Object.keys(entityData.components).length} components`);
828
+ * });
829
+ * ```
830
+ */
831
+ getFullState(): {
832
+ entities: Array<{
833
+ entity: Entity;
834
+ components: Map<ComponentName, unknown>;
835
+ }>;
836
+ };
837
+ /**
838
+ * Serialize the entire ECS state to a JSON-compatible format.
839
+ * Note: Only works with global symbols (created via Symbol.for or createGlobalComponentName).
840
+ *
841
+ * @returns A serializable representation of the ECS state
842
+ * @throws Error if any component name is not a global symbol
843
+ *
844
+ * @example
845
+ * ```typescript
846
+ * const serialized = coordinator.serialize();
847
+ * const json = JSON.stringify(serialized);
848
+ * // Save to file or send over network
849
+ * ```
850
+ */
851
+ serialize(): SerializedECSState;
852
+ /**
853
+ * Deserialize an ECS state from a JSON-compatible format.
854
+ * This will restore all entities and their components.
855
+ *
856
+ * @param serialized - The serialized ECS state
857
+ * @param options - Options for deserialization
858
+ * @param options.clearExisting - Whether to clear existing entities before deserializing (default: false)
859
+ * @throws Error if component names cannot be resolved or components are not registered
860
+ *
861
+ * @example
862
+ * ```typescript
863
+ * const json = fs.readFileSync('state.json', 'utf-8');
864
+ * const serialized = JSON.parse(json);
865
+ * coordinator.deserialize(serialized, { clearExisting: true });
866
+ * ```
867
+ */
868
+ deserialize(serialized: SerializedECSState, options?: {
869
+ clearExisting?: boolean;
870
+ }): void;
321
871
  }
872
+ export {};
package/index.js CHANGED
@@ -1,3 +1,3 @@
1
- var O=1e4,W=32;class G{_availableEntities=[];_signatures=[];_maxEntities;_livingEntityCount=0;constructor(b=1e4){this._maxEntities=b;for(let j=0;j<this._maxEntities;j++)this._availableEntities.push(j),this._signatures.push(0)}createEntity(){if(this._livingEntityCount>=this._maxEntities)throw Error("Max entities reached");let b=this._availableEntities.shift();if(b===void 0)throw Error("No available entities");return this._signatures[b]=0,this._livingEntityCount++,b}destroyEntity(b){if(b>=this._maxEntities||b<0)throw Error("Invalid entity out of range");this._signatures[b]=0,this._availableEntities.push(b),this._livingEntityCount--}setSignature(b,j){if(b>=this._maxEntities||b<0)throw Error("Invalid entity out of range");this._signatures[b]=j}getSignature(b){if(b>=this._maxEntities||b<0)return null;return this._signatures[b]}}class H{denseArray;sparse;reverse;_count;constructor(b){this._count=0,this.denseArray=Array(b),this.sparse=Array(b),this.reverse=Array(b)}insertData(b,j){if(this.getData(b)!==null)this.removeData(b);if(this.sparse.length<b)this.sparse=[...this.sparse,...Array(b-this.sparse.length).fill(null)];this.denseArray[this._count]=j,this.reverse[this._count]=b,this.sparse[b]=this._count,this._count++}getData(b){if(this.sparse.length<=b)return null;let j=this.sparse[b];if(j===void 0||j===null||j>=this._count)return null;if(this.reverse[j]!==b)return null;return this.denseArray[j]}removeData(b){let j=this.sparse[b];if(j===void 0||j===null||j>=this._count)return;let z=this.reverse[this._count-1];if(z===null)return;this.denseArray[j]=this.denseArray[this._count-1],this.reverse[j]=z,this.sparse[z]=j,this.sparse[b]=null,this._count--}entityDestroyed(b){this.removeData(b)}}class J{_componentNameToTypeMap=new Map;_nextAvailableComponentType=0;registerComponent(b){if(this._componentNameToTypeMap.has(b))console.warn(`Component ${b} already registered; registering with the given new type`);let j=this._nextAvailableComponentType;this._componentNameToTypeMap.set(b,{componentType:j,componentArray:new H(1e4)}),this._nextAvailableComponentType++}getComponentType(b){return this._componentNameToTypeMap.get(b)?.componentType??null}addComponentToEntity(b,j,z){let B=this._getComponentArray(b);if(B===null)return;B.insertData(j,z)}removeComponentFromEntity(b,j){let z=this._getComponentArray(b);if(z===null)return;z.removeData(j)}getComponentFromEntity(b,j){let z=this._getComponentArray(b);if(z===null)return null;return z.getData(j)}entityDestroyed(b){for(let j of this._componentNameToTypeMap.values())j.componentArray.entityDestroyed(b)}_getComponentArray(b){let j=this._componentNameToTypeMap.get(b);if(j===void 0)return console.warn(`Component ${b} not registered`),null;return j.componentArray}}class K{_systems=new Map;registerSystem(b,j){if(this._systems.has(b)){console.warn(`System ${b} already registered`);return}this._systems.set(b,{system:j,signature:0})}setSignature(b,j){if(!this._systems.has(b)){console.warn(`System ${b} not registered`);return}let z=this._systems.get(b);if(z===void 0){console.warn(`System ${b} not registered`);return}z.signature=j}entityDestroyed(b){for(let j of this._systems.values())j.system.entities.delete(b)}entitySignatureChanged(b,j){for(let z of this._systems.values()){let B=z.signature;if((B&j)===B)z.system.entities.add(b);else z.system.entities.delete(b)}}}class L{_entityManager;_componentManager;_systemManager;constructor(){this._entityManager=new G,this._componentManager=new J,this._systemManager=new K}createEntity(){return this._entityManager.createEntity()}destroyEntity(b){this._entityManager.destroyEntity(b),this._componentManager.entityDestroyed(b),this._systemManager.entityDestroyed(b)}registerComponent(b){this._componentManager.registerComponent(b)}addComponentToEntity(b,j,z){this._componentManager.addComponentToEntity(b,j,z);let B=this._entityManager.getSignature(j);if(B===null)B=0;let D=this._componentManager.getComponentType(b);if(D===null){console.warn(`Component ${b} not registered`);return}B|=1<<D,this._entityManager.setSignature(j,B),this._systemManager.entitySignatureChanged(j,B)}removeComponentFromEntity(b,j){this._componentManager.removeComponentFromEntity(b,j);let z=this._entityManager.getSignature(j);if(z===null)z=0;let B=this._componentManager.getComponentType(b);if(B===null)return;z&=~(1<<B),this._entityManager.setSignature(j,z),this._systemManager.entitySignatureChanged(j,z)}getComponentFromEntity(b,j){return this._componentManager.getComponentFromEntity(b,j)}getComponentType(b){return this._componentManager.getComponentType(b)??null}registerSystem(b,j){this._systemManager.registerSystem(b,j)}setSystemSignature(b,j){this._systemManager.setSignature(b,j)}}export{K as SystemManager,O as MAX_ENTITIES,W as MAX_COMPONENTS,G as EntityManager,L as Coordinator,J as ComponentManager,H as ComponentArray};
1
+ var W=1e4,j=32;function O(q){return Symbol(q)}function Q(q){return q.description||q.toString()}function b(q){return Symbol.for(q)}function M(q){return Symbol(q)}function Y(q){return q.description||q.toString()}function k(q){return Symbol.for(q)}function w(q){let B=Symbol.keyFor(q.componentName);if(B===void 0)throw Error("Cannot serialize schema: component name is not a global symbol. Use createGlobalComponentName() or Symbol.for() to create component names.");return{componentName:B,fields:q.fields.map((F)=>{if(F.type==="array")if(F.arrayElementType.kind==="custom"){let H=Symbol.keyFor(F.arrayElementType.typeName);if(H===void 0)throw Error("Cannot serialize schema: custom array element type is not a global symbol.");return{...F,arrayElementType:{kind:"custom",typeName:H}}}else return{...F,arrayElementType:F.arrayElementType};return F})}}function D(q){return{componentName:Symbol.for(q.componentName),fields:q.fields.map((B)=>{if(B.type==="array")if(B.arrayElementType.kind==="custom")return{...B,arrayElementType:{kind:"custom",typeName:Symbol.for(B.arrayElementType.typeName)}};else return{...B,arrayElementType:B.arrayElementType};return B})}}class Z{_availableEntities=[];_signatures=[];_maxEntities;_livingEntityCount=0;constructor(q=1e4){this._maxEntities=q;for(let B=0;B<this._maxEntities;B++)this._availableEntities.push(B),this._signatures.push(0)}createEntity(){if(this._livingEntityCount>=this._maxEntities)throw Error("Max entities reached");let q=this._availableEntities.shift();if(q===void 0)throw Error("No available entities");return this._signatures[q]=0,this._livingEntityCount++,q}destroyEntity(q){if(q>=this._maxEntities||q<0)throw Error("Invalid entity out of range");this._signatures[q]=0,this._availableEntities.push(q),this._livingEntityCount--}setSignature(q,B){if(q>=this._maxEntities||q<0)throw Error("Invalid entity out of range");this._signatures[q]=B}getSignature(q){if(q>=this._maxEntities||q<0)return null;return this._signatures[q]}getAllLivingEntities(){let q=[],B=new Set(this._availableEntities);for(let F=0;F<this._maxEntities;F++)if(!B.has(F))q.push(F);return q}entityExists(q){if(q>=this._maxEntities||q<0)return!1;return!this._availableEntities.includes(q)}}class V{denseArray;sparse;reverse;_count;constructor(q){this._count=0,this.denseArray=Array(q),this.sparse=Array(q),this.reverse=Array(q)}insertData(q,B){if(this.getData(q)!==null)this.removeData(q);if(this.sparse.length<q)this.sparse=[...this.sparse,...Array(q-this.sparse.length).fill(null)];this.denseArray[this._count]=B,this.reverse[this._count]=q,this.sparse[q]=this._count,this._count++}getData(q){if(this.sparse.length<=q)return null;let B=this.sparse[q];if(B===void 0||B===null||B>=this._count)return null;if(this.reverse[B]!==q)return null;return this.denseArray[B]}removeData(q){let B=this.sparse[q];if(B===void 0||B===null||B>=this._count)return;let F=this.reverse[this._count-1];if(F===null)return;this.denseArray[B]=this.denseArray[this._count-1],this.reverse[B]=F,this.sparse[F]=B,this.sparse[q]=null,this._count--}entityDestroyed(q){this.removeData(q)}getAllEntities(){let q=[];for(let B=0;B<this._count;B++){let F=this.reverse[B];if(F!==null&&F!==void 0)q.push(F)}return q}getCount(){return this._count}}class _{_componentNameToTypeMap=new Map;_nextAvailableComponentType=0;_schemas=new Map;getRegisteredComponentNames(){return Array.from(this._componentNameToTypeMap.keys())}getAllEntitiesWithComponent(q){let B=this._componentNameToTypeMap.get(q);if(B===void 0)return[];return B.componentArray.getAllEntities()}getComponentSchema(q){return this._schemas.get(q)??null}getAllComponentSchemas(){return Array.from(this._schemas.values())}registerComponent(q){if(this._componentNameToTypeMap.has(q))return;let B=this._nextAvailableComponentType;this._componentNameToTypeMap.set(q,{componentType:B,componentArray:new V(1e4)}),this._nextAvailableComponentType++}getComponentType(q){return this._componentNameToTypeMap.get(q)?.componentType??null}addComponentToEntity(q,B,F){let H=this._getComponentArray(q);if(H===null)return;H.insertData(B,F)}removeComponentFromEntity(q,B){let F=this._getComponentArray(q);if(F===null)return;F.removeData(B)}getComponentFromEntity(q,B){let F=this._getComponentArray(q);if(F===null)return null;return F.getData(B)}entityDestroyed(q){for(let B of this._componentNameToTypeMap.values())B.componentArray.entityDestroyed(q)}_getComponentArray(q){let B=this._componentNameToTypeMap.get(q);if(B===void 0)return console.warn(`Component ${Q(q)} not registered`),null;return B.componentArray}componentIsCustomSchema(q){return this._schemas.has(q)}registerComponentWithSchema(q){if(!q.componentName)throw Error("Component schema must have a componentName");if(!q.fields||q.fields.length===0)throw Error("Component schema must have at least one field");let B=new Set;for(let F of q.fields){if(B.has(F.name))throw Error(`Duplicate field name "${F.name}" in schema for component "${Q(q.componentName)}"`);if(B.add(F.name),F.type==="array");}if(this._schemas.has(q.componentName))return;if(!this._componentNameToTypeMap.has(q.componentName)){let F=this._nextAvailableComponentType;this._componentNameToTypeMap.set(q.componentName,{componentType:F,componentArray:new V(1e4)}),this._nextAvailableComponentType++}this._schemas.set(q.componentName,q)}createComponentFromSchema(q,B={}){let F=this._schemas.get(q);if(!F)throw Error(`Component "${Q(q)}" is not registered with a schema`);let H={};for(let G of F.fields)if(B.hasOwnProperty(G.name))H[G.name]=B[G.name];else if(G.defaultValue!==void 0)H[G.name]=G.defaultValue;else if(!G.optional)if(G.type==="array")H[G.name]=this._getDefaultValueForType(G.type,G.arrayElementType);else H[G.name]=this._getDefaultValueForType(G.type);return H}validateComponentData(q,B){let F=this._schemas.get(q);if(!F)return!0;if(typeof B!=="object"||B===null||Array.isArray(B))return!1;let H=B;for(let G of F.fields){if(!G.optional&&!H.hasOwnProperty(G.name))return!1;if(H.hasOwnProperty(G.name)){if(G.type==="array"){if(!this._validateFieldType(G.type,H[G.name],G.arrayElementType))return!1}else if(!this._validateFieldType(G.type,H[G.name]))return!1}}return!0}_getDefaultValueForType(q,B){switch(q){case"string":return"";case"number":return 0;case"boolean":return!1;case"object":return{};case"array":return[];case"entity":return null;default:return null}}_validateFieldType(q,B,F){switch(q){case"string":return typeof B==="string";case"number":return typeof B==="number";case"boolean":return typeof B==="boolean";case"object":return typeof B==="object"&&B!==null&&!Array.isArray(B);case"array":if(!Array.isArray(B))return!1;if(F)if(F.kind==="builtin")return B.every((H)=>this._validateFieldType(F.type,H));else{if(!this._schemas.get(F.typeName))return B.every((G)=>typeof G==="object"&&G!==null&&!Array.isArray(G));return B.every((G)=>this.validateComponentData(F.typeName,G))}return!0;case"entity":return typeof B==="number"||B===null;default:return!1}}addComponentToEntityWithSchema(q,B,F,H=!0){if(H&&!this.validateComponentData(q,F))throw Error(`Component data for "${Q(q)}" does not match its schema`);this.addComponentToEntity(q,B,F)}}class ${_systems=new Map;registerSystem(q,B){if(this._systems.has(q))return;this._systems.set(q,{system:B,signature:0})}setSignature(q,B){if(!this._systems.has(q)){console.warn(`System ${Y(q)} not registered`);return}let F=this._systems.get(q);if(F===void 0){console.warn(`System ${Y(q)} not registered`);return}F.signature=B}entityDestroyed(q){for(let B of this._systems.values())B.system.entities.delete(q)}entitySignatureChanged(q,B){for(let F of this._systems.values()){let H=F.signature;if((H&B)===H)F.system.entities.add(q);else F.system.entities.delete(q)}}getSystem(q){let B=this._systems.get(q);if(B===void 0)return null;return B.system}}class K{_entityManager;_componentManager;_systemManager;constructor(){this._entityManager=new Z,this._componentManager=new _,this._systemManager=new $}createEntity(){return this._entityManager.createEntity()}destroyEntity(q){this._entityManager.destroyEntity(q),this._componentManager.entityDestroyed(q),this._systemManager.entityDestroyed(q)}registerComponent(q){this._componentManager.registerComponent(q)}addComponentToEntity(q,B,F){this._componentManager.addComponentToEntity(q,B,F);let H=this._entityManager.getSignature(B);if(H===null)H=0;let G=this._componentManager.getComponentType(q);if(G===null){console.warn(`Component ${Q(q)} not registered`);return}H|=1<<G,this._entityManager.setSignature(B,H),this._systemManager.entitySignatureChanged(B,H)}removeComponentFromEntity(q,B){this._componentManager.removeComponentFromEntity(q,B);let F=this._entityManager.getSignature(B);if(F===null)F=0;let H=this._componentManager.getComponentType(q);if(H===null)return;F&=~(1<<H),this._entityManager.setSignature(B,F),this._systemManager.entitySignatureChanged(B,F)}getComponentFromEntity(q,B){return this._componentManager.getComponentFromEntity(q,B)}getComponentType(q){return this._componentManager.getComponentType(q)??null}registerSystem(q,B){this._systemManager.registerSystem(q,B)}setSystemSignature(q,B){this._systemManager.setSignature(q,B)}getSystem(q){return this._systemManager.getSystem(q)??null}registerComponentWithSchema(q){this._componentManager.registerComponentWithSchema(q)}getComponentSchema(q){return this._componentManager.getComponentSchema(q)}getComponentPropertyNames(q){let B=this.getComponentSchema(q);if(B)return B.fields.map((G)=>G.name);let F=this._componentManager.getAllEntitiesWithComponent(q);if(F.length===0)return[];let H=this._componentManager.getComponentFromEntity(q,F[0]);if(H===null)return[];if(typeof H==="object"&&H!==null&&!Array.isArray(H))return Object.keys(H);return[]}getAllComponentSchemas(){return this._componentManager.getAllComponentSchemas()}createComponentFromSchema(q,B={}){return this._componentManager.createComponentFromSchema(q,B)}validateComponentData(q,B){return this._componentManager.validateComponentData(q,B)}addComponentToEntityWithSchema(q,B,F,H=!0){this._componentManager.addComponentToEntityWithSchema(q,B,F,H);let G=this._entityManager.getSignature(B);if(G===null)G=0;let J=this._componentManager.getComponentType(q);if(J===null){console.warn(`Component ${Q(q)} not registered`);return}G|=1<<J,this._entityManager.setSignature(B,G),this._systemManager.entitySignatureChanged(B,G)}getAllEntities(){return this._entityManager.getAllLivingEntities()}entityExists(q){return this._entityManager.entityExists(q)}getEntityComponents(q){let B=this._entityManager.getSignature(q);if(B===null||B===0)return null;let F=new Map,H=this._componentManager.getRegisteredComponentNames();for(let G of H){let J=this._componentManager.getComponentType(G);if(J===null)continue;if((B&1<<J)!==0){let L=this._componentManager.getComponentFromEntity(G,q);if(L!==null)F.set(G,L)}}return F}getFullState(){return{entities:this.getAllEntities().map((F)=>({entity:F,components:this.getEntityComponents(F)??new Map}))}}serialize(){let q=this.getAllEntities(),B=[],F=this._componentManager.getRegisteredComponentNames();for(let J of q){let L={},P=!1;for(let R of F){let U=this._componentManager.getComponentFromEntity(R,J);if(U!==null){let X=Symbol.keyFor(R);if(X===void 0)throw Error(`Cannot serialize: component name "${Q(R)}" is not a global symbol. Use createGlobalComponentName() or Symbol.for() to create component names.`);L[X]=U,P=!0}}if(P)B.push({entity:J,components:L})}let H=this._componentManager.getAllComponentSchemas(),G=H.length>0?H.map((J)=>w(J)):void 0;return{entities:B,...G&&{schemas:G}}}deserialize(q,B={}){let{clearExisting:F=!1}=B;if(F){let H=this.getAllEntities();for(let G of H)this.destroyEntity(G)}for(let H of q.entities){let G;if(F)G=this.createEntity();else if(this._entityManager.getSignature(H.entity)===null)G=this.createEntity();else G=H.entity;for(let[J,L]of Object.entries(H.components)){let P=Symbol.for(J);if(this._componentManager.getComponentType(P)===null)throw Error(`Cannot deserialize: component "${J}" is not registered. Register it first using registerComponent() or registerComponentWithSchema().`);if(this._componentManager.getComponentSchema(P))this.addComponentToEntityWithSchema(P,G,L,!0);else this.addComponentToEntity(P,G,L)}}}}export{w as serializeComponentSchema,Y as getSystemNameString,Q as getComponentNameString,D as deserializeComponentSchema,M as createSystemName,k as createGlobalSystemName,b as createGlobalComponentName,O as createComponentName,$ as SystemManager,W as MAX_ENTITIES,j as MAX_COMPONENTS,Z as EntityManager,K as Coordinator,_ as ComponentManager,V as ComponentArray};
2
2
 
3
- //# debugId=983008DE2E282BA464756E2164756E21
3
+ //# debugId=1A0F397F448E17CB64756E2164756E21
package/index.js.map CHANGED
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../src/index.ts"],
4
4
  "sourcesContent": [
5
- "/**\n * @packageDocumentation\n * Entity Component System (ECS) implementation for TypeScript.\n *\n * @remarks\n * The `@ue-too/ecs` package provides a high-performance Entity Component System architecture\n * based on the tutorial from https://austinmorlan.com/posts/entity_component_system/\n *\n * ## ECS Architecture\n *\n * - **Entities**: Unique identifiers (numbers) representing game objects\n * - **Components**: Data containers attached to entities\n * - **Systems**: Logic that operates on entities with specific component combinations\n * - **Signatures**: Bit flags indicating which components an entity has\n *\n * ## Key Features\n *\n * - **Efficient Storage**: Component arrays using sparse-set data structure\n * - **Fast Iteration**: Dense packing for cache-friendly iteration\n * - **Type-Safe**: TypeScript generics for component type safety\n * - **Signature Matching**: Automatic system updates when entity signatures change\n * - **Pooling**: Entity ID recycling for memory efficiency\n *\n * ## Core Classes\n *\n * - {@link Coordinator}: Main ECS coordinator managing all subsystems\n * - {@link EntityManager}: Creates and destroys entities\n * - {@link ComponentManager}: Registers components and manages component data\n * - {@link SystemManager}: Registers systems and maintains entity sets\n * - {@link ComponentArray}: Efficient sparse-set storage for component data\n *\n * @example\n * Basic ECS usage\n * ```typescript\n * import { Coordinator } from '@ue-too/ecs';\n *\n * // Define component types\n * type Position = { x: number; y: number };\n * type Velocity = { x: number; y: number };\n *\n * // Create coordinator\n * const coordinator = new Coordinator();\n *\n * // Register components\n * coordinator.registerComponent<Position>('Position');\n * coordinator.registerComponent<Velocity>('Velocity');\n *\n * // Create entity with components\n * const entity = coordinator.createEntity();\n * coordinator.addComponentToEntity('Position', entity, { x: 0, y: 0 });\n * coordinator.addComponentToEntity('Velocity', entity, { x: 1, y: 1 });\n *\n * // Query components\n * const pos = coordinator.getComponentFromEntity<Position>('Position', entity);\n * console.log('Position:', pos);\n * ```\n *\n * @example\n * System registration\n * ```typescript\n * import { Coordinator, System } from '@ue-too/ecs';\n *\n * const coordinator = new Coordinator();\n * coordinator.registerComponent<Position>('Position');\n * coordinator.registerComponent<Velocity>('Velocity');\n *\n * // Create a movement system\n * const movementSystem: System = {\n * entities: new Set()\n * };\n *\n * coordinator.registerSystem('Movement', movementSystem);\n *\n * // Set signature (entities with Position AND Velocity)\n * const posType = coordinator.getComponentType('Position')!;\n * const velType = coordinator.getComponentType('Velocity')!;\n * const signature = (1 << posType) | (1 << velType);\n * coordinator.setSystemSignature('Movement', signature);\n *\n * // Update loop\n * function update(deltaTime: number) {\n * movementSystem.entities.forEach(entity => {\n * const pos = coordinator.getComponentFromEntity<Position>('Position', entity)!;\n * const vel = coordinator.getComponentFromEntity<Velocity>('Velocity', entity)!;\n * pos.x += vel.x * deltaTime;\n * pos.y += vel.y * deltaTime;\n * });\n * }\n * ```\n *\n * @see {@link Coordinator} for the main ECS API\n */\n\n/**\n * Maximum number of entities that can exist simultaneously.\n * @category Configuration\n */\nexport const MAX_ENTITIES = 10000;\n\n/**\n * Maximum number of component types that can be registered.\n * @category Configuration\n */\nexport const MAX_COMPONENTS = 32;\n\n/**\n * Component signature type (bit field indicating which components an entity has).\n * @category Types\n */\nexport type ComponentSignature = number;\n\n/**\n * Component type identifier.\n * @category Types\n */\nexport type ComponentType = number;\n\n/**\n * Entity identifier (unique number).\n * @category Types\n */\nexport type Entity = number;\n\n/**\n * Manages entity lifecycle and signatures.\n *\n * @remarks\n * The EntityManager handles:\n * - Creating new entities (recycling IDs from a pool)\n * - Destroying entities (returning IDs to the pool)\n * - Storing and updating component signatures for each entity\n *\n * Entities are represented as simple numbers (IDs) and the manager maintains\n * a signature (bit field) for each entity indicating which components it has.\n *\n * @category Managers\n */\nexport class EntityManager {\n\n private _availableEntities: Entity[] = [];\n private _signatures: ComponentSignature[] = [];\n private _maxEntities: number;\n\n private _livingEntityCount = 0;\n\n constructor(maxEntities: number = MAX_ENTITIES) {\n this._maxEntities = maxEntities;\n for (let i = 0; i < this._maxEntities; i++) {\n this._availableEntities.push(i);\n this._signatures.push(0);\n }\n }\n\n createEntity(): Entity {\n if(this._livingEntityCount >= this._maxEntities) {\n throw new Error('Max entities reached');\n }\n const entity = this._availableEntities.shift();\n if(entity === undefined) {\n throw new Error('No available entities');\n }\n this._signatures[entity] = 0;\n this._livingEntityCount++;\n return entity;\n }\n\n destroyEntity(entity: Entity): void {\n if(entity >= this._maxEntities || entity < 0) {\n throw new Error('Invalid entity out of range');\n }\n this._signatures[entity] = 0;\n this._availableEntities.push(entity);\n this._livingEntityCount--;\n }\n\n setSignature(entity: Entity, signature: ComponentSignature): void {\n if(entity >= this._maxEntities || entity < 0) {\n throw new Error('Invalid entity out of range');\n }\n this._signatures[entity] = signature;\n }\n\n getSignature(entity: Entity): ComponentSignature | null {\n if(entity >= this._maxEntities || entity < 0) {\n return null;\n }\n return this._signatures[entity];\n }\n}\n\ntype Tuple<T, N extends number> = N extends N\n ? number extends N\n ? T[]\n : _TupleOf<T, N, []>\n : never;\n\ntype _TupleOf<T, N extends number, R extends unknown[]> = R['length'] extends N\n ? R\n : _TupleOf<T, N, [...R, T]>;\n\n// Usage\n\n/**\n * Internal interface for component array lifecycle hooks.\n * @internal\n */\nexport interface CArray {\n entityDestroyed(entity: Entity): void;\n}\n\n/**\n * Efficient sparse-set data structure for storing component data.\n *\n * @remarks\n * ComponentArray uses a sparse-set implementation for O(1) insertion, deletion,\n * and lookup while maintaining dense packing for cache-efficient iteration.\n *\n * The sparse-set consists of:\n * - **Dense array**: Packed component data for iteration\n * - **Sparse array**: Maps entity ID to dense array index\n * - **Reverse array**: Maps dense array index back to entity ID\n *\n * This structure allows fast component access by entity ID and fast iteration\n * over all components without gaps.\n *\n * @typeParam T - The component data type\n *\n * @category Data Structures\n */\nexport class ComponentArray<T> implements CArray {\n\n private denseArray: T[]; // packed array of data\n private sparse: (Entity | null)[]; // maps entity to index in dense array\n private reverse: (Entity | null)[]; // maps index in dense array to entity\n private _count: number;\n\n constructor(maxEntities: number) {\n this._count = 0;\n this.denseArray = new Array(maxEntities);\n this.sparse = new Array(maxEntities);\n this.reverse = new Array(maxEntities);\n }\n\n insertData(entity: Entity, data: T): void {\n if(this.getData(entity) !== null) {\n this.removeData(entity);\n }\n if(this.sparse.length < entity){\n // resize the array for the new entity but normally this should not happen\n this.sparse = [...this.sparse, ...new Array(entity - this.sparse.length).fill(null)];\n }\n\n this.denseArray[this._count] = data;\n this.reverse[this._count] = entity;\n this.sparse[entity] = this._count;\n this._count++;\n }\n\n getData(entity: Entity): T | null {\n if(this.sparse.length <= entity){\n return null;\n }\n\n const denseIndex = this.sparse[entity];\n if(denseIndex === undefined || denseIndex === null || denseIndex >= this._count){\n return null;\n }\n\n if(this.reverse[denseIndex] !== entity) {\n return null;\n }\n\n return this.denseArray[denseIndex];\n }\n\n removeData(entity: Entity): void {\n const denseIndex = this.sparse[entity];\n if(denseIndex === undefined || denseIndex === null || denseIndex >= this._count){\n return;\n }\n\n const lastEntity = this.reverse[this._count - 1];\n\n if(lastEntity === null) {\n return;\n }\n\n this.denseArray[denseIndex] = this.denseArray[this._count - 1];\n this.reverse[denseIndex] = lastEntity;\n this.sparse[lastEntity] = denseIndex;\n this.sparse[entity] = null;\n\n this._count--;\n }\n\n entityDestroyed(entity: Entity): void {\n this.removeData(entity);\n }\n}\n\n/**\n * Manages component registration and component data storage.\n *\n * @remarks\n * The ComponentManager handles:\n * - Registering new component types and assigning unique type IDs\n * - Creating ComponentArray storage for each component type\n * - Adding, removing, and querying component data for entities\n * - Cleaning up component data when entities are destroyed\n *\n * Each component type gets a unique ID (0-31) and its own ComponentArray\n * for efficient storage and retrieval.\n *\n * @category Managers\n */\nexport class ComponentManager {\n\n private _componentNameToTypeMap: Map<string, {componentType: ComponentType, componentArray: CArray}> = new Map();\n private _nextAvailableComponentType: ComponentType = 0;\n \n registerComponent<T>(componentName: string){\n if(this._componentNameToTypeMap.has(componentName)) {\n console.warn(`Component ${componentName} already registered; registering with the given new type`);\n }\n const componentType = this._nextAvailableComponentType;\n this._componentNameToTypeMap.set(componentName, {componentType, componentArray: new ComponentArray<T>(MAX_ENTITIES)});\n this._nextAvailableComponentType++;\n }\n\n getComponentType(componentName: string): ComponentType | null {\n return this._componentNameToTypeMap.get(componentName)?.componentType ?? null;\n }\n\n addComponentToEntity<T>(componentName: string, entity: Entity, component: T){\n const componentArray = this._getComponentArray<T>(componentName);\n if(componentArray === null) {\n return;\n }\n componentArray.insertData(entity, component);\n }\n\n removeComponentFromEntity<T>(componentName: string, entity: Entity){\n const componentArray = this._getComponentArray<T>(componentName);\n if(componentArray === null) {\n return;\n }\n componentArray.removeData(entity);\n }\n\n getComponentFromEntity<T>(componentName: string, entity: Entity): T | null {\n const componentArray = this._getComponentArray<T>(componentName);\n if(componentArray === null) {\n return null;\n }\n return componentArray.getData(entity);\n }\n\n entityDestroyed(entity: Entity){\n for(const component of this._componentNameToTypeMap.values()){\n component.componentArray.entityDestroyed(entity);\n }\n }\n\n private _getComponentArray<T>(componentName: string): ComponentArray<T> | null {\n const component = this._componentNameToTypeMap.get(componentName);\n if(component === undefined) {\n console.warn(`Component ${componentName} not registered`);\n return null;\n }\n return component.componentArray as ComponentArray<T>;\n }\n\n}\n\n/**\n * System interface for processing entities with specific component combinations.\n *\n * @remarks\n * A System maintains a set of entities that match its component signature.\n * The ECS automatically updates this set when entities are created, destroyed,\n * or have their components modified.\n *\n * Systems contain only the logic for processing entities - the `entities` set\n * is automatically managed by the SystemManager.\n *\n * @example\n * ```typescript\n * const movementSystem: System = {\n * entities: new Set()\n * };\n *\n * // System logic (called in game loop)\n * function updateMovement(deltaTime: number) {\n * movementSystem.entities.forEach(entity => {\n * const pos = ecs.getComponentFromEntity<Position>('Position', entity);\n * const vel = ecs.getComponentFromEntity<Velocity>('Velocity', entity);\n * if (pos && vel) {\n * pos.x += vel.x * deltaTime;\n * pos.y += vel.y * deltaTime;\n * }\n * });\n * }\n * ```\n *\n * @category Types\n */\nexport interface System {\n entities: Set<Entity>;\n}\n\n/**\n * Manages system registration and entity-system matching.\n *\n * @remarks\n * The SystemManager handles:\n * - Registering systems with their component signature requirements\n * - Maintaining the set of entities that match each system's signature\n * - Automatically adding/removing entities from systems when signatures change\n * - Cleaning up system entity sets when entities are destroyed\n *\n * When an entity's component signature changes (components added/removed),\n * the SystemManager checks all registered systems and updates their entity sets.\n * An entity is added to a system's set if its signature contains all components\n * required by the system's signature.\n *\n * @category Managers\n */\nexport class SystemManager {\n private _systems: Map<string, {system: System, signature: ComponentSignature}> = new Map();\n\n registerSystem(systemName: string, system: System){\n if(this._systems.has(systemName)) {\n console.warn(`System ${systemName} already registered`);\n return;\n }\n this._systems.set(systemName, {system, signature: 0});\n }\n\n setSignature(systemName: string, signature: ComponentSignature){\n if(!this._systems.has(systemName)) {\n console.warn(`System ${systemName} not registered`);\n return;\n }\n const system = this._systems.get(systemName);\n if(system === undefined) {\n console.warn(`System ${systemName} not registered`);\n return;\n }\n system.signature = signature;\n }\n\n entityDestroyed(entity: Entity){\n for(const system of this._systems.values()){\n system.system.entities.delete(entity);\n }\n }\n\n entitySignatureChanged(entity: Entity, signature: ComponentSignature){\n for(const system of this._systems.values()){\n const systemSignature = system.signature;\n if((systemSignature & signature) === systemSignature){\n system.system.entities.add(entity);\n } else {\n system.system.entities.delete(entity);\n }\n }\n }\n}\n\n/**\n * Main ECS coordinator that manages entities, components, and systems.\n *\n * @remarks\n * The Coordinator is the central API for working with the ECS. It provides a unified\n * interface for:\n * - Creating and destroying entities\n * - Registering and managing components\n * - Registering and configuring systems\n * - Querying component data\n *\n * The Coordinator automatically keeps entity signatures up-to-date and notifies\n * systems when entities match their component requirements.\n *\n * @example\n * Complete ECS workflow\n * ```typescript\n * const ecs = new Coordinator();\n *\n * // Setup\n * ecs.registerComponent<Position>('Position');\n * ecs.registerComponent<Velocity>('Velocity');\n *\n * // Create entity\n * const entity = ecs.createEntity();\n * ecs.addComponentToEntity('Position', entity, { x: 0, y: 0 });\n * ecs.addComponentToEntity('Velocity', entity, { x: 1, y: 0 });\n *\n * // Update\n * const pos = ecs.getComponentFromEntity<Position>('Position', entity);\n * const vel = ecs.getComponentFromEntity<Velocity>('Velocity', entity);\n * if (pos && vel) {\n * pos.x += vel.x;\n * pos.y += vel.y;\n * }\n *\n * // Cleanup\n * ecs.destroyEntity(entity);\n * ```\n *\n * @category Core\n */\nexport class Coordinator {\n private _entityManager: EntityManager;\n private _componentManager: ComponentManager;\n private _systemManager: SystemManager;\n\n constructor(){\n this._entityManager = new EntityManager();\n this._componentManager = new ComponentManager();\n this._systemManager = new SystemManager();\n }\n\n createEntity(): Entity {\n return this._entityManager.createEntity();\n }\n\n destroyEntity(entity: Entity): void {\n this._entityManager.destroyEntity(entity);\n this._componentManager.entityDestroyed(entity);\n this._systemManager.entityDestroyed(entity);\n }\n\n registerComponent<T>(componentName: string): void {\n this._componentManager.registerComponent<T>(componentName);\n }\n\n addComponentToEntity<T>(componentName: string, entity: Entity, component: T): void {\n this._componentManager.addComponentToEntity<T>(componentName, entity, component);\n let signature = this._entityManager.getSignature(entity);\n if(signature === null) {\n signature = 0;\n }\n const componentType = this._componentManager.getComponentType(componentName);\n if(componentType === null) {\n console.warn(`Component ${componentName} not registered`);\n return;\n }\n signature |= 1 << componentType;\n this._entityManager.setSignature(entity, signature);\n this._systemManager.entitySignatureChanged(entity, signature);\n }\n\n removeComponentFromEntity<T>(componentName: string, entity: Entity): void {\n this._componentManager.removeComponentFromEntity<T>(componentName, entity);\n let signature = this._entityManager.getSignature(entity);\n if(signature === null) {\n signature = 0;\n }\n const componentType = this._componentManager.getComponentType(componentName);\n if(componentType === null) {\n return;\n }\n signature &= ~(1 << componentType);\n this._entityManager.setSignature(entity, signature);\n this._systemManager.entitySignatureChanged(entity, signature);\n }\n\n getComponentFromEntity<T>(componentName: string, entity: Entity): T | null {\n return this._componentManager.getComponentFromEntity<T>(componentName, entity);\n }\n\n getComponentType(componentName: string): ComponentType | null {\n return this._componentManager.getComponentType(componentName) ?? null;\n }\n\n registerSystem(systemName: string, system: System): void {\n this._systemManager.registerSystem(systemName, system);\n }\n\n setSystemSignature(systemName: string, signature: ComponentSignature): void {\n this._systemManager.setSignature(systemName, signature);\n }\n}\n"
5
+ "/**\n * @packageDocumentation\n * Entity Component System (ECS) implementation for TypeScript.\n *\n * @remarks\n * The `@ue-too/ecs` package provides a high-performance Entity Component System architecture\n * based on the tutorial from https://austinmorlan.com/posts/entity_component_system/\n *\n * ## ECS Architecture\n *\n * - **Entities**: Unique identifiers (numbers) representing game objects\n * - **Components**: Data containers attached to entities\n * - **Systems**: Logic that operates on entities with specific component combinations\n * - **Signatures**: Bit flags indicating which components an entity has\n *\n * ## Key Features\n *\n * - **Efficient Storage**: Component arrays using sparse-set data structure\n * - **Fast Iteration**: Dense packing for cache-friendly iteration\n * - **Type-Safe**: TypeScript generics for component type safety\n * - **Signature Matching**: Automatic system updates when entity signatures change\n * - **Pooling**: Entity ID recycling for memory efficiency\n *\n * ## Core Classes\n *\n * - {@link Coordinator}: Main ECS coordinator managing all subsystems\n * - {@link EntityManager}: Creates and destroys entities\n * - {@link ComponentManager}: Registers components and manages component data\n * - {@link SystemManager}: Registers systems and maintains entity sets\n * - {@link ComponentArray}: Efficient sparse-set storage for component data\n *\n * @example\n * Basic ECS usage\n * ```typescript\n * import { Coordinator } from '@ue-too/ecs';\n *\n * // Define component types\n * type Position = { x: number; y: number };\n * type Velocity = { x: number; y: number };\n *\n * // Create coordinator\n * const coordinator = new Coordinator();\n *\n * // Register components\n * coordinator.registerComponent<Position>('Position');\n * coordinator.registerComponent<Velocity>('Velocity');\n *\n * // Create entity with components\n * const entity = coordinator.createEntity();\n * coordinator.addComponentToEntity('Position', entity, { x: 0, y: 0 });\n * coordinator.addComponentToEntity('Velocity', entity, { x: 1, y: 1 });\n *\n * // Query components\n * const pos = coordinator.getComponentFromEntity<Position>('Position', entity);\n * console.log('Position:', pos);\n * ```\n *\n * @example\n * System registration\n * ```typescript\n * import { Coordinator, System } from '@ue-too/ecs';\n *\n * const coordinator = new Coordinator();\n * coordinator.registerComponent<Position>('Position');\n * coordinator.registerComponent<Velocity>('Velocity');\n *\n * // Create a movement system\n * const movementSystem: System = {\n * entities: new Set()\n * };\n *\n * const Movement = createSystemName('Movement');\n * coordinator.registerSystem(Movement, movementSystem);\n *\n * // Set signature (entities with Position AND Velocity)\n * const Position = createComponentName('Position');\n * const Velocity = createComponentName('Velocity');\n * const posType = coordinator.getComponentType(Position)!;\n * const velType = coordinator.getComponentType(Velocity)!;\n * const signature = (1 << posType) | (1 << velType);\n * coordinator.setSystemSignature(Movement, signature);\n *\n * // Update loop\n * function update(deltaTime: number) {\n * movementSystem.entities.forEach(entity => {\n * const pos = coordinator.getComponentFromEntity<Position>('Position', entity)!;\n * const vel = coordinator.getComponentFromEntity<Velocity>('Velocity', entity)!;\n * pos.x += vel.x * deltaTime;\n * pos.y += vel.y * deltaTime;\n * });\n * }\n * ```\n *\n * @see {@link Coordinator} for the main ECS API\n */\n\n/**\n * Maximum number of entities that can exist simultaneously.\n * @category Configuration\n */\nexport const MAX_ENTITIES = 10000;\n\n/**\n * Maximum number of component types that can be registered.\n * @category Configuration\n */\nexport const MAX_COMPONENTS = 32;\n\n/**\n * Component signature type (bit field indicating which components an entity has).\n * @category Types\n */\nexport type ComponentSignature = number;\n\n/**\n * Component type identifier.\n * @category Types\n */\nexport type ComponentType = number;\n\n/**\n * Entity identifier (unique number).\n * @category Types\n */\nexport type Entity = number;\n\n/**\n * Component name identifier using Symbol for type safety and uniqueness.\n * Use {@link createComponentName} to create component names, or {@link Symbol.for} for global symbols.\n * @category Types\n */\nexport type ComponentName = symbol;\n\n/**\n * System name identifier using Symbol for type safety and uniqueness.\n * Use {@link createSystemName} to create system names, or {@link Symbol.for} for global symbols.\n * @category Types\n */\nexport type SystemName = symbol;\n\n/**\n * Supported field types for runtime-defined component schemas.\n * @category Types\n */\nexport type ComponentFieldType = \n | 'string' \n | 'number' \n | 'boolean' \n | 'object' \n | 'array'\n | 'entity';\n\n/**\n * Discriminated union for array element types.\n * Supports both built-in types and custom component types.\n * @category Types\n */\nexport type ArrayElementType = \n | { kind: 'builtin'; type: Exclude<ComponentFieldType, 'array'> }\n | { kind: 'custom'; typeName: ComponentName };\n\n/**\n * Base properties shared by all field definitions.\n * @category Types\n */\ninterface BaseComponentField {\n /** The name of the field */\n name: string;\n /** Whether the field is optional (default: false) */\n optional?: boolean;\n /** Default value for the field (used when creating new instances) */\n defaultValue?: unknown;\n}\n\n/**\n * Definition for a primitive (non-array) field in a component schema.\n * @category Types\n */\nexport interface ComponentPrimitiveField extends BaseComponentField {\n /** Discriminator for the union type */\n type: Exclude<ComponentFieldType, 'array'>;\n}\n\n/**\n * Definition for an array field in a component schema.\n * @category Types\n */\nexport interface ComponentArrayField extends BaseComponentField {\n /** Discriminator for the union type */\n type: 'array';\n /** \n * The element type for array fields (required).\n * Specifies what type each element in the array should be.\n * Can be a built-in type or a custom component type name.\n */\n arrayElementType: ArrayElementType;\n}\n\n/**\n * Discriminated union for field definitions in a component schema.\n * Use type guards to distinguish between primitive and array fields.\n * @category Types\n */\nexport type ComponentFieldDefinition = ComponentPrimitiveField | ComponentArrayField;\n\n/**\n * Schema definition for a component type that can be defined at runtime.\n * @category Types\n */\nexport interface ComponentSchema {\n /** The name of the component type (using Symbol for type safety) */\n componentName: ComponentName;\n /** Array of field definitions */\n fields: ComponentFieldDefinition[];\n}\n\n/**\n * Helper function to create a component name from a string.\n * This creates a unique symbol for the component name.\n * \n * @param name - The string name for the component\n * @returns A unique symbol for the component name\n * \n * @example\n * ```typescript\n * const Position = createComponentName('Position');\n * coordinator.registerComponent<Position>(Position);\n * ```\n * \n * @category Utilities\n */\nexport function createComponentName(name: string): ComponentName {\n return Symbol(name);\n}\n\n/**\n * Helper function to get the string description from a component name symbol.\n * Useful for debugging and serialization.\n * \n * @param componentName - The component name symbol\n * @returns The string description of the symbol\n * \n * @category Utilities\n */\nexport function getComponentNameString(componentName: ComponentName): string {\n return componentName.description || componentName.toString();\n}\n\n/**\n * Helper function to create a component name using Symbol.for().\n * This creates a global symbol that can be looked up by string key,\n * which is useful for serialization and cross-module access.\n * \n * @param key - The string key for the global symbol\n * @returns A global symbol for the component name\n * \n * @example\n * ```typescript\n * const Position = createGlobalComponentName('Position');\n * coordinator.registerComponent<Position>(Position);\n * // Can be retrieved later with Symbol.for('Position')\n * ```\n * \n * @category Utilities\n */\nexport function createGlobalComponentName(key: string): ComponentName {\n return Symbol.for(key);\n}\n\n/**\n * Helper function to create a system name from a string.\n * This creates a unique symbol for the system name.\n * \n * @param name - The string name for the system\n * @returns A unique symbol for the system name\n * \n * @example\n * ```typescript\n * const Movement = createSystemName('Movement');\n * coordinator.registerSystem(Movement, movementSystem);\n * ```\n * \n * @category Utilities\n */\nexport function createSystemName(name: string): SystemName {\n return Symbol(name);\n}\n\n/**\n * Helper function to get the string description from a system name symbol.\n * Useful for debugging and serialization.\n * \n * @param systemName - The system name symbol\n * @returns The string description of the symbol\n * \n * @category Utilities\n */\nexport function getSystemNameString(systemName: SystemName): string {\n return systemName.description || systemName.toString();\n}\n\n/**\n * Helper function to create a system name using Symbol.for().\n * This creates a global symbol that can be looked up by string key,\n * which is useful for serialization and cross-module access.\n * \n * @param key - The string key for the global symbol\n * @returns A global symbol for the system name\n * \n * @example\n * ```typescript\n * const Movement = createGlobalSystemName('Movement');\n * coordinator.registerSystem(Movement, movementSystem);\n * // Can be retrieved later with Symbol.for('Movement')\n * ```\n * \n * @category Utilities\n */\nexport function createGlobalSystemName(key: string): SystemName {\n return Symbol.for(key);\n}\n\n/**\n * Serialized representation of an array element type for JSON storage.\n * @category Types\n */\ntype SerializedArrayElementType = \n | { kind: 'builtin'; type: Exclude<ComponentFieldType, 'array'> }\n | { kind: 'custom'; typeName: string };\n\n/**\n * Serialized representation of a component field for JSON storage.\n * @category Types\n */\ntype SerializedComponentField = \n | (Omit<ComponentPrimitiveField, 'type'> & { type: Exclude<ComponentFieldType, 'array'> })\n | (Omit<ComponentArrayField, 'arrayElementType'> & { arrayElementType: SerializedArrayElementType });\n\n/**\n * Serialized representation of a component schema for JSON storage.\n * Component names are stored as strings (using Symbol.for keys for global symbols).\n * @category Types\n */\nexport interface SerializedComponentSchema {\n componentName: string;\n fields: SerializedComponentField[];\n}\n\n/**\n * Serialized representation of an entity's component data.\n * @category Types\n */\nexport interface SerializedEntity {\n /** The entity ID */\n entity: Entity;\n /** Map of component names (as strings) to their serialized data */\n components: Record<string, unknown>;\n}\n\n/**\n * Serialized representation of the entire ECS state.\n * @category Types\n */\nexport interface SerializedECSState {\n /** Array of all entities with their component data */\n entities: SerializedEntity[];\n /** Optional: Array of component schemas (if using schema-based components) */\n schemas?: SerializedComponentSchema[];\n}\n\n/**\n * Serialize a component schema to a JSON-compatible format.\n * Note: Only works with global symbols (created via Symbol.for).\n * \n * @param schema - The component schema to serialize\n * @returns A serializable representation of the schema\n * @throws Error if component name is not a global symbol\n * \n * @category Utilities\n */\nexport function serializeComponentSchema(schema: ComponentSchema): SerializedComponentSchema {\n const key = Symbol.keyFor(schema.componentName);\n if (key === undefined) {\n throw new Error(`Cannot serialize schema: component name is not a global symbol. Use createGlobalComponentName() or Symbol.for() to create component names.`);\n }\n \n return {\n componentName: key,\n fields: schema.fields.map(field => {\n if (field.type === 'array') {\n if (field.arrayElementType.kind === 'custom') {\n const customKey = Symbol.keyFor(field.arrayElementType.typeName);\n if (customKey === undefined) {\n throw new Error(`Cannot serialize schema: custom array element type is not a global symbol.`);\n }\n return {\n ...field,\n arrayElementType: {\n kind: 'custom' as const,\n typeName: customKey\n }\n } as SerializedComponentField;\n } else {\n return {\n ...field,\n arrayElementType: field.arrayElementType\n } as SerializedComponentField;\n }\n }\n return field as SerializedComponentField;\n })\n };\n}\n\n/**\n * Deserialize a component schema from a JSON-compatible format.\n * \n * @param serialized - The serialized schema\n * @returns The component schema with symbols restored\n * \n * @category Utilities\n */\nexport function deserializeComponentSchema(serialized: SerializedComponentSchema): ComponentSchema {\n return {\n componentName: Symbol.for(serialized.componentName),\n fields: serialized.fields.map(field => {\n if (field.type === 'array') {\n if (field.arrayElementType.kind === 'custom') {\n return {\n ...field,\n arrayElementType: {\n kind: 'custom' as const,\n typeName: Symbol.for(field.arrayElementType.typeName)\n }\n } as ComponentArrayField;\n } else {\n return {\n ...field,\n arrayElementType: field.arrayElementType\n } as ComponentArrayField;\n }\n }\n return field as ComponentPrimitiveField;\n })\n };\n}\n\n/**\n * Manages entity lifecycle and signatures.\n *\n * @remarks\n * The EntityManager handles:\n * - Creating new entities (recycling IDs from a pool)\n * - Destroying entities (returning IDs to the pool)\n * - Storing and updating component signatures for each entity\n *\n * Entities are represented as simple numbers (IDs) and the manager maintains\n * a signature (bit field) for each entity indicating which components it has.\n *\n * @category Managers\n */\nexport class EntityManager {\n\n private _availableEntities: Entity[] = [];\n private _signatures: ComponentSignature[] = [];\n private _maxEntities: number;\n\n private _livingEntityCount = 0;\n\n constructor(maxEntities: number = MAX_ENTITIES) {\n this._maxEntities = maxEntities;\n for (let i = 0; i < this._maxEntities; i++) {\n this._availableEntities.push(i);\n this._signatures.push(0);\n }\n }\n\n createEntity(): Entity {\n if(this._livingEntityCount >= this._maxEntities) {\n throw new Error('Max entities reached');\n }\n const entity = this._availableEntities.shift();\n if(entity === undefined) {\n throw new Error('No available entities');\n }\n this._signatures[entity] = 0;\n this._livingEntityCount++;\n return entity;\n }\n\n destroyEntity(entity: Entity): void {\n if(entity >= this._maxEntities || entity < 0) {\n throw new Error('Invalid entity out of range');\n }\n this._signatures[entity] = 0;\n this._availableEntities.push(entity);\n this._livingEntityCount--;\n }\n\n setSignature(entity: Entity, signature: ComponentSignature): void {\n if(entity >= this._maxEntities || entity < 0) {\n throw new Error('Invalid entity out of range');\n }\n this._signatures[entity] = signature;\n }\n\n getSignature(entity: Entity): ComponentSignature | null {\n if(entity >= this._maxEntities || entity < 0) {\n return null;\n }\n return this._signatures[entity];\n }\n\n /**\n * Get all living entities (entities that are currently active, not in the available pool).\n * @returns Array of all living entity IDs\n */\n getAllLivingEntities(): Entity[] {\n const livingEntities: Entity[] = [];\n const availableSet = new Set(this._availableEntities);\n \n for (let i = 0; i < this._maxEntities; i++) {\n if (!availableSet.has(i)) {\n livingEntities.push(i);\n }\n }\n \n return livingEntities;\n }\n\n /**\n * Check if an entity exists (is currently active, not in the available pool).\n * @param entity - The entity ID to check\n * @returns true if the entity exists, false otherwise\n */\n entityExists(entity: Entity): boolean {\n if (entity >= this._maxEntities || entity < 0) {\n return false;\n }\n // An entity exists if it's not in the available pool\n return !this._availableEntities.includes(entity);\n }\n}\n\ntype Tuple<T, N extends number> = N extends N\n ? number extends N\n ? T[]\n : _TupleOf<T, N, []>\n : never;\n\ntype _TupleOf<T, N extends number, R extends unknown[]> = R['length'] extends N\n ? R\n : _TupleOf<T, N, [...R, T]>;\n\n// Usage\n\n/**\n * Internal interface for component array lifecycle hooks.\n * @internal\n */\nexport interface CArray {\n entityDestroyed(entity: Entity): void;\n}\n\n/**\n * Efficient sparse-set data structure for storing component data.\n *\n * @remarks\n * ComponentArray uses a sparse-set implementation for O(1) insertion, deletion,\n * and lookup while maintaining dense packing for cache-efficient iteration.\n *\n * The sparse-set consists of:\n * - **Dense array**: Packed component data for iteration\n * - **Sparse array**: Maps entity ID to dense array index\n * - **Reverse array**: Maps dense array index back to entity ID\n *\n * This structure allows fast component access by entity ID and fast iteration\n * over all components without gaps.\n *\n * @typeParam T - The component data type\n *\n * @category Data Structures\n */\nexport class ComponentArray<T> implements CArray {\n\n private denseArray: T[]; // packed array of data\n private sparse: (Entity | null)[]; // maps entity to index in dense array\n private reverse: (Entity | null)[]; // maps index in dense array to entity\n private _count: number;\n\n constructor(maxEntities: number) {\n this._count = 0;\n this.denseArray = new Array(maxEntities);\n this.sparse = new Array(maxEntities);\n this.reverse = new Array(maxEntities);\n }\n\n insertData(entity: Entity, data: T): void {\n if(this.getData(entity) !== null) {\n this.removeData(entity);\n }\n if(this.sparse.length < entity){\n // resize the array for the new entity but normally this should not happen\n this.sparse = [...this.sparse, ...new Array(entity - this.sparse.length).fill(null)];\n }\n\n this.denseArray[this._count] = data;\n this.reverse[this._count] = entity;\n this.sparse[entity] = this._count;\n this._count++;\n }\n\n getData(entity: Entity): T | null {\n if(this.sparse.length <= entity){\n return null;\n }\n\n const denseIndex = this.sparse[entity];\n if(denseIndex === undefined || denseIndex === null || denseIndex >= this._count){\n return null;\n }\n\n if(this.reverse[denseIndex] !== entity) {\n return null;\n }\n\n return this.denseArray[denseIndex];\n }\n\n removeData(entity: Entity): void {\n const denseIndex = this.sparse[entity];\n if(denseIndex === undefined || denseIndex === null || denseIndex >= this._count){\n return;\n }\n\n const lastEntity = this.reverse[this._count - 1];\n\n if(lastEntity === null) {\n return;\n }\n\n this.denseArray[denseIndex] = this.denseArray[this._count - 1];\n this.reverse[denseIndex] = lastEntity;\n this.sparse[lastEntity] = denseIndex;\n this.sparse[entity] = null;\n\n this._count--;\n }\n\n entityDestroyed(entity: Entity): void {\n this.removeData(entity);\n }\n\n /**\n * Get all entities that have this component.\n * @returns Array of entity IDs that have this component\n */\n getAllEntities(): Entity[] {\n const entities: Entity[] = [];\n for (let i = 0; i < this._count; i++) {\n const entity = this.reverse[i];\n if (entity !== null && entity !== undefined) {\n entities.push(entity);\n }\n }\n return entities;\n }\n\n /**\n * Get the count of entities with this component.\n * @returns Number of entities with this component\n */\n getCount(): number {\n return this._count;\n }\n}\n\n/**\n * Manages component registration and component data storage.\n *\n * @remarks\n * The ComponentManager handles:\n * - Registering new component types and assigning unique type IDs\n * - Creating ComponentArray storage for each component type\n * - Adding, removing, and querying component data for entities\n * - Cleaning up component data when entities are destroyed\n *\n * Each component type gets a unique ID (0-31) and its own ComponentArray\n * for efficient storage and retrieval.\n *\n * @category Managers\n */\nexport class ComponentManager {\n\n private _componentNameToTypeMap: Map<ComponentName, {componentType: ComponentType, componentArray: CArray}> = new Map();\n private _nextAvailableComponentType: ComponentType = 0;\n private _schemas: Map<ComponentName, ComponentSchema> = new Map();\n\n getRegisteredComponentNames(): ComponentName[] {\n return Array.from(this._componentNameToTypeMap.keys());\n }\n\n /**\n * Get all entities that have a specific component.\n * @param componentName - The name of the component type\n * @returns Array of entity IDs that have this component, or empty array if component not registered\n */\n getAllEntitiesWithComponent(componentName: ComponentName): Entity[] {\n const component = this._componentNameToTypeMap.get(componentName);\n if (component === undefined) {\n return [];\n }\n return (component.componentArray as ComponentArray<unknown>).getAllEntities();\n }\n\n /**\n * Get the schema for a component type, if it was registered with a schema.\n * @param componentName - The name of the component type\n * @returns The component schema or null if not found\n */\n getComponentSchema(componentName: ComponentName): ComponentSchema | null {\n return this._schemas.get(componentName) ?? null;\n }\n\n /**\n * Get all registered component schemas.\n * @returns Array of all component schemas\n */\n getAllComponentSchemas(): ComponentSchema[] {\n return Array.from(this._schemas.values());\n }\n \n registerComponent<T>(componentName: ComponentName){\n // Idempotent: if component is already registered, do nothing\n if(this._componentNameToTypeMap.has(componentName)) {\n return;\n }\n const componentType = this._nextAvailableComponentType;\n this._componentNameToTypeMap.set(componentName, {componentType, componentArray: new ComponentArray<T>(MAX_ENTITIES)});\n this._nextAvailableComponentType++;\n }\n\n getComponentType(componentName: ComponentName): ComponentType | null {\n return this._componentNameToTypeMap.get(componentName)?.componentType ?? null;\n }\n\n addComponentToEntity<T>(componentName: ComponentName, entity: Entity, component: T){\n const componentArray = this._getComponentArray<T>(componentName);\n if(componentArray === null) {\n return;\n }\n componentArray.insertData(entity, component);\n }\n\n removeComponentFromEntity<T>(componentName: ComponentName, entity: Entity){\n const componentArray = this._getComponentArray<T>(componentName);\n if(componentArray === null) {\n return;\n }\n componentArray.removeData(entity);\n }\n\n getComponentFromEntity<T>(componentName: ComponentName, entity: Entity): T | null {\n const componentArray = this._getComponentArray<T>(componentName);\n if(componentArray === null) {\n return null;\n }\n return componentArray.getData(entity);\n }\n\n entityDestroyed(entity: Entity){\n for(const component of this._componentNameToTypeMap.values()){\n component.componentArray.entityDestroyed(entity);\n }\n }\n\n private _getComponentArray<T>(componentName: ComponentName): ComponentArray<T> | null {\n const component = this._componentNameToTypeMap.get(componentName);\n if(component === undefined) {\n console.warn(`Component ${getComponentNameString(componentName)} not registered`);\n return null;\n }\n return component.componentArray as ComponentArray<T>;\n }\n\n componentIsCustomSchema(componentName: ComponentName): boolean {\n return this._schemas.has(componentName);\n }\n\n /**\n * Register a component with a runtime-defined schema.\n * This allows components to be defined dynamically (e.g., through a GUI).\n * \n * @param schema - The component schema definition\n * @throws Error if schema validation fails\n */\n registerComponentWithSchema(schema: ComponentSchema): void {\n // Validate schema\n if (!schema.componentName) {\n throw new Error('Component schema must have a componentName');\n }\n if (!schema.fields || schema.fields.length === 0) {\n throw new Error('Component schema must have at least one field');\n }\n\n // Check for duplicate field names and validate array types\n const fieldNames = new Set<string>();\n for (const field of schema.fields) {\n if (fieldNames.has(field.name)) {\n throw new Error(`Duplicate field name \"${field.name}\" in schema for component \"${getComponentNameString(schema.componentName)}\"`);\n }\n fieldNames.add(field.name);\n\n // Validate array fields - TypeScript ensures arrayElementType is required for array fields\n if (field.type === 'array') {\n // Custom types are validated when they're registered\n // No need to check for empty string since we're using symbols\n }\n }\n\n // Idempotent: if component schema is already registered, do nothing\n if (this._schemas.has(schema.componentName)) {\n return;\n }\n \n // Register the component type (if not already registered)\n if (!this._componentNameToTypeMap.has(schema.componentName)) {\n const componentType = this._nextAvailableComponentType;\n this._componentNameToTypeMap.set(schema.componentName, {\n componentType,\n componentArray: new ComponentArray<Record<string, unknown>>(MAX_ENTITIES)\n });\n this._nextAvailableComponentType++;\n }\n // Store the schema\n this._schemas.set(schema.componentName, schema);\n\n }\n\n /**\n * Create a component instance from a schema with default values.\n * \n * @param componentName - The name of the component type\n * @param overrides - Optional values to override defaults\n * @returns A component instance with all fields initialized\n * @throws Error if component is not registered with a schema\n */\n createComponentFromSchema(componentName: ComponentName, overrides: Record<string, unknown> = {}): Record<string, unknown> {\n const schema = this._schemas.get(componentName);\n if (!schema) {\n throw new Error(`Component \"${getComponentNameString(componentName)}\" is not registered with a schema`);\n }\n\n const component: Record<string, unknown> = {};\n \n for (const field of schema.fields) {\n if (overrides.hasOwnProperty(field.name)) {\n component[field.name] = overrides[field.name];\n } else if (field.defaultValue !== undefined) {\n component[field.name] = field.defaultValue;\n } else if (!field.optional) {\n // Required field with no default - use type-appropriate default\n if (field.type === 'array') {\n component[field.name] = this._getDefaultValueForType(field.type, field.arrayElementType);\n } else {\n component[field.name] = this._getDefaultValueForType(field.type);\n }\n }\n // Optional fields without defaults are omitted\n }\n\n return component;\n }\n\n /**\n * Validate component data against its schema.\n * \n * @param componentName - The name of the component type\n * @param data - The component data to validate\n * @returns true if valid, false otherwise\n */\n validateComponentData(componentName: ComponentName, data: unknown): boolean {\n const schema = this._schemas.get(componentName);\n if (!schema) {\n // No schema means no validation required\n return true;\n }\n\n if (typeof data !== 'object' || data === null || Array.isArray(data)) {\n return false;\n }\n\n const dataObj = data as Record<string, unknown>;\n\n // Check all required fields are present\n for (const field of schema.fields) {\n if (!field.optional && !dataObj.hasOwnProperty(field.name)) {\n return false;\n }\n\n // If field is present, validate its type\n if (dataObj.hasOwnProperty(field.name)) {\n if (field.type === 'array') {\n if (!this._validateFieldType(field.type, dataObj[field.name], field.arrayElementType)) {\n return false;\n }\n } else {\n if (!this._validateFieldType(field.type, dataObj[field.name])) {\n return false;\n }\n }\n }\n }\n\n // Check for extra fields not in schema (optional - could be configurable)\n // For now, we allow extra fields\n\n return true;\n }\n\n /**\n * Get default value for a field type.\n */\n private _getDefaultValueForType(type: ComponentFieldType, arrayElementType?: ArrayElementType): unknown {\n switch (type) {\n case 'string':\n return '';\n case 'number':\n return 0;\n case 'boolean':\n return false;\n case 'object':\n return {};\n case 'array':\n return []; // Empty array - element type validation happens at runtime\n case 'entity':\n return null;\n default:\n return null;\n }\n }\n\n /**\n * Validate that a value matches the expected field type.\n * \n * @param type - The field type\n * @param value - The value to validate\n * @param arrayElementType - The element type for array fields\n * @returns true if the value matches the expected type\n */\n private _validateFieldType(type: ComponentFieldType, value: unknown, arrayElementType?: ArrayElementType): boolean {\n switch (type) {\n case 'string':\n return typeof value === 'string';\n case 'number':\n return typeof value === 'number';\n case 'boolean':\n return typeof value === 'boolean';\n case 'object':\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n case 'array':\n if (!Array.isArray(value)) {\n return false;\n }\n // If arrayElementType is specified, validate each element\n if (arrayElementType) {\n if (arrayElementType.kind === 'builtin') {\n return (value as unknown[]).every(element => \n this._validateFieldType(arrayElementType.type, element)\n );\n } else {\n // Custom type: validate against the referenced component schema\n const customSchema = this._schemas.get(arrayElementType.typeName);\n if (!customSchema) {\n // Custom type not found - could be strict or lenient\n // For now, we'll validate that it's an object\n return (value as unknown[]).every(element => \n typeof element === 'object' && element !== null && !Array.isArray(element)\n );\n }\n // Validate each element against the custom schema\n return (value as unknown[]).every(element => \n this.validateComponentData(arrayElementType.typeName, element)\n );\n }\n }\n return true;\n case 'entity':\n return typeof value === 'number' || value === null;\n default:\n return false;\n }\n }\n\n /**\n * Add a component to an entity with schema validation.\n * \n * @param componentName - The name of the component type\n * @param entity - The entity to add the component to\n * @param component - The component data\n * @param validate - Whether to validate against schema (default: true)\n * @throws Error if validation fails\n */\n addComponentToEntityWithSchema(componentName: ComponentName, entity: Entity, component: Record<string, unknown>, validate: boolean = true): void {\n if (validate && !this.validateComponentData(componentName, component)) {\n throw new Error(`Component data for \"${getComponentNameString(componentName)}\" does not match its schema`);\n }\n this.addComponentToEntity<Record<string, unknown>>(componentName, entity, component);\n }\n\n}\n\n/**\n * System interface for processing entities with specific component combinations.\n *\n * @remarks\n * A System maintains a set of entities that match its component signature.\n * The ECS automatically updates this set when entities are created, destroyed,\n * or have their components modified.\n *\n * Systems contain only the logic for processing entities - the `entities` set\n * is automatically managed by the SystemManager.\n *\n * @example\n * ```typescript\n * const Position = createComponentName('Position');\n * const Velocity = createComponentName('Velocity');\n * const movementSystem: System = {\n * entities: new Set()\n * };\n *\n * // System logic (called in game loop)\n * function updateMovement(deltaTime: number) {\n * movementSystem.entities.forEach(entity => {\n * const pos = ecs.getComponentFromEntity<Position>(Position, entity);\n * const vel = ecs.getComponentFromEntity<Velocity>(Velocity, entity);\n * if (pos && vel) {\n * pos.x += vel.x * deltaTime;\n * pos.y += vel.y * deltaTime;\n * }\n * });\n * }\n * ```\n *\n * @category Types\n */\nexport interface System {\n entities: Set<Entity>;\n}\n\n/**\n * Manages system registration and entity-system matching.\n *\n * @remarks\n * The SystemManager handles:\n * - Registering systems with their component signature requirements\n * - Maintaining the set of entities that match each system's signature\n * - Automatically adding/removing entities from systems when signatures change\n * - Cleaning up system entity sets when entities are destroyed\n *\n * When an entity's component signature changes (components added/removed),\n * the SystemManager checks all registered systems and updates their entity sets.\n * An entity is added to a system's set if its signature contains all components\n * required by the system's signature.\n *\n * @category Managers\n */\nexport class SystemManager {\n private _systems: Map<SystemName, {system: System, signature: ComponentSignature}> = new Map();\n\n registerSystem(systemName: SystemName, system: System){\n // Idempotent: if system is already registered, do nothing\n if(this._systems.has(systemName)) {\n return;\n }\n this._systems.set(systemName, {system, signature: 0});\n }\n\n setSignature(systemName: SystemName, signature: ComponentSignature){\n if(!this._systems.has(systemName)) {\n console.warn(`System ${getSystemNameString(systemName)} not registered`);\n return;\n }\n const system = this._systems.get(systemName);\n if(system === undefined) {\n console.warn(`System ${getSystemNameString(systemName)} not registered`);\n return;\n }\n system.signature = signature;\n }\n\n entityDestroyed(entity: Entity){\n for(const system of this._systems.values()){\n system.system.entities.delete(entity);\n }\n }\n\n entitySignatureChanged(entity: Entity, signature: ComponentSignature){\n for(const system of this._systems.values()){\n const systemSignature = system.signature;\n if((systemSignature & signature) === systemSignature){\n system.system.entities.add(entity);\n } else {\n system.system.entities.delete(entity);\n }\n }\n }\n\n getSystem<T extends System>(systemName: SystemName): T | null {\n const system = this._systems.get(systemName);\n if(system === undefined) {\n return null;\n }\n return system.system as T;\n }\n}\n\n/**\n * Main ECS coordinator that manages entities, components, and systems.\n *\n * @remarks\n * The Coordinator is the central API for working with the ECS. It provides a unified\n * interface for:\n * - Creating and destroying entities\n * - Registering and managing components\n * - Registering and configuring systems\n * - Querying component data\n *\n * The Coordinator automatically keeps entity signatures up-to-date and notifies\n * systems when entities match their component requirements.\n *\n * @example\n * Complete ECS workflow\n * ```typescript\n * const ecs = new Coordinator();\n *\n * // Setup\n * ecs.registerComponent<Position>('Position');\n * ecs.registerComponent<Velocity>('Velocity');\n *\n * // Create entity\n * const entity = ecs.createEntity();\n * ecs.addComponentToEntity('Position', entity, { x: 0, y: 0 });\n * ecs.addComponentToEntity('Velocity', entity, { x: 1, y: 0 });\n *\n * // Update\n * const pos = ecs.getComponentFromEntity<Position>('Position', entity);\n * const vel = ecs.getComponentFromEntity<Velocity>('Velocity', entity);\n * if (pos && vel) {\n * pos.x += vel.x;\n * pos.y += vel.y;\n * }\n *\n * // Cleanup\n * ecs.destroyEntity(entity);\n * ```\n *\n * @category Core\n */\nexport class Coordinator {\n private _entityManager: EntityManager;\n private _componentManager: ComponentManager;\n private _systemManager: SystemManager;\n\n constructor(){\n this._entityManager = new EntityManager();\n this._componentManager = new ComponentManager();\n this._systemManager = new SystemManager();\n }\n\n createEntity(): Entity {\n return this._entityManager.createEntity();\n }\n\n destroyEntity(entity: Entity): void {\n this._entityManager.destroyEntity(entity);\n this._componentManager.entityDestroyed(entity);\n this._systemManager.entityDestroyed(entity);\n }\n\n registerComponent<T>(componentName: ComponentName): void {\n this._componentManager.registerComponent<T>(componentName);\n }\n\n addComponentToEntity<T>(componentName: ComponentName, entity: Entity, component: T): void {\n this._componentManager.addComponentToEntity<T>(componentName, entity, component);\n let signature = this._entityManager.getSignature(entity);\n if(signature === null) {\n signature = 0;\n }\n const componentType = this._componentManager.getComponentType(componentName);\n if(componentType === null) {\n console.warn(`Component ${getComponentNameString(componentName)} not registered`);\n return;\n }\n signature |= 1 << componentType;\n this._entityManager.setSignature(entity, signature);\n this._systemManager.entitySignatureChanged(entity, signature);\n }\n\n removeComponentFromEntity<T>(componentName: ComponentName, entity: Entity): void {\n this._componentManager.removeComponentFromEntity<T>(componentName, entity);\n let signature = this._entityManager.getSignature(entity);\n if(signature === null) {\n signature = 0;\n }\n const componentType = this._componentManager.getComponentType(componentName);\n if(componentType === null) {\n return;\n }\n signature &= ~(1 << componentType);\n this._entityManager.setSignature(entity, signature);\n this._systemManager.entitySignatureChanged(entity, signature);\n }\n\n getComponentFromEntity<T>(componentName: ComponentName, entity: Entity): T | null {\n return this._componentManager.getComponentFromEntity<T>(componentName, entity);\n }\n\n getComponentType(componentName: ComponentName): ComponentType | null {\n return this._componentManager.getComponentType(componentName) ?? null;\n }\n\n registerSystem(systemName: SystemName, system: System): void {\n this._systemManager.registerSystem(systemName, system);\n }\n\n setSystemSignature(systemName: SystemName, signature: ComponentSignature): void {\n this._systemManager.setSignature(systemName, signature);\n }\n\n getSystem<T extends System>(systemName: SystemName): T | null {\n return this._systemManager.getSystem<T>(systemName) ?? null;\n }\n\n /**\n * Register a component with a runtime-defined schema.\n * This allows components to be defined dynamically (e.g., through a GUI).\n * \n * @param schema - The component schema definition\n * @throws Error if schema validation fails\n * \n * @example\n * ```typescript\n * const coordinator = new Coordinator();\n * \n * // Define a component schema at runtime\n * coordinator.registerComponentWithSchema({\n * componentName: 'PlayerStats',\n * fields: [\n * { name: 'health', type: 'number', defaultValue: 100 },\n * { name: 'name', type: 'string', defaultValue: 'Player' },\n * { name: 'isAlive', type: 'boolean', defaultValue: true },\n * { name: 'inventory', type: 'array', defaultValue: [] }\n * ]\n * });\n * \n * // Create an entity with the component\n * const entity = coordinator.createEntity();\n * const component = coordinator.createComponentFromSchema('PlayerStats', { health: 150 });\n * coordinator.addComponentToEntityWithSchema('PlayerStats', entity, component);\n * ```\n */\n registerComponentWithSchema(schema: ComponentSchema): void {\n this._componentManager.registerComponentWithSchema(schema);\n }\n\n /**\n * Get the schema for a component type, if it was registered with a schema.\n * \n * @param componentName - The name of the component type\n * @returns The component schema or null if not found\n */\n getComponentSchema(componentName: ComponentName): ComponentSchema | null {\n return this._componentManager.getComponentSchema(componentName);\n }\n\n /**\n * Get the property field names of a component.\n * \n * This method works in two ways:\n * 1. If the component was registered with a schema, returns field names from the schema\n * 2. If no schema exists, attempts to extract property names from an actual component instance\n * (requires at least one entity to have an instance of the component)\n * \n * @param componentName - The name of the component type\n * @returns Array of property field names, or empty array if component has no schema and no instances exist\n * \n * @example\n * ```typescript\n * const coordinator = new Coordinator();\n * \n * // Method 1: Using schema\n * coordinator.registerComponentWithSchema({\n * componentName: 'PlayerStats',\n * fields: [\n * { name: 'health', type: 'number', defaultValue: 100 },\n * { name: 'name', type: 'string', defaultValue: 'Player' },\n * { name: 'isAlive', type: 'boolean', defaultValue: true }\n * ]\n * });\n * const fieldNames1 = coordinator.getComponentPropertyNames('PlayerStats');\n * console.log(fieldNames1); // ['health', 'name', 'isAlive']\n * \n * // Method 2: From component instance\n * type LocationComponent = { location: Entity; sortIndex: number };\n * coordinator.registerComponent<LocationComponent>('LocationComponent');\n * const entity = coordinator.createEntity();\n * coordinator.addComponentToEntity('LocationComponent', entity, { \n * location: otherEntity, \n * sortIndex: 0 \n * });\n * const fieldNames2 = coordinator.getComponentPropertyNames('LocationComponent');\n * console.log(fieldNames2); // ['location', 'sortIndex']\n * ```\n */\n getComponentPropertyNames(componentName: ComponentName): string[] {\n // First, try to get from schema if available\n const schema = this.getComponentSchema(componentName);\n if (schema) {\n return schema.fields.map(field => field.name);\n }\n \n // If no schema, try to extract from an actual component instance\n const entitiesWithComponent = this._componentManager.getAllEntitiesWithComponent(componentName);\n if (entitiesWithComponent.length === 0) {\n return [];\n }\n \n // Get the first entity's component instance\n const component = this._componentManager.getComponentFromEntity(componentName, entitiesWithComponent[0]);\n if (component === null) {\n return [];\n }\n \n // Extract property names from the component object\n if (typeof component === 'object' && component !== null && !Array.isArray(component)) {\n return Object.keys(component);\n }\n \n return [];\n }\n\n /**\n * Get all registered component schemas.\n * \n * @returns Array of all component schemas\n */\n getAllComponentSchemas(): ComponentSchema[] {\n return this._componentManager.getAllComponentSchemas();\n }\n\n /**\n * Create a component instance from a schema with default values.\n * \n * @param componentName - The name of the component type\n * @param overrides - Optional values to override defaults\n * @returns A component instance with all fields initialized\n * @throws Error if component is not registered with a schema\n * \n * @example\n * ```typescript\n * // Create component with all defaults\n * const component1 = coordinator.createComponentFromSchema('PlayerStats');\n * \n * // Create component with some overrides\n * const component2 = coordinator.createComponentFromSchema('PlayerStats', {\n * health: 200,\n * name: 'SuperPlayer'\n * });\n * ```\n */\n createComponentFromSchema(componentName: ComponentName, overrides: Record<string, unknown> = {}): Record<string, unknown> {\n return this._componentManager.createComponentFromSchema(componentName, overrides);\n }\n\n /**\n * Validate component data against its schema.\n * \n * @param componentName - The name of the component type\n * @param data - The component data to validate\n * @returns true if valid, false otherwise\n */\n validateComponentData(componentName: ComponentName, data: unknown): boolean {\n return this._componentManager.validateComponentData(componentName, data);\n }\n\n /**\n * Add a component to an entity with schema validation.\n * \n * @param componentName - The name of the component type\n * @param entity - The entity to add the component to\n * @param component - The component data\n * @param validate - Whether to validate against schema (default: true)\n * @throws Error if validation fails\n */\n addComponentToEntityWithSchema(componentName: ComponentName, entity: Entity, component: Record<string, unknown>, validate: boolean = true): void {\n this._componentManager.addComponentToEntityWithSchema(componentName, entity, component, validate);\n let signature = this._entityManager.getSignature(entity);\n if(signature === null) {\n signature = 0;\n }\n const componentType = this._componentManager.getComponentType(componentName);\n if(componentType === null) {\n console.warn(`Component ${getComponentNameString(componentName)} not registered`);\n return;\n }\n signature |= 1 << componentType;\n this._entityManager.setSignature(entity, signature);\n this._systemManager.entitySignatureChanged(entity, signature);\n }\n\n /**\n * Get all living entities in the ECS.\n * @returns Array of all entity IDs that are currently active\n * \n * @example\n * ```typescript\n * const entities = coordinator.getAllEntities();\n * console.log(`Total entities: ${entities.length}`);\n * ```\n */\n getAllEntities(): Entity[] {\n return this._entityManager.getAllLivingEntities();\n }\n\n /**\n * Check if an entity exists in the coordinator.\n * @param entity - The entity ID to check\n * @returns true if the entity exists, false otherwise\n * \n * @example\n * ```typescript\n * const entity = coordinator.createEntity();\n * if (coordinator.entityExists(entity)) {\n * console.log('Entity exists');\n * }\n * \n * coordinator.destroyEntity(entity);\n * if (!coordinator.entityExists(entity)) {\n * console.log('Entity no longer exists');\n * }\n * ```\n */\n entityExists(entity: Entity): boolean {\n return this._entityManager.entityExists(entity);\n }\n\n /**\n * Get all components for a specific entity.\n * @param entity - The entity ID\n * @returns Map of component names to their data, or null if entity doesn't exist\n * \n * @example\n * ```typescript\n * const components = coordinator.getEntityComponents(entity);\n * if (components) {\n * console.log('Entity components:', components);\n * }\n * ```\n */\n getEntityComponents(entity: Entity): Map<ComponentName, unknown> | null {\n const signature = this._entityManager.getSignature(entity);\n if (signature === null || signature === 0) {\n return null;\n }\n\n const components = new Map<ComponentName, unknown>();\n const componentNames = this._componentManager.getRegisteredComponentNames();\n\n for (const componentName of componentNames) {\n const componentType = this._componentManager.getComponentType(componentName);\n if (componentType === null) {\n continue;\n }\n\n // Check if entity has this component (bit is set in signature)\n if ((signature & (1 << componentType)) !== 0) {\n const componentData = this._componentManager.getComponentFromEntity(componentName, entity);\n if (componentData !== null) {\n components.set(componentName, componentData);\n }\n }\n }\n\n return components;\n }\n\n /**\n * Get the entire state of the ECS: all entities with all their component values.\n * @returns Object containing all entities and their components\n * \n * @example\n * ```typescript\n * const state = coordinator.getFullState();\n * console.log(`Total entities: ${state.entities.length}`);\n * state.entities.forEach(entityData => {\n * console.log(`Entity ${entityData.entity} has ${Object.keys(entityData.components).length} components`);\n * });\n * ```\n */\n getFullState(): { entities: Array<{ entity: Entity; components: Map<ComponentName, unknown> }> } {\n const allEntities = this.getAllEntities();\n const entities = allEntities.map(entity => ({\n entity,\n components: this.getEntityComponents(entity) ?? new Map<ComponentName, unknown>()\n }));\n\n return { entities };\n }\n\n /**\n * Serialize the entire ECS state to a JSON-compatible format.\n * Note: Only works with global symbols (created via Symbol.for or createGlobalComponentName).\n * \n * @returns A serializable representation of the ECS state\n * @throws Error if any component name is not a global symbol\n * \n * @example\n * ```typescript\n * const serialized = coordinator.serialize();\n * const json = JSON.stringify(serialized);\n * // Save to file or send over network\n * ```\n */\n serialize(): SerializedECSState {\n const allEntities = this.getAllEntities();\n const serializedEntities: SerializedEntity[] = [];\n const componentNames = this._componentManager.getRegisteredComponentNames();\n\n for (const entity of allEntities) {\n const components: Record<string, unknown> = {};\n let hasComponents = false;\n\n for (const componentName of componentNames) {\n const componentData = this._componentManager.getComponentFromEntity(componentName, entity);\n if (componentData !== null) {\n const key = Symbol.keyFor(componentName);\n if (key === undefined) {\n throw new Error(\n `Cannot serialize: component name \"${getComponentNameString(componentName)}\" is not a global symbol. ` +\n `Use createGlobalComponentName() or Symbol.for() to create component names.`\n );\n }\n components[key] = componentData;\n hasComponents = true;\n }\n }\n\n // Only include entities that have at least one component\n if (hasComponents) {\n serializedEntities.push({\n entity,\n components\n });\n }\n }\n\n // Optionally include schemas\n const schemas = this._componentManager.getAllComponentSchemas();\n const serializedSchemas = schemas.length > 0\n ? schemas.map(schema => serializeComponentSchema(schema))\n : undefined;\n\n return {\n entities: serializedEntities,\n ...(serializedSchemas && { schemas: serializedSchemas })\n };\n }\n\n /**\n * Deserialize an ECS state from a JSON-compatible format.\n * This will restore all entities and their components.\n * \n * @param serialized - The serialized ECS state\n * @param options - Options for deserialization\n * @param options.clearExisting - Whether to clear existing entities before deserializing (default: false)\n * @throws Error if component names cannot be resolved or components are not registered\n * \n * @example\n * ```typescript\n * const json = fs.readFileSync('state.json', 'utf-8');\n * const serialized = JSON.parse(json);\n * coordinator.deserialize(serialized, { clearExisting: true });\n * ```\n */\n deserialize(serialized: SerializedECSState, options: { clearExisting?: boolean } = {}): void {\n const { clearExisting = false } = options;\n\n if (clearExisting) {\n // Destroy all existing entities\n const existingEntities = this.getAllEntities();\n for (const entity of existingEntities) {\n this.destroyEntity(entity);\n }\n }\n\n // Restore entities and components\n for (const entityData of serialized.entities) {\n // Create entity (or reuse if not clearing)\n let entity: Entity;\n if (clearExisting) {\n entity = this.createEntity();\n } else {\n // Try to use the original entity ID if available\n // If entity already exists, we'll update it; otherwise create new\n const existingSignature = this._entityManager.getSignature(entityData.entity);\n if (existingSignature === null) {\n // Entity doesn't exist, we need to create it\n // But we can't control the entity ID, so we'll create a new one\n entity = this.createEntity();\n } else {\n entity = entityData.entity;\n }\n }\n\n // Add all components\n for (const [componentNameStr, componentData] of Object.entries(entityData.components)) {\n const componentName = Symbol.for(componentNameStr);\n \n // Check if component is registered\n const componentType = this._componentManager.getComponentType(componentName);\n if (componentType === null) {\n throw new Error(\n `Cannot deserialize: component \"${componentNameStr}\" is not registered. ` +\n `Register it first using registerComponent() or registerComponentWithSchema().`\n );\n }\n\n // Add component (with schema validation if schema exists)\n const schema = this._componentManager.getComponentSchema(componentName);\n if (schema) {\n this.addComponentToEntityWithSchema(\n componentName,\n entity,\n componentData as Record<string, unknown>,\n true\n );\n } else {\n this.addComponentToEntity(componentName, entity, componentData);\n }\n }\n }\n }\n}\n"
6
6
  ],
7
- "mappings": "AAiGO,IAAM,EAAe,IAMf,EAAiB,GAkCvB,MAAM,CAAc,CAEf,mBAA+B,CAAC,EAChC,YAAoC,CAAC,EACrC,aAEA,mBAAqB,EAE7B,WAAW,CAAC,EAhDY,IAgDwB,CAC5C,KAAK,aAAe,EACpB,QAAS,EAAI,EAAG,EAAI,KAAK,aAAc,IACnC,KAAK,mBAAmB,KAAK,CAAC,EAC9B,KAAK,YAAY,KAAK,CAAC,EAI/B,YAAY,EAAW,CACnB,GAAG,KAAK,oBAAsB,KAAK,aAC/B,MAAU,MAAM,sBAAsB,EAE1C,IAAM,EAAS,KAAK,mBAAmB,MAAM,EAC7C,GAAG,IAAW,OACV,MAAU,MAAM,uBAAuB,EAI3C,OAFA,KAAK,YAAY,GAAU,EAC3B,KAAK,qBACE,EAGX,aAAa,CAAC,EAAsB,CAChC,GAAG,GAAU,KAAK,cAAgB,EAAS,EACvC,MAAU,MAAM,6BAA6B,EAEjD,KAAK,YAAY,GAAU,EAC3B,KAAK,mBAAmB,KAAK,CAAM,EACnC,KAAK,qBAGT,YAAY,CAAC,EAAgB,EAAqC,CAC9D,GAAG,GAAU,KAAK,cAAgB,EAAS,EACvC,MAAU,MAAM,6BAA6B,EAEjD,KAAK,YAAY,GAAU,EAG/B,YAAY,CAAC,EAA2C,CACpD,GAAG,GAAU,KAAK,cAAgB,EAAS,EACvC,OAAO,KAEX,OAAO,KAAK,YAAY,GAEhC,CAyCO,MAAM,CAAoC,CAErC,WACA,OACA,QACA,OAER,WAAW,CAAC,EAAqB,CAC7B,KAAK,OAAS,EACd,KAAK,WAAiB,MAAM,CAAW,EACvC,KAAK,OAAa,MAAM,CAAW,EACnC,KAAK,QAAc,MAAM,CAAW,EAGxC,UAAU,CAAC,EAAgB,EAAe,CACtC,GAAG,KAAK,QAAQ,CAAM,IAAM,KACxB,KAAK,WAAW,CAAM,EAE1B,GAAG,KAAK,OAAO,OAAS,EAEpB,KAAK,OAAS,CAAC,GAAG,KAAK,OAAQ,GAAO,MAAM,EAAS,KAAK,OAAO,MAAM,EAAE,KAAK,IAAI,CAAC,EAGvF,KAAK,WAAW,KAAK,QAAU,EAC/B,KAAK,QAAQ,KAAK,QAAU,EAC5B,KAAK,OAAO,GAAU,KAAK,OAC3B,KAAK,SAGT,OAAO,CAAC,EAA0B,CAC9B,GAAG,KAAK,OAAO,QAAU,EACrB,OAAO,KAGX,IAAM,EAAa,KAAK,OAAO,GAC/B,GAAG,IAAe,QAAa,IAAe,MAAQ,GAAc,KAAK,OACrE,OAAO,KAGX,GAAG,KAAK,QAAQ,KAAgB,EAC5B,OAAO,KAGX,OAAO,KAAK,WAAW,GAG3B,UAAU,CAAC,EAAsB,CAC7B,IAAM,EAAa,KAAK,OAAO,GAC/B,GAAG,IAAe,QAAa,IAAe,MAAQ,GAAc,KAAK,OACrE,OAGJ,IAAM,EAAa,KAAK,QAAQ,KAAK,OAAS,GAE9C,GAAG,IAAe,KACd,OAGJ,KAAK,WAAW,GAAc,KAAK,WAAW,KAAK,OAAS,GAC5D,KAAK,QAAQ,GAAc,EAC3B,KAAK,OAAO,GAAc,EAC1B,KAAK,OAAO,GAAU,KAEtB,KAAK,SAGT,eAAe,CAAC,EAAsB,CAClC,KAAK,WAAW,CAAM,EAE9B,CAiBO,MAAM,CAAiB,CAElB,wBAA+F,IAAI,IACnG,4BAA6C,EAErD,iBAAoB,CAAC,EAAsB,CACvC,GAAG,KAAK,wBAAwB,IAAI,CAAa,EAC7C,QAAQ,KAAK,aAAa,2DAAuE,EAErG,IAAM,EAAgB,KAAK,4BAC3B,KAAK,wBAAwB,IAAI,EAAe,CAAC,gBAAe,eAAgB,IAAI,EApOhE,GAoO8F,CAAC,CAAC,EACpH,KAAK,8BAGT,gBAAgB,CAAC,EAA6C,CAC1D,OAAO,KAAK,wBAAwB,IAAI,CAAa,GAAG,eAAiB,KAG7E,oBAAuB,CAAC,EAAuB,EAAgB,EAAa,CACxE,IAAM,EAAiB,KAAK,mBAAsB,CAAa,EAC/D,GAAG,IAAmB,KAClB,OAEJ,EAAe,WAAW,EAAQ,CAAS,EAG/C,yBAA4B,CAAC,EAAuB,EAAe,CAC/D,IAAM,EAAiB,KAAK,mBAAsB,CAAa,EAC/D,GAAG,IAAmB,KAClB,OAEJ,EAAe,WAAW,CAAM,EAGpC,sBAAyB,CAAC,EAAuB,EAA0B,CACvE,IAAM,EAAiB,KAAK,mBAAsB,CAAa,EAC/D,GAAG,IAAmB,KAClB,OAAO,KAEX,OAAO,EAAe,QAAQ,CAAM,EAGxC,eAAe,CAAC,EAAe,CAC3B,QAAU,KAAa,KAAK,wBAAwB,OAAO,EACvD,EAAU,eAAe,gBAAgB,CAAM,EAI/C,kBAAqB,CAAC,EAAiD,CAC3E,IAAM,EAAY,KAAK,wBAAwB,IAAI,CAAa,EAChE,GAAG,IAAc,OAEb,OADA,QAAQ,KAAK,aAAa,kBAA8B,EACjD,KAEX,OAAO,EAAU,eAGzB,CAuDO,MAAM,CAAc,CACf,SAAyE,IAAI,IAErF,cAAc,CAAC,EAAoB,EAAe,CAC9C,GAAG,KAAK,SAAS,IAAI,CAAU,EAAG,CAC9B,QAAQ,KAAK,UAAU,sBAA+B,EACtD,OAEJ,KAAK,SAAS,IAAI,EAAY,CAAC,SAAQ,UAAW,CAAC,CAAC,EAGxD,YAAY,CAAC,EAAoB,EAA8B,CAC3D,GAAG,CAAC,KAAK,SAAS,IAAI,CAAU,EAAG,CAC/B,QAAQ,KAAK,UAAU,kBAA2B,EAClD,OAEJ,IAAM,EAAS,KAAK,SAAS,IAAI,CAAU,EAC3C,GAAG,IAAW,OAAW,CACrB,QAAQ,KAAK,UAAU,kBAA2B,EAClD,OAEJ,EAAO,UAAY,EAGvB,eAAe,CAAC,EAAe,CAC3B,QAAU,KAAU,KAAK,SAAS,OAAO,EACrC,EAAO,OAAO,SAAS,OAAO,CAAM,EAI5C,sBAAsB,CAAC,EAAgB,EAA8B,CACjE,QAAU,KAAU,KAAK,SAAS,OAAO,EAAE,CACvC,IAAM,EAAkB,EAAO,UAC/B,IAAI,EAAkB,KAAe,EACjC,EAAO,OAAO,SAAS,IAAI,CAAM,EAEjC,OAAO,OAAO,SAAS,OAAO,CAAM,GAIpD,CA4CO,MAAM,CAAY,CACb,eACA,kBACA,eAER,WAAW,EAAE,CACT,KAAK,eAAiB,IAAI,EAC1B,KAAK,kBAAoB,IAAI,EAC7B,KAAK,eAAiB,IAAI,EAG9B,YAAY,EAAW,CACnB,OAAO,KAAK,eAAe,aAAa,EAG5C,aAAa,CAAC,EAAsB,CAChC,KAAK,eAAe,cAAc,CAAM,EACxC,KAAK,kBAAkB,gBAAgB,CAAM,EAC7C,KAAK,eAAe,gBAAgB,CAAM,EAG9C,iBAAoB,CAAC,EAA6B,CAC9C,KAAK,kBAAkB,kBAAqB,CAAa,EAG7D,oBAAuB,CAAC,EAAuB,EAAgB,EAAoB,CAC/E,KAAK,kBAAkB,qBAAwB,EAAe,EAAQ,CAAS,EAC/E,IAAI,EAAY,KAAK,eAAe,aAAa,CAAM,EACvD,GAAG,IAAc,KACb,EAAY,EAEhB,IAAM,EAAgB,KAAK,kBAAkB,iBAAiB,CAAa,EAC3E,GAAG,IAAkB,KAAM,CACvB,QAAQ,KAAK,aAAa,kBAA8B,EACxD,OAEJ,GAAa,GAAK,EAClB,KAAK,eAAe,aAAa,EAAQ,CAAS,EAClD,KAAK,eAAe,uBAAuB,EAAQ,CAAS,EAGhE,yBAA4B,CAAC,EAAuB,EAAsB,CACtE,KAAK,kBAAkB,0BAA6B,EAAe,CAAM,EACzE,IAAI,EAAY,KAAK,eAAe,aAAa,CAAM,EACvD,GAAG,IAAc,KACb,EAAY,EAEhB,IAAM,EAAgB,KAAK,kBAAkB,iBAAiB,CAAa,EAC3E,GAAG,IAAkB,KACjB,OAEJ,GAAa,EAAE,GAAK,GACpB,KAAK,eAAe,aAAa,EAAQ,CAAS,EAClD,KAAK,eAAe,uBAAuB,EAAQ,CAAS,EAGhE,sBAAyB,CAAC,EAAuB,EAA0B,CACvE,OAAO,KAAK,kBAAkB,uBAA0B,EAAe,CAAM,EAGjF,gBAAgB,CAAC,EAA6C,CAC1D,OAAO,KAAK,kBAAkB,iBAAiB,CAAa,GAAK,KAGrE,cAAc,CAAC,EAAoB,EAAsB,CACrD,KAAK,eAAe,eAAe,EAAY,CAAM,EAGzD,kBAAkB,CAAC,EAAoB,EAAqC,CACxE,KAAK,eAAe,aAAa,EAAY,CAAS,EAE9D",
8
- "debugId": "983008DE2E282BA464756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "1A0F397F448E17CB64756E2164756E21",
9
9
  "names": []
10
10
  }
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@ue-too/ecs",
3
3
  "author": "niuee",
4
4
  "type": "module",
5
- "version": "0.12.0",
5
+ "version": "0.13.0",
6
6
  "description": "Entity Component System for uē-tôo",
7
7
  "license": "MIT",
8
8
  "repository": {