@vworlds/vecs 1.0.53 → 1.0.55

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/README.md +9 -0
  2. package/dist/entity/entity.components.js +4 -2
  3. package/dist/entity/entity.components.js.map +1 -1
  4. package/dist/entity/entity.lifecycle.d.ts +2 -0
  5. package/dist/entity/entity.lifecycle.js +9 -4
  6. package/dist/entity/entity.lifecycle.js.map +1 -1
  7. package/dist/geometry.d.ts +5 -0
  8. package/dist/geometry.js +2 -0
  9. package/dist/geometry.js.map +1 -0
  10. package/dist/index.d.ts +3 -1
  11. package/dist/index.js +2 -1
  12. package/dist/index.js.map +1 -1
  13. package/dist/package.json +1 -1
  14. package/dist/system.d.ts +10 -0
  15. package/dist/system.js +19 -2
  16. package/dist/system.js.map +1 -1
  17. package/dist/timer.d.ts +15 -1
  18. package/dist/timer.js +24 -4
  19. package/dist/timer.js.map +1 -1
  20. package/dist/world/destroy-order.d.ts +8 -0
  21. package/dist/world/destroy-order.js +60 -0
  22. package/dist/world/destroy-order.js.map +1 -0
  23. package/dist/world/stats.d.ts +51 -0
  24. package/dist/world/stats.js +88 -0
  25. package/dist/world/stats.js.map +1 -0
  26. package/dist/world/world.base.js +2 -0
  27. package/dist/world/world.base.js.map +1 -1
  28. package/dist/world/world.components.d.ts +2 -0
  29. package/dist/world/world.components.js +4 -0
  30. package/dist/world/world.components.js.map +1 -1
  31. package/dist/world/world.disposal.d.ts +34 -36
  32. package/dist/world/world.disposal.js +89 -94
  33. package/dist/world/world.disposal.js.map +1 -1
  34. package/dist/world/world.entities.d.ts +21 -1
  35. package/dist/world/world.entities.js +54 -7
  36. package/dist/world/world.entities.js.map +1 -1
  37. package/dist/world/world.js +17 -11
  38. package/dist/world/world.js.map +1 -1
  39. package/dist/world/world.modules.d.ts +8 -0
  40. package/dist/world/world.modules.js +22 -1
  41. package/dist/world/world.modules.js.map +1 -1
  42. package/dist/world/world.pipeline.d.ts +15 -1
  43. package/dist/world/world.pipeline.js +40 -4
  44. package/dist/world/world.pipeline.js.map +1 -1
  45. package/docs/README.md +21 -19
  46. package/docs/components.md +9 -0
  47. package/docs/concepts.md +4 -0
  48. package/docs/design-guide.md +7 -3
  49. package/docs/entities.md +36 -25
  50. package/docs/glossary.md +3 -3
  51. package/docs/modules.md +62 -0
  52. package/docs/systems.md +108 -2
  53. package/package.json +1 -1
  54. package/tsconfig.types.json +6 -1
@@ -1,7 +1,14 @@
1
1
  import { Entity, Identity } from "../entity/index.js";
2
2
  import { Deferred } from "./world.deferred.js";
3
+ import { carriersFirst } from "./destroy-order.js";
4
+ import { ChildOf } from "../modules/relationship_types.js";
3
5
  const RESERVED_EID = 0;
