@oasys/oecs 0.3.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (324) hide show
  1. package/CHANGELOG.md +553 -0
  2. package/README.md +207 -267
  3. package/dist/core/ecs/access_check.d.cts +77 -0
  4. package/dist/core/ecs/access_check.d.ts +77 -0
  5. package/dist/core/ecs/access_check.d.ts.map +1 -0
  6. package/dist/core/ecs/archetype.d.cts +486 -0
  7. package/dist/core/ecs/archetype.d.ts +486 -0
  8. package/dist/core/ecs/archetype.d.ts.map +1 -0
  9. package/dist/core/ecs/archetype_graph.d.cts +96 -0
  10. package/dist/core/ecs/archetype_graph.d.ts +96 -0
  11. package/dist/core/ecs/archetype_graph.d.ts.map +1 -0
  12. package/dist/core/ecs/builtin_relations.d.cts +43 -0
  13. package/dist/core/ecs/builtin_relations.d.ts +43 -0
  14. package/dist/core/ecs/builtin_relations.d.ts.map +1 -0
  15. package/dist/core/ecs/command_log.d.cts +116 -0
  16. package/dist/core/ecs/command_log.d.ts +116 -0
  17. package/dist/core/ecs/command_log.d.ts.map +1 -0
  18. package/dist/core/ecs/component.d.cts +176 -0
  19. package/dist/core/ecs/component.d.ts +176 -0
  20. package/dist/core/ecs/component.d.ts.map +1 -0
  21. package/dist/core/ecs/compute_backend.d.cts +37 -0
  22. package/dist/core/ecs/compute_backend.d.ts +37 -0
  23. package/dist/core/ecs/compute_backend.d.ts.map +1 -0
  24. package/dist/core/ecs/debug_names.d.cts +7 -0
  25. package/dist/core/ecs/debug_names.d.ts +7 -0
  26. package/dist/core/ecs/debug_names.d.ts.map +1 -0
  27. package/dist/core/ecs/deferred_commands.d.cts +55 -0
  28. package/dist/core/ecs/deferred_commands.d.ts +55 -0
  29. package/dist/core/ecs/deferred_commands.d.ts.map +1 -0
  30. package/dist/core/ecs/dispatch_trace.d.cts +93 -0
  31. package/dist/core/ecs/dispatch_trace.d.ts +93 -0
  32. package/dist/core/ecs/dispatch_trace.d.ts.map +1 -0
  33. package/dist/core/ecs/ecs.d.cts +562 -0
  34. package/dist/core/ecs/ecs.d.ts +562 -0
  35. package/dist/core/ecs/ecs.d.ts.map +1 -0
  36. package/dist/core/ecs/ecs_memory.d.cts +179 -0
  37. package/dist/core/ecs/ecs_memory.d.ts +179 -0
  38. package/dist/core/ecs/ecs_memory.d.ts.map +1 -0
  39. package/dist/core/ecs/entity.d.cts +34 -0
  40. package/dist/core/ecs/entity.d.ts +34 -0
  41. package/dist/core/ecs/entity.d.ts.map +1 -0
  42. package/dist/core/ecs/entity_allocator.d.cts +59 -0
  43. package/dist/core/ecs/entity_allocator.d.ts +59 -0
  44. package/dist/core/ecs/entity_allocator.d.ts.map +1 -0
  45. package/dist/core/ecs/event.d.cts +79 -0
  46. package/dist/core/ecs/event.d.ts +79 -0
  47. package/dist/core/ecs/event.d.ts.map +1 -0
  48. package/dist/core/ecs/event_registry.d.cts +22 -0
  49. package/dist/core/ecs/event_registry.d.ts +22 -0
  50. package/dist/core/ecs/event_registry.d.ts.map +1 -0
  51. package/dist/core/ecs/facades.d.cts +158 -0
  52. package/dist/core/ecs/facades.d.ts +158 -0
  53. package/dist/core/ecs/facades.d.ts.map +1 -0
  54. package/dist/core/ecs/frame_stepper.d.cts +58 -0
  55. package/dist/core/ecs/frame_stepper.d.ts +58 -0
  56. package/dist/core/ecs/frame_stepper.d.ts.map +1 -0
  57. package/dist/core/ecs/frame_trace.d.cts +133 -0
  58. package/dist/core/ecs/frame_trace.d.ts +133 -0
  59. package/dist/core/ecs/frame_trace.d.ts.map +1 -0
  60. package/dist/core/ecs/host_commands.d.cts +274 -0
  61. package/dist/core/ecs/host_commands.d.ts +274 -0
  62. package/dist/core/ecs/host_commands.d.ts.map +1 -0
  63. package/dist/core/ecs/index.d.cts +46 -0
  64. package/dist/core/ecs/index.d.ts +46 -0
  65. package/dist/core/ecs/index.d.ts.map +1 -0
  66. package/dist/core/ecs/observer.d.cts +173 -0
  67. package/dist/core/ecs/observer.d.ts +173 -0
  68. package/dist/core/ecs/observer.d.ts.map +1 -0
  69. package/dist/core/ecs/query.d.cts +718 -0
  70. package/dist/core/ecs/query.d.ts +718 -0
  71. package/dist/core/ecs/query.d.ts.map +1 -0
  72. package/dist/core/ecs/ref.d.cts +31 -0
  73. package/dist/core/ecs/ref.d.ts +31 -0
  74. package/dist/core/ecs/ref.d.ts.map +1 -0
  75. package/dist/core/ecs/relation.d.cts +243 -0
  76. package/dist/core/ecs/relation.d.ts +243 -0
  77. package/dist/core/ecs/relation.d.ts.map +1 -0
  78. package/dist/core/ecs/relation_service.d.cts +235 -0
  79. package/dist/core/ecs/relation_service.d.ts +235 -0
  80. package/dist/core/ecs/relation_service.d.ts.map +1 -0
  81. package/dist/core/ecs/resource.d.cts +53 -0
  82. package/dist/core/ecs/resource.d.ts +53 -0
  83. package/dist/core/ecs/resource.d.ts.map +1 -0
  84. package/dist/core/ecs/resource_registry.d.cts +20 -0
  85. package/dist/core/ecs/resource_registry.d.ts +20 -0
  86. package/dist/core/ecs/resource_registry.d.ts.map +1 -0
  87. package/dist/core/ecs/resume.d.cts +85 -0
  88. package/dist/core/ecs/resume.d.ts +85 -0
  89. package/dist/core/ecs/resume.d.ts.map +1 -0
  90. package/dist/core/ecs/run_condition.d.cts +81 -0
  91. package/dist/core/ecs/run_condition.d.ts +81 -0
  92. package/dist/core/ecs/run_condition.d.ts.map +1 -0
  93. package/dist/core/ecs/schedule.d.cts +142 -0
  94. package/dist/core/ecs/schedule.d.ts +142 -0
  95. package/dist/core/ecs/schedule.d.ts.map +1 -0
  96. package/dist/core/ecs/snapshot_service.d.cts +94 -0
  97. package/dist/core/ecs/snapshot_service.d.ts +94 -0
  98. package/dist/core/ecs/snapshot_service.d.ts.map +1 -0
  99. package/dist/core/ecs/sparse_store.d.cts +110 -0
  100. package/dist/core/ecs/sparse_store.d.ts +110 -0
  101. package/dist/core/ecs/sparse_store.d.ts.map +1 -0
  102. package/dist/core/ecs/store.d.cts +950 -0
  103. package/dist/core/ecs/store.d.ts +950 -0
  104. package/dist/core/ecs/store.d.ts.map +1 -0
  105. package/dist/core/ecs/store_layout_listener.d.cts +23 -0
  106. package/dist/core/ecs/store_layout_listener.d.ts +23 -0
  107. package/dist/core/ecs/store_layout_listener.d.ts.map +1 -0
  108. package/dist/core/ecs/system.d.cts +250 -0
  109. package/dist/core/ecs/system.d.ts +250 -0
  110. package/dist/core/ecs/system.d.ts.map +1 -0
  111. package/dist/core/ecs/utils/arrays.d.cts +7 -0
  112. package/dist/{utils → core/ecs/utils}/arrays.d.ts +2 -1
  113. package/dist/core/ecs/utils/arrays.d.ts.map +1 -0
  114. package/dist/core/ecs/utils/constants.d.ts +12 -0
  115. package/dist/core/ecs/utils/constants.d.ts.map +1 -0
  116. package/dist/core/ecs/utils/error.d.cts +61 -0
  117. package/dist/core/ecs/utils/error.d.ts +61 -0
  118. package/dist/core/ecs/utils/error.d.ts.map +1 -0
  119. package/dist/core/store/action_ring.d.cts +136 -0
  120. package/dist/core/store/action_ring.d.ts +136 -0
  121. package/dist/core/store/action_ring.d.ts.map +1 -0
  122. package/dist/core/store/allocator.d.cts +238 -0
  123. package/dist/core/store/allocator.d.ts +238 -0
  124. package/dist/core/store/allocator.d.ts.map +1 -0
  125. package/dist/core/store/buffer_backed_column.d.cts +69 -0
  126. package/dist/core/store/buffer_backed_column.d.ts +69 -0
  127. package/dist/core/store/buffer_backed_column.d.ts.map +1 -0
  128. package/dist/core/store/column_store.d.cts +273 -0
  129. package/dist/core/store/column_store.d.ts +273 -0
  130. package/dist/core/store/column_store.d.ts.map +1 -0
  131. package/dist/core/store/command_dispatch.d.cts +52 -0
  132. package/dist/core/store/command_dispatch.d.ts +52 -0
  133. package/dist/core/store/command_dispatch.d.ts.map +1 -0
  134. package/dist/core/store/command_ring.d.cts +107 -0
  135. package/dist/core/store/command_ring.d.ts +107 -0
  136. package/dist/core/store/command_ring.d.ts.map +1 -0
  137. package/dist/core/store/descriptor.d.cts +80 -0
  138. package/dist/core/store/descriptor.d.ts +80 -0
  139. package/dist/core/store/descriptor.d.ts.map +1 -0
  140. package/dist/core/store/entity_index.d.cts +108 -0
  141. package/dist/core/store/entity_index.d.ts +108 -0
  142. package/dist/core/store/entity_index.d.ts.map +1 -0
  143. package/dist/core/store/event_ring.d.cts +95 -0
  144. package/dist/core/store/event_ring.d.ts +95 -0
  145. package/dist/core/store/event_ring.d.ts.map +1 -0
  146. package/dist/core/store/extend.d.cts +39 -0
  147. package/dist/core/store/extend.d.ts +39 -0
  148. package/dist/core/store/extend.d.ts.map +1 -0
  149. package/dist/core/store/grow.d.cts +34 -0
  150. package/dist/core/store/grow.d.ts +34 -0
  151. package/dist/core/store/grow.d.ts.map +1 -0
  152. package/dist/core/store/header.d.cts +64 -0
  153. package/dist/core/store/header.d.ts +64 -0
  154. package/dist/core/store/header.d.ts.map +1 -0
  155. package/dist/core/store/index.d.cts +17 -0
  156. package/dist/core/store/index.d.ts +17 -0
  157. package/dist/core/store/index.d.ts.map +1 -0
  158. package/dist/core/store/layout_ops.d.cts +152 -0
  159. package/dist/core/store/layout_ops.d.ts +152 -0
  160. package/dist/core/store/layout_ops.d.ts.map +1 -0
  161. package/dist/core/store/region_table.d.cts +74 -0
  162. package/dist/core/store/region_table.d.ts +74 -0
  163. package/dist/core/store/region_table.d.ts.map +1 -0
  164. package/dist/core/store/snapshot.d.cts +43 -0
  165. package/dist/core/store/snapshot.d.ts +43 -0
  166. package/dist/core/store/snapshot.d.ts.map +1 -0
  167. package/dist/core/store/state_hash.d.cts +38 -0
  168. package/dist/core/store/state_hash.d.ts +38 -0
  169. package/dist/core/store/state_hash.d.ts.map +1 -0
  170. package/dist/core/store/store_regions.d.cts +38 -0
  171. package/dist/core/store/store_regions.d.ts +38 -0
  172. package/dist/core/store/store_regions.d.ts.map +1 -0
  173. package/dist/core/store/vendored_abi/abi.d.cts +43 -0
  174. package/dist/core/store/vendored_abi/abi.d.ts +43 -0
  175. package/dist/core/store/vendored_abi/abi.d.ts.map +1 -0
  176. package/dist/dev_flag.d.cts +17 -0
  177. package/dist/dev_flag.d.ts +17 -0
  178. package/dist/dev_flag.d.ts.map +1 -0
  179. package/dist/extensions/editor/editor.d.cts +170 -0
  180. package/dist/extensions/editor/editor.d.ts +170 -0
  181. package/dist/extensions/editor/editor.d.ts.map +1 -0
  182. package/dist/extensions/editor/field_handle.d.cts +40 -0
  183. package/dist/extensions/editor/field_handle.d.ts +40 -0
  184. package/dist/extensions/editor/field_handle.d.ts.map +1 -0
  185. package/dist/extensions/editor/index.cjs +1 -0
  186. package/dist/extensions/editor/index.d.cts +21 -0
  187. package/dist/extensions/editor/index.d.ts +21 -0
  188. package/dist/extensions/editor/index.d.ts.map +1 -0
  189. package/dist/extensions/editor/index.js +237 -0
  190. package/dist/extensions/reactive/ecs_sync.d.cts +214 -0
  191. package/dist/extensions/reactive/ecs_sync.d.ts +214 -0
  192. package/dist/extensions/reactive/ecs_sync.d.ts.map +1 -0
  193. package/dist/extensions/reactive/index.cjs +1 -0
  194. package/dist/extensions/reactive/index.d.cts +23 -0
  195. package/dist/extensions/reactive/index.d.ts +23 -0
  196. package/dist/extensions/reactive/index.d.ts.map +1 -0
  197. package/dist/extensions/reactive/index.js +215 -0
  198. package/dist/extensions/solid/index.cjs +1 -0
  199. package/dist/extensions/solid/index.d.cts +6 -0
  200. package/dist/extensions/solid/index.d.ts +6 -0
  201. package/dist/extensions/solid/index.d.ts.map +1 -0
  202. package/dist/extensions/solid/index.js +36 -0
  203. package/dist/extensions/solid/kernel_solid.d.cts +45 -0
  204. package/dist/extensions/solid/kernel_solid.d.ts +45 -0
  205. package/dist/extensions/solid/kernel_solid.d.ts.map +1 -0
  206. package/dist/host_commands-BF8QMi3c.cjs +1 -0
  207. package/dist/host_commands-i4cAeyL5.js +2318 -0
  208. package/dist/index.cjs +1 -1
  209. package/dist/index.d.cts +66 -0
  210. package/dist/index.d.ts +65 -12
  211. package/dist/index.d.ts.map +1 -1
  212. package/dist/index.js +7080 -1289
  213. package/dist/internal.cjs +2 -0
  214. package/dist/internal.d.cts +20 -0
  215. package/dist/internal.d.ts +20 -0
  216. package/dist/internal.d.ts.map +1 -0
  217. package/dist/internal.js +141 -0
  218. package/dist/interop-CT-REx0W.cjs +1 -0
  219. package/dist/interop-CcY6ASQc.js +18 -0
  220. package/dist/kernel-DgyrLFjW.js +227 -0
  221. package/dist/kernel-yWV3XnAb.cjs +1 -0
  222. package/dist/primitives.cjs +1 -0
  223. package/dist/primitives.d.cts +18 -0
  224. package/dist/primitives.d.ts +18 -0
  225. package/dist/primitives.d.ts.map +1 -0
  226. package/dist/primitives.js +45 -0
  227. package/dist/reactive/array.d.cts +24 -0
  228. package/dist/reactive/array.d.ts +24 -0
  229. package/dist/reactive/array.d.ts.map +1 -0
  230. package/dist/reactive/index.cjs +1 -0
  231. package/dist/reactive/index.d.cts +11 -0
  232. package/dist/reactive/index.d.ts +11 -0
  233. package/dist/reactive/index.d.ts.map +1 -0
  234. package/dist/reactive/index.js +18 -0
  235. package/dist/reactive/interop.d.cts +19 -0
  236. package/dist/reactive/interop.d.ts +19 -0
  237. package/dist/reactive/interop.d.ts.map +1 -0
  238. package/dist/reactive/kernel.d.cts +73 -0
  239. package/dist/reactive/kernel.d.ts +73 -0
  240. package/dist/reactive/kernel.d.ts.map +1 -0
  241. package/dist/reactive/map.d.cts +16 -0
  242. package/dist/reactive/map.d.ts +16 -0
  243. package/dist/reactive/map.d.ts.map +1 -0
  244. package/dist/reactive/shallow.d.cts +11 -0
  245. package/dist/reactive/shallow.d.ts +11 -0
  246. package/dist/reactive/shallow.d.ts.map +1 -0
  247. package/dist/reactive/struct.d.cts +10 -0
  248. package/dist/reactive/struct.d.ts +10 -0
  249. package/dist/reactive/struct.d.ts.map +1 -0
  250. package/dist/shallow-DQ8aG51_.cjs +1 -0
  251. package/dist/shallow-DfnAm9vG.js +150 -0
  252. package/dist/shared-BU1Cd40h.js +103 -0
  253. package/dist/shared-BymrGTyR.cjs +1 -0
  254. package/dist/shared.cjs +1 -0
  255. package/dist/shared.d.cts +22 -0
  256. package/dist/shared.d.ts +22 -0
  257. package/dist/shared.d.ts.map +1 -0
  258. package/dist/shared.js +7 -0
  259. package/dist/topological_sort-BDvEyb9W.cjs +1 -0
  260. package/dist/topological_sort-DK6EjpWa.js +135 -0
  261. package/dist/type_primitives/assertions.d.cts +32 -0
  262. package/dist/type_primitives/assertions.d.ts +25 -9
  263. package/dist/type_primitives/assertions.d.ts.map +1 -1
  264. package/dist/type_primitives/binary_heap/binary_heap.d.cts +37 -0
  265. package/dist/type_primitives/binary_heap/binary_heap.d.ts +6 -2
  266. package/dist/type_primitives/binary_heap/binary_heap.d.ts.map +1 -1
  267. package/dist/type_primitives/bitset/bitset.d.cts +54 -0
  268. package/dist/type_primitives/bitset/bitset.d.ts +16 -4
  269. package/dist/type_primitives/bitset/bitset.d.ts.map +1 -1
  270. package/dist/type_primitives/brand.d.cts +23 -0
  271. package/dist/type_primitives/brand.d.ts +6 -1
  272. package/dist/type_primitives/brand.d.ts.map +1 -1
  273. package/dist/type_primitives/error.d.cts +16 -0
  274. package/dist/type_primitives/error.d.ts +8 -3
  275. package/dist/type_primitives/error.d.ts.map +1 -1
  276. package/dist/type_primitives/index.d.cts +13 -0
  277. package/dist/type_primitives/index.d.ts +12 -9
  278. package/dist/type_primitives/index.d.ts.map +1 -1
  279. package/dist/type_primitives/sparse_map/sparse_map.d.cts +30 -0
  280. package/dist/type_primitives/sparse_map/sparse_map.d.ts +7 -3
  281. package/dist/type_primitives/sparse_map/sparse_map.d.ts.map +1 -1
  282. package/dist/type_primitives/sparse_set/sparse_set.d.cts +28 -0
  283. package/dist/type_primitives/sparse_set/sparse_set.d.ts +4 -0
  284. package/dist/type_primitives/sparse_set/sparse_set.d.ts.map +1 -1
  285. package/dist/type_primitives/topological_sort/topological_sort.d.cts +29 -0
  286. package/dist/type_primitives/topological_sort/topological_sort.d.ts +7 -3
  287. package/dist/type_primitives/topological_sort/topological_sort.d.ts.map +1 -1
  288. package/dist/type_primitives/typed_arrays/typed_arrays.d.cts +127 -0
  289. package/dist/type_primitives/typed_arrays/typed_arrays.d.ts +53 -16
  290. package/dist/type_primitives/typed_arrays/typed_arrays.d.ts.map +1 -1
  291. package/dist/typed_arrays-BcXcnzB4.js +258 -0
  292. package/dist/typed_arrays-D3NmwtCG.cjs +1 -0
  293. package/dist/utils/error.d.cts +6 -0
  294. package/dist/utils/error.d.ts +2 -20
  295. package/dist/utils/error.d.ts.map +1 -1
  296. package/dist/version.d.cts +10 -0
  297. package/dist/version.d.ts +10 -0
  298. package/dist/version.d.ts.map +1 -0
  299. package/package.json +115 -5
  300. package/dist/archetype.d.ts +0 -108
  301. package/dist/archetype.d.ts.map +0 -1
  302. package/dist/component.d.ts +0 -45
  303. package/dist/component.d.ts.map +0 -1
  304. package/dist/ecs.d.ts +0 -104
  305. package/dist/ecs.d.ts.map +0 -1
  306. package/dist/entity.d.ts +0 -11
  307. package/dist/entity.d.ts.map +0 -1
  308. package/dist/event.d.ts +0 -30
  309. package/dist/event.d.ts.map +0 -1
  310. package/dist/query.d.ts +0 -94
  311. package/dist/query.d.ts.map +0 -1
  312. package/dist/ref.d.ts +0 -23
  313. package/dist/ref.d.ts.map +0 -1
  314. package/dist/resource.d.ts +0 -23
  315. package/dist/resource.d.ts.map +0 -1
  316. package/dist/schedule.d.ts +0 -45
  317. package/dist/schedule.d.ts.map +0 -1
  318. package/dist/store.d.ts +0 -118
  319. package/dist/store.d.ts.map +0 -1
  320. package/dist/system.d.ts +0 -16
  321. package/dist/system.d.ts.map +0 -1
  322. package/dist/utils/arrays.d.ts.map +0 -1
  323. package/dist/utils/constants.d.ts.map +0 -1
  324. /package/dist/{utils/constants.d.ts → core/ecs/utils/constants.d.cts} +0 -0
