iris-ecs 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +721 -0
  3. package/dist/actions.d.ts +43 -0
  4. package/dist/actions.d.ts.map +1 -0
  5. package/dist/actions.js +35 -0
  6. package/dist/actions.js.map +1 -0
  7. package/dist/archetype.d.ts +194 -0
  8. package/dist/archetype.d.ts.map +1 -0
  9. package/dist/archetype.js +412 -0
  10. package/dist/archetype.js.map +1 -0
  11. package/dist/component.d.ts +89 -0
  12. package/dist/component.d.ts.map +1 -0
  13. package/dist/component.js +237 -0
  14. package/dist/component.js.map +1 -0
  15. package/dist/encoding.d.ts +204 -0
  16. package/dist/encoding.d.ts.map +1 -0
  17. package/dist/encoding.js +215 -0
  18. package/dist/encoding.js.map +1 -0
  19. package/dist/entity.d.ts +129 -0
  20. package/dist/entity.d.ts.map +1 -0
  21. package/dist/entity.js +243 -0
  22. package/dist/entity.js.map +1 -0
  23. package/dist/event.d.ts +237 -0
  24. package/dist/event.d.ts.map +1 -0
  25. package/dist/event.js +293 -0
  26. package/dist/event.js.map +1 -0
  27. package/dist/filters.d.ts +121 -0
  28. package/dist/filters.d.ts.map +1 -0
  29. package/dist/filters.js +202 -0
  30. package/dist/filters.js.map +1 -0
  31. package/dist/index.d.ts +24 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +54 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/name.d.ts +70 -0
  36. package/dist/name.d.ts.map +1 -0
  37. package/dist/name.js +172 -0
  38. package/dist/name.js.map +1 -0
  39. package/dist/observer.d.ts +83 -0
  40. package/dist/observer.d.ts.map +1 -0
  41. package/dist/observer.js +62 -0
  42. package/dist/observer.js.map +1 -0
  43. package/dist/query.d.ts +198 -0
  44. package/dist/query.d.ts.map +1 -0
  45. package/dist/query.js +299 -0
  46. package/dist/query.js.map +1 -0
  47. package/dist/registry.d.ts +118 -0
  48. package/dist/registry.d.ts.map +1 -0
  49. package/dist/registry.js +112 -0
  50. package/dist/registry.js.map +1 -0
  51. package/dist/relation.d.ts +60 -0
  52. package/dist/relation.d.ts.map +1 -0
  53. package/dist/relation.js +171 -0
  54. package/dist/relation.js.map +1 -0
  55. package/dist/removal.d.ts +27 -0
  56. package/dist/removal.d.ts.map +1 -0
  57. package/dist/removal.js +66 -0
  58. package/dist/removal.js.map +1 -0
  59. package/dist/resource.d.ts +78 -0
  60. package/dist/resource.d.ts.map +1 -0
  61. package/dist/resource.js +86 -0
  62. package/dist/resource.js.map +1 -0
  63. package/dist/scheduler.d.ts +106 -0
  64. package/dist/scheduler.d.ts.map +1 -0
  65. package/dist/scheduler.js +204 -0
  66. package/dist/scheduler.js.map +1 -0
  67. package/dist/schema.d.ts +117 -0
  68. package/dist/schema.d.ts.map +1 -0
  69. package/dist/schema.js +113 -0
  70. package/dist/schema.js.map +1 -0
  71. package/dist/world.d.ts +172 -0
  72. package/dist/world.d.ts.map +1 -0
  73. package/dist/world.js +127 -0
  74. package/dist/world.js.map +1 -0
  75. package/package.json +52 -0