4
6
  export class Entities extends Deferred {
7
+ constructor() {
8
+ super(...arguments);
9
+ /** @internal Parent applied only to entities created in the current scope. */
10
+ this._scope = undefined;
11
+ }
5
12
  /**
6
13
  * Return the entity with id `eid`, creating it if it does not yet exist.
7
14
  *
@@ -30,6 +37,10 @@ export class Entities extends Deferred {
30
37
  }
31
38
  else {
32
39
  this._entities.set(eid, e);
40
+ const parent = this._scope;
41
+ if (parent !== undefined) {
42
+ e.childOf(parent);
43
+ }
33
44
  this._notifyEntityCreated(e);
34
45
  onCreateCallback?.(e);
35
46
  }
@@ -92,26 +103,58 @@ export class Entities extends Deferred {
92
103
  }
93
104
  throw new Error(`No entity with eid ${ref.eid}`);
94
105
  }
95
- /** Destroy every entity currently tracked by the world. */
106
+ /**
107
+ * Destroy every tracked entity, ordering both carriers and ChildOf children
108
+ * before their keys/parents. Retains ordinary cleanup policies; throws when
109
+ * dependency cycles prevent safe destruction (unlike dispose's final pass).
110
+ */
96
111
  clearAllEntities() {
97
112
  const pending = new Set(this._entities.values());
98
113
  while (pending.size > 0) {
99
114
  let destroyed = 0;
100
- for (const entity of [...pending]) {
101
- const instanceCount = entity.instanceCount();
102
- if (instanceCount > (entity._get(entity.eid) ? 1 : 0)) {
103
- continue;
104
- }
115
+ for (const entity of carriersFirst([...pending], this._classRegistry.get(ChildOf)?.eid)) {
105
116
  entity.destroy();
106
117
  pending.delete(entity);
107
118
  destroyed++;
108
119
  }
109
120
  if (destroyed === 0) {
110
- throw new Error("Cannot clear entities because component eids are still in use");
121
+ throw new Error("Cannot clear entities because component or ChildOf dependencies cannot be ordered");
111
122
  }
112
123
  }
113
124
  this.flush();
114
125
  }
126
+ /**
127
+ * Parent entities created synchronously in `fn`'s body to `parent` through ChildOf.
128
+ * Includes components, modules, queries, systems and ordinary entities. Existing
129
+ * lookups are not reparented; an explicit childOf call replaces the scope parent.
130
+ * Nested scopes restore their caller in finally, even when fn throws.
131
+ * Entities created by deferred callbacks inside the body are not parented:
132
+ * query.forEach, enter backfill during query build, or an explicit world.defer.
133
+ * These are run-time data; the same callback outside the scope would not parent
134
+ * them either. For example, health bars created per existing ship by an enter
135
+ * or forEach callback remain roots, unlike definitions created directly in init.
136
+ * Throws while deferred: call outside progress() and defer, not during a command
137
+ * drain. Schedule lazy module loading after progress() returns.
138
+ * The parent must be a live entity of this world. This is a synchronous scope,
139
+ * not an async context; it does not change deferral or catch callback errors.
140
+ */
141
+ scope(parent, fn) {
142
+ if (this.deferred) {
143
+ throw new Error("Call world.scope() outside progress() and defer");
144
+ }
145
+ this.entity(parent);
146
+ if (parent.destroyed) {
147
+ throw new Error("scope parent must be alive");
148
+ }
149
+ const previous = this._scope;
150
+ this._scope = parent;
151
+ try {
152
+ fn();
153
+ }
154
+ finally {
155
+ this._scope = previous;
156
+ }
157
+ }
115
158
  /** @internal Create an entity with an id from the entity pool. */
116
159
  _entity(Constructor) {
117
160
  const eid = this._entityPool.alloc();
@@ -122,6 +165,10 @@ export class Entities extends Deferred {
122
165
  }
123
166
  else {
124
167
  this._entities.set(eid, e);
168
+ const parent = this._scope;
169
+ if (parent !== undefined) {
170
+ e.childOf(parent);
171
+ }
125
172
  this._notifyEntityCreated(e);
126
173
  }
127
174
  return e;
@@ -1 +1 @@
1
- {"version":3,"file":"world.entities.js","sourceRoot":"","sources":["../../src/world/world.entities.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"world.entities.js","sourceRoot":"","sources":["../../src/world/world.entities.ts"],"names":[],"mappings":"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"}
@@ -44,17 +44,23 @@ export class World extends Pipeline {
44
44
  this.component(SilenceSource).on("remove", (entity) => entity.get(Query)?._clearSilence());
45
45
  this.component(Query).on("remove", (_entity, query) => query.destroy());
46
46
  this.component(System).on("remove", (_entity, system) => system.destroy());
47
- [
48
- IdentityModule,
49
- ImplementsModule,
50
- SingletonModule,
51
- RelationshipsModule,
52
- // Registration order is not load-bearing: a capture binds the materializer
53
- // its policy resolved to, so `SnapshotModule` may install or change a
54
- // policy after entities already carry the component.
55
- SnapshotModule,
56
- PipelineModule,
57
- ].forEach((mod) => this.module(mod));
47
+ this._initializingModules = true;
48
+ try {
49
+ [
50
+ IdentityModule,
51
+ ImplementsModule,
52
+ SingletonModule,
53
+ RelationshipsModule,
54
+ // Registration order is not load-bearing: a capture binds the materializer
55
+ // its policy resolved to, so `SnapshotModule` may install or change a
56
+ // policy after entities already carry the component.
57
+ SnapshotModule,
58
+ PipelineModule,
59
+ ].forEach((mod) => this.module(mod));
60
+ }
61
+ finally {
62
+ this._initializingModules = false;
63
+ }
58
64
  }
59
65
  }
60
66
  //# sourceMappingURL=world.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"world.js","sourceRoot":"","sources":["../../src/world/world.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAG/C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,OAAO,KAAM,SAAQ,QAAQ;IACjC,YAAmB,UAAwB,EAAE;QAC3C,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,aAAa,EAAE,CAAC,CAAC;QAC3F,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QACxE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;QAC3E;YACE,cAAc;YACd,gBAAgB;YAChB,eAAe;YACf,mBAAmB;YACnB,2EAA2E;YAC3E,sEAAsE;YACtE,qDAAqD;YACrD,cAAc;YACd,cAAc;SACf,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IACvC,CAAC;CACF"}
1
+ {"version":3,"file":"world.js","sourceRoot":"","sources":["../../src/world/world.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAG/C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,OAAO,KAAM,SAAQ,QAAQ;IACjC,YAAmB,UAAwB,EAAE;QAC3C,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,aAAa,EAAE,CAAC,CAAC;QAC3F,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QACxE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;QAC3E,IAAI,CAAC,oBAAoB,GAAG,IAAI,CAAC;QACjC,IAAI,CAAC;YACH;gBACE,cAAc;gBACd,gBAAgB;gBAChB,eAAe;gBACf,mBAAmB;gBACnB,2EAA2E;gBAC3E,sEAAsE;gBACtE,qDAAqD;gBACrD,cAAc;gBACd,cAAc;aACf,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QACvC,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,oBAAoB,GAAG,KAAK,CAAC;QACpC,CAAC;IACH,CAAC;CACF"}
@@ -4,6 +4,14 @@ import { Components } from "./world.components.js";
4
4
  import type { World } from "./world.js";
5
5
  type ModuleArgs<T extends Module<any>> = undefined extends ModuleConfig<T> ? [eid?: EID] | [config: Exclude<ModuleConfig<T>, undefined>, eid?: EID] : [config: ModuleConfig<T>, eid?: EID];
6
6
  export declare class Modules extends Components {
7
+ /**
8
+ * Install a module once and run its synchronous init inside its entity scope.
9
+ * Constructor-installed core modules are unscoped; later modules parent all
10
+ * newly created entities, including nested modules. Existing entities stay put.
11
+ * Subsequent calls return the existing instance; passing config again throws.
12
+ * New installations throw while deferred; call outside progress() and defer.
13
+ * Existing-instance lookups remain available while deferred.
14
+ */
7
15
  module<T extends Module<any>>(this: World, ModuleClass: EntityClass<T>, ...args: ModuleArgs<T>): T;
8
16
  }
9
17
  export {};
@@ -1,15 +1,36 @@
1
1
  import { Components } from "./world.components.js";
2
2
  export class Modules extends Components {
3
+ constructor() {
4
+ super(...arguments);
5
+ /** @internal Constructor-installed core modules predate scoped ChildOf support. */
6
+ this._initializingModules = false;
7
+ }
8
+ /**
9
+ * Install a module once and run its synchronous init inside its entity scope.
10
+ * Constructor-installed core modules are unscoped; later modules parent all
11
+ * newly created entities, including nested modules. Existing entities stay put.
12
+ * Subsequent calls return the existing instance; passing config again throws.
13
+ * New installations throw while deferred; call outside progress() and defer.
14
+ * Existing-instance lookups remain available while deferred.
15
+ */
3
16
  module(ModuleClass, ...args) {
4
17
  const { config, eid } = resolveModuleArgs(args);
5
18
  const ComponentClass = ModuleClass;
6
19
  const isNew = !this._classRegistry.has(ComponentClass);
20
+ if (isNew && this.deferred) {
21
+ throw new Error("Call world.module() outside progress() and defer to install a new module");
22
+ }
7
23
  const mod = this._component(ModuleClass, ComponentClass, eid, this._modulePool);
8
24
  if (!isNew && config !== undefined) {
9
25
  throw new Error(`Module ${ModuleClass.name} is already registered; configuration is only accepted on first registration`);
10
26
  }
11
27
  if (isNew) {
12
- mod.init(config);
28
+ if (this._initializingModules) {
29
+ mod.init(config);
30
+ }
31
+ else {
32
+ this.scope(mod, () => mod.init(config));
33
+ }
13
34
  }
14
35
  return mod;
15
36
  }
@@ -1 +1 @@
1
- {"version":3,"file":"world.modules.js","sourceRoot":"","sources":["../../src/world/world.modules.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAQnD,MAAM,OAAO,OAAQ,SAAQ,UAAU;IAC9B,MAAM,CAEX,WAA2B,EAC3B,GAAG,IAAmB;QAEtB,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,iBAAiB,CAAC,IAAiD,CAAC,CAAC;QAC7F,MAAM,cAAc,GAAG,WAAwC,CAAC;QAChE,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QACvD,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAI,WAAW,EAAE,cAAc,EAAE,GAAG,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QACnF,IAAI,CAAC,KAAK,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACnC,MAAM,IAAI,KAAK,CACb,UAAU,WAAW,CAAC,IAAI,8EAA8E,CACzG,CAAC;QACJ,CAAC;QACD,IAAI,KAAK,EAAE,CAAC;YACV,GAAG,CAAC,IAAI,CAAC,MAAyB,CAAC,CAAC;QACtC,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;CACF;AAED,SAAS,iBAAiB,CAAC,IAA+C;IAIxE,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACtB,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;IAC3C,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;AACzC,CAAC"}
1
+ {"version":3,"file":"world.modules.js","sourceRoot":"","sources":["../../src/world/world.modules.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAQnD,MAAM,OAAO,OAAQ,SAAQ,UAAU;IAAvC;;QACE,mFAAmF;QACzE,yBAAoB,GAAG,KAAK,CAAC;IAoCzC,CAAC;IAlCC;;;;;;;OAOG;IACI,MAAM,CAEX,WAA2B,EAC3B,GAAG,IAAmB;QAEtB,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,iBAAiB,CAAC,IAAiD,CAAC,CAAC;QAC7F,MAAM,cAAc,GAAG,WAAwC,CAAC;QAChE,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QACvD,IAAI,KAAK,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC3B,MAAM,IAAI,KAAK,CAAC,0EAA0E,CAAC,CAAC;QAC9F,CAAC;QACD,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAI,WAAW,EAAE,cAAc,EAAE,GAAG,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QACnF,IAAI,CAAC,KAAK,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACnC,MAAM,IAAI,KAAK,CACb,UAAU,WAAW,CAAC,IAAI,8EAA8E,CACzG,CAAC;QACJ,CAAC;QACD,IAAI,KAAK,EAAE,CAAC;YACV,IAAI,IAAI,CAAC,oBAAoB,EAAE,CAAC;gBAC9B,GAAG,CAAC,IAAI,CAAC,MAAyB,CAAC,CAAC;YACtC,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,MAAyB,CAAC,CAAC,CAAC;YAC7D,CAAC;QACH,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;CACF;AAED,SAAS,iBAAiB,CAAC,IAA+C;IAIxE,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACtB,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;IAC3C,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;AACzC,CAAC"}
@@ -3,16 +3,30 @@ import { Query } from "../query/index.js";
3
3
  import { System } from "../system.js";
4
4
  import type { WorldOptions } from "./world.base.js";
5
5
  import { Disposal } from "./world.disposal.js";
6
+ import { WorldStats } from "./stats.js";
6
7
  export declare class Pipeline extends Disposal {
8
+ /** Opt-in per-system timing, including each admitted system's subsequent flush. */
9
+ readonly stats: WorldStats;
7
10
  constructor(options?: WorldOptions);
11
+ /**
12
+ * Systems in pipeline execution order, including disabled systems.
13
+ * Between frames, builds pending queries (finishing builder configuration)
14
+ * and refreshes the existing flat pipeline only when its query changed.
15
+ * During a frame, returns that frame's pipeline. Does not drain deferred
16
+ * commands or run systems.
17
+ * The array is read-only at the type level; do not mutate it. Re-read this
18
+ * getter after configuration changes rather than retaining an old array.
19
+ */
20
+ get pipeline(): readonly System[];
8
21
  /** Open a new frame and evaluate every registered tick source once. */
9
22
  beginFrame(delta: number): void;
10
23
  /** Close the current frame. */
11
24
  endFrame(): void;
12
- /** Run every system in the pipeline query order. */
25
+ /** Run every system in pipeline order; opt-in stats include each system's flush. */
13
26
  progress(now: number, delta: number): void;
14
27
  /** Define the query whose ordered results become this world's system pipeline. */
15
28
  setPipeline<const S extends QuerySpec>(spec: S): Query<[typeof System]>;
16
29
  /** Create and return a new {@link System}, ready for fluent configuration. */
17
30
  system(name: string): System;
31
+ private _progressInstrumented;
18
32
  }
@@ -1,9 +1,12 @@
1
1
  import { System } from "../system.js";
2
2
  import { ALWAYS_TICK_SOURCE } from "../timer.js";
3
3
  import { Disposal } from "./world.disposal.js";
4
+ import { WorldStats } from "./stats.js";
4
5
  export class Pipeline extends Disposal {
5
6
  constructor(options = {}) {
6
7
  super(options);
8
+ /** Opt-in per-system timing, including each admitted system's subsequent flush. */
9
+ this.stats = new WorldStats(() => this._pipeline);
7
10
  /** @internal Flat system execution pipeline, rebuilt from `_pipelineQuery`. */
8
11
  this._pipeline = [];
9
12
  /** @internal Query whose ordered result defines the system pipeline. */
@@ -14,6 +17,22 @@ export class Pipeline extends Disposal {
14
17
  this._frameCounter = 0;
15
18
  this._tickSources.add(ALWAYS_TICK_SOURCE);
16
19
  }
20
+ /**
21
+ * Systems in pipeline execution order, including disabled systems.
22
+ * Between frames, builds pending queries (finishing builder configuration)
23
+ * and refreshes the existing flat pipeline only when its query changed.
24
+ * During a frame, returns that frame's pipeline. Does not drain deferred
25
+ * commands or run systems.
26
+ * The array is read-only at the type level; do not mutate it. Re-read this
27
+ * getter after configuration changes rather than retaining an old array.
28
+ */
29
+ get pipeline() {
30
+ if (!this._frameInProgress) {
31
+ this._buildPendingQueries();
32
+ this._refreshPipelineIfChanged();
33
+ }
34
+ return this._pipeline;
35
+ }
17
36
  /** Open a new frame and evaluate every registered tick source once. */
18
37
  beginFrame(delta) {
19
38
  if (this._frameInProgress) {
@@ -33,13 +52,18 @@ export class Pipeline extends Disposal {
33
52
  }
34
53
  this._frameInProgress = false;
35
54
  }
36
- /** Run every system in the pipeline query order. */
55
+ /** Run every system in pipeline order; opt-in stats include each system's flush. */
37
56
  progress(now, delta) {
38
57
  this.beginFrame(delta);
39
58
  try {
40
- for (const system of this._pipeline) {
41
- system._run(now, delta);
42
- this.flush();
59
+ if (this.stats.systemsEnabled) {
60
+ this._progressInstrumented(now, delta);
61
+ }
62
+ else {
63
+ for (const system of this._pipeline) {
64
+ system._run(now, delta);
65
+ this.flush();
66
+ }
43
67
  }
44
68
  }
45
69
  finally {
@@ -75,5 +99,17 @@ export class Pipeline extends Disposal {
75
99
  });
76
100
  this._pipeline = systems;
77
101
  }
102
+ _progressInstrumented(now, delta) {
103
+ for (const system of this._pipeline) {
104
+ const slot = this.stats._systemSlot(system);
105
+ const start = performance.now();
106
+ const ran = system._run(now, delta);
107
+ this.flush();
108
+ const elapsed = performance.now() - start;
109
+ if (ran) {
110
+ this.stats._record(slot, elapsed);
111
+ }
112
+ }
113
+ }
78
114
  }
79
115
  //# sourceMappingURL=world.pipeline.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"world.pipeline.js","sourceRoot":"","sources":["../../src/world/world.pipeline.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"world.pipeline.js","sourceRoot":"","sources":["../../src/world/world.pipeline.ts"],"names":[],"mappings":"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"}
package/docs/README.md CHANGED
@@ -15,16 +15,18 @@ Read in this order the first time through:
15
15
  routing. Read this before designing anything non-trivial.
16
16
  4. Subsystem guides, in any order:
17
17
  - [Components](./components.md) — registration, hooks, traits, exclusivity, cleanup policies,
18
- interfaces, singletons.
18
+ interfaces, singletons, and [registration provenance](./components.md#registration-provenance).
19
19
  - [Entities](./entities.md) — creation, lookup, the component API, relationship targets, lifecycle,
20
- disposing a world.
20
+ [synchronous world disposal and allowed call sites](./entities.md#disposing-a-world).
21
21
  - [Systems](./systems.md) — membership, reactive callbacks, callback options, `each`/`run`, cadence,
22
- component, relationship, and [clock injection](./systems.md#clock-injection).
22
+ component, relationship, and [clock injection](./systems.md#clock-injection), plus
23
+ [execution-order and cadence introspection](./systems.md#introspection) and
24
+ [opt-in timing and run counts](./systems.md#measuring-systems).
23
25
  - [Queries and filters](./queries-and-filters.md) — the query DSL, live queries, one-shot
24
26
  filters, grouped queries, `Bitset`.
25
27
  - [Relationships](./relationships.md) — links, target creation and projection, ownership, hierarchy,
26
28
  cleanup cascades.
27
- - [Modules](./modules.md) — packaging features, composition, the built-in modules.
29
+ - [Modules](./modules.md) — packaging features, composition, scopes and module provenance, built-in modules.
28
30
  - [Subtree snapshots](./snapshots.md) — capturing, restoring, and moving an entity forest
29
31
  between two worlds.
30
32
  5. [Design guide](./design-guide.md) — opinionated patterns and anti-patterns distilled from real
@@ -38,21 +40,21 @@ Keep the [Glossary](./glossary.md) at hand for terminology.
38
40
 
39
41
  For Node clients that need replicated Phaser poses, see [Headless clients](../../vecs-phaser-client/README.md#headless-clients).
40
42
 
41
- | Guide | Covers |
42
- | -------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
43
- | [getting-started.md](./getting-started.md) | A runnable tutorial from `npm install` to a ticking world. |
44
- | [concepts.md](./concepts.md) | The core vocabulary and how the pieces relate. |
45
- | [execution-model.md](./execution-model.md) | `world.progress`, the 8 built-in phases, deferred commands, flush boundaries, event routing. |
46
- | [components.md](./components.md) | Component registration, hooks, traits, exclusivity, cleanup, aliases, and singletons. |
47
- | [entities.md](./entities.md) | Entity creation, mutation, relationship targets, lifecycle, disposal, deferred reads. |
48
- | [systems.md](./systems.md) | `world.system`, callbacks, component/relationship/clock injection, ordering, cadence, and tick sources. |
49
- | [queries-and-filters.md](./queries-and-filters.md) | `QueryDSL`, `Query`, `Filter`, `groupBy`, `ignoreSource`. |
50
- | [relationships.md](./relationships.md) | Relationships, target creation, projection and ownership, hierarchy, traversal, and cleanup. |
51
- | [modules.md](./modules.md) | `Module<Config>`, `world.module`, composition, built-in modules. |
52
- | [snapshots.md](./snapshots.md) | `snapshotSubtree`, `restoreSubtree`, `moveSubtree`, and `OnSnapshot` capture policies. |
53
- | [design-guide.md](./design-guide.md) | Patterns, anti-patterns, and a Phaser render-layer case study. |
54
- | [utilities.md](./utilities.md) | Public helper classes: `Events`, `ArrayMap`, `IterableArrayMap`, plus `Bitset` cross-ref. |
55
- | [glossary.md](./glossary.md) | ECS and vecs terminology. |
43
+ | Guide | Covers |
44
+ | -------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
45
+ | [getting-started.md](./getting-started.md) | A runnable tutorial from `npm install` to a ticking world. |
46
+ | [concepts.md](./concepts.md) | The core vocabulary and how the pieces relate, including the shared `Vec2` type. |
47
+ | [execution-model.md](./execution-model.md) | `world.progress`, the 8 built-in phases, deferred commands, flush boundaries, event routing. |
48
+ | [components.md](./components.md) | Component registration/provenance, hooks, traits, exclusivity, cleanup, aliases, and singletons. |
49
+ | [entities.md](./entities.md) | Entity creation, mutation, relationship targets, lifecycle, disposal, deferred reads. |
50
+ | [systems.md](./systems.md) | `world.system`, callbacks, injection, ordering, cadence, tick sources, introspection, and opt-in timing. |
51
+ | [queries-and-filters.md](./queries-and-filters.md) | `QueryDSL`, `Query`, `Filter`, `groupBy`, `ignoreSource`. |
52
+ | [relationships.md](./relationships.md) | Relationships, target creation, projection and ownership, hierarchy, traversal, and cleanup. |
53
+ | [modules.md](./modules.md) | `Module<Config>`, `world.module`, `world.scope`, hierarchy provenance, built-in modules. |
54
+ | [snapshots.md](./snapshots.md) | `snapshotSubtree`, `restoreSubtree`, `moveSubtree`, and `OnSnapshot` capture policies. |
55
+ | [design-guide.md](./design-guide.md) | Patterns, anti-patterns, and a Phaser render-layer case study. |
56
+ | [utilities.md](./utilities.md) | Public helper classes: `Events`, `ArrayMap`, `IterableArrayMap`, plus `Bitset` cross-ref. |
57
+ | [glossary.md](./glossary.md) | ECS and vecs terminology. |
56
58
 
57
59
  Networking (wire encoding with `@wireType`, protocol component ordering, replication, RPCs, server
58
60
  sessions, and the client world) lives in the `@vworlds/vecs-wire`, `@vworlds/vecs-protocol`,
@@ -55,6 +55,15 @@ same class return the same entity. The same class can be registered independentl
55
55
  worlds — metadata is world-specific. Passing an explicit id for an already-registered class (with
56
56
  a different id) throws, as does passing a name with no matching component entity.
57
57
 
58
+ ### Registration provenance
59
+
60
+ Components created during a module's `init` become its `ChildOf` children, through
61
+ [`world.scope`](./modules.md#scopes-and-module-provenance). Read `world.component(C).parent`,
62
+ or walk parents to the nearest `Module` when an explicit hierarchy intervenes (for example
63
+ `OneOf` values). Existing registrations are never reparented by a second module. There is no
64
+ registrar list or per-trait audit; trait additions do not create separate entities. Vecs' own
65
+ constructor-installed built-in modules remain unscoped.
66
+
58
67
  ### Id pools
59
68
 
60
69
  Entity ids are drawn from configurable pools. The defaults
package/docs/concepts.md CHANGED
@@ -12,6 +12,10 @@ every idiom in the [Design guide](./design-guide.md) is a consequence of taking
12
12
 
13
13
  ## The pieces
14
14
 
15
+ For packages and applications that exchange 2D points or vectors, import the shared type with
16
+ `import type { Vec2 } from "@vworlds/vecs"`. It is structural (`{ x: number; y: number }`) and has
17
+ no runtime or wire representation.
18
+
15
19
  | Concept | What it is |
16
20
  | -------------------------- | ------------------------------------------------------------------------------------------------------------ |
17
21
  | **World** | Central container. Owns every entity, registered component, query, system, and the flat system pipeline. |
@@ -135,7 +135,8 @@ world.component(Phaser.GameObjects.Arc).on("remove", (_entity, obj) => obj.destr
135
135
 
136
136
  `onRemove` (below) releases the resource whenever it leaves — whether removed explicitly,
137
137
  because the entity was destroyed, or because the world was disposed (`world.dispose()` destroys
138
- every entity the application created; see [Disposing a world](./entities.md#disposing-a-world)).
138
+ application entities and then infrastructure and singleton data; see
139
+ [Disposing a world](./entities.md#disposing-a-world)).
139
140
  When several resource types should share one cleanup hook or be queried together, give them a
140
141
  common **interface** with `Implements` (see §7 and the §10 case study). A plain wrapper component
141
142
  (`class Handle { obj }`) is still fine when you need extra fields beside the resource.
@@ -881,9 +882,12 @@ system after whatever produces the entity/companion.
881
882
  That guard is legitimate; elsewhere a `destroyed` check usually signals a missing edge (see §8 and
882
883
  [Hooks](./components.md#hooks-component-and-relationship-edges)).
883
884
  - **Release resources in `remove` hooks, not in a system's `exit` callback.** `world.dispose()`
884
- runs the hooks during the call, but a system's `exit` callback only queues its event, and a
885
- disposed world never runs the system again (see
885
+ runs hooks during teardown, but a system's `exit` callback only queues its event and may not
886
+ run before infrastructure is destroyed (see
886
887
  [Disposing a world](./entities.md#disposing-a-world)).
888
+ - **Request shutdown in a system; dispose after the tick.** For allowed call sites and refusal
889
+ behavior, see [Disposing a world](./entities.md#disposing-a-world). No core tick or mutation
890
+ boundary performs disposal for you.
887
891
  - **Within a phase, order = registration order;** across phases, the spine guarantees order. Don't
888
892
  use registration order for cross-module correctness — use phases.
889
893
  - **Networked component order = wire protocol.** Reordering breaks the protocol.
package/docs/entities.md CHANGED
@@ -186,8 +186,8 @@ runtime-created component types work without declaring a class.
186
186
  ## Disposing a world
187
187
 
188
188
  When you are finished with a world — a scene or route change, a hot reload — call
189
- `world.dispose()` and drop the reference. It destroys every entity the application and its modules
190
- created, so the `remove` hook of each component they carry runs and releases what the component
189
+ `world.dispose()` and drop the reference. It destroys application entities, then the world's
190
+ infrastructure, so the `remove` hook of each component they carry runs and releases what the component
191
191
  owns: a render object, a handle, a timer.
192
192
 
193
193
  ```ts
@@ -206,13 +206,13 @@ world.dispose();
206
206
  handle.released; // true
207
207
  ```
208
208
 
209
- Each entity goes through the ordinary destroy path. Every `remove` hook fires once,
210
- [cleanup policies and cascades](./relationships.md#cleanup-when-a-target-dies) run as for any
211
- `destroy()`, and an entity that a `ChildOf` or `OwnedTarget` cascade, or a hook, has already
212
- destroyed is skipped instead of destroyed twice.
209
+ Disposal uses two passes through the existing entity destroy path. Every `remove` hook fires once;
210
+ entities already destroyed by a hook or cascade are skipped. In **pass 1**, every application entity
211
+ uses ordinary [cleanup policies and cascades](./relationships.md#cleanup-when-a-target-dies).
212
+ This includes plain entities created inside module scopes, even though their parent is infrastructure.
213
+ Application hook-generated commands settle before pass 2 starts.
213
214
 
214
- `dispose()` leaves the world's infrastructure in place, because the world needs it to stay
215
- coherent. It recognizes it as follows (`lib/vecs/src/world/world.disposal.ts`):
215
+ **Pass 2** destroys remaining infrastructure (`lib/vecs/src/world/world.disposal.ts`):
216
216
 
217
217
  | Infrastructure | Recognized by |
218
218
  | ----------------------------- | ------------------------------------------------------------- |
@@ -220,26 +220,37 @@ coherent. It recognizes it as follows (`lib/vecs/src/world/world.disposal.ts`):
220
220
  | Query and system entities | They carry the `Query` component. |
221
221
  | Phase entities | They carry the `Phase` component. |
222
222
 
223
- What those entities hold stays with them: data stored on a component entity (a singleton set with
224
- `world.set`) and any entity they still carry as a [component key](#entities-as-component-keys),
225
- which cannot be destroyed while it is in use. Release those yourself; their `remove` hooks do not
226
- run. `clearAllEntities()` is the full wipe that takes the infrastructure too.
223
+ Data stored on component entities (including singletons set with `world.set`) is removed once,
224
+ after queued application cleanup. Bind module-owned resources to that data with `remove` hooks;
225
+ you do not need a separate disposal callback.
226
+
227
+ During pass 2 only, cleanup policies are suspended. `ChildOf`/`OwnedTarget` do not cascade;
228
+ children are destroyed explicitly in the pass. A component still carried by another entity is removed
229
+ from each carrier through the ordinary remove path, firing its public `remove` hooks, instead of
230
+ throwing or deleting the carriers. Irrevocable relationship-trait guards are bypassed, extending the
231
+ existing destroy-time exemption. This suspension also covers the pass's hook-generated commands and
232
+ is reset in `finally`. Successful disposal leaves nothing, including component-carrier cycles.
227
233
 
228
234
  - **Order.** Among unrelated entities the order is unspecified, so do not make a hook depend on it.
229
- An entity used as a component key is destroyed after every entity that carries it, because
230
- destroying it first would throw under the default cleanup policy.
231
- - **Pending commands.** `dispose()` neither flushes the command queue early nor discards it. Commands
232
- queued ahead of it run first, in order, and the destruction follows in the same queue, so each
233
- hook fires once however the component left. At top level nothing is queued, and `dispose()`
234
- returns with the entities gone. Inside a system, a hook or a `defer` block the world is
235
- [deferred](./execution-model.md#deferred-mutation-and-flush-boundaries), so `dispose()` queues the
236
- destruction as `destroy()` does, and it completes when the queue next drains. An entity whose
237
- creation is still queued is created, then destroyed.
235
+ Pass 2 processes systems and queries first, then modules in reverse registration order, then the
236
+ rest. Beyond those priorities the order is unspecified; it is not a resource dependency contract.
237
+ There is no infrastructure carriers-first sort or dependency-survivor error. If an internal bug
238
+ prevents a full teardown pass from destroying anything, an invariant error names the remaining
239
+ registered entities instead of looping forever. `clearAllEntities()` retains its
240
+ ordinary cleanup policies and throwing behavior; it orders both carriers before component keys
241
+ and children before parents, and throws if those dependencies cannot be ordered. The suspension
242
+ belongs only to `dispose()`.
243
+ - **Call site.** Call at top level: not inside `progress()`, `defer`, a command drain or an
244
+ entity's destroy. A forbidden call throws before disposal changes anything, leaving the world
245
+ usable; finish the enclosing operation and dispose afterwards. Ordinary synchronous top-level
246
+ `add`, `set` and `remove` hooks may call it. Teardown is synchronous: application hook-generated
247
+ commands settle before infrastructure teardown, and `dispose()` returns with the entities gone.
248
+ The final pass drains its own hook-generated commands and repeats while it can destroy more entities.
238
249
  - **After disposal.** A disposed world must not be used again. Nothing enforces it — no other method
239
- checks, so `entity()` and `progress()` keep their cost. Calling `dispose()` again, or from a hook
240
- during the teardown, does nothing. An entity that a `remove` hook creates during the teardown is
241
- left behind, so do not spawn from teardown hooks. A system's `exit` callback only queues its event,
242
- and a disposed world never runs the system again; release resources in `remove` hooks, as
250
+ mutation checks are added. Calling `dispose()` again at top level does nothing; the call-site
251
+ rule still applies during teardown. Do not keep spawning from teardown hooks: that prevents
252
+ the repeated final pass from settling. A system's queued `exit` callback will not run after
253
+ teardown; release resources in `remove` hooks, as
243
254
  [Resources as components](./design-guide.md#resources-as-components-hold-non-ecs-objects)
244
255
  recommends.
245
256
 
package/docs/glossary.md CHANGED
@@ -38,9 +38,9 @@ behavior. [Components](./components.md).
38
38
  queued as commands; `flush` drains the queue at the scope boundary (after each system in the
39
39
  pipeline). [Execution model](./execution-model.md#deferred-mutation-and-flush-boundaries).
40
40
 
41
- **Dispose** — `world.dispose()`: end a world's life by destroying every entity the application and
42
- its modules created, so their components' `remove` hooks run. The infrastructure (component,
43
- module, query, system, and phase entities) stays. [Entities](./entities.md#disposing-a-world).
41
+ **Dispose** — `world.dispose()`: end a world's life by destroying application entities, then
42
+ infrastructure and singleton data, through their `remove` hooks. See
43
+ [Entities](./entities.md#disposing-a-world) for timing, ordering and still-carried keys.
44
44
 
45
45
  **Entity** — a unique numeric id (`eid`) owned by a world, with a set of components attached.
46
46
  [Entities](./entities.md).