@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,718 @@
1
+ import { Store } from './store.js';
2
+ import { FrameTraceSink } from './frame_trace.js';
3
+ import { Archetype, ArchetypeView } from './archetype.js';
4
+ import { EntityID } from './entity.js';
5
+ import { ComponentDef, ComponentHandle, ComponentID, MutableColumnsForSchema, ColumnsForSchema, AttachValuesArg, SchemaOf, DeclaredQueryTerm } from './component.js';
6
+ import { SparseComponentDef, SparseComponentID, SparseSchemaOf } from './sparse_store.js';
7
+ import { RelationDef } from './relation.js';
8
+ import { SystemAccess, DeclaredRead, DeclaredWrite, DeclaredAdd, DeclaredRemove, DeclaredSparseRead, DeclaredSparseWrite, DeclaredRelationRead, DeclaredRelationWrite, DeclaredResourceRead, DeclaredResourceWrite, DespawnArg } from './system.js';
9
+ import { ComponentRef, ReadonlyComponentRef } from './ref.js';
10
+ import { EventKey, EventReader, EventShape, SignalKey } from './event.js';
11
+ import { ResourceKey, ResourceValueOf } from './resource.js';
12
+ import { BitSet } from '../../type_primitives/index.js';
13
+ /** The query-driver seam on `Store` — the typed contract behind the
14
+ * underscore members `ecs.ts` and the query internals reach (M1). `Store`
15
+ * implements this; when the cache/driver layer is extracted (M2/H1) the
16
+ * interface retargets at the collaborator without touching consumers.
17
+ * `_tick` / `_trace` are deliberately mutable: `ECS.update()` advances the
18
+ * change tick and `ECS.setTrace` installs the sink through this seam. */
19
+ export interface QueryHost {
20
+ /** Change tick — advanced by `ECS.update()` each frame. */
21
+ _tick: number;
22
+ /** Dev-only frame-trace sink (`ECS.setTrace`); always null in prod. */
23
+ _trace: FrameTraceSink | null;
24
+ /** True once any component observer opted into per-entity dirty tracking —
25
+ * gates `_noteSet` at every write site. */
26
+ readonly _anyDirtyTracked: boolean;
27
+ /** Bumped when an archetype crosses empty↔non-empty — cached query
28
+ * archetype lists rebuild when their observed epoch is stale (#327). */
29
+ readonly _queryDirtyEpoch: number;
30
+ /** Record a per-entity onSet dirty mark for `def` (gated by
31
+ * `_anyDirtyTracked` at the call site). */
32
+ _noteSet(def: ComponentHandle, eid: EntityID): void;
33
+ /** Dev-only: buffered event count across dirty channels (mid-update emit
34
+ * detection in `ECS.update()`). */
35
+ _devBufferedEventCount(): number;
36
+ /** Second query-match path: sparse-term intersection (#469 / ADR-0011). */
37
+ _forEachSparseMatch(include: BitSet, exclude: BitSet | null, anyOf: BitSet | null, sparseInclude: readonly SparseComponentID[], sparseExclude: readonly SparseComponentID[], denseArchetypes: readonly Archetype[], cb: (entityId: EntityID) => void, includeDisabled: boolean): void;
38
+ /** Third query-match path: the `(*, T)` wildcard (#579). */
39
+ _forEachRelationTargetMatch(target: EntityID, include: BitSet, exclude: BitSet | null, anyOf: BitSet | null, sparseInclude: readonly SparseComponentID[], sparseExclude: readonly SparseComponentID[], includeDisabled: boolean, cb: (entityId: EntityID) => void): void;
40
+ /** Fourth query-match path: hierarchy depth ordering (#581). */
41
+ _forEachHierarchyMatch(include: BitSet, exclude: BitSet | null, anyOf: BitSet | null, sparseInclude: readonly SparseComponentID[], sparseExclude: readonly SparseComponentID[], denseArchetypes: readonly Archetype[], relation: RelationDef, maxDepth: number, includeDisabled: boolean, cb: (entityId: EntityID) => void): void;
42
+ }
43
+ export interface QueryCacheEntry {
44
+ includeMask: BitSet;
45
+ excludeMask: BitSet | null;
46
+ anyOfMask: BitSet | null;
47
+ query: Query<any>;
48
+ }
49
+ /** One owner for every query-resolution cache (M2). Previously the dedup
50
+ * bucket map lived on `ECS` while `Query` populated eleven composition maps
51
+ * declared on the resolver interface — ownership split across two modules.
52
+ * All entries are structural (a query is minted once per unique term set and
53
+ * lives for the world's lifetime; components and queries are never
54
+ * unregistered), so there is no invalidation lifecycle — the maps are
55
+ * append-only. Key encodings are unchanged from the pre-extraction fields.
56
+ *
57
+ * The composition maps are exposed as readonly fields (not per-kind accessor
58
+ * pairs): the mutation protocol is uniform (`get` → miss → build → `set`) and
59
+ * hot enough that composition sites keep direct map access; the invariant
60
+ * this class carries is single ownership, not access mediation. */
61
+ export declare class QueryCache {
62
+ private readonly dedup;
63
+ readonly andSingle: Map<number, Query<any>>;
64
+ readonly notSingle: Map<number, Query<any>>;
65
+ readonly anyOfSingle: Map<number, Query<any>>;
66
+ readonly changedSingle: Map<number, ChangedQuery<any>>;
67
+ readonly optionalSingle: Map<number, Query<any>>;
68
+ readonly withSparseSingle: Map<number, Query<any>>;
69
+ readonly withoutSparseSingle: Map<number, Query<any>>;
70
+ readonly withRelationSingle: Map<number, Query<any>>;
71
+ readonly withoutRelationSingle: Map<number, Query<any>>;
72
+ readonly includeDisabledSingle: Map<number, Query<any>>;
73
+ readonly hierarchySingle: Map<number, Query<any>>;
74
+ /** Dedup lookup: bucket scan with full mask equality (buckets are
75
+ * typically 1–2 entries). */
76
+ findDedup(key: number, include: BitSet, exclude: BitSet | null, anyOf: BitSet | null): QueryCacheEntry | undefined;
77
+ /** Record a freshly minted query under its dedup key. */
78
+ addDedup(key: number, entry: QueryCacheEntry): void;
79
+ }
80
+ export interface QueryResolver {
81
+ _resolveQuery(include: BitSet, exclude: BitSet | null, anyOf: BitSet | null, defs: readonly ComponentDef[]): Query<any>;
82
+ _getLastRunTick(): number;
83
+ /** Current ECS write tick — the tick `eachChunk` stamps via `cols.mut` (§eachChunk). */
84
+ _getCurrentTick(): number;
85
+ _getQueryDirtyEpoch(): number;
86
+ _nextQueryId(): number;
87
+ /** All query-resolution caches — dedup + composition (M2). One owner; see
88
+ * `QueryCache` for the per-map keying/id-space notes. */
89
+ readonly _caches: QueryCache;
90
+ /** Second query-match path (#469 / ADR-0011): drive iteration by sparse
91
+ * membership rather than the archetype mask, yielding entities — sparse
92
+ * members are scattered across archetypes, so there is no archetype-column
93
+ * span to hand back. With a sparse require term, drive from the smallest
94
+ * required store and filter; with only sparse excludes, drive the dense
95
+ * archetype list and skip excluded rows; with neither, walk dense entities.
96
+ * Only entered via `Query.forEachEntity`, so dense `forEach` never pays.
97
+ * `includeDisabled` widens the per-archetype row scan from enabled rows to
98
+ * all rows (#577). */
99
+ _forEachSparseMatch(include: BitSet, exclude: BitSet | null, anyOf: BitSet | null, sparseInclude: readonly SparseComponentID[], sparseExclude: readonly SparseComponentID[], denseArchetypes: readonly Archetype[], cb: (entityId: EntityID) => void, includeDisabled: boolean): void;
100
+ /** Backing sparse id of a relation — resolves a `(R, *)` wildcard term
101
+ * (`withRelation`, #579) to the membership store the sparse-match path
102
+ * already drives. */
103
+ _relationBackingSparseId(def: RelationDef): SparseComponentID;
104
+ /** Third query-match path (#579): `(*, T)` — drive iteration from the union of
105
+ * every relation's `sourcesOf(target)` (dedup + canonical sort), intersected
106
+ * with the dense mask + sparse terms + the enabled-row filter. Only entered via
107
+ * `Query.forEachRelatedTo`. */
108
+ _forEachRelationTargetMatch(target: EntityID, include: BitSet, exclude: BitSet | null, anyOf: BitSet | null, sparseInclude: readonly SparseComponentID[], sparseExclude: readonly SparseComponentID[], includeDisabled: boolean, cb: (entityId: EntityID) => void): void;
109
+ /** Fourth query-match path (#581): yield the matched entities (dense mask +
110
+ * sparse terms + enabled-row filter, exactly the `_forEachSparseMatch`
111
+ * intersection) in canonical **hierarchy depth order** over exclusive relation
112
+ * `relation` — depth ascending (parents before children), entity index
113
+ * ascending within a depth band. Entities deeper than `maxDepth` are skipped
114
+ * (`HIERARCHY_UNBOUNDED` = no limit). Only entered via `Query.forEachEntity`
115
+ * on a query carrying a `.hierarchy(R)` term. */
116
+ _forEachHierarchyMatch(include: BitSet, exclude: BitSet | null, anyOf: BitSet | null, sparseInclude: readonly SparseComponentID[], sparseExclude: readonly SparseComponentID[], denseArchetypes: readonly Archetype[], relation: RelationDef, maxDepth: number, includeDisabled: boolean, cb: (entityId: EntityID) => void): void;
117
+ }
118
+ /** No depth limit on a `.hierarchy(R)` term (#581) — yield every matched entity
119
+ * regardless of its depth in the tree. The default `maxDepth`. */
120
+ export declare const HIERARCHY_UNBOUNDED: number;
121
+ /** A `.hierarchy(R)` depth-ordering term (#581). Records the exclusive relation
122
+ * whose tree defines the order and the (optional) max depth to yield. Stored on
123
+ * the Query and consumed by the `forEachEntity` hierarchy match path; absent
124
+ * (`null`) for the common case. */
125
+ export interface HierarchyTerm {
126
+ /** The exclusive relation whose chain/tree defines the depth ordering. */
127
+ readonly relation: RelationDef;
128
+ /** Inclusive max depth to yield (root = 0); entities deeper than this are
129
+ * skipped. `HIERARCHY_UNBOUNDED` for no limit (bitECS `Hierarchy()` depth arg). */
130
+ readonly maxDepth: number;
131
+ }
132
+ /**
133
+ * eachChunk cursor (§eachChunk). One instance is allocated per `eachChunk`
134
+ * pass and reused across every matched archetype in that pass — only `_arch`/
135
+ * `_tick` are re-pointed per archetype, so the inner loop allocates nothing.
136
+ * Per-call (not cached on the query) so a nested `eachChunk` on the same query
137
+ * gets its own cursor and can't re-point an outer pass's position. `.mut(def)` /
138
+ * `.read(def)` resolve a whole component's columns at once into a field-keyed
139
+ * object (a per-archetype-per-component cache refreshed in place), hiding the
140
+ * change tick. Destructure the group immediately; don't retain it across calls.
141
+ */
142
+ export declare class ChunkColumns<out Defs extends readonly ComponentDef<any>[] = readonly ComponentDef<any>[]> {
143
+ /** @internal */ _arch: Archetype;
144
+ /** @internal */ _tick: number;
145
+ /** Mutable column group — `const { x, y } = cols.mut(Pos)`. Stamps the tick.
146
+ * `def` must be a term of the iterating query (POLISH_AUDIT #6). */
147
+ mut<D extends ComponentDef<any>>(def: D & DeclaredQueryTerm<Defs, D>): MutableColumnsForSchema<SchemaOf<D>>;
148
+ /** Read-only column group — `const { vx, vy } = cols.read(Vel)`. No tick bump.
149
+ * `def` must be a term of the iterating query (POLISH_AUDIT #6). */
150
+ read<D extends ComponentDef<any>>(def: D & DeclaredQueryTerm<Defs, D>): ColumnsForSchema<SchemaOf<D>>;
151
+ }
152
+ export declare class Query<Defs extends readonly ComponentDef[]> {
153
+ private readonly _archetypes;
154
+ readonly _defs: Defs;
155
+ private readonly _resolver;
156
+ readonly _include: BitSet;
157
+ private readonly _exclude;
158
+ private readonly _anyOf;
159
+ private _nonEmptyArchetypes;
160
+ private _lastSeenEpoch;
161
+ readonly _id: number;
162
+ readonly _sparseInclude: readonly SparseComponentID[];
163
+ readonly _sparseExclude: readonly SparseComponentID[];
164
+ readonly _optional: readonly ComponentID[];
165
+ readonly _includeDisabled: boolean;
166
+ readonly _relationIncludes: readonly RelationDef[];
167
+ readonly _relationExcludes: readonly RelationDef[];
168
+ readonly _hierarchy: HierarchyTerm | null;
169
+ constructor(archetypes: Archetype[], defs: Defs, resolver: QueryResolver, include: BitSet, exclude: BitSet | null, anyOf: BitSet | null, id: number, sparseInclude?: readonly SparseComponentID[], sparseExclude?: readonly SparseComponentID[], optional?: readonly ComponentID[], includeDisabled?: boolean, relationIncludes?: readonly RelationDef[], relationExcludes?: readonly RelationDef[], hierarchy?: HierarchyTerm | null);
170
+ /** Guard the dense-only methods (`count` / `forEach` / `archetype_count`)
171
+ * against a query carrying sparse terms. These walk the dense archetype
172
+ * list and never consult `_sparseInclude` / `_sparseExclude`, so on a
173
+ * sparse-derived query they'd **fail open** — returning the unfiltered dense
174
+ * result instead of the sparse-filtered one. Throw in `DEV` (compiled
175
+ * out of prod) steering the caller to `forEachEntity`, the only path that
176
+ * honors sparse membership (#469). Mirrors `ChangedQuery`'s dev-guard on its
177
+ * include-mask invariant. */
178
+ private _assertDenseOnly;
179
+ /** Whether this query carries only dense terms — the precondition for the
180
+ * archetype-walk fast paths (`count`, `firstEntity`, `singleEntity`). */
181
+ private _isDenseOnly;
182
+ /** First matching entity, or `undefined` when the query matches none — the
183
+ * singleton read (`player`, `camera`) without hand-rolling a forEach +
184
+ * closure capture (POLISH_AUDIT M8). Dense-only queries answer from the
185
+ * first non-empty archetype in O(archetypes); queries with sparse /
186
+ * relation / hierarchy terms fall back to a full `forEachEntity` walk.
187
+ * "First" is iteration order, not spawn order — with more than one match
188
+ * the pick is arbitrary (use `singleEntity` to assert uniqueness). */
189
+ firstEntity(): EntityID | undefined;
190
+ /** The query's one matching entity. Dev-throws `QUERY_NOT_SINGLETON` when
191
+ * the match count is 0 or >1 — the singleton assertion for entities that
192
+ * must be unique (player, camera). Prod skips the count and returns the
193
+ * first match (`undefined` if none). */
194
+ singleEntity(): EntityID;
195
+ /** Count for non-dense queries — full `forEachEntity` walk. */
196
+ private _countViaWalk;
197
+ /** Number of matching archetypes (including empty ones). */
198
+ get archetypeCount(): number;
199
+ /** Total entity count across all matching archetypes — enabled rows only by
200
+ * default, or all rows when `includeDisabled()` (#577). Reads the partition
201
+ * fields directly (not the archetype's flag-dependent `entityCount`
202
+ * getter). */
203
+ get entityCount(): number;
204
+ get archetypes(): readonly ArchetypeView<Defs>[];
205
+ /** Carry this query's non-dense terms — optional fetch-if-present (#575) and
206
+ * sparse membership (#469) — onto a freshly composed dense query. `and` /
207
+ * `not` / `anyOf` build the new dense mask via `_resolveQuery`, which is
208
+ * keyed on the mask alone and so hands back a query carrying NONE of these
209
+ * terms; before #592 that silently dropped them, making composition
210
+ * order-dependent (`q.optional(V).and(H)` lost `V`; `q.and(H).optional(V)`
211
+ * kept it). When this query carries no non-dense terms (the common case)
212
+ * `base` is already correct and returned as-is, preserving the mask-cached
213
+ * singleton with zero allocation. Otherwise re-derive on top of `base`'s dense
214
+ * state, threading the terms forward so composition is symmetric regardless of
215
+ * order. Reading `base`'s private fields is allowed — same-class instance. */
216
+ private _carryNondense;
217
+ /** Extend required component set. Returns a new (cached) Query. */
218
+ and<D extends ComponentDef[]>(...comps: D): Query<[...Defs, ...D]>;
219
+ /** @internal — cold cache-miss path for single-arg `and`, split out (#649) so
220
+ * the hot `and` body is just key-compute + cache hit. The miss path runs once
221
+ * per unique composition, then every repeat is a cache hit; keeping it out of
222
+ * line shrinks `and`'s inlined footprint when several composes share one hot
223
+ * function (the `query_compose` shape). Same rationale for `_notMiss` /
224
+ * `_anyOfMiss` / `_changedMiss`. */
225
+ private _andMiss;
226
+ /** Exclude archetypes that have any of these components. */
227
+ without(...comps: ComponentDef[]): Query<Defs>;
228
+ /** @internal — cold cache-miss path for single-arg `not` (#649); see `_andMiss`. */
229
+ private _notMiss;
230
+ /** Require a sparse component (#469): match only entities that hold it,
231
+ * across every archetype. A sparse term doesn't touch the dense mask, so
232
+ * the returned (cached) query reuses this one's live archetype list; it is
233
+ * iterated via `forEachEntity`, never `forEach` (sparse members are
234
+ * scattered within archetypes, so there is no SoA column span to yield). */
235
+ withSparse(...defs: SparseComponentDef[]): Query<Defs>;
236
+ /** One-id `withSparse` composition, cached on `(parent_id, sparseId)` in
237
+ * the resolver's shared single-term map. Both the single- and multi-arg public
238
+ * forms fold over this, so all sparse-require composition is deduplicated. */
239
+ private _withSparseOne;
240
+ /** Exclude a sparse component (#469): drop entities that hold it. Same
241
+ * dense-list reuse and `forEachEntity` iteration as `withSparse`. */
242
+ withoutSparse(...defs: SparseComponentDef[]): Query<Defs>;
243
+ /** One-id `withoutSparse` composition, cached on `(parent_id, sparseId)`. The
244
+ * multi-arg form folds over this (#497) — mirrors `_withSparseOne`. */
245
+ private _withoutSparseOne;
246
+ /** Build a derived query carrying new sparse terms. Reuses this query's
247
+ * dense state by reference — the masks are never mutated in place (`and` /
248
+ * `not` / `anyOf` copy before mutating), and `_archetypes` is the same
249
+ * live array the store appends to, so the derived query stays live too.
250
+ * Carries the existing `_optional` terms through unchanged (the two axes
251
+ * compose). */
252
+ private _deriveSparse;
253
+ /** Require the `(R, *)` wildcard (#579): match only sources that hold **any**
254
+ * target under relation `R`. "Has any `(R, *)` pair" is exactly membership in
255
+ * R's backing sparse store (exclusive `{target}` row / multi tag), so this is a
256
+ * relation-typed front door over `withSparse` — it pushes R's backing sparse
257
+ * id onto `_sparseInclude` and reuses the `forEachEntity` sparse-match path
258
+ * (insertion order; canonical sorting is reserved for `stateHash`/snapshot, and
259
+ * costs 4–5× here for no determinism benefit — see the §579 bench report).
260
+ * Membership semantics: each source once; fetch its targets with
261
+ * `ctx.targetsOf(e, R)`. Requires `relationReads: [R]` (checked at iteration).
262
+ * Cached per `(parent_id, relation_id)` like the sparse terms (#497). */
263
+ withRelation(...defs: RelationDef[]): Query<Defs>;
264
+ private _withRelationOne;
265
+ /** Exclude the `(R, *)` wildcard (#579): drop sources that hold any target
266
+ * under `R`. Mirror of `withRelation` on the exclude side (pushes R's
267
+ * backing sparse id onto `_sparseExclude`). */
268
+ withoutRelation(...defs: RelationDef[]): Query<Defs>;
269
+ private _withoutRelationOne;
270
+ /** Build a derived query carrying new relation-wildcard terms. Threads the
271
+ * backing-sparse ids (which the driver actually consumes) plus the relation
272
+ * ids (which only the `DEV` access check consumes), reusing the dense /
273
+ * optional / disabled state by reference — same rationale as `_deriveSparse`. */
274
+ private _deriveRelation;
275
+ /** Order this query's matched entities in **hierarchy depth order** over the
276
+ * exclusive relation `R` — parents before children — and (optionally) drop any
277
+ * deeper than `maxDepth` (#581; flecs `cascade` / bitECS `Hierarchy()`). The
278
+ * matched *set* is unchanged (still the dense mask + sparse + `(R, *)` + disabled
279
+ * terms); `.hierarchy(R)` only **reorders** + depth-limits it, so an entity with
280
+ * no `R`-parent is a root at depth 0 and still yielded (first). The canonical
281
+ * order is depth ascending, then **entity index ascending within each depth
282
+ * band** — a total, insertion-order-independent order (identical across lockstep
283
+ * peers), produced by an O(K) radix on the entity index, never a comparator sort.
284
+ *
285
+ * Iterate with `forEachEntity`: members scatter across archetypes, so there is
286
+ * no SoA column span — `forEach` / `count` reject a hierarchy query (like a
287
+ * sparse term). **Exclusive relations only** (matches the traversal constraint
288
+ * #474); a multi relation throws `RELATION_MODE_MISMATCH` at iteration, and a
289
+ * cycle is a loud `RELATION_CYCLE` in `DEV` (a safe break in production).
290
+ * Requires `relationReads: [R]` (checked at iteration). Carried through
291
+ * `and`/`not`/`anyOf` like the sparse terms (`_carryNondense`).
292
+ *
293
+ * `Defs` is unchanged — `R` is an ordering, not a required component (like
294
+ * `not` / `anyOf`). Returns a new query; the unbounded form is cached. */
295
+ hierarchy(relation: RelationDef<"exclusive">, maxDepth?: number): Query<Defs>;
296
+ /** Build a derived query carrying a hierarchy ordering term. Reuses this
297
+ * query's dense / sparse / optional / disabled / relation-wildcard state by
298
+ * reference (the matched set is unchanged) — same rationale as `_deriveSparse`. */
299
+ private _deriveHierarchy;
300
+ /** Assert every `(R, *)` wildcard term on this query was declared in the
301
+ * system's `relationReads` (#579 / #496). Iteration-time (`forEachEntity` /
302
+ * `forEachRelatedTo`), not construction-time, so it is robust to queries
303
+ * built outside a system — same rationale as the data-op checks. `DEV` only;
304
+ * outside a system `checkRelationRead` is a no-op. */
305
+ private _checkRelationAccess;
306
+ /** Iterate every source related to `target` under **any** relation — the
307
+ * `(*, T)` wildcard (#579) — intersected with this query's dense + sparse +
308
+ * `(R, *)` + disabled predicate, each source yielded once in ascending-EntityID
309
+ * order (the `sourcesOf` / `sourcesOfAny` convention). `target` is supplied
310
+ * here rather than as a chained term because it is a runtime `EntityID`: baking
311
+ * it into a cached `Query` would key the cache on a recycled value and churn
312
+ * query-ids, and `(*, T)` is the rare/cold shape. Composes with
313
+ * `withRelation` / `withSparse` / dense terms on the receiver. Reads
314
+ * every relation's reverse index, so the system must declare
315
+ * `relationReads: [ANY_RELATION]` (plus `[R]` for any composed `withRelation`).
316
+ * Cold/structural — not a per-tick hot loop over many targets. */
317
+ forEachRelatedTo(target: EntityID, cb: (entityId: EntityID) => void): void;
318
+ /** Add optional fetch-if-present terms (#575). Does NOT narrow the matched
319
+ * set — the dense mask is untouched, so iteration still spans archetypes with
320
+ * and without each `T`. Read each column per archetype span via
321
+ * `arch.getOptionalColumnRead(T, field)` (column when present, `undefined`
322
+ * when absent). `.optional(T)` is the *declaration* that authorizes that fetch:
323
+ * inside `forEach`, `getOptionalColumnRead` throws in `DEV` if `T` was
324
+ * not declared here (#592) — the read-side analog of `reads:[T]`, which is also
325
+ * still required for access coverage (both checks fire, even on the absent
326
+ * span). The term is carried through `and`/`not`/`anyOf` (see
327
+ * `_carryNondense`), so it survives composition in any order. Returns a new
328
+ * (cached) Query.
329
+ *
330
+ * `Defs` is unchanged (the optional `T` is not a required component, like
331
+ * `not` / `anyOf`); column types come from the accessor's own generics. */
332
+ optional(...defs: ComponentDef[]): Query<Defs>;
333
+ /** One-id `optional` composition, cached on `(parent_id << 16) | cid` in the
334
+ * resolver's shared single-term map (dense cid <= 128, same packing as the
335
+ * `and` / `not` / `anyOf` caches). */
336
+ private _optionalOne;
337
+ /** Build a derived query carrying new optional terms. Reuses this query's
338
+ * dense state by reference (the matched set is unchanged) and carries the
339
+ * existing sparse terms through unchanged — same rationale as `_deriveSparse`. */
340
+ private _deriveOptional;
341
+ /** Opt this query back in to disabled entities (#577). By default a query
342
+ * excludes disabled entities (the iteration bound `arch.entityCount` is the
343
+ * enabled-row count). The returned (cached) query spans disabled rows too:
344
+ * `forEach` publishes the all-rows flag so the SoA loop's `arch.entityCount`
345
+ * reports `length`, and `count`/`forEachEntity` widen accordingly. Does NOT
346
+ * touch the dense mask, so it reuses this query's live archetype list and is
347
+ * carried through `and`/`not`/`anyOf` like the sparse/optional terms. */
348
+ includeDisabled(): Query<Defs>;
349
+ forEach(cb: (arch: ArchetypeView<Defs>) => void): void;
350
+ /** @internal — cold `includeDisabled` wrapper for `forEach` (#577), split out
351
+ * (#649) so the all-rows flag dance (`_setIterAllRows` + try/finally) stays
352
+ * out of `forEach`'s inlined hot body. The default (enabled-only) query never
353
+ * reaches here, so V8 leaves this uninlined and `forEach` shrinks accordingly. */
354
+ private _forEachIncludeDisabled;
355
+ /**
356
+ * Per-archetype destructured column iteration (§eachChunk) — the flecs
357
+ * `run()` / koota `useStores` model, and the recommended hot-path default for
358
+ * mutating systems:
359
+ *
360
+ * q.eachChunk((cols, count) => {
361
+ * const { x, y } = cols.mut(Pos); // whole group, tick stamped inside
362
+ * const { vx, vy } = cols.read(Vel); // read-only group
363
+ * for (let i = 0; i < count; i++) { x[i] += vx[i] * dt; y[i] += vy[i] * dt; }
364
+ * });
365
+ *
366
+ * vs the raw path it replaces (per-field `getColumn` + manual `ecsTick`
367
+ * thread + `entityCount` loop). It folds away: per-field fetches (one call
368
+ * per component), the `getColumn`/`getColumnRead` choice (→ `.mut`/`.read`),
369
+ * the manual tick arg (hidden in `.mut`), and the `.length`-vs-`entityCount`
370
+ * corruption trap (`count` is `entityCount`). It is also the only mutable
371
+ * column accessor reachable through the iteration path — the read-only
372
+ * `ArchetypeView` from `forEach` deliberately omits the mutable `getColumn`.
373
+ * The SoA inner loop is byte-identical, and the per-archetype group objects
374
+ * are cached (zero per-archetype allocation). One `ChunkColumns` cursor is
375
+ * allocated per pass and reused across that pass's archetypes. Honours
376
+ * `includeDisabled()` exactly like `forEach` (the bound widens to the
377
+ * disabled tail); dense-only like `forEach` (sparse/relation/hierarchy terms
378
+ * throw in `DEV` — iterate those with `forEachEntity`).
379
+ */
380
+ eachChunk(cb: (cols: ChunkColumns<Defs>, count: number) => void): void;
381
+ /** @internal — shared body for `eachChunk`'s default and `includeDisabled`
382
+ * paths. The `ChunkColumns` cursor is allocated per call (a 2-field object whose
383
+ * cost doesn't scale with the per-row work) rather than cached on the query, so
384
+ * a nested `eachChunk` on the SAME query gets its own cursor instead of
385
+ * re-pointing the outer pass's `_arch`/`_tick`. The per-(archetype, component)
386
+ * column-group caches that actually matter for allocation live on the
387
+ * `Archetype`, untouched. */
388
+ private _eachChunkInner;
389
+ /**
390
+ * Early-exit iteration: like `forEach`, but stops as soon as `cb` returns
391
+ * `true`, and returns whether any callback did. The predicate analog for
392
+ * "does any matching row satisfy X?" — without it, callers hand-rolled a
393
+ * `query.archetypes` walk (re-implementing the empty-archetype skip) just
394
+ * to be able to `return` mid-scan. Deliberately a separate method:
395
+ * honouring return values on `forEach`'s existing `=> void` callback
396
+ * would silently change behaviour for arrow-expression bodies that happen
397
+ * to return a truthy value.
398
+ */
399
+ forEachUntil(cb: (arch: ArchetypeView<Defs>) => boolean): boolean;
400
+ /** @internal — shared body for `forEachUntil`'s default and
401
+ * `includeDisabled` paths. Same dev-mode optional-term scope as
402
+ * `forEach` (#592). */
403
+ private _forEachUntilInner;
404
+ /** @internal — the `includeDisabled` delegate for `forEach` (#577). The
405
+ * default (enabled-only) path inlines this body directly into `forEach`
406
+ * (#608) to dodge a megamorphic delegate hop; this copy survives only for the
407
+ * rare all-rows path, which needs the `_setIterAllRows` try/finally wrap. */
408
+ private _forEachInner;
409
+ /** Iterate the entities this query matches, yielding each `EntityID`
410
+ * (#469 — the sparse-membership match path). Use this whenever the query
411
+ * carries a `withSparse` / `withoutSparse` term: members are scattered
412
+ * across archetypes, so there is no SoA column span to hand back — read
413
+ * fields via `ctx.getField` (dense) or `ctx.getSparseField` (sparse) on
414
+ * the yielded entity. A dense-only query also works here (it walks its
415
+ * archetypes' entity ids), but prefer `forEach` for the SoA hot loop.
416
+ *
417
+ * Iteration is read-mostly: mutating the *driving* sparse component's
418
+ * membership mid-iteration is unsafe. The walk drives off the store's live
419
+ * key array, so **adding** the driving component (the store `push`es a new
420
+ * key, which the `i < length` loop then visits) and **removing** it (the
421
+ * store swap-pops, shifting the index list under the walk) both corrupt the
422
+ * traversal. This is sharper than for dense `forEach`: `ctx.addSparse` /
423
+ * `ctx.addRelation` apply *immediately* (no archetype transition to defer),
424
+ * so unlike a deferred dense `addComponent` the mutation lands in the live
425
+ * array at once. Buffer such edits and apply them after the walk. */
426
+ forEachEntity(cb: (entityId: EntityID) => void): void;
427
+ /** @internal — used by ChangedQuery. Rebuild non-empty archetype list if the
428
+ * Store has bumped its dirty epoch since our last rebuild, return cached result.
429
+ *
430
+ * Rebuild allocates a *fresh* array and swaps it in rather than truncating
431
+ * the cached one in place (#431). `forEach`/`count`/`ChangedQuery.forEach`
432
+ * bind the returned array once and walk it; an in-place `dst.length = 0` +
433
+ * re-push would corrupt that walk if the query is re-entrantly iterated —
434
+ * i.e. the callback runs an immediate-mode mutation that crosses a
435
+ * 0↔non-zero entity boundary on the *same* Query (bumping the epoch) and
436
+ * then re-enters here via a nested `forEach`/`count`. Building fresh hands
437
+ * the inner call its own array and leaves the outer iterator's snapshot
438
+ * intact, so each archetype is visited exactly once. Cost is one array
439
+ * allocation per epoch advance (rare — only on boundary crossings); the
440
+ * steady-state path returns the cached array with zero allocation. In-system
441
+ * iteration never triggers a rebuild mid-loop: deferred mutations settle the
442
+ * epoch during `flushStructural`, between systems. */
443
+ _nonEmpty(): Archetype[];
444
+ /** @internal — cold rebuild path for `_nonEmpty`, split out (#649) so the
445
+ * hot `_nonEmpty` body is just an epoch check + cached return. Keeping the
446
+ * filter loops here shrinks `_nonEmpty`'s inlined bytecode footprint, which
447
+ * matters when several composed queries iterate inside one hot function (the
448
+ * `query_compose` shape): the leaner `_nonEmpty` keeps `forEach` under V8's
449
+ * per-function cumulative inlining budget. */
450
+ private _rebuildNonEmpty;
451
+ /** Require at least one of these components. */
452
+ anyOf(...comps: ComponentDef[]): Query<Defs>;
453
+ /** @internal — cold cache-miss path for single-arg `anyOf` (#649); see `_andMiss`. */
454
+ private _anyOfMiss;
455
+ /** Create a ChangedQuery that filters archetypes by change tick.
456
+ *
457
+ * Granularity is **archetype**, not row: the `_changedTick[cid]` is
458
+ * bumped per archetype on any write into that component's column
459
+ * (`Archetype._changedTick` in archetype.ts). A 1-row write in a
460
+ * 1000-row archetype trips `forEach` on the whole archetype next tick.
461
+ * Use cases that need row-level granularity should compare per-row
462
+ * state explicitly inside the callback.
463
+ *
464
+ * The returned ChangedQuery is composable (M6): `and`/`without`/`anyOf`/
465
+ * `optional` refine it further, so `q.changed(Pos).without(Dead)` works — and
466
+ * is the same set as `q.without(Dead).changed(Pos)`. */
467
+ changed(...defs: ComponentDef[]): ChangedQuery<Defs>;
468
+ /** @internal — cold cache-miss path for single-arg `changed` (#649); see `_andMiss`. */
469
+ private _changedMiss;
470
+ /** @internal — reads lastRunTick from the resolver (ECS). */
471
+ _ctxLastRunTick(): number;
472
+ }
473
+ export declare class QueryBuilder {
474
+ private readonly _resolver;
475
+ constructor(_resolver: QueryResolver);
476
+ with<T extends ComponentDef[]>(...defs: T): Query<T>;
477
+ }
478
+ /**
479
+ * A `BundleOrDef` whose def is constrained to the enclosing system's declared
480
+ * add surface (§typestate). The bundle branch restates `Bundle`'s shape with
481
+ * the def slot narrowed — intersecting `Bundle<any> & { def: … }` instead
482
+ * would put two `ComponentDef` instantiations in one intersection, which TS
483
+ * relates leniently (see system.ts §typestate notes).
484
+ *
485
+ * The outer conditional is a deliberate no-op (`[D] extends [unknown]` is
486
+ * always true): it makes the variance of `D` — and therefore of the access
487
+ * param `A` threaded through `Commands` / `SystemContext` — UNMEASURABLE to
488
+ * the compiler. A measurable (plain-union) definition here gets `A` marked
489
+ * reliably contravariant, variance-based comparison then rejects
490
+ * `SystemContext<Narrow> → SystemContext` without the structural fallback,
491
+ * and every helper taking a bare `SystemContext` stops accepting typed
492
+ * contexts. Unmeasurable variance forces the structural path, where class
493
+ * methods compare bivariantly and the conversion holds.
494
+ */
495
+ export type DeclaredBundleOrDef<D> = [D] extends [unknown] ? D | {
496
+ readonly def: D;
497
+ readonly values: Readonly<Partial<Record<string, number>>>;
498
+ } : never;
499
+ /**
500
+ * Deferred structural-command facade (§ctx.commands — Bevy `Commands`).
501
+ * Namespaces the deferred structural ops so the call site is self-documenting:
502
+ * `ctx.commands.add(e, …)` is *always* deferred (applied at the phase flush),
503
+ * ending the collision where `ecs.addComponent` (immediate) and a bare
504
+ * `ctx.addComponent` (deferred) would share a name with opposite timing. Takes
505
+ * varargs callable bundles, so one shape — `commands.spawn(bundle(Pos,{x,y}), bundle(Vel,{vx:1}))`
506
+ * — serves spawn and add. This is the ONLY deferred surface: the bare
507
+ * `ctx.addComponent` / `ctx.removeComponent` / `ctx.disable` / `ctx.enable`
508
+ * duplicates were removed in 0.5.0, completing the receiver-implies-timing
509
+ * rule (`ecs.*` immediate, `ctx.commands.*` deferred) that 0.5.0 started for
510
+ * spawn/despawn.
511
+ *
512
+ * `A` narrows the def-taking methods to the enclosing system's declared access
513
+ * (§typestate, system.ts); the default is fully permissive.
514
+ *
515
+ * `out A` (declared covariance) is deliberate: every use of `A` sits inside a
516
+ * declared-access conditional, whose variance the compiler cannot measure —
517
+ * left unannotated, the measured verdict rejects `Commands<Narrow> →
518
+ * Commands` (the direction every permissive consumer needs). Covariance is
519
+ * the honest direction: a context with MORE declared access is usable where
520
+ * one with less is expected. The checks themselves are per-instantiation, so
521
+ * the annotation does not weaken them.
522
+ */
523
+ export declare class Commands<out A extends SystemAccess = SystemAccess> {
524
+ private readonly store;
525
+ constructor(store: Store);
526
+ /** Spawn from bundles. Create is immediate (the id is returned now); the
527
+ * component attaches are deferred to the phase flush — so until that flush the
528
+ * entity exists in its empty/partial archetype and a query running later in
529
+ * the same phase can observe it half-built. (Same semantics as
530
+ * `ctx.commands.spawn()` + `ctx.addComponent`; fully-deferred id-reservation
531
+ * spawn, à la Bevy, is a separate follow-up.) */
532
+ spawn(...items: DeclaredBundleOrDef<A["add"]>[]): EntityID;
533
+ /** Attach bundles to an existing entity (deferred). Bundles zero-fill
534
+ * omitted fields. */
535
+ add(entityId: EntityID, ...items: DeclaredBundleOrDef<A["add"]>[]): this;
536
+ /** Explicit complete-values attach (deferred) — the compile-checked shape
537
+ * where a typo'd or missing field is a compile error, mirroring the
538
+ * immediate `ecs.addComponent(e, def, values)`. Tags take no values
539
+ * argument (`AttachValuesArg`). */
540
+ add<D extends ComponentDef<any>>(entityId: EntityID, def: D & DeclaredAdd<A, D>, ...values: AttachValuesArg<SchemaOf<D>>): this;
541
+ /** Remove a component (deferred). */
542
+ remove<D extends ComponentDef<any>>(entityId: EntityID, def: D & DeclaredRemove<A, D>): this;
543
+ /** Destroy an entity (deferred). */
544
+ despawn(entityId: DespawnArg<A>): this;
545
+ /** Buffer `entityId` to be disabled at the phase flush (idempotent, #577).
546
+ * Deferred because a toggle is an in-archetype row swap, which would corrupt
547
+ * a `forEach` SoA loop iterating that archetype if applied mid-system (it
548
+ * reorders the dense columns being read). A disabled entity is excluded from
549
+ * default queries; opt back in per query with `.includeDisabled()`. The
550
+ * immediate read is `ctx.isDisabled`. */
551
+ disable(entityId: EntityID): this;
552
+ /** Buffer `entityId` to be re-enabled at the phase flush (idempotent).
553
+ * Deferred for the same row-swap reason as `disable`. */
554
+ enable(entityId: EntityID): this;
555
+ }
556
+ /**
557
+ * The per-system world facade. `A` is the system's declared access surface
558
+ * (§typestate, system.ts): the config-form `registerSystem` computes it from
559
+ * the literal `reads`/`writes`/… declarations and every guarded method below
560
+ * checks its handle argument against the matching union at compile time —
561
+ * the same rules `accessCheck` enforces at runtime in `DEV`. The default
562
+ * `A = SystemAccess` is fully permissive, so a bare `SystemContext` (helper
563
+ * functions, host-side code, explicitly-annotated escape hatches) behaves
564
+ * exactly as before, and every narrowed `SystemContext<…>` is assignable to
565
+ * it.
566
+ *
567
+ * `out A` (declared covariance) is deliberate — see `Commands` above: the
568
+ * declared-access conditionals are unmeasurable to the compiler, and the
569
+ * unannotated verdict rejects exactly the `SystemContext<Narrow> →
570
+ * SystemContext` conversion the whole design depends on.
571
+ */
572
+ export declare class SystemContext<out A extends SystemAccess = SystemAccess> {
573
+ private readonly store;
574
+ lastRunTick: number;
575
+ /** Deferred structural-command facade (§ctx.commands). */
576
+ readonly commands: Commands<A>;
577
+ /** Current ECS tick. Use this for write ticks in getColumn. */
578
+ get ecsTick(): number;
579
+ /** The world's frame-trace sink (ADR-0030), or `null`. Lets the schedule
580
+ * fire `systemStart`/`flush*` without reaching into the private store.
581
+ * Read only under `if (DEV)`; the seam is dead-code-eliminated in prod. */
582
+ get _trace(): FrameTraceSink | null;
583
+ constructor(store: Store);
584
+ isAlive(entityId: EntityID): boolean;
585
+ hasComponent(entityId: EntityID, def: ComponentDef): boolean;
586
+ getField<D extends ComponentDef<any>>(entityId: EntityID, def: D & DeclaredRead<A, D>, field: string & keyof SchemaOf<D>): number;
587
+ /** Total sibling of {@link getField}, mirroring `ecs.tryGetField`
588
+ * (POLISH_AUDIT #9): `undefined` when the entity is dead or doesn't hold
589
+ * the component, instead of a dev throw / prod garbage read. The safe way
590
+ * to probe-and-read in one call: `ctx.tryGetField(e, Health, "current") ?? 0`. */
591
+ tryGetField<D extends ComponentDef<any>>(entityId: EntityID, def: D & DeclaredRead<A, D>, field: string & keyof SchemaOf<D>): number | undefined;
592
+ setField<D extends ComponentDef<any>>(entityId: EntityID, def: D & DeclaredWrite<A, D>, field: string & keyof SchemaOf<D>, value: number): void;
593
+ /** Read-modify-write one field: `updateField(e, Gold, "value", v => v - cost)`
594
+ * is the one-line form of the `getField` → compute → `setField` round trip.
595
+ * Returns the written value. Same access-check and observer semantics as the
596
+ * two calls it composes (inlined here: the declared-access conditionals on
597
+ * those methods only resolve per `A` instantiation, so a body where `A` is
598
+ * still generic cannot call them without casts). */
599
+ updateField<D extends ComponentDef<any>>(entityId: EntityID, def: D & DeclaredWrite<A, D>, field: string & keyof SchemaOf<D>, fn: (current: number) => number): number;
600
+ /**
601
+ * Record an entity as changed for a component's per-entity `onSet` observer
602
+ * (#517 §1 / ADR-0013). The SoA write idiom — `const col = arch.getColumn(D,
603
+ * f, tick); col[i] = v` in a tight loop — bypasses the deferred buffer and the
604
+ * engine never sees the per-element writes, so a per-entity `onSet` consumer
605
+ * pushes the row here (the bench's winning `tick+list`: raw write + an int
606
+ * push, fired batched at the post-update detection point — never a per-element
607
+ * observable setter). No-op for components without a per-entity onSet observer.
608
+ * `setField` records automatically; this is for the hot `getColumn` loop.
609
+ */
610
+ markChanged(entityId: EntityID, def: ComponentDef): void;
611
+ /**
612
+ * Create a cached component reference for a single entity. Marks the
613
+ * component as changed (the mutable default — see `refRead` for the
614
+ * read-only variant to reach for when you are not mutating). See ref.ts.
615
+ */
616
+ ref<D extends ComponentDef<any>>(def: D & DeclaredWrite<A, D>, entityId: EntityID): ComponentRef<SchemaOf<D>>;
617
+ /**
618
+ * Create a cached read-only component reference for a single entity. Use
619
+ * this when you are not mutating. The returned `ReadonlyComponentRef<S>`
620
+ * is an *advisory* compile-time barrier (no `_changedTick` bump): the
621
+ * `readonly` typing blocks field writes at the type layer, but the
622
+ * underlying accessor shares its prototype with `ref()` and can still be
623
+ * written through a §10c-policed cast. See ref.ts.
624
+ */
625
+ refRead<D extends ComponentDef<any>>(def: D & DeclaredRead<A, D>, entityId: EntityID): ReadonlyComponentRef<SchemaOf<D>>;
626
+ /** Whether `entityId` is currently disabled (immediate read). Toggling is
627
+ * deferred — `ctx.commands.disable` / `ctx.commands.enable` (#577). */
628
+ isDisabled(entityId: EntityID): boolean;
629
+ /** Tags take no values argument; valued schemas require a complete one. */
630
+ addSparse<D extends SparseComponentDef<any>>(entityId: EntityID, def: D & DeclaredSparseWrite<A, D>, ...values: AttachValuesArg<SparseSchemaOf<D>>): this;
631
+ removeSparse<D extends SparseComponentDef<any>>(entityId: EntityID, def: D & DeclaredSparseWrite<A, D>): this;
632
+ hasSparse(entityId: EntityID, def: SparseComponentDef): boolean;
633
+ getSparseField<D extends SparseComponentDef<any>>(entityId: EntityID, def: D & DeclaredSparseRead<A, D>, field: string & keyof SparseSchemaOf<D>): number;
634
+ setSparseField<D extends SparseComponentDef<any>>(entityId: EntityID, def: D & DeclaredSparseWrite<A, D>, field: string & keyof SparseSchemaOf<D>, value: number): void;
635
+ /** Add a `(R, tgt)` pair to `src` (exclusive replaces, multi adds). */
636
+ addRelation<D extends RelationDef>(src: EntityID, def: D & DeclaredRelationWrite<A, D>, tgt: EntityID): this;
637
+ /** Remove a `(R, tgt)` pair from `src`; for multi, omitting `tgt` removes all. */
638
+ removeRelation<D extends RelationDef>(src: EntityID, def: D & DeclaredRelationWrite<A, D>, tgt?: EntityID): this;
639
+ /** The single target of `src` under an exclusive relation, or `undefined`. */
640
+ targetOf<D extends RelationDef<"exclusive">>(src: EntityID, def: D & DeclaredRelationRead<A, D>): EntityID | undefined;
641
+ /** All targets of `src` under `R`, ascending by id. */
642
+ targetsOf<D extends RelationDef>(src: EntityID, def: D & DeclaredRelationRead<A, D>): EntityID[];
643
+ /** Sources pointing at `tgt` under `R` (the reverse index), ascending by id.
644
+ * `(entity, def)` order, matching `targetOf` / `targetsOf`. */
645
+ sourcesOf<D extends RelationDef>(tgt: EntityID, def: D & DeclaredRelationRead<A, D>): EntityID[];
646
+ /** Whether `src` holds any pair under `R`. */
647
+ hasRelation(src: EntityID, def: RelationDef): boolean;
648
+ /** Flush all deferred changes: structural (add/remove) first, then
649
+ * destructions. Republishes archetype row counts into the SAB
650
+ * descriptor at the end so any WASM scan running in the next phase
651
+ * sees fresh `row_count` fields. This is one of two publish sites —
652
+ * `ECS.update()` also republishes once at tick start (see PATTERNS.md
653
+ * §60), covering host-side mutations between updates. The publish walks
654
+ * descriptors only — it doesn't touch column data — and benches at
655
+ * sub-microsecond per archetype, so paying it once per phase boundary
656
+ * is materially cheaper than the pre-#306 pattern of paying it per
657
+ * WASM-using system per tick. After #336 the descriptor walk is gated
658
+ * on a dirty flag, so read-only phases skip the walk entirely. */
659
+ flush(): void;
660
+ /**
661
+ * Emit an event (or a payload-less signal) onto its channel. The event is
662
+ * visible to every system that runs *later* in the same `update()` and is
663
+ * cleared at the tick's tail — events live exactly one tick, there is no
664
+ * ack/consume. The channel must have been registered at world setup via
665
+ * `ecs.events.register(key, fields)` / `registerSignal(key)`.
666
+ *
667
+ * @example
668
+ * const Damaged = eventKey<{ target: EntityID; amount: number }>("Damaged");
669
+ * ecs.events.register(Damaged, ["target", "amount"]);
670
+ * // inside a system:
671
+ * ctx.emit(Damaged, { target: e, amount: 10 });
672
+ */
673
+ emit(key: SignalKey): void;
674
+ emit<S extends EventShape<S>>(key: EventKey<S>, values: NoInfer<S>): void;
675
+ /**
676
+ * Read this tick's events on a channel. Returns an SoA reader over
677
+ * everything emitted *earlier in the same `update()`* — order systems so
678
+ * readers run after emitters, or they see an empty reader.
679
+ *
680
+ * @example
681
+ * const dmg = ctx.read(Damaged); // SoA columns, one per field
682
+ * for (let i = 0; i < dmg.length; i++) {
683
+ * applyDamage(dmg.target[i], dmg.amount[i]);
684
+ * }
685
+ */
686
+ read<S extends EventShape<S>>(key: EventKey<S>): EventReader<S>;
687
+ resource<K extends ResourceKey<any>>(key: K & DeclaredResourceRead<A, K>): ResourceValueOf<K>;
688
+ setResource<K extends ResourceKey<any>>(key: K & DeclaredResourceWrite<A, K>, value: ResourceValueOf<NoInfer<K>>): void;
689
+ /** Drop a resource mid-tick (#798). A lifecycle mutation, so it is access-
690
+ * checked as a *write* — the system must declare the key in `resourceWrites`,
691
+ * which serialises it against readers/writers of the same resource. Fails
692
+ * closed on a missing key. */
693
+ removeResource<K extends ResourceKey<any>>(key: K & DeclaredResourceWrite<A, K>): void;
694
+ hasResource<T>(key: ResourceKey<T>): boolean;
695
+ }
696
+ export declare class ChangedQuery<Defs extends readonly ComponentDef[]> {
697
+ private readonly _query;
698
+ private readonly _changedIds;
699
+ constructor(query: Query<Defs>, changedIds: number[]);
700
+ /** Also require these components (mirrors `Query.and`). */
701
+ and<D extends ComponentDef[]>(...comps: D): ChangedQuery<[...Defs, ...D]>;
702
+ /** Exclude archetypes holding any of these (mirrors `Query.without`). */
703
+ without(...comps: ComponentDef[]): ChangedQuery<Defs>;
704
+ /** Require at least one of these (mirrors `Query.anyOf`). */
705
+ anyOf(...comps: ComponentDef[]): ChangedQuery<Defs>;
706
+ /** Permit optional-component data access in the loop (mirrors `Query.optional`). */
707
+ optional(...defs: ComponentDef[]): ChangedQuery<Defs>;
708
+ forEach(cb: (arch: ArchetypeView<Defs>) => void): void;
709
+ /** @internal — cold `includeDisabled` wrapper (#577), split out of `forEach`
710
+ * (#649) so the all-rows flag dance stays out of the inlined hot body. */
711
+ private _forEachIncludeDisabled;
712
+ /** @internal — the `includeDisabled` delegate for `forEach` (#577). The
713
+ * default path inlines this body directly into `forEach` (#608) to dodge a
714
+ * megamorphic delegate hop; this copy survives only for the rare all-rows
715
+ * path, which needs the `_setIterAllRows` try/finally wrap. */
716
+ private _forEachInner;
717
+ }
718
+ //# sourceMappingURL=query.d.ts.map