@adobe/ecs 0.2.0 → 0.2.3

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 (262) hide show
  1. package/README.md +2 -2
  2. package/dist/implementation/compiler/describe.d.ts +1 -1
  3. package/dist/implementation/compiler/describe.js +3 -3
  4. package/dist/implementation/compiler/describe.js.map +1 -1
  5. package/dist/implementation/compiler/signature.js +1 -1
  6. package/dist/implementation/compiler/transform.js +3 -3
  7. package/dist/implementation/compiler/transform.js.map +1 -1
  8. package/dist/implementation/world/commands.js +50 -1
  9. package/dist/implementation/world/commands.js.map +1 -1
  10. package/dist/implementation/world/create.js.map +1 -1
  11. package/dist/implementation/world/entities.d.ts +2 -0
  12. package/dist/implementation/world/entities.js +6 -0
  13. package/dist/implementation/world/entities.js.map +1 -1
  14. package/dist/implementation/world/finalizers.js.map +1 -1
  15. package/dist/implementation/world/join.js +10 -2
  16. package/dist/implementation/world/join.js.map +1 -1
  17. package/dist/implementation/world/register.js +2 -2
  18. package/dist/implementation/world/rows.d.ts +1 -1
  19. package/dist/implementation/world/rows.js +5 -0
  20. package/dist/implementation/world/rows.js.map +1 -1
  21. package/dist/implementation/world/runner.js +3 -3
  22. package/dist/implementation/world/runner.js.map +1 -1
  23. package/dist/implementation/world/sharing.js +1 -1
  24. package/dist/implementation/world/staging.d.ts +4 -0
  25. package/dist/implementation/world/staging.js +15 -3
  26. package/dist/implementation/world/staging.js.map +1 -1
  27. package/dist/implementation/world/tables-read.d.ts +7 -0
  28. package/dist/implementation/world/tables-read.js +60 -0
  29. package/dist/implementation/world/tables-read.js.map +1 -0
  30. package/dist/implementation/world/tables.d.ts +9 -0
  31. package/dist/implementation/world/tables.js +355 -0
  32. package/dist/implementation/world/tables.js.map +1 -0
  33. package/dist/implementation/world/thread-observer.js +1 -1
  34. package/dist/implementation/world/thread-observer.js.map +1 -1
  35. package/dist/implementation/world/thread-systems.js +1 -0
  36. package/dist/implementation/world/thread-systems.js.map +1 -1
  37. package/dist/index.d.ts +8 -8
  38. package/dist/index.js +4 -9
  39. package/dist/index.js.map +1 -1
  40. package/dist/interface/component/component.d.ts +7 -1
  41. package/dist/interface/component/component.js +0 -1
  42. package/dist/interface/component/component.js.map +1 -1
  43. package/dist/interface/component/declarations.d.ts +4 -0
  44. package/dist/interface/component/declarations.js +8 -0
  45. package/dist/interface/component/declarations.js.map +1 -0
  46. package/dist/interface/component/declared.d.ts +12 -0
  47. package/dist/interface/component/declared.js +2 -0
  48. package/dist/interface/component/declared.js.map +1 -0
  49. package/dist/interface/component/index.d.ts +3 -1
  50. package/dist/interface/component/index.js +1 -1
  51. package/dist/interface/component/index.js.map +1 -1
  52. package/dist/interface/component/value.d.ts +5 -5
  53. package/dist/interface/component/values.d.ts +2 -2
  54. package/dist/interface/finalizer/body.d.ts +5 -5
  55. package/dist/interface/registry/names.d.ts +2 -0
  56. package/dist/interface/registry/names.js +9 -0
  57. package/dist/interface/registry/names.js.map +1 -1
  58. package/dist/interface/registry/schedule.d.ts +3 -3
  59. package/dist/interface/registry/schedule.js +3 -3
  60. package/dist/interface/registry/schedule.js.map +1 -1
  61. package/dist/interface/resource/condition.d.ts +3 -3
  62. package/dist/interface/resource/declarations.d.ts +4 -0
  63. package/dist/interface/resource/declarations.js +8 -0
  64. package/dist/interface/resource/declarations.js.map +1 -0
  65. package/dist/interface/resource/index.d.ts +2 -1
  66. package/dist/interface/resource/index.js +1 -1
  67. package/dist/interface/resource/index.js.map +1 -1
  68. package/dist/interface/resource/resource.d.ts +4 -1
  69. package/dist/interface/resource/resource.js +0 -1
  70. package/dist/interface/resource/resource.js.map +1 -1
  71. package/dist/interface/resource/value.d.ts +5 -5
  72. package/dist/interface/resources/cadence.d.ts +1 -1
  73. package/dist/interface/system/access.d.ts +1 -1
  74. package/dist/interface/system/body.d.ts +13 -8
  75. package/dist/interface/system/check.d.ts +1 -1
  76. package/dist/interface/system/check.js +25 -9
  77. package/dist/interface/system/check.js.map +1 -1
  78. package/dist/interface/system/commands.d.ts +20 -4
  79. package/dist/interface/system/create.d.ts +21 -9
  80. package/dist/interface/system/create.js +3 -3
  81. package/dist/interface/system/create.js.map +1 -1
  82. package/dist/interface/system/declaration.d.ts +9 -2
  83. package/dist/interface/system/struct.d.ts +2 -2
  84. package/dist/interface/system/tables.d.ts +20 -0
  85. package/dist/interface/system/tables.js +2 -0
  86. package/dist/interface/system/tables.js.map +1 -0
  87. package/dist/interface/system/values-of.d.ts +4 -4
  88. package/dist/interface/system/values.d.ts +5 -5
  89. package/dist/interface/trait/types.d.ts +4 -4
  90. package/dist/interface/world/create.d.ts +3 -7
  91. package/dist/interface/world/declarations.d.ts +2 -2
  92. package/dist/interface/world/index.d.ts +1 -1
  93. package/dist/interface/world/join.d.ts +2 -10
  94. package/dist/interface/world/table/index.d.ts +26 -0
  95. package/dist/interface/world/table/index.js +3 -0
  96. package/dist/interface/world/table/index.js.map +1 -0
  97. package/dist/interface/world/table/table.d.ts +11 -0
  98. package/dist/interface/world/table/table.js +2 -0
  99. package/dist/interface/world/table/table.js.map +1 -0
  100. package/dist/interface/world/world.d.ts +10 -10
  101. package/dist/world.d.ts +27 -0
  102. package/dist/world.js +27 -0
  103. package/dist/world.js.map +1 -0
  104. package/package.json +1 -1
  105. package/src/exports.test.ts +3 -3
  106. package/src/guide/00-keys.ts +1 -1
  107. package/src/guide/01-resources.md +1 -1
  108. package/src/guide/01-resources.ts +1 -1
  109. package/src/guide/02-entities.ts +2 -2
  110. package/src/guide/03-systems.md +2 -2
  111. package/src/guide/03-systems.out +1 -1
  112. package/src/guide/03-systems.ts +3 -3
  113. package/src/guide/04-ticks.md +1 -1
  114. package/src/guide/04-ticks.ts +3 -3
  115. package/src/guide/05-scheduling.ts +1 -1
  116. package/src/guide/06-sync-points.md +9 -2
  117. package/src/guide/06-sync-points.ts +2 -2
  118. package/src/guide/07-change-filters.ts +2 -2
  119. package/src/guide/08-input.ts +1 -1
  120. package/src/guide/09-rules.ts +1 -1
  121. package/src/guide/11-traits.ts +3 -3
  122. package/src/guide/11-traits.type-test.ts +1 -1
  123. package/src/guide/12-lookups.ts +2 -2
  124. package/src/guide/13-indexes.ts +4 -4
  125. package/src/guide/14-kernels.ts +1 -1
  126. package/src/guide/15-reductions.ts +1 -1
  127. package/src/guide/16-gpu.ts +1 -1
  128. package/src/guide/17-hierarchies.ts +1 -1
  129. package/src/guide/18-identity.out +1 -1
  130. package/src/guide/19-threads.md +4 -2
  131. package/src/guide/19-threads.ts +2 -2
  132. package/src/guide/20-shared.ts +3 -3
  133. package/src/guide/21-dom.md +2 -2
  134. package/src/guide/21-dom.ts +1 -1
  135. package/src/guide/22-canvas.md +1 -1
  136. package/src/guide/22-canvas.ts +1 -1
  137. package/src/guide/CLAUDE.md +1 -1
  138. package/src/guide/guide.test.ts +7 -5
  139. package/src/implementation/compiler/describe.test-helper.ts +1 -1
  140. package/src/implementation/compiler/describe.test.ts +1 -1
  141. package/src/implementation/compiler/describe.ts +3 -3
  142. package/src/implementation/compiler/hygiene.test.ts +1 -1
  143. package/src/implementation/compiler/plugin.test.ts +2 -2
  144. package/src/implementation/compiler/signature.ts +1 -1
  145. package/src/implementation/compiler/transform.test.ts +3 -3
  146. package/src/implementation/compiler/transform.ts +3 -3
  147. package/src/implementation/world/change-blocks.test.ts +1 -1
  148. package/src/implementation/world/commands.ts +44 -1
  149. package/src/implementation/world/create.ts +3 -3
  150. package/src/implementation/world/defaults.test.ts +1 -1
  151. package/src/implementation/world/entities.ts +6 -0
  152. package/src/implementation/world/finalizers.test.ts +1 -1
  153. package/src/implementation/world/finalizers.ts +3 -3
  154. package/src/implementation/world/index-changed.test.ts +2 -2
  155. package/src/implementation/world/index-joined.test.ts +5 -5
  156. package/src/implementation/world/index-order.test.ts +1 -1
  157. package/src/implementation/world/join.test.ts +4 -4
  158. package/src/implementation/world/join.ts +10 -2
  159. package/src/implementation/world/joined-observer.test.ts +1 -1
  160. package/src/implementation/world/joining-worker.fixture.ts +1 -1
  161. package/src/implementation/world/joining.fixture.ts +1 -1
  162. package/src/implementation/world/joining.test-helper.ts +1 -1
  163. package/src/implementation/world/kernel-spawns.test.ts +1 -1
  164. package/src/implementation/world/observe-factories.test.ts +2 -2
  165. package/src/implementation/world/observe-ticks-cases.test.ts +1 -1
  166. package/src/implementation/world/observe.test-helper.ts +1 -1
  167. package/src/implementation/world/observer-contained-worker.fixture.ts +1 -1
  168. package/src/implementation/world/observer-contained.test-helper.ts +1 -1
  169. package/src/implementation/world/observer-contained.test.ts +2 -2
  170. package/src/implementation/world/observer-joined.test-helper.ts +4 -4
  171. package/src/implementation/world/observer-joined.test.ts +23 -15
  172. package/src/implementation/world/observer.browser.test.ts +2 -2
  173. package/src/implementation/world/observer.test.ts +8 -8
  174. package/src/implementation/world/optional-workers.fixture.ts +1 -1
  175. package/src/implementation/world/optional.test.ts +7 -7
  176. package/src/implementation/world/pool-size.cases.ts +3 -1
  177. package/src/implementation/world/reads.test-helper.ts +6 -6
  178. package/src/implementation/world/reclaim.test.ts +3 -3
  179. package/src/implementation/world/register.ts +2 -2
  180. package/src/implementation/world/remote-objects.test-helper.ts +1 -1
  181. package/src/implementation/world/rows.ts +5 -1
  182. package/src/implementation/world/run-results.test.ts +10 -10
  183. package/src/implementation/world/runner.ts +3 -3
  184. package/src/implementation/world/shared-gpu.browser.test.ts +2 -2
  185. package/src/implementation/world/shared-kernels.test.ts +2 -2
  186. package/src/implementation/world/shared-workers.fixture.ts +2 -2
  187. package/src/implementation/world/shared.test.ts +8 -8
  188. package/src/implementation/world/sharing.ts +1 -1
  189. package/src/implementation/world/staging.ts +16 -3
  190. package/src/implementation/world/tables-read.ts +59 -0
  191. package/src/implementation/world/tables.test.ts +267 -0
  192. package/src/implementation/world/tables.ts +330 -0
  193. package/src/implementation/world/tails.test.ts +1 -1
  194. package/src/implementation/world/target.test.ts +2 -2
  195. package/src/implementation/world/thread-observer.ts +1 -1
  196. package/src/implementation/world/thread-systems.test-helper.ts +3 -3
  197. package/src/implementation/world/thread-systems.ts +1 -0
  198. package/src/implementation/world/where.test.ts +4 -4
  199. package/src/implementation/world/workers.fixture.ts +2 -2
  200. package/src/index.ts +4 -6
  201. package/src/interface/component/component.ts +7 -1
  202. package/src/interface/component/declarations.ts +11 -0
  203. package/src/interface/component/declared.ts +9 -0
  204. package/src/interface/component/index.ts +3 -1
  205. package/src/interface/component/value.ts +5 -5
  206. package/src/interface/component/values.ts +2 -2
  207. package/src/interface/finalizer/body.ts +5 -5
  208. package/src/interface/index.type-test.ts +3 -3
  209. package/src/interface/indexes/index.type-test.ts +1 -1
  210. package/src/interface/registry/names.ts +8 -0
  211. package/src/interface/registry/schedule.ts +4 -4
  212. package/src/interface/resource/condition.ts +3 -3
  213. package/src/interface/resource/declarations.ts +11 -0
  214. package/src/interface/resource/index.ts +2 -1
  215. package/src/interface/resource/resource.ts +4 -1
  216. package/src/interface/resource/value.ts +5 -5
  217. package/src/interface/resources/cadence.ts +1 -1
  218. package/src/interface/system/access.ts +1 -1
  219. package/src/interface/system/body.ts +9 -7
  220. package/src/interface/system/check.ts +22 -8
  221. package/src/interface/system/commands.ts +18 -4
  222. package/src/interface/system/create.test.ts +13 -13
  223. package/src/interface/system/create.ts +15 -10
  224. package/src/interface/system/declaration.ts +9 -2
  225. package/src/interface/system/lists.type-test.ts +1 -1
  226. package/src/interface/system/optional.type-test.ts +1 -1
  227. package/src/interface/system/shared.type-test.ts +1 -1
  228. package/src/interface/system/struct.ts +2 -2
  229. package/src/interface/system/system.type-test.ts +26 -20
  230. package/src/interface/system/tables.ts +21 -0
  231. package/src/interface/system/up.type-test.ts +3 -3
  232. package/src/interface/system/values-of.ts +4 -4
  233. package/src/interface/system/values.ts +5 -5
  234. package/src/interface/thread/thread.type-test.ts +1 -1
  235. package/src/interface/trait/trait.type-test.ts +4 -4
  236. package/src/interface/trait/types.ts +4 -4
  237. package/src/interface/world/create.ts +3 -7
  238. package/src/interface/world/declarations.ts +2 -2
  239. package/src/interface/world/index.ts +2 -2
  240. package/src/interface/world/join.ts +2 -10
  241. package/src/interface/world/loop.type-test.ts +6 -6
  242. package/src/interface/world/run.type-test.ts +3 -3
  243. package/src/interface/world/table/index.ts +19 -0
  244. package/src/interface/world/table/table.ts +12 -0
  245. package/src/interface/world/world.ts +10 -10
  246. package/src/observe/entity.ts +2 -2
  247. package/src/observe/members.ts +3 -3
  248. package/src/observe/query.ts +1 -1
  249. package/src/observe/resource.ts +2 -2
  250. package/src/observe/select.ts +5 -5
  251. package/src/observe/values.ts +2 -2
  252. package/src/observe/world-state.ts +3 -3
  253. package/src/perftest/benchmarks.ts +1 -1
  254. package/src/perftest/indexes.ts +3 -3
  255. package/src/perftest/loop.ts +1 -1
  256. package/src/perftest/observer.ts +4 -4
  257. package/src/perftest/reads.ts +2 -2
  258. package/src/perftest/remote.ts +5 -5
  259. package/src/perftest/strings.ts +1 -1
  260. package/src/perftest/suite.ts +1 -1
  261. package/src/world.test.ts +2 -2
  262. package/src/world.ts +32 -0
