@jamesyong42/infinite-canvas 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.
package/dist/ecs.cjs ADDED
@@ -0,0 +1,487 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/ecs.ts
21
+ var ecs_exports = {};
22
+ __export(ecs_exports, {
23
+ SystemScheduler: () => SystemScheduler,
24
+ createWorld: () => createWorld,
25
+ defineComponent: () => defineComponent,
26
+ defineResource: () => defineResource,
27
+ defineSystem: () => defineSystem,
28
+ defineTag: () => defineTag
29
+ });
30
+ module.exports = __toCommonJS(ecs_exports);
31
+
32
+ // src/ecs/define.ts
33
+ function defineComponent(name, defaults) {
34
+ return Object.freeze({ name, defaults, __kind: "component" });
35
+ }
36
+ function defineTag(name) {
37
+ return Object.freeze({ name, __kind: "tag" });
38
+ }
39
+ function defineResource(name, defaults) {
40
+ return Object.freeze({ name, defaults, __kind: "resource" });
41
+ }
42
+ function defineSystem(def) {
43
+ return def;
44
+ }
45
+
46
+ // src/ecs/world.ts
47
+ function createWorld() {
48
+ let nextEntityId = 1;
49
+ let currentTick = 0;
50
+ const alive = /* @__PURE__ */ new Set();
51
+ const components = /* @__PURE__ */ new Map();
52
+ const tags = /* @__PURE__ */ new Map();
53
+ const resources = /* @__PURE__ */ new Map();
54
+ const frameHandlers = /* @__PURE__ */ new Set();
55
+ const queryCache = /* @__PURE__ */ new Map();
56
+ const typeToQueries = /* @__PURE__ */ new Map();
57
+ const queryKeyTypes = /* @__PURE__ */ new Map();
58
+ function getQueryKey(types) {
59
+ return types.map((t) => t.name).sort().join("|");
60
+ }
61
+ function buildQueryResult(compNames, tagNames) {
62
+ const result = /* @__PURE__ */ new Set();
63
+ let smallest = null;
64
+ let smallestSize = Number.POSITIVE_INFINITY;
65
+ for (const name of compNames) {
66
+ const store = components.get(name);
67
+ if (!store || store.data.size === 0) return result;
68
+ if (store.data.size < smallestSize) {
69
+ smallestSize = store.data.size;
70
+ smallest = new Set(store.data.keys());
71
+ }
72
+ }
73
+ for (const name of tagNames) {
74
+ const store = tags.get(name);
75
+ if (!store || store.entities.size === 0) return result;
76
+ if (store.entities.size < smallestSize) {
77
+ smallestSize = store.entities.size;
78
+ smallest = store.entities;
79
+ }
80
+ }
81
+ if (!smallest) return result;
82
+ for (const entity of smallest) {
83
+ if (!alive.has(entity)) continue;
84
+ if (matchesQuery(entity, compNames, tagNames)) {
85
+ result.add(entity);
86
+ }
87
+ }
88
+ return result;
89
+ }
90
+ function matchesQuery(entity, compNames, tagNames) {
91
+ for (const name of compNames) {
92
+ const store = components.get(name);
93
+ if (!store || !store.data.has(entity)) return false;
94
+ }
95
+ for (const name of tagNames) {
96
+ const store = tags.get(name);
97
+ if (!store || !store.entities.has(entity)) return false;
98
+ }
99
+ return true;
100
+ }
101
+ function updateCachesForEntity(typeName, entity) {
102
+ const queryKeys = typeToQueries.get(typeName);
103
+ if (!queryKeys) return;
104
+ for (const key of queryKeys) {
105
+ const cached = queryCache.get(key);
106
+ const types = queryKeyTypes.get(key);
107
+ if (!cached || !types) continue;
108
+ if (matchesQuery(entity, types.components, types.tags)) {
109
+ cached.add(entity);
110
+ } else {
111
+ cached.delete(entity);
112
+ }
113
+ }
114
+ }
115
+ function removeCachesForEntity(entity) {
116
+ for (const cached of queryCache.values()) {
117
+ cached.delete(entity);
118
+ }
119
+ }
120
+ function getComponentStore(type) {
121
+ let store = components.get(type.name);
122
+ if (!store) {
123
+ store = {
124
+ data: /* @__PURE__ */ new Map(),
125
+ dirty: /* @__PURE__ */ new Set(),
126
+ added: /* @__PURE__ */ new Set(),
127
+ handlers: /* @__PURE__ */ new Map()
128
+ };
129
+ components.set(type.name, store);
130
+ }
131
+ return store;
132
+ }
133
+ function getTagStore(type) {
134
+ let store = tags.get(type.name);
135
+ if (!store) {
136
+ store = {
137
+ entities: /* @__PURE__ */ new Set(),
138
+ addedHandlers: /* @__PURE__ */ new Map(),
139
+ removedHandlers: /* @__PURE__ */ new Map()
140
+ };
141
+ tags.set(type.name, store);
142
+ }
143
+ return store;
144
+ }
145
+ function hasListeners(store) {
146
+ if (store.handlers.size === 0) return false;
147
+ for (const set of store.handlers.values()) {
148
+ if (set.size > 0) return true;
149
+ }
150
+ return false;
151
+ }
152
+ function emitComponentChanged(store, entityId, prev, next) {
153
+ const entityHandlers = store.handlers.get(entityId);
154
+ if (entityHandlers) {
155
+ for (const h of entityHandlers) h(entityId, prev, next);
156
+ }
157
+ const wildcardHandlers = store.handlers.get("*");
158
+ if (wildcardHandlers) {
159
+ for (const h of wildcardHandlers) h(entityId, prev, next);
160
+ }
161
+ }
162
+ function emitTagAdded(store, entityId) {
163
+ const entityHandlers = store.addedHandlers.get(entityId);
164
+ if (entityHandlers) {
165
+ for (const h of entityHandlers) h(entityId);
166
+ }
167
+ const wildcardHandlers = store.addedHandlers.get("*");
168
+ if (wildcardHandlers) {
169
+ for (const h of wildcardHandlers) h(entityId);
170
+ }
171
+ }
172
+ function emitTagRemoved(store, entityId) {
173
+ const entityHandlers = store.removedHandlers.get(entityId);
174
+ if (entityHandlers) {
175
+ for (const h of entityHandlers) h(entityId);
176
+ }
177
+ const wildcardHandlers = store.removedHandlers.get("*");
178
+ if (wildcardHandlers) {
179
+ for (const h of wildcardHandlers) h(entityId);
180
+ }
181
+ }
182
+ const world = {
183
+ get currentTick() {
184
+ return currentTick;
185
+ },
186
+ get entityCount() {
187
+ return alive.size;
188
+ },
189
+ // === Entity lifecycle ===
190
+ createEntity() {
191
+ const id = nextEntityId++;
192
+ alive.add(id);
193
+ return id;
194
+ },
195
+ destroyEntity(id) {
196
+ if (!alive.has(id)) return;
197
+ alive.delete(id);
198
+ removeCachesForEntity(id);
199
+ for (const store of components.values()) {
200
+ store.data.delete(id);
201
+ store.dirty.delete(id);
202
+ store.added.delete(id);
203
+ store.handlers.delete(id);
204
+ }
205
+ for (const store of tags.values()) {
206
+ store.entities.delete(id);
207
+ store.addedHandlers.delete(id);
208
+ store.removedHandlers.delete(id);
209
+ }
210
+ },
211
+ entityExists(id) {
212
+ return alive.has(id);
213
+ },
214
+ // === Component access ===
215
+ addComponent(entity, type, data) {
216
+ const store = getComponentStore(type);
217
+ const merged = { ...type.defaults, ...data };
218
+ store.data.set(entity, merged);
219
+ store.dirty.add(entity);
220
+ store.added.add(entity);
221
+ updateCachesForEntity(type.name, entity);
222
+ emitComponentChanged(store, entity, void 0, merged);
223
+ },
224
+ removeComponent(entity, type) {
225
+ const store = getComponentStore(type);
226
+ store.data.delete(entity);
227
+ store.dirty.delete(entity);
228
+ updateCachesForEntity(type.name, entity);
229
+ },
230
+ getComponent(entity, type) {
231
+ const store = getComponentStore(type);
232
+ return store.data.get(entity);
233
+ },
234
+ hasComponent(entity, type) {
235
+ const store = getComponentStore(type);
236
+ return store.data.has(entity);
237
+ },
238
+ // P2: Only allocate prev object when there are listeners
239
+ setComponent(entity, type, data) {
240
+ const store = getComponentStore(type);
241
+ const existing = store.data.get(entity);
242
+ if (!existing) return;
243
+ if (hasListeners(store)) {
244
+ const prev = { ...existing };
245
+ const next = Object.assign(existing, data);
246
+ store.data.set(entity, next);
247
+ store.dirty.add(entity);
248
+ emitComponentChanged(store, entity, prev, next);
249
+ } else {
250
+ Object.assign(existing, data);
251
+ store.dirty.add(entity);
252
+ }
253
+ },
254
+ // === Tag access ===
255
+ addTag(entity, type) {
256
+ const store = getTagStore(type);
257
+ if (store.entities.has(entity)) return;
258
+ store.entities.add(entity);
259
+ updateCachesForEntity(type.name, entity);
260
+ emitTagAdded(store, entity);
261
+ },
262
+ removeTag(entity, type) {
263
+ const store = getTagStore(type);
264
+ if (!store.entities.has(entity)) return;
265
+ store.entities.delete(entity);
266
+ updateCachesForEntity(type.name, entity);
267
+ emitTagRemoved(store, entity);
268
+ },
269
+ hasTag(entity, type) {
270
+ const store = getTagStore(type);
271
+ return store.entities.has(entity);
272
+ },
273
+ // === Queries (cached) ===
274
+ query(...types) {
275
+ if (types.length === 0) return [...alive];
276
+ const key = getQueryKey(types);
277
+ let cached = queryCache.get(key);
278
+ if (cached) return [...cached];
279
+ const compNames = [];
280
+ const tagNames = [];
281
+ for (const type of types) {
282
+ if (type.__kind === "component") compNames.push(type.name);
283
+ else tagNames.push(type.name);
284
+ }
285
+ cached = buildQueryResult(compNames, tagNames);
286
+ queryCache.set(key, cached);
287
+ queryKeyTypes.set(key, { components: compNames, tags: tagNames });
288
+ for (const name of [...compNames, ...tagNames]) {
289
+ let queryKeys = typeToQueries.get(name);
290
+ if (!queryKeys) {
291
+ queryKeys = /* @__PURE__ */ new Set();
292
+ typeToQueries.set(name, queryKeys);
293
+ }
294
+ queryKeys.add(key);
295
+ }
296
+ return [...cached];
297
+ },
298
+ queryChanged(type) {
299
+ const store = getComponentStore(type);
300
+ return [...store.dirty];
301
+ },
302
+ queryAdded(type) {
303
+ const store = getComponentStore(type);
304
+ return [...store.added];
305
+ },
306
+ queryTagged(type) {
307
+ const store = getTagStore(type);
308
+ return [...store.entities];
309
+ },
310
+ // === Resources ===
311
+ getResource(type) {
312
+ if (!resources.has(type.name)) {
313
+ resources.set(type.name, { ...type.defaults });
314
+ }
315
+ return resources.get(type.name);
316
+ },
317
+ setResource(type, data) {
318
+ const existing = world.getResource(type);
319
+ Object.assign(existing, data);
320
+ },
321
+ // === Events ===
322
+ onComponentChanged(type, handler, entityId) {
323
+ const store = getComponentStore(type);
324
+ const key = entityId ?? "*";
325
+ let handlers = store.handlers.get(key);
326
+ if (!handlers) {
327
+ handlers = /* @__PURE__ */ new Set();
328
+ store.handlers.set(key, handlers);
329
+ }
330
+ handlers.add(handler);
331
+ return () => handlers.delete(handler);
332
+ },
333
+ onTagAdded(type, handler, entityId) {
334
+ const store = getTagStore(type);
335
+ const key = entityId ?? "*";
336
+ let handlers = store.addedHandlers.get(key);
337
+ if (!handlers) {
338
+ handlers = /* @__PURE__ */ new Set();
339
+ store.addedHandlers.set(key, handlers);
340
+ }
341
+ handlers.add(handler);
342
+ return () => handlers.delete(handler);
343
+ },
344
+ onTagRemoved(type, handler, entityId) {
345
+ const store = getTagStore(type);
346
+ const key = entityId ?? "*";
347
+ let handlers = store.removedHandlers.get(key);
348
+ if (!handlers) {
349
+ handlers = /* @__PURE__ */ new Set();
350
+ store.removedHandlers.set(key, handlers);
351
+ }
352
+ handlers.add(handler);
353
+ return () => handlers.delete(handler);
354
+ },
355
+ onFrame(handler) {
356
+ frameHandlers.add(handler);
357
+ return () => frameHandlers.delete(handler);
358
+ },
359
+ // Frame lifecycle
360
+ clearDirty() {
361
+ for (const store of components.values()) {
362
+ store.dirty.clear();
363
+ store.added.clear();
364
+ }
365
+ },
366
+ incrementTick() {
367
+ currentTick++;
368
+ },
369
+ emitFrame() {
370
+ for (const h of frameHandlers) h();
371
+ }
372
+ };
373
+ return world;
374
+ }
375
+
376
+ // src/ecs/scheduler.ts
377
+ var SystemScheduler = class {
378
+ systems = [];
379
+ sorted = null;
380
+ profiler = null;
381
+ register(system) {
382
+ this.systems = this.systems.filter((s) => s.name !== system.name);
383
+ this.systems.push(system);
384
+ this.sorted = null;
385
+ }
386
+ remove(name) {
387
+ this.systems = this.systems.filter((s) => s.name !== name);
388
+ this.sorted = null;
389
+ }
390
+ /**
391
+ * Execute all systems in dependency order.
392
+ */
393
+ execute(world) {
394
+ if (!this.sorted) {
395
+ this.sorted = this.topoSort();
396
+ }
397
+ const p = this.profiler;
398
+ for (const system of this.sorted) {
399
+ if (p) p.beginSystem(system.name);
400
+ system.execute(world);
401
+ if (p) p.endSystem(system.name);
402
+ }
403
+ }
404
+ getSystemNames() {
405
+ if (!this.sorted) {
406
+ this.sorted = this.topoSort();
407
+ }
408
+ return this.sorted.map((s) => s.name);
409
+ }
410
+ /**
411
+ * Topological sort based on after/before constraints.
412
+ * Falls back to registration order for unconstrained systems.
413
+ */
414
+ topoSort() {
415
+ const byName = /* @__PURE__ */ new Map();
416
+ for (const s of this.systems) {
417
+ byName.set(s.name, s);
418
+ }
419
+ const edges = /* @__PURE__ */ new Map();
420
+ const inDegree = /* @__PURE__ */ new Map();
421
+ for (const s of this.systems) {
422
+ if (!edges.has(s.name)) edges.set(s.name, /* @__PURE__ */ new Set());
423
+ if (!inDegree.has(s.name)) inDegree.set(s.name, 0);
424
+ }
425
+ for (const s of this.systems) {
426
+ const afters = Array.isArray(s.after) ? s.after : s.after ? [s.after] : [];
427
+ for (const dep of afters) {
428
+ if (byName.has(dep)) {
429
+ if (!edges.has(dep)) edges.set(dep, /* @__PURE__ */ new Set());
430
+ edges.get(dep).add(s.name);
431
+ inDegree.set(s.name, (inDegree.get(s.name) || 0) + 1);
432
+ }
433
+ }
434
+ const befores = Array.isArray(s.before) ? s.before : s.before ? [s.before] : [];
435
+ for (const dep of befores) {
436
+ if (byName.has(dep)) {
437
+ if (!edges.has(s.name)) edges.set(s.name, /* @__PURE__ */ new Set());
438
+ edges.get(s.name).add(dep);
439
+ inDegree.set(dep, (inDegree.get(dep) || 0) + 1);
440
+ }
441
+ }
442
+ }
443
+ const queue = [];
444
+ const registrationOrder = /* @__PURE__ */ new Map();
445
+ for (let i = 0; i < this.systems.length; i++) {
446
+ registrationOrder.set(this.systems[i].name, i);
447
+ }
448
+ for (const s of this.systems) {
449
+ if ((inDegree.get(s.name) || 0) === 0) {
450
+ queue.push(s.name);
451
+ }
452
+ }
453
+ queue.sort((a, b) => (registrationOrder.get(a) || 0) - (registrationOrder.get(b) || 0));
454
+ const result = [];
455
+ while (queue.length > 0) {
456
+ const name = queue.shift();
457
+ const system = byName.get(name);
458
+ if (system) result.push(system);
459
+ const neighbors = edges.get(name) || /* @__PURE__ */ new Set();
460
+ const newReady = [];
461
+ for (const neighbor of neighbors) {
462
+ const deg = (inDegree.get(neighbor) || 0) - 1;
463
+ inDegree.set(neighbor, deg);
464
+ if (deg === 0) {
465
+ newReady.push(neighbor);
466
+ }
467
+ }
468
+ newReady.sort((a, b) => (registrationOrder.get(a) || 0) - (registrationOrder.get(b) || 0));
469
+ queue.push(...newReady);
470
+ }
471
+ if (result.length !== this.systems.length) {
472
+ const missing = this.systems.filter((s) => !result.find((r) => r.name === s.name)).map((s) => s.name);
473
+ throw new Error(`Circular system dependency detected involving: ${missing.join(", ")}`);
474
+ }
475
+ return result;
476
+ }
477
+ };
478
+ // Annotate the CommonJS export names for ESM import in node:
479
+ 0 && (module.exports = {
480
+ SystemScheduler,
481
+ createWorld,
482
+ defineComponent,
483
+ defineResource,
484
+ defineSystem,
485
+ defineTag
486
+ });
487
+ //# sourceMappingURL=ecs.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/ecs.ts","../src/ecs/define.ts","../src/ecs/world.ts","../src/ecs/scheduler.ts"],"sourcesContent":["// ECS primitives for advanced users\nexport {\n\tdefineComponent,\n\tdefineTag,\n\tdefineResource,\n\tdefineSystem,\n\tcreateWorld,\n\tSystemScheduler,\n} from './ecs/index.js';\n\nexport type {\n\tEntityId,\n\tComponentType,\n\tTagType,\n\tResourceType,\n\tSystemDef,\n\tComponentInit,\n\tQueryResult,\n\tWorld,\n\tUnsubscribe,\n} from './ecs/index.js';\n","import type { ComponentType, ResourceType, SystemDef, TagType } from './types.js';\n\n/**\n * Define a component type. Components hold data attached to entities.\n *\n * @example\n * const Transform2D = defineComponent('Transform2D', {\n * x: 0, y: 0, width: 100, height: 100, rotation: 0,\n * });\n */\nexport function defineComponent<T extends Record<string, any>>(\n\tname: string,\n\tdefaults: T,\n): ComponentType<T> {\n\treturn Object.freeze({ name, defaults, __kind: 'component' as const });\n}\n\n/**\n * Define a tag type. Tags are markers with no data — used for boolean state.\n *\n * @example\n * const Selected = defineTag('Selected');\n */\nexport function defineTag(name: string): TagType {\n\treturn Object.freeze({ name, __kind: 'tag' as const });\n}\n\n/**\n * Define a resource type. Resources are global singletons (camera, viewport, etc.)\n *\n * @example\n * const Camera = defineResource('Camera', { x: 0, y: 0, zoom: 1 });\n */\nexport function defineResource<T extends Record<string, any>>(\n\tname: string,\n\tdefaults: T,\n): ResourceType<T> {\n\treturn Object.freeze({ name, defaults, __kind: 'resource' as const });\n}\n\n/**\n * Define a system. Systems are named functions that query and transform ECS data.\n *\n * @example\n * const mySystem = defineSystem({\n * name: 'physics',\n * after: 'layout',\n * execute: (world) => {\n * for (const entity of world.query(Transform2D, Velocity)) { ... }\n * },\n * });\n */\nexport function defineSystem(def: SystemDef): SystemDef {\n\treturn def;\n}\n","import type {\n\tComponentChangedHandler,\n\tComponentType,\n\tEntityId,\n\tFrameHandler,\n\tQueryResult,\n\tResourceType,\n\tTagChangedHandler,\n\tTagType,\n\tUnsubscribe,\n\tWorld,\n} from './types.js';\n\n/** Internal storage for a single component type */\ninterface ComponentStore<T = any> {\n\tdata: Map<EntityId, T>;\n\tdirty: Set<EntityId>;\n\tadded: Set<EntityId>;\n\thandlers: Map<EntityId | '*', Set<ComponentChangedHandler<T>>>;\n}\n\n/** Internal storage for a single tag type */\ninterface TagStore {\n\tentities: Set<EntityId>;\n\taddedHandlers: Map<EntityId | '*', Set<TagChangedHandler>>;\n\tremovedHandlers: Map<EntityId | '*', Set<TagChangedHandler>>;\n}\n\nexport function createWorld(): World {\n\tlet nextEntityId = 1;\n\tlet currentTick = 0;\n\tconst alive = new Set<EntityId>();\n\n\t// Component storage: one Map per component type\n\tconst components = new Map<string, ComponentStore>();\n\t// Tag storage: one Set per tag type\n\tconst tags = new Map<string, TagStore>();\n\t// Resources: one value per resource type\n\tconst resources = new Map<string, any>();\n\t// Frame handlers\n\tconst frameHandlers = new Set<FrameHandler>();\n\n\t// === Query cache ===\n\t// Key: sorted type names joined by '|' (e.g., \"Transform2D|Visible\")\n\t// Value: live Set<EntityId> of entities matching all types in the key\n\tconst queryCache = new Map<string, Set<EntityId>>();\n\t// Reverse index: typeName → Set<queryKey> — which cached queries use this type\n\tconst typeToQueries = new Map<string, Set<string>>();\n\t// Store the type names per query key for re-evaluation\n\tconst queryKeyTypes = new Map<string, { components: string[]; tags: string[] }>();\n\n\tfunction getQueryKey(types: (ComponentType | TagType)[]): string {\n\t\treturn types\n\t\t\t.map((t) => t.name)\n\t\t\t.sort()\n\t\t\t.join('|');\n\t}\n\n\tfunction buildQueryResult(compNames: string[], tagNames: string[]): Set<EntityId> {\n\t\tconst result = new Set<EntityId>();\n\n\t\t// Find smallest set to start iteration\n\t\tlet smallest: Set<EntityId> | null = null;\n\t\tlet smallestSize = Number.POSITIVE_INFINITY;\n\n\t\tfor (const name of compNames) {\n\t\t\tconst store = components.get(name);\n\t\t\tif (!store || store.data.size === 0) return result; // empty — no matches\n\t\t\tif (store.data.size < smallestSize) {\n\t\t\t\tsmallestSize = store.data.size;\n\t\t\t\tsmallest = new Set(store.data.keys());\n\t\t\t}\n\t\t}\n\t\tfor (const name of tagNames) {\n\t\t\tconst store = tags.get(name);\n\t\t\tif (!store || store.entities.size === 0) return result;\n\t\t\tif (store.entities.size < smallestSize) {\n\t\t\t\tsmallestSize = store.entities.size;\n\t\t\t\tsmallest = store.entities;\n\t\t\t}\n\t\t}\n\n\t\tif (!smallest) return result;\n\n\t\tfor (const entity of smallest) {\n\t\t\tif (!alive.has(entity)) continue;\n\t\t\tif (matchesQuery(entity, compNames, tagNames)) {\n\t\t\t\tresult.add(entity);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tfunction matchesQuery(entity: EntityId, compNames: string[], tagNames: string[]): boolean {\n\t\tfor (const name of compNames) {\n\t\t\tconst store = components.get(name);\n\t\t\tif (!store || !store.data.has(entity)) return false;\n\t\t}\n\t\tfor (const name of tagNames) {\n\t\t\tconst store = tags.get(name);\n\t\t\tif (!store || !store.entities.has(entity)) return false;\n\t\t}\n\t\treturn true;\n\t}\n\n\t/** Update all cached queries that include this type name */\n\tfunction updateCachesForEntity(typeName: string, entity: EntityId) {\n\t\tconst queryKeys = typeToQueries.get(typeName);\n\t\tif (!queryKeys) return;\n\t\tfor (const key of queryKeys) {\n\t\t\tconst cached = queryCache.get(key);\n\t\t\tconst types = queryKeyTypes.get(key);\n\t\t\tif (!cached || !types) continue;\n\t\t\tif (matchesQuery(entity, types.components, types.tags)) {\n\t\t\t\tcached.add(entity);\n\t\t\t} else {\n\t\t\t\tcached.delete(entity);\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Remove entity from all cached queries */\n\tfunction removeCachesForEntity(entity: EntityId) {\n\t\tfor (const cached of queryCache.values()) {\n\t\t\tcached.delete(entity);\n\t\t}\n\t}\n\n\tfunction getComponentStore<T>(type: ComponentType<T>): ComponentStore<T> {\n\t\tlet store = components.get(type.name);\n\t\tif (!store) {\n\t\t\tstore = {\n\t\t\t\tdata: new Map(),\n\t\t\t\tdirty: new Set(),\n\t\t\t\tadded: new Set(),\n\t\t\t\thandlers: new Map(),\n\t\t\t};\n\t\t\tcomponents.set(type.name, store);\n\t\t}\n\t\treturn store;\n\t}\n\n\tfunction getTagStore(type: TagType): TagStore {\n\t\tlet store = tags.get(type.name);\n\t\tif (!store) {\n\t\t\tstore = {\n\t\t\t\tentities: new Set(),\n\t\t\t\taddedHandlers: new Map(),\n\t\t\t\tremovedHandlers: new Map(),\n\t\t\t};\n\t\t\ttags.set(type.name, store);\n\t\t}\n\t\treturn store;\n\t}\n\n\tfunction hasListeners(store: ComponentStore): boolean {\n\t\tif (store.handlers.size === 0) return false;\n\t\tfor (const set of store.handlers.values()) {\n\t\t\tif (set.size > 0) return true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tfunction emitComponentChanged<T>(\n\t\tstore: ComponentStore<T>,\n\t\tentityId: EntityId,\n\t\tprev: T | undefined,\n\t\tnext: T,\n\t) {\n\t\tconst entityHandlers = store.handlers.get(entityId);\n\t\tif (entityHandlers) {\n\t\t\tfor (const h of entityHandlers) h(entityId, prev, next);\n\t\t}\n\t\tconst wildcardHandlers = store.handlers.get('*');\n\t\tif (wildcardHandlers) {\n\t\t\tfor (const h of wildcardHandlers) h(entityId, prev, next);\n\t\t}\n\t}\n\n\tfunction emitTagAdded(store: TagStore, entityId: EntityId) {\n\t\tconst entityHandlers = store.addedHandlers.get(entityId);\n\t\tif (entityHandlers) {\n\t\t\tfor (const h of entityHandlers) h(entityId);\n\t\t}\n\t\tconst wildcardHandlers = store.addedHandlers.get('*');\n\t\tif (wildcardHandlers) {\n\t\t\tfor (const h of wildcardHandlers) h(entityId);\n\t\t}\n\t}\n\n\tfunction emitTagRemoved(store: TagStore, entityId: EntityId) {\n\t\tconst entityHandlers = store.removedHandlers.get(entityId);\n\t\tif (entityHandlers) {\n\t\t\tfor (const h of entityHandlers) h(entityId);\n\t\t}\n\t\tconst wildcardHandlers = store.removedHandlers.get('*');\n\t\tif (wildcardHandlers) {\n\t\t\tfor (const h of wildcardHandlers) h(entityId);\n\t\t}\n\t}\n\n\tconst world: World = {\n\t\tget currentTick() {\n\t\t\treturn currentTick;\n\t\t},\n\n\t\tget entityCount() {\n\t\t\treturn alive.size;\n\t\t},\n\n\t\t// === Entity lifecycle ===\n\n\t\tcreateEntity(): EntityId {\n\t\t\tconst id = nextEntityId++;\n\t\t\talive.add(id);\n\t\t\treturn id;\n\t\t},\n\n\t\tdestroyEntity(id: EntityId) {\n\t\t\tif (!alive.has(id)) return;\n\t\t\talive.delete(id);\n\t\t\t// Remove from all cached queries\n\t\t\tremoveCachesForEntity(id);\n\t\t\t// Remove all components\n\t\t\tfor (const store of components.values()) {\n\t\t\t\tstore.data.delete(id);\n\t\t\t\tstore.dirty.delete(id);\n\t\t\t\tstore.added.delete(id);\n\t\t\t\tstore.handlers.delete(id);\n\t\t\t}\n\t\t\t// Remove all tags\n\t\t\tfor (const store of tags.values()) {\n\t\t\t\tstore.entities.delete(id);\n\t\t\t\tstore.addedHandlers.delete(id);\n\t\t\t\tstore.removedHandlers.delete(id);\n\t\t\t}\n\t\t},\n\n\t\tentityExists(id: EntityId): boolean {\n\t\t\treturn alive.has(id);\n\t\t},\n\n\t\t// === Component access ===\n\n\t\taddComponent<T>(entity: EntityId, type: ComponentType<T>, data: T) {\n\t\t\tconst store = getComponentStore(type);\n\t\t\tconst merged = { ...type.defaults, ...data };\n\t\t\tstore.data.set(entity, merged);\n\t\t\tstore.dirty.add(entity);\n\t\t\tstore.added.add(entity);\n\t\t\t// Update cached queries that include this component\n\t\t\tupdateCachesForEntity(type.name, entity);\n\t\t\temitComponentChanged(store, entity, undefined, merged);\n\t\t},\n\n\t\tremoveComponent<T>(entity: EntityId, type: ComponentType<T>) {\n\t\t\tconst store = getComponentStore(type);\n\t\t\tstore.data.delete(entity);\n\t\t\tstore.dirty.delete(entity);\n\t\t\t// Update cached queries — entity may no longer match\n\t\t\tupdateCachesForEntity(type.name, entity);\n\t\t},\n\n\t\tgetComponent<T>(entity: EntityId, type: ComponentType<T>): T | undefined {\n\t\t\tconst store = getComponentStore(type);\n\t\t\treturn store.data.get(entity);\n\t\t},\n\n\t\thasComponent(entity: EntityId, type: ComponentType): boolean {\n\t\t\tconst store = getComponentStore(type);\n\t\t\treturn store.data.has(entity);\n\t\t},\n\n\t\t// P2: Only allocate prev object when there are listeners\n\t\tsetComponent<T>(entity: EntityId, type: ComponentType<T>, data: Partial<T>) {\n\t\t\tconst store = getComponentStore(type);\n\t\t\tconst existing = store.data.get(entity);\n\t\t\tif (!existing) return;\n\t\t\tif (hasListeners(store)) {\n\t\t\t\tconst prev = { ...existing };\n\t\t\t\tconst next = Object.assign(existing, data);\n\t\t\t\tstore.data.set(entity, next);\n\t\t\t\tstore.dirty.add(entity);\n\t\t\t\temitComponentChanged(store, entity, prev, next);\n\t\t\t} else {\n\t\t\t\tObject.assign(existing, data);\n\t\t\t\tstore.dirty.add(entity);\n\t\t\t}\n\t\t},\n\n\t\t// === Tag access ===\n\n\t\taddTag(entity: EntityId, type: TagType) {\n\t\t\tconst store = getTagStore(type);\n\t\t\tif (store.entities.has(entity)) return;\n\t\t\tstore.entities.add(entity);\n\t\t\t// Update cached queries that include this tag\n\t\t\tupdateCachesForEntity(type.name, entity);\n\t\t\temitTagAdded(store, entity);\n\t\t},\n\n\t\tremoveTag(entity: EntityId, type: TagType) {\n\t\t\tconst store = getTagStore(type);\n\t\t\tif (!store.entities.has(entity)) return;\n\t\t\tstore.entities.delete(entity);\n\t\t\t// Update cached queries — entity may no longer match\n\t\t\tupdateCachesForEntity(type.name, entity);\n\t\t\temitTagRemoved(store, entity);\n\t\t},\n\n\t\thasTag(entity: EntityId, type: TagType): boolean {\n\t\t\tconst store = getTagStore(type);\n\t\t\treturn store.entities.has(entity);\n\t\t},\n\n\t\t// === Queries (cached) ===\n\n\t\tquery(...types: (ComponentType | TagType)[]): QueryResult {\n\t\t\tif (types.length === 0) return [...alive];\n\n\t\t\tconst key = getQueryKey(types);\n\n\t\t\t// Return from cache if available\n\t\t\tlet cached = queryCache.get(key);\n\t\t\tif (cached) return [...cached];\n\n\t\t\t// Build cache on first call\n\t\t\tconst compNames: string[] = [];\n\t\t\tconst tagNames: string[] = [];\n\t\t\tfor (const type of types) {\n\t\t\t\tif (type.__kind === 'component') compNames.push(type.name);\n\t\t\t\telse tagNames.push(type.name);\n\t\t\t}\n\n\t\t\tcached = buildQueryResult(compNames, tagNames);\n\t\t\tqueryCache.set(key, cached);\n\t\t\tqueryKeyTypes.set(key, { components: compNames, tags: tagNames });\n\n\t\t\t// Register reverse index so cache updates on add/remove\n\t\t\tfor (const name of [...compNames, ...tagNames]) {\n\t\t\t\tlet queryKeys = typeToQueries.get(name);\n\t\t\t\tif (!queryKeys) {\n\t\t\t\t\tqueryKeys = new Set();\n\t\t\t\t\ttypeToQueries.set(name, queryKeys);\n\t\t\t\t}\n\t\t\t\tqueryKeys.add(key);\n\t\t\t}\n\n\t\t\treturn [...cached];\n\t\t},\n\n\t\tqueryChanged(type: ComponentType): QueryResult {\n\t\t\tconst store = getComponentStore(type);\n\t\t\treturn [...store.dirty];\n\t\t},\n\n\t\tqueryAdded(type: ComponentType): QueryResult {\n\t\t\tconst store = getComponentStore(type);\n\t\t\treturn [...store.added];\n\t\t},\n\n\t\tqueryTagged(type: TagType): QueryResult {\n\t\t\tconst store = getTagStore(type);\n\t\t\treturn [...store.entities];\n\t\t},\n\n\t\t// === Resources ===\n\n\t\tgetResource<T>(type: ResourceType<T>): T {\n\t\t\tif (!resources.has(type.name)) {\n\t\t\t\tresources.set(type.name, { ...type.defaults });\n\t\t\t}\n\t\t\treturn resources.get(type.name);\n\t\t},\n\n\t\tsetResource<T>(type: ResourceType<T>, data: Partial<T>) {\n\t\t\tconst existing = world.getResource(type);\n\t\t\tObject.assign(existing as Record<string, unknown>, data);\n\t\t},\n\n\t\t// === Events ===\n\n\t\tonComponentChanged<T>(\n\t\t\ttype: ComponentType<T>,\n\t\t\thandler: ComponentChangedHandler<T>,\n\t\t\tentityId?: EntityId,\n\t\t): Unsubscribe {\n\t\t\tconst store = getComponentStore(type);\n\t\t\tconst key: EntityId | '*' = entityId ?? '*';\n\t\t\tlet handlers = store.handlers.get(key);\n\t\t\tif (!handlers) {\n\t\t\t\thandlers = new Set();\n\t\t\t\tstore.handlers.set(key, handlers);\n\t\t\t}\n\t\t\thandlers.add(handler);\n\t\t\treturn () => handlers!.delete(handler);\n\t\t},\n\n\t\tonTagAdded(type: TagType, handler: TagChangedHandler, entityId?: EntityId): Unsubscribe {\n\t\t\tconst store = getTagStore(type);\n\t\t\tconst key: EntityId | '*' = entityId ?? '*';\n\t\t\tlet handlers = store.addedHandlers.get(key);\n\t\t\tif (!handlers) {\n\t\t\t\thandlers = new Set();\n\t\t\t\tstore.addedHandlers.set(key, handlers);\n\t\t\t}\n\t\t\thandlers.add(handler);\n\t\t\treturn () => handlers!.delete(handler);\n\t\t},\n\n\t\tonTagRemoved(type: TagType, handler: TagChangedHandler, entityId?: EntityId): Unsubscribe {\n\t\t\tconst store = getTagStore(type);\n\t\t\tconst key: EntityId | '*' = entityId ?? '*';\n\t\t\tlet handlers = store.removedHandlers.get(key);\n\t\t\tif (!handlers) {\n\t\t\t\thandlers = new Set();\n\t\t\t\tstore.removedHandlers.set(key, handlers);\n\t\t\t}\n\t\t\thandlers.add(handler);\n\t\t\treturn () => handlers!.delete(handler);\n\t\t},\n\n\t\tonFrame(handler: FrameHandler): Unsubscribe {\n\t\t\tframeHandlers.add(handler);\n\t\t\treturn () => frameHandlers.delete(handler);\n\t\t},\n\n\t\t// Frame lifecycle\n\t\tclearDirty() {\n\t\t\tfor (const store of components.values()) {\n\t\t\t\tstore.dirty.clear();\n\t\t\t\tstore.added.clear();\n\t\t\t}\n\t\t},\n\n\t\tincrementTick() {\n\t\t\tcurrentTick++;\n\t\t},\n\n\t\temitFrame() {\n\t\t\tfor (const h of frameHandlers) h();\n\t\t},\n\t};\n\n\treturn world;\n}\n","import type { Profiler } from '../profiler.js';\nimport type { SystemDef, World } from './types.js';\n\n/**\n * Manages system registration and ordered execution.\n * Systems declare after/before constraints and are topologically sorted.\n */\nexport class SystemScheduler {\n\tprivate systems: SystemDef[] = [];\n\tprivate sorted: SystemDef[] | null = null;\n\tprofiler: Profiler | null = null;\n\n\tregister(system: SystemDef) {\n\t\t// Replace if system with same name exists\n\t\tthis.systems = this.systems.filter((s) => s.name !== system.name);\n\t\tthis.systems.push(system);\n\t\tthis.sorted = null; // invalidate sort\n\t}\n\n\tremove(name: string) {\n\t\tthis.systems = this.systems.filter((s) => s.name !== name);\n\t\tthis.sorted = null;\n\t}\n\n\t/**\n\t * Execute all systems in dependency order.\n\t */\n\texecute(world: World) {\n\t\tif (!this.sorted) {\n\t\t\tthis.sorted = this.topoSort();\n\t\t}\n\t\tconst p = this.profiler;\n\t\tfor (const system of this.sorted) {\n\t\t\tif (p) p.beginSystem(system.name);\n\t\t\tsystem.execute(world);\n\t\t\tif (p) p.endSystem(system.name);\n\t\t}\n\t}\n\n\tgetSystemNames(): string[] {\n\t\tif (!this.sorted) {\n\t\t\tthis.sorted = this.topoSort();\n\t\t}\n\t\treturn this.sorted.map((s) => s.name);\n\t}\n\n\t/**\n\t * Topological sort based on after/before constraints.\n\t * Falls back to registration order for unconstrained systems.\n\t */\n\tprivate topoSort(): SystemDef[] {\n\t\tconst byName = new Map<string, SystemDef>();\n\t\tfor (const s of this.systems) {\n\t\t\tbyName.set(s.name, s);\n\t\t}\n\n\t\t// Build adjacency list: edges[a] = [b] means a must run before b\n\t\tconst edges = new Map<string, Set<string>>();\n\t\tconst inDegree = new Map<string, number>();\n\n\t\tfor (const s of this.systems) {\n\t\t\tif (!edges.has(s.name)) edges.set(s.name, new Set());\n\t\t\tif (!inDegree.has(s.name)) inDegree.set(s.name, 0);\n\t\t}\n\n\t\tfor (const s of this.systems) {\n\t\t\tconst afters = Array.isArray(s.after) ? s.after : s.after ? [s.after] : [];\n\t\t\tfor (const dep of afters) {\n\t\t\t\t// dep must run before s\n\t\t\t\tif (byName.has(dep)) {\n\t\t\t\t\tif (!edges.has(dep)) edges.set(dep, new Set());\n\t\t\t\t\tedges.get(dep)!.add(s.name);\n\t\t\t\t\tinDegree.set(s.name, (inDegree.get(s.name) || 0) + 1);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst befores = Array.isArray(s.before) ? s.before : s.before ? [s.before] : [];\n\t\t\tfor (const dep of befores) {\n\t\t\t\t// s must run before dep\n\t\t\t\tif (byName.has(dep)) {\n\t\t\t\t\tif (!edges.has(s.name)) edges.set(s.name, new Set());\n\t\t\t\t\tedges.get(s.name)!.add(dep);\n\t\t\t\t\tinDegree.set(dep, (inDegree.get(dep) || 0) + 1);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Kahn's algorithm — stable sort (preserves registration order for ties)\n\t\tconst queue: string[] = [];\n\t\tconst registrationOrder = new Map<string, number>();\n\t\tfor (let i = 0; i < this.systems.length; i++) {\n\t\t\tregistrationOrder.set(this.systems[i].name, i);\n\t\t}\n\n\t\tfor (const s of this.systems) {\n\t\t\tif ((inDegree.get(s.name) || 0) === 0) {\n\t\t\t\tqueue.push(s.name);\n\t\t\t}\n\t\t}\n\t\t// Sort queue by registration order for stability\n\t\tqueue.sort((a, b) => (registrationOrder.get(a) || 0) - (registrationOrder.get(b) || 0));\n\n\t\tconst result: SystemDef[] = [];\n\t\twhile (queue.length > 0) {\n\t\t\tconst name = queue.shift()!;\n\t\t\tconst system = byName.get(name);\n\t\t\tif (system) result.push(system);\n\n\t\t\tconst neighbors = edges.get(name) || new Set();\n\t\t\tconst newReady: string[] = [];\n\t\t\tfor (const neighbor of neighbors) {\n\t\t\t\tconst deg = (inDegree.get(neighbor) || 0) - 1;\n\t\t\t\tinDegree.set(neighbor, deg);\n\t\t\t\tif (deg === 0) {\n\t\t\t\t\tnewReady.push(neighbor);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Sort newly ready by registration order\n\t\t\tnewReady.sort((a, b) => (registrationOrder.get(a) || 0) - (registrationOrder.get(b) || 0));\n\t\t\tqueue.push(...newReady);\n\t\t}\n\n\t\tif (result.length !== this.systems.length) {\n\t\t\tconst missing = this.systems\n\t\t\t\t.filter((s) => !result.find((r) => r.name === s.name))\n\t\t\t\t.map((s) => s.name);\n\t\t\tthrow new Error(`Circular system dependency detected involving: ${missing.join(', ')}`);\n\t\t}\n\n\t\treturn result;\n\t}\n}\n"],"mappings":"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","names":[]}
package/dist/ecs.d.cts ADDED
@@ -0,0 +1,65 @@
1
+ import { C as ComponentType, R as ResourceType, S as SystemDef, T as TagType, W as World, P as Profiler } from './profiler-DKuXy4MW.cjs';
2
+ export { b as ComponentInit, E as EntityId, Q as QueryResult, U as Unsubscribe } from './profiler-DKuXy4MW.cjs';
3
+
4
+ /**
5
+ * Define a component type. Components hold data attached to entities.
6
+ *
7
+ * @example
8
+ * const Transform2D = defineComponent('Transform2D', {
9
+ * x: 0, y: 0, width: 100, height: 100, rotation: 0,
10
+ * });
11
+ */
12
+ declare function defineComponent<T extends Record<string, any>>(name: string, defaults: T): ComponentType<T>;
13
+ /**
14
+ * Define a tag type. Tags are markers with no data — used for boolean state.
15
+ *
16
+ * @example
17
+ * const Selected = defineTag('Selected');
18
+ */
19
+ declare function defineTag(name: string): TagType;
20
+ /**
21
+ * Define a resource type. Resources are global singletons (camera, viewport, etc.)
22
+ *
23
+ * @example
24
+ * const Camera = defineResource('Camera', { x: 0, y: 0, zoom: 1 });
25
+ */
26
+ declare function defineResource<T extends Record<string, any>>(name: string, defaults: T): ResourceType<T>;
27
+ /**
28
+ * Define a system. Systems are named functions that query and transform ECS data.
29
+ *
30
+ * @example
31
+ * const mySystem = defineSystem({
32
+ * name: 'physics',
33
+ * after: 'layout',
34
+ * execute: (world) => {
35
+ * for (const entity of world.query(Transform2D, Velocity)) { ... }
36
+ * },
37
+ * });
38
+ */
39
+ declare function defineSystem(def: SystemDef): SystemDef;
40
+
41
+ declare function createWorld(): World;
42
+
43
+ /**
44
+ * Manages system registration and ordered execution.
45
+ * Systems declare after/before constraints and are topologically sorted.
46
+ */
47
+ declare class SystemScheduler {
48
+ private systems;
49
+ private sorted;
50
+ profiler: Profiler | null;
51
+ register(system: SystemDef): void;
52
+ remove(name: string): void;
53
+ /**
54
+ * Execute all systems in dependency order.
55
+ */
56
+ execute(world: World): void;
57
+ getSystemNames(): string[];
58
+ /**
59
+ * Topological sort based on after/before constraints.
60
+ * Falls back to registration order for unconstrained systems.
61
+ */
62
+ private topoSort;
63
+ }
64
+
65
+ export { ComponentType, ResourceType, SystemDef, SystemScheduler, TagType, World, createWorld, defineComponent, defineResource, defineSystem, defineTag };
package/dist/ecs.d.ts ADDED
@@ -0,0 +1,65 @@
1
+ import { C as ComponentType, R as ResourceType, S as SystemDef, T as TagType, W as World, P as Profiler } from './profiler-DKuXy4MW.js';
2
+ export { b as ComponentInit, E as EntityId, Q as QueryResult, U as Unsubscribe } from './profiler-DKuXy4MW.js';
3
+
4
+ /**
5
+ * Define a component type. Components hold data attached to entities.
6
+ *
7
+ * @example
8
+ * const Transform2D = defineComponent('Transform2D', {
9
+ * x: 0, y: 0, width: 100, height: 100, rotation: 0,
10
+ * });
11
+ */
12
+ declare function defineComponent<T extends Record<string, any>>(name: string, defaults: T): ComponentType<T>;
13
+ /**
14
+ * Define a tag type. Tags are markers with no data — used for boolean state.
15
+ *
16
+ * @example
17
+ * const Selected = defineTag('Selected');
18
+ */
19
+ declare function defineTag(name: string): TagType;
20
+ /**
21
+ * Define a resource type. Resources are global singletons (camera, viewport, etc.)
22
+ *
23
+ * @example
24
+ * const Camera = defineResource('Camera', { x: 0, y: 0, zoom: 1 });
25
+ */
26
+ declare function defineResource<T extends Record<string, any>>(name: string, defaults: T): ResourceType<T>;
27
+ /**
28
+ * Define a system. Systems are named functions that query and transform ECS data.
29
+ *
30
+ * @example
31
+ * const mySystem = defineSystem({
32
+ * name: 'physics',
33
+ * after: 'layout',
34
+ * execute: (world) => {
35
+ * for (const entity of world.query(Transform2D, Velocity)) { ... }
36
+ * },
37
+ * });
38
+ */
39
+ declare function defineSystem(def: SystemDef): SystemDef;
40
+
41
+ declare function createWorld(): World;
42
+
43
+ /**
44
+ * Manages system registration and ordered execution.
45
+ * Systems declare after/before constraints and are topologically sorted.
46
+ */
47
+ declare class SystemScheduler {
48
+ private systems;
49
+ private sorted;
50
+ profiler: Profiler | null;
51
+ register(system: SystemDef): void;
52
+ remove(name: string): void;
53
+ /**
54
+ * Execute all systems in dependency order.
55
+ */
56
+ execute(world: World): void;
57
+ getSystemNames(): string[];
58
+ /**
59
+ * Topological sort based on after/before constraints.
60
+ * Falls back to registration order for unconstrained systems.
61
+ */
62
+ private topoSort;
63
+ }
64
+
65
+ export { ComponentType, ResourceType, SystemDef, SystemScheduler, TagType, World, createWorld, defineComponent, defineResource, defineSystem, defineTag };