@@ -0,0 +1,96 @@
1
+ import { BitSet } from '../../type_primitives/index.js';
2
+ import { Archetype, ArchetypeColumnLayout, ArchetypeID } from './archetype.js';
3
+ import { ComponentID } from './component.js';
4
+ import { ComponentMeta } from './store.js';
5
+ import { ArchetypeSpec } from '../store/index.js';
6
+ /** What the graph needs from `Store` — closure-injected. `extendStore` and
7
+ * `materialize` bind the storage lifecycle (SAB extend + column-store views
8
+ * + grow handler) on the Store side; `fanIntoQueries` binds query-registry
9
+ * state. All are creation-path only — never called on an edge-cache hit. */
10
+ export interface ArchetypeGraphHost {
11
+ /** Component field metadata, indexed by ComponentID — for building a new
12
+ * archetype's column layouts. */
13
+ readonly componentMetas: () => readonly ComponentMeta[];
14
+ /** Row capacity for a new archetype's column region. */
15
+ readonly initialCapacity: () => number;
16
+ /** Extend the SAB with the new archetypes' column regions (one call for
17
+ * the whole batch — the bulk path's O(N²)→O(N) win, #213). */
18
+ readonly extendStore: (specs: ArchetypeSpec[]) => void;
19
+ /** Materialise the `Archetype` over the live column store and attach the
20
+ * store's grow handler. */
21
+ readonly materialize: (id: ArchetypeID, ownedMask: BitSet, layouts: ArchetypeColumnLayout[]) => Archetype;
22
+ /** Push a newly-installed archetype into every registered query whose
23
+ * masks it satisfies. */
24
+ readonly fanIntoQueries: (archetype: Archetype) => void;
25
+ }
26
+ export declare class ArchetypeGraph {
27
+ /** All archetypes, indexed by `ArchetypeID` (ids are minted monotonically
28
+ * and never removed). Store's flush loops hoist this array to a local. */
29
+ readonly archetypes: Archetype[];
30
+ /** Inverted index: ComponentID → ascending list of ArchetypeIDs that contain
31
+ * that component. Indexed POSITIONALLY by component id (a small, dense id
32
+ * space, 0..STORE_DESCRIPTOR_COMPONENT_LIMIT-1), so a lookup is an array
33
+ * index, not a Map hash. Used by `getMatchingArchetypes` to start the
34
+ * superset scan from the smallest bucket. Each bucket is a plain push-only
35
+ * array — NOT a Set — and deliberately does NOT dedup: a (component,
36
+ * archetype) pair can be inserted here at most once (see the "no duplicate
37
+ * pair" invariant on `install` + ADR-0015), so there is nothing for a Set
38
+ * to collapse. Archetypes are never removed from a Store, so buckets only
39
+ * grow, in ascending archetype-id order — which is canonical order,
40
+ * exploited by `_forEachChangedArchetype` to skip a sort. */
41
+ readonly componentIndex: ArchetypeID[][];
42
+ private readonly archetypeMap;
43
+ private nextArchetypeId;
44
+ private readonly host;
45
+ constructor(host: ArchetypeGraphHost);
46
+ get(id: ArchetypeID): Archetype;
47
+ /**
48
+ * Find or create an archetype for the given component mask.
49
+ * Also updates the componentIndex and pushes into matching registered queries.
50
+ *
51
+ * Hot single-mask path. The bulk batched variant — used by Phase C
52
+ * pre-warming at `ecs.startup()` — is `createManyFromMasks`;
53
+ * see #213 / `ECS.startup()` for how it gets called and why.
54
+ */
55
+ getOrCreateFromMask(mask: BitSet): ArchetypeID;
56
+ /**
57
+ * Bulk variant of `getOrCreateFromMask` — Phase C of issue #213.
58
+ *
59
+ * Given a set of masks, creates Archetypes for the ones not already
60
+ * planted, in a SINGLE `extendColumnStore` call (instead of one per
61
+ * archetype). Single-mask creation is O(N) in archetypes-so-far because
62
+ * the extend has to copy every existing archetype's live rows forward;
63
+ * N such calls compound to O(N²). Batching collapses the per-archetype
64
+ * setup-and-copy down to one pass — the per-startup cost the design doc
65
+ * §5.2 calls out as "O(N²) → O(N)" for in-tree systems whose archetype
66
+ * set is known at registration time via `spawns` + `transitions`.
67
+ *
68
+ * Masks already in the map are skipped. Returns the resolved
69
+ * `ArchetypeID` per input mask in input order — callers that don't need
70
+ * the ids can ignore the return value.
71
+ */
72
+ createManyFromMasks(masks: readonly BitSet[]): ArchetypeID[];
73
+ /** Hash-bucketed mask → ArchetypeID lookup; null when the mask isn't planted. */
74
+ private lookup;
75
+ /** Walk the mask's set bits and resolve each non-tag component to its
76
+ * layout. Used by both single and bulk archetype-create paths. */
77
+ private buildLayouts;
78
+ /** Materialise the `Archetype` for `id` (via the host, which binds the
79
+ * live column store + grow handler), register in the archetype map +
80
+ * component index, and fan into any matching registered queries.
81
+ *
82
+ * Clones `mask` before storing — callers may pass scratch BitSets that
83
+ * they intend to reuse (e.g. `addComponents` / `removeComponents`'s
84
+ * `_scratchTargetMask`). The Archetype and the archetypeMap bucket
85
+ * both keep references long-term, so the clone is required for
86
+ * correctness — and is the previously-implicit guarantee made by the
87
+ * mask-allocating callers (`copyWithSet`, `copyWithClear`, etc.). */
88
+ private install;
89
+ /** Resolve "add component_id to archetype_id" → target ArchetypeID. Caches the edge. */
90
+ resolveAdd(archetypeId: ArchetypeID, componentId: ComponentID): ArchetypeID;
91
+ /** Resolve "remove component_id from archetype_id" → target ArchetypeID. Caches the edge. */
92
+ resolveRemove(archetypeId: ArchetypeID, componentId: ComponentID): ArchetypeID;
93
+ /** Cache a bidirectional add/remove edge between two archetypes. */
94
+ private cacheEdge;
95
+ }
96
+ //# sourceMappingURL=archetype_graph.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"archetype_graph.d.ts","sourceRoot":"","sources":["../../../src/core/ecs/archetype_graph.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,MAAM,EAAsB,MAAM,uBAAuB,CAAC;AACnE,OAAO,EACN,SAAS,EAGT,KAAK,qBAAqB,EAE1B,KAAK,WAAW,EAChB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAG7C,OAAO,EAGN,KAAK,aAAa,EAElB,MAAM,UAAU,CAAC;AAGlB;;;4EAG4E;AAC5E,MAAM,WAAW,kBAAkB;IAClC;qCACiC;IACjC,QAAQ,CAAC,cAAc,EAAE,MAAM,SAAS,aAAa,EAAE,CAAC;IACxD,wDAAwD;IACxD,QAAQ,CAAC,eAAe,EAAE,MAAM,MAAM,CAAC;IACvC;kEAC8D;IAC9D,QAAQ,CAAC,WAAW,EAAE,CAAC,KAAK,EAAE,aAAa,EAAE,KAAK,IAAI,CAAC;IACvD;+BAC2B;IAC3B,QAAQ,CAAC,WAAW,EAAE,CACrB,EAAE,EAAE,WAAW,EACf,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,qBAAqB,EAAE,KAC5B,SAAS,CAAC;IACf;6BACyB;IACzB,QAAQ,CAAC,cAAc,EAAE,CAAC,SAAS,EAAE,SAAS,KAAK,IAAI,CAAC;CACxD;AAED,qBAAa,cAAc;IAC1B;8EAC0E;IAC1E,SAAgB,UAAU,EAAE,SAAS,EAAE,CAAM;IAC7C;;;;;;;;;;iEAU6D;IAC7D,SAAgB,cAAc,EAAE,WAAW,EAAE,EAAE,CAAM;IAErD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAyC;IACtE,OAAO,CAAC,eAAe,CAAK;IAE5B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAqB;gBAE9B,IAAI,EAAE,kBAAkB;IAI7B,GAAG,CAAC,EAAE,EAAE,WAAW,GAAG,SAAS;IAStC;;;;;;;OAOG;IACI,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW;IAkBrD;;;;;;;;;;;;;;;OAeG;IACI,mBAAmB,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,WAAW,EAAE;IA4DnE,iFAAiF;IACjF,OAAO,CAAC,MAAM;IASd;sEACkE;IAClE,OAAO,CAAC,YAAY;IAkBpB;;;;;;;;;yEASqE;IACrE,OAAO,CAAC,OAAO;IA0Df,wFAAwF;IACjF,UAAU,CAAC,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,GAAG,WAAW;IAYlF,6FAA6F;IACtF,aAAa,CAAC,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,GAAG,WAAW;IAYrF,oEAAoE;IACpE,OAAO,CAAC,SAAS;CAuBjB"}
@@ -0,0 +1,43 @@
1
+ import { ECS } from './ecs.cjs';
2
+ import { OnDeleteTarget, RelationDef } from './relation.cjs';
3
+ /** Options for a built-in relation. `exclusive` / `multi` are fixed (always
4
+ * exclusive — required for the chain/tree traversal helpers), so only the
5
+ * target-deletion cleanup policy is tunable. */
6
+ export interface BuiltinRelationOptions {
7
+ /** What happens to a relation's sources when a target is destroyed.
8
+ * Defaults per relation (see each registrar). */
9
+ readonly onDeleteTarget?: OnDeleteTarget;
10
+ }
11
+ /**
12
+ * Register an **`IsA(instance → exemplar)`** relation — a thin instance-of link.
13
+ *
14
+ * - "all instances of exemplar E" is `ecs.relations.sourcesOf(E, IsA)`.
15
+ * - the IsA chain (`instance → exemplar → …`) is walked with
16
+ * `ecs.relations.ancestorsOf(instance, IsA)` / `rootOf` / `cascadeOf(exemplar, IsA)`.
17
+ * - **No component inheritance** — IsA records the link only; materialization of
18
+ * an instance from its exemplar stays a spawn-time copy (the template path,
19
+ * #462), deliberately decoupled (#477 / #478). An exemplar is a real entity,
20
+ * not a `Template` (a non-entity template can't be a relation target).
21
+ *
22
+ * Default `onDeleteTarget: "clear"` — destroying an exemplar drops its
23
+ * instances' IsA link but leaves the instances alive (the thin analog of
24
+ * flecs's `IsA`-remove, since there is no inherited data to strip). Pass
25
+ * `"delete"` for strong instance-of (exemplar death cascade-destroys instances).
26
+ */
27
+ export declare function registerIsA(ecs: ECS, opts?: BuiltinRelationOptions): RelationDef<"exclusive">;
28
+ /**
29
+ * Register a **`ChildOf(child → parent)`** relation — a thin hierarchy link.
30
+ *
31
+ * - a parent's children are `ecs.relations.sourcesOf(parent, ChildOf)`.
32
+ * - the hierarchy is walked with `ecs.relations.ancestorsOf(child, ChildOf)` (up to the
33
+ * root), `rootOf`, and `cascadeOf(root, ChildOf)` (down, breadth-first,
34
+ * parents before children).
35
+ * - unlike flecs's `ChildOf`, this does **not** scope names/lookup — the engine
36
+ * has no name registry; it is purely the structural parent link.
37
+ *
38
+ * Default `onDeleteTarget: "delete"` — destroying a parent cascade-destroys
39
+ * its whole subtree (flecs's default). Pass `"clear"` to let children survive as
40
+ * roots, or `"orphan"` to leave a dangling `targetOf`.
41
+ */
42
+ export declare function registerChildOf(ecs: ECS, opts?: BuiltinRelationOptions): RelationDef<"exclusive">;
43
+ //# sourceMappingURL=builtin_relations.d.ts.map
@@ -0,0 +1,43 @@
1
+ import { ECS } from './ecs.js';
2
+ import { OnDeleteTarget, RelationDef } from './relation.js';
3
+ /** Options for a built-in relation. `exclusive` / `multi` are fixed (always
4
+ * exclusive — required for the chain/tree traversal helpers), so only the
5
+ * target-deletion cleanup policy is tunable. */
6
+ export interface BuiltinRelationOptions {
7
+ /** What happens to a relation's sources when a target is destroyed.
8
+ * Defaults per relation (see each registrar). */
9
+ readonly onDeleteTarget?: OnDeleteTarget;
10
+ }
11
+ /**
12
+ * Register an **`IsA(instance → exemplar)`** relation — a thin instance-of link.
13
+ *
14
+ * - "all instances of exemplar E" is `ecs.relations.sourcesOf(E, IsA)`.
15
+ * - the IsA chain (`instance → exemplar → …`) is walked with
16
+ * `ecs.relations.ancestorsOf(instance, IsA)` / `rootOf` / `cascadeOf(exemplar, IsA)`.
17
+ * - **No component inheritance** — IsA records the link only; materialization of
18
+ * an instance from its exemplar stays a spawn-time copy (the template path,
19
+ * #462), deliberately decoupled (#477 / #478). An exemplar is a real entity,
20
+ * not a `Template` (a non-entity template can't be a relation target).
21
+ *
22
+ * Default `onDeleteTarget: "clear"` — destroying an exemplar drops its
23
+ * instances' IsA link but leaves the instances alive (the thin analog of
24
+ * flecs's `IsA`-remove, since there is no inherited data to strip). Pass
25
+ * `"delete"` for strong instance-of (exemplar death cascade-destroys instances).
26
+ */
27
+ export declare function registerIsA(ecs: ECS, opts?: BuiltinRelationOptions): RelationDef<"exclusive">;
28
+ /**
29
+ * Register a **`ChildOf(child → parent)`** relation — a thin hierarchy link.
30
+ *
31
+ * - a parent's children are `ecs.relations.sourcesOf(parent, ChildOf)`.
32
+ * - the hierarchy is walked with `ecs.relations.ancestorsOf(child, ChildOf)` (up to the
33
+ * root), `rootOf`, and `cascadeOf(root, ChildOf)` (down, breadth-first,
34
+ * parents before children).
35
+ * - unlike flecs's `ChildOf`, this does **not** scope names/lookup — the engine
36
+ * has no name registry; it is purely the structural parent link.
37
+ *
38
+ * Default `onDeleteTarget: "delete"` — destroying a parent cascade-destroys
39
+ * its whole subtree (flecs's default). Pass `"clear"` to let children survive as
40
+ * roots, or `"orphan"` to leave a dangling `targetOf`.
41
+ */
42
+ export declare function registerChildOf(ecs: ECS, opts?: BuiltinRelationOptions): RelationDef<"exclusive">;
43
+ //# sourceMappingURL=builtin_relations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builtin_relations.d.ts","sourceRoot":"","sources":["../../../src/core/ecs/builtin_relations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;KAsBK;AAEL,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9D;;gDAEgD;AAChD,MAAM,WAAW,sBAAsB;IACtC;qDACiD;IACjD,QAAQ,CAAC,cAAc,CAAC,EAAE,cAAc,CAAC;CACzC;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,EAAE,sBAAsB,GAAG,WAAW,CAAC,WAAW,CAAC,CAK7F;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,EAAE,sBAAsB,GAAG,WAAW,CAAC,WAAW,CAAC,CAKjG"}
@@ -0,0 +1,116 @@
1
+ import { ECS } from './ecs.cjs';
2
+ import { HostCommand, HostCommandQueue, HostCommandSink } from './host_commands.cjs';
3
+ /** One recorded update tick: the commands the apply system drained at this
4
+ * tick's update-phase head, plus the `dt` passed to `ecs.update(dt)`. Replay
5
+ * MUST re-issue `update(dt)` for every recorded tick — even an empty one — since
6
+ * `dt` itself drives the sim (movement, timers), not just the commands. */
7
+ export interface RecordedTick {
8
+ /** The ECS tick (`ctx.ecsTick`) this bucket belongs to. */
9
+ readonly tick: number;
10
+ /** The `dt` `ecs.update(dt)` was called with for this tick. */
11
+ readonly dt: number;
12
+ /** Commands applied this tick, in apply order (typed queue first, then ring),
13
+ * `onSpawned` stripped. */
14
+ readonly commands: readonly HostCommand[];
15
+ }
16
+ /**
17
+ * A recorded session: the `seed` it ran under, the seed-time commands drained at
18
+ * startup, and the per-tick command stream. Plain, serializable data — the
19
+ * record-side mirror of the typed `HostCommand` vocabulary. Replay it with
20
+ * {@link replayCommandLog}; persist it with {@link serializeCommandLog}.
21
+ */
22
+ export interface CommandLog {
23
+ /** Session seed — the implementer's deterministic input (e.g. an RNG seed).
24
+ * Opaque to the engine (the core tick takes only `dt`); carried so a replay
25
+ * rebuilds the world the same way the original was built. */
26
+ readonly seed: number;
27
+ /** Commands drained at the PRE_STARTUP head (seed-time edits), applied before
28
+ * the first update tick. Enqueued BEFORE `ecs.startup()` on replay. */
29
+ readonly startup: readonly HostCommand[];
30
+ /** One entry per update tick, in order. */
31
+ readonly ticks: readonly RecordedTick[];
32
+ }
33
+ /**
34
+ * The record side of record/replay: a {@link HostCommandSink} the apply system
35
+ * feeds. Construct one with the session `seed`, hand it to
36
+ * `installHostCommandSeam(world, { recorder })`, and it accumulates the
37
+ * command stream as the ECS ticks. Read it back with {@link log} (a live view,
38
+ * ready to {@link serializeCommandLog serialize}).
39
+ *
40
+ * Bucketing: STARTUP-phase drains (which never call {@link openTick}) append to
41
+ * the {@link startup} bucket; each update-phase drain {@link openTick}s its tick
42
+ * — multiple update-phase drains in one tick reuse the same bucket (keyed by the
43
+ * ECS tick), so a frame's commands stay together. The apply system runs every
44
+ * tick, so every tick's `dt` is recorded even when no commands were applied.
45
+ *
46
+ * One recorder per session — don't share across worlds.
47
+ */
48
+ export declare class HostCommandRecorder implements HostCommandSink {
49
+ /** Session seed, echoed into the produced {@link CommandLog}. */
50
+ readonly seed: number;
51
+ private readonly _startup;
52
+ private readonly _ticks;
53
+ /** Where {@link record} appends. Defaults to the startup bucket (seed-time
54
+ * drains happen before any `openTick`); each `openTick` repoints it. */
55
+ private sink;
56
+ constructor(seed?: number);
57
+ openTick(tick: number, dt: number): void;
58
+ readonly record: (cmd: HostCommand) => void;
59
+ /** A live {@link CommandLog} view over the accumulated stream — not a copy.
60
+ * Serialize it (which deep-copies through JSON) before mutating the world
61
+ * further if you need a stable snapshot, or use {@link snapshotLog}. */
62
+ log(): CommandLog;
63
+ /** A STABLE deep copy of the accumulated stream — safe to hold across
64
+ * further recording (the safe default; `log()` is the zero-copy live view). */
65
+ snapshotLog(): CommandLog;
66
+ }
67
+ /** Serialize a {@link CommandLog} to a JSON string. `EntityID` is a plain number
68
+ * and round-trips as-is; a `ComponentDef` is a callable, so the replacer writes
69
+ * it as `{ [DEF_TAG]: id }`. (The recorder already stripped `onSpawned`, the
70
+ * only other non-serializable member.)
71
+ *
72
+ * Throws {@link ECS_ERROR.COMMAND_LOG_TAG_COLLISION} if any non-def object in the
73
+ * log (i.e. a command's `values` map) owns a field named {@link DEF_TAG}: the
74
+ * reviver tags defs in-band, so such a value would be silently revived as a def,
75
+ * dropping the real field data. Field names are arbitrary, so this is reachable;
76
+ * failing here keeps the round-trip lossless instead of corrupting on parse. */
77
+ export declare function serializeCommandLog(log: CommandLog): string;
78
+ /** Parse a {@link CommandLog} from {@link serializeCommandLog} output. */
79
+ export declare function deserializeCommandLog(json: string): CommandLog;
80
+ /** Outcome of {@link replayCommandLog}. */
81
+ export interface ReplayResult {
82
+ /** Seed-time commands re-applied before the first tick. */
83
+ readonly startupCommands: number;
84
+ /** Update ticks replayed. */
85
+ readonly ticks: number;
86
+ /** Per-tick `stateHash` captured after each `update`, in tick order — empty
87
+ * unless the world is deterministic (or `hash` was forced). Compare against
88
+ * the original run's per-tick hashes to prove the replay matched (ADR-0020). */
89
+ readonly stateHashes: readonly number[];
90
+ }
91
+ /** Options for {@link replayCommandLog}. */
92
+ export interface ReplayOptions {
93
+ /** Capture `ecs.snapshots.stateHash()` after each tick. Defaults to the world's
94
+ * `deterministic` flag — a deterministic world is hashed, a non-deterministic
95
+ * one is not (its `stateHash` would throw, ADR-0020). Force `true` only on a
96
+ * deterministic world. */
97
+ readonly hash?: boolean;
98
+ }
99
+ /**
100
+ * Replay a recorded {@link CommandLog} against `world`, reproducing the original
101
+ * session tick-for-tick. `world` must be FRESH and NOT yet started, built
102
+ * identically to the recorded run (same components registered in the same order,
103
+ * same systems, same `seed` from `log.seed`) and seam-installed — pass the
104
+ * `HostCommandQueue` `installHostCommandSeam` returned as `queue`. The driver
105
+ * owns startup: it enqueues the seed-time commands, calls `ecs.startup()`
106
+ * (which drains them at PRE_STARTUP), then for each recorded tick enqueues that
107
+ * tick's commands and calls `ecs.update(dt)` with the recorded `dt`.
108
+ *
109
+ * Determinism (ADR-0020): with `{ deterministic: true }` the per-tick
110
+ * `stateHashes` this returns must equal the original run's — that equality is
111
+ * replay fidelity. Identity caveat (§85): a despawned-then-respawned entity gets
112
+ * a fresh id, but because spawn order is reproduced, every recorded id still
113
+ * resolves to the same entity on replay.
114
+ */
115
+ export declare function replayCommandLog(ecs: ECS, queue: HostCommandQueue, log: CommandLog, opts?: ReplayOptions): ReplayResult;
116
+ //# sourceMappingURL=command_log.d.ts.map
@@ -0,0 +1,116 @@
1
+ import { ECS } from './ecs.js';
2
+ import { HostCommand, HostCommandQueue, HostCommandSink } from './host_commands.js';
3
+ /** One recorded update tick: the commands the apply system drained at this
4
+ * tick's update-phase head, plus the `dt` passed to `ecs.update(dt)`. Replay
5
+ * MUST re-issue `update(dt)` for every recorded tick — even an empty one — since
6
+ * `dt` itself drives the sim (movement, timers), not just the commands. */
7
+ export interface RecordedTick {
8
+ /** The ECS tick (`ctx.ecsTick`) this bucket belongs to. */
9
+ readonly tick: number;
10
+ /** The `dt` `ecs.update(dt)` was called with for this tick. */
11
+ readonly dt: number;
12
+ /** Commands applied this tick, in apply order (typed queue first, then ring),
13
+ * `onSpawned` stripped. */
14
+ readonly commands: readonly HostCommand[];
15
+ }
16
+ /**
17
+ * A recorded session: the `seed` it ran under, the seed-time commands drained at
18
+ * startup, and the per-tick command stream. Plain, serializable data — the
19
+ * record-side mirror of the typed `HostCommand` vocabulary. Replay it with
20
+ * {@link replayCommandLog}; persist it with {@link serializeCommandLog}.
21
+ */
22
+ export interface CommandLog {
23
+ /** Session seed — the implementer's deterministic input (e.g. an RNG seed).
24
+ * Opaque to the engine (the core tick takes only `dt`); carried so a replay
25
+ * rebuilds the world the same way the original was built. */
26
+ readonly seed: number;
27
+ /** Commands drained at the PRE_STARTUP head (seed-time edits), applied before
28
+ * the first update tick. Enqueued BEFORE `ecs.startup()` on replay. */
29
+ readonly startup: readonly HostCommand[];
30
+ /** One entry per update tick, in order. */
31
+ readonly ticks: readonly RecordedTick[];
32
+ }
33
+ /**
34
+ * The record side of record/replay: a {@link HostCommandSink} the apply system
35
+ * feeds. Construct one with the session `seed`, hand it to
36
+ * `installHostCommandSeam(world, { recorder })`, and it accumulates the
37
+ * command stream as the ECS ticks. Read it back with {@link log} (a live view,
38
+ * ready to {@link serializeCommandLog serialize}).
39
+ *
40
+ * Bucketing: STARTUP-phase drains (which never call {@link openTick}) append to
41
+ * the {@link startup} bucket; each update-phase drain {@link openTick}s its tick
42
+ * — multiple update-phase drains in one tick reuse the same bucket (keyed by the
43
+ * ECS tick), so a frame's commands stay together. The apply system runs every
44
+ * tick, so every tick's `dt` is recorded even when no commands were applied.
45
+ *
46
+ * One recorder per session — don't share across worlds.
47
+ */
48
+ export declare class HostCommandRecorder implements HostCommandSink {
49
+ /** Session seed, echoed into the produced {@link CommandLog}. */
50
+ readonly seed: number;
51
+ private readonly _startup;
52
+ private readonly _ticks;
53
+ /** Where {@link record} appends. Defaults to the startup bucket (seed-time
54
+ * drains happen before any `openTick`); each `openTick` repoints it. */
55
+ private sink;
56
+ constructor(seed?: number);
57
+ openTick(tick: number, dt: number): void;
58
+ readonly record: (cmd: HostCommand) => void;
59
+ /** A live {@link CommandLog} view over the accumulated stream — not a copy.
60
+ * Serialize it (which deep-copies through JSON) before mutating the world
61
+ * further if you need a stable snapshot, or use {@link snapshotLog}. */
62
+ log(): CommandLog;
63
+ /** A STABLE deep copy of the accumulated stream — safe to hold across
64
+ * further recording (the safe default; `log()` is the zero-copy live view). */
65
+ snapshotLog(): CommandLog;
66
+ }
67
+ /** Serialize a {@link CommandLog} to a JSON string. `EntityID` is a plain number
68
+ * and round-trips as-is; a `ComponentDef` is a callable, so the replacer writes
69
+ * it as `{ [DEF_TAG]: id }`. (The recorder already stripped `onSpawned`, the
70
+ * only other non-serializable member.)
71
+ *
72
+ * Throws {@link ECS_ERROR.COMMAND_LOG_TAG_COLLISION} if any non-def object in the
73
+ * log (i.e. a command's `values` map) owns a field named {@link DEF_TAG}: the
74
+ * reviver tags defs in-band, so such a value would be silently revived as a def,
75
+ * dropping the real field data. Field names are arbitrary, so this is reachable;
76
+ * failing here keeps the round-trip lossless instead of corrupting on parse. */
77
+ export declare function serializeCommandLog(log: CommandLog): string;
78
+ /** Parse a {@link CommandLog} from {@link serializeCommandLog} output. */
79
+ export declare function deserializeCommandLog(json: string): CommandLog;
80
+ /** Outcome of {@link replayCommandLog}. */
81
+ export interface ReplayResult {
82
+ /** Seed-time commands re-applied before the first tick. */
83
+ readonly startupCommands: number;
84
+ /** Update ticks replayed. */
85
+ readonly ticks: number;
86
+ /** Per-tick `stateHash` captured after each `update`, in tick order — empty
87
+ * unless the world is deterministic (or `hash` was forced). Compare against
88
+ * the original run's per-tick hashes to prove the replay matched (ADR-0020). */
89
+ readonly stateHashes: readonly number[];
90
+ }
91
+ /** Options for {@link replayCommandLog}. */
92
+ export interface ReplayOptions {
93
+ /** Capture `ecs.snapshots.stateHash()` after each tick. Defaults to the world's
94
+ * `deterministic` flag — a deterministic world is hashed, a non-deterministic
95
+ * one is not (its `stateHash` would throw, ADR-0020). Force `true` only on a
96
+ * deterministic world. */
97
+ readonly hash?: boolean;
98
+ }
99
+ /**
100
+ * Replay a recorded {@link CommandLog} against `world`, reproducing the original
101
+ * session tick-for-tick. `world` must be FRESH and NOT yet started, built
102
+ * identically to the recorded run (same components registered in the same order,
103
+ * same systems, same `seed` from `log.seed`) and seam-installed — pass the
104
+ * `HostCommandQueue` `installHostCommandSeam` returned as `queue`. The driver
105
+ * owns startup: it enqueues the seed-time commands, calls `ecs.startup()`
106
+ * (which drains them at PRE_STARTUP), then for each recorded tick enqueues that
107
+ * tick's commands and calls `ecs.update(dt)` with the recorded `dt`.
108
+ *
109
+ * Determinism (ADR-0020): with `{ deterministic: true }` the per-tick
110
+ * `stateHashes` this returns must equal the original run's — that equality is
111
+ * replay fidelity. Identity caveat (§85): a despawned-then-respawned entity gets
112
+ * a fresh id, but because spawn order is reproduced, every recorded id still
113
+ * resolves to the same entity on replay.
114
+ */
115
+ export declare function replayCommandLog(ecs: ECS, queue: HostCommandQueue, log: CommandLog, opts?: ReplayOptions): ReplayResult;
116
+ //# sourceMappingURL=command_log.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command_log.d.ts","sourceRoot":"","sources":["../../../src/core/ecs/command_log.ts"],"names":[],"mappings":"AAyCA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEtF;;;2EAG2E;AAC3E,MAAM,WAAW,YAAY;IAC5B,2DAA2D;IAC3D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB;+BAC2B;IAC3B,QAAQ,CAAC,QAAQ,EAAE,SAAS,WAAW,EAAE,CAAC;CAC1C;AAED;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IAC1B;;iEAE6D;IAC7D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;2EACuE;IACvE,QAAQ,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE,CAAC;IACzC,2CAA2C;IAC3C,QAAQ,CAAC,KAAK,EAAE,SAAS,YAAY,EAAE,CAAC;CACxC;AAiBD;;;;;;;;;;;;;;GAcG;AACH,qBAAa,mBAAoB,YAAW,eAAe;IAC1D,iEAAiE;IACjE,SAAgB,IAAI,EAAE,MAAM,CAAC;IAC7B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqB;IAC9C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAC5C;4EACwE;IACxE,OAAO,CAAC,IAAI,CAAgC;gBAEhC,IAAI,SAAI;IAIpB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI;IAaxC,QAAQ,CAAC,MAAM,QAAS,WAAW,KAAG,IAAI,CAExC;IAEF;;4EAEwE;IACxE,GAAG,IAAI,UAAU;IAIjB;mFAC+E;IAC/E,WAAW,IAAI,UAAU;CAOzB;AAYD;;;;;;;;;gFASgF;AAChF,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,UAAU,GAAG,MAAM,CAqB3D;AAED,0EAA0E;AAC1E,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAW9D;AAED,2CAA2C;AAC3C,MAAM,WAAW,YAAY;IAC5B,2DAA2D;IAC3D,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,6BAA6B;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;;oFAEgF;IAChF,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;CACxC;AAED,4CAA4C;AAC5C,MAAM,WAAW,aAAa;IAC7B;;;8BAG0B;IAC1B,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,CAC/B,GAAG,EAAE,GAAG,EACR,KAAK,EAAE,gBAAgB,EACvB,GAAG,EAAE,UAAU,EACf,IAAI,CAAC,EAAE,aAAa,GAClB,YAAY,CAcd"}
@@ -0,0 +1,176 @@
1
+ import { Brand, TypedArrayTag } from '../../type_primitives/index.cjs';
2
+ export type ComponentID = Brand<number, "component_id">;
3
+ export declare const asComponentId: (value: number) => ComponentID;
4
+ /** Core schema type: maps field names to typed array tags. */
5
+ export type ComponentSchema = Readonly<Record<string, TypedArrayTag>>;
6
+ /** Compile-time tag → TypedArray mapping. */
7
+ export type TagToTypedArray = {
8
+ f32: Float32Array;
9
+ f64: Float64Array;
10
+ i8: Int8Array;
11
+ i16: Int16Array;
12
+ i32: Int32Array;
13
+ u8: Uint8Array;
14
+ u16: Uint16Array;
15
+ u32: Uint32Array;
16
+ };
17
+ /** Maps schema fields to their value object: { x: number, y: number }. */
18
+ export type FieldValues<S extends ComponentSchema> = {
19
+ readonly [K in keyof S]: number;
20
+ };
21
+ /**
22
+ * Values argument tuple for attaching a component of schema `S` — empty for a
23
+ * tag, a single optional partial-values map otherwise. A tag schema
24
+ * (`Record<string, never>`) would otherwise degenerate: `keyof` an
25
+ * index-signature record is `string`, so `Partial<FieldValues<…>>` collapses to
26
+ * `Record<string, number>` and `Frozen({ anything: 1 })` compiles. The
27
+ * conditional forbids values on tags outright; a schema-erased `ComponentDef`
28
+ * falls into the valued branch, so untyped call sites keep the loose shape.
29
+ */
30
+ export type ValuesArg<S extends ComponentSchema> = S extends Record<string, never> ? [] : [values?: Partial<FieldValues<S>>];
31
+ /**
32
+ * `FieldValues` for APIs where the values object is required and complete
33
+ * (`addComponent`'s valued overload, the host-seam `SpawnEntry`). Guards the
34
+ * same tag degeneracy as `ValuesArg`: a tag accepts only the empty object
35
+ * (`Record<string, never>` — every property typed `never`), so
36
+ * `addComponent(e, Frozen, { x: 1 })` is a compile error while the
37
+ * tag-overload-less call sites can still pass `{}`.
38
+ */
39
+ export type CompleteFieldValues<S extends ComponentSchema> = S extends Record<string, never> ? Record<string, never> : FieldValues<S>;
40
+ /**
41
+ * Trailing-argument tuple for the attach surfaces (`ctx.commands.add`'s
42
+ * explicit-values form, `ctx.addSparse`): a tag takes NO values argument, a valued schema REQUIRES a
43
+ * complete one. Encodes the former tag/valued overload pair as one signature,
44
+ * which the typed system seam needs — its `def` parameter is a single
45
+ * declared-access-constrained type param, and per-schema overloads would
46
+ * re-introduce the tag-vs-valued split on top of it.
47
+ */
48
+ export type AttachValuesArg<S extends ComponentSchema> = S extends Record<string, never> ? [] : [values: CompleteFieldValues<S>];
49
+ /** Maps schema fields to their specific typed array columns. */
50
+ export type ColumnsForSchema<S extends ComponentSchema> = {
51
+ readonly [K in keyof S]: TagToTypedArray[S[K]];
52
+ };
53
+ /**
54
+ * Mutable sibling of `ColumnsForSchema` — the field-keyed column group handed
55
+ * back by `eachChunk`'s `cols.mut(def)` (no `readonly`, since the whole point
56
+ * is in-place writes). The change-tick is stamped once when the group is
57
+ * resolved, so the per-row loop is plain typed-array indexing (§eachChunk).
58
+ */
59
+ export type MutableColumnsForSchema<S extends ComponentSchema> = {
60
+ [K in keyof S]: TagToTypedArray[S[K]];
61
+ };
62
+ declare const __schema: unique symbol;
63
+ /**
64
+ * A component handle. **Callable**: `Pos({ x, y })` produces a `Bundle` (omitted
65
+ * fields zero-fill at attach), so one varargs shape — `spawn(Pos({x,y}),
66
+ * Vel({vx:1}), IsEnemy)` — replaces the older incompatible attach shapes. A bare
67
+ * `Pos` (uncalled) still stands in for a tag / all-zero values wherever a
68
+ * `BundleOrDef` is accepted.
69
+ *
70
+ * The numeric component id lives on `.id` (registration order). Consumers treat
71
+ * the def as an opaque handle; internal code reads `def.id` where it needs the
72
+ * raw id. The call signature's `S` makes `ComponentDef<{x:"f64"}>` distinct from
73
+ * `ComponentDef<{vx:"f64"}>`.
74
+ *
75
+ * The optional `[__schema]` slot never exists at runtime; it re-states `S` in a
76
+ * covariant tuple position so that a TAG def type is not a universal assignment
77
+ * sink. Through the call signature alone every def is assignable to
78
+ * `ComponentDef<Record<string, never>>` (the tag callable takes no required
79
+ * args and any `Bundle` satisfies its return), which would let ONE tag in a
80
+ * system's declared-access union admit every component at compile time
81
+ * (§typestate — `DeclaredRead` and friends in system.ts). With the slot, a
82
+ * valued schema is not assignable to the tag schema (`"f64" ⊀ never`), while
83
+ * schema erasure (`ComponentDef<S>` → bare `ComponentDef`) still works because
84
+ * every schema is assignable to `ComponentSchema`.
85
+ *
86
+ * Build one with `makeComponentDef`; never construct by hand.
87
+ */
88
+ export interface ComponentDef<S extends ComponentSchema = ComponentSchema> {
89
+ (...values: ValuesArg<S>): Bundle<S>;
90
+ readonly id: ComponentID;
91
+ readonly [__schema]?: [S];
92
+ }
93
+ /**
94
+ * Recover a def's schema type: `SchemaOf<typeof Pos>` is `{x:"f64", y:"f64"}`.
95
+ * The typed `SystemContext` methods (§typestate) constrain their `def`
96
+ * parameter to the system's declared-access union and use this to type the
97
+ * field argument, in place of taking `ComponentDef<S>` directly.
98
+ */
99
+ export type SchemaOf<D> = D extends ComponentDef<infer S extends ComponentSchema> ? S : never;
100
+ /**
101
+ * `unknown` if `D` is one of the query's declared terms, else an error tuple —
102
+ * the query-seam sibling of system.ts's `DeclaredRead` (§typestate,
103
+ * POLISH_AUDIT #6). `Query.eachChunk`'s cursor and `ArchetypeView`'s column
104
+ * accessors intersect this into their `def` parameter so fetching a component
105
+ * that is NOT a term of the iterating query fails to compile (previously
106
+ * caught only by the dev-mode access check, and only when the system's
107
+ * declaration was itself wrong). Same encoding rules as the system asserts:
108
+ * stable `D extends ComponentDef<any>` constraints keep instantiations
109
+ * mutually assignable, and the conditional keys on the signature's own `D`.
110
+ */
111
+ export type DeclaredQueryTerm<Defs extends readonly ComponentDef<any>[], D> = [D] extends [
112
+ Defs[number]
113
+ ] ? unknown : ["component is not a term of this query — add it with .and(...)", D];
114
+ /** Options bag accepted by `registerComponent` / `registerSparseComponent`. */
115
+ export interface ComponentRegisterOptions {
116
+ /** Debug label for diagnostics — errors then read `'Pos' (component 5)`
117
+ * instead of `component 5`. Never affects behaviour, layout, or hashing. */
118
+ readonly name?: string;
119
+ }
120
+ /**
121
+ * Schema-erased component handle — just the `.id`. Internal, schema-agnostic
122
+ * code (access checks, dirty-set notes, field-id lookup) takes this instead of
123
+ * `ComponentDef`: the callable signature makes `ComponentDef<S>` *invariant* in
124
+ * `S` (a generic `ComponentDef<S>` is not assignable to `ComponentDef`), but
125
+ * every `ComponentDef<S>` is assignable to `ComponentHandle` because it carries
126
+ * `.id`. Use it wherever only the id is read.
127
+ */
128
+ export type ComponentHandle = {
129
+ readonly id: ComponentID;
130
+ };
131
+ /**
132
+ * Mint a callable `ComponentDef` for a freshly-registered component id. The
133
+ * returned function produces a `Bundle` when called (`Pos({x,y})`) and carries
134
+ * its numeric id on a non-enumerable `.id` (invisible to spreads / `JSON`).
135
+ * The single cast bridges the function value to the branded handle type — the
136
+ * `.id` is installed at runtime by `defineProperty` (§10c branded-ID boundary).
137
+ */
138
+ export declare function makeComponentDef<S extends ComponentSchema>(id: ComponentID): ComponentDef<S>;
139
+ export interface Bundle<S extends ComponentSchema = ComponentSchema> {
140
+ readonly def: ComponentDef<S>;
141
+ readonly values: Partial<FieldValues<S>>;
142
+ }
143
+ /** Either a populated bundle or a bare def (tag / all-fields-zero). */
144
+ export type BundleOrDef<S extends ComponentSchema = ComponentSchema> = Bundle<S> | ComponentDef<S>;
145
+ /** Pair a component def with field values to attach. Omitted fields zero-fill;
146
+ * a tag def takes no values (see `ValuesArg`). */
147
+ export declare function bundle<S extends ComponentSchema>(def: ComponentDef<S>, ...values: ValuesArg<S>): Bundle<S>;
148
+ /** Extract the def from a `BundleOrDef`. A bare def is the callable; a bundle a plain object. */
149
+ export declare function bundleDef(item: BundleOrDef): ComponentDef;
150
+ /** Extract the values from a `BundleOrDef` (a bare def contributes no values). */
151
+ export declare function bundleValues(item: BundleOrDef): Readonly<Record<string, number>>;
152
+ /**
153
+ * Compile-time readonly view of a typed array column. Blocks index writes at
154
+ * the type layer.
155
+ *
156
+ * **Advisory, not a runtime barrier:** the value behind this type is the live
157
+ * mutable backing `TypedArray` (`Archetype.getColumnRead` returns
158
+ * `.buf as unknown as ReadonlyColumn`), so a §10c-policed cast can still write
159
+ * through. For mutation use the mutable `Archetype.getColumn` (tick-bumping).
160
+ * Enforced by the escape-hatch lint, not the runtime.
161
+ */
162
+ export interface ReadonlyColumn {
163
+ readonly [index: number]: number;
164
+ readonly length: number;
165
+ }
166
+ /**
167
+ * Compile-time readonly view of a Uint32Array. Blocks index writes at the type
168
+ * layer. **Advisory, not a runtime barrier** — same caveat as `ReadonlyColumn`:
169
+ * the underlying value is the live mutable buffer.
170
+ */
171
+ export interface ReadonlyUint32Array {
172
+ readonly [index: number]: number;
173
+ readonly length: number;
174
+ }
175
+ export {};
176
+ //# sourceMappingURL=component.d.ts.map