@@ -6,8 +6,8 @@ import type { Resource } from '../resource/resource.js';
6
6
  import type { Comparison } from '../world/filter.js';
7
7
  import type { Listed, Property } from './property.js';
8
8
 
9
- export type ComponentValues = { readonly [K in Component.Key]: Component.Value<K> };
10
- export type ResourceValues = { readonly [K in Resource.Key]: Resource.Value<K> };
9
+ export type ComponentValues = { readonly [K in Component.Key]: Component<K> };
10
+ export type ResourceValues = { readonly [K in Resource.Key]: Resource<K> };
11
11
 
12
12
  /** `Read` values are read-only, `Write` values writable. */
13
13
  export type Values<Read, Write, Keys extends PropertyKey, Types> =
@@ -21,7 +21,7 @@ export type KeyOf<D> = D extends { readonly key: infer K extends readonly Compon
21
21
  export type HeldBy<D> = KeyOf<D>[number] | Listed<Property<D, "components">, "with">;
22
22
 
23
23
  /** The key's values, in key order. */
24
- type KeyValues<K extends readonly Component.Key[]> = { readonly [I in keyof K]: Component.Value<K[I] & Component.Key> };
24
+ type KeyValues<K extends readonly Component.Key[]> = { readonly [I in keyof K]: Component<K[I] & Component.Key> };
25
25
 
26
26
  /** A prefix of the key, possibly empty, whose last part may be a comparison. */
27
27
  type Prefix<V extends readonly unknown[]> = V extends readonly [infer First, ...infer Rest]
@@ -29,7 +29,7 @@ type Prefix<V extends readonly unknown[]> = V extends readonly [infer First, ...
29
29
  : readonly [];
30
30
 
31
31
  /** A row an index lookup gives: its entity and the values of what every entity the index holds has, read-only. */
32
- type IndexRow<D> = { readonly entity: Entity } & { readonly [K in HeldBy<D> & Component.Key]: Component.Value<K> };
32
+ type IndexRow<D> = { readonly entity: Entity } & { readonly [K in HeldBy<D> & Component.Key]: Component<K> };
33
33
 
34
34
  /**
35
35
  * The rows a lookup found, in the index's order: by entity for a hash index, by key and then entity for a sorted one.
@@ -65,7 +65,7 @@ type IndexLookup<D> =
65
65
  type EntityRow<L> = {
66
66
  readonly [K in (Listed<L, "with"> & Component.Key) | (Exclude<Listed<L, "optional">, Listed<L, "with">> & Component.Key) | (L extends { readonly changed: readonly Component.Key[] } ? "changed" : never)]:
67
67
  // Its `optional` components are their values where the entity has them, `undefined` where it doesn't.
68
- K extends Component.Key ? K extends Listed<L, "with"> ? Component.Value<K> : Component.Value<K> | undefined : boolean
68
+ K extends Component.Key ? K extends Listed<L, "with"> ? Component<K> : Component<K> | undefined : boolean
69
69
  };
70
70
 
71
71
  export type LookupFunction<L> = L extends { readonly index: Index<infer D> }
@@ -55,7 +55,7 @@ declare module '@adobe/ecs' {
55
55
  }
56
56
  }
57
57
 
58
- check<Equal<Component.Value<typeof path>, readonly number[]>>();
58
+ check<Equal<Component<typeof path>, readonly number[]>>();
59
59
  check<Equal<ThreadOf<{ readonly thread: "main" }, string>, never>>();
60
60
  check<Equal<ThreadOf<{ readonly thread: "main" }, "edit" | "view">, never>>();
61
61
  check<Equal<ThreadOf<{ readonly thread: "main" }, readonly string[]>, "main">>();
@@ -16,7 +16,7 @@ const gpuOnly = Symbol("traitTest/gpuOnly");
16
16
  const nonPersistent = Symbol("traitTest/nonPersistent");
17
17
  declare module '@adobe/ecs' {
18
18
  export interface Traits<N> {
19
- readonly [gpuOnly]: N extends Component.Key ? (IsStruct<Component.Value<N>> extends true ? true : never) : never;
19
+ readonly [gpuOnly]: N extends Component.Key ? (IsStruct<Component<N>> extends true ? true : never) : never;
20
20
  readonly [nonPersistent]: N extends Component.Key ? (Components[N] extends { readonly derived: true } ? never : true) : true;
21
21
  }
22
22
  }
@@ -53,15 +53,15 @@ declare module '@adobe/ecs' {
53
53
 
54
54
  // Types filter components by their traits and value types.
55
55
  type Ours = typeof parent | typeof follows | typeof slot | typeof ready | typeof score | typeof link | typeof pair | typeof cache;
56
- check<Equal<Component.Value<typeof parent>, Entity>>();
57
- check<Equal<Component.Value<typeof link>, { readonly to: Entity; readonly weight: number }>>();
56
+ check<Equal<Component<typeof parent>, Entity>>();
57
+ check<Equal<Component<typeof link>, { readonly to: Entity; readonly weight: number }>>();
58
58
  check<Equal<Extract<Component.With<"reference">, Ours>, typeof parent | typeof follows>>();
59
59
  check<Equal<Extract<Component.With<"reference", "owner">, Ours>, typeof parent>>();
60
60
  check<Equal<Extract<Derived, Ours>, typeof slot>>();
61
61
  check<Equal<Extract<Component.With<typeof gpuOnly>, Ours>, typeof pair>>();
62
62
  type Persisted = Exclude<Essential, Component.With<typeof nonPersistent>>;
63
63
  check<Equal<Extract<Persisted, Ours>, Exclude<Ours, typeof slot | typeof cache>>>();
64
- check<Equal<Resource.Value<typeof time>, number>>();
64
+ check<Equal<Resource<typeof time>, number>>();
65
65
 
66
66
  // Commands add and remove only essential components.
67
67
  export const issue = (commands: Commands, entity: Entity): void => {
@@ -9,7 +9,7 @@ import type { IsComparable, IsString, IsStruct } from '../schema/is-struct.js';
9
9
  import type { Thread } from '../thread/thread.js';
10
10
 
11
11
  /** The value type of the component or resource `N`. */
12
- type ValueOf<N> = N extends Component.Key ? Component.Value<N> : N extends Resource.Key ? Resource.Value<N> : never;
12
+ type ValueOf<N> = N extends Component.Key ? Component<N> : N extends Resource.Key ? Resource<N> : never;
13
13
 
14
14
  /**
15
15
  * Whether each component's and resource's value is a struct, `"string"` for a string, computed once so a check is a
@@ -39,14 +39,14 @@ export interface Traits<N extends Component.Key | Resource.Key> {
39
39
  * component. Not on a derived component, whose target only a command could set.
40
40
  */
41
41
  readonly reference: N extends Component.Key
42
- ? Components[N] extends { readonly derived: true } | { readonly shared: true } ? never : [Component.Value<N>] extends [Entity] ? "owner" | "weak" : never
42
+ ? Components[N] extends { readonly derived: true } | { readonly shared: true } ? never : [Component<N>] extends [Entity] ? "owner" | "weak" : never
43
43
  : never;
44
44
  /**
45
45
  * On a resource, the operator systems reduce into it with: each run that a contributor runs in starts it at the
46
46
  * operator's identity and leaves it holding the fold of every contribution. Booleans fold bitwise.
47
47
  */
48
48
  readonly reduce: N extends Resource.Key
49
- ? [Resource.Value<N>] extends [boolean] ? "&" | "|" | "^" : Structs[N] extends true ? Reduction : never
49
+ ? [Resource<N>] extends [boolean] ? "&" | "|" | "^" : Structs[N] extends true ? Reduction : never
50
50
  : never;
51
51
  /**
52
52
  * The logical thread an object lives on, `"world"` without it. Not on a struct or a string, which live in shared
@@ -64,6 +64,6 @@ export interface Traits<N extends Component.Key | Resource.Key> {
64
64
  * reference, and it has no thread: every thread reads it.
65
65
  */
66
66
  readonly shared: N extends Component.Key
67
- ? Components[N] extends { readonly derived: true } | { readonly reference: unknown } ? never : IsComparable<Component.Value<N>> extends true ? true : never
67
+ ? Components[N] extends { readonly derived: true } | { readonly reference: unknown } ? never : IsComparable<Component<N>> extends true ? true : never
68
68
  : never;
69
69
  }
@@ -5,15 +5,11 @@ import type { InvalidDeclarations } from './declarations.js';
5
5
  import type { World } from './world.js';
6
6
 
7
7
  /** Values resources start at in place of their defaults: any but those only the world writes. */
8
- export type InitialResources = { readonly [K in Exclude<Resource.Key, WorldWritten>]?: Resource.Value<K> };
8
+ export type InitialResources = { readonly [K in Exclude<Resource.Key, WorldWritten>]?: Resource<K> };
9
9
 
10
10
  /**
11
- * Creates a world on this thread, synchronously, with resources starting at the given values in place of their
12
- * defaults. This thread is its `"world"` thread for the world's life: it runs the sync points, the ticks and the GPU
13
- * device, and fills every logical thread no joined thread claims. Keys are the resources' symbols, built-in ones
14
- * included (`{ [workers]: 0 }`); string keys are never a resource's, so they're ignored. Throws for a symbol that isn't
15
- * a resource, or is one only the world writes. While a declaration's trait or default doesn't hold, each call fails to
16
- * compile, once, naming each such key, its members and what's wrong with them.
11
+ * The type of `World.create`.
12
+ * @inline
17
13
  */
18
14
  export type Create = (
19
15
  // Unknown while every declaration holds; else what a call's `this` can't be, so the call reports it, printed whole.
@@ -30,5 +30,5 @@ type Reported<K, Members extends PropertyKey> = [Members] extends [never] ? neve
30
30
  * `World.create` reports these.
31
31
  */
32
32
  export type InvalidDeclarations =
33
- | { readonly [K in Component.Key]: Reported<K, Invalid<K, Components[K], Component.Value<K>>> }[Component.Key]
34
- | { readonly [K in Resource.Key]: Reported<K, Invalid<K, Resources[K], Resource.Value<K>>> }[Resource.Key];
33
+ | { readonly [K in Component.Key]: Reported<K, Invalid<K, Components[K], Component<K>>> }[Component.Key]
34
+ | { readonly [K in Resource.Key]: Reported<K, Invalid<K, Resources[K], Resource<K>>> }[Resource.Key];
@@ -1,3 +1,3 @@
1
1
  // © 2026 Adobe. MIT License. See /LICENSE for details.
2
- // The `World` namespace's members: none, since a consumer declares nothing more with it.
3
- export {};
2
+ // The `World` namespace's types.
3
+ export type { Table } from './table/table.js';
@@ -3,15 +3,7 @@ import type { Thread } from '../thread/thread.js';
3
3
  import type { World } from './world.js';
4
4
 
5
5
  /**
6
- * Joins, from another thread, a world that `share` let join through the other end of `port`, claiming the logical
7
- * `threads` this thread fills: their objects live here, and the systems and finalizers reading them run here. Resolves,
8
- * once the world accepted the claim, to the same world: its `run` runs systems there, and its `add` and `remove` take
9
- * observer systems, which run here after the world's sync points. Add them before awaiting anything else, so the
10
- * world's `share` resolves with them in place. Its `dispose` disconnects this thread. Rejects with an `Error` saying
11
- * why it didn't join: the world refused the claim, was disposed, or its thread ended first, as the platform reports it:
12
- * the world's `Worker` failing to start or throwing first, a port closed, as in node, or, in a browser, the world's
13
- * thread ending once it was shared through a port this thread listened on. A browser world's worker that the page ended
14
- * before this thread heard from it isn't reported, so the join stays pending. Rejects too where memory can't be shared,
15
- * as without cross-origin isolation.
6
+ * The type of `World.join`.
7
+ * @inline
16
8
  */
17
9
  export type Join = (port: Parameters<World["share"]>[0], options?: { readonly threads?: readonly Exclude<Thread, "world">[] }) => Promise<World>;
@@ -25,14 +25,14 @@ world.remove(move);
25
25
  void removed;
26
26
 
27
27
  // Built-in resources.
28
- check<Equal<Resource.Value<typeof gpuDevice>, GPUDevice | null>>();
29
- check<Equal<Resource.Value<typeof workers>, number | null>>();
28
+ check<Equal<Resource<typeof gpuDevice>, GPUDevice | null>>();
29
+ check<Equal<Resource<typeof workers>, number | null>>();
30
30
  // null is the platform's choice of pool size.
31
31
  export const platformPool: World = create({ [workers]: null });
32
- check<Equal<Resource.Value<typeof always>, boolean>>();
33
- check<Equal<Resource.Value<typeof wake>, number>>();
34
- check<Equal<Resource.Value<typeof clock>, { readonly now: number; readonly delta: number; readonly tick: number }>>();
35
- check<Equal<Resource.Value<typeof cadence>, { readonly kind: "frame" } | { readonly kind: "fixed"; readonly step: number; readonly maxSteps?: number }>>();
32
+ check<Equal<Resource<typeof always>, boolean>>();
33
+ check<Equal<Resource<typeof wake>, number>>();
34
+ check<Equal<Resource<typeof clock>, { readonly now: number; readonly delta: number; readonly tick: number }>>();
35
+ check<Equal<Resource<typeof cadence>, { readonly kind: "frame" } | { readonly kind: "fixed"; readonly step: number; readonly maxSteps?: number }>>();
36
36
  // Built-in resources are symbols, so worlds start them at other values through their imported keys.
37
37
  check<Equal<[typeof gpuDevice, typeof workers, typeof cadence, typeof always, typeof wake, typeof clock] extends readonly symbol[] ? true : false, true>>();
38
38
  // @ts-expect-error a resource key is its imported symbol, never its description
@@ -19,7 +19,7 @@ declare module '@adobe/ecs' {
19
19
  }
20
20
 
21
21
  // A run resolves to its per-run body's value: a one-off read is an observer system returning it.
22
- const count = System.create({ observer: true }, ({ resources }) => resources[frames]);
22
+ const count = System.create({ readonly: true }, ({ resources }) => resources[frames]);
23
23
  check<Equal<typeof count, System<undefined, number>>>();
24
24
  const counted: Promise<number> = world.run(count);
25
25
  // @ts-expect-error a run of it resolves to a number
@@ -32,7 +32,7 @@ const scaled = System.create({}, ({ resources }, input: { readonly by: number })
32
32
  const scaledValue: Promise<{ scaled: number }> = world.run(scaled, { by: 2 });
33
33
 
34
34
  // A body that may be skipped, as one whose conditions or resource change filters can fail, may give undefined.
35
- const changedFrames = System.create({ observer: true, resources: { changed: [frames] } }, ({ resources }) => resources[frames]);
35
+ const changedFrames = System.create({ readonly: true, resources: { changed: [frames] } }, ({ resources }) => resources[frames]);
36
36
  check<Equal<typeof changedFrames, System<undefined, number | undefined>>>();
37
37
  const whileDevice = System.create({ resources: { is: [gpuDevice] } }, () => "drawn");
38
38
  const drawn: Promise<string | undefined> = world.run(whileDevice);
@@ -68,7 +68,7 @@ void [counted, notText, nextValue, scaledValue, drawn, rows, composite, input, n
68
68
  // @ts-expect-error a body returns no promise
69
69
  System.create(() => Promise.resolve(1));
70
70
  // @ts-expect-error a body returns no promise
71
- System.create({ observer: true }, () => Promise.resolve(1));
71
+ System.create({ readonly: true }, () => Promise.resolve(1));
72
72
  // @ts-expect-error a body returns no promise, a row system's neither
73
73
  System.create({ components: { with: [position] } }, () => Promise.resolve());
74
74
  // @ts-expect-error a body returns no promise, a render system's neither
@@ -0,0 +1,19 @@
1
+ // © 2026 Adobe. MIT License. See /LICENSE for details.
2
+
3
+ /**
4
+ * One component's values in a table, copies taken as a readonly system reads `tables`:
5
+ * - `bytes`: a struct's or number's, `stride` bytes per row in the world's layout for it, which is a function of the
6
+ * component's schema alone;
7
+ * - `values`: a string's or an object's, one per row;
8
+ * - `value`: one value every row holds, for a shared component or one whose schema is a constant.
9
+ */
10
+ export type Column =
11
+ | { readonly kind: "bytes"; readonly bytes: Uint8Array; readonly stride: number }
12
+ | { readonly kind: "values"; readonly values: readonly unknown[] }
13
+ | { readonly kind: "value"; readonly value: unknown };
14
+
15
+ /**
16
+ * What `commands.spawnTables` spawned: each table's new entities in its row order, `Entity.none` for a row it didn't
17
+ * spawn, and how many rows it didn't, those owned by an entity outside the tables.
18
+ */
19
+ export type Spawned = { readonly entities: readonly Float64Array[]; readonly dropped: number };
@@ -0,0 +1,12 @@
1
+ // © 2026 Adobe. MIT License. See /LICENSE for details.
2
+ import type { Component } from '../../component/component.js';
3
+ import type { Column } from './index.js';
4
+
5
+ /** The rows of one archetype: their entities in row order, and a column for each component asked for that it holds. */
6
+ export type Table = {
7
+ readonly count: number;
8
+ readonly entities: Float64Array;
9
+ readonly columns: { readonly [K in Component.Key]?: Column };
10
+ };
11
+
12
+ export type * as Table from './index.js';
@@ -3,23 +3,23 @@ import type { Input } from '../system/input.js';
3
3
  import type { System } from '../system/system.js';
4
4
 
5
5
  /**
6
- * A world. Systems read and change it; observer systems read it after each run's and tick's sync point. Every member's
6
+ * A world. Systems read and change it; readonly systems read it after each run's and tick's sync point. Every member's
7
7
  * type is named from the package root, so declarations a consumer emits for its results name no internal module.
8
8
  */
9
9
  export type World = {
10
10
  /**
11
11
  * The one way to change state. Runs are sequential in call order; physically, any that don't conflict overlap. Each
12
- * runs a system or composite, ending in a sync point, then observer systems, the run's and those added, and
12
+ * runs a system or composite, ending in a sync point, then readonly systems, the run's and those added, and
13
13
  * resolves to what a per-run body returns: a system without components resolves to its body's value, or
14
14
  * `undefined` when its body was skipped, and any other system or composite to nothing. So a one-off read is a run
15
- * of an observer system returning what it read; one that runs on a joined thread, as it reads objects there, runs
16
- * there before the run resolves, to its value as structured clone. A run of observer systems alone runs them once
15
+ * of a readonly system returning what it read; one that runs on a joined thread, as it reads objects there, runs
16
+ * there before the run resolves, to its value as structured clone. A run of readonly systems alone runs them once
17
17
  * after an empty sync point, and doesn't wake the loop.
18
18
  *
19
19
  * When a system or finalizer of the run fails, later tiers are skipped, the sync point still applies what was done,
20
- * and once its observer systems ran the run rejects with an `Error` naming each failure, its system's label and id,
20
+ * and once its readonly systems ran the run rejects with an `Error` naming each failure, its system's label and id,
21
21
  * message and cause. It rejects too when the run can't happen or finish: registration fails, the world is disposed,
22
- * its GPU device is lost, or its sync point can't apply a command's value. What fails after it, an observer system
22
+ * its GPU device is lost, or its sync point can't apply a command's value. What fails after it, a readonly system
23
23
  * added or GPU work, is reported out of band, as ticks' failures are (see `add`).
24
24
  */
25
25
  run<I, R>(system: System<I, R>, ...input: Input<NoInfer<I>>): Promise<R>;
@@ -27,9 +27,9 @@ export type World = {
27
27
  * Adds a system to every tick, from the next one on, ordered with those already added by its constraints, as a
28
28
  * composite's members are. A tick runs on a beat of the `cadence` resource where `always` is set, `wake` is due or
29
29
  * a run arrived since the last tick, and only while some system is added. Throws for a system with no ordering path
30
- * to one already added that conflicts with it. An observer system runs after every run's and tick's sync point
30
+ * to one already added that conflicts with it. A readonly system runs after every run's and tick's sync point
31
31
  * instead. It never conflicts and doesn't count as an added system for ticking. On a joined thread `add` takes only
32
- * observer systems, whose keys need ids: each runs on that thread after the world's sync points, once for the
32
+ * readonly systems, whose keys need ids: each runs on that thread after the world's sync points, once for the
33
33
  * newest when the thread fell behind, reading structs and the objects of the threads it fills as of one sync point.
34
34
  *
35
35
  * What added systems throw, and what fails in ticks, is reported out of band on the world's thread, as an `Error`
@@ -43,14 +43,14 @@ export type World = {
43
43
  * released. A system added both alone and within an added composite stays until both are removed; constraints
44
44
  * naming a removed system are ignored. Removing a value that isn't added does nothing. Throws, removing nothing,
45
45
  * when the systems left would conflict with no ordering path between them, as `add` does. On a joined thread it
46
- * takes only observer systems.
46
+ * takes only readonly systems.
47
47
  */
48
48
  remove(system: System<void>): void;
49
49
  /**
50
50
  * Lets another thread join this world through `port`, one end of a channel to it, of the browser or node: a
51
51
  * `MessagePort`, a `Worker`, or a worker's own scope, `self` or node's `parentPort`. That thread joins through the
52
52
  * other end, claiming the logical threads it fills. Resolves once it has joined: the threads it claims are its own,
53
- * and the observer systems it added as its join resolved, before awaiting anything else, are added, so a run
53
+ * and the readonly systems it added as its join resolved, before awaiting anything else, are added, so a run
54
54
  * started afterwards runs on it and reaches them; one it adds later reaches the runs after its add arrived.
55
55
  * Rejects with an `Error` saying why it didn't join: the world refused its claim, as of a thread claimed twice, the
56
56
  * world was disposed, the port is shared already, or that thread ended first, as the platform reports it: a
@@ -129,14 +129,14 @@ const createShape = (state: WorldState, byShape: Map<string, EntityShape>, id: s
129
129
  let finders: Finders | null = null;
130
130
  let source: object | null = null;
131
131
  const system = optional.length === 0
132
- ? System.create(labelled({ observer: true, lookup: { presence: { with: required, changed: required }, values: { with: required }, members: { index: membersOf(required), changed: required } } }, name, { lookup: { values: required } }), ({ lookup }) => {
132
+ ? System.create(labelled({ readonly: true, lookup: { presence: { with: required, changed: required }, values: { with: required }, members: { index: membersOf(required), changed: required } } }, name, { lookup: { values: required } }), ({ lookup }) => {
133
133
  if (source !== lookup || finders === null) {
134
134
  source = lookup;
135
135
  finders = { presence: lookup.presence, values: lookup.values, optional: noOptional };
136
136
  }
137
137
  pass(lookup.members().changed, finders);
138
138
  })
139
- : System.create(labelled({ observer: true, lookup: optionalLookups(required, optional) }, name, { lookup: optionalReads(required, optional) }), ({ lookup }) => {
139
+ : System.create(labelled({ readonly: true, lookup: optionalLookups(required, optional) }, name, { lookup: optionalReads(required, optional) }), ({ lookup }) => {
140
140
  if (source !== lookup || finders === null) {
141
141
  source = lookup;
142
142
  finders = { presence: lookup.presence, values: lookup.values, optional: (index, entity) => lookup[index](entity) };
@@ -5,7 +5,7 @@ import type { Observe } from './observe.js';
5
5
  import { observeCount, observeSelect } from './select.js';
6
6
  import type { Query } from './query.js';
7
7
  import { observeResource } from './resource.js';
8
- import type { ReadonlyResourceValue, ReadonlyValue } from './values.js';
8
+ import type { ReadonlyResourceType, ReadonlyType } from './values.js';
9
9
 
10
10
  export { toPromise } from './to-promise.js';
11
11
  export type { Query } from './query.js';
@@ -14,7 +14,7 @@ export type { Query } from './query.js';
14
14
  * A resource's value, then a new one after each run or tick that changed it: one whose sync point stamped it, even with
15
15
  * the same value, a reduced resource when its fold differs.
16
16
  */
17
- export const resource = <R extends Resource.Key>(world: World, resource: R): Observe<ReadonlyResourceValue<R>> =>
17
+ export const resource = <R extends Resource.Key>(world: World, resource: R): Observe<ReadonlyResourceType<R>> =>
18
18
  observeResource(world, resource);
19
19
 
20
20
  /**
@@ -27,7 +27,7 @@ export const entity = <const R extends readonly Component.Key[] = [], const O ex
27
27
  world: World,
28
28
  entity: Entity,
29
29
  components: { readonly required?: R; readonly optional?: O },
30
- ): Observe<({ readonly [K in keyof Pick<Components, R[number]>]: ReadonlyValue<K> } & { readonly [K in keyof Pick<Components, O[number]>]?: ReadonlyValue<K> }) | null> =>
30
+ ): Observe<({ readonly [K in keyof Pick<Components, R[number]>]: ReadonlyType<K> } & { readonly [K in keyof Pick<Components, O[number]>]?: ReadonlyType<K> }) | null> =>
31
31
  observeEntity(world, entity, components);
32
32
 
33
33
  /**
@@ -10,7 +10,7 @@ type Comparison<T> = {
10
10
  readonly ">="?: T;
11
11
  };
12
12
 
13
- type ValuesOf<C extends readonly Component.Key[]> = { readonly [K in C[number]]: Component.Value<K> };
13
+ type ValuesOf<C extends readonly Component.Key[]> = { readonly [K in C[number]]: Component<K> };
14
14
 
15
15
  /**
16
16
  * Entities that have every component in `required`, every entity but the resource entity without it, and none in
@@ -31,14 +31,14 @@ const createShape = (state: WorldState, byKey: Map<Resource.Key, ResourceShape>,
31
31
  const label = `Observe.resource(${key.description ?? "?"})`;
32
32
  // On a joined thread, first values come once a run of this system resolved, never in its pass: none to skip.
33
33
  const { joined } = state;
34
- const notifier = System.create(labelled({ observer: true, resources: { changed: [key] } }, label, { resources: [key] }), ({ resources }) => {
34
+ const notifier = System.create(labelled({ readonly: true, resources: { changed: [key] } }, label, { resources: [key] }), ({ resources }) => {
35
35
  passed(state);
36
36
  entry.value = resources[key];
37
37
  entry.valid = true;
38
38
  if (entry.stopped > 0) sweepSubscribers(entry);
39
39
  throwFailed(give(entry, 0, true, state.pass, joined ? -1 : state.pass, none));
40
40
  });
41
- const reader = System.create(labelled({ observer: true }, label, { resources: [key] }), ({ resources }) => {
41
+ const reader = System.create(labelled({ readonly: true }, label, { resources: [key] }), ({ resources }) => {
42
42
  const through = shape.called.shift() ?? 0;
43
43
  entry.value = resources[key];
44
44
  entry.valid = true;
@@ -161,7 +161,7 @@ const rangeOf = (condition: unknown): Range => {
161
161
  return bounds.length === 0 ? unbounded : { range, bounds, exact };
162
162
  };
163
163
 
164
- type Value = Component.Value<Component.Key>;
164
+ type Value = Component<Component.Key>;
165
165
 
166
166
  /** A value or comparison a sorted index on one key part looks up by. */
167
167
  type Bound = Value | { readonly "<="?: Value; readonly ">="?: Value; readonly "=="?: Value };
@@ -403,16 +403,16 @@ const createShape = (state: WorldState, byShape: Map<string, QueryShape>, id: st
403
403
  };
404
404
 
405
405
  const tracker = ordered !== null
406
- ? System.create(labelled({ observer: true, lookup: { list: { index: ordered, changed: reads } } }, name, { lookup: { list: reads } }), ({ lookup }) => {
406
+ ? System.create(labelled({ readonly: true, lookup: { list: { index: ordered, changed: reads } } }, name, { lookup: { list: reads } }), ({ lookup }) => {
407
407
  track(lookup.list(), null, fromSorted);
408
408
  })
409
409
  : byRange !== null
410
- ? System.create(labelled({ observer: true, lookup: { list: { index: byRange, changed: reads } } }, name, { lookup: { list: reads } }), ({ lookup }) => {
410
+ ? System.create(labelled({ readonly: true, lookup: { list: { index: byRange, changed: reads } } }, name, { lookup: { list: reads } }), ({ lookup }) => {
411
411
  // A range is of a `where` condition on the index's key, which the query's type checked against its
412
412
  // values.
413
413
  track(null, entry => ownRange(entry, range => lookup.list(range as Parameters<typeof lookup.list>[0]), () => lookup.list()), fromSorted);
414
414
  })
415
- : System.create(labelled({ observer: true, lookup: { list: { index: keylessOf(has, not), changed: reads } } }, name, { lookup: { list: reads } }), ({ lookup }) => {
415
+ : System.create(labelled({ readonly: true, lookup: { list: { index: keylessOf(has, not), changed: reads } } }, name, { lookup: { list: reads } }), ({ lookup }) => {
416
416
  track(lookup.list(), null, fromKeyless);
417
417
  });
418
418
 
@@ -466,7 +466,7 @@ const createShape = (state: WorldState, byShape: Map<string, QueryShape>, id: st
466
466
  for (const entry of scan.entries) entry.gather.start();
467
467
  accept = acceptOf(scan.entries);
468
468
  };
469
- const scanner = System.create(labelled({ observer: true, components: { with: [...reads, ...required.filter(key => !reads.includes(key))], not } }, name, { components: reads }), row => {
469
+ const scanner = System.create(labelled({ readonly: true, components: { with: [...reads, ...required.filter(key => !reads.includes(key))], not } }, name, { components: reads }), row => {
470
470
  if (accept === null) start();
471
471
  if (direct === 0) {
472
472
  accept?.(row);
@@ -4,7 +4,7 @@ import type { Component, Resource } from '../interface/index.js';
4
4
  type Primitive = string | number | boolean | bigint | symbol | null | undefined;
5
5
 
6
6
  /** Component `K`'s value as observers give it: read-only, with branded primitives such as `Entity` as they are. */
7
- export type ReadonlyValue<K extends Component.Key> = Component.Value<K> extends Primitive ? Component.Value<K> : Readonly<Component.Value<K>>;
7
+ export type ReadonlyType<K extends Component.Key> = Component<K> extends Primitive ? Component<K> : Readonly<Component<K>>;
8
8
 
9
9
  /** Resource `K`'s value as observers give it. */
10
- export type ReadonlyResourceValue<K extends Resource.Key> = Resource.Value<K> extends Primitive ? Resource.Value<K> : Readonly<Resource.Value<K>>;
10
+ export type ReadonlyResourceType<K extends Resource.Key> = Resource<K> extends Primitive ? Resource<K> : Readonly<Resource<K>>;
@@ -116,7 +116,7 @@ const ignore = (): void => {
116
116
  };
117
117
 
118
118
  /** Runs nothing: a run of it resolves while its world lives. */
119
- const alive = System.create(labelled({ observer: true }, "Observe/alive"), () => {});
119
+ const alive = System.create(labelled({ readonly: true }, "Observe/alive"), () => {});
120
120
 
121
121
  /**
122
122
  * What a rejected run of the factories' own does: nothing for a disposed world, whose first values never come, and for
@@ -232,7 +232,7 @@ export const stateOf = (world: World): WorldState => {
232
232
  deliveries: [],
233
233
  idle: [],
234
234
  rejected: rejectedOf(world),
235
- deliver: System.create(labelled({ observer: true }, "Observe/deliver"), () => {
235
+ deliver: System.create(labelled({ readonly: true }, "Observe/deliver"), () => {
236
236
  const delivery = created.deliveries.shift();
237
237
  if (delivery === undefined) return;
238
238
  created.delivered = delivery.batch;
@@ -243,7 +243,7 @@ export const stateOf = (world: World): WorldState => {
243
243
  states.set(world, created);
244
244
  if (joined) return created;
245
245
  // Added before any shape's system, so in each pass it counts the pass before they run.
246
- world.add(System.create(labelled({ observer: true }, "Observe/maintain"), () => {
246
+ world.add(System.create(labelled({ readonly: true }, "Observe/maintain"), () => {
247
247
  created.pass++;
248
248
  if (created.idle.length > 0) sweepShapes(created);
249
249
  }));
@@ -505,7 +505,7 @@ export const benchmarks: readonly Benchmark[] = [
505
505
  run: async () => {
506
506
  const { world, roots } = await filteredForest();
507
507
  const found: { child: Entity | null } = { child: null };
508
- await world.run(System.create({ observer: true, components: { with: [hierarchyParent] } }, row => {
508
+ await world.run(System.create({ readonly: true, components: { with: [hierarchyParent] } }, row => {
509
509
  if (found.child === null && row[hierarchyParent] === roots[0]) found.child = row.entity;
510
510
  }));
511
511
  const { child } = found;
@@ -307,13 +307,13 @@ const seedFlags = System.create({}, ({ commands }) => {
307
307
  for (let i = 0; i < flagged; i++) commands.spawn([flag])({ [flag]: i % 2 === 0 });
308
308
  });
309
309
  /** A run of observer systems alone, which passes every one added. */
310
- const pass = System.create({ observer: true }, () => {});
310
+ const pass = System.create({ readonly: true }, () => {});
311
311
  /** A count of each bucket, written only when the index's entries changed: by `changed: true`, or by its lists' `changed`. */
312
312
  const countsWhenChanged = (filtered: boolean): System => filtered
313
- ? System.create({ observer: true, lookup: { byFlag: { index: byFlag, changed: true } } }, ({ lookup }) => {
313
+ ? System.create({ readonly: true, lookup: { byFlag: { index: byFlag, changed: true } } }, ({ lookup }) => {
314
314
  found += lookup.byFlag(false).length + lookup.byFlag(true).length;
315
315
  })
316
- : System.create({ observer: true, lookup: { byFlag: { index: byFlag } } }, ({ lookup }) => {
316
+ : System.create({ readonly: true, lookup: { byFlag: { index: byFlag } } }, ({ lookup }) => {
317
317
  const off = lookup.byFlag(false);
318
318
  const on = lookup.byFlag(true);
319
319
  if (!off.changed && !on.changed) return;
@@ -12,7 +12,7 @@ export const loopTicks = 10_000;
12
12
  export const observerIdles = 100;
13
13
 
14
14
  /** Observer systems no entity matches, each run after every tick. */
15
- const idleObserver = Array.from({ length: observerIdles }, (_, i) => System.create({ observer: true, components: { with: [unused] } }, () => {}));
15
+ const idleObserver = Array.from({ length: observerIdles }, (_, i) => System.create({ readonly: true, components: { with: [unused] } }, () => {}));
16
16
 
17
17
  /**
18
18
  * The fastest of `stretches` stretches of `loopTicks` ticks with nothing changed, after one to warm up: a world with
@@ -14,14 +14,14 @@ import type { World } from "../interface/world/world.js";
14
14
  * first call only starts the stretch that warms up.
15
15
  */
16
16
  export const eachTick = (world: World, notify: () => void): (() => void) => {
17
- const counter = System.create({ observer: true, resources: { changed: [clock] } }, () => { notify(); });
17
+ const counter = System.create({ readonly: true, resources: { changed: [clock] } }, () => { notify(); });
18
18
  world.add(counter);
19
19
  return () => world.remove(counter);
20
20
  };
21
21
 
22
22
  /** The clock as an observer run last read it. */
23
23
  const read = { tick: 0, now: 0 };
24
- const readClock = System.create({ observer: true }, ({ resources }) => {
24
+ const readClock = System.create({ readonly: true }, ({ resources }) => {
25
25
  read.tick = resources[clock].tick;
26
26
  read.now = resources[clock].now;
27
27
  });
@@ -36,7 +36,7 @@ export const ticksAfter = async (world: World, count: number): Promise<void> =>
36
36
  let { tick, now } = read;
37
37
  let seen = 0;
38
38
  await new Promise<void>(resolve => {
39
- const counter = System.create({ observer: true }, ({ resources }) => {
39
+ const counter = System.create({ readonly: true }, ({ resources }) => {
40
40
  const current = resources[clock];
41
41
  if (current.tick === tick && current.now === now) return;
42
42
  tick = current.tick;
@@ -52,7 +52,7 @@ export const ticksAfter = async (world: World, count: number): Promise<void> =>
52
52
  /** The entities with every component of `has` and none of `not`, in storage order, read by an observer run. */
53
53
  export const entitiesWith = async (world: World, has: readonly Component.Key[], not: readonly Component.Key[] = []): Promise<Entity[]> => {
54
54
  const found: Entity[] = [];
55
- await world.run(System.create({ observer: true, components: { with: [...has], not } }, row => { found.push(row.entity); }));
55
+ await world.run(System.create({ readonly: true, components: { with: [...has], not } }, row => { found.push(row.entity); }));
56
56
  return found;
57
57
  };
58
58
 
@@ -78,7 +78,7 @@ const lookups = async (system: System): Promise<{ readonly best: number; readonl
78
78
  /** Every entity a seeded world holds. */
79
79
  const entitiesOf = async (world: World): Promise<readonly Entity[]> => {
80
80
  const found: Entity[] = [];
81
- await world.run(System.create({ observer: true, components: { with: [value] } }, row => { found.push(row.entity); }));
81
+ await world.run(System.create({ readonly: true, components: { with: [value] } }, row => { found.push(row.entity); }));
82
82
  return found;
83
83
  };
84
84
 
@@ -124,7 +124,7 @@ export const readBenchmarks: readonly Benchmark[] = [
124
124
  run: async () => {
125
125
  const world = await seeded(10_000);
126
126
  copied = 0;
127
- const best = await fastest(() => world.run(System.create({ observer: true }, ({ resources }) => { copied = resources[level]; })), 300);
127
+ const best = await fastest(() => world.run(System.create({ readonly: true }, ({ resources }) => { copied = resources[level]; })), 300);
128
128
  check(copied === 3, "read run observer: wrong value");
129
129
  await world.dispose();
130
130
  return best;
@@ -49,7 +49,7 @@ export const reorder = System.create([flip, reverse]);
49
49
  export const observerSeen = { last: 0, notified: 0 };
50
50
 
51
51
  /** On a joined thread, after each sync point that changed it: the observed resource. */
52
- export const observerCounter = System.create({ observer: true, resources: { changed: [counter] } }, ({ resources }) => {
52
+ export const observerCounter = System.create({ readonly: true, resources: { changed: [counter] } }, ({ resources }) => {
53
53
  observerSeen.last = resources[counter];
54
54
  observerSeen.notified++;
55
55
  });
@@ -61,7 +61,7 @@ const sortedKeys = { keys: new Float64Array(0), entities: new Float64Array(0), p
61
61
  * On a joined thread, after each sync point: the entities in `order`, sorted from a scan of the index of every ranked
62
62
  * entity into reused arrays.
63
63
  */
64
- export const observerSelect = System.create({ observer: true, lookup: { all: { index: ranked } } }, ({ lookup }) => {
64
+ export const observerSelect = System.create({ readonly: true, lookup: { all: { index: ranked } } }, ({ lookup }) => {
65
65
  const list = lookup.all();
66
66
  const count = list.length;
67
67
  if (sortedKeys.keys.length < count) {
@@ -99,12 +99,12 @@ export const retext = System.create([count, recaption]);
99
99
  export const reamounted = System.create([count, reamount]);
100
100
 
101
101
  /** On a joined thread, after each sync point: every row's caption, out of its record. */
102
- export const observerCaptions = System.create({ observer: true, components: { with: [caption] } }, row => {
102
+ export const observerCaptions = System.create({ readonly: true, components: { with: [caption] } }, row => {
103
103
  observerSeen.last += row[caption].length;
104
104
  observerSeen.notified++;
105
105
  });
106
106
  /** On a joined thread, after each sync point: every row's amount. */
107
- export const observerAmounts = System.create({ observer: true, components: { with: [amount] } }, row => {
107
+ export const observerAmounts = System.create({ readonly: true, components: { with: [amount] } }, row => {
108
108
  observerSeen.last += row[amount];
109
109
  observerSeen.notified++;
110
110
  });
@@ -129,7 +129,7 @@ const joinedFile = "./joined.js";
129
129
  /** The observed resource, read by an observer run. */
130
130
  const counterOf = async (world: World): Promise<number> => {
131
131
  let value = 0;
132
- await world.run(System.create({ observer: true }, ({ resources }) => { value = resources[counter]; }));
132
+ await world.run(System.create({ readonly: true }, ({ resources }) => { value = resources[counter]; }));
133
133
  return value;
134
134
  };
135
135
 
@@ -80,7 +80,7 @@ const read = (system: System, name: string) => measure(system, async world => {
80
80
  /** Each row's text, as the last write left it. */
81
81
  const written = (name: string) => async (world: World): Promise<void> => {
82
82
  let wrong = 0;
83
- await world.run(System.create({ observer: true, components: { with: [text, boxed] } }, row => {
83
+ await world.run(System.create({ readonly: true, components: { with: [text, boxed] } }, row => {
84
84
  if (row[text] !== row[boxed].text && row[text] !== labelOf(row.entity, round) && row[boxed].text !== labelOf(row.entity, round)) wrong++;
85
85
  }));
86
86
  check(wrong === 0, `${name}: wrong text`);