@@ -0,0 +1,118 @@
1
+ import type { Component, Relation, Tag } from "./encoding.js";
2
+ import type { SchemaRecord } from "./schema.js";
3
+ /**
4
+ * Component metadata.
5
+ *
6
+ * Stores component name, optional schema, and relation traits.
7
+ */
8
+ export type ComponentMeta = {
9
+ /**
10
+ * Component name (user-defined).
11
+ */
12
+ name: string;
13
+ /**
14
+ * Field schemas for data components (undefined for tags).
15
+ */
16
+ schema?: SchemaRecord;
17
+ /**
18
+ * If true, entity can only have one target at a time for this relation.
19
+ */
20
+ exclusive?: boolean;
21
+ /**
22
+ * What happens when a pair target is destroyed. Default is "remove".
23
+ */
24
+ onDeleteTarget?: "remove" | "delete";
25
+ };
26
+ /**
27
+ * Options for defining relations.
28
+ *
29
+ * Controls relation behavior including exclusivity and delete policies.
30
+ */
31
+ export type RelationOptions<S extends SchemaRecord = Record<string, never>> = {
32
+ /**
33
+ * Field schemas for pair data (optional).
34
+ */
35
+ schema?: S;
36
+ /**
37
+ * If true, entity can only have one target for this relation.
38
+ */
39
+ exclusive?: boolean;
40
+ /**
41
+ * What happens when a pair target is destroyed. Default is "remove".
42
+ */
43
+ onDeleteTarget?: "remove" | "delete";
44
+ };
45
+ /**
46
+ * Global singleton storing all component metadata across all worlds.
47
+ */
48
+ export type ComponentRegistry = {
49
+ /**
50
+ * Component metadata lookup (component ID -> metadata).
51
+ */
52
+ byId: Map<Tag | Component | Relation, ComponentMeta>;
53
+ /**
54
+ * Next raw ID to allocate for tags.
55
+ */
56
+ nextTagId: number;
57
+ /**
58
+ * Next raw ID to allocate for data components.
59
+ */
60
+ nextComponentId: number;
61
+ /**
62
+ * Next raw ID to allocate for relations.
63
+ */
64
+ nextRelationId: number;
65
+ };
66
+ /**
67
+ * Global component registry singleton.
68
+ */
69
+ export declare const COMPONENT_REGISTRY: ComponentRegistry;
70
+ /**
71
+ * Defines a tag component. Tags are lightweight markers without data.
72
+ * @param name - Human-readable tag name for debugging
73
+ * @returns Encoded tag ID
74
+ * @throws {RangeError} If tag limit (1,048,576) exceeded
75
+ * @example
76
+ * const Player = defineTag("Player");
77
+ * addTag(world, entity, Player);
78
+ */
79
+ export declare function defineTag(name: string): Tag;
80
+ /**
81
+ * Defines a data component with a typed schema for storage.
82
+ * @param name - Human-readable component name for debugging
83
+ * @param schema - Field schema record defining data layout
84
+ * @returns Encoded component ID with schema type
85
+ * @throws {RangeError} If component limit (1,048,576) exceeded
86
+ * @example
87
+ * const Position = defineComponent("Position", { x: Type.f32, y: Type.f32 });
88
+ * set(world, entity, Position, { x: 10, y: 20 });
89
+ */
90
+ export declare function defineComponent<S extends SchemaRecord>(name: string, schema: S): Component<S>;
91
+ /**
92
+ * Defines a relation for entity-to-entity relationships.
93
+ * @param name - Human-readable relation name for debugging
94
+ * @param options - Configuration: schema for data, exclusive trait, delete behavior
95
+ * @returns Encoded relation ID with schema type
96
+ * @throws {RangeError} If relation limit (256) exceeded
97
+ * @example
98
+ * const ChildOf = defineRelation("ChildOf", { exclusive: true, onDeleteTarget: "delete" });
99
+ * addPair(world, child, ChildOf, parent);
100
+ */
101
+ export declare function defineRelation<S extends SchemaRecord = Record<string, never>>(name: string, options?: RelationOptions<S>): Relation<S>;
102
+ /**
103
+ * Wildcard relation for query patterns. Reserved as relation ID 0.
104
+ * - `pair(Wildcard, target)` matches all entities targeting target
105
+ * - `pair(relation, Wildcard)` matches entities with any target for relation
106
+ */
107
+ export declare const Wildcard: Relation<Record<string, never>>;
108
+ /**
109
+ * Marks a relation as exclusive (one target per subject).
110
+ * Adding a pair with an exclusive relation auto-removes any existing pair with that relation.
111
+ */
112
+ export declare const Exclusive: Tag;
113
+ /**
114
+ * Cascade delete subjects when target is destroyed.
115
+ * When an entity is destroyed, all entities with a pair targeting it are also destroyed.
116
+ */
117
+ export declare const OnDeleteTarget: Tag;
118
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAE9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAMhD;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,MAAM,CAAC,EAAE,YAAY,CAAC;IAEtB;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;OAEG;IACH,cAAc,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;CACtC,CAAC;AAMF;;;;GAIG;AACH,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI;IAC5E;;OAEG;IACH,MAAM,CAAC,EAAE,CAAC,CAAC;IAEX;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;OAEG;IACH,cAAc,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;CACtC,CAAC;AAMF;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;OAEG;IACH,IAAI,EAAE,GAAG,CAAC,GAAG,GAAG,SAAS,GAAG,QAAQ,EAAE,aAAa,CAAC,CAAC;IACrD;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,eAAe,EAAE,MAAM,CAAC;IACxB;;OAEG;IACH,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,kBAAkB,EAAE,iBAKhC,CAAC;AAMF;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,CAiB3C;AAMD;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,CAiB7F;AAMD;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EAC3E,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,eAAe,CAAC,CAAC,CAAC,GAC3B,QAAQ,CAAC,CAAC,CAAC,CAmBb;AAMD;;;;GAIG;AACH,eAAO,MAAM,QAAQ,iCAA6B,CAAC;AAMnD;;;GAGG;AACH,eAAO,MAAM,SAAS,KAAyB,CAAC;AAEhD;;;GAGG;AACH,eAAO,MAAM,cAAc,KAA8B,CAAC"}
@@ -0,0 +1,112 @@
1
+ import { encodeComponent, encodeRelation, encodeTag, ID_MASK_8, ID_MASK_20 } from "./encoding.js";
2
+ /**
3
+ * Global component registry singleton.
4
+ */
5
+ export const COMPONENT_REGISTRY = {
6
+ byId: new Map(),
7
+ nextTagId: 0,
8
+ nextComponentId: 0,
9
+ nextRelationId: 0,
10
+ };
11
+ // ============================================================================
12
+ // Tag Definition
13
+ // ============================================================================
14
+ /**
15
+ * Defines a tag component. Tags are lightweight markers without data.
16
+ * @param name - Human-readable tag name for debugging
17
+ * @returns Encoded tag ID
18
+ * @throws {RangeError} If tag limit (1,048,576) exceeded
19
+ * @example
20
+ * const Player = defineTag("Player");
21
+ * addTag(world, entity, Player);
22
+ */
23
+ export function defineTag(name) {
24
+ const rawId = COMPONENT_REGISTRY.nextTagId;
25
+ if (rawId > ID_MASK_20) {
26
+ throw new RangeError(`Tag limit exceeded (max ${ID_MASK_20})`);
27
+ }
28
+ const tagId = encodeTag(rawId);
29
+ COMPONENT_REGISTRY.byId.set(tagId, {
30
+ name,
31
+ schema: undefined,
32
+ });
33
+ COMPONENT_REGISTRY.nextTagId++;
34
+ return tagId;
35
+ }
36
+ // ============================================================================
37
+ // Component Definition
38
+ // ============================================================================
39
+ /**
40
+ * Defines a data component with a typed schema for storage.
41
+ * @param name - Human-readable component name for debugging
42
+ * @param schema - Field schema record defining data layout
43
+ * @returns Encoded component ID with schema type
44
+ * @throws {RangeError} If component limit (1,048,576) exceeded
45
+ * @example
46
+ * const Position = defineComponent("Position", { x: Type.f32, y: Type.f32 });
47
+ * set(world, entity, Position, { x: 10, y: 20 });
48
+ */
49
+ export function defineComponent(name, schema) {
50
+ const rawId = COMPONENT_REGISTRY.nextComponentId;
51
+ if (rawId > ID_MASK_20) {
52
+ throw new RangeError(`Component limit exceeded (max ${ID_MASK_20})`);
53
+ }
54
+ const componentId = encodeComponent(rawId);
55
+ COMPONENT_REGISTRY.byId.set(componentId, {
56
+ name,
57
+ schema,
58
+ });
59
+ COMPONENT_REGISTRY.nextComponentId++;
60
+ return componentId;
61
+ }
62
+ // ============================================================================
63
+ // Relation Definition
64
+ // ============================================================================
65
+ /**
66
+ * Defines a relation for entity-to-entity relationships.
67
+ * @param name - Human-readable relation name for debugging
68
+ * @param options - Configuration: schema for data, exclusive trait, delete behavior
69
+ * @returns Encoded relation ID with schema type
70
+ * @throws {RangeError} If relation limit (256) exceeded
71
+ * @example
72
+ * const ChildOf = defineRelation("ChildOf", { exclusive: true, onDeleteTarget: "delete" });
73
+ * addPair(world, child, ChildOf, parent);
74
+ */
75
+ export function defineRelation(name, options) {
76
+ const rawId = COMPONENT_REGISTRY.nextRelationId;
77
+ if (rawId > ID_MASK_8) {
78
+ throw new RangeError(`Relation limit exceeded (max ${ID_MASK_8})`);
79
+ }
80
+ const relationId = encodeRelation(rawId);
81
+ COMPONENT_REGISTRY.byId.set(relationId, {
82
+ name,
83
+ schema: options?.schema,
84
+ exclusive: options?.exclusive,
85
+ onDeleteTarget: options?.onDeleteTarget,
86
+ });
87
+ COMPONENT_REGISTRY.nextRelationId++;
88
+ return relationId;
89
+ }
90
+ // ============================================================================
91
+ // Built-in Relations
92
+ // ============================================================================
93
+ /**
94
+ * Wildcard relation for query patterns. Reserved as relation ID 0.
95
+ * - `pair(Wildcard, target)` matches all entities targeting target
96
+ * - `pair(relation, Wildcard)` matches entities with any target for relation
97
+ */
98
+ export const Wildcard = defineRelation("Wildcard");
99
+ // ============================================================================
100
+ // Relation Trait Tags
101
+ // ============================================================================
102
+ /**
103
+ * Marks a relation as exclusive (one target per subject).
104
+ * Adding a pair with an exclusive relation auto-removes any existing pair with that relation.
105
+ */
106
+ export const Exclusive = defineTag("Exclusive");
107
+ /**
108
+ * Cascade delete subjects when target is destroyed.
109
+ * When an entity is destroyed, all entities with a pair targeting it are also destroyed.
110
+ */
111
+ export const OnDeleteTarget = defineTag("OnDeleteTarget");
112
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAsFlG;;GAEG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAsB;IACnD,IAAI,EAAE,IAAI,GAAG,EAAE;IACf,SAAS,EAAE,CAAC;IACZ,eAAe,EAAE,CAAC;IAClB,cAAc,EAAE,CAAC;CAClB,CAAC;AAEF,+EAA+E;AAC/E,iBAAiB;AACjB,+EAA+E;AAE/E;;;;;;;;GAQG;AACH,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,MAAM,KAAK,GAAG,kBAAkB,CAAC,SAAS,CAAC;IAE3C,IAAI,KAAK,GAAG,UAAU,EAAE,CAAC;QACvB,MAAM,IAAI,UAAU,CAAC,2BAA2B,UAAU,GAAG,CAAC,CAAC;IACjE,CAAC;IAED,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;IAE/B,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE;QACjC,IAAI;QACJ,MAAM,EAAE,SAAS;KAClB,CAAC,CAAC;IAEH,kBAAkB,CAAC,SAAS,EAAE,CAAC;IAE/B,OAAO,KAAK,CAAC;AACf,CAAC;AAED,+EAA+E;AAC/E,uBAAuB;AACvB,+EAA+E;AAE/E;;;;;;;;;GASG;AACH,MAAM,UAAU,eAAe,CAAyB,IAAY,EAAE,MAAS;IAC7E,MAAM,KAAK,GAAG,kBAAkB,CAAC,eAAe,CAAC;IAEjD,IAAI,KAAK,GAAG,UAAU,EAAE,CAAC;QACvB,MAAM,IAAI,UAAU,CAAC,iCAAiC,UAAU,GAAG,CAAC,CAAC;IACvE,CAAC;IAED,MAAM,WAAW,GAAG,eAAe,CAAI,KAAK,CAAC,CAAC;IAE9C,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE;QACvC,IAAI;QACJ,MAAM;KACP,CAAC,CAAC;IAEH,kBAAkB,CAAC,eAAe,EAAE,CAAC;IAErC,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,+EAA+E;AAC/E,sBAAsB;AACtB,+EAA+E;AAE/E;;;;;;;;;GASG;AACH,MAAM,UAAU,cAAc,CAC5B,IAAY,EACZ,OAA4B;IAE5B,MAAM,KAAK,GAAG,kBAAkB,CAAC,cAAc,CAAC;IAEhD,IAAI,KAAK,GAAG,SAAS,EAAE,CAAC;QACtB,MAAM,IAAI,UAAU,CAAC,gCAAgC,SAAS,GAAG,CAAC,CAAC;IACrE,CAAC;IAED,MAAM,UAAU,GAAG,cAAc,CAAI,KAAK,CAAC,CAAC;IAE5C,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE;QACtC,IAAI;QACJ,MAAM,EAAE,OAAO,EAAE,MAAM;QACvB,SAAS,EAAE,OAAO,EAAE,SAAS;QAC7B,cAAc,EAAE,OAAO,EAAE,cAAc;KACxC,CAAC,CAAC;IAEH,kBAAkB,CAAC,cAAc,EAAE,CAAC;IAEpC,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,+EAA+E;AAC/E,qBAAqB;AACrB,+EAA+E;AAE/E;;;;GAIG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,cAAc,CAAC,UAAU,CAAC,CAAC;AAEnD,+EAA+E;AAC/E,sBAAsB;AACtB,+EAA+E;AAE/E;;;GAGG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,SAAS,CAAC,WAAW,CAAC,CAAC;AAEhD;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,SAAS,CAAC,gBAAgB,CAAC,CAAC"}
@@ -0,0 +1,60 @@
1
+ import type { EntityId, Pair, Relation, RelationTargetId } from "./encoding.js";
2
+ import type { World } from "./world.js";
3
+ /**
4
+ * Create a pair from a relation and target.
5
+ *
6
+ * @param relation - Relation ID
7
+ * @param target - Target entity, tag, component, or relation
8
+ * @returns Encoded pair ID that can be used as a component
9
+ *
10
+ * @example
11
+ * const childOf = pair(ChildOf, parent);
12
+ * addComponent(world, child, childOf);
13
+ */
14
+ export declare function pair<R extends Relation>(relation: R, target: RelationTargetId): Pair<R>;
15
+ /**
16
+ * Extract the relation component from a pair.
17
+ *
18
+ * @param pairId - Encoded pair ID
19
+ * @returns The relation ID
20
+ *
21
+ * @example
22
+ * const rel = getPairRelation(pair(ChildOf, parent)); // ChildOf
23
+ */
24
+ export declare function getPairRelation<R extends Relation>(pairId: Pair<R>): R;
25
+ /**
26
+ * Extract the target from a pair.
27
+ *
28
+ * For entity targets, looks up current generation for weak reference semantics.
29
+ *
30
+ * @param world - World instance
31
+ * @param pairId - Encoded pair ID
32
+ * @returns Target entity, tag, component, or relation
33
+ *
34
+ * @example
35
+ * const target = getPairTarget(world, pair(ChildOf, parent)); // parent
36
+ */
37
+ export declare function getPairTarget(world: World, pairId: Pair): RelationTargetId;
38
+ /**
39
+ * Get all targets for a relation on an entity.
40
+ *
41
+ * @param world - World instance
42
+ * @param entityId - Entity to query
43
+ * @param relation - Relation to find targets for
44
+ * @returns Array of target IDs
45
+ *
46
+ * @example
47
+ * const parents = getRelationTargets(world, child, ChildOf);
48
+ */
49
+ export declare function getRelationTargets(world: World, entityId: EntityId, relation: Relation): RelationTargetId[];
50
+ /**
51
+ * Clean up all pairs targeting a specific entity when it is destroyed.
52
+ *
53
+ * Handles OnDeleteTarget cascade policy by collecting and destroying subjects
54
+ * that have pairs with the target entity.
55
+ *
56
+ * @param world - World instance
57
+ * @param targetEntity - Entity being destroyed that may be a target
58
+ */
59
+ export declare function cleanupPairsTargetingEntity(world: World, targetEntity: EntityId): void;
60
+ //# sourceMappingURL=relation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relation.d.ts","sourceRoot":"","sources":["../src/relation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAmBhF,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAMxC;;;;;;;;;;GAUG;AACH,wBAAgB,IAAI,CAAC,CAAC,SAAS,QAAQ,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAAC,CAAC,CAAC,CAEvF;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAItE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,GAAG,gBAAgB,CA2B1E;AAMD;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,GAAG,gBAAgB,EAAE,CA4B3G;AAMD;;;;;;;;GAQG;AACH,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,QAAQ,GAAG,IAAI,CAkEtF"}
@@ -0,0 +1,171 @@
1
+ import { hasComponent } from "./component.js";
2
+ import { COMPONENT_TYPE, ENTITY_TYPE, encodeComponent, encodeEntity, encodePair, encodeRelation, encodeTag, extractId, extractPairRelationId, extractPairTargetId, extractPairTargetType, isPair, RELATIONSHIP_TYPE, TAG_TYPE, } from "./encoding.js";
3
+ import { destroyEntity, ensureEntity, isEntityAlive } from "./entity.js";
4
+ import { OnDeleteTarget, Wildcard } from "./registry.js";
5
+ // ============================================================================
6
+ // Pair Creation and Extraction
7
+ // ============================================================================
8
+ /**
9
+ * Create a pair from a relation and target.
10
+ *
11
+ * @param relation - Relation ID
12
+ * @param target - Target entity, tag, component, or relation
13
+ * @returns Encoded pair ID that can be used as a component
14
+ *
15
+ * @example
16
+ * const childOf = pair(ChildOf, parent);
17
+ * addComponent(world, child, childOf);
18
+ */
19
+ export function pair(relation, target) {
20
+ return encodePair(relation, target);
21
+ }
22
+ /**
23
+ * Extract the relation component from a pair.
24
+ *
25
+ * @param pairId - Encoded pair ID
26
+ * @returns The relation ID
27
+ *
28
+ * @example
29
+ * const rel = getPairRelation(pair(ChildOf, parent)); // ChildOf
30
+ */
31
+ export function getPairRelation(pairId) {
32
+ const relationRawId = extractPairRelationId(pairId);
33
+ return encodeRelation(relationRawId);
34
+ }
35
+ /**
36
+ * Extract the target from a pair.
37
+ *
38
+ * For entity targets, looks up current generation for weak reference semantics.
39
+ *
40
+ * @param world - World instance
41
+ * @param pairId - Encoded pair ID
42
+ * @returns Target entity, tag, component, or relation
43
+ *
44
+ * @example
45
+ * const target = getPairTarget(world, pair(ChildOf, parent)); // parent
46
+ */
47
+ export function getPairTarget(world, pairId) {
48
+ const targetRawId = extractPairTargetId(pairId);
49
+ const targetType = extractPairTargetType(pairId);
50
+ switch (targetType) {
51
+ case ENTITY_TYPE: {
52
+ // Entity targets use weak reference semantics - look up current generation
53
+ const generation = world.entities.generations.get(targetRawId);
54
+ return encodeEntity(targetRawId, generation);
55
+ }
56
+ case TAG_TYPE: {
57
+ return encodeTag(targetRawId);
58
+ }
59
+ case COMPONENT_TYPE: {
60
+ return encodeComponent(targetRawId);
61
+ }
62
+ case RELATIONSHIP_TYPE: {
63
+ return encodeRelation(targetRawId);
64
+ }
65
+ default:
66
+ throw new Error(`Invalid target type in pair: ${targetType}`);
67
+ }
68
+ }
69
+ // ============================================================================
70
+ // Relation Queries
71
+ // ============================================================================
72
+ /**
73
+ * Get all targets for a relation on an entity.
74
+ *
75
+ * @param world - World instance
76
+ * @param entityId - Entity to query
77
+ * @param relation - Relation to find targets for
78
+ * @returns Array of target IDs
79
+ *
80
+ * @example
81
+ * const parents = getRelationTargets(world, child, ChildOf);
82
+ */
83
+ export function getRelationTargets(world, entityId, relation) {
84
+ const meta = ensureEntity(world, entityId);
85
+ const relationRawId = extractId(relation);
86
+ const relationWildcardPair = encodePair(relation, Wildcard);
87
+ const targets = [];
88
+ for (const typeId of meta.archetype.types) {
89
+ if (!isPair(typeId)) {
90
+ continue;
91
+ }
92
+ // Skip wildcard pair (pair(relation, Wildcard))
93
+ if (typeId === relationWildcardPair) {
94
+ continue;
95
+ }
96
+ const pairRelationRawId = extractPairRelationId(typeId);
97
+ if (pairRelationRawId !== relationRawId) {
98
+ continue;
99
+ }
100
+ targets.push(getPairTarget(world, typeId));
101
+ }
102
+ return targets;
103
+ }
104
+ // ============================================================================
105
+ // Cleanup
106
+ // ============================================================================
107
+ /**
108
+ * Clean up all pairs targeting a specific entity when it is destroyed.
109
+ *
110
+ * Handles OnDeleteTarget cascade policy by collecting and destroying subjects
111
+ * that have pairs with the target entity.
112
+ *
113
+ * @param world - World instance
114
+ * @param targetEntity - Entity being destroyed that may be a target
115
+ */
116
+ export function cleanupPairsTargetingEntity(world, targetEntity) {
117
+ // Pairs themselves cannot be targets of other pairs
118
+ if (isPair(targetEntity)) {
119
+ return;
120
+ }
121
+ // Use wildcard pair to find all archetypes containing pairs with this target
122
+ const wildcardTargetPair = encodePair(Wildcard, targetEntity);
123
+ if (!isEntityAlive(world, wildcardTargetPair)) {
124
+ // Entity was never used as a target, nothing to clean up
125
+ return;
126
+ }
127
+ const wildcardMeta = ensureEntity(world, wildcardTargetPair);
128
+ // Separate pairs by their OnDeleteTarget policy:
129
+ // - pairsToRemove: Just destroy the pair entity (default behavior)
130
+ // - pairsToDelete: Cascade delete to subjects holding the pair
131
+ const pairsToRemove = new Set([wildcardTargetPair]);
132
+ const pairsToDelete = new Set();
133
+ for (const archetype of wildcardMeta.records) {
134
+ for (const typeId of archetype.types) {
135
+ if (typeId === wildcardTargetPair || !isPair(typeId) || getPairTarget(world, typeId) !== targetEntity) {
136
+ continue;
137
+ }
138
+ const relation = getPairRelation(typeId);
139
+ if (hasComponent(world, relation, OnDeleteTarget)) {
140
+ pairsToDelete.add(typeId);
141
+ }
142
+ else {
143
+ pairsToRemove.add(typeId);
144
+ }
145
+ }
146
+ }
147
+ // Phase 1: Collect subjects for cascade delete before destroying pairs
148
+ // Using Set prevents duplicates when entity has multiple cascading pairs
149
+ const subjectsToDelete = new Set();
150
+ for (const pairId of pairsToDelete) {
151
+ const pairMeta = ensureEntity(world, pairId);
152
+ for (const archetype of pairMeta.records) {
153
+ for (const entityId of archetype.entities) {
154
+ subjectsToDelete.add(entityId);
155
+ }
156
+ }
157
+ }
158
+ // Phase 2: Destroy non-cascading pair entities (removes pairs from subjects)
159
+ for (const pairId of pairsToRemove) {
160
+ destroyEntity(world, pairId);
161
+ }
162
+ // Phase 3: Destroy cascading pair entities
163
+ for (const pairId of pairsToDelete) {
164
+ destroyEntity(world, pairId);
165
+ }
166
+ // Phase 4: Delete subjects that had cascading pairs (may trigger recursive cascades)
167
+ for (const entityId of subjectsToDelete) {
168
+ destroyEntity(world, entityId);
169
+ }
170
+ }
171
+ //# sourceMappingURL=relation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relation.js","sourceRoot":"","sources":["../src/relation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import type { EntityId } from "./encoding.js";
2
+ import type { Event } from "./event.js";
3
+ import type { World } from "./world.js";
4
+ /**
5
+ * Schema for removal events containing the entity that had a component removed.
6
+ */
7
+ declare const RemovalEventSchema: {
8
+ entity: import("./schema.js").Schema<number>;
9
+ };
10
+ /**
11
+ * Gets the removal event for a component, creating it lazily if needed.
12
+ * @param componentId - Component to track removals for
13
+ * @returns Event that fires when the component is removed from any entity
14
+ * @example
15
+ * for (const { entity } of fetchEvents(world, removed(Health))) {
16
+ * playDeathEffect(entity);
17
+ * }
18
+ */
19
+ export declare function removed(componentId: EntityId): Event<typeof RemovalEventSchema>;
20
+ /**
21
+ * Initializes removal tracking by registering observers for component removals.
22
+ * @param world - World instance to initialize
23
+ * @internal
24
+ */
25
+ export declare function initRemovalSystem(world: World): void;
26
+ export {};
27
+ //# sourceMappingURL=removal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"removal.d.ts","sourceRoot":"","sources":["../src/removal.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAIxC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAMxC;;GAEG;AACH,QAAA,MAAM,kBAAkB;;CAEvB,CAAC;AAeF;;;;;;;;GAQG;AACH,wBAAgB,OAAO,CAAC,WAAW,EAAE,QAAQ,GAAG,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAS/E;AAMD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAmBpD"}
@@ -0,0 +1,66 @@
1
+ import { defineEvent, emitEvent } from "./event.js";
2
+ import { registerObserverCallback } from "./observer.js";
3
+ import { Type } from "./schema.js";
4
+ // ============================================================================
5
+ // Removal Event Schema
6
+ // ============================================================================
7
+ /**
8
+ * Schema for removal events containing the entity that had a component removed.
9
+ */
10
+ const RemovalEventSchema = {
11
+ entity: Type.i32(),
12
+ };
13
+ // ============================================================================
14
+ // Global Removal Event Registry
15
+ // ============================================================================
16
+ /**
17
+ * Maps component IDs to their lazily-created removal events.
18
+ */
19
+ const removalEvents = new Map();
20
+ // ============================================================================
21
+ // Public API
22
+ // ============================================================================
23
+ /**
24
+ * Gets the removal event for a component, creating it lazily if needed.
25
+ * @param componentId - Component to track removals for
26
+ * @returns Event that fires when the component is removed from any entity
27
+ * @example
28
+ * for (const { entity } of fetchEvents(world, removed(Health))) {
29
+ * playDeathEffect(entity);
30
+ * }
31
+ */
32
+ export function removed(componentId) {
33
+ let event = removalEvents.get(componentId);
34
+ if (!event) {
35
+ event = defineEvent(`Removed<${componentId}>`, RemovalEventSchema);
36
+ removalEvents.set(componentId, event);
37
+ }
38
+ return event;
39
+ }
40
+ // ============================================================================
41
+ // Initialization
42
+ // ============================================================================
43
+ /**
44
+ * Initializes removal tracking by registering observers for component removals.
45
+ * @param world - World instance to initialize
46
+ * @internal
47
+ */
48
+ export function initRemovalSystem(world) {
49
+ // Handle explicit component removal via removeComponent()
50
+ registerObserverCallback(world, "componentRemoved", (componentId, entityId) => {
51
+ emitEvent(world, removed(componentId), { entity: entityId });
52
+ });
53
+ // Handle entity destruction - destroyEntity() doesn't call removeComponent() for each
54
+ // component, so we emit removal events for all components on the entity here
55
+ registerObserverCallback(world, "entityDestroyed", (entityId) => {
56
+ // Observer fires before entity metadata is deleted, so meta is guaranteed to exist
57
+ const meta = world.entities.byId.get(entityId);
58
+ for (const componentId of meta.archetype.types) {
59
+ // Skip the entity's own ID (entities are components in ECS)
60
+ if (componentId !== entityId) {
61
+ emitEvent(world, removed(componentId), { entity: entityId });
62
+ }
63
+ }
64
+ });
65
+ }
66
+ //# sourceMappingURL=removal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"removal.js","sourceRoot":"","sources":["../src/removal.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAGnC,+EAA+E;AAC/E,uBAAuB;AACvB,+EAA+E;AAE/E;;GAEG;AACH,MAAM,kBAAkB,GAAG;IACzB,MAAM,EAAE,IAAI,CAAC,GAAG,EAAE;CACnB,CAAC;AAEF,+EAA+E;AAC/E,gCAAgC;AAChC,+EAA+E;AAE/E;;GAEG;AACH,MAAM,aAAa,GAAG,IAAI,GAAG,EAA8C,CAAC;AAE5E,+EAA+E;AAC/E,aAAa;AACb,+EAA+E;AAE/E;;;;;;;;GAQG;AACH,MAAM,UAAU,OAAO,CAAC,WAAqB;IAC3C,IAAI,KAAK,GAAG,aAAa,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAE3C,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,KAAK,GAAG,WAAW,CAAC,WAAW,WAAW,GAAG,EAAE,kBAAkB,CAAC,CAAC;QACnE,aAAa,CAAC,GAAG,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;IACxC,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,+EAA+E;AAC/E,iBAAiB;AACjB,+EAA+E;AAE/E;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAY;IAC5C,0DAA0D;IAC1D,wBAAwB,CAAC,KAAK,EAAE,kBAAkB,EAAE,CAAC,WAAW,EAAE,QAAQ,EAAE,EAAE;QAC5E,SAAS,CAAC,KAAK,EAAE,OAAO,CAAC,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,QAAkB,EAAE,CAAC,CAAC;IACzE,CAAC,CAAC,CAAC;IAEH,sFAAsF;IACtF,6EAA6E;IAC7E,wBAAwB,CAAC,KAAK,EAAE,iBAAiB,EAAE,CAAC,QAAQ,EAAE,EAAE;QAC9D,mFAAmF;QACnF,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAE,CAAC;QAEhD,KAAK,MAAM,WAAW,IAAI,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;YAC/C,4DAA4D;YAC5D,IAAI,WAAW,KAAK,QAAQ,EAAE,CAAC;gBAC7B,SAAS,CAAC,KAAK,EAAE,OAAO,CAAC,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,QAAkB,EAAE,CAAC,CAAC;YACzE,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,78 @@
1
+ import type { Component, EntityId } from "./encoding.js";
2
+ import type { InferSchema, InferSchemaRecord, SchemaRecord } from "./schema.js";
3
+ import type { World } from "./world.js";
4
+ /**
5
+ * Adds a global resource (singleton) to the world using the component-on-self pattern.
6
+ *
7
+ * Resources are stored by adding the component to itself as an entity. Idempotent if already present.
8
+ *
9
+ * @param world - World instance
10
+ * @param component - Component definition to use as resource
11
+ * @param data - Initial values for the resource
12
+ * @returns void
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * const Time = defineComponent("Time", { delta: Type.f32() });
17
+ * addResource(world, Time, { delta: 0.016 });
18
+ * ```
19
+ */
20
+ export declare function addResource<S extends SchemaRecord>(world: World, component: Component<S>, data: InferSchemaRecord<S>): void;
21
+ /**
22
+ * Removes a global resource from the world.
23
+ *
24
+ * @param world - World instance
25
+ * @param component - Component definition (acting as resource handle)
26
+ * @returns void
27
+ *
28
+ * @example
29
+ * ```typescript
30
+ * removeResource(world, Time);
31
+ * ```
32
+ */
33
+ export declare function removeResource(world: World, component: EntityId): void;
34
+ /**
35
+ * Checks if a global resource exists in the world.
36
+ *
37
+ * @param world - World instance
38
+ * @param component - Component definition (acting as resource handle)
39
+ * @returns True if the resource exists, false otherwise
40
+ *
41
+ * @example
42
+ * ```typescript
43
+ * if (hasResource(world, Time)) {
44
+ * // Time resource is available
45
+ * }
46
+ * ```
47
+ */
48
+ export declare function hasResource(world: World, component: EntityId): boolean;
49
+ /**
50
+ * Gets the value of a specific field on a global resource.
51
+ *
52
+ * @param world - World instance
53
+ * @param component - Component definition
54
+ * @param key - Field name to retrieve
55
+ * @returns The field value, or undefined if the resource is not present
56
+ *
57
+ * @example
58
+ * ```typescript
59
+ * const dt = getResourceValue(world, Time, "delta");
60
+ * ```
61
+ */
62
+ export declare function getResourceValue<S extends SchemaRecord, K extends keyof S>(world: World, component: Component<S>, key: K): InferSchema<S[K]> | undefined;
63
+ /**
64
+ * Sets the value of a specific field on a global resource.
65
+ *
66
+ * @param world - World instance
67
+ * @param component - Component definition
68
+ * @param key - Field name to set
69
+ * @param value - New value for the field
70
+ * @returns void
71
+ *
72
+ * @example
73
+ * ```typescript
74
+ * setResourceValue(world, Time, "delta", 0.033);
75
+ * ```
76
+ */
77
+ export declare function setResourceValue<S extends SchemaRecord, K extends keyof S>(world: World, component: Component<S>, key: K, value: InferSchema<S[K]>): void;
78
+ //# sourceMappingURL=resource.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resource.d.ts","sourceRoot":"","sources":["../src/resource.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChF,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAExC;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,YAAY,EAChD,KAAK,EAAE,KAAK,EACZ,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,EACvB,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,GACzB,IAAI,CAEN;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,GAAG,IAAI,CAEtE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,GAAG,OAAO,CAEtE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,YAAY,EAAE,CAAC,SAAS,MAAM,CAAC,EACxE,KAAK,EAAE,KAAK,EACZ,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,EACvB,GAAG,EAAE,CAAC,GACL,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS,CAE/B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,YAAY,EAAE,CAAC,SAAS,MAAM,CAAC,EACxE,KAAK,EAAE,KAAK,EACZ,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,EACvB,GAAG,EAAE,CAAC,EACN,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GACvB,IAAI,CAEN"}