@idleflowgames/anotherecs 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/dist/index.js +113 -49
- package/dist/index.js.map +1 -1
- package/dist/spatial-hash.d.ts +12 -2
- package/package.json +14 -12
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/bitmask.ts","../src/command-buffer.ts","../src/events.ts","../src/incremental-query.ts","../src/migration.ts","../src/query.ts","../src/schedule.ts","../src/serialize.ts","../src/store.ts","../src/spatial-hash.ts","../src/types.ts","../src/world.ts"],"sourcesContent":["// Bitmask: opt-in per-entity component signature index\n// Enabled per World via `enableBitmask()`. A derived mirror of dense-store\n// membership that accelerates O(1) `hasMask` / O(words) `hasAllMask` tests; the\n// dense stores remain the data home. set/clear are idempotent, commutative bit\n// ops, so a row's final state depends only on which (entity, component) pairs are\n// members, never the order they were applied.\n//\n// Layout: `rows` is one flat Uint32Array of `capacity * wordsPerEntity`; entity\n// `e` owns `[e * words, (e + 1) * words)`. `words` grows lazily as higher\n// component ids are first set, keeping the common small-id case at 1–2 words.\n// Component ids are assigned at module load, so width stabilizes after the first\n// back-fill and never changes on the per-frame path.\n\nexport class Bitmask {\n private readonly capacity: number;\n private words = 1;\n private rows: Uint32Array;\n\n constructor(capacity: number) {\n this.capacity = capacity;\n this.rows = new Uint32Array(capacity * 1);\n }\n\n /** Current words per entity (>= 1). */\n get wordsPerEntity(): number {\n return this.words;\n }\n\n // Grow the per-entity stride so `compId` is addressable, re-laying-out every\n // existing row at the wider stride. Only triggers when a never-before-seen\n // high component id is first set, never on the hot path.\n private ensureWidth(compId: number): void {\n const need = (compId >>> 5) + 1;\n if (need <= this.words) return;\n const next = new Uint32Array(this.capacity * need);\n const old = this.words;\n for (let e = 0; e < this.capacity; e++) {\n next.set(this.rows.subarray(e * old, (e + 1) * old), e * need);\n }\n this.rows = next;\n this.words = need;\n }\n\n /** Set bit `compId` for entity `e`. Grows word width if needed. */\n set(e: number, compId: number): void {\n this.ensureWidth(compId);\n this.rows[e * this.words + (compId >>> 5)] |= (1 << (compId & 31)) >>> 0;\n }\n\n /** Clear bit `compId` for entity `e`. */\n clear(e: number, compId: number): void {\n const w = compId >>> 5;\n if (w >= this.words) return;\n this.rows[e * this.words + w] &= ~((1 << (compId & 31)) >>> 0);\n }\n\n /** Test bit `compId` for entity `e`. */\n has(e: number, compId: number): boolean {\n const w = compId >>> 5;\n if (w >= this.words) return false;\n return (this.rows[e * this.words + w] & ((1 << (compId & 31)) >>> 0)) !== 0;\n }\n\n /** Clear every bit for entity `e` (despawn path). */\n clearEntity(e: number): void {\n this.rows.fill(0, e * this.words, (e + 1) * this.words);\n }\n\n /**\n * Build a packed query signature: the OR of each def's single bit, sized to\n * span the highest component id in `compIds`. Bit positions are static per\n * component id, so the returned signature is valid forever and can be cached.\n */\n signature(compIds: readonly number[]): Uint32Array {\n let maxWord = 0;\n for (let i = 0; i < compIds.length; i++) {\n const w = compIds[i] >>> 5;\n if (w > maxWord) maxWord = w;\n }\n const sig = new Uint32Array(maxWord + 1);\n for (let i = 0; i < compIds.length; i++) {\n const id = compIds[i];\n sig[id >>> 5] |= (1 << (id & 31)) >>> 0;\n }\n return sig;\n }\n\n /** Whether entity `e`'s row has all bits in `sig` set. */\n hasAll(e: number, sig: Uint32Array): boolean {\n for (let w = 0; w < sig.length; w++) {\n const want = sig[w];\n if (want === 0) continue;\n if (w >= this.words) return false;\n // `>>> 0` normalizes the AND result to unsigned: a component on bit 31 of\n // its word makes `want` include 0x80000000, and JS `&` yields a SIGNED\n // int32, so without this the masked value compares as negative and a true\n // match wrongly returns false. `want` is already unsigned (Uint32Array).\n if ((this.rows[e * this.words + w] & want) >>> 0 !== want) return false;\n }\n return true;\n }\n}\n","// CommandBuffer: opt-in deferred structural mutation\n// Records add / remove / addComponent / despawn and replays them in strict record\n// order at a single point chosen by the consumer: an explicit\n// `world.applyCommands(buf)`, or a Schedule with a `commandBuffer` (applied at\n// each group boundary). Systems enqueue mutations that take effect only after\n// iteration finishes, removing mid-iteration structural-mutation hazards.\n//\n// World, Schedule, and this module reference each other as types only, so there\n// is no runtime import cycle.\n//\n// Caller rules (determinism contract):\n// - Commands replay FIFO (index 0..n-1). The effect is a pure function of the\n// record sequence: no map iteration, sort, RNG, or time.\n// - Do NOT record into a buffer during its own flushInto. The supported entry\n// points (a Schedule group boundary or applyCommands) run no system during\n// apply, so this cannot arise in supported usage.\n// - addComponent stores its `data` Partial by reference and merges at apply\n// time; do not mutate `data` between record and apply (the same\n// read-only-until-applied contract the query result arrays carry).\n// - spawn is NOT buffered: it must return an id synchronously. A system spawns\n// immediately, then records component adds against the returned id, keeping id\n// allocation and recycle order identical to the immediate path.\n// - A recorded despawn defers to the next world.flush() (like world.despawn): a\n// later recorded add writes, then flush() strips it, identical to the\n// equivalent immediate world.* calls.\n\nimport type { ComponentType, Entity, PooledComponentType } from \"./types\";\nimport type { World } from \"./world\";\n\n/**\n * A recorded structural mutation. Discriminated by a numeric `kind` (0..3) so the\n * apply switch is a jump table and no string is allocated. Tag plus payload only,\n * no behavior, so the buffer is a pure ordered log that World replays verbatim.\n */\nexport type Command =\n | { kind: 0; type: ComponentType<unknown>; entity: Entity; data: unknown } // add\n | { kind: 1; type: ComponentType<unknown>; entity: Entity } // remove\n | {\n kind: 2;\n type: PooledComponentType<object>;\n entity: Entity;\n data?: object;\n } // addComponent\n | { kind: 3; entity: Entity }; // despawn\n\n/**\n * Records add/remove/addComponent/despawn and replays them, in record order, when\n * the consumer flushes the buffer (via `world.applyCommands(buf)` or a Schedule\n * configured with `commandBuffer`). Mirrors the World mutation surface so call\n * sites read identically to immediate mutation.\n */\nexport class CommandBuffer {\n private readonly commands: Command[] = [];\n\n /** Queue `world.add(entity, type, data)` for replay. Mirrors World.add. */\n add<T>(entity: Entity, type: ComponentType<T>, data: T): this {\n this.commands.push({\n kind: 0,\n type: type as ComponentType<unknown>,\n entity,\n data,\n });\n return this;\n }\n\n /** Queue `world.remove(entity, type)` for replay. Mirrors World.remove. */\n remove<T>(entity: Entity, type: ComponentType<T>): this {\n this.commands.push({\n kind: 1,\n type: type as ComponentType<unknown>,\n entity,\n });\n return this;\n }\n\n /**\n * Queue `world.addComponent(entity, def, data)` for replay. The factory/pool\n * acquisition and the Object.assign merge happen at APPLY time, not record time,\n * so a pooled object is never aliased while still recorded. The `data` Partial\n * is held by reference; do not mutate it between record and apply.\n */\n addComponent<T extends object>(\n entity: Entity,\n def: PooledComponentType<T>,\n data?: Partial<T>,\n ): this {\n this.commands.push({\n kind: 2,\n type: def as unknown as PooledComponentType<object>,\n entity,\n data: data as object | undefined,\n });\n return this;\n }\n\n /** Queue `world.despawn(entity)` for replay (it then defers to the next flush). */\n despawn(entity: Entity): this {\n this.commands.push({ kind: 3, entity });\n return this;\n }\n\n /** Number of queued commands (for tests/metrics). */\n size(): number {\n return this.commands.length;\n }\n\n /** Whether any command is queued. */\n isEmpty(): boolean {\n return this.commands.length === 0;\n }\n\n /** Drop all queued commands without applying them. */\n clear(): void {\n this.commands.length = 0;\n }\n\n /**\n * Apply every queued command against `world` in record order, then clear.\n * Equivalent to calling the matching `world.*` method for each, in order.\n * Idempotent on an empty buffer (no-op). Reused after apply (the array is\n * truncated, not reallocated).\n *\n * Iterated forward, index-based; record order is the contract. Each branch\n * delegates to the existing World method verbatim, so all version-bump /\n * pooling / deferred-despawn semantics are inherited unchanged.\n */\n flushInto(world: World): void {\n const commands = this.commands;\n for (let i = 0; i < commands.length; i++) {\n const c = commands[i];\n switch (c.kind) {\n case 0:\n world.add(c.entity, c.type, c.data);\n break;\n case 1:\n world.remove(c.entity, c.type);\n break;\n case 2:\n world.addComponent(c.entity, c.type, c.data);\n break;\n case 3:\n world.despawn(c.entity);\n break;\n }\n }\n this.commands.length = 0;\n }\n}\n","// Typed Event Bus: frame-scoped event queues\n// Events emitted during a frame are readable by later systems in the same frame.\n// Reads are non-destructive, so many systems may read one queue per frame. The\n// consumer owns the frame lifecycle: clearAll() empties every queue at frame\n// start, and the framework never emits or clears events on its own.\n\nimport type { EventType } from \"./types\";\n\nexport class EventBus {\n private readonly queues = new Map<number, unknown[]>();\n\n /** Emit an event. Subsequent systems can read it this frame. */\n emit<T>(type: EventType<T>, data: T): void {\n let queue = this.queues.get(type.id);\n if (!queue) {\n queue = [];\n this.queues.set(type.id, queue);\n }\n queue.push(data);\n }\n\n /**\n * Read all events of a given type emitted this frame. Non-destructive: many\n * systems may read the same queue in one frame. Returns the LIVE internal queue;\n * do not mutate it or retain it across frames (clearAll() empties it in place).\n * Use {@link readCopy} for a retainable snapshot.\n */\n read<T>(type: EventType<T>): ReadonlyArray<T> {\n return (this.queues.get(type.id) as T[] | undefined) ?? _empty;\n }\n\n /** Like {@link read} but returns a fresh array safe to mutate or retain across frames. */\n readCopy<T>(type: EventType<T>): T[] {\n const queue = this.queues.get(type.id) as T[] | undefined;\n return queue === undefined ? [] : queue.slice();\n }\n\n /** Check if any events of a given type were emitted this frame. */\n has<T>(type: EventType<T>): boolean {\n const queue = this.queues.get(type.id);\n return queue !== undefined && queue.length > 0;\n }\n\n /** Clear all event queues. Called at frame start. */\n clearAll(): void {\n for (const queue of this.queues.values()) {\n queue.length = 0;\n }\n }\n}\n\nconst _empty: ReadonlyArray<never> = [];\n","// Incremental query: opt-in, maintained not rebuilt\n// Maintains its match set incrementally as components are added/removed (and on\n// despawn), instead of rebuilding via a full smallest-store scan on the next\n// access after a mutation. This avoids the per-frame O(n) rebuild the\n// version-cached QueryEngine pays for a query that mutates and re-queries the\n// same components every frame.\n//\n// How it works: the World indexes incremental queries by component id and calls\n// `reconcile(entity)` on every add/remove of a membership component (with /\n// without / any). reconcile rechecks membership in O(terms) and adds/removes the\n// entity from a dense match list backed by a sparse `pos` index: the store's own\n// swap-delete bookkeeping, one level up. `maybe` components never change\n// membership, so they skip reconcile; `each()` reads their values live and\n// `results()` refreshes them lazily.\n//\n// Determinism: match-list order is append-on-match, swap-delete-on-unmatch, a\n// pure function of the operation sequence, but DIFFERENT from the rebuild path's\n// smallest-store-dense order. Hence opt-in: a consumer chooses it per hot query\n// and accepts that order, while `query` / `compileQuery` / `select` keep their\n// rebuild order and caching. A single boolean gates the World's hooks.\n\nimport type { YieldSlot } from \"./query\";\nimport type { ComponentStore } from \"./store\";\nimport type { Entity, QueryResult } from \"./types\";\n\n/** The minimal store-access surface (mirrors the QueryEngine's Queryable). */\nexport interface IncrementalAccess {\n isAlive(entity: Entity): boolean;\n storeIfPresent(id: number): ComponentStore<unknown> | undefined;\n}\n\ntype EachFn = (entity: Entity, ...components: unknown[]) => void;\n\nexport class IncrementalQuery {\n /** Required component ids. */\n readonly withIds: number[];\n /** Excluded component ids. */\n readonly withoutIds: number[];\n /** Optional component ids (yielded, never constrain membership). */\n readonly maybeIds: number[];\n /** `any(...)` groups: at least one member of each must be present. */\n readonly anyGroups: number[][];\n /** Declaration-ordered yield slots (with + maybe). */\n readonly yieldPlan: YieldSlot[];\n /**\n * Components whose add/remove must trigger a reconcile: with ∪ without ∪ any.\n * NOT maybe (it never changes membership). The World registers the query under\n * exactly these ids.\n */\n readonly membershipDeps: number[];\n\n // Dense match list + sparse entity->index (-1 if absent), mirroring the store.\n private readonly entities: Entity[] = [];\n private readonly pos: Int32Array;\n // Bumped whenever reconcile adds or removes a member; drives results() reuse.\n private membershipVersion = 0;\n\n // Reused per-call buffers (one allocation per query arity, not per entity).\n private readonly yieldStores: (ComponentStore<unknown> | undefined)[] = [];\n private readonly scratch: unknown[];\n\n // Maintained results() tuple cache: rebuilt over the (already maintained)\n // entities list only when membership changed or a yielded store changed.\n private cachedResults: QueryResult<unknown[]>[] = [];\n private resultsBuiltAt = -1;\n private readonly yieldDepVersions: number[];\n private readonly access: IncrementalAccess;\n\n constructor(\n access: IncrementalAccess,\n capacity: number,\n withIds: number[],\n withoutIds: number[],\n maybeIds: number[],\n anyGroups: number[][],\n yieldPlan: YieldSlot[],\n ) {\n this.access = access;\n this.withIds = withIds;\n this.withoutIds = withoutIds;\n this.maybeIds = maybeIds;\n this.anyGroups = anyGroups;\n this.yieldPlan = yieldPlan;\n const deps = new Set<number>(withIds);\n for (let i = 0; i < withoutIds.length; i++) deps.add(withoutIds[i]);\n for (let g = 0; g < anyGroups.length; g++)\n for (let j = 0; j < anyGroups[g].length; j++) deps.add(anyGroups[g][j]);\n this.membershipDeps = [...deps];\n this.pos = new Int32Array(capacity).fill(-1);\n this.scratch = new Array(1 + yieldPlan.length);\n this.yieldDepVersions = new Array(yieldPlan.length).fill(-1);\n }\n\n /** Whether `entity` satisfies every with/without/any term and is alive. */\n private matches(entity: number): boolean {\n if (!this.access.isAlive(entity as Entity)) return false;\n for (let i = 0; i < this.withIds.length; i++) {\n const s = this.access.storeIfPresent(this.withIds[i]);\n if (s === undefined || !s.has(entity as Entity)) return false;\n }\n for (let i = 0; i < this.withoutIds.length; i++) {\n const s = this.access.storeIfPresent(this.withoutIds[i]);\n if (s?.has(entity as Entity)) return false;\n }\n for (let g = 0; g < this.anyGroups.length; g++) {\n const group = this.anyGroups[g];\n let satisfied = false;\n for (let j = 0; j < group.length; j++) {\n const s = this.access.storeIfPresent(group[j]);\n if (s?.has(entity as Entity)) {\n satisfied = true;\n break;\n }\n }\n if (!satisfied) return false;\n }\n return true;\n }\n\n /**\n * Bring `entity`'s membership in line with `matches()`. Called by the World on\n * any membership-component add/remove for the entity, or on despawn. O(terms).\n */\n reconcile(entity: number): void {\n const should = this.matches(entity);\n const at = this.pos[entity];\n if (should && at === -1) {\n this.pos[entity] = this.entities.length;\n this.entities.push(entity as Entity);\n this.membershipVersion++;\n } else if (!should && at !== -1) {\n const last = this.entities.length - 1;\n const lastEntity = this.entities[last] as number;\n this.entities[at] = lastEntity as Entity;\n this.pos[lastEntity] = at;\n this.entities.length = last;\n this.pos[entity] = -1;\n this.membershipVersion++;\n }\n }\n\n /**\n * One-time full population, for compiling against an already-populated world.\n * Scans the smallest required store and reconciles each of its entities.\n */\n rebuildFromStores(): void {\n this.clear();\n let smallest = this.access.storeIfPresent(this.withIds[0]);\n if (smallest === undefined) return; // withIds[0]'s store absent => no matches\n for (let i = 1; i < this.withIds.length; i++) {\n const s = this.access.storeIfPresent(this.withIds[i]);\n if (s === undefined) return; // a required store is absent => no matches\n if (smallest === undefined || s.size() < smallest.size()) smallest = s;\n }\n if (smallest === undefined || smallest.size() === 0) return;\n const ents = smallest.iterEntities();\n for (let i = 0; i < ents.length; i++) this.reconcile(ents[i] as number);\n }\n\n /** Drop the whole match set (World.clear()). */\n clear(): void {\n for (let i = 0; i < this.entities.length; i++) {\n this.pos[this.entities[i] as number] = -1;\n }\n this.entities.length = 0;\n this.membershipVersion++;\n }\n\n count(): number {\n return this.entities.length;\n }\n\n /** The live match list (deterministic incremental order). Read-only. */\n view(): readonly Entity[] {\n return this.entities;\n }\n\n // Resolve the store for each yield slot into the reused `yieldStores` buffer.\n private resolveYieldStores(): void {\n const stores = this.yieldStores;\n const { yieldPlan } = this;\n stores.length = 0;\n for (let i = 0; i < yieldPlan.length; i++) {\n stores.push(this.access.storeIfPresent(yieldPlan[i].id));\n }\n }\n\n /**\n * Zero-rebuild iteration over the maintained match set. The callback must NOT\n * add/remove a membership component on a visited entity: that mutates the live\n * match list mid-iteration (swap-delete) and skips/double-visits; use\n * {@link results} for a stable snapshot. The generic lane shares one scratch\n * buffer, so do not re-enter this query's each() from within the callback.\n */\n each(fn: EachFn): void {\n const ents = this.entities;\n if (ents.length === 0) return;\n this.resolveYieldStores();\n const { yieldStores, yieldPlan } = this;\n // Fast lanes: all-required (no maybe), small arity; values via getUnsafe.\n if (this.maybeIds.length === 0 && yieldPlan.length <= 2) {\n if (yieldPlan.length === 1) {\n const s0 = yieldStores[0];\n if (s0 === undefined) return;\n for (let i = 0; i < ents.length; i++)\n fn(ents[i], s0.getUnsafe(ents[i]));\n return;\n }\n const s0 = yieldStores[0];\n const s1 = yieldStores[1];\n if (s0 === undefined || s1 === undefined) return;\n for (let i = 0; i < ents.length; i++) {\n const e = ents[i];\n fn(e, s0.getUnsafe(e), s1.getUnsafe(e));\n }\n return;\n }\n // Generic lane: reused scratch; optional slots via get (=> value|undefined).\n const scratch = this.scratch;\n for (let i = 0; i < ents.length; i++) {\n const e = ents[i];\n scratch[0] = e;\n for (let k = 0; k < yieldPlan.length; k++) {\n const s = yieldStores[k];\n scratch[1 + k] =\n s === undefined\n ? undefined\n : yieldPlan[k].optional\n ? s.get(e)\n : s.getUnsafe(e);\n }\n fn.apply(undefined, scratch as never);\n }\n }\n\n // Whether any yielded store changed since the results() cache was built (an\n // object replacement or a maybe add/remove that membership didn't capture).\n private yieldDepsChanged(): boolean {\n const yieldDepVersions = this.yieldDepVersions;\n const { yieldPlan } = this;\n for (let i = 0; i < yieldPlan.length; i++) {\n const s = this.access.storeIfPresent(yieldPlan[i].id);\n const v = s === undefined ? -1 : s.version;\n if (v !== yieldDepVersions[i]) return true;\n }\n return false;\n }\n\n /**\n * Allocation-stable tuple view, rebuilt over the (already maintained) match set\n * only when membership changed or a yielded component store changed, so it\n * stays cached across mutations to UNrelated components AND across frames with\n * no relevant change. Tuples follow declaration (yield) order. Do not retain\n * the array across a structural change (the reference is swapped on rebuild).\n */\n results(): readonly QueryResult<unknown[]>[] {\n if (\n this.resultsBuiltAt === this.membershipVersion &&\n !this.yieldDepsChanged()\n )\n return this.cachedResults;\n this.resolveYieldStores();\n const { entities, yieldStores, yieldPlan, yieldDepVersions } = this;\n const out: QueryResult<unknown[]>[] = new Array(entities.length);\n for (let i = 0; i < entities.length; i++) {\n const e = entities[i];\n const tuple: QueryResult<unknown[]> = [e];\n for (let k = 0; k < yieldPlan.length; k++) {\n const s = yieldStores[k];\n tuple.push(\n s === undefined\n ? undefined\n : yieldPlan[k].optional\n ? s.get(e)\n : s.getUnsafe(e),\n );\n }\n out[i] = tuple;\n }\n this.cachedResults = out;\n this.resultsBuiltAt = this.membershipVersion;\n for (let i = 0; i < yieldPlan.length; i++) {\n const s = this.access.storeIfPresent(yieldPlan[i].id);\n yieldDepVersions[i] = s === undefined ? -1 : s.version;\n }\n return out;\n }\n}\n","// Schema migration: linear, named per-component upgrade chains\n// A pure-data module (imports only `./types` for the ComponentType token),\n// driven by the serializer's load path.\n//\n// Every snapshot / delta blob carries a per-component `_version`. On restore the\n// decoded plain value is upgraded step-by-step from its stored version to the\n// component's current version before it is written into the World. The empty\n// registry is the identity: each component is implicitly version 0 with no steps.\n//\n// Determinism: `migrate` applies `steps[storedVersion..current-1]` in ascending\n// index order: no RNG, clock, or Map iteration (the chains Map is point-lookup\n// only). A fixed save buffer + fixed registry restores to an identical World.\n// Steps MUST be pure (no globals, RNG, or I/O); a consumer contract the type\n// system cannot enforce.\n\nimport type { ComponentType } from \"./types\";\n\n/**\n * One forward step in a component's linear migration chain. Transforms a plain\n * decoded value at version `from` into the shape at version `from + 1`. Pure:\n * no World access, no I/O, no RNG, deterministic. May mutate `prev` in place and\n * return it, or return a fresh object.\n */\nexport type MigrationStep = (\n prev: Record<string, unknown>,\n) => Record<string, unknown>;\n\n/**\n * A linear, named migration chain for one component type. `currentVersion` is\n * the version the live code writes; `steps[v]` upgrades a value from version `v`\n * to `v + 1`. A chain of N steps covers versions 0..N (currentVersion === N).\n */\nexport interface ComponentMigration {\n readonly componentId: number;\n readonly componentName: string;\n readonly currentVersion: number;\n /** Length === currentVersion. steps[v] : value@v -> value@(v+1). */\n readonly steps: readonly MigrationStep[];\n}\n\n/** Thrown when a stored version cannot be upgraded to current. */\nexport class MigrationError extends Error {\n readonly componentName: string;\n readonly storedVersion: number;\n readonly currentVersion: number;\n constructor(\n componentName: string,\n storedVersion: number,\n currentVersion: number,\n detail: string,\n ) {\n super(\n `Cannot migrate component \"${componentName}\" from v${storedVersion} ` +\n `to v${currentVersion}: ${detail}`,\n );\n this.componentName = componentName;\n this.storedVersion = storedVersion;\n this.currentVersion = currentVersion;\n this.name = \"MigrationError\";\n }\n}\n\n/**\n * Registry of per-component migration chains. Consumer-owned, passed to the\n * {@link Serializer}. An empty registry treats every component as version 0\n * with a zero-step identity chain.\n */\nexport class MigrationRegistry {\n /** chains keyed by ComponentType.id */\n private readonly chains = new Map<number, ComponentMigration>();\n\n /**\n * Define the linear chain for `def`. Call once per component with the full\n * ordered step list. `steps[i]` upgrades vi -> v(i+1); currentVersion is\n * `steps.length`. Re-registering the same component id throws (chains are\n * append-only by intent; mutate the array you pass instead). Returns `this`\n * for chaining (matches `Serializer.register` / `Schedule.addGroup`).\n */\n register<T>(def: ComponentType<T>, steps: readonly MigrationStep[]): this {\n if (this.chains.has(def.id)) {\n throw new Error(`migration chain for \"${def.name}\" already registered`);\n }\n if (steps.length === 0) {\n throw new Error(\n `migration chain for \"${def.name}\" has no steps: a zero-step chain is a no-op; omit it`,\n );\n }\n this.chains.set(def.id, {\n componentId: def.id,\n componentName: def.name,\n currentVersion: steps.length,\n // Copy the array so later external mutation can't desync currentVersion.\n steps: [...steps],\n });\n return this;\n }\n\n /**\n * Current (live-code) version for a component, or 0 if no chain registered.\n * Generic in the component's data type so a concrete `ComponentType<T>` flows\n * in without a cast (a bare `ComponentType<unknown>` would force one at every\n * call site under `strictFunctionTypes`); only `def.id` is read.\n */\n currentVersion<T>(def: ComponentType<T>): number {\n return this.currentVersionById(def.id);\n }\n\n /** Current version by raw component id. */\n currentVersionById(componentId: number): number {\n return this.chains.get(componentId)?.currentVersion ?? 0;\n }\n\n /**\n * Upgrade a decoded plain value from `storedVersion` to the component's\n * current version by applying each step in order. Returns the upgraded value\n * (same object identity allowed). Throws {@link MigrationError} when\n * `storedVersion` exceeds current (a save newer than the code), is negative,\n * or is not an integer.\n */\n migrate(\n componentId: number,\n storedVersion: number,\n value: Record<string, unknown>,\n componentName?: string,\n ): Record<string, unknown> {\n const chain = this.chains.get(componentId);\n const current = chain?.currentVersion ?? 0;\n const name = componentName ?? chain?.componentName ?? String(componentId);\n // Fast path: identity, no step calls, same object reference.\n if (storedVersion === current) return value;\n if (storedVersion < 0 || !Number.isInteger(storedVersion)) {\n throw new MigrationError(\n name,\n storedVersion,\n current,\n \"version is not a non-negative integer\",\n );\n }\n if (storedVersion > current) {\n throw new MigrationError(\n name,\n storedVersion,\n current,\n \"save is newer than the running code (no downgrade path)\",\n );\n }\n if (typeof value !== \"object\" || value === null) {\n throw new MigrationError(\n name,\n storedVersion,\n current,\n \"cannot migrate a non-object value: chains require object-shaped data\",\n );\n }\n // storedVersion < current ⇒ current > 0 ⇒ a chain is registered.\n // Apply each forward step in fixed ascending index order.\n let v = value;\n for (let s = storedVersion; s < current; s++) {\n // biome-ignore lint/style/noNonNullAssertion: storedVersion < current implies the chain exists.\n const step = chain!.steps[s];\n v = step(v); // step s upgrades vS -> v(S+1)\n }\n return v;\n }\n\n /** True if no chain is registered (lets the serializer skip the migrate path). */\n get isEmpty(): boolean {\n return this.chains.size === 0;\n }\n}\n","// Query engine: cached, allocation-stable, smallest-store-first\n// The matching entity list is cached and rebuilt only on a world version bump,\n// not per call. Component object references are stable (each component is created\n// once and mutated in place), so the cached result tuples stay valid until the\n// next version bump too.\n//\n// Returned arrays are READ-ONLY and must not be retained across a structural\n// change (add/remove/despawn): the version bump rebuilds the array, so stale\n// retention is observable (the same contract as iterData()).\n\nimport type { Bitmask } from \"./bitmask\";\nimport type { ComponentStore } from \"./store\";\nimport type {\n AnyComponentType,\n AnyGroup,\n ComponentType,\n Entity,\n QueryArg,\n QueryResult,\n QueryTerm,\n} from \"./types\";\n// Query filter term builders\n// These wrap a def or group of defs to mark its role inside a QuerySpec passed\n// to `world.select(...)`. A bare `ComponentType` passed to select() is treated\n// as a required `with` term without wrapping.\n\n/** Exclude entities that have `def`. Contributes no value to the yield tuple. */\nexport function without<T>(def: ComponentType<T>): QueryTerm<T> {\n return { kind: \"without\", def };\n}\n\n/**\n * Yield `def`'s value when present, `undefined` when absent; never constrains\n * membership. Contributes a `T | undefined` slot to the yield tuple in\n * declaration order.\n */\nexport function maybe<T>(def: ComponentType<T>): QueryTerm<T> {\n return { kind: \"maybe\", def };\n}\n\n/**\n * Require at least one of `defs` to be present. Contributes no value to the\n * yield tuple. `defs` is typed {@link AnyComponentType}[] so specific component\n * types flow in without a cast.\n */\nexport function any(...defs: AnyComponentType[]): AnyGroup {\n return { kind: \"any\", defs };\n}\n\n/** One declaration-ordered yield slot: the def's id and whether it is optional. */\nexport interface YieldSlot {\n id: number;\n optional: boolean;\n}\n\n/** Normalized form of a `select()` / `compileIncremental()` argument list. */\nexport interface ParsedQuery {\n /** Required (`with`) component defs, in declaration order. */\n withDefs: ComponentType<unknown>[];\n /** Required (`with`) component ids, in declaration order. */\n withIds: number[];\n /** Excluded (`without`) component ids. */\n withoutIds: number[];\n /** Optional (`maybe`) component ids (yielded, never constrain membership). */\n maybeIds: number[];\n /** `any(...)` groups: at least one member of each must be present. */\n anyGroups: number[][];\n /** Declaration-ordered yield slots (`with` + `maybe`; without/any excluded). */\n yieldPlan: YieldSlot[];\n}\n\n/**\n * Normalize a {@link QueryArg} list (bare defs = required `with`,\n * `without(...)` / `maybe(...)` terms, and `any(...)` groups) into id arrays and\n * a declaration-ordered yield plan. Shared by {@link QueryEngine.compileSpec} and\n * `World.compileIncremental` so both accept the identical filter spec. Throws if\n * there is no required (`with`) term: driving iteration off the whole alive set\n * is an O(all-entities) scan and a determinism-order question we keep closed.\n */\nexport function parseQueryArgs(args: QueryArg[]): ParsedQuery {\n const withDefs: ComponentType<unknown>[] = [];\n const withIds: number[] = [];\n const withoutIds: number[] = [];\n const maybeIds: number[] = [];\n const anyGroups: number[][] = [];\n const yieldPlan: YieldSlot[] = [];\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n if (\"kind\" in arg) {\n if (arg.kind === \"any\") {\n const group: number[] = [];\n for (let j = 0; j < arg.defs.length; j++) group.push(arg.defs[j].id);\n anyGroups.push(group);\n } else if (arg.kind === \"without\") {\n withoutIds.push(arg.def.id);\n } else if (arg.kind === \"maybe\") {\n maybeIds.push(arg.def.id);\n yieldPlan.push({ id: arg.def.id, optional: true });\n } else {\n withDefs.push(arg.def);\n withIds.push(arg.def.id);\n yieldPlan.push({ id: arg.def.id, optional: false });\n }\n } else {\n withDefs.push(arg);\n withIds.push(arg.id);\n yieldPlan.push({ id: arg.id, optional: false });\n }\n }\n if (withDefs.length === 0) {\n throw new Error(\n \"a query needs at least one required (non-maybe, non-without) component\",\n );\n }\n return { withDefs, withIds, withoutIds, maybeIds, anyGroups, yieldPlan };\n}\n\n/** The minimal World surface the query engine reads. */\nexport interface Queryable {\n isAlive(entity: Entity): boolean;\n /** The store for a component id, or undefined if none exists yet (no lazy create). */\n storeIfPresent(id: number): ComponentStore<unknown> | undefined;\n /**\n * The opt-in per-entity component bitmask index, or null when disabled. When\n * present, `rebuildEntities` replaces its per-store `has()` probe loop with a\n * single signature AND.\n */\n bitmask(): Bitmask | null;\n}\n\ninterface QueryCache {\n key: string;\n ids: number[];\n // Stores resolved in call order, refreshed alongside `entities`. Invariant:\n // whenever `entities.length > 0` this holds exactly `ids.length` live stores\n // in call order. A query that cannot match leaves both `entities` empty and\n // `stores` short, so store access is always gated on a non-empty `entities`.\n stores: ComponentStore<unknown>[];\n entities: Entity[];\n results: QueryResult<unknown[]>[];\n // Build epochs. `entitiesVersion` is bumped each time the entity list is\n // rebuilt; `resultsVersion` records the epoch at which the tuple array was\n // last built, so `each` and `query`/`results` can reuse matching work.\n entitiesVersion: number;\n resultsVersion: number;\n // Every store id this cache reads (required `with` ∪ without ∪ any ∪ maybe),\n // and a snapshot of their per-store versions at the last entities rebuild. The\n // cache rebuilds only when one of THESE stores changed; a mutation to an\n // unrelated component no longer invalidates this query.\n depIds: number[];\n depVersions: number[];\n // Cached required-components bitmask signature for the accelerated rebuild\n // (static per cache; computed once the bitmask is first observed). Null unused.\n reqSig: Uint32Array | null;\n // A bare-def cache leaves these arrays empty and keeps `spec` false. They are\n // populated only when a spec carries a without/maybe/any term.\n spec: boolean;\n // Required (`with`) defs, in declaration order. `ids`/`stores` mirror these\n // for pure-with paths, so smallest-store iteration and the fast `each` switch\n // keep reading `ids`/`stores`.\n withoutIds: number[];\n maybeIds: number[];\n anyGroups: number[][];\n // Declaration-ordered list of the defs that contribute a value to each tuple\n // (`with` => optional:false, `maybe` => optional:true; without/any excluded).\n // Drives both results-tuple building and each-arg assembly so the yield order\n // is exactly the call order.\n yieldPlan: YieldSlot[];\n // Stores parallel to yieldPlan, resolved during rebuild. A `with` yield store\n // is the matching `stores` entry; a `maybe` yield store may be undefined when\n // its store was never created (then the value is always undefined).\n yieldStores: (ComponentStore<unknown> | undefined)[];\n // Stores parallel to maybeIds (for membership-free optional reads); a never-\n // created maybe store is undefined.\n maybeStores: (ComponentStore<unknown> | undefined)[];\n // Reused scratch buffers (one allocation per cache arity, not per entity) for\n // the generic each / pairs lanes. Sized lazily in rebuild.\n scratch: unknown[];\n pairsScratch: unknown[];\n}\n\ntype EachFn = (entity: Entity, ...components: unknown[]) => void;\n\n/**\n * A reusable, pre-resolved query handle (see {@link QueryEngine.compile}).\n * `each` is the per-call zero-allocation hot path; `results` is the\n * allocation-stable, read-only tuple array (do not retain across a structural\n * change); `first` / `count` are conveniences.\n */\nexport interface CompiledQuery<T extends unknown[]> {\n each(fn: (entity: Entity, ...components: T) => void): void;\n results(): readonly QueryResult<T>[];\n first(): QueryResult<T> | null;\n count(): number;\n /**\n * Assert exactly one match and return its tuple; throws (with the actual\n * count) for zero or many. Use for singleton lookups (e.g. the player).\n */\n single(): QueryResult<T>;\n /**\n * Random-access the tuple for `entity` if it currently matches, else null.\n * The returned tuple is a FRESH array; unlike `results()`, it is NOT the\n * cached, allocation-stable reference, so it is safe to retain independently.\n */\n get(entity: Entity): QueryResult<T> | null;\n /**\n * Visit each unordered entity pair (`i < j` over the matched list) exactly\n * once. `fn` receives both entities followed by entity `a`'s component tuple\n * tail; fetch `b`'s components on demand via `get(b)` / direct store access\n * when needed (the broadphase-then-narrowphase pattern). Do NOT re-enter the\n * same compiled query's `each`/`pairs` inside this callback (the per-cache\n * scratch buffer would be clobbered).\n */\n pairs(fn: (a: Entity, b: Entity, ...components: T) => void): void;\n}\n\nexport class QueryEngine {\n private readonly caches = new Map<string, QueryCache>();\n private readonly world: Queryable;\n\n constructor(world: Queryable) {\n this.world = world;\n }\n\n /** Allocation-stable array of `[entity, ...components]` tuples. Read-only. */\n query(defs: ComponentType<unknown>[]): readonly QueryResult<unknown[]>[] {\n return this.resultsOn(this.getCache(defs));\n }\n\n /** First matching tuple, or null. */\n queryFirst(defs: ComponentType<unknown>[]): QueryResult<unknown[]> | null {\n return this.firstOn(this.getCache(defs));\n }\n\n /**\n * Zero-(per-entity)-allocation callback form. Iterates the cached entity list\n * and calls `fn` with components fetched straight from the dense stores; no\n * tuple objects are created. Use for the hottest inner loops.\n */\n each(defs: ComponentType<unknown>[], fn: EachFn): void {\n this.eachOn(this.getCache(defs), fn);\n }\n\n /**\n * Resolve the cache for `defs` once and return a reusable handle. The handle's\n * methods skip the per-call key derivation and variadic unpacking that the\n * `world.query/each(...)` entry points pay, so a compiled handle is the truly\n * per-call zero-allocation path for hot loops.\n */\n compile(defs: ComponentType<unknown>[]): CompiledQuery<unknown[]> {\n return this.handleFor(this.getCache(defs));\n }\n\n /**\n * Compile a query from a filter {@link QueryArg} spec: bare defs (required\n * `with`), `without(...)` / `maybe(...)` terms, and `any(...)` groups. Returns\n * the same reusable handle shape as {@link compile}, now also exposing\n * `single` / `get` / `pairs`.\n *\n * A spec with NO required (`with`) term throws: driving iteration off the\n * whole alive set would be an O(all-entities) scan and a determinism-order\n * question this API deliberately avoids. When the spec is pure-`with` (no\n * without/maybe/any) it delegates to the same cache as `world.query`/`compile`.\n */\n compileSpec(args: QueryArg[]): CompiledQuery<unknown[]> {\n const { withDefs, withoutIds, maybeIds, anyGroups, yieldPlan } =\n parseQueryArgs(args);\n\n // Pure-with spec: route back to the same cache used by `world.query(A)`.\n if (\n withoutIds.length === 0 &&\n maybeIds.length === 0 &&\n anyGroups.length === 0\n ) {\n return this.handleFor(this.getCache(withDefs));\n }\n\n return this.handleFor(\n this.getSpecCache(withDefs, withoutIds, maybeIds, anyGroups, yieldPlan),\n );\n }\n\n /** Build the reusable handle object shared by `compile` and `compileSpec`. */\n private handleFor(cache: QueryCache): CompiledQuery<unknown[]> {\n return {\n each: (fn) => this.eachOn(cache, fn),\n results: () => this.resultsOn(cache),\n first: () => this.firstOn(cache),\n count: () => this.countOn(cache),\n single: () => this.singleOn(cache),\n get: (entity) => this.getOn(cache, entity),\n pairs: (fn) => this.pairsOn(cache, fn),\n };\n }\n\n /**\n * Reset every cached query in place (used by World.clear()). The cache objects\n * are kept rather than dropped, so any {@link CompiledQuery} handle holding one\n * stays valid and simply rebuilds on next use.\n */\n clear(): void {\n for (const cache of this.caches.values()) {\n cache.entities.length = 0;\n cache.stores.length = 0;\n cache.results = [];\n cache.entitiesVersion = 0;\n cache.resultsVersion = -1;\n // Drop the dep-version snapshot so the next access sees `depsChanged` and\n // rebuilds (the stores were just cleared). reqSig (a static signature of\n // the required ids) stays valid.\n cache.depVersions.length = 0;\n // Spec caches also hold resolved yield/maybe stores parallel to entities;\n // drop them so a stale store reference can't survive a clear(). Plan/ids\n // and scratch buffers are kept.\n cache.yieldStores.length = 0;\n cache.maybeStores.length = 0;\n }\n }\n\n /** Drop all cached queries (memory reclaim). Retained handles keep working but rebuild independently. */\n dropCaches(): void {\n this.caches.clear();\n }\n\n private resultsOn(cache: QueryCache): readonly QueryResult<unknown[]>[] {\n this.refreshResults(cache);\n return cache.results;\n }\n\n private firstOn(cache: QueryCache): QueryResult<unknown[]> | null {\n const results = this.resultsOn(cache);\n return results.length > 0 ? results[0] : null;\n }\n\n private countOn(cache: QueryCache): number {\n this.refreshEntities(cache);\n return cache.entities.length;\n }\n\n private eachOn(cache: QueryCache, fn: EachFn): void {\n this.refreshEntities(cache);\n const ents = cache.entities;\n if (ents.length === 0) return; // no matches -> stores may be short; never read\n const stores = cache.stores;\n // Fast switch only when every yielded slot is a required `with` store\n // (yield arity === withIds length, no maybe terms) and arity <= 4. Any spec\n // with a maybe term or yield arity > 4 falls to the generic scratch lane.\n if (cache.yieldPlan.length === cache.ids.length && cache.ids.length <= 4) {\n switch (cache.ids.length) {\n case 1: {\n const s0 = stores[0];\n for (let i = 0; i < ents.length; i++) {\n const e = ents[i];\n fn(e, s0.getUnsafe(e));\n }\n break;\n }\n case 2: {\n const s0 = stores[0];\n const s1 = stores[1];\n for (let i = 0; i < ents.length; i++) {\n const e = ents[i];\n fn(e, s0.getUnsafe(e), s1.getUnsafe(e));\n }\n break;\n }\n case 3: {\n const s0 = stores[0];\n const s1 = stores[1];\n const s2 = stores[2];\n for (let i = 0; i < ents.length; i++) {\n const e = ents[i];\n fn(e, s0.getUnsafe(e), s1.getUnsafe(e), s2.getUnsafe(e));\n }\n break;\n }\n case 4: {\n const s0 = stores[0];\n const s1 = stores[1];\n const s2 = stores[2];\n const s3 = stores[3];\n for (let i = 0; i < ents.length; i++) {\n const e = ents[i];\n fn(\n e,\n s0.getUnsafe(e),\n s1.getUnsafe(e),\n s2.getUnsafe(e),\n s3.getUnsafe(e),\n );\n }\n break;\n }\n }\n return;\n }\n // Generic scratch lane for 5+ components and maybe-bearing specs.\n // Reuses one per-cache scratch array (sized in resolveSpecStores, or here\n // for a pure-with 5+ cache), so it stays zero-per-entity-allocation. Optional\n // slots fetch via `.get`, required via `.getUnsafe`; a never-created maybe\n // store yields undefined.\n const plan = cache.yieldPlan;\n const arity = plan.length;\n const yieldStores = cache.spec ? cache.yieldStores : stores;\n if (cache.scratch.length !== 1 + arity)\n cache.scratch = new Array(1 + arity);\n const scratch = cache.scratch;\n for (let i = 0; i < ents.length; i++) {\n const e = ents[i];\n scratch[0] = e;\n for (let k = 0; k < arity; k++) {\n const s = yieldStores[k];\n scratch[1 + k] =\n s === undefined\n ? undefined\n : plan[k].optional\n ? s.get(e)\n : s.getUnsafe(e);\n }\n fn.apply(undefined, scratch as never);\n }\n }\n\n private getCache(defs: ComponentType<unknown>[]): QueryCache {\n if (defs.length === 0) {\n throw new Error(\n \"a query needs at least one required (non-maybe, non-without) component\",\n );\n }\n // Keyed by call-order ids. Two call orders of the same component set get\n // separate caches so the cached tuples stay correct for each order (rather\n // than sharing one cache keyed by sorted ids), preserving the load-bearing\n // contract: allocation-stable, correct-order tuples.\n let key = \"\";\n const ids: number[] = [];\n for (let i = 0; i < defs.length; i++) {\n const id = defs[i].id;\n ids.push(id);\n key += i === 0 ? id : `,${id}`;\n }\n let cache = this.caches.get(key);\n if (!cache) {\n // A bare-def cache: `spec` false, all filter arrays empty. The yieldPlan\n // mirrors `ids`, so every term is required.\n const yieldPlan: YieldSlot[] = [];\n for (let i = 0; i < ids.length; i++)\n yieldPlan.push({ id: ids[i], optional: false });\n cache = {\n key,\n ids,\n stores: [],\n entities: [],\n results: [],\n entitiesVersion: 0,\n resultsVersion: -1,\n spec: false,\n withoutIds: [],\n maybeIds: [],\n anyGroups: [],\n yieldPlan,\n yieldStores: [],\n maybeStores: [],\n scratch: [],\n pairsScratch: [],\n // A bare-def cache reads only its required stores, so its dep set is `ids`.\n depIds: ids.slice(),\n depVersions: [],\n reqSig: null,\n };\n this.caches.set(key, cache);\n }\n return cache;\n }\n\n /**\n * Build (or fetch) a filter-spec cache. Keyed by a richer key encoding every\n * term role, so different filters never collide with each other or with\n * bare-def caches (whose key is just `ids.join(\",\")`). Only reached for specs\n * that carry a without/maybe/any term.\n */\n private getSpecCache(\n withDefs: ComponentType<unknown>[],\n withoutIds: number[],\n maybeIds: number[],\n anyGroups: number[][],\n yieldPlan: YieldSlot[],\n ): QueryCache {\n const ids: number[] = [];\n for (let i = 0; i < withDefs.length; i++) ids.push(withDefs[i].id);\n const key = `${ids.join(\",\")}|w:${withoutIds.join(\",\")}|m:${maybeIds.join(\n \",\",\n )}|a:${anyGroups.map((g) => g.join(\".\")).join(\";\")}`;\n let cache = this.caches.get(key);\n if (!cache) {\n // A spec cache's result depends on every store it reads: the required\n // `with` ids, plus the without / any / maybe stores. Dedupe into depIds so\n // a change to ANY of them (and only them) invalidates the cache.\n const depSet = new Set<number>(ids);\n for (let i = 0; i < withoutIds.length; i++) depSet.add(withoutIds[i]);\n for (let i = 0; i < maybeIds.length; i++) depSet.add(maybeIds[i]);\n for (let g = 0; g < anyGroups.length; g++)\n for (let j = 0; j < anyGroups[g].length; j++)\n depSet.add(anyGroups[g][j]);\n cache = {\n key,\n ids,\n stores: [],\n entities: [],\n results: [],\n entitiesVersion: 0,\n resultsVersion: -1,\n spec: true,\n withoutIds,\n maybeIds,\n anyGroups,\n yieldPlan,\n yieldStores: [],\n maybeStores: [],\n scratch: [],\n pairsScratch: [],\n depIds: [...depSet],\n depVersions: [],\n reqSig: null,\n };\n this.caches.set(key, cache);\n }\n return cache;\n }\n\n // True if any store this cache depends on has changed (or appeared/vanished)\n // since the last snapshot. An absent store reads as version -1, so a store\n // appearing (or its first add bumping 0→1) is detected. O(depIds), tiny.\n private depsChanged(cache: QueryCache): boolean {\n const { depIds, depVersions } = cache;\n if (depVersions.length !== depIds.length) return true;\n for (let i = 0; i < depIds.length; i++) {\n const s = this.world.storeIfPresent(depIds[i]);\n const v = s === undefined ? -1 : s.version;\n if (v !== depVersions[i]) return true;\n }\n return false;\n }\n\n // Record the current dep-store versions as the cache's baseline.\n private snapshotDeps(cache: QueryCache): void {\n const { depIds, depVersions } = cache;\n depVersions.length = depIds.length;\n for (let i = 0; i < depIds.length; i++) {\n const s = this.world.storeIfPresent(depIds[i]);\n depVersions[i] = s === undefined ? -1 : s.version;\n }\n }\n\n private refreshEntities(cache: QueryCache): void {\n // Rebuild only when one of THIS query's own stores changed; a mutation to an\n // unrelated component leaves the cache valid (the key per-store-versioning\n // win). `entitiesVersion` advances as a build epoch on each actual rebuild.\n if (!this.depsChanged(cache)) return;\n this.rebuildEntities(cache);\n this.snapshotDeps(cache);\n cache.entitiesVersion++;\n }\n\n private refreshResults(cache: QueryCache): void {\n this.refreshEntities(cache);\n // Tuples are current iff they were built at the latest entities epoch.\n if (cache.resultsVersion === cache.entitiesVersion) return;\n\n const { entities, stores, ids } = cache;\n const results: QueryResult<unknown[]>[] = new Array(entities.length);\n if (!cache.spec) {\n // Pure-with path: every yielded slot is a required component.\n for (let i = 0; i < entities.length; i++) {\n const entity = entities[i];\n const tuple: QueryResult<unknown[]> = [entity];\n for (let j = 0; j < ids.length; j++) {\n tuple.push(stores[j].getUnsafe(entity));\n }\n results[i] = tuple;\n }\n } else {\n // Spec path: yields follow declaration order via the yieldPlan, fetching\n // optional slots with `get` (=> value or undefined) and required slots\n // with `getUnsafe`. yieldStores were resolved alongside entities.\n const { yieldPlan, yieldStores } = cache;\n for (let i = 0; i < entities.length; i++) {\n const entity = entities[i];\n const tuple: QueryResult<unknown[]> = [entity];\n for (let j = 0; j < yieldPlan.length; j++) {\n const s = yieldStores[j];\n if (s === undefined) {\n tuple.push(undefined);\n } else if (yieldPlan[j].optional) {\n tuple.push(s.get(entity));\n } else {\n tuple.push(s.getUnsafe(entity));\n }\n }\n results[i] = tuple;\n }\n }\n // New array reference on every rebuild; callers that retained an old array\n // across a structural change observe the swap.\n cache.results = results;\n cache.resultsVersion = cache.entitiesVersion;\n }\n\n private rebuildEntities(cache: QueryCache): void {\n const { ids, stores, entities } = cache;\n entities.length = 0;\n stores.length = 0;\n // Reset spec-resolved stores too, so the early-return-on-empty path below\n // leaves a single well-defined \"no match\" state (never stale arrays).\n cache.yieldStores.length = 0;\n cache.maybeStores.length = 0;\n\n // Resolve current stores in call order. Pick the smallest to iterate; bail\n // (leaving `entities` empty, `stores` short) if any store is absent or empty:\n // no matches are possible.\n let smallest = -1;\n let smallestSize = Infinity;\n for (let i = 0; i < ids.length; i++) {\n const s = this.world.storeIfPresent(ids[i]);\n if (s === undefined || s.size() === 0) return;\n stores.push(s);\n if (s.size() < smallestSize) {\n smallestSize = s.size();\n smallest = i;\n }\n }\n\n // Filter specs need the without/maybe/any stores resolved before iterating;\n // resolve them, then narrow the smallest required store with the same per-\n // entity predicate. Pure-with caches keep the required-store check below.\n if (cache.spec) {\n this.resolveSpecStores(cache);\n }\n\n // Bitmask-accelerated required-membership check (opt-in via enableBitmask):\n // one signature AND replaces the per-store has() probe loop. Same result set\n // and same iteration order; only the inner check changes. Gated on >= 4\n // required components: a measured crossover, below which the has() loop (1–2\n // probes) beats the signature AND's per-word overhead. Null bitmask, or a\n // low-arity query, falls to the sparse-store `has()` loop. The signature is\n // static per cache and computed once observed.\n let sig: Uint32Array | null = null;\n const bm = ids.length >= 4 ? this.world.bitmask() : null;\n if (bm !== null) {\n if (cache.reqSig === null) cache.reqSig = bm.signature(ids);\n sig = cache.reqSig;\n }\n\n const smallestEntities = stores[smallest].iterEntities();\n for (let e = 0; e < smallestEntities.length; e++) {\n const entity = smallestEntities[e];\n if (!this.world.isAlive(entity)) continue;\n if (bm !== null && sig !== null) {\n if (!bm.hasAll(entity as number, sig)) continue;\n } else {\n let hasAll = true;\n for (let i = 0; i < stores.length; i++) {\n if (i === smallest) continue;\n if (!stores[i].has(entity)) {\n hasAll = false;\n break;\n }\n }\n if (!hasAll) continue;\n }\n // Apply the filter predicate only for spec caches.\n if (cache.spec && !this.filterMatches(cache, entity)) continue;\n entities.push(entity);\n }\n }\n\n /**\n * Resolve the `maybe`/`yield` stores for a spec cache (the without/any stores\n * are resolved on the fly by `filterMatches`, which closes over `this.world`).\n * Also sizes the per-cache scratch buffers once.\n */\n private resolveSpecStores(cache: QueryCache): void {\n const { maybeIds, maybeStores, yieldPlan, yieldStores } = cache;\n maybeStores.length = 0;\n for (let i = 0; i < maybeIds.length; i++)\n maybeStores.push(this.world.storeIfPresent(maybeIds[i]));\n // yieldStores parallels yieldPlan: a required slot's store is the resolved\n // `stores` entry at its `with` position; an optional slot's store is the\n // maybe store (which may be undefined when never created => value undefined).\n yieldStores.length = 0;\n let withCursor = 0;\n let maybeCursor = 0;\n for (let i = 0; i < yieldPlan.length; i++) {\n if (yieldPlan[i].optional) {\n yieldStores.push(maybeStores[maybeCursor++]);\n } else {\n yieldStores.push(cache.stores[withCursor++]);\n }\n }\n // Size the reused scratch buffers once (one allocation per cache arity).\n const arity = yieldPlan.length;\n if (cache.scratch.length !== 1 + arity)\n cache.scratch = new Array(1 + arity);\n if (cache.pairsScratch.length !== 2 + arity)\n cache.pairsScratch = new Array(2 + arity);\n }\n\n /**\n * The per-entity filter predicate shared by rebuild and `get`: NO withoutId's\n * store has the entity, and EVERY anyGroup has at least one member store with\n * it. (Required `with` membership is enforced separately, by the smallest-\n * store iteration in rebuild and by an explicit check in `get`.) `maybe` terms\n * impose no constraint.\n */\n private filterMatches(cache: QueryCache, entity: Entity): boolean {\n const { withoutIds, anyGroups } = cache;\n for (let i = 0; i < withoutIds.length; i++) {\n const s = this.world.storeIfPresent(withoutIds[i]);\n if (s?.has(entity)) return false;\n }\n for (let g = 0; g < anyGroups.length; g++) {\n const group = anyGroups[g];\n let satisfied = false;\n for (let j = 0; j < group.length; j++) {\n const s = this.world.storeIfPresent(group[j]);\n if (s?.has(entity)) {\n satisfied = true;\n break;\n }\n }\n if (!satisfied) return false;\n }\n return true;\n }\n\n private singleOn(cache: QueryCache): QueryResult<unknown[]> {\n this.refreshEntities(cache);\n const n = cache.entities.length;\n if (n !== 1) {\n throw new Error(`Query.single(): expected exactly one match, got ${n}`);\n }\n return this.resultsOn(cache)[0];\n }\n\n private getOn(\n cache: QueryCache,\n entity: Entity,\n ): QueryResult<unknown[]> | null {\n this.refreshEntities(cache);\n if (!this.world.isAlive(entity)) return null;\n // Membership: all required stores have it, then the filter predicate. When\n // entities is empty the stores array is short; re-resolve required stores\n // from ids so a hit on an otherwise-empty smallest store still works.\n const { ids } = cache;\n for (let i = 0; i < ids.length; i++) {\n const s = this.world.storeIfPresent(ids[i]);\n if (s === undefined || !s.has(entity)) return null;\n }\n if (cache.spec && !this.filterMatches(cache, entity)) return null;\n // Build a FRESH tuple (not the cached results reference, documented).\n return this.buildTuple(cache, entity);\n }\n\n private pairsOn(\n cache: QueryCache,\n fn: (a: Entity, b: Entity, ...components: unknown[]) => void,\n ): void {\n this.refreshEntities(cache);\n const ents = cache.entities;\n const n = ents.length;\n if (n < 2) return;\n const arity = cache.spec ? cache.yieldPlan.length : cache.ids.length;\n // A pure-with cache also reaches here; resolve its yield buffers from\n // `stores`/`ids` so the scratch lane works without spec fields.\n if (cache.pairsScratch.length !== 2 + arity)\n cache.pairsScratch = new Array(2 + arity);\n const scratch = cache.pairsScratch;\n const stores = cache.spec ? cache.yieldStores : cache.stores;\n const plan = cache.yieldPlan;\n for (let i = 0; i < n; i++) {\n const a = ents[i];\n // Fill a's component tail once per `i`.\n for (let k = 0; k < arity; k++) {\n const s = stores[k];\n scratch[2 + k] =\n s === undefined\n ? undefined\n : plan[k].optional\n ? s.get(a)\n : s.getUnsafe(a);\n }\n scratch[0] = a;\n for (let j = i + 1; j < n; j++) {\n scratch[1] = ents[j];\n fn.apply(undefined, scratch as never);\n }\n }\n }\n\n /** Build one `[entity, ...yields]` tuple via the yieldPlan (fresh array). */\n private buildTuple(\n cache: QueryCache,\n entity: Entity,\n ): QueryResult<unknown[]> {\n const tuple: QueryResult<unknown[]> = [entity];\n if (!cache.spec) {\n for (let j = 0; j < cache.ids.length; j++) {\n const s = this.world.storeIfPresent(cache.ids[j]);\n // Required, guaranteed present (callers verify membership first).\n tuple.push(s === undefined ? undefined : s.getUnsafe(entity));\n }\n return tuple;\n }\n const { yieldPlan } = cache;\n for (let j = 0; j < yieldPlan.length; j++) {\n const slot = yieldPlan[j];\n const s = this.world.storeIfPresent(slot.id);\n if (s === undefined) {\n tuple.push(undefined);\n } else if (slot.optional) {\n tuple.push(s.get(entity));\n } else {\n tuple.push(s.getUnsafe(entity));\n }\n }\n return tuple;\n }\n}\n","import type { CommandBuffer } from \"./command-buffer\";\nimport type { System, World } from \"./types\";\n\ninterface SystemGroup {\n label: string;\n systems: System[];\n}\n\nexport interface ScheduleConfig {\n /** Flush deferred despawns after every group. Default true. */\n flushBetweenGroups?: boolean;\n /**\n * When set, this CommandBuffer is applied (world.applyCommands) after each\n * group's systems run and BEFORE the per-group flush(). Lets systems record\n * deferred add/remove and have them applied at the group boundary. Default\n * undefined: no command buffer.\n */\n commandBuffer?: CommandBuffer;\n}\n\nexport class Schedule {\n private readonly groups: SystemGroup[] = [];\n private readonly flushBetweenGroups: boolean;\n private readonly commandBuffer: CommandBuffer | undefined;\n\n constructor(config?: ScheduleConfig) {\n this.flushBetweenGroups = config?.flushBetweenGroups ?? true;\n this.commandBuffer = config?.commandBuffer;\n }\n\n /** Add a named group of systems to the end of the schedule. */\n addGroup(label: string, ...systems: System[]): this {\n this.groups.push({ label, systems });\n return this;\n }\n\n /** Run all system groups in order. Flushes between groups per the policy. */\n run(world: World, dt = 1): void {\n for (const group of this.groups) {\n for (const system of group.systems) {\n system(world, dt);\n }\n if (this.commandBuffer !== undefined)\n world.applyCommands(this.commandBuffer);\n if (this.flushBetweenGroups) world.flush();\n }\n }\n\n private requireLabel(label: string): void {\n for (const g of this.groups) if (g.label === label) return;\n throw new Error(`Schedule: no group labeled \"${label}\"`);\n }\n\n /** Run groups up to and including the named group. */\n runUpTo(world: World, upToLabel: string, dt = 1): void {\n this.requireLabel(upToLabel);\n for (const group of this.groups) {\n for (const system of group.systems) {\n system(world, dt);\n }\n if (this.commandBuffer !== undefined)\n world.applyCommands(this.commandBuffer);\n if (this.flushBetweenGroups) world.flush();\n if (group.label === upToLabel) break;\n }\n }\n\n /** Run groups starting from (exclusive) the named group. */\n runFrom(world: World, afterLabel: string, dt = 1): void {\n this.requireLabel(afterLabel);\n let started = false;\n for (const group of this.groups) {\n if (!started) {\n if (group.label === afterLabel) started = true;\n continue;\n }\n for (const system of group.systems) {\n system(world, dt);\n }\n if (this.commandBuffer !== undefined)\n world.applyCommands(this.commandBuffer);\n if (this.flushBetweenGroups) world.flush();\n }\n }\n\n /** Get group labels (for debugging). */\n getGroupLabels(): string[] {\n return this.groups.map((g) => g.label);\n }\n\n /**\n * Build a single-group schedule from a priority-sorted system list,\n * preserving exact order (stable sort on priority). Defaults to\n * flushBetweenGroups=false (overridable via `config`) with one group \"main\":\n * a convenient entry point when porting a priority-number scheduler.\n */\n static fromPriorityList(\n systems: { priority: number; update: System }[],\n config?: ScheduleConfig,\n ): Schedule {\n const schedule = new Schedule({ flushBetweenGroups: false, ...config });\n const ordered = systems\n .map((s, index) => ({ s, index }))\n .sort((a, b) => a.s.priority - b.s.priority || a.index - b.index)\n .map((w) => w.s.update);\n schedule.addGroup(\"main\", ...ordered);\n return schedule;\n }\n}\n","// Serialization: snapshot / restore / delta, driven by consumer codecs\n// Reads the world only through public methods (getStoreRaw, iterEntities, has,\n// getUnsafe, spawn, clear, add, setResource, tryGetResource, ...); never mutates\n// engine internals.\n//\n// Determinism: a snapshot is a pure function of the world's logical state, made\n// canonical by iterating entities in ASCENDING INDEX order (explicitly not the\n// store's swap-delete order) and ordering each entity's components by ascending\n// ComponentType.id. Two worlds with identical logical content but different\n// operation histories produce byte-identical snapshots. Numeric encoding is\n// little-endian via explicit DataView calls; the delta byte-compare is exact\n// (===), never a tolerance. Zero runtime deps: DataView, typed arrays, and\n// TextEncoder only.\n\nimport type { ComponentType, Entity, ResourceType, World } from \"./index\";\nimport { MigrationError, type MigrationRegistry } from \"./migration\";\n\nexport interface SerializerOptions {\n /** Codec write headroom per component (default 4096). */\n readonly maxComponentBytes?: number;\n /**\n * Optional migration registry. When provided, every component blob is read\n * back through the chain on restore/applyDelta. Omitted (or empty) => all\n * components are treated as version 0 with an identity upgrade: byte-identical\n * to a no-migration serializer for current-version data. The per-component\n * `_version` field is written UNCONDITIONALLY (a constant 0 when no chain is\n * registered), so \"no migrations\" is represented in the format.\n */\n readonly migrations?: MigrationRegistry;\n}\n\n/**\n * Per-component-type binary codec the consumer supplies. The serializer never\n * reflects on component shape; the codec owns the byte layout.\n *\n * - `write` appends `c`'s bytes into `view` at `offset` and returns the new\n * offset (offset + bytesWritten).\n * - `read` decodes a value starting at `offset` and returns it with the new\n * offset. `read` MUST consume exactly as many bytes as the matching `write`\n * produced (round-trip byte-symmetry is the core contract).\n * - `refFields` lists keys whose values are `Entity` references; on `restore`\n * they are remapped from old indices to the new spawned ids via the idMap.\n * A ref equal to 0 (\"no entity\") is preserved as 0.\n * - `readVersioned` is an optional version-aware decode. REQUIRED for any\n * migrated component whose OLDER versions wrote a DIFFERENT on-wire byte\n * layout than the current `read` expects, which is essentially every\n * add/remove/reorder of a serialized field, since each changes the byte count\n * or field set. It receives `storedVersion` and must consume exactly the bytes\n * THAT version wrote, returning the value in that version's shape; the\n * migration chain then upgrades it to current. `read` alone is safe ONLY when\n * every stored version's bytes are identical to what the current `read`\n * consumes (e.g. a migration that derives a new JS field at upgrade time\n * without changing the serialized bytes). Supplying `read` for a layout-\n * changing migration desyncs the byte stream; `restore` detects the resulting\n * length mismatch and throws rather than silently mis-loading.\n */\nexport interface ComponentCodec<T> {\n write(view: DataView, offset: number, c: T): number;\n read(view: DataView, offset: number): { value: T; offset: number };\n refFields?: (keyof T)[];\n readVersioned?(\n view: DataView,\n offset: number,\n version: number,\n ): { value: Record<string, unknown>; offset: number };\n}\n\n/** A registered resource codec: same byte contract, no refFields. */\nexport interface ResourceCodec<T> {\n write(view: DataView, offset: number, value: T): number;\n read(view: DataView, offset: number): { value: T; offset: number };\n}\n\nconst MAGIC = 0x41454353; // \"AECS\"\nconst FORMAT_SNAPSHOT = 1;\nconst FORMAT_DELTA = 2;\nconst FORMAT_VERSION = 1;\nconst DEFAULT_MAX_COMPONENT_BYTES = 4096;\n\n// biome-ignore lint/suspicious/noExplicitAny: codec registry is value-erased: only the byte layout matters; the consumer owns the typed boundary.\ntype AnyCodec = ComponentCodec<any>;\n// biome-ignore lint/suspicious/noExplicitAny: same erasure as AnyCodec, for resources.\ntype AnyResourceCodec = ResourceCodec<any>;\n// Component sizes are codec-defined, so the backing buffer grows on demand. The\n// codec writes directly into the writer's DataView at the current offset; the\n// writer pre-`ensure`s a generous per-component slab so a codec never overruns.\n\nclass ByteWriter {\n buf: ArrayBuffer;\n view: DataView;\n offset = 0;\n\n constructor() {\n this.buf = new ArrayBuffer(64);\n this.view = new DataView(this.buf);\n }\n\n /** Grow the backing buffer so at least `extra` more bytes fit at `offset`. */\n ensure(extra: number): void {\n const need = this.offset + extra;\n if (need <= this.buf.byteLength) return;\n const next = new ArrayBuffer(Math.max(this.buf.byteLength * 2, need));\n new Uint8Array(next).set(new Uint8Array(this.buf, 0, this.offset));\n this.buf = next;\n this.view = new DataView(next);\n }\n\n u32(n: number): void {\n this.ensure(4);\n this.view.setUint32(this.offset, n >>> 0, true);\n this.offset += 4;\n }\n\n /**\n * Write one component via its codec. Pre-`ensure`s `maxComponentBytes` of\n * headroom so the codec writes into a DataView with room; advances `offset` to\n * the codec's returned offset. Codecs writing larger blobs must raise\n * `maxComponentBytes` on the Serializer constructor.\n */\n writeComponent(codec: AnyCodec, c: unknown, maxComponentBytes: number): void {\n this.ensure(maxComponentBytes);\n this.offset = codec.write(this.view, this.offset, c);\n }\n\n /** Write one resource via its codec (same headroom contract as a component). */\n writeResource(\n codec: AnyResourceCodec,\n value: unknown,\n maxComponentBytes: number,\n ): void {\n this.ensure(maxComponentBytes);\n this.offset = codec.write(this.view, this.offset, value);\n }\n\n /** Return an exact-length copy of the written bytes. */\n finish(): ArrayBuffer {\n return this.buf.slice(0, this.offset);\n }\n}\nclass ByteReader {\n readonly view: DataView;\n offset = 0;\n\n constructor(buffer: ArrayBuffer) {\n this.view = new DataView(buffer);\n }\n\n u32(): number {\n const n = this.view.getUint32(this.offset, true);\n this.offset += 4;\n return n;\n }\n}\n\nfunction buffersEqual(a: ArrayBuffer, b: ArrayBuffer): boolean {\n if (a.byteLength !== b.byteLength) return false;\n const ua = new Uint8Array(a);\n const ub = new Uint8Array(b);\n for (let i = 0; i < ua.length; i++) if (ua[i] !== ub[i]) return false;\n return true;\n}\n\ninterface DecodedRecord {\n oldIndex: number;\n comps: { compId: number; value: unknown }[];\n}\n\nexport class Serializer {\n private readonly codecs = new Map<\n number,\n { def: ComponentType<unknown>; codec: AnyCodec }\n >();\n private readonly resourceCodecs = new Map<\n number,\n { type: ResourceType<unknown>; codec: AnyResourceCodec }\n >();\n // Sorted ascending list of registered component ids; recomputed on register\n // so snapshot ordering is stable and independent of registration order.\n private orderedComponentIds: number[] = [];\n // shadow[compId][entityIndex] = last-written component bytes; shadowAlive is\n // the entity-index set present at the last baseline. resourceShadow[resId] =\n // last-written resource bytes. The shadow is the source of truth for delta();\n // change-tracking, when present, only narrows the candidate set, and every\n // candidate is still byte-verified against the shadow, so both paths emit\n // identical bytes for the same state transition.\n private shadow = new Map<number, Map<number, ArrayBuffer>>();\n private shadowAlive = new Set<number>();\n private resourceShadow = new Map<number, ArrayBuffer>();\n\n // Old-index -> live entity, seeded by restore/applyDelta so a subsequent\n // applyDelta remaps refs consistently against the live world.\n private applyIdMap = new Map<number, Entity>();\n\n private readonly maxComponentBytes: number;\n\n // Optional consumer-owned migration registry. `undefined` or an empty registry\n // means every component is implicitly version 0 with an identity upgrade.\n private readonly migrations?: MigrationRegistry;\n\n constructor(options?: SerializerOptions) {\n this.maxComponentBytes =\n options?.maxComponentBytes ?? DEFAULT_MAX_COMPONENT_BYTES;\n this.migrations = options?.migrations;\n }\n\n // Current (live-code) version written for a component blob. When no migrations\n // are registered this is a constant 0 for every component, so the `_version`\n // field is a fixed 0.\n private versionOf(componentId: number): number {\n return this.migrations?.currentVersionById(componentId) ?? 0;\n }\n\n // Decode one component blob: read its `_version`, then decode the value via\n // `readVersioned` (version-aware, for wire-layout changes) or `read` (current\n // layout), then upgrade it through the migration chain. Advances `r.offset`.\n // Runs AFTER decode and BEFORE the world write so refField remap (declared\n // against the CURRENT shape) sees the migrated value. Returns the migrated\n // plain value; the caller remaps refs and writes it.\n private decodeComponent(\n r: ByteReader,\n compId: number,\n ): { value: unknown; offset: number } {\n const storedVersion = r.u32();\n const codec = this.codecById(compId);\n const decoded = codec.readVersioned\n ? codec.readVersioned(r.view, r.offset, storedVersion)\n : (codec.read(r.view, r.offset) as {\n value: Record<string, unknown>;\n offset: number;\n });\n let value: unknown = decoded.value;\n if (this.migrations !== undefined && !this.migrations.isEmpty) {\n value = this.migrations.migrate(\n compId,\n storedVersion,\n decoded.value as Record<string, unknown>,\n this.defById(compId).name,\n );\n } else if (storedVersion !== 0) {\n // A versioned save but no registry supplied -> fail loud, never silently\n // mis-load.\n throw new MigrationError(\n this.defById(compId).name,\n storedVersion,\n 0,\n \"no MigrationRegistry supplied to deserialize a versioned save\",\n );\n }\n return { value, offset: decoded.offset };\n }\n\n /** Register a binary codec for a component type. Chainable. */\n register<T>(def: ComponentType<T>, codec: ComponentCodec<T>): this {\n this.codecs.set(def.id, {\n def: def as ComponentType<unknown>,\n codec: codec as AnyCodec,\n });\n this.orderedComponentIds = [...this.codecs.keys()].sort((a, b) => a - b);\n return this;\n }\n\n /** Register a resource to include in snapshots (optional, opt-in). */\n registerResource<T>(type: ResourceType<T>, codec: ResourceCodec<T>): this {\n this.resourceCodecs.set(type.id, {\n type: type as ResourceType<unknown>,\n codec: codec as AnyResourceCodec,\n });\n return this;\n }\n\n private defById(id: number): ComponentType<unknown> {\n const entry = this.codecs.get(id);\n if (entry === undefined) {\n throw new Error(`serialize: no codec registered for component id ${id}`);\n }\n return entry.def;\n }\n\n private codecById(id: number): AnyCodec {\n const entry = this.codecs.get(id);\n if (entry === undefined) {\n throw new Error(`serialize: no codec registered for component id ${id}`);\n }\n return entry.codec;\n }\n /**\n * Full world state as a self-describing buffer. Entities are emitted in\n * ascending index order; per entity, components are emitted in ascending\n * ComponentType.id order. Little-endian throughout.\n */\n snapshot(world: World): ArrayBuffer {\n const w = new ByteWriter();\n w.u32(MAGIC);\n w.u32(FORMAT_SNAPSHOT);\n w.u32(FORMAT_VERSION);\n\n const entities = this.aliveSorted(world);\n w.u32(entities.length);\n\n for (let i = 0; i < entities.length; i++) {\n const idx = entities[i];\n w.u32(idx);\n const present = this.presentComponents(world, idx);\n w.u32(present.length);\n for (let j = 0; j < present.length; j++) {\n const compId = present[j];\n w.u32(compId);\n // Per-component `_version`, written with the same primitive as compId.\n // A constant 0 when no migration chain is registered.\n w.u32(this.versionOf(compId));\n const c = world\n .getStoreRaw(this.defById(compId))\n .getUnsafe(idx as Entity);\n w.writeComponent(this.codecById(compId), c, this.maxComponentBytes);\n }\n }\n\n this.writeResources(world, w);\n this.captureBaseline(world, entities);\n return w.finish();\n }\n\n // Union of every registered store's members, as a sorted ascending array.\n // KEY: sorting by index makes the buffer canonical regardless of the store's\n // dense swap-delete order. UNION MODEL (deliberate): serialization is\n // component-driven: an entity with no registered component is in no store and\n // is therefore not serialized. Losing its last registered component removes an\n // entity from the serialized view (see delta()'s note).\n private aliveSorted(world: World): number[] {\n const alive = new Set<number>();\n for (let i = 0; i < this.orderedComponentIds.length; i++) {\n const def = this.defById(this.orderedComponentIds[i]);\n const ents = world.getStoreRaw(def).iterEntities();\n for (let e = 0; e < ents.length; e++) alive.add(ents[e] as number);\n }\n return [...alive].sort((a, b) => a - b);\n }\n\n // Registered component ids present on `idx`, in ascending id order.\n private presentComponents(world: World, idx: number): number[] {\n const present: number[] = [];\n for (let i = 0; i < this.orderedComponentIds.length; i++) {\n const compId = this.orderedComponentIds[i];\n if (world.getStoreRaw(this.defById(compId)).has(idx as Entity)) {\n present.push(compId);\n }\n }\n return present;\n }\n\n // Collect present registered resources (sorted by id), then write count + each.\n private writeResources(world: World, w: ByteWriter): void {\n const ids = [...this.resourceCodecs.keys()].sort((a, b) => a - b);\n const present: number[] = [];\n for (let i = 0; i < ids.length; i++) {\n const entry = this.resourceCodecs.get(ids[i]);\n if (entry === undefined) continue;\n if (world.tryGetResource(entry.type) !== undefined) present.push(ids[i]);\n }\n w.u32(present.length);\n for (let i = 0; i < present.length; i++) {\n const entry = this.resourceCodecs.get(present[i]);\n if (entry === undefined) continue;\n w.u32(present[i]);\n const value = world.tryGetResource(entry.type);\n w.writeResource(entry.codec, value, this.maxComponentBytes);\n }\n }\n /**\n * Clear `world`, re-spawn every entity in the snapshot, re-add components via\n * the registered codecs, and remap every `refFields` value from old index to\n * the freshly-spawned id. After restore, `delta()` baselines reset.\n */\n restore(world: World, buffer: ArrayBuffer): void {\n const r = new ByteReader(buffer);\n if (r.u32() !== MAGIC) throw new Error(\"serialize: bad magic\");\n if (r.u32() !== FORMAT_SNAPSHOT) {\n throw new Error(\"serialize: bad format (expected snapshot)\");\n }\n if (r.u32() !== FORMAT_VERSION) throw new Error(\"serialize: bad version\");\n\n world.clear();\n\n const n = r.u32();\n const idMap = new Map<number, Entity>();\n const records: DecodedRecord[] = [];\n\n // FIRST PASS: spawn every entity up front so the idMap is complete BEFORE\n // any ref remap: a ref pointing at an entity that appears later in the\n // buffer still resolves.\n for (let i = 0; i < n; i++) {\n const oldIndex = r.u32();\n const newE = world.spawn();\n idMap.set(oldIndex, newE);\n const compCount = r.u32();\n const comps: { compId: number; value: unknown }[] = [];\n for (let j = 0; j < compCount; j++) {\n const compId = r.u32();\n // decodeComponent reads the per-component `_version`, decodes via the\n // (version-aware) codec, and upgrades through the migration chain.\n const decoded = this.decodeComponent(r, compId);\n r.offset = decoded.offset;\n comps.push({ compId, value: decoded.value });\n }\n records.push({ oldIndex, comps });\n }\n\n // SECOND PASS: remap refs through the now-complete idMap and add.\n for (let i = 0; i < records.length; i++) {\n const record = records[i];\n const newE = idMap.get(record.oldIndex) as Entity;\n for (let j = 0; j < record.comps.length; j++) {\n const { compId, value } = record.comps[j];\n this.remapRefs(compId, value, idMap);\n world.add(newE, this.defById(compId), value);\n }\n }\n\n this.readResources(world, r);\n\n // Integrity check: a well-formed snapshot is consumed exactly. A leftover or\n // short tail means a codec read/write byte-count asymmetry or a migrated\n // component decoded with `read` instead of `readVersioned`: fail loudly\n // here rather than silently dropping/mis-loading later entities.\n if (r.offset !== buffer.byteLength) {\n throw new Error(\n `serialize: restore consumed ${r.offset} of ${buffer.byteLength} bytes; ` +\n `likely a codec read/write byte mismatch or a migrated component missing readVersioned`,\n );\n }\n\n const restored = [...idMap.values()]\n .map((e) => e as number)\n .sort((a, b) => a - b);\n this.captureBaseline(world, restored);\n this.applyIdMap = idMap;\n }\n\n // Remap a decoded value's refFields from old index to live entity. A ref of 0\n // (\"no entity\") stays 0; an unmapped ref also becomes 0.\n private remapRefs(\n compId: number,\n value: unknown,\n idMap: Map<number, Entity>,\n ): void {\n const codec = this.codecById(compId);\n const refFields = codec.refFields;\n if (\n refFields === undefined ||\n value === null ||\n typeof value !== \"object\"\n ) {\n return;\n }\n const v = value as Record<string, number>;\n for (let i = 0; i < refFields.length; i++) {\n const f = refFields[i] as string;\n const old = v[f];\n v[f] = old === 0 ? 0 : ((idMap.get(old) ?? 0) as number);\n }\n }\n\n private readResources(world: World, r: ByteReader): void {\n const resCount = r.u32();\n for (let i = 0; i < resCount; i++) {\n const rid = r.u32();\n const entry = this.resourceCodecs.get(rid);\n if (entry === undefined) {\n throw new Error(\n `serialize: no codec registered for resource id ${rid}`,\n );\n }\n const decoded = entry.codec.read(r.view, r.offset);\n r.offset = decoded.offset;\n world.setResource(entry.type, decoded.value);\n }\n }\n /**\n * Bytes for only the entities/components changed since the last `delta()` or\n * `snapshot()`/`restore()` baseline. Computed by an exact (epsilon-0) byte\n * diff of every alive entity's registered components against the per-Serializer\n * shadow captured at the last baseline. Emits removed-entity, then per-entity\n * added/changed and removed-component records, then resource diffs; entities\n * ascending, components ascending, so the output is a pure function of state\n * (never the store's dense order). Delta output is INDEPENDENT of whether\n * change tracking is enabled: the shadow diff is the source of truth.\n *\n * UNION MODEL: an entity is part of the serialized world only while it holds a\n * registered component. Removing an entity's LAST registered component (even if\n * the entity stays alive in the source world) is emitted as a removed-entity\n * record, so `applyDelta` despawns its replica, keeping the delta path\n * consistent with what a fresh `snapshot`/`restore` of the same source would\n * produce. To persist an otherwise-componentless entity across a snapshot,\n * keep at least one registered (tag) component on it.\n */\n delta(world: World): ArrayBuffer {\n const w = new ByteWriter();\n w.u32(MAGIC);\n w.u32(FORMAT_DELTA);\n w.u32(FORMAT_VERSION);\n\n const curr = this.aliveSorted(world);\n const currSet = new Set(curr);\n\n // Removed entities: present at baseline, absent now (ascending).\n const removedEntities: number[] = [];\n for (const idx of this.shadowAlive) {\n if (!currSet.has(idx)) removedEntities.push(idx);\n }\n removedEntities.sort((a, b) => a - b);\n\n w.u32(removedEntities.length);\n for (let i = 0; i < removedEntities.length; i++) w.u32(removedEntities[i]);\n\n // Per-entity component diff against the shadow (ascending entity, ascending\n // compId, both pure functions of state, never the store's dense order).\n const records: {\n idx: number;\n addedOrChanged: { compId: number; bytes: ArrayBuffer }[];\n removed: number[];\n }[] = [];\n\n for (let i = 0; i < curr.length; i++) {\n const idx = curr[i];\n const shadowRow = this.shadow.get(idx);\n const addedOrChanged: { compId: number; bytes: ArrayBuffer }[] = [];\n const removed: number[] = [];\n for (let j = 0; j < this.orderedComponentIds.length; j++) {\n const compId = this.orderedComponentIds[j];\n const def = this.defById(compId);\n const store = world.getStoreRaw(def);\n const presentNow = store.has(idx as Entity);\n const prevBytes = shadowRow?.get(compId);\n if (presentNow) {\n const bytes = this.componentBytes(world, compId, idx);\n // ADDED (not in shadow) or CHANGED (bytes differ). A markChanged that\n // did not change bytes emits nothing; the byte-verify guarantees the\n // delta is byte-identical regardless of which path produced the\n // candidate.\n if (prevBytes === undefined || !buffersEqual(prevBytes, bytes)) {\n addedOrChanged.push({ compId, bytes });\n }\n } else if (prevBytes !== undefined) {\n // REMOVED component (was in shadow, absent now).\n removed.push(compId);\n }\n }\n if (addedOrChanged.length > 0 || removed.length > 0) {\n records.push({ idx, addedOrChanged, removed });\n }\n }\n\n w.u32(records.length);\n for (let i = 0; i < records.length; i++) {\n const rec = records[i];\n w.u32(rec.idx);\n w.u32(rec.addedOrChanged.length);\n w.u32(rec.removed.length);\n for (let j = 0; j < rec.addedOrChanged.length; j++) {\n const { compId, bytes } = rec.addedOrChanged[j];\n w.u32(compId);\n // Per-component `_version` (same constant-0 rule as snapshot). The\n // shadow stores only the codec bytes, so the version is\n // emitted here, not embedded in `bytes`.\n w.u32(this.versionOf(compId));\n this.appendBytes(w, bytes);\n }\n for (let j = 0; j < rec.removed.length; j++) w.u32(rec.removed[j]);\n }\n\n this.writeResourceDelta(world, w);\n this.captureBaseline(world, curr);\n return w.finish();\n }\n\n // Serialize a single component into its own exact-length buffer (for shadow\n // storage and byte comparison).\n private componentBytes(\n world: World,\n compId: number,\n idx: number,\n ): ArrayBuffer {\n const scratch = new ByteWriter();\n const c = world.getStoreRaw(this.defById(compId)).getUnsafe(idx as Entity);\n scratch.writeComponent(this.codecById(compId), c, this.maxComponentBytes);\n return scratch.finish();\n }\n\n // Append a pre-serialized component's bytes verbatim (length-prefixed-free:\n // the codec's read consumes exactly its own bytes, so no length tag needed).\n private appendBytes(w: ByteWriter, bytes: ArrayBuffer): void {\n const src = new Uint8Array(bytes);\n w.ensure(src.length);\n new Uint8Array(w.buf).set(src, w.offset);\n w.offset += src.length;\n }\n\n // Resource diff: emit each changed/added resource (id + bytes), then removed\n // resource ids. Diffed against resourceShadow, byte-exact.\n private writeResourceDelta(world: World, w: ByteWriter): void {\n const ids = [...this.resourceCodecs.keys()].sort((a, b) => a - b);\n const changed: { rid: number; bytes: ArrayBuffer }[] = [];\n const removed: number[] = [];\n const presentNow = new Set<number>();\n for (let i = 0; i < ids.length; i++) {\n const rid = ids[i];\n const entry = this.resourceCodecs.get(rid);\n if (entry === undefined) continue;\n const value = world.tryGetResource(entry.type);\n const prev = this.resourceShadow.get(rid);\n if (value !== undefined) {\n presentNow.add(rid);\n const scratch = new ByteWriter();\n scratch.writeResource(entry.codec, value, this.maxComponentBytes);\n const bytes = scratch.finish();\n if (prev === undefined || !buffersEqual(prev, bytes)) {\n changed.push({ rid, bytes });\n }\n }\n }\n for (const rid of this.resourceShadow.keys()) {\n if (!presentNow.has(rid)) removed.push(rid);\n }\n changed.sort((a, b) => a.rid - b.rid);\n removed.sort((a, b) => a - b);\n w.u32(changed.length);\n for (let i = 0; i < changed.length; i++) {\n w.u32(changed[i].rid);\n this.appendBytes(w, changed[i].bytes);\n }\n w.u32(removed.length);\n for (let i = 0; i < removed.length; i++) w.u32(removed[i]);\n }\n /** Apply a `delta()` buffer to `world`, remapping refs through the live idMap. */\n applyDelta(world: World, buffer: ArrayBuffer): void {\n const r = new ByteReader(buffer);\n if (r.u32() !== MAGIC) throw new Error(\"serialize: bad magic\");\n if (r.u32() !== FORMAT_DELTA) {\n throw new Error(\"serialize: bad format (expected delta)\");\n }\n if (r.u32() !== FORMAT_VERSION) throw new Error(\"serialize: bad version\");\n\n const idMap = this.applyIdMap;\n\n // Removed entities: despawn + flush immediately so removals are visible\n // before re-adds. delta apply is a save-load boundary, not a mid-frame op,\n // so a flush here does not affect any running schedule.\n const removedCount = r.u32();\n for (let i = 0; i < removedCount; i++) {\n const oldIndex = r.u32();\n const e = idMap.get(oldIndex);\n if (e !== undefined && world.isAlive(e)) world.despawn(e);\n idMap.delete(oldIndex);\n }\n if (removedCount > 0) world.flush();\n\n // Changed records: decode into a temp structure, spawning unknown indices\n // FIRST so the idMap is complete before any ref remap (two-phase, like\n // restore).\n const recordCount = r.u32();\n const decoded: {\n target: Entity;\n addedOrChanged: { compId: number; value: unknown }[];\n removed: number[];\n }[] = [];\n\n for (let i = 0; i < recordCount; i++) {\n const oldIndex = r.u32();\n const addedOrChangedCount = r.u32();\n const removedCount2 = r.u32();\n let target = idMap.get(oldIndex);\n if (target === undefined) {\n target = world.spawn();\n idMap.set(oldIndex, target);\n }\n const addedOrChanged: { compId: number; value: unknown }[] = [];\n for (let j = 0; j < addedOrChangedCount; j++) {\n const compId = r.u32();\n // decodeComponent reads the per-component `_version`, decodes, and\n // upgrades through the migration chain (mirrors restore).\n const d = this.decodeComponent(r, compId);\n r.offset = d.offset;\n addedOrChanged.push({ compId, value: d.value });\n }\n const removed: number[] = [];\n for (let j = 0; j < removedCount2; j++) removed.push(r.u32());\n decoded.push({ target, addedOrChanged, removed });\n }\n\n for (let i = 0; i < decoded.length; i++) {\n const rec = decoded[i];\n for (let j = 0; j < rec.addedOrChanged.length; j++) {\n const { compId, value } = rec.addedOrChanged[j];\n this.remapRefs(compId, value, idMap);\n world.add(rec.target, this.defById(compId), value);\n }\n for (let j = 0; j < rec.removed.length; j++) {\n world.remove(rec.target, this.defById(rec.removed[j]));\n }\n }\n\n this.applyResourceDelta(world, r);\n\n if (r.offset !== buffer.byteLength) {\n throw new Error(\n `serialize: applyDelta consumed ${r.offset} of ${buffer.byteLength} bytes; ` +\n `likely a codec read/write byte mismatch or a migrated component missing readVersioned`,\n );\n }\n\n const alive = this.aliveSorted(world);\n this.captureBaseline(world, alive);\n }\n\n private applyResourceDelta(world: World, r: ByteReader): void {\n const changedCount = r.u32();\n for (let i = 0; i < changedCount; i++) {\n const rid = r.u32();\n const entry = this.resourceCodecs.get(rid);\n if (entry === undefined) {\n throw new Error(\n `serialize: no codec registered for resource id ${rid}`,\n );\n }\n const d = entry.codec.read(r.view, r.offset);\n r.offset = d.offset;\n world.setResource(entry.type, d.value);\n }\n const removedCount = r.u32();\n for (let i = 0; i < removedCount; i++) {\n const rid = r.u32();\n const entry = this.resourceCodecs.get(rid);\n if (entry !== undefined) world.unsetResource(entry.type);\n }\n }\n // captureBaseline (private): rebuild the shadow + shadowAlive\n // O(alive × components × bytes), run only on snapshot/restore/delta/applyDelta\n // calls (never per-frame unless the consumer calls delta per-frame).\n\n private captureBaseline(world: World, sortedIndices: number[]): void {\n const shadow = new Map<number, Map<number, ArrayBuffer>>();\n for (let i = 0; i < sortedIndices.length; i++) {\n const idx = sortedIndices[i];\n let row: Map<number, ArrayBuffer> | undefined;\n for (let j = 0; j < this.orderedComponentIds.length; j++) {\n const compId = this.orderedComponentIds[j];\n const store = world.getStoreRaw(this.defById(compId));\n if (!store.has(idx as Entity)) continue;\n if (row === undefined) {\n row = new Map();\n shadow.set(idx, row);\n }\n row.set(compId, this.componentBytes(world, compId, idx));\n }\n }\n this.shadow = shadow;\n this.shadowAlive = new Set(sortedIndices);\n\n const resourceShadow = new Map<number, ArrayBuffer>();\n for (const [rid, entry] of this.resourceCodecs) {\n const value = world.tryGetResource(entry.type);\n if (value === undefined) continue;\n const scratch = new ByteWriter();\n scratch.writeResource(entry.codec, value, this.maxComponentBytes);\n resourceShadow.set(rid, scratch.finish());\n }\n this.resourceShadow = resourceShadow;\n }\n}\n// jsonCodec: generic JSON codec for plain-data components\n// Slower, non-binary (UTF-8 via TextEncoder). A convenience so consumers can\n// serialize before hand-writing a binary codec; `refFields` still works (JSON\n// stores raw numeric ids, and entity ids are < 2^53 so they round-trip exact).\n//\n// Determinism caveat: JSON.stringify key order follows insertion order, so for\n// byte-identity the component object must have stable key order (true for plain\n// components built by a factory). For values containing -0, NaN, or floats whose\n// decimal round-trip differs, use the binary path; jsonCodec targets integer /\n// string plain data.\n\nconst enc = new TextEncoder();\nconst dec = new TextDecoder();\n\n/**\n * Generic JSON codec for plain-data components (slower, non-binary; UTF-8 via\n * TextEncoder). `refFields` still works (JSON stores raw numeric ids). Does NOT\n * round-trip `-0` (→ `0`), `NaN`/`Infinity` (→ `null`), or floats whose decimal\n * form differs; use a binary codec for those.\n */\nexport function jsonCodec<T>(refFields?: (keyof T)[]): ComponentCodec<T> {\n return {\n write(view: DataView, offset: number, c: T): number {\n const json = JSON.stringify(c);\n const bytes = enc.encode(json);\n view.setUint32(offset, bytes.length, true);\n new Uint8Array(\n view.buffer,\n view.byteOffset + offset + 4,\n bytes.length,\n ).set(bytes);\n return offset + 4 + bytes.length;\n },\n read(view: DataView, offset: number): { value: T; offset: number } {\n const len = view.getUint32(offset, true);\n const slice = new Uint8Array(\n view.buffer,\n view.byteOffset + offset + 4,\n len,\n );\n const value = JSON.parse(dec.decode(slice)) as T;\n return { value, offset: offset + 4 + len };\n },\n refFields,\n };\n}\n","// ComponentStore: sparse-set dense component storage\n// Iteration order is a deterministic function of the add/remove sequence. Do NOT\n// replace swap-delete with another compaction (e.g. tombstones): that would shift\n// iteration order, which downstream determinism depends on.\n\nimport type { EntityId } from \"./types\";\n\n/**\n * Default maximum entity count. The sparse Int32Array is pre-allocated to this\n * size, so each store pays `capacity × 4` bytes (256 KB at 65536). Removes the\n * cap as a practical concern for spawner-heavy moments.\n */\nexport const DEFAULT_MAX_ENTITIES = 65536;\n\nconst EMPTY = -1;\n\nexport class ComponentStore<T> {\n private readonly sparse: Int32Array;\n private readonly entities: EntityId[] = [];\n private readonly data: T[] = [];\n private count = 0;\n private readonly capacity: number;\n\n private pooling = false;\n private resetFn: ((c: T) => void) | null = null;\n private readonly freeList: T[] = [];\n\n // Deltas accumulate in dense store order on set/remove and drain on\n // drainChanges(). Untracked stores record nothing.\n private tracked = false;\n private readonly _added: EntityId[] = [];\n private readonly _removed: EntityId[] = [];\n private readonly _changed: EntityId[] = [];\n // Per-list callback dispatch cursors: how many _added/_removed entries the\n // onAdded/onRemoved fan-out has already fired. The delta lists drain only on\n // drainChanges() (once per frame), but flush() can run several times per frame\n // (the default Schedule flushes after every group), so without a cursor a\n // single add would re-fire its callback on every flush until the frame drain.\n private _addedFired = 0;\n private _removedFired = 0;\n\n // Bumped on every membership change (add/remove) AND object replacement (a\n // `set` on an existing entity replaces the stored object, invalidating cached\n // query tuples that hold the old reference). Lets a query rebuild only when\n // one of its own component stores changes.\n private _version = 0;\n\n constructor(capacity: number = DEFAULT_MAX_ENTITIES) {\n this.capacity = capacity;\n this.sparse = new Int32Array(capacity).fill(EMPTY);\n }\n\n /**\n * Enable component pooling for this store. On `remove`, the removed object is\n * passed through `reset` and pushed onto a free list; the next pooled\n * `acquire()` hands it back instead of allocating. Opt-in per store. Do not\n * enable it where callers rely on each add storing the exact object passed;\n * pooling aliases objects across entities.\n */\n enablePooling(reset: (c: T) => void): void {\n this.pooling = true;\n this.resetFn = reset;\n }\n\n /** Whether pooling is enabled for this store. */\n isPooling(): boolean {\n return this.pooling;\n }\n\n /**\n * Enable add/removed/changed tracking for this store. Idempotent. Default OFF;\n * an untracked store records nothing and pays a single already-false branch on\n * set()/remove(). Does NOT retroactively record existing members, only\n * post-enable transitions, matching event-bus \"from now on\" semantics. Deltas\n * accumulate in dense store order until drainChanges().\n */\n enableTracking(): void {\n this.tracked = true;\n }\n\n /** Whether tracking is enabled for this store. */\n isTracking(): boolean {\n return this.tracked;\n }\n\n /**\n * Pop a pooled (already-reset) object, or undefined if pooling is off or the\n * free list is empty. Used by `World.addComponent` to reuse component objects.\n */\n acquire(): T | undefined {\n return this.pooling ? this.freeList.pop() : undefined;\n }\n\n /** Number of objects currently parked in the free list (for tests/metrics). */\n pooledCount(): number {\n return this.freeList.length;\n }\n\n /**\n * Monotonic version, bumped on every add/remove (membership change) and on a\n * `set` that replaces an existing object. Read by the query engine to rebuild\n * a cached query only when one of its own component stores has changed.\n */\n get version(): number {\n return this._version;\n }\n\n /** Whether entity has this component. */\n has(id: EntityId): boolean {\n return (\n (id as number) < this.capacity && this.sparse[id as number] !== EMPTY\n );\n }\n\n /** Get component data. Returns undefined if not present. */\n get(id: EntityId): T | undefined {\n const idx = this.sparse[id as number];\n return idx !== EMPTY ? this.data[idx] : undefined;\n }\n\n /** Get component data without bounds check. Caller must ensure has(id). */\n getUnsafe(id: EntityId): T {\n return this.data[this.sparse[id as number]];\n }\n\n private outOfRange(method: string, id: EntityId): never {\n throw new Error(\n `ComponentStore.${method}(): entity id ${id} exceeds capacity ` +\n `(${this.capacity}). The sparse array cannot index it: this id was not ` +\n `produced by a World sized for it (see World maxEntities).`,\n );\n }\n\n /** Set (add or update) component data for entity. */\n set(id: EntityId, value: T): void {\n if ((id as number) >= this.capacity) this.outOfRange(\"set\", id);\n const idx = this.sparse[id as number];\n if (idx !== EMPTY) {\n this.data[idx] = value;\n } else {\n const dense = this.count++;\n this.sparse[id as number] = dense;\n this.entities[dense] = id;\n this.data[dense] = value;\n if (this.tracked) this._added.push(id);\n }\n // Bump on both add and object-replacement: a replaced object invalidates any\n // cached query tuple holding the old reference.\n this._version++;\n }\n\n /**\n * Record an explicit change for an entity that currently has the component.\n * No-op when untracked or absent. Coarse: no dedup; calling it twice on the\n * same entity records two entries. Not pruned on remove, so a changed-then-\n * removed id stays in iterChanged() until drainChanges(); re-check has() if\n * liveness matters.\n */\n markChanged(id: EntityId): void {\n if ((id as number) >= this.capacity) this.outOfRange(\"markChanged\", id);\n if (this.tracked && this.sparse[id as number] !== EMPTY) {\n this._changed.push(id);\n }\n }\n\n /**\n * Remove component from entity. Swap-delete to keep arrays dense. Returns\n * `true` if the entity had the component (membership changed), `false` if it\n * was absent.\n */\n remove(id: EntityId): boolean {\n if ((id as number) >= this.capacity) this.outOfRange(\"remove\", id);\n const idx = this.sparse[id as number];\n if (idx === EMPTY) return false;\n\n // Pooling: reset and park the removed object before it leaves the store.\n // Reading data[idx] here happens before the swap below overwrites it.\n if (this.pooling && this.resetFn !== null) {\n const removed = this.data[idx];\n this.resetFn(removed);\n this.freeList.push(removed);\n }\n\n // Capture the removed id BEFORE the swap-delete mutates the arrays; `id` is\n // the entity itself and is unaffected by compaction, so the recorded delta\n // is the exact membership loss in dense order.\n if (this.tracked) this._removed.push(id);\n\n const last = this.count - 1;\n if (idx !== last) {\n const lastEntity = this.entities[last];\n this.entities[idx] = lastEntity;\n this.data[idx] = this.data[last];\n this.sparse[lastEntity as number] = idx;\n }\n this.sparse[id as number] = EMPTY;\n this.entities.length = last;\n this.data.length = last;\n this.count = last;\n this._version++;\n return true;\n }\n\n /** Dense entity array; iterate for hot paths. Length is size(). */\n iterEntities(): ReadonlyArray<EntityId> {\n return this.entities;\n }\n\n /** Dense data array; iterate for hot paths. Length is size(). */\n iterData(): ReadonlyArray<T> {\n return this.data;\n }\n\n /** Entities that gained the component since drainChanges(), in dense order. */\n iterAdded(): ReadonlyArray<EntityId> {\n return this._added;\n }\n\n /** Entities that lost the component since drainChanges(), in dense order. */\n iterRemoved(): ReadonlyArray<EntityId> {\n return this._removed;\n }\n\n /** Entities marked changed since drainChanges(), in dense order. May include a changed-then-removed id (see markChanged). */\n iterChanged(): ReadonlyArray<EntityId> {\n return this._changed;\n }\n\n /** Count of _added entries the onAdded fan-out has already dispatched. */\n get addedFired(): number {\n return this._addedFired;\n }\n\n /** Count of _removed entries the onRemoved fan-out has already dispatched. */\n get removedFired(): number {\n return this._removedFired;\n }\n\n /** Advance the onAdded dispatch cursor (set by World.flush's callback fan-out). */\n setAddedFired(n: number): void {\n this._addedFired = n;\n }\n\n /** Advance the onRemoved dispatch cursor. */\n setRemovedFired(n: number): void {\n this._removedFired = n;\n }\n\n /** Truncate all three delta lists to length 0, resetting dispatch cursors. */\n drainChanges(): void {\n this._added.length = 0;\n this._removed.length = 0;\n this._changed.length = 0;\n this._addedFired = 0;\n this._removedFired = 0;\n }\n\n /** Number of entities with this component. */\n size(): number {\n return this.count;\n }\n\n /** Remove all entries. */\n clear(): void {\n for (let i = 0; i < this.count; i++) {\n this.sparse[this.entities[i] as number] = EMPTY;\n }\n this.entities.length = 0;\n this.data.length = 0;\n this.count = 0;\n this.freeList.length = 0;\n // Reset deltas so a cleared store starts fresh. `tracked` stays enabled\n // (opt-in survives clear, mirroring pooling). clear() does NOT push the\n // cleared members into _removed; it is a bulk teardown, not a per-frame\n // structural change, and consumers never observe deltas across a clear().\n this._added.length = 0;\n this._removed.length = 0;\n this._changed.length = 0;\n this._addedFired = 0;\n this._removedFired = 0;\n this._version++;\n }\n}\n","// Spatial Hash: uniform grid broad phase\n// Configurable cell size, Szudzik pairing for negative coordinates, and a\n// `queryRadius` broad-plus-narrow pass. Result arrays are passed in by reference,\n// so queries allocate nothing.\n//\n// Query dedup uses an `Int32Array` keyed by entity id plus a monotonic generation\n// counter (no per-query Set or Map allocation). This runs ~2-3.7x faster than a\n// `Map<Entity, number>` when one query runs per entity per frame, and a monotonic\n// counter never collides. That avoids the false-negative a position-derived\n// generation would risk: two queries at colliding positions could share a\n// generation, so one would skip an entity the other already marked.\n\nimport { DEFAULT_MAX_ENTITIES } from \"./store\";\nimport type { Entity } from \"./types\";\n\nexport class SpatialHash {\n private invCellSize: number;\n private cells = new Map<number, Entity[]>();\n // `seen[entity]` holds the generation of the last query that visited it. Gens\n // are monotonic and start at 1, so the zero-initialised array reads as unseen.\n private generation = 0;\n private readonly seen: Int32Array;\n\n /**\n * @param cellSize grid cell size in world units. Must be > 0.\n * @param maxEntities upper bound on entity ids inserted (sizes the dedup\n * array, `maxEntities * 4` bytes). Match the consuming World's capacity.\n */\n constructor(cellSize = 64, maxEntities: number = DEFAULT_MAX_ENTITIES) {\n if (!(cellSize > 0)) {\n throw new Error(`SpatialHash: cellSize must be > 0 (got ${cellSize})`);\n }\n this.invCellSize = 1 / cellSize;\n this.seen = new Int32Array(maxEntities);\n }\n\n // `| 0` keeps the counter in the same int32 domain as `seen`; skip 0 (= unseen).\n private nextGen(): number {\n this.generation = (this.generation + 1) | 0;\n if (this.generation === 0) this.generation = 1;\n return this.generation;\n }\n\n clear(): void {\n this.cells.clear();\n // `generation` is intentionally NOT reset; monotonic gens keep the dedup\n // correct across frames without having to clear `seen`.\n }\n\n insert(entity: Entity, x: number, y: number, radius: number): void {\n if ((entity as number) >= this.seen.length) {\n throw new Error(\n `SpatialHash.insert(): entity id ${entity} exceeds maxEntities ` +\n `(${this.seen.length}). Construct the SpatialHash with a maxEntities ` +\n `that matches the consuming World's capacity.`,\n );\n }\n const minCX = Math.floor((x - radius) * this.invCellSize);\n const maxCX = Math.floor((x + radius) * this.invCellSize);\n const minCY = Math.floor((y - radius) * this.invCellSize);\n const maxCY = Math.floor((y + radius) * this.invCellSize);\n\n for (let cx = minCX; cx <= maxCX; cx++) {\n for (let cy = minCY; cy <= maxCY; cy++) {\n const key = this.hashKey(cx, cy);\n let cell = this.cells.get(key);\n if (!cell) {\n cell = [];\n this.cells.set(key, cell);\n }\n cell.push(entity);\n }\n }\n }\n\n /** Query all entities within a circle. Deduplicates via generation counter. */\n query(x: number, y: number, radius: number, results: Entity[]): void {\n results.length = 0;\n const queryGen = this.nextGen();\n\n const minCX = Math.floor((x - radius) * this.invCellSize);\n const maxCX = Math.floor((x + radius) * this.invCellSize);\n const minCY = Math.floor((y - radius) * this.invCellSize);\n const maxCY = Math.floor((y + radius) * this.invCellSize);\n\n for (let cx = minCX; cx <= maxCX; cx++) {\n for (let cy = minCY; cy <= maxCY; cy++) {\n const key = this.hashKey(cx, cy);\n const cell = this.cells.get(key);\n if (!cell) continue;\n for (let i = 0; i < cell.length; i++) {\n const entity = cell[i];\n if (this.seen[entity as number] !== queryGen) {\n this.seen[entity as number] = queryGen;\n results.push(entity);\n }\n }\n }\n }\n }\n\n /** Query + circle-circle narrow phase in one pass. */\n queryRadius(\n x: number,\n y: number,\n radius: number,\n getPos: (e: Entity) => { x: number; y: number } | undefined,\n getRadius: (e: Entity) => number,\n results: Entity[],\n ): void {\n results.length = 0;\n const queryGen = this.nextGen();\n const minCX = Math.floor((x - radius) * this.invCellSize);\n const maxCX = Math.floor((x + radius) * this.invCellSize);\n const minCY = Math.floor((y - radius) * this.invCellSize);\n const maxCY = Math.floor((y + radius) * this.invCellSize);\n\n for (let cx = minCX; cx <= maxCX; cx++) {\n for (let cy = minCY; cy <= maxCY; cy++) {\n const key = this.hashKey(cx, cy);\n const cell = this.cells.get(key);\n if (!cell) continue;\n for (let i = 0; i < cell.length; i++) {\n const entity = cell[i];\n if (this.seen[entity as number] === queryGen) continue;\n this.seen[entity as number] = queryGen;\n\n const pos = getPos(entity);\n if (!pos) continue;\n const r = getRadius(entity);\n const dx = pos.x - x;\n const dy = pos.y - y;\n const distSq = dx * dx + dy * dy;\n const combinedR = radius + r;\n if (distSq <= combinedR * combinedR) {\n results.push(entity);\n }\n }\n }\n }\n }\n\n private hashKey(cx: number, cy: number): number {\n // Szudzik pairing, handles negatives. Cell-index magnitude must stay below\n // ~sqrt(2^53) (~9.4e7) for `a * a` to remain an exact integer; beyond that\n // distinct cells can collide.\n const a = cx >= 0 ? 2 * cx : -2 * cx - 1;\n const b = cy >= 0 ? 2 * cy : -2 * cy - 1;\n return a >= b ? a * a + a + b : b * b + a;\n }\n}\n","/** Branded entity identifier. `EntityId` is a convenience alias. */\nexport type Entity = number & { readonly __brand: unique symbol };\nexport type EntityId = Entity;\n\n/**\n * A stable, storable reference to an entity = (index, generation), encoded as\n * one safe-integer number (index in the low bits, generation in the high bits;\n * safe while the World's `maxEntities` ≤ 2^21, which the World constructor\n * enforces). Unlike {@link Entity} (the bare dense index, recycled on despawn), a handle\n * also carries the index's generation at stamp time, so a handle to a despawned\n * entity fails to resolve even after the index is reused. Opaque: build with\n * `world.handleOf`, consume with `world.resolve` / `world.isHandleValid`. Do not\n * pack a generation into `Entity` itself: that would break `sparse[entity]`\n * O(1) indexing in the store and spatial hash.\n */\nexport type EntityHandle = number & { readonly __handleBrand: unique symbol };\n\n/**\n * A stable, storable reference to an entity = its dense index packed with the\n * generation it had when the ref was taken. The SAME runtime encoding as\n * {@link EntityHandle} (index in the low bits, generation in the high bits, one\n * safe integer), so a ref and a handle for the same entity are bit-identical and\n * resolve through the same generations side-array; they never fork. Unlike a\n * bare {@link Entity} (recycled on despawn), a ref carries the stamp generation,\n * so once the target is despawned (and its index possibly recycled) the ref no\n * longer matches the live generation and resolves to `null`. Encoded as one\n * safe-integer number so it can be stored inside plain component data and\n * compared with `===`. Build with `world.ref`, consume with `world.deref` /\n * `world.isRefValid`. {@link NULL_REF} (0) is the canonical \"points at nothing\".\n */\nexport type EntityRef = EntityHandle & { readonly __refBrand: unique symbol };\n\n/** The canonical empty reference. Resolves to `null`, never matches an entity. */\nexport const NULL_REF = 0 as EntityRef;\n\n/**\n * Token identifying a component type. Created via {@link defineComponent}.\n *\n * `create` / `reset` are optional:\n * - `defineComponent<T>(name)` builds component data at the call site\n * (`world.add`).\n * - `defineComponent<T>(name, create, reset)` uses a factory and is added with\n * `world.addComponent(entity, def, partial)`, with optional pooling on\n * despawn (the `reset` hook).\n */\nexport interface ComponentType<T> {\n readonly id: number;\n readonly name: string;\n readonly create?: () => T;\n readonly reset?: (component: T) => void;\n /** Phantom field to carry the data type; never read at runtime. */\n readonly _phantom?: T;\n /** Per-kind nominal brand (never set at runtime); makes token kinds mutually non-assignable. */\n readonly __kind?: \"component\";\n}\n\n/**\n * A component token created *with* a `create` factory (and `reset` hook). The\n * factory-using APIs (`world.addComponent` and `world.enablePooling`) require\n * this narrower type, so they are statically guaranteed a factory/reset exists\n * (no `data as T` cast, no runtime \"missing factory/reset\" throw).\n */\nexport interface PooledComponentType<T> extends ComponentType<T> {\n readonly create: () => T;\n readonly reset: (component: T) => void;\n}\n\n/**\n * A presence-only (\"tag\") component: a {@link ComponentType}<true> whose store\n * holds the shared constant `true` for every member rather than a per-entity\n * object. Branded with `readonly tag: true` so APIs that want to forbid data\n * components (or detect tags) can do so at the type level. Use with\n * `world.addTag` / `world.hasTag` / `world.removeTag`; it also participates in\n * queries exactly like any other component (the store membership is identical).\n * A tag is intentionally NOT a {@link PooledComponentType} (no `create`/`reset`),\n * so it can never be routed through the pooling reset path.\n */\nexport interface TagType extends ComponentType<true> {\n readonly tag: true;\n}\n\n/** Alias of {@link ComponentType}, for code that prefers the `Def` spelling. */\nexport type ComponentDef<T> = ComponentType<T>;\n\n/** Token identifying a resource (singleton) type. Created via {@link defineResource}. */\nexport interface ResourceType<T> {\n readonly id: number;\n readonly name: string;\n readonly _phantom?: T;\n /** Per-kind nominal brand. See {@link ComponentType.__kind}. */\n readonly __kind?: \"resource\";\n}\n\n/** Token identifying an event type. Created via {@link defineEvent}. */\nexport interface EventType<T = void> {\n readonly id: number;\n readonly name: string;\n readonly _phantom?: T;\n /** Per-kind nominal brand. See {@link ComponentType.__kind}. */\n readonly __kind?: \"event\";\n}\n\n/**\n * Token identifying a per-system local scratch slot. Created via\n * {@link defineLocal}. Unlike a resource, a local carries its own lazy\n * initializer; the first {@link World.local} call for the token builds the\n * value. Intended for private per-system state (counters, ring buffers,\n * cached scratch arrays) without reaching for a global resource.\n */\nexport interface LocalType<T> {\n readonly id: number;\n readonly name: string;\n /** Builds the initial value on first access. Called at most once per World. */\n readonly init: () => T;\n /** Phantom field to carry the data type; never read at runtime. */\n readonly _phantom?: T;\n /** Per-kind nominal brand. See {@link ComponentType.__kind}. */\n readonly __kind?: \"local\";\n}\n\n// Avoid a circular import: the World class lives in world.ts.\nimport type { World } from \"./world\";\n\nexport type { World };\n\n/**\n * A system is a plain function. The second argument is the frame delta; systems\n * that don't use it can be written as `(world) => void`. Both shapes are valid\n * `System` values.\n */\nexport type System = (world: World, dt: number) => void;\n\n/** Query result: a tuple of `[Entity, ...components]`. */\nexport type QueryResult<T extends unknown[]> = [Entity, ...T];\n/**\n * A {@link ComponentType} of *some* (erased) data type, for heterogeneous\n * collections of component defs where only the `.id` is read. `ComponentType<T>`\n * is invariant-to-contravariant in `T` under `strictFunctionTypes` (its `reset`\n * takes `T`), so a specific `ComponentType<{x}>` is NOT assignable to\n * `ComponentType<unknown>`; `unknown` would force a cast at every call site.\n * `any` is the canonical, and only, escape; it is confined to this single alias\n * (the value is never read through it, only the id). All public filter types\n * below build on this so `select(...)`/`any(...)` accept concrete components\n * without casts.\n */\n// biome-ignore lint/suspicious/noExplicitAny: heterogeneous, value-erased component collection (see the JSDoc above); only `.id` is read.\nexport type AnyComponentType = ComponentType<any>;\n\n/** Role a single wrapped component term plays inside a query spec. */\nexport type QueryTermKind = \"with\" | \"without\" | \"maybe\";\n\n/**\n * A component reference wrapped to mark its role inside a query spec. Built by\n * the `without` / `maybe` factories in query.ts (a bare def is treated as\n * `with` without wrapping).\n */\nexport interface QueryTerm<T> {\n readonly kind: QueryTermKind;\n readonly def: ComponentType<T>;\n}\n\n/**\n * A {@link QueryTerm} of some erased data type: the heterogeneous form a\n * `without(...)`/`maybe(...)` result flows into a {@link QueryArg} as. Its `def`\n * is an {@link AnyComponentType}, so the same variance rationale applies.\n */\nexport interface AnyQueryTerm {\n readonly kind: QueryTermKind;\n readonly def: AnyComponentType;\n}\n\n/**\n * An `any(...)` group: at least one of the listed defs must be present for an\n * entity to match. Contributes no value to the yield tuple. Built by the `any`\n * factory in query.ts. Stores defs as {@link AnyComponentType} so concrete\n * component types flow in without a cast.\n */\nexport interface AnyGroup {\n readonly kind: \"any\";\n readonly defs: AnyComponentType[];\n}\n\n/**\n * A single argument to `world.select(...)` / `compileSpec(...)`: a bare\n * {@link ComponentType} (required `with`), a {@link QueryTerm} (`without` /\n * `maybe`), or an {@link AnyGroup} (`any`). Built on {@link AnyComponentType} so\n * a specific `ComponentType<{x}>` / `QueryTerm<{x}>` flows in without a cast.\n */\nexport type QueryArg = AnyComponentType | AnyQueryTerm | AnyGroup;\nlet _nextComponentId = 0;\nlet _nextResourceId = 0;\nlet _nextEventId = 0;\nlet _nextLocalId = 0;\n\n/**\n * The shared singleton value every tag store entry points at; never a fresh\n * object, so a tag costs zero per-entity allocation. Exported for the store-fill\n * path and tests; never mutated.\n */\nexport const TAG_VALUE = true as const;\n\n/**\n * Define a new component type.\n *\n * Two call styles, distinguished at the type level:\n * defineComponent<T>(name) // data built at the call site\n * // -> ComponentType<T> (use world.add)\n * defineComponent<T>(name, create, reset) // factory + pooling hook\n * // -> PooledComponentType<T>\n * // (use world.addComponent / pooling)\n */\nexport function defineComponent<T>(name: string): ComponentType<T>;\nexport function defineComponent<T>(\n name: string,\n create: () => T,\n reset: (c: T) => void,\n): PooledComponentType<T>;\nexport function defineComponent<T>(\n name: string,\n create?: () => T,\n reset?: (c: T) => void,\n): ComponentType<T> {\n return { id: _nextComponentId++, name, create, reset } as ComponentType<T>;\n}\n\n/**\n * Define a zero-sized tag component. Unlike {@link defineComponent}, no data\n * object is ever created or stored: membership in the dense store IS the\n * component, and the store value is the module-level shared {@link TAG_VALUE}\n * (= true). Tag ids draw from the SAME counter as `defineComponent`, so a tag is\n * a fully ordinary component id for `world.store`, queries, the bitmask, and\n * `flush`. The `create`/`reset` fields are deliberately absent, so a tag is not\n * a {@link PooledComponentType} and cannot be pooled.\n */\nexport function defineTag(name: string): TagType {\n return { id: _nextComponentId++, name, tag: true } as TagType;\n}\n\n/** Define a new resource (singleton) type. */\nexport function defineResource<T>(name: string): ResourceType<T> {\n return { id: _nextResourceId++, name } as ResourceType<T>;\n}\n\n/** Define a new event type. */\nexport function defineEvent<T = void>(name: string): EventType<T> {\n return { id: _nextEventId++, name } as EventType<T>;\n}\n\n/**\n * Define a per-system local scratch slot.\n *\n * const Accum = defineLocal<{ n: number }>(\"frameAccum\", () => ({ n: 0 }));\n * const tick: System = (world) => { world.local(Accum).n++; };\n *\n * Each call produces a unique, process-wide id (same convention as\n * defineComponent / defineResource / defineEvent).\n */\nexport function defineLocal<T>(name: string, init: () => T): LocalType<T> {\n return { id: _nextLocalId++, name, init } as LocalType<T>;\n}\n","import { Bitmask } from \"./bitmask\";\nimport type { CommandBuffer } from \"./command-buffer\";\nimport { EventBus } from \"./events\";\nimport { IncrementalQuery } from \"./incremental-query\";\nimport { type CompiledQuery, parseQueryArgs, QueryEngine } from \"./query\";\nimport { ComponentStore, DEFAULT_MAX_ENTITIES } from \"./store\";\nimport {\n type AnyComponentType,\n type ComponentType,\n type Entity,\n type EntityHandle,\n type EntityId,\n type EntityRef,\n type LocalType,\n NULL_REF,\n type PooledComponentType,\n type QueryArg,\n type QueryResult,\n type ResourceType,\n TAG_VALUE,\n type TagType,\n} from \"./types\";\n\nexport class World {\n private nextId = 1; // 0 is reserved as \"no entity\"\n private readonly maxEntities: number;\n private readonly alive = new Set<EntityId>();\n private readonly recycled: EntityId[] = [];\n private readonly pendingDespawns: EntityId[] = [];\n // Bumped only when a despawn is applied in flush(); read by handleOf/resolve\n // to detect a handle held across a despawn and recycled id.\n private readonly generations: Uint32Array;\n private readonly indexBits: number; // ceil(log2(maxEntities)), >=1\n private readonly indexMask: number; // (2 ** indexBits) - 1\n // EntityRef reuses the exact (index, generation) packing as EntityHandle. The\n // reverse index is allocated only after enableBackrefs().\n private backrefsEnabled = false;\n // target index -> holder entities, in insertion order, de-duplicated.\n private backrefEdges: Map<number, Entity[]> | null = null;\n // holder index -> target indices it points at, so a despawned holder is swept\n // from every target's edge list during flush(). Allocated by enableBackrefs().\n private holderToTargets: Map<number, Set<number>> | null = null;\n // Indexed by component id (dense, from the module-level counter), plus a\n // compact list of created stores for flush/clear iteration. Array indexing is\n // ~2.5x faster than Map.get on the per-access hot path (get/has/add), with\n // identical semantics and iteration order.\n private readonly stores: (ComponentStore<unknown> | undefined)[] = [];\n private readonly activeStores: ComponentStore<unknown>[] = [];\n // A compact list of the stores opted into tracking, so clearChanges() touches\n // only opted-in stores. The callback maps stay null until onAdded/onRemoved is\n // used, so flush() checks one `!== null` branch.\n private readonly trackedStores: ComponentStore<unknown>[] = [];\n private addedCallbacks: Map<number, ((e: Entity) => void)[]> | null = null;\n private removedCallbacks: Map<number, ((e: Entity) => void)[]> | null = null;\n private readonly resources = new Map<number, unknown>();\n // String-keyed resources: an alternative to typed tokens (e.g. for quick\n // experimenting or porting a string-keyed resource map).\n private readonly stringResources = new Map<string, unknown>();\n // Per-system local scratch state, keyed by LocalType id. Lazily built on\n // first local() access; independent of resources.\n private readonly locals = new Map<number, unknown>();\n readonly events = new EventBus();\n private readonly queryEngine: QueryEngine;\n private _version = 0;\n // A derived per-entity component-signature mirror, built by enableBitmask()\n // and kept in sync on every World-API membership change. Stays null until\n // opted in. Signatures for hasAllMask are cached by def-id-list key.\n private bitmask: Bitmask | null = null;\n private readonly maskSigs = new Map<string, Uint32Array>();\n // Queries whose match set is maintained on add/remove instead of rebuilt on the\n // next access. `incrementalByComponent[id]` is the list to reconcile when\n // component `id` changes for an entity; `incrementalQueries` is the flat list\n // for flush/clear. `hasIncremental` gates mutation hooks to a single boolean\n // check when no incremental query is registered.\n private hasIncremental = false;\n private readonly incrementalByComponent: (IncrementalQuery[] | undefined)[] =\n [];\n private readonly incrementalQueries: IncrementalQuery[] = [];\n\n /**\n * Called inside flush() for each entity actually removed, before its\n * components are stripped (so the callback can still read them). Defaults to\n * null; set it to e.g. tear down a sprite or other external resource.\n */\n onBeforeDestroy: ((entity: Entity) => void) | null = null;\n\n /** Monotonic version, bumped on component add/remove and applied despawns. */\n get version(): number {\n return this._version;\n }\n\n /**\n * @param options.maxEntities Per-store sparse-array capacity and the spawn\n * ceiling. Defaults to {@link DEFAULT_MAX_ENTITIES} (65536). Raise it for a\n * world that can hold more live entities at once.\n */\n constructor(options?: { maxEntities?: number }) {\n this.maxEntities = options?.maxEntities ?? DEFAULT_MAX_ENTITIES;\n this.indexBits = Math.max(1, Math.ceil(Math.log2(this.maxEntities)));\n this.indexMask = 2 ** this.indexBits - 1;\n // Handle/ref pack gen (u32) into the high bits above indexBits, so the packed\n // value stays a safe integer only while indexBits + 32 <= 53.\n if (this.indexBits + 32 > 53) {\n throw new Error(\n `World: maxEntities ${this.maxEntities} too large; entity handles need ` +\n `maxEntities <= 2^21 (2097152) to stay safe integers.`,\n );\n }\n // Zero-filled generation per index (every fresh index is gen 0).\n this.generations = new Uint32Array(this.maxEntities);\n\n this.queryEngine = new QueryEngine({\n isAlive: (entity) => this.alive.has(entity),\n storeIfPresent: (id) => this.stores[id],\n // The per-entity component bitmask, when enabled, lets rebuildEntities\n // replace its per-store has() probe with one signature AND.\n bitmask: () => this.bitmask,\n });\n }\n /** Create a new entity immediately. Returns its id. */\n spawn(): EntityId {\n const id =\n this.recycled.length > 0\n ? (this.recycled.pop() as EntityId)\n : (this.nextId++ as EntityId);\n if ((id as number) >= this.maxEntities) {\n throw new Error(\n `World.spawn(): entity id ${id} exceeds maxEntities (${this.maxEntities}). ` +\n `Component sparse arrays cannot index this id. Construct the World with ` +\n `a larger { maxEntities } or audit for an entity leak.`,\n );\n }\n this.alive.add(id);\n return id;\n }\n\n /** Queue entity for removal. Applied on flush(). */\n despawn(id: EntityId): void {\n this.pendingDespawns.push(id);\n }\n\n /** Whether entity is currently alive. */\n isAlive(id: EntityId): boolean {\n return this.alive.has(id);\n }\n\n /** Number of alive entities. */\n get entityCount(): number {\n return this.alive.size;\n }\n\n /**\n * Apply deferred despawns. Called between system groups by the Schedule.\n * Removes all components from despawned entities and recycles their ids.\n */\n flush(): void {\n if (this.pendingDespawns.length > 0) {\n for (const id of this.pendingDespawns) {\n if (!this.alive.delete(id)) continue;\n if (this.onBeforeDestroy) this.onBeforeDestroy(id);\n for (const store of this.activeStores) {\n store.remove(id);\n }\n this._version++;\n // Bump the index's generation so any handle stamped at the old generation\n // fails to resolve, even once this index is recycled and reused. >>> 0\n // keeps it an explicit unsigned 32-bit value (Uint32Array wraps on store).\n this.generations[id as number] =\n (this.generations[id as number] + 1) >>> 0;\n this.recycled.push(id);\n // Drop the entity's whole signature row in one call (store removes above\n // already settled membership).\n if (this.bitmask) this.bitmask.clearEntity(id as number);\n // Sweep the despawned target's reverse-index edge: the \"who points at me\"\n // list for a now-dead target is meaningless. Holders are not deleted\n // and no holder component scan, so this introduces zero new entity\n // removals and cannot shift any store's swap-delete order.\n if (this.backrefsEnabled && this.backrefEdges !== null) {\n this.backrefEdges.delete(id as number);\n // Sweep this id where it was a HOLDER: drop it from every target's\n // edge list, so a despawned holder's edges don't linger.\n const targets = this.holderToTargets?.get(id as number);\n if (targets !== undefined) {\n for (const t of targets) {\n const holders = this.backrefEdges.get(t);\n if (holders !== undefined) {\n const at = holders.indexOf(id as Entity);\n if (at !== -1) {\n holders.splice(at, 1);\n if (holders.length === 0) this.backrefEdges.delete(t);\n }\n }\n }\n this.holderToTargets?.delete(id as number);\n }\n }\n // Drop the now-dead entity from any incremental query it is in. The\n // entity was alive.delete()'d and stripped from its stores above, so\n // reconcile() sees no match and swap-deletes it.\n if (this.hasIncremental) {\n for (let q = 0; q < this.incrementalQueries.length; q++) {\n this.incrementalQueries[q].reconcile(id as number);\n }\n }\n }\n this.pendingDespawns.length = 0;\n }\n // Change-tracking callbacks fire at one deterministic point, AFTER the\n // despawn loop fully settles (so callbacks observe a fully-applied frame).\n // Both maps are null until onAdded/onRemoved is used.\n if (this.addedCallbacks !== null)\n this.fireCallbacks(this.addedCallbacks, true);\n if (this.removedCallbacks !== null) {\n this.fireCallbacks(this.removedCallbacks, false);\n }\n }\n /** Get (or lazily create) the store for a component type. */\n store<T>(type: ComponentType<T>): ComponentStore<T> {\n let s = this.stores[type.id];\n if (s === undefined) {\n s = new ComponentStore<unknown>(this.maxEntities);\n this.stores[type.id] = s;\n this.activeStores.push(s);\n }\n return s as ComponentStore<T>;\n }\n\n /**\n * Add a component to an entity (direct style: the passed object is stored\n * as-is). Bumps the version unconditionally: unlike addComponent's in-place\n * merge, `add` *replaces* the stored object, so any cached query tuple holding\n * the old reference must be invalidated.\n */\n add(id: EntityId, type: TagType, data?: never): void;\n add<T>(id: EntityId, type: ComponentType<T>, data: T): void;\n add<T>(id: EntityId, type: ComponentType<T>, data: T): void {\n this.store(type).set(id, data);\n this._version++;\n if (this.bitmask) this.bitmask.set(id as number, type.id);\n if (this.hasIncremental) this.reconcileIncremental(type.id, id as number);\n }\n\n /** Remove a component from an entity. */\n remove<T>(id: EntityId, type: ComponentType<T>): void {\n const removed = this.stores[type.id]?.remove(id);\n if (removed) {\n this._version++;\n if (this.bitmask) this.bitmask.clear(id as number, type.id);\n if (this.hasIncremental) this.reconcileIncremental(type.id, id as number);\n }\n }\n\n /** Get a component. Returns undefined if not present. */\n get<T>(id: EntityId, type: ComponentType<T>): T | undefined {\n return this.store(type).get(id);\n }\n\n /** Get a component without bounds check. Caller must ensure entity has it. */\n getUnsafe<T>(id: EntityId, type: ComponentType<T>): T {\n return this.store(type).getUnsafe(id);\n }\n\n /** Whether entity has a component. */\n has<T>(id: EntityId, type: ComponentType<T>): boolean {\n return this.store(type).has(id);\n }\n\n /**\n * Get the first entry of a component store (e.g. a player singleton). Throws if\n * empty. Does NOT assert uniqueness; use {@link CompiledQuery.single} for that.\n */\n getFirst<T>(type: ComponentType<T>): T {\n const data = this.store(type).iterData();\n if (data.length === 0) {\n throw new Error(`Component \"${type.name}\" has no entries`);\n }\n return data[0];\n }\n /**\n * Add a factory component ({@link PooledComponentType}). If the entity\n * already has the component, the existing instance is reused; otherwise\n * a pooled object is reused if available, else a fresh one is built via the\n * factory. `data` (a partial) is then merged onto the instance. (Components\n * without a factory are added with {@link add}.)\n */\n addComponent<T extends object>(\n entity: Entity,\n def: PooledComponentType<T>,\n data?: Partial<T>,\n ): T {\n const store = this.store(def);\n let component = store.get(entity);\n if (component === undefined) {\n component = store.acquire() ?? def.create();\n store.set(entity, component);\n this._version++;\n if (this.bitmask) this.bitmask.set(entity as number, def.id);\n if (this.hasIncremental)\n this.reconcileIncremental(def.id, entity as number);\n if (data) Object.assign(component, data);\n } else if (data) {\n Object.assign(component, data);\n store.markChanged(entity);\n }\n return component;\n }\n\n /** Alias of get(): component or undefined. */\n getComponent<T>(entity: Entity, def: ComponentType<T>): T | undefined {\n return this.store(def).get(entity);\n }\n\n /** Alias of has(). */\n hasComponent<T>(entity: Entity, def: ComponentType<T>): boolean {\n return this.store(def).has(entity);\n }\n\n /** Remove a component. Bumps version when one was actually removed. */\n removeComponent<T>(entity: Entity, def: ComponentType<T>): void {\n if (this.stores[def.id]?.remove(entity)) {\n this._version++;\n if (this.bitmask) this.bitmask.clear(entity as number, def.id);\n if (this.hasIncremental)\n this.reconcileIncremental(def.id, entity as number);\n }\n }\n\n /** Get a component, throwing if missing. */\n getOrThrow<T>(entity: Entity, def: ComponentType<T>): T {\n const c = this.store(def).get(entity);\n if (c === undefined) {\n throw new Error(`Entity ${entity} missing component ${def.name}`);\n }\n return c;\n }\n /**\n * Add a tag to an entity. Equivalent to `add(entity, tag, true)` but takes no\n * data argument; the store value is the shared {@link TAG_VALUE}, so no data\n * object is allocated. Membership-gated version bump: bumps only when the tag\n * is newly added (matches addComponent's \"bump only when newly added\"\n * semantics; a tag has no object to replace, so re-adds are idempotent).\n */\n addTag(entity: Entity, tag: TagType): void {\n const store = this.store(tag);\n if (!store.has(entity)) {\n store.set(entity, TAG_VALUE);\n this._version++;\n if (this.bitmask) this.bitmask.set(entity as number, tag.id);\n }\n }\n\n /** Whether an entity has a tag. Alias of `has(entity, tag)`. */\n hasTag(entity: Entity, tag: TagType): boolean {\n return this.store(tag).has(entity);\n }\n\n /** Remove a tag. Bumps version only when one was actually removed. */\n removeTag(entity: Entity, tag: TagType): void {\n if (this.stores[tag.id]?.remove(entity)) {\n this._version++;\n if (this.bitmask) this.bitmask.clear(entity as number, tag.id);\n }\n }\n /**\n * Enable a per-entity component bitmask index for this world. Builds a\n * {@link Bitmask} sized to `maxEntities` and back-fills it from every existing\n * store, then keeps it in sync on every subsequent add/remove/despawn.\n * Idempotent. Pays nothing until called. Returns the world for chaining.\n *\n * Contract: the index mirrors only mutations made through the World API\n * (add/remove/addComponent/removeComponent/addTag/removeTag/despawn+flush). A\n * caller that pokes a raw store via `getStoreRaw`/`store(...).set(...)` bypasses\n * it, exactly like the query version counter; `hasMask` would then drift for\n * that entity. Use the World API for any entity you also query via the mask.\n */\n enableBitmask(): this {\n if (this.bitmask) return this;\n const bm = new Bitmask(this.maxEntities);\n // Back-fill from every existing store, in store-id order. Index `id` IS the\n // component id, and bit-set is idempotent, so the result is independent of\n // traversal order.\n for (let id = 0; id < this.stores.length; id++) {\n const s = this.stores[id];\n if (s === undefined) continue;\n const ents = s.iterEntities();\n for (let i = 0; i < ents.length; i++) bm.set(ents[i] as number, id);\n }\n this.bitmask = bm;\n return this;\n }\n\n /** Whether the bitmask index is enabled. */\n isBitmaskEnabled(): boolean {\n return this.bitmask !== null;\n }\n\n /**\n * O(1) membership test through the bitmask (requires {@link enableBitmask}).\n * Throws if the index is disabled. Semantically identical to `has`, but a\n * single word-and-test instead of a sparse lookup.\n */\n hasMask<T>(entity: Entity, def: ComponentType<T>): boolean {\n if (!this.bitmask) throw new Error(\"hasMask requires enableBitmask()\");\n return this.bitmask.has(entity as number, def.id);\n }\n\n /**\n * O(words) \"has ALL of these components\" test through the bitmask (requires\n * {@link enableBitmask}). `defs` is hashed into a reusable query signature on\n * first use and cached by the def-id list. Throws if disabled.\n */\n hasAllMask(entity: Entity, defs: readonly ComponentType<unknown>[]): boolean {\n if (!this.bitmask) throw new Error(\"hasAllMask requires enableBitmask()\");\n let key = \"\";\n const ids: number[] = [];\n for (let i = 0; i < defs.length; i++) {\n const id = defs[i].id;\n ids.push(id);\n key += i === 0 ? id : `,${id}`;\n }\n let sig = this.maskSigs.get(key);\n if (!sig) {\n sig = this.bitmask.signature(ids);\n this.maskSigs.set(key, sig);\n }\n return this.bitmask.hasAll(entity as number, sig);\n }\n /**\n * Compile an INCREMENTAL query. Accepts the same spec as {@link select}: bare\n * defs (required `with`), `without(...)` / `maybe(...)` terms, and `any(...)`\n * groups. Unlike `compileQuery`/`select`, its match set is MAINTAINED as\n * components are added/removed (and on despawn) rather than rebuilt on the next\n * access, eliminating the per-frame O(n) rebuild a system pays when it mutates\n * and then queries the same components every frame. Returns an\n * {@link IncrementalQuery} handle (`each` / `results` / `count` / `view`).\n *\n * Deliberately opt-in, for hot mutate-then-query systems:\n * - its iteration ORDER is the incremental \"append-on-match /\n * swap-delete-on-unmatch\" order, which is deterministic but different from\n * `query`/`compileQuery`/`select`;\n * - it allocates a per-query sparse index sized to `maxEntities` and adds a\n * reconcile to each membership-component add/remove (so it earns its keep\n * on a hot query, not on every query);\n * - it tracks only World-API mutations; a `getStoreRaw` write bypasses it,\n * like the bitmask.\n * Components present before this call are captured by a one-time initial scan.\n */\n compileIncremental(...args: QueryArg[]): IncrementalQuery {\n const { withIds, withoutIds, maybeIds, anyGroups, yieldPlan } =\n parseQueryArgs(args);\n const q = new IncrementalQuery(\n {\n isAlive: (e) => this.alive.has(e),\n storeIfPresent: (id) => this.stores[id],\n },\n this.maxEntities,\n withIds,\n withoutIds,\n maybeIds,\n anyGroups,\n yieldPlan,\n );\n q.rebuildFromStores();\n this.incrementalQueries.push(q);\n // Register only under membership components (with ∪ without ∪ any); a `maybe`\n // change never alters membership, so it must not trigger a reconcile.\n for (let i = 0; i < q.membershipDeps.length; i++) {\n const id = q.membershipDeps[i];\n let list = this.incrementalByComponent[id];\n if (list === undefined) {\n list = [];\n this.incrementalByComponent[id] = list;\n }\n list.push(q);\n }\n this.hasIncremental = true;\n return q;\n }\n\n private reconcileIncremental(componentId: number, entity: number): void {\n const qs = this.incrementalByComponent[componentId];\n if (qs === undefined) return;\n for (let i = 0; i < qs.length; i++) qs[i].reconcile(entity);\n }\n query<A>(a: ComponentType<A>): readonly QueryResult<[A]>[];\n query<A, B>(\n a: ComponentType<A>,\n b: ComponentType<B>,\n ): readonly QueryResult<[A, B]>[];\n query<A, B, C>(\n a: ComponentType<A>,\n b: ComponentType<B>,\n c: ComponentType<C>,\n ): readonly QueryResult<[A, B, C]>[];\n query<A, B, C, D>(\n a: ComponentType<A>,\n b: ComponentType<B>,\n c: ComponentType<C>,\n d: ComponentType<D>,\n ): readonly QueryResult<[A, B, C, D]>[];\n // 5+ components: the runtime is already variadic; this overload lifts the\n // type-level 4-cap (per-slot inference stops at 4, falling back to unknown[]).\n // `AnyComponentType` (not `unknown`) so specific component types flow in\n // without a cast; same variance reason as QueryArg (see types.ts).\n query(...defs: AnyComponentType[]): readonly QueryResult<unknown[]>[];\n query(...defs: ComponentType<unknown>[]): readonly QueryResult<unknown[]>[] {\n return this.queryEngine.query(defs);\n }\n\n queryFirst<A>(a: ComponentType<A>): QueryResult<[A]> | null {\n const results = this.query(a);\n return results.length > 0 ? results[0] : null;\n }\n\n each<A>(a: ComponentType<A>, fn: (e: Entity, a: A) => void): void;\n each<A, B>(\n a: ComponentType<A>,\n b: ComponentType<B>,\n fn: (e: Entity, a: A, b: B) => void,\n ): void;\n each<A, B, C>(\n a: ComponentType<A>,\n b: ComponentType<B>,\n c: ComponentType<C>,\n fn: (e: Entity, a: A, b: B, c: C) => void,\n ): void;\n each<A, B, C, D>(\n a: ComponentType<A>,\n b: ComponentType<B>,\n c: ComponentType<C>,\n d: ComponentType<D>,\n fn: (e: Entity, a: A, b: B, c: C, d: D) => void,\n ): void;\n // 5+ components: lifts the type-level 4-cap. The trailing arg is the callback;\n // the leading args are component defs (no per-slot inference beyond 4).\n // `AnyComponentType` for the variance reason documented on QueryArg.\n each(\n ...args: [\n ...defs: AnyComponentType[],\n fn: (e: Entity, ...c: never[]) => void,\n ]\n ): void;\n each(...args: unknown[]): void {\n const fn = args[args.length - 1] as (e: Entity, ...c: unknown[]) => void;\n const defs = args.slice(0, -1) as ComponentType<unknown>[];\n this.queryEngine.each(defs, fn);\n }\n\n /**\n * Resolve a query once and return a reusable handle. Prefer this over\n * `query`/`each` in per-frame hot loops: the handle skips the key derivation\n * and argument unpacking those entry points pay on every call. The handle\n * stays valid across structural changes and across `clear()`.\n */\n compileQuery<A>(a: ComponentType<A>): CompiledQuery<[A]>;\n compileQuery<A, B>(\n a: ComponentType<A>,\n b: ComponentType<B>,\n ): CompiledQuery<[A, B]>;\n compileQuery<A, B, C>(\n a: ComponentType<A>,\n b: ComponentType<B>,\n c: ComponentType<C>,\n ): CompiledQuery<[A, B, C]>;\n compileQuery<A, B, C, D>(\n a: ComponentType<A>,\n b: ComponentType<B>,\n c: ComponentType<C>,\n d: ComponentType<D>,\n ): CompiledQuery<[A, B, C, D]>;\n // 5+ components: lifts the type-level 4-cap (tuple falls back to unknown[]).\n // `AnyComponentType` for the variance reason documented on QueryArg.\n compileQuery(...defs: AnyComponentType[]): CompiledQuery<unknown[]>;\n compileQuery(...defs: ComponentType<unknown>[]): CompiledQuery<unknown[]> {\n return this.queryEngine.compile(defs);\n }\n\n /**\n * The filter-aware query entry point. Returns a reusable {@link CompiledQuery}\n * handle, like {@link compileQuery}, but accepts `without(...)` / `maybe(...)`\n * terms and `any(...)` groups alongside bare required defs, and lifts the\n * type-level 4-cap. A spec with no required (bare/`with`) component throws.\n *\n * A pure-`with` `select(...)` delegates to the same cache as\n * `query`/`compileQuery`, so the result reference is identical.\n */\n select<A>(a: ComponentType<A>): CompiledQuery<[A]>;\n select<A, B>(a: ComponentType<A>, b: ComponentType<B>): CompiledQuery<[A, B]>;\n select<A, B, C>(\n a: ComponentType<A>,\n b: ComponentType<B>,\n c: ComponentType<C>,\n ): CompiledQuery<[A, B, C]>;\n select<A, B, C, D>(\n a: ComponentType<A>,\n b: ComponentType<B>,\n c: ComponentType<C>,\n d: ComponentType<D>,\n ): CompiledQuery<[A, B, C, D]>;\n select(...args: QueryArg[]): CompiledQuery<unknown[]>;\n select(...args: QueryArg[]): CompiledQuery<unknown[]> {\n return this.queryEngine.compileSpec(args);\n }\n\n /** O(1) count of entities with a component. */\n count<T>(def: ComponentType<T>): number {\n return this.stores[def.id]?.size() ?? 0;\n }\n\n /** Drop all cached queries (memory reclaim). Retained handles keep working but rebuild independently. */\n clearQueryCache(): void {\n this.queryEngine.dropCaches();\n this.maskSigs.clear();\n }\n\n /**\n * Direct dense-store access for the rare hand-tuned loop. A raw `set`/`remove`\n * through it bypasses the bitmask and incremental-query indexes (maintained only\n * by the World mutators), so `hasMask` and incremental queries can drift for an\n * entity mutated this way. The version-gated query cache and change-tracking\n * (which live in the store) stay correct.\n */\n getStoreRaw<T>(def: ComponentType<T>): ComponentStore<T> {\n return this.store(def);\n }\n /**\n * Enable object pooling for a component's store. On despawn/remove the object\n * is reset and parked; the next addComponent reuses it. Only factory\n * components ({@link PooledComponentType}) can be pooled; the `reset` hook is\n * guaranteed by the type.\n */\n enablePooling<T>(def: PooledComponentType<T>): void {\n this.store(def).enablePooling(def.reset);\n }\n /**\n * Apply a {@link CommandBuffer}'s queued add/remove/addComponent/despawn ops\n * against this world, in record order, then clear the buffer. Delegates to the\n * same `add`/`remove`/`addComponent`/`despawn` methods, so version bumps,\n * pooling, and deferred-despawn timing are identical to immediate calls. Does\n * NOT call flush(): a queued despawn is applied as a deferred despawn (visible\n * on the next flush()), preserving despawn timing exactly.\n */\n applyCommands(buffer: CommandBuffer): void {\n buffer.flushInto(this);\n }\n /**\n * Opt a component type into added/removed/changed tracking. Idempotent.\n * A type never passed here records nothing. Tracking does NOT retroactively\n * record existing members, only post-enable transitions.\n */\n trackChanges<T>(def: ComponentType<T>): void {\n const s = this.store(def);\n if (!s.isTracking()) {\n s.enableTracking();\n this.trackedStores.push(s as ComponentStore<unknown>);\n }\n }\n\n /** Entities that gained `def` since the last clearChanges(), in dense order. */\n added<T>(def: ComponentType<T>): readonly Entity[] {\n return (\n (this.stores[def.id]?.iterAdded() as readonly Entity[] | undefined) ??\n _emptyEntities\n );\n }\n\n /** Entities that lost `def` since the last clearChanges(), in dense order. */\n removed<T>(def: ComponentType<T>): readonly Entity[] {\n return (\n (this.stores[def.id]?.iterRemoved() as readonly Entity[] | undefined) ??\n _emptyEntities\n );\n }\n\n /** Entities marked changed since the last clearChanges(), in dense order. */\n changed<T>(def: ComponentType<T>): readonly Entity[] {\n return (\n (this.stores[def.id]?.iterChanged() as readonly Entity[] | undefined) ??\n _emptyEntities\n );\n }\n\n /**\n * Record an explicit mutation of an existing component. No-op when untracked\n * or absent. Coarse: no dedup; calling it twice on the same entity records\n * two entries. Consumers needing a unique set must dedup themselves.\n */\n markChanged<T>(entity: Entity, def: ComponentType<T>): void {\n this.stores[def.id]?.markChanged(entity);\n }\n\n /**\n * Get a component and, if its store is tracked & the entity has it, record it\n * changed. Returns the live stored object (mutate it in place) or undefined if\n * absent. The ergonomic read-then-mark path for tracked mutable components.\n */\n getMut<T>(entity: Entity, def: ComponentType<T>): T | undefined {\n const s = this.stores[def.id] as ComponentStore<T> | undefined;\n if (s === undefined) return undefined;\n const c = s.get(entity);\n if (c !== undefined) s.markChanged(entity);\n return c;\n }\n\n /**\n * Drain all tracked stores' added/removed/changed lists. Call once per frame,\n * like events.clearAll(). Callbacks do NOT auto-drain, so this stays the\n * primary lifecycle hook; skipping it lets the delta lists grow unbounded.\n */\n clearChanges(): void {\n for (const s of this.trackedStores) s.drainChanges();\n }\n\n /**\n * Fire `fn(e)` for each entity that gained `def`, at one deterministic point\n * inside flush() (after structural changes settle). Auto-enables tracking for\n * `def`. Does NOT auto-drain; call clearChanges() each frame.\n */\n onAdded<T>(def: ComponentType<T>, fn: (entity: Entity) => void): void {\n this.trackChanges(def);\n if (this.addedCallbacks === null) this.addedCallbacks = new Map();\n const list = this.addedCallbacks.get(def.id);\n if (list) list.push(fn);\n else this.addedCallbacks.set(def.id, [fn]);\n }\n\n /**\n * Fire `fn(e)` for each entity that lost `def`, at one deterministic point\n * inside flush() (after structural changes settle). Auto-enables tracking for\n * `def`. Does NOT auto-drain; call clearChanges() each frame.\n */\n onRemoved<T>(def: ComponentType<T>, fn: (entity: Entity) => void): void {\n this.trackChanges(def);\n if (this.removedCallbacks === null) this.removedCallbacks = new Map();\n const list = this.removedCallbacks.get(def.id);\n if (list) list.push(fn);\n else this.removedCallbacks.set(def.id, [fn]);\n }\n\n // Iterate registered callbacks (Map insertion = registration order) and, per\n // component, its delta list in dense store order, fully reproducible.\n private fireCallbacks(\n map: Map<number, ((e: Entity) => void)[]>,\n isAdded: boolean,\n ): void {\n for (const [id, fns] of map) {\n const store = this.stores[id];\n if (store === undefined) continue;\n const list = isAdded ? store.iterAdded() : store.iterRemoved();\n // Fire only entries appended since the last flush this frame, then advance\n // the cursor; the delta list itself drains once per frame (clearChanges),\n // but flush() may run several times before then, so the cursor is what\n // keeps each transition firing exactly once.\n const from = isAdded ? store.addedFired : store.removedFired;\n for (let i = from; i < list.length; i++) {\n const e = list[i] as Entity;\n for (let j = 0; j < fns.length; j++) fns[j](e);\n }\n if (isAdded) store.setAddedFired(list.length);\n else store.setRemovedFired(list.length);\n }\n }\n /** Set a resource value, by typed token (canonical) or string key. */\n setResource<T>(type: ResourceType<T>, value: T): void;\n setResource<T>(key: string, value: T): void;\n setResource<T>(typeOrKey: ResourceType<T> | string, value: T): void {\n if (typeof typeOrKey === \"string\") {\n this.stringResources.set(typeOrKey, value);\n } else {\n this.resources.set(typeOrKey.id, value);\n }\n }\n\n /**\n * Get a resource value. By token it throws if unset; by string key it returns\n * undefined if unset.\n */\n getResource<T>(type: ResourceType<T>): T;\n getResource<T>(key: string): T | undefined;\n getResource<T>(typeOrKey: ResourceType<T> | string): T | undefined {\n if (typeof typeOrKey === \"string\") {\n return this.stringResources.get(typeOrKey) as T | undefined;\n }\n const val = this.resources.get(typeOrKey.id);\n if (val === undefined) {\n throw new Error(`Resource \"${typeOrKey.name}\" not set`);\n }\n return val as T;\n }\n\n /** Get a resource value by token, or undefined if not set. */\n tryGetResource<T>(type: ResourceType<T>): T | undefined {\n return this.resources.get(type.id) as T | undefined;\n }\n\n /** Remove a resource, by typed token or string key. The inverse of setResource; no-op if unset. */\n unsetResource<T>(type: ResourceType<T>): void;\n unsetResource(key: string): void;\n unsetResource<T>(typeOrKey: ResourceType<T> | string): void {\n if (typeof typeOrKey === \"string\") {\n this.stringResources.delete(typeOrKey);\n } else {\n this.resources.delete(typeOrKey.id);\n }\n }\n /**\n * Get (lazily initializing) this token's local scratch state. The value is\n * created via the token's `init` on first access for this World and then\n * returned by reference on every subsequent call, so mutations persist across\n * frames. Local state is private to whoever holds the token (typically one\n * system) and is independent of resources, components, and events.\n */\n local<T>(type: LocalType<T>): T {\n let v = this.locals.get(type.id);\n if (v === undefined && !this.locals.has(type.id)) {\n v = type.init();\n this.locals.set(type.id, v);\n }\n return v as T;\n }\n\n /**\n * Whether this local has been initialized in this World yet (i.e. `local()`\n * has been called for the token at least once since construction/clear).\n */\n hasLocal<T>(type: LocalType<T>): boolean {\n return this.locals.has(type.id);\n }\n\n /**\n * Reset a single local back to \"uninitialized\": the next `local()` call\n * rebuilds it from `init`. No-op if it was never initialized.\n */\n resetLocal<T>(type: LocalType<T>): void {\n this.locals.delete(type.id);\n }\n /** Despawn all entities and clear all stores, resources, and events. */\n clear(): void {\n this.pendingDespawns.length = 0;\n // Bump live ids' generations before dropping them so pre-clear handles/refs\n // can't resolve to a reused id once nextId is reset below.\n for (const id of this.alive) {\n this.generations[id as number] =\n (this.generations[id as number] + 1) >>> 0;\n }\n this.alive.clear();\n for (const store of this.activeStores) {\n store.clear();\n }\n // The bitmask index survives clear() (opt-in persists, like pooling and\n // tracking), but every bit must drop with the stores. A fresh Bitmask is the\n // simplest correct reset; cheap, since clear() is a world reset, not a\n // per-frame path. Cached signatures stay valid (bit positions are static).\n if (this.bitmask) this.bitmask = new Bitmask(this.maxEntities);\n this.resources.clear();\n this.stringResources.clear();\n // Per-system locals are DATA, not configuration: a cleared World forgets all\n // locals, so the next local() rebuilds from init. Touches only the new map,\n // empty for any consumer that never called local().\n this.locals.clear();\n this.events.clearAll();\n this.queryEngine.clear();\n // Incremental queries survive clear() (registration persists, like compiled\n // queries) but their match sets must empty with the stores; the add hooks\n // repopulate as entities are re-spawned. No-op when none are registered.\n for (let i = 0; i < this.incrementalQueries.length; i++) {\n this.incrementalQueries[i].clear();\n }\n // Change tracking: each ComponentStore.clear() already reset its own delta\n // lists and kept its `tracked` flag (opt-in survives clear, like pooling),\n // so trackedStores stays valid and intact. Drop only the callback maps so a\n // reused World does not keep stale onAdded/onRemoved closures.\n this.addedCallbacks = null;\n this.removedCallbacks = null;\n // Reissue ids from 1; generations are monotonic per index and not reset.\n this.nextId = 1;\n this.recycled.length = 0;\n // Reverse index: clear() resets DATA, not CONFIGURATION; drop every tracked\n // edge but keep backrefsEnabled, matching how clear() leaves pooling/tracking\n // opt-ins intact. No-op when backrefs were never enabled (map is null).\n if (this.backrefEdges !== null) this.backrefEdges.clear();\n if (this.holderToTargets !== null) this.holderToTargets.clear();\n }\n // Shared (index, generation) packing for both handles and refs: index in the\n // low indexBits, generation above. handleOf/ref/resolve/deref/unref all route\n // through these so the two encodings never fork.\n private pack(index: number, gen: number): number {\n return gen * (this.indexMask + 1) + index;\n }\n private unpackIndex(value: number): number {\n return value & this.indexMask;\n }\n private unpackGen(value: number): number {\n return Math.floor(value / (this.indexMask + 1));\n }\n\n /** Stamp the entity's current generation into a stable, storable handle. */\n handleOf(entity: Entity): EntityHandle {\n const index = entity as number;\n return this.pack(index, this.generations[index]) as EntityHandle;\n }\n\n /**\n * Resolve a handle to its entity, or null if the entity is no longer alive\n * with that generation (it was despawned, or despawned-and-recycled). The\n * returned number is the bare {@link Entity} index, usable with every existing\n * World/store API.\n */\n resolve(handle: EntityHandle): Entity | null {\n const h = handle as number;\n const index = this.unpackIndex(h);\n const gen = this.unpackGen(h);\n if (this.generations[index] !== gen) return null;\n if (!this.alive.has(index as Entity)) return null;\n return index as Entity;\n }\n\n /** Whether `resolve(handle)` would return a non-null entity. */\n isHandleValid(handle: EntityHandle): boolean {\n return this.resolve(handle) !== null;\n }\n // A ref is the SAME (index, generation) packing as a handle (see handleOf),\n // so the two never fork. Taking a ref is a pure read: it never bumps version\n // and never throws; a ref to a dead/never-spawned entity simply won't resolve.\n\n /**\n * Create a storable reference to `entity`, stamped with its current\n * generation. If backrefs are enabled and `holder` is supplied, registers a\n * reverse edge so `backrefs(entity)` will report `holder`. Pass `holder`\n * (the entity that stores the ref) whenever you store the ref in a component,\n * so the backref edge is tracked; enabling backrefs does not retroactively\n * index refs taken without a holder.\n */\n ref(entity: Entity): EntityRef;\n ref(entity: Entity, holder: Entity): EntityRef;\n ref(entity: Entity, holder?: Entity): EntityRef {\n const index = entity as number;\n const r = this.pack(index, this.generations[index]) as EntityRef;\n if (\n holder !== undefined &&\n this.backrefsEnabled &&\n this.backrefEdges !== null\n ) {\n // Register the (holder -> target) edge under the TARGET's index. Dedupe\n // keeps backrefs() a set; includes() is O(k) but k is tiny for the\n // surgical parent/child and projectile->owner fan-in this serves.\n let holders = this.backrefEdges.get(index);\n if (holders === undefined) {\n holders = [];\n this.backrefEdges.set(index, holders);\n }\n if (!holders.includes(holder)) holders.push(holder);\n // Mirror the edge under the holder so flush() can sweep it when the holder\n // despawns (see flush()).\n if (this.holderToTargets !== null) {\n let targets = this.holderToTargets.get(holder as number);\n if (targets === undefined) {\n targets = new Set();\n this.holderToTargets.set(holder as number, targets);\n }\n targets.add(index);\n }\n }\n return r;\n }\n\n /**\n * Resolve a ref to the live entity, or `null` if the target was despawned\n * (generation mismatch) or the ref is {@link NULL_REF}. Pure read: no\n * allocation, no version bump, no structural change. A recycled-and-respawned\n * index is alive but at a bumped generation, so the generation check catches\n * the stale-alias case (the whole point of a ref over a bare entity id).\n */\n deref(ref: EntityRef): Entity | null {\n if (ref === NULL_REF) return null;\n const r = ref as number;\n const index = this.unpackIndex(r);\n const gen = this.unpackGen(r);\n if (this.generations[index] !== gen) return null;\n if (!this.alive.has(index as Entity)) return null;\n return index as Entity;\n }\n\n /** Whether `ref` still points at a live entity. `deref(ref) !== null`. */\n isRefValid(ref: EntityRef): boolean {\n return this.deref(ref) !== null;\n }\n /**\n * Enable the reverse index. Idempotent. After this, every `ref(target,\n * holder)` records a (holder -> target) edge; `backrefs(target)` lists the\n * holders, and flush() sweeps edges whose target was despawned. Off by\n * default; when off, `ref()` does no edge bookkeeping and `backrefs()` returns\n * the shared empty array. Enabling it does NOT retroactively index refs taken\n * before the call.\n */\n enableBackrefs(): void {\n if (this.backrefsEnabled) return;\n this.backrefsEnabled = true;\n this.backrefEdges = new Map();\n this.holderToTargets = new Map();\n }\n\n /** Whether the reverse index is enabled. */\n hasBackrefs(): boolean {\n return this.backrefsEnabled;\n }\n\n /**\n * Entities that hold a (tracked) ref pointing at `target`, in deterministic\n * insertion order, de-duplicated, filtered to those still alive. Returns a\n * shared READ-ONLY empty array when backrefs are disabled or none point at\n * `target`; do not retain it across a structural change (flush() may sweep\n * the underlying list). Never throws.\n *\n * Contract: a holder is auto-swept only when the target dies. A holder is not\n * auto-removed when the holder itself despawns, so its edge can linger; this\n * method filters out despawned holders so they are never reported. A holder\n * index that has been recycled into a different live entity cannot be\n * distinguished and may still appear, so callers needing certainty should\n * `unref()` in the holder's own teardown or re-validate a stored EntityRef.\n */\n backrefs(target: Entity): readonly Entity[] {\n if (!this.backrefsEnabled || this.backrefEdges === null)\n return EMPTY_BACKREFS;\n const holders = this.backrefEdges.get(target as number);\n if (holders === undefined || holders.length === 0) return EMPTY_BACKREFS;\n // Common case: every holder is alive; return the stored array (no alloc).\n let allAlive = true;\n for (let i = 0; i < holders.length; i++) {\n if (!this.alive.has(holders[i])) {\n allAlive = false;\n break;\n }\n }\n if (allAlive) return holders;\n const live: Entity[] = [];\n for (let i = 0; i < holders.length; i++) {\n if (this.alive.has(holders[i])) live.push(holders[i]);\n }\n return live.length === 0 ? EMPTY_BACKREFS : live;\n }\n\n /**\n * Drop a previously-registered reverse edge (e.g. when a holder overwrites or\n * clears the ref field before the target dies). No-op if backrefs are off or\n * the edge is unknown. Order-preserving (indexOf + splice, not swap-remove) so\n * the remaining holder order stays a pure function of insertion/removal order.\n * Keeps the reverse index from leaking stale holders that outlive the ref but\n * not the target.\n */\n unref(ref: EntityRef, holder: Entity): void {\n if (!this.backrefsEnabled || this.backrefEdges === null) return;\n const index = this.unpackIndex(ref as number);\n const holders = this.backrefEdges.get(index);\n if (holders === undefined) return;\n const at = holders.indexOf(holder);\n if (at !== -1) {\n holders.splice(at, 1);\n if (holders.length === 0) this.backrefEdges.delete(index);\n }\n const targets = this.holderToTargets?.get(holder as number);\n if (targets !== undefined) {\n targets.delete(index);\n if (targets.size === 0) this.holderToTargets?.delete(holder as number);\n }\n }\n}\n\n// Shared read-only empty backrefs result: when the reverse index is disabled or\n// no holder points at a target, backrefs() hands back this single frozen array,\n// so the disabled path allocates nothing and returns a stable reference.\nconst EMPTY_BACKREFS: readonly Entity[] = Object.freeze([]);\n\n// Shared empty result for added/removed/changed reads of an untracked or\n// never-created component type: never allocates, never bumps version.\nconst _emptyEntities: readonly Entity[] = [];\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/bitmask.ts","../src/command-buffer.ts","../src/events.ts","../src/incremental-query.ts","../src/migration.ts","../src/query.ts","../src/schedule.ts","../src/serialize.ts","../src/store.ts","../src/spatial-hash.ts","../src/types.ts","../src/world.ts"],"sourcesContent":["// Bitmask: opt-in per-entity component signature index\n// Enabled per World via `enableBitmask()`. A derived mirror of dense-store\n// membership that accelerates O(1) `hasMask` / O(words) `hasAllMask` tests; the\n// dense stores remain the data home. set/clear are idempotent, commutative bit\n// ops, so a row's final state depends only on which (entity, component) pairs are\n// members, never the order they were applied.\n//\n// Layout: `rows` is one flat Uint32Array of `capacity * wordsPerEntity`; entity\n// `e` owns `[e * words, (e + 1) * words)`. `words` grows lazily as higher\n// component ids are first set, keeping the common small-id case at 1–2 words.\n// Component ids are assigned at module load, so width stabilizes after the first\n// back-fill and never changes on the per-frame path.\n\nexport class Bitmask {\n private readonly capacity: number;\n private words = 1;\n private rows: Uint32Array;\n\n constructor(capacity: number) {\n this.capacity = capacity;\n this.rows = new Uint32Array(capacity * 1);\n }\n\n /** Current words per entity (>= 1). */\n get wordsPerEntity(): number {\n return this.words;\n }\n\n // Grow the per-entity stride so `compId` is addressable, re-laying-out every\n // existing row at the wider stride. Only triggers when a never-before-seen\n // high component id is first set, never on the hot path.\n private ensureWidth(compId: number): void {\n const need = (compId >>> 5) + 1;\n if (need <= this.words) return;\n const next = new Uint32Array(this.capacity * need);\n const old = this.words;\n for (let e = 0; e < this.capacity; e++) {\n next.set(this.rows.subarray(e * old, (e + 1) * old), e * need);\n }\n this.rows = next;\n this.words = need;\n }\n\n /** Set bit `compId` for entity `e`. Grows word width if needed. */\n set(e: number, compId: number): void {\n this.ensureWidth(compId);\n this.rows[e * this.words + (compId >>> 5)] |= (1 << (compId & 31)) >>> 0;\n }\n\n /** Clear bit `compId` for entity `e`. */\n clear(e: number, compId: number): void {\n const w = compId >>> 5;\n if (w >= this.words) return;\n this.rows[e * this.words + w] &= ~((1 << (compId & 31)) >>> 0);\n }\n\n /** Test bit `compId` for entity `e`. */\n has(e: number, compId: number): boolean {\n const w = compId >>> 5;\n if (w >= this.words) return false;\n return (this.rows[e * this.words + w] & ((1 << (compId & 31)) >>> 0)) !== 0;\n }\n\n /** Clear every bit for entity `e` (despawn path). */\n clearEntity(e: number): void {\n this.rows.fill(0, e * this.words, (e + 1) * this.words);\n }\n\n /**\n * Build a packed query signature: the OR of each def's single bit, sized to\n * span the highest component id in `compIds`. Bit positions are static per\n * component id, so the returned signature is valid forever and can be cached.\n */\n signature(compIds: readonly number[]): Uint32Array {\n let maxWord = 0;\n for (let i = 0; i < compIds.length; i++) {\n const w = compIds[i] >>> 5;\n if (w > maxWord) maxWord = w;\n }\n const sig = new Uint32Array(maxWord + 1);\n for (let i = 0; i < compIds.length; i++) {\n const id = compIds[i];\n sig[id >>> 5] |= (1 << (id & 31)) >>> 0;\n }\n return sig;\n }\n\n /** Whether entity `e`'s row has all bits in `sig` set. */\n hasAll(e: number, sig: Uint32Array): boolean {\n for (let w = 0; w < sig.length; w++) {\n const want = sig[w];\n if (want === 0) continue;\n if (w >= this.words) return false;\n // `>>> 0` normalizes the AND result to unsigned: a component on bit 31 of\n // its word makes `want` include 0x80000000, and JS `&` yields a SIGNED\n // int32, so without this the masked value compares as negative and a true\n // match wrongly returns false. `want` is already unsigned (Uint32Array).\n if ((this.rows[e * this.words + w] & want) >>> 0 !== want) return false;\n }\n return true;\n }\n}\n","// CommandBuffer: opt-in deferred structural mutation\n// Records add / remove / addComponent / despawn and replays them in strict record\n// order at a single point chosen by the consumer: an explicit\n// `world.applyCommands(buf)`, or a Schedule with a `commandBuffer` (applied at\n// each group boundary). Systems enqueue mutations that take effect only after\n// iteration finishes, removing mid-iteration structural-mutation hazards.\n//\n// World, Schedule, and this module reference each other as types only, so there\n// is no runtime import cycle.\n//\n// Caller rules (determinism contract):\n// - Commands replay FIFO (index 0..n-1). The effect is a pure function of the\n// record sequence: no map iteration, sort, RNG, or time.\n// - Do NOT record into a buffer during its own flushInto. The supported entry\n// points (a Schedule group boundary or applyCommands) run no system during\n// apply, so this cannot arise in supported usage.\n// - addComponent stores its `data` Partial by reference and merges at apply\n// time; do not mutate `data` between record and apply (the same\n// read-only-until-applied contract the query result arrays carry).\n// - spawn is NOT buffered: it must return an id synchronously. A system spawns\n// immediately, then records component adds against the returned id, keeping id\n// allocation and recycle order identical to the immediate path.\n// - A recorded despawn defers to the next world.flush() (like world.despawn): a\n// later recorded add writes, then flush() strips it, identical to the\n// equivalent immediate world.* calls.\n\nimport type { ComponentType, Entity, PooledComponentType } from \"./types\";\nimport type { World } from \"./world\";\n\n/**\n * A recorded structural mutation. Discriminated by a numeric `kind` (0..3) so the\n * apply switch is a jump table and no string is allocated. Tag plus payload only,\n * no behavior, so the buffer is a pure ordered log that World replays verbatim.\n */\nexport type Command =\n | { kind: 0; type: ComponentType<unknown>; entity: Entity; data: unknown } // add\n | { kind: 1; type: ComponentType<unknown>; entity: Entity } // remove\n | {\n kind: 2;\n type: PooledComponentType<object>;\n entity: Entity;\n data?: object;\n } // addComponent\n | { kind: 3; entity: Entity }; // despawn\n\n/**\n * Records add/remove/addComponent/despawn and replays them, in record order, when\n * the consumer flushes the buffer (via `world.applyCommands(buf)` or a Schedule\n * configured with `commandBuffer`). Mirrors the World mutation surface so call\n * sites read identically to immediate mutation.\n */\nexport class CommandBuffer {\n private readonly commands: Command[] = [];\n\n /** Queue `world.add(entity, type, data)` for replay. Mirrors World.add. */\n add<T>(entity: Entity, type: ComponentType<T>, data: T): this {\n this.commands.push({\n kind: 0,\n type: type as ComponentType<unknown>,\n entity,\n data,\n });\n return this;\n }\n\n /** Queue `world.remove(entity, type)` for replay. Mirrors World.remove. */\n remove<T>(entity: Entity, type: ComponentType<T>): this {\n this.commands.push({\n kind: 1,\n type: type as ComponentType<unknown>,\n entity,\n });\n return this;\n }\n\n /**\n * Queue `world.addComponent(entity, def, data)` for replay. The factory/pool\n * acquisition and the Object.assign merge happen at APPLY time, not record time,\n * so a pooled object is never aliased while still recorded. The `data` Partial\n * is held by reference; do not mutate it between record and apply.\n */\n addComponent<T extends object>(\n entity: Entity,\n def: PooledComponentType<T>,\n data?: Partial<T>,\n ): this {\n this.commands.push({\n kind: 2,\n type: def as unknown as PooledComponentType<object>,\n entity,\n data: data as object | undefined,\n });\n return this;\n }\n\n /** Queue `world.despawn(entity)` for replay (it then defers to the next flush). */\n despawn(entity: Entity): this {\n this.commands.push({ kind: 3, entity });\n return this;\n }\n\n /** Number of queued commands (for tests/metrics). */\n size(): number {\n return this.commands.length;\n }\n\n /** Whether any command is queued. */\n isEmpty(): boolean {\n return this.commands.length === 0;\n }\n\n /** Drop all queued commands without applying them. */\n clear(): void {\n this.commands.length = 0;\n }\n\n /**\n * Apply every queued command against `world` in record order, then clear.\n * Equivalent to calling the matching `world.*` method for each, in order.\n * Idempotent on an empty buffer (no-op). Reused after apply (the array is\n * truncated, not reallocated).\n *\n * Iterated forward, index-based; record order is the contract. Each branch\n * delegates to the existing World method verbatim, so all version-bump /\n * pooling / deferred-despawn semantics are inherited unchanged.\n */\n flushInto(world: World): void {\n const commands = this.commands;\n for (let i = 0; i < commands.length; i++) {\n const c = commands[i];\n switch (c.kind) {\n case 0:\n world.add(c.entity, c.type, c.data);\n break;\n case 1:\n world.remove(c.entity, c.type);\n break;\n case 2:\n world.addComponent(c.entity, c.type, c.data);\n break;\n case 3:\n world.despawn(c.entity);\n break;\n }\n }\n this.commands.length = 0;\n }\n}\n","// Typed Event Bus: frame-scoped event queues\n// Events emitted during a frame are readable by later systems in the same frame.\n// Reads are non-destructive, so many systems may read one queue per frame. The\n// consumer owns the frame lifecycle: clearAll() empties every queue at frame\n// start, and the framework never emits or clears events on its own.\n\nimport type { EventType } from \"./types\";\n\nexport class EventBus {\n private readonly queues = new Map<number, unknown[]>();\n\n /** Emit an event. Subsequent systems can read it this frame. */\n emit<T>(type: EventType<T>, data: T): void {\n let queue = this.queues.get(type.id);\n if (!queue) {\n queue = [];\n this.queues.set(type.id, queue);\n }\n queue.push(data);\n }\n\n /**\n * Read all events of a given type emitted this frame. Non-destructive: many\n * systems may read the same queue in one frame. Returns the LIVE internal queue;\n * do not mutate it or retain it across frames (clearAll() empties it in place).\n * Use {@link readCopy} for a retainable snapshot.\n */\n read<T>(type: EventType<T>): ReadonlyArray<T> {\n return (this.queues.get(type.id) as T[] | undefined) ?? _empty;\n }\n\n /** Like {@link read} but returns a fresh array safe to mutate or retain across frames. */\n readCopy<T>(type: EventType<T>): T[] {\n const queue = this.queues.get(type.id) as T[] | undefined;\n return queue === undefined ? [] : queue.slice();\n }\n\n /** Check if any events of a given type were emitted this frame. */\n has<T>(type: EventType<T>): boolean {\n const queue = this.queues.get(type.id);\n return queue !== undefined && queue.length > 0;\n }\n\n /** Clear all event queues. Called at frame start. */\n clearAll(): void {\n for (const queue of this.queues.values()) {\n queue.length = 0;\n }\n }\n}\n\nconst _empty: ReadonlyArray<never> = [];\n","// Incremental query: opt-in, maintained not rebuilt\n// Maintains its match set incrementally as components are added/removed (and on\n// despawn), instead of rebuilding via a full smallest-store scan on the next\n// access after a mutation. This avoids the per-frame O(n) rebuild the\n// version-cached QueryEngine pays for a query that mutates and re-queries the\n// same components every frame.\n//\n// How it works: the World indexes incremental queries by component id and calls\n// `reconcile(entity)` on every add/remove of a membership component (with /\n// without / any). reconcile rechecks membership in O(terms) and adds/removes the\n// entity from a dense match list backed by a sparse `pos` index: the store's own\n// swap-delete bookkeeping, one level up. `maybe` components never change\n// membership, so they skip reconcile; `each()` reads their values live and\n// `results()` refreshes them lazily.\n//\n// Determinism: match-list order is append-on-match, swap-delete-on-unmatch, a\n// pure function of the operation sequence, but DIFFERENT from the rebuild path's\n// smallest-store-dense order. Hence opt-in: a consumer chooses it per hot query\n// and accepts that order, while `query` / `compileQuery` / `select` keep their\n// rebuild order and caching. A single boolean gates the World's hooks.\n\nimport type { YieldSlot } from \"./query\";\nimport type { ComponentStore } from \"./store\";\nimport type { Entity, QueryResult } from \"./types\";\n\n/** The minimal store-access surface (mirrors the QueryEngine's Queryable). */\nexport interface IncrementalAccess {\n isAlive(entity: Entity): boolean;\n storeIfPresent(id: number): ComponentStore<unknown> | undefined;\n}\n\ntype EachFn = (entity: Entity, ...components: unknown[]) => void;\n\nexport class IncrementalQuery {\n /** Required component ids. */\n readonly withIds: number[];\n /** Excluded component ids. */\n readonly withoutIds: number[];\n /** Optional component ids (yielded, never constrain membership). */\n readonly maybeIds: number[];\n /** `any(...)` groups: at least one member of each must be present. */\n readonly anyGroups: number[][];\n /** Declaration-ordered yield slots (with + maybe). */\n readonly yieldPlan: YieldSlot[];\n /**\n * Components whose add/remove must trigger a reconcile: with ∪ without ∪ any.\n * NOT maybe (it never changes membership). The World registers the query under\n * exactly these ids.\n */\n readonly membershipDeps: number[];\n\n // Dense match list + sparse entity->index (-1 if absent), mirroring the store.\n private readonly entities: Entity[] = [];\n private readonly pos: Int32Array;\n // Bumped whenever reconcile adds or removes a member; drives results() reuse.\n private membershipVersion = 0;\n\n // Reused per-call buffers (one allocation per query arity, not per entity).\n private readonly yieldStores: (ComponentStore<unknown> | undefined)[] = [];\n private readonly scratch: unknown[];\n\n // Maintained results() tuple cache: rebuilt over the (already maintained)\n // entities list only when membership changed or a yielded store changed.\n private cachedResults: QueryResult<unknown[]>[] = [];\n private resultsBuiltAt = -1;\n private readonly yieldDepVersions: number[];\n private readonly access: IncrementalAccess;\n\n constructor(\n access: IncrementalAccess,\n capacity: number,\n withIds: number[],\n withoutIds: number[],\n maybeIds: number[],\n anyGroups: number[][],\n yieldPlan: YieldSlot[],\n ) {\n this.access = access;\n this.withIds = withIds;\n this.withoutIds = withoutIds;\n this.maybeIds = maybeIds;\n this.anyGroups = anyGroups;\n this.yieldPlan = yieldPlan;\n const deps = new Set<number>(withIds);\n for (let i = 0; i < withoutIds.length; i++) deps.add(withoutIds[i]);\n for (let g = 0; g < anyGroups.length; g++)\n for (let j = 0; j < anyGroups[g].length; j++) deps.add(anyGroups[g][j]);\n this.membershipDeps = [...deps];\n this.pos = new Int32Array(capacity).fill(-1);\n this.scratch = new Array(1 + yieldPlan.length);\n this.yieldDepVersions = new Array(yieldPlan.length).fill(-1);\n }\n\n /** Whether `entity` satisfies every with/without/any term and is alive. */\n private matches(entity: number): boolean {\n if (!this.access.isAlive(entity as Entity)) return false;\n for (let i = 0; i < this.withIds.length; i++) {\n const s = this.access.storeIfPresent(this.withIds[i]);\n if (s === undefined || !s.has(entity as Entity)) return false;\n }\n for (let i = 0; i < this.withoutIds.length; i++) {\n const s = this.access.storeIfPresent(this.withoutIds[i]);\n if (s?.has(entity as Entity)) return false;\n }\n for (let g = 0; g < this.anyGroups.length; g++) {\n const group = this.anyGroups[g];\n let satisfied = false;\n for (let j = 0; j < group.length; j++) {\n const s = this.access.storeIfPresent(group[j]);\n if (s?.has(entity as Entity)) {\n satisfied = true;\n break;\n }\n }\n if (!satisfied) return false;\n }\n return true;\n }\n\n /**\n * Bring `entity`'s membership in line with `matches()`. Called by the World on\n * any membership-component add/remove for the entity, or on despawn. O(terms).\n */\n reconcile(entity: number): void {\n const should = this.matches(entity);\n const at = this.pos[entity];\n if (should && at === -1) {\n this.pos[entity] = this.entities.length;\n this.entities.push(entity as Entity);\n this.membershipVersion++;\n } else if (!should && at !== -1) {\n const last = this.entities.length - 1;\n const lastEntity = this.entities[last] as number;\n this.entities[at] = lastEntity as Entity;\n this.pos[lastEntity] = at;\n this.entities.length = last;\n this.pos[entity] = -1;\n this.membershipVersion++;\n }\n }\n\n /**\n * One-time full population, for compiling against an already-populated world.\n * Scans the smallest required store and reconciles each of its entities.\n */\n rebuildFromStores(): void {\n this.clear();\n let smallest = this.access.storeIfPresent(this.withIds[0]);\n if (smallest === undefined) return; // withIds[0]'s store absent => no matches\n for (let i = 1; i < this.withIds.length; i++) {\n const s = this.access.storeIfPresent(this.withIds[i]);\n if (s === undefined) return; // a required store is absent => no matches\n if (smallest === undefined || s.size() < smallest.size()) smallest = s;\n }\n if (smallest === undefined || smallest.size() === 0) return;\n const ents = smallest.iterEntities();\n for (let i = 0; i < ents.length; i++) this.reconcile(ents[i] as number);\n }\n\n /** Drop the whole match set (World.clear()). */\n clear(): void {\n for (let i = 0; i < this.entities.length; i++) {\n this.pos[this.entities[i] as number] = -1;\n }\n this.entities.length = 0;\n this.membershipVersion++;\n }\n\n count(): number {\n return this.entities.length;\n }\n\n /** The live match list (deterministic incremental order). Read-only. */\n view(): readonly Entity[] {\n return this.entities;\n }\n\n // Resolve the store for each yield slot into the reused `yieldStores` buffer.\n private resolveYieldStores(): void {\n const stores = this.yieldStores;\n const { yieldPlan } = this;\n stores.length = 0;\n for (let i = 0; i < yieldPlan.length; i++) {\n stores.push(this.access.storeIfPresent(yieldPlan[i].id));\n }\n }\n\n /**\n * Zero-rebuild iteration over the maintained match set. The callback must NOT\n * add/remove a membership component on a visited entity: that mutates the live\n * match list mid-iteration (swap-delete) and skips/double-visits; use\n * {@link results} for a stable snapshot. The generic lane shares one scratch\n * buffer, so do not re-enter this query's each() from within the callback.\n */\n each(fn: EachFn): void {\n const ents = this.entities;\n if (ents.length === 0) return;\n this.resolveYieldStores();\n const { yieldStores, yieldPlan } = this;\n // Fast lanes: all-required (no maybe), small arity; values via getUnsafe.\n if (this.maybeIds.length === 0 && yieldPlan.length <= 2) {\n if (yieldPlan.length === 1) {\n const s0 = yieldStores[0];\n if (s0 === undefined) return;\n for (let i = 0; i < ents.length; i++)\n fn(ents[i], s0.getUnsafe(ents[i]));\n return;\n }\n const s0 = yieldStores[0];\n const s1 = yieldStores[1];\n if (s0 === undefined || s1 === undefined) return;\n for (let i = 0; i < ents.length; i++) {\n const e = ents[i];\n fn(e, s0.getUnsafe(e), s1.getUnsafe(e));\n }\n return;\n }\n // Generic lane: reused scratch; optional slots via get (=> value|undefined).\n const scratch = this.scratch;\n for (let i = 0; i < ents.length; i++) {\n const e = ents[i];\n scratch[0] = e;\n for (let k = 0; k < yieldPlan.length; k++) {\n const s = yieldStores[k];\n scratch[1 + k] =\n s === undefined\n ? undefined\n : yieldPlan[k].optional\n ? s.get(e)\n : s.getUnsafe(e);\n }\n fn.apply(undefined, scratch as never);\n }\n }\n\n // Whether any yielded store changed since the results() cache was built (an\n // object replacement or a maybe add/remove that membership didn't capture).\n private yieldDepsChanged(): boolean {\n const yieldDepVersions = this.yieldDepVersions;\n const { yieldPlan } = this;\n for (let i = 0; i < yieldPlan.length; i++) {\n const s = this.access.storeIfPresent(yieldPlan[i].id);\n const v = s === undefined ? -1 : s.version;\n if (v !== yieldDepVersions[i]) return true;\n }\n return false;\n }\n\n /**\n * Allocation-stable tuple view, rebuilt over the (already maintained) match set\n * only when membership changed or a yielded component store changed, so it\n * stays cached across mutations to UNrelated components AND across frames with\n * no relevant change. Tuples follow declaration (yield) order. Do not retain\n * the array across a structural change (the reference is swapped on rebuild).\n */\n results(): readonly QueryResult<unknown[]>[] {\n if (\n this.resultsBuiltAt === this.membershipVersion &&\n !this.yieldDepsChanged()\n )\n return this.cachedResults;\n this.resolveYieldStores();\n const { entities, yieldStores, yieldPlan, yieldDepVersions } = this;\n const out: QueryResult<unknown[]>[] = new Array(entities.length);\n for (let i = 0; i < entities.length; i++) {\n const e = entities[i];\n const tuple: QueryResult<unknown[]> = [e];\n for (let k = 0; k < yieldPlan.length; k++) {\n const s = yieldStores[k];\n tuple.push(\n s === undefined\n ? undefined\n : yieldPlan[k].optional\n ? s.get(e)\n : s.getUnsafe(e),\n );\n }\n out[i] = tuple;\n }\n this.cachedResults = out;\n this.resultsBuiltAt = this.membershipVersion;\n for (let i = 0; i < yieldPlan.length; i++) {\n const s = this.access.storeIfPresent(yieldPlan[i].id);\n yieldDepVersions[i] = s === undefined ? -1 : s.version;\n }\n return out;\n }\n}\n","// Schema migration: linear, named per-component upgrade chains\n// A pure-data module (imports only `./types` for the ComponentType token),\n// driven by the serializer's load path.\n//\n// Every snapshot / delta blob carries a per-component `_version`. On restore the\n// decoded plain value is upgraded step-by-step from its stored version to the\n// component's current version before it is written into the World. The empty\n// registry is the identity: each component is implicitly version 0 with no steps.\n//\n// Determinism: `migrate` applies `steps[storedVersion..current-1]` in ascending\n// index order: no RNG, clock, or Map iteration (the chains Map is point-lookup\n// only). A fixed save buffer + fixed registry restores to an identical World.\n// Steps MUST be pure (no globals, RNG, or I/O); a consumer contract the type\n// system cannot enforce.\n\nimport type { ComponentType } from \"./types\";\n\n/**\n * One forward step in a component's linear migration chain. Transforms a plain\n * decoded value at version `from` into the shape at version `from + 1`. Pure:\n * no World access, no I/O, no RNG, deterministic. May mutate `prev` in place and\n * return it, or return a fresh object.\n */\nexport type MigrationStep = (\n prev: Record<string, unknown>,\n) => Record<string, unknown>;\n\n/**\n * A linear, named migration chain for one component type. `currentVersion` is\n * the version the live code writes; `steps[v]` upgrades a value from version `v`\n * to `v + 1`. A chain of N steps covers versions 0..N (currentVersion === N).\n */\nexport interface ComponentMigration {\n readonly componentId: number;\n readonly componentName: string;\n readonly currentVersion: number;\n /** Length === currentVersion. steps[v] : value@v -> value@(v+1). */\n readonly steps: readonly MigrationStep[];\n}\n\n/** Thrown when a stored version cannot be upgraded to current. */\nexport class MigrationError extends Error {\n readonly componentName: string;\n readonly storedVersion: number;\n readonly currentVersion: number;\n constructor(\n componentName: string,\n storedVersion: number,\n currentVersion: number,\n detail: string,\n ) {\n super(\n `Cannot migrate component \"${componentName}\" from v${storedVersion} ` +\n `to v${currentVersion}: ${detail}`,\n );\n this.componentName = componentName;\n this.storedVersion = storedVersion;\n this.currentVersion = currentVersion;\n this.name = \"MigrationError\";\n }\n}\n\n/**\n * Registry of per-component migration chains. Consumer-owned, passed to the\n * {@link Serializer}. An empty registry treats every component as version 0\n * with a zero-step identity chain.\n */\nexport class MigrationRegistry {\n /** chains keyed by ComponentType.id */\n private readonly chains = new Map<number, ComponentMigration>();\n\n /**\n * Define the linear chain for `def`. Call once per component with the full\n * ordered step list. `steps[i]` upgrades vi -> v(i+1); currentVersion is\n * `steps.length`. Re-registering the same component id throws (chains are\n * append-only by intent; mutate the array you pass instead). Returns `this`\n * for chaining (matches `Serializer.register` / `Schedule.addGroup`).\n */\n register<T>(def: ComponentType<T>, steps: readonly MigrationStep[]): this {\n if (this.chains.has(def.id)) {\n throw new Error(`migration chain for \"${def.name}\" already registered`);\n }\n if (steps.length === 0) {\n throw new Error(\n `migration chain for \"${def.name}\" has no steps: a zero-step chain is a no-op; omit it`,\n );\n }\n this.chains.set(def.id, {\n componentId: def.id,\n componentName: def.name,\n currentVersion: steps.length,\n // Copy the array so later external mutation can't desync currentVersion.\n steps: [...steps],\n });\n return this;\n }\n\n /**\n * Current (live-code) version for a component, or 0 if no chain registered.\n * Generic in the component's data type so a concrete `ComponentType<T>` flows\n * in without a cast (a bare `ComponentType<unknown>` would force one at every\n * call site under `strictFunctionTypes`); only `def.id` is read.\n */\n currentVersion<T>(def: ComponentType<T>): number {\n return this.currentVersionById(def.id);\n }\n\n /** Current version by raw component id. */\n currentVersionById(componentId: number): number {\n return this.chains.get(componentId)?.currentVersion ?? 0;\n }\n\n /**\n * Upgrade a decoded plain value from `storedVersion` to the component's\n * current version by applying each step in order. Returns the upgraded value\n * (same object identity allowed). Throws {@link MigrationError} when\n * `storedVersion` exceeds current (a save newer than the code), is negative,\n * or is not an integer.\n */\n migrate(\n componentId: number,\n storedVersion: number,\n value: Record<string, unknown>,\n componentName?: string,\n ): Record<string, unknown> {\n const chain = this.chains.get(componentId);\n const current = chain?.currentVersion ?? 0;\n const name = componentName ?? chain?.componentName ?? String(componentId);\n // Fast path: identity, no step calls, same object reference.\n if (storedVersion === current) return value;\n if (storedVersion < 0 || !Number.isInteger(storedVersion)) {\n throw new MigrationError(\n name,\n storedVersion,\n current,\n \"version is not a non-negative integer\",\n );\n }\n if (storedVersion > current) {\n throw new MigrationError(\n name,\n storedVersion,\n current,\n \"save is newer than the running code (no downgrade path)\",\n );\n }\n if (typeof value !== \"object\" || value === null) {\n throw new MigrationError(\n name,\n storedVersion,\n current,\n \"cannot migrate a non-object value: chains require object-shaped data\",\n );\n }\n // storedVersion < current ⇒ current > 0 ⇒ a chain is registered.\n // Apply each forward step in fixed ascending index order.\n let v = value;\n for (let s = storedVersion; s < current; s++) {\n // biome-ignore lint/style/noNonNullAssertion: storedVersion < current implies the chain exists.\n const step = chain!.steps[s];\n v = step(v); // step s upgrades vS -> v(S+1)\n }\n return v;\n }\n\n /** True if no chain is registered (lets the serializer skip the migrate path). */\n get isEmpty(): boolean {\n return this.chains.size === 0;\n }\n}\n","// Query engine: cached, allocation-stable, smallest-store-first\n// The matching entity list is cached and rebuilt only on a world version bump,\n// not per call. Component object references are stable (each component is created\n// once and mutated in place), so the cached result tuples stay valid until the\n// next version bump too.\n//\n// Returned arrays are READ-ONLY and must not be retained across a structural\n// change (add/remove/despawn): the version bump rebuilds the array, so stale\n// retention is observable (the same contract as iterData()).\n\nimport type { Bitmask } from \"./bitmask\";\nimport type { ComponentStore } from \"./store\";\nimport type {\n AnyComponentType,\n AnyGroup,\n ComponentType,\n Entity,\n QueryArg,\n QueryResult,\n QueryTerm,\n} from \"./types\";\n// Query filter term builders\n// These wrap a def or group of defs to mark its role inside a QuerySpec passed\n// to `world.select(...)`. A bare `ComponentType` passed to select() is treated\n// as a required `with` term without wrapping.\n\n/** Exclude entities that have `def`. Contributes no value to the yield tuple. */\nexport function without<T>(def: ComponentType<T>): QueryTerm<T> {\n return { kind: \"without\", def };\n}\n\n/**\n * Yield `def`'s value when present, `undefined` when absent; never constrains\n * membership. Contributes a `T | undefined` slot to the yield tuple in\n * declaration order.\n */\nexport function maybe<T>(def: ComponentType<T>): QueryTerm<T> {\n return { kind: \"maybe\", def };\n}\n\n/**\n * Require at least one of `defs` to be present. Contributes no value to the\n * yield tuple. `defs` is typed {@link AnyComponentType}[] so specific component\n * types flow in without a cast.\n */\nexport function any(...defs: AnyComponentType[]): AnyGroup {\n return { kind: \"any\", defs };\n}\n\n/** One declaration-ordered yield slot: the def's id and whether it is optional. */\nexport interface YieldSlot {\n id: number;\n optional: boolean;\n}\n\n/** Normalized form of a `select()` / `compileIncremental()` argument list. */\nexport interface ParsedQuery {\n /** Required (`with`) component defs, in declaration order. */\n withDefs: ComponentType<unknown>[];\n /** Required (`with`) component ids, in declaration order. */\n withIds: number[];\n /** Excluded (`without`) component ids. */\n withoutIds: number[];\n /** Optional (`maybe`) component ids (yielded, never constrain membership). */\n maybeIds: number[];\n /** `any(...)` groups: at least one member of each must be present. */\n anyGroups: number[][];\n /** Declaration-ordered yield slots (`with` + `maybe`; without/any excluded). */\n yieldPlan: YieldSlot[];\n}\n\n/**\n * Normalize a {@link QueryArg} list (bare defs = required `with`,\n * `without(...)` / `maybe(...)` terms, and `any(...)` groups) into id arrays and\n * a declaration-ordered yield plan. Shared by {@link QueryEngine.compileSpec} and\n * `World.compileIncremental` so both accept the identical filter spec. Throws if\n * there is no required (`with`) term: driving iteration off the whole alive set\n * is an O(all-entities) scan and a determinism-order question we keep closed.\n */\nexport function parseQueryArgs(args: QueryArg[]): ParsedQuery {\n const withDefs: ComponentType<unknown>[] = [];\n const withIds: number[] = [];\n const withoutIds: number[] = [];\n const maybeIds: number[] = [];\n const anyGroups: number[][] = [];\n const yieldPlan: YieldSlot[] = [];\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n if (\"kind\" in arg) {\n if (arg.kind === \"any\") {\n const group: number[] = [];\n for (let j = 0; j < arg.defs.length; j++) group.push(arg.defs[j].id);\n anyGroups.push(group);\n } else if (arg.kind === \"without\") {\n withoutIds.push(arg.def.id);\n } else if (arg.kind === \"maybe\") {\n maybeIds.push(arg.def.id);\n yieldPlan.push({ id: arg.def.id, optional: true });\n } else {\n withDefs.push(arg.def);\n withIds.push(arg.def.id);\n yieldPlan.push({ id: arg.def.id, optional: false });\n }\n } else {\n withDefs.push(arg);\n withIds.push(arg.id);\n yieldPlan.push({ id: arg.id, optional: false });\n }\n }\n if (withDefs.length === 0) {\n throw new Error(\n \"a query needs at least one required (non-maybe, non-without) component\",\n );\n }\n return { withDefs, withIds, withoutIds, maybeIds, anyGroups, yieldPlan };\n}\n\n/** The minimal World surface the query engine reads. */\nexport interface Queryable {\n isAlive(entity: Entity): boolean;\n /** The store for a component id, or undefined if none exists yet (no lazy create). */\n storeIfPresent(id: number): ComponentStore<unknown> | undefined;\n /**\n * The opt-in per-entity component bitmask index, or null when disabled. When\n * present, `rebuildEntities` replaces its per-store `has()` probe loop with a\n * single signature AND.\n */\n bitmask(): Bitmask | null;\n}\n\ninterface QueryCache {\n key: string;\n ids: number[];\n // Stores resolved in call order, refreshed alongside `entities`. Invariant:\n // whenever `entities.length > 0` this holds exactly `ids.length` live stores\n // in call order. A query that cannot match leaves both `entities` empty and\n // `stores` short, so store access is always gated on a non-empty `entities`.\n stores: ComponentStore<unknown>[];\n entities: Entity[];\n results: QueryResult<unknown[]>[];\n // Build epochs. `entitiesVersion` is bumped each time the entity list is\n // rebuilt; `resultsVersion` records the epoch at which the tuple array was\n // last built, so `each` and `query`/`results` can reuse matching work.\n entitiesVersion: number;\n resultsVersion: number;\n // Every store id this cache reads (required `with` ∪ without ∪ any ∪ maybe),\n // and a snapshot of their per-store versions at the last entities rebuild. The\n // cache rebuilds only when one of THESE stores changed; a mutation to an\n // unrelated component no longer invalidates this query.\n depIds: number[];\n depVersions: number[];\n // Cached required-components bitmask signature for the accelerated rebuild\n // (static per cache; computed once the bitmask is first observed). Null unused.\n reqSig: Uint32Array | null;\n // A bare-def cache leaves these arrays empty and keeps `spec` false. They are\n // populated only when a spec carries a without/maybe/any term.\n spec: boolean;\n // Required (`with`) defs, in declaration order. `ids`/`stores` mirror these\n // for pure-with paths, so smallest-store iteration and the fast `each` switch\n // keep reading `ids`/`stores`.\n withoutIds: number[];\n maybeIds: number[];\n anyGroups: number[][];\n // Declaration-ordered list of the defs that contribute a value to each tuple\n // (`with` => optional:false, `maybe` => optional:true; without/any excluded).\n // Drives both results-tuple building and each-arg assembly so the yield order\n // is exactly the call order.\n yieldPlan: YieldSlot[];\n // Stores parallel to yieldPlan, resolved during rebuild. A `with` yield store\n // is the matching `stores` entry; a `maybe` yield store may be undefined when\n // its store was never created (then the value is always undefined).\n yieldStores: (ComponentStore<unknown> | undefined)[];\n // Stores parallel to maybeIds (for membership-free optional reads); a never-\n // created maybe store is undefined.\n maybeStores: (ComponentStore<unknown> | undefined)[];\n // Reused scratch buffers (one allocation per cache arity, not per entity) for\n // the generic each / pairs lanes. Sized lazily in rebuild.\n scratch: unknown[];\n pairsScratch: unknown[];\n}\n\ntype EachFn = (entity: Entity, ...components: unknown[]) => void;\n\n/**\n * A reusable, pre-resolved query handle (see {@link QueryEngine.compile}).\n * `each` is the per-call zero-allocation hot path; `results` is the\n * allocation-stable, read-only tuple array (do not retain across a structural\n * change); `first` / `count` are conveniences.\n */\nexport interface CompiledQuery<T extends unknown[]> {\n each(fn: (entity: Entity, ...components: T) => void): void;\n results(): readonly QueryResult<T>[];\n first(): QueryResult<T> | null;\n count(): number;\n /**\n * Assert exactly one match and return its tuple; throws (with the actual\n * count) for zero or many. Use for singleton lookups (e.g. the player).\n */\n single(): QueryResult<T>;\n /**\n * Random-access the tuple for `entity` if it currently matches, else null.\n * The returned tuple is a FRESH array; unlike `results()`, it is NOT the\n * cached, allocation-stable reference, so it is safe to retain independently.\n */\n get(entity: Entity): QueryResult<T> | null;\n /**\n * Visit each unordered entity pair (`i < j` over the matched list) exactly\n * once. `fn` receives both entities followed by entity `a`'s component tuple\n * tail; fetch `b`'s components on demand via `get(b)` / direct store access\n * when needed (the broadphase-then-narrowphase pattern). Do NOT re-enter the\n * same compiled query's `each`/`pairs` inside this callback (the per-cache\n * scratch buffer would be clobbered).\n */\n pairs(fn: (a: Entity, b: Entity, ...components: T) => void): void;\n}\n\nexport class QueryEngine {\n private readonly caches = new Map<string, QueryCache>();\n private readonly world: Queryable;\n\n constructor(world: Queryable) {\n this.world = world;\n }\n\n /** Allocation-stable array of `[entity, ...components]` tuples. Read-only. */\n query(defs: ComponentType<unknown>[]): readonly QueryResult<unknown[]>[] {\n return this.resultsOn(this.getCache(defs));\n }\n\n /** First matching tuple, or null. */\n queryFirst(defs: ComponentType<unknown>[]): QueryResult<unknown[]> | null {\n return this.firstOn(this.getCache(defs));\n }\n\n /**\n * Zero-(per-entity)-allocation callback form. Iterates the cached entity list\n * and calls `fn` with components fetched straight from the dense stores; no\n * tuple objects are created. Use for the hottest inner loops.\n */\n each(defs: ComponentType<unknown>[], fn: EachFn): void {\n this.eachOn(this.getCache(defs), fn);\n }\n\n /**\n * Resolve the cache for `defs` once and return a reusable handle. The handle's\n * methods skip the per-call key derivation and variadic unpacking that the\n * `world.query/each(...)` entry points pay, so a compiled handle is the truly\n * per-call zero-allocation path for hot loops.\n */\n compile(defs: ComponentType<unknown>[]): CompiledQuery<unknown[]> {\n return this.handleFor(this.getCache(defs));\n }\n\n /**\n * Compile a query from a filter {@link QueryArg} spec: bare defs (required\n * `with`), `without(...)` / `maybe(...)` terms, and `any(...)` groups. Returns\n * the same reusable handle shape as {@link compile}, now also exposing\n * `single` / `get` / `pairs`.\n *\n * A spec with NO required (`with`) term throws: driving iteration off the\n * whole alive set would be an O(all-entities) scan and a determinism-order\n * question this API deliberately avoids. When the spec is pure-`with` (no\n * without/maybe/any) it delegates to the same cache as `world.query`/`compile`.\n */\n compileSpec(args: QueryArg[]): CompiledQuery<unknown[]> {\n const { withDefs, withoutIds, maybeIds, anyGroups, yieldPlan } =\n parseQueryArgs(args);\n\n // Pure-with spec: route back to the same cache used by `world.query(A)`.\n if (\n withoutIds.length === 0 &&\n maybeIds.length === 0 &&\n anyGroups.length === 0\n ) {\n return this.handleFor(this.getCache(withDefs));\n }\n\n return this.handleFor(\n this.getSpecCache(withDefs, withoutIds, maybeIds, anyGroups, yieldPlan),\n );\n }\n\n /** Build the reusable handle object shared by `compile` and `compileSpec`. */\n private handleFor(cache: QueryCache): CompiledQuery<unknown[]> {\n return {\n each: (fn) => this.eachOn(cache, fn),\n results: () => this.resultsOn(cache),\n first: () => this.firstOn(cache),\n count: () => this.countOn(cache),\n single: () => this.singleOn(cache),\n get: (entity) => this.getOn(cache, entity),\n pairs: (fn) => this.pairsOn(cache, fn),\n };\n }\n\n /**\n * Reset every cached query in place (used by World.clear()). The cache objects\n * are kept rather than dropped, so any {@link CompiledQuery} handle holding one\n * stays valid and simply rebuilds on next use.\n */\n clear(): void {\n for (const cache of this.caches.values()) {\n cache.entities.length = 0;\n cache.stores.length = 0;\n cache.results = [];\n cache.entitiesVersion = 0;\n cache.resultsVersion = -1;\n // Drop the dep-version snapshot so the next access sees `depsChanged` and\n // rebuilds (the stores were just cleared). reqSig (a static signature of\n // the required ids) stays valid.\n cache.depVersions.length = 0;\n // Spec caches also hold resolved yield/maybe stores parallel to entities;\n // drop them so a stale store reference can't survive a clear(). Plan/ids\n // and scratch buffers are kept.\n cache.yieldStores.length = 0;\n cache.maybeStores.length = 0;\n }\n }\n\n /** Drop all cached queries (memory reclaim). Retained handles keep working but rebuild independently. */\n dropCaches(): void {\n this.caches.clear();\n }\n\n private resultsOn(cache: QueryCache): readonly QueryResult<unknown[]>[] {\n this.refreshResults(cache);\n return cache.results;\n }\n\n private firstOn(cache: QueryCache): QueryResult<unknown[]> | null {\n const results = this.resultsOn(cache);\n return results.length > 0 ? results[0] : null;\n }\n\n private countOn(cache: QueryCache): number {\n this.refreshEntities(cache);\n return cache.entities.length;\n }\n\n private eachOn(cache: QueryCache, fn: EachFn): void {\n this.refreshEntities(cache);\n const ents = cache.entities;\n if (ents.length === 0) return; // no matches -> stores may be short; never read\n const stores = cache.stores;\n // Fast switch only when every yielded slot is a required `with` store\n // (yield arity === withIds length, no maybe terms) and arity <= 6. Any spec\n // with a maybe term or yield arity > 6 falls to the generic scratch lane.\n // The 5/6 cases matter for wide hot queries (e.g. a per-frame 5-component\n // physics/separation pass): they avoid the generic lane's per-entity\n // `fn.apply(undefined, scratch)`, which is markedly slower than a direct call.\n if (cache.yieldPlan.length === cache.ids.length && cache.ids.length <= 6) {\n switch (cache.ids.length) {\n case 1: {\n const s0 = stores[0];\n for (let i = 0; i < ents.length; i++) {\n const e = ents[i];\n fn(e, s0.getUnsafe(e));\n }\n break;\n }\n case 2: {\n const s0 = stores[0];\n const s1 = stores[1];\n for (let i = 0; i < ents.length; i++) {\n const e = ents[i];\n fn(e, s0.getUnsafe(e), s1.getUnsafe(e));\n }\n break;\n }\n case 3: {\n const s0 = stores[0];\n const s1 = stores[1];\n const s2 = stores[2];\n for (let i = 0; i < ents.length; i++) {\n const e = ents[i];\n fn(e, s0.getUnsafe(e), s1.getUnsafe(e), s2.getUnsafe(e));\n }\n break;\n }\n case 4: {\n const s0 = stores[0];\n const s1 = stores[1];\n const s2 = stores[2];\n const s3 = stores[3];\n for (let i = 0; i < ents.length; i++) {\n const e = ents[i];\n fn(\n e,\n s0.getUnsafe(e),\n s1.getUnsafe(e),\n s2.getUnsafe(e),\n s3.getUnsafe(e),\n );\n }\n break;\n }\n case 5: {\n const s0 = stores[0];\n const s1 = stores[1];\n const s2 = stores[2];\n const s3 = stores[3];\n const s4 = stores[4];\n for (let i = 0; i < ents.length; i++) {\n const e = ents[i];\n fn(\n e,\n s0.getUnsafe(e),\n s1.getUnsafe(e),\n s2.getUnsafe(e),\n s3.getUnsafe(e),\n s4.getUnsafe(e),\n );\n }\n break;\n }\n case 6: {\n const s0 = stores[0];\n const s1 = stores[1];\n const s2 = stores[2];\n const s3 = stores[3];\n const s4 = stores[4];\n const s5 = stores[5];\n for (let i = 0; i < ents.length; i++) {\n const e = ents[i];\n fn(\n e,\n s0.getUnsafe(e),\n s1.getUnsafe(e),\n s2.getUnsafe(e),\n s3.getUnsafe(e),\n s4.getUnsafe(e),\n s5.getUnsafe(e),\n );\n }\n break;\n }\n }\n return;\n }\n // Generic scratch lane for 7+ components and maybe-bearing specs.\n // Reuses one per-cache scratch array (sized in resolveSpecStores, or here\n // for a pure-with 5+ cache), so it stays zero-per-entity-allocation. Optional\n // slots fetch via `.get`, required via `.getUnsafe`; a never-created maybe\n // store yields undefined.\n const plan = cache.yieldPlan;\n const arity = plan.length;\n const yieldStores = cache.spec ? cache.yieldStores : stores;\n if (cache.scratch.length !== 1 + arity)\n cache.scratch = new Array(1 + arity);\n const scratch = cache.scratch;\n for (let i = 0; i < ents.length; i++) {\n const e = ents[i];\n scratch[0] = e;\n for (let k = 0; k < arity; k++) {\n const s = yieldStores[k];\n scratch[1 + k] =\n s === undefined\n ? undefined\n : plan[k].optional\n ? s.get(e)\n : s.getUnsafe(e);\n }\n fn.apply(undefined, scratch as never);\n }\n }\n\n private getCache(defs: ComponentType<unknown>[]): QueryCache {\n if (defs.length === 0) {\n throw new Error(\n \"a query needs at least one required (non-maybe, non-without) component\",\n );\n }\n // Keyed by call-order ids. Two call orders of the same component set get\n // separate caches so the cached tuples stay correct for each order (rather\n // than sharing one cache keyed by sorted ids), preserving the load-bearing\n // contract: allocation-stable, correct-order tuples.\n let key = \"\";\n const ids: number[] = [];\n for (let i = 0; i < defs.length; i++) {\n const id = defs[i].id;\n ids.push(id);\n key += i === 0 ? id : `,${id}`;\n }\n let cache = this.caches.get(key);\n if (!cache) {\n // A bare-def cache: `spec` false, all filter arrays empty. The yieldPlan\n // mirrors `ids`, so every term is required.\n const yieldPlan: YieldSlot[] = [];\n for (let i = 0; i < ids.length; i++)\n yieldPlan.push({ id: ids[i], optional: false });\n cache = {\n key,\n ids,\n stores: [],\n entities: [],\n results: [],\n entitiesVersion: 0,\n resultsVersion: -1,\n spec: false,\n withoutIds: [],\n maybeIds: [],\n anyGroups: [],\n yieldPlan,\n yieldStores: [],\n maybeStores: [],\n scratch: [],\n pairsScratch: [],\n // A bare-def cache reads only its required stores, so its dep set is `ids`.\n depIds: ids.slice(),\n depVersions: [],\n reqSig: null,\n };\n this.caches.set(key, cache);\n }\n return cache;\n }\n\n /**\n * Build (or fetch) a filter-spec cache. Keyed by a richer key encoding every\n * term role, so different filters never collide with each other or with\n * bare-def caches (whose key is just `ids.join(\",\")`). Only reached for specs\n * that carry a without/maybe/any term.\n */\n private getSpecCache(\n withDefs: ComponentType<unknown>[],\n withoutIds: number[],\n maybeIds: number[],\n anyGroups: number[][],\n yieldPlan: YieldSlot[],\n ): QueryCache {\n const ids: number[] = [];\n for (let i = 0; i < withDefs.length; i++) ids.push(withDefs[i].id);\n const key = `${ids.join(\",\")}|w:${withoutIds.join(\",\")}|m:${maybeIds.join(\n \",\",\n )}|a:${anyGroups.map((g) => g.join(\".\")).join(\";\")}`;\n let cache = this.caches.get(key);\n if (!cache) {\n // A spec cache's result depends on every store it reads: the required\n // `with` ids, plus the without / any / maybe stores. Dedupe into depIds so\n // a change to ANY of them (and only them) invalidates the cache.\n const depSet = new Set<number>(ids);\n for (let i = 0; i < withoutIds.length; i++) depSet.add(withoutIds[i]);\n for (let i = 0; i < maybeIds.length; i++) depSet.add(maybeIds[i]);\n for (let g = 0; g < anyGroups.length; g++)\n for (let j = 0; j < anyGroups[g].length; j++)\n depSet.add(anyGroups[g][j]);\n cache = {\n key,\n ids,\n stores: [],\n entities: [],\n results: [],\n entitiesVersion: 0,\n resultsVersion: -1,\n spec: true,\n withoutIds,\n maybeIds,\n anyGroups,\n yieldPlan,\n yieldStores: [],\n maybeStores: [],\n scratch: [],\n pairsScratch: [],\n depIds: [...depSet],\n depVersions: [],\n reqSig: null,\n };\n this.caches.set(key, cache);\n }\n return cache;\n }\n\n // True if any store this cache depends on has changed (or appeared/vanished)\n // since the last snapshot. An absent store reads as version -1, so a store\n // appearing (or its first add bumping 0→1) is detected. O(depIds), tiny.\n private depsChanged(cache: QueryCache): boolean {\n const { depIds, depVersions } = cache;\n if (depVersions.length !== depIds.length) return true;\n for (let i = 0; i < depIds.length; i++) {\n const s = this.world.storeIfPresent(depIds[i]);\n const v = s === undefined ? -1 : s.version;\n if (v !== depVersions[i]) return true;\n }\n return false;\n }\n\n // Record the current dep-store versions as the cache's baseline.\n private snapshotDeps(cache: QueryCache): void {\n const { depIds, depVersions } = cache;\n depVersions.length = depIds.length;\n for (let i = 0; i < depIds.length; i++) {\n const s = this.world.storeIfPresent(depIds[i]);\n depVersions[i] = s === undefined ? -1 : s.version;\n }\n }\n\n private refreshEntities(cache: QueryCache): void {\n // Rebuild only when one of THIS query's own stores changed; a mutation to an\n // unrelated component leaves the cache valid (the key per-store-versioning\n // win). `entitiesVersion` advances as a build epoch on each actual rebuild.\n if (!this.depsChanged(cache)) return;\n this.rebuildEntities(cache);\n this.snapshotDeps(cache);\n cache.entitiesVersion++;\n }\n\n private refreshResults(cache: QueryCache): void {\n this.refreshEntities(cache);\n // Tuples are current iff they were built at the latest entities epoch.\n if (cache.resultsVersion === cache.entitiesVersion) return;\n\n const { entities, stores, ids } = cache;\n const results: QueryResult<unknown[]>[] = new Array(entities.length);\n if (!cache.spec) {\n // Pure-with path: every yielded slot is a required component.\n for (let i = 0; i < entities.length; i++) {\n const entity = entities[i];\n const tuple: QueryResult<unknown[]> = [entity];\n for (let j = 0; j < ids.length; j++) {\n tuple.push(stores[j].getUnsafe(entity));\n }\n results[i] = tuple;\n }\n } else {\n // Spec path: yields follow declaration order via the yieldPlan, fetching\n // optional slots with `get` (=> value or undefined) and required slots\n // with `getUnsafe`. yieldStores were resolved alongside entities.\n const { yieldPlan, yieldStores } = cache;\n for (let i = 0; i < entities.length; i++) {\n const entity = entities[i];\n const tuple: QueryResult<unknown[]> = [entity];\n for (let j = 0; j < yieldPlan.length; j++) {\n const s = yieldStores[j];\n if (s === undefined) {\n tuple.push(undefined);\n } else if (yieldPlan[j].optional) {\n tuple.push(s.get(entity));\n } else {\n tuple.push(s.getUnsafe(entity));\n }\n }\n results[i] = tuple;\n }\n }\n // New array reference on every rebuild; callers that retained an old array\n // across a structural change observe the swap.\n cache.results = results;\n cache.resultsVersion = cache.entitiesVersion;\n }\n\n private rebuildEntities(cache: QueryCache): void {\n const { ids, stores, entities } = cache;\n entities.length = 0;\n stores.length = 0;\n // Reset spec-resolved stores too, so the early-return-on-empty path below\n // leaves a single well-defined \"no match\" state (never stale arrays).\n cache.yieldStores.length = 0;\n cache.maybeStores.length = 0;\n\n // Resolve current stores in call order. Pick the smallest to iterate; bail\n // (leaving `entities` empty, `stores` short) if any store is absent or empty:\n // no matches are possible.\n let smallest = -1;\n let smallestSize = Infinity;\n for (let i = 0; i < ids.length; i++) {\n const s = this.world.storeIfPresent(ids[i]);\n if (s === undefined || s.size() === 0) return;\n stores.push(s);\n if (s.size() < smallestSize) {\n smallestSize = s.size();\n smallest = i;\n }\n }\n\n // Filter specs need the without/maybe/any stores resolved before iterating;\n // resolve them, then narrow the smallest required store with the same per-\n // entity predicate. Pure-with caches keep the required-store check below.\n if (cache.spec) {\n this.resolveSpecStores(cache);\n }\n\n // Bitmask-accelerated required-membership check (opt-in via enableBitmask):\n // one signature AND replaces the per-store has() probe loop. Same result set\n // and same iteration order; only the inner check changes. Gated on >= 4\n // required components: a measured crossover, below which the has() loop (1–2\n // probes) beats the signature AND's per-word overhead. Null bitmask, or a\n // low-arity query, falls to the sparse-store `has()` loop. The signature is\n // static per cache and computed once observed.\n let sig: Uint32Array | null = null;\n const bm = ids.length >= 4 ? this.world.bitmask() : null;\n if (bm !== null) {\n if (cache.reqSig === null) cache.reqSig = bm.signature(ids);\n sig = cache.reqSig;\n }\n\n const smallestEntities = stores[smallest].iterEntities();\n for (let e = 0; e < smallestEntities.length; e++) {\n const entity = smallestEntities[e];\n if (!this.world.isAlive(entity)) continue;\n if (bm !== null && sig !== null) {\n if (!bm.hasAll(entity as number, sig)) continue;\n } else {\n let hasAll = true;\n for (let i = 0; i < stores.length; i++) {\n if (i === smallest) continue;\n if (!stores[i].has(entity)) {\n hasAll = false;\n break;\n }\n }\n if (!hasAll) continue;\n }\n // Apply the filter predicate only for spec caches.\n if (cache.spec && !this.filterMatches(cache, entity)) continue;\n entities.push(entity);\n }\n }\n\n /**\n * Resolve the `maybe`/`yield` stores for a spec cache (the without/any stores\n * are resolved on the fly by `filterMatches`, which closes over `this.world`).\n * Also sizes the per-cache scratch buffers once.\n */\n private resolveSpecStores(cache: QueryCache): void {\n const { maybeIds, maybeStores, yieldPlan, yieldStores } = cache;\n maybeStores.length = 0;\n for (let i = 0; i < maybeIds.length; i++)\n maybeStores.push(this.world.storeIfPresent(maybeIds[i]));\n // yieldStores parallels yieldPlan: a required slot's store is the resolved\n // `stores` entry at its `with` position; an optional slot's store is the\n // maybe store (which may be undefined when never created => value undefined).\n yieldStores.length = 0;\n let withCursor = 0;\n let maybeCursor = 0;\n for (let i = 0; i < yieldPlan.length; i++) {\n if (yieldPlan[i].optional) {\n yieldStores.push(maybeStores[maybeCursor++]);\n } else {\n yieldStores.push(cache.stores[withCursor++]);\n }\n }\n // Size the reused scratch buffers once (one allocation per cache arity).\n const arity = yieldPlan.length;\n if (cache.scratch.length !== 1 + arity)\n cache.scratch = new Array(1 + arity);\n if (cache.pairsScratch.length !== 2 + arity)\n cache.pairsScratch = new Array(2 + arity);\n }\n\n /**\n * The per-entity filter predicate shared by rebuild and `get`: NO withoutId's\n * store has the entity, and EVERY anyGroup has at least one member store with\n * it. (Required `with` membership is enforced separately, by the smallest-\n * store iteration in rebuild and by an explicit check in `get`.) `maybe` terms\n * impose no constraint.\n */\n private filterMatches(cache: QueryCache, entity: Entity): boolean {\n const { withoutIds, anyGroups } = cache;\n for (let i = 0; i < withoutIds.length; i++) {\n const s = this.world.storeIfPresent(withoutIds[i]);\n if (s?.has(entity)) return false;\n }\n for (let g = 0; g < anyGroups.length; g++) {\n const group = anyGroups[g];\n let satisfied = false;\n for (let j = 0; j < group.length; j++) {\n const s = this.world.storeIfPresent(group[j]);\n if (s?.has(entity)) {\n satisfied = true;\n break;\n }\n }\n if (!satisfied) return false;\n }\n return true;\n }\n\n private singleOn(cache: QueryCache): QueryResult<unknown[]> {\n this.refreshEntities(cache);\n const n = cache.entities.length;\n if (n !== 1) {\n throw new Error(`Query.single(): expected exactly one match, got ${n}`);\n }\n return this.resultsOn(cache)[0];\n }\n\n private getOn(\n cache: QueryCache,\n entity: Entity,\n ): QueryResult<unknown[]> | null {\n this.refreshEntities(cache);\n if (!this.world.isAlive(entity)) return null;\n // Membership: all required stores have it, then the filter predicate. When\n // entities is empty the stores array is short; re-resolve required stores\n // from ids so a hit on an otherwise-empty smallest store still works.\n const { ids } = cache;\n for (let i = 0; i < ids.length; i++) {\n const s = this.world.storeIfPresent(ids[i]);\n if (s === undefined || !s.has(entity)) return null;\n }\n if (cache.spec && !this.filterMatches(cache, entity)) return null;\n // Build a FRESH tuple (not the cached results reference, documented).\n return this.buildTuple(cache, entity);\n }\n\n private pairsOn(\n cache: QueryCache,\n fn: (a: Entity, b: Entity, ...components: unknown[]) => void,\n ): void {\n this.refreshEntities(cache);\n const ents = cache.entities;\n const n = ents.length;\n if (n < 2) return;\n const arity = cache.spec ? cache.yieldPlan.length : cache.ids.length;\n // A pure-with cache also reaches here; resolve its yield buffers from\n // `stores`/`ids` so the scratch lane works without spec fields.\n if (cache.pairsScratch.length !== 2 + arity)\n cache.pairsScratch = new Array(2 + arity);\n const scratch = cache.pairsScratch;\n const stores = cache.spec ? cache.yieldStores : cache.stores;\n const plan = cache.yieldPlan;\n for (let i = 0; i < n; i++) {\n const a = ents[i];\n // Fill a's component tail once per `i`.\n for (let k = 0; k < arity; k++) {\n const s = stores[k];\n scratch[2 + k] =\n s === undefined\n ? undefined\n : plan[k].optional\n ? s.get(a)\n : s.getUnsafe(a);\n }\n scratch[0] = a;\n for (let j = i + 1; j < n; j++) {\n scratch[1] = ents[j];\n fn.apply(undefined, scratch as never);\n }\n }\n }\n\n /** Build one `[entity, ...yields]` tuple via the yieldPlan (fresh array). */\n private buildTuple(\n cache: QueryCache,\n entity: Entity,\n ): QueryResult<unknown[]> {\n const tuple: QueryResult<unknown[]> = [entity];\n if (!cache.spec) {\n for (let j = 0; j < cache.ids.length; j++) {\n const s = this.world.storeIfPresent(cache.ids[j]);\n // Required, guaranteed present (callers verify membership first).\n tuple.push(s === undefined ? undefined : s.getUnsafe(entity));\n }\n return tuple;\n }\n const { yieldPlan } = cache;\n for (let j = 0; j < yieldPlan.length; j++) {\n const slot = yieldPlan[j];\n const s = this.world.storeIfPresent(slot.id);\n if (s === undefined) {\n tuple.push(undefined);\n } else if (slot.optional) {\n tuple.push(s.get(entity));\n } else {\n tuple.push(s.getUnsafe(entity));\n }\n }\n return tuple;\n }\n}\n","import type { CommandBuffer } from \"./command-buffer\";\nimport type { System, World } from \"./types\";\n\ninterface SystemGroup {\n label: string;\n systems: System[];\n}\n\nexport interface ScheduleConfig {\n /** Flush deferred despawns after every group. Default true. */\n flushBetweenGroups?: boolean;\n /**\n * When set, this CommandBuffer is applied (world.applyCommands) after each\n * group's systems run and BEFORE the per-group flush(). Lets systems record\n * deferred add/remove and have them applied at the group boundary. Default\n * undefined: no command buffer.\n */\n commandBuffer?: CommandBuffer;\n}\n\nexport class Schedule {\n private readonly groups: SystemGroup[] = [];\n private readonly flushBetweenGroups: boolean;\n private readonly commandBuffer: CommandBuffer | undefined;\n\n constructor(config?: ScheduleConfig) {\n this.flushBetweenGroups = config?.flushBetweenGroups ?? true;\n this.commandBuffer = config?.commandBuffer;\n }\n\n /** Add a named group of systems to the end of the schedule. */\n addGroup(label: string, ...systems: System[]): this {\n this.groups.push({ label, systems });\n return this;\n }\n\n /** Run all system groups in order. Flushes between groups per the policy. */\n run(world: World, dt = 1): void {\n for (const group of this.groups) {\n for (const system of group.systems) {\n system(world, dt);\n }\n if (this.commandBuffer !== undefined)\n world.applyCommands(this.commandBuffer);\n if (this.flushBetweenGroups) world.flush();\n }\n }\n\n private requireLabel(label: string): void {\n for (const g of this.groups) if (g.label === label) return;\n throw new Error(`Schedule: no group labeled \"${label}\"`);\n }\n\n /** Run groups up to and including the named group. */\n runUpTo(world: World, upToLabel: string, dt = 1): void {\n this.requireLabel(upToLabel);\n for (const group of this.groups) {\n for (const system of group.systems) {\n system(world, dt);\n }\n if (this.commandBuffer !== undefined)\n world.applyCommands(this.commandBuffer);\n if (this.flushBetweenGroups) world.flush();\n if (group.label === upToLabel) break;\n }\n }\n\n /** Run groups starting from (exclusive) the named group. */\n runFrom(world: World, afterLabel: string, dt = 1): void {\n this.requireLabel(afterLabel);\n let started = false;\n for (const group of this.groups) {\n if (!started) {\n if (group.label === afterLabel) started = true;\n continue;\n }\n for (const system of group.systems) {\n system(world, dt);\n }\n if (this.commandBuffer !== undefined)\n world.applyCommands(this.commandBuffer);\n if (this.flushBetweenGroups) world.flush();\n }\n }\n\n /** Get group labels (for debugging). */\n getGroupLabels(): string[] {\n return this.groups.map((g) => g.label);\n }\n\n /**\n * Build a single-group schedule from a priority-sorted system list,\n * preserving exact order (stable sort on priority). Defaults to\n * flushBetweenGroups=false (overridable via `config`) with one group \"main\":\n * a convenient entry point when porting a priority-number scheduler.\n */\n static fromPriorityList(\n systems: { priority: number; update: System }[],\n config?: ScheduleConfig,\n ): Schedule {\n const schedule = new Schedule({ flushBetweenGroups: false, ...config });\n const ordered = systems\n .map((s, index) => ({ s, index }))\n .sort((a, b) => a.s.priority - b.s.priority || a.index - b.index)\n .map((w) => w.s.update);\n schedule.addGroup(\"main\", ...ordered);\n return schedule;\n }\n}\n","// Serialization: snapshot / restore / delta, driven by consumer codecs\n// Reads the world only through public methods (getStoreRaw, iterEntities, has,\n// getUnsafe, spawn, clear, add, setResource, tryGetResource, ...); never mutates\n// engine internals.\n//\n// Determinism: a snapshot is a pure function of the world's logical state, made\n// canonical by iterating entities in ASCENDING INDEX order (explicitly not the\n// store's swap-delete order) and ordering each entity's components by ascending\n// ComponentType.id. Two worlds with identical logical content but different\n// operation histories produce byte-identical snapshots. Numeric encoding is\n// little-endian via explicit DataView calls; the delta byte-compare is exact\n// (===), never a tolerance. Zero runtime deps: DataView, typed arrays, and\n// TextEncoder only.\n\nimport type { ComponentType, Entity, ResourceType, World } from \"./index\";\nimport { MigrationError, type MigrationRegistry } from \"./migration\";\n\nexport interface SerializerOptions {\n /** Codec write headroom per component (default 4096). */\n readonly maxComponentBytes?: number;\n /**\n * Optional migration registry. When provided, every component blob is read\n * back through the chain on restore/applyDelta. Omitted (or empty) => all\n * components are treated as version 0 with an identity upgrade: byte-identical\n * to a no-migration serializer for current-version data. The per-component\n * `_version` field is written UNCONDITIONALLY (a constant 0 when no chain is\n * registered), so \"no migrations\" is represented in the format.\n */\n readonly migrations?: MigrationRegistry;\n}\n\n/**\n * Per-component-type binary codec the consumer supplies. The serializer never\n * reflects on component shape; the codec owns the byte layout.\n *\n * - `write` appends `c`'s bytes into `view` at `offset` and returns the new\n * offset (offset + bytesWritten).\n * - `read` decodes a value starting at `offset` and returns it with the new\n * offset. `read` MUST consume exactly as many bytes as the matching `write`\n * produced (round-trip byte-symmetry is the core contract).\n * - `refFields` lists keys whose values are `Entity` references; on `restore`\n * they are remapped from old indices to the new spawned ids via the idMap.\n * A ref equal to 0 (\"no entity\") is preserved as 0.\n * - `readVersioned` is an optional version-aware decode. REQUIRED for any\n * migrated component whose OLDER versions wrote a DIFFERENT on-wire byte\n * layout than the current `read` expects, which is essentially every\n * add/remove/reorder of a serialized field, since each changes the byte count\n * or field set. It receives `storedVersion` and must consume exactly the bytes\n * THAT version wrote, returning the value in that version's shape; the\n * migration chain then upgrades it to current. `read` alone is safe ONLY when\n * every stored version's bytes are identical to what the current `read`\n * consumes (e.g. a migration that derives a new JS field at upgrade time\n * without changing the serialized bytes). Supplying `read` for a layout-\n * changing migration desyncs the byte stream; `restore` detects the resulting\n * length mismatch and throws rather than silently mis-loading.\n */\nexport interface ComponentCodec<T> {\n write(view: DataView, offset: number, c: T): number;\n read(view: DataView, offset: number): { value: T; offset: number };\n refFields?: (keyof T)[];\n readVersioned?(\n view: DataView,\n offset: number,\n version: number,\n ): { value: Record<string, unknown>; offset: number };\n}\n\n/** A registered resource codec: same byte contract, no refFields. */\nexport interface ResourceCodec<T> {\n write(view: DataView, offset: number, value: T): number;\n read(view: DataView, offset: number): { value: T; offset: number };\n}\n\nconst MAGIC = 0x41454353; // \"AECS\"\nconst FORMAT_SNAPSHOT = 1;\nconst FORMAT_DELTA = 2;\nconst FORMAT_VERSION = 1;\nconst DEFAULT_MAX_COMPONENT_BYTES = 4096;\n\n// biome-ignore lint/suspicious/noExplicitAny: codec registry is value-erased: only the byte layout matters; the consumer owns the typed boundary.\ntype AnyCodec = ComponentCodec<any>;\n// biome-ignore lint/suspicious/noExplicitAny: same erasure as AnyCodec, for resources.\ntype AnyResourceCodec = ResourceCodec<any>;\n// Component sizes are codec-defined, so the backing buffer grows on demand. The\n// codec writes directly into the writer's DataView at the current offset; the\n// writer pre-`ensure`s a generous per-component slab so a codec never overruns.\n\nclass ByteWriter {\n buf: ArrayBuffer;\n view: DataView;\n offset = 0;\n\n constructor() {\n this.buf = new ArrayBuffer(64);\n this.view = new DataView(this.buf);\n }\n\n /** Grow the backing buffer so at least `extra` more bytes fit at `offset`. */\n ensure(extra: number): void {\n const need = this.offset + extra;\n if (need <= this.buf.byteLength) return;\n const next = new ArrayBuffer(Math.max(this.buf.byteLength * 2, need));\n new Uint8Array(next).set(new Uint8Array(this.buf, 0, this.offset));\n this.buf = next;\n this.view = new DataView(next);\n }\n\n u32(n: number): void {\n this.ensure(4);\n this.view.setUint32(this.offset, n >>> 0, true);\n this.offset += 4;\n }\n\n /**\n * Write one component via its codec. Pre-`ensure`s `maxComponentBytes` of\n * headroom so the codec writes into a DataView with room; advances `offset` to\n * the codec's returned offset. Codecs writing larger blobs must raise\n * `maxComponentBytes` on the Serializer constructor.\n */\n writeComponent(codec: AnyCodec, c: unknown, maxComponentBytes: number): void {\n this.ensure(maxComponentBytes);\n this.offset = codec.write(this.view, this.offset, c);\n }\n\n /** Write one resource via its codec (same headroom contract as a component). */\n writeResource(\n codec: AnyResourceCodec,\n value: unknown,\n maxComponentBytes: number,\n ): void {\n this.ensure(maxComponentBytes);\n this.offset = codec.write(this.view, this.offset, value);\n }\n\n /** Return an exact-length copy of the written bytes. */\n finish(): ArrayBuffer {\n return this.buf.slice(0, this.offset);\n }\n}\nclass ByteReader {\n readonly view: DataView;\n offset = 0;\n\n constructor(buffer: ArrayBuffer) {\n this.view = new DataView(buffer);\n }\n\n u32(): number {\n const n = this.view.getUint32(this.offset, true);\n this.offset += 4;\n return n;\n }\n}\n\nfunction buffersEqual(a: ArrayBuffer, b: ArrayBuffer): boolean {\n if (a.byteLength !== b.byteLength) return false;\n const ua = new Uint8Array(a);\n const ub = new Uint8Array(b);\n for (let i = 0; i < ua.length; i++) if (ua[i] !== ub[i]) return false;\n return true;\n}\n\ninterface DecodedRecord {\n oldIndex: number;\n comps: { compId: number; value: unknown }[];\n}\n\nexport class Serializer {\n private readonly codecs = new Map<\n number,\n { def: ComponentType<unknown>; codec: AnyCodec }\n >();\n private readonly resourceCodecs = new Map<\n number,\n { type: ResourceType<unknown>; codec: AnyResourceCodec }\n >();\n // Sorted ascending list of registered component ids; recomputed on register\n // so snapshot ordering is stable and independent of registration order.\n private orderedComponentIds: number[] = [];\n // shadow[compId][entityIndex] = last-written component bytes; shadowAlive is\n // the entity-index set present at the last baseline. resourceShadow[resId] =\n // last-written resource bytes. The shadow is the source of truth for delta();\n // change-tracking, when present, only narrows the candidate set, and every\n // candidate is still byte-verified against the shadow, so both paths emit\n // identical bytes for the same state transition.\n private shadow = new Map<number, Map<number, ArrayBuffer>>();\n private shadowAlive = new Set<number>();\n private resourceShadow = new Map<number, ArrayBuffer>();\n\n // Old-index -> live entity, seeded by restore/applyDelta so a subsequent\n // applyDelta remaps refs consistently against the live world.\n private applyIdMap = new Map<number, Entity>();\n\n private readonly maxComponentBytes: number;\n\n // Optional consumer-owned migration registry. `undefined` or an empty registry\n // means every component is implicitly version 0 with an identity upgrade.\n private readonly migrations?: MigrationRegistry;\n\n constructor(options?: SerializerOptions) {\n this.maxComponentBytes =\n options?.maxComponentBytes ?? DEFAULT_MAX_COMPONENT_BYTES;\n this.migrations = options?.migrations;\n }\n\n // Current (live-code) version written for a component blob. When no migrations\n // are registered this is a constant 0 for every component, so the `_version`\n // field is a fixed 0.\n private versionOf(componentId: number): number {\n return this.migrations?.currentVersionById(componentId) ?? 0;\n }\n\n // Decode one component blob: read its `_version`, then decode the value via\n // `readVersioned` (version-aware, for wire-layout changes) or `read` (current\n // layout), then upgrade it through the migration chain. Advances `r.offset`.\n // Runs AFTER decode and BEFORE the world write so refField remap (declared\n // against the CURRENT shape) sees the migrated value. Returns the migrated\n // plain value; the caller remaps refs and writes it.\n private decodeComponent(\n r: ByteReader,\n compId: number,\n ): { value: unknown; offset: number } {\n const storedVersion = r.u32();\n const codec = this.codecById(compId);\n const decoded = codec.readVersioned\n ? codec.readVersioned(r.view, r.offset, storedVersion)\n : (codec.read(r.view, r.offset) as {\n value: Record<string, unknown>;\n offset: number;\n });\n let value: unknown = decoded.value;\n if (this.migrations !== undefined && !this.migrations.isEmpty) {\n value = this.migrations.migrate(\n compId,\n storedVersion,\n decoded.value as Record<string, unknown>,\n this.defById(compId).name,\n );\n } else if (storedVersion !== 0) {\n // A versioned save but no registry supplied -> fail loud, never silently\n // mis-load.\n throw new MigrationError(\n this.defById(compId).name,\n storedVersion,\n 0,\n \"no MigrationRegistry supplied to deserialize a versioned save\",\n );\n }\n return { value, offset: decoded.offset };\n }\n\n /** Register a binary codec for a component type. Chainable. */\n register<T>(def: ComponentType<T>, codec: ComponentCodec<T>): this {\n this.codecs.set(def.id, {\n def: def as ComponentType<unknown>,\n codec: codec as AnyCodec,\n });\n this.orderedComponentIds = [...this.codecs.keys()].sort((a, b) => a - b);\n return this;\n }\n\n /** Register a resource to include in snapshots (optional, opt-in). */\n registerResource<T>(type: ResourceType<T>, codec: ResourceCodec<T>): this {\n this.resourceCodecs.set(type.id, {\n type: type as ResourceType<unknown>,\n codec: codec as AnyResourceCodec,\n });\n return this;\n }\n\n private defById(id: number): ComponentType<unknown> {\n const entry = this.codecs.get(id);\n if (entry === undefined) {\n throw new Error(`serialize: no codec registered for component id ${id}`);\n }\n return entry.def;\n }\n\n private codecById(id: number): AnyCodec {\n const entry = this.codecs.get(id);\n if (entry === undefined) {\n throw new Error(`serialize: no codec registered for component id ${id}`);\n }\n return entry.codec;\n }\n /**\n * Full world state as a self-describing buffer. Entities are emitted in\n * ascending index order; per entity, components are emitted in ascending\n * ComponentType.id order. Little-endian throughout.\n */\n snapshot(world: World): ArrayBuffer {\n const w = new ByteWriter();\n w.u32(MAGIC);\n w.u32(FORMAT_SNAPSHOT);\n w.u32(FORMAT_VERSION);\n\n const entities = this.aliveSorted(world);\n w.u32(entities.length);\n\n for (let i = 0; i < entities.length; i++) {\n const idx = entities[i];\n w.u32(idx);\n const present = this.presentComponents(world, idx);\n w.u32(present.length);\n for (let j = 0; j < present.length; j++) {\n const compId = present[j];\n w.u32(compId);\n // Per-component `_version`, written with the same primitive as compId.\n // A constant 0 when no migration chain is registered.\n w.u32(this.versionOf(compId));\n const c = world\n .getStoreRaw(this.defById(compId))\n .getUnsafe(idx as Entity);\n w.writeComponent(this.codecById(compId), c, this.maxComponentBytes);\n }\n }\n\n this.writeResources(world, w);\n this.captureBaseline(world, entities);\n return w.finish();\n }\n\n // Union of every registered store's members, as a sorted ascending array.\n // KEY: sorting by index makes the buffer canonical regardless of the store's\n // dense swap-delete order. UNION MODEL (deliberate): serialization is\n // component-driven: an entity with no registered component is in no store and\n // is therefore not serialized. Losing its last registered component removes an\n // entity from the serialized view (see delta()'s note).\n private aliveSorted(world: World): number[] {\n const alive = new Set<number>();\n for (let i = 0; i < this.orderedComponentIds.length; i++) {\n const def = this.defById(this.orderedComponentIds[i]);\n const ents = world.getStoreRaw(def).iterEntities();\n for (let e = 0; e < ents.length; e++) alive.add(ents[e] as number);\n }\n return [...alive].sort((a, b) => a - b);\n }\n\n // Registered component ids present on `idx`, in ascending id order.\n private presentComponents(world: World, idx: number): number[] {\n const present: number[] = [];\n for (let i = 0; i < this.orderedComponentIds.length; i++) {\n const compId = this.orderedComponentIds[i];\n if (world.getStoreRaw(this.defById(compId)).has(idx as Entity)) {\n present.push(compId);\n }\n }\n return present;\n }\n\n // Collect present registered resources (sorted by id), then write count + each.\n private writeResources(world: World, w: ByteWriter): void {\n const ids = [...this.resourceCodecs.keys()].sort((a, b) => a - b);\n const present: number[] = [];\n for (let i = 0; i < ids.length; i++) {\n const entry = this.resourceCodecs.get(ids[i]);\n if (entry === undefined) continue;\n if (world.tryGetResource(entry.type) !== undefined) present.push(ids[i]);\n }\n w.u32(present.length);\n for (let i = 0; i < present.length; i++) {\n const entry = this.resourceCodecs.get(present[i]);\n if (entry === undefined) continue;\n w.u32(present[i]);\n const value = world.tryGetResource(entry.type);\n w.writeResource(entry.codec, value, this.maxComponentBytes);\n }\n }\n /**\n * Clear `world`, re-spawn every entity in the snapshot, re-add components via\n * the registered codecs, and remap every `refFields` value from old index to\n * the freshly-spawned id. After restore, `delta()` baselines reset.\n */\n restore(world: World, buffer: ArrayBuffer): void {\n const r = new ByteReader(buffer);\n if (r.u32() !== MAGIC) throw new Error(\"serialize: bad magic\");\n if (r.u32() !== FORMAT_SNAPSHOT) {\n throw new Error(\"serialize: bad format (expected snapshot)\");\n }\n if (r.u32() !== FORMAT_VERSION) throw new Error(\"serialize: bad version\");\n\n world.clear();\n\n const n = r.u32();\n const idMap = new Map<number, Entity>();\n const records: DecodedRecord[] = [];\n\n // FIRST PASS: spawn every entity up front so the idMap is complete BEFORE\n // any ref remap: a ref pointing at an entity that appears later in the\n // buffer still resolves.\n for (let i = 0; i < n; i++) {\n const oldIndex = r.u32();\n const newE = world.spawn();\n idMap.set(oldIndex, newE);\n const compCount = r.u32();\n const comps: { compId: number; value: unknown }[] = [];\n for (let j = 0; j < compCount; j++) {\n const compId = r.u32();\n // decodeComponent reads the per-component `_version`, decodes via the\n // (version-aware) codec, and upgrades through the migration chain.\n const decoded = this.decodeComponent(r, compId);\n r.offset = decoded.offset;\n comps.push({ compId, value: decoded.value });\n }\n records.push({ oldIndex, comps });\n }\n\n // SECOND PASS: remap refs through the now-complete idMap and add.\n for (let i = 0; i < records.length; i++) {\n const record = records[i];\n const newE = idMap.get(record.oldIndex) as Entity;\n for (let j = 0; j < record.comps.length; j++) {\n const { compId, value } = record.comps[j];\n this.remapRefs(compId, value, idMap);\n world.add(newE, this.defById(compId), value);\n }\n }\n\n this.readResources(world, r);\n\n // Integrity check: a well-formed snapshot is consumed exactly. A leftover or\n // short tail means a codec read/write byte-count asymmetry or a migrated\n // component decoded with `read` instead of `readVersioned`: fail loudly\n // here rather than silently dropping/mis-loading later entities.\n if (r.offset !== buffer.byteLength) {\n throw new Error(\n `serialize: restore consumed ${r.offset} of ${buffer.byteLength} bytes; ` +\n `likely a codec read/write byte mismatch or a migrated component missing readVersioned`,\n );\n }\n\n const restored = [...idMap.values()]\n .map((e) => e as number)\n .sort((a, b) => a - b);\n this.captureBaseline(world, restored);\n this.applyIdMap = idMap;\n }\n\n // Remap a decoded value's refFields from old index to live entity. A ref of 0\n // (\"no entity\") stays 0; an unmapped ref also becomes 0.\n private remapRefs(\n compId: number,\n value: unknown,\n idMap: Map<number, Entity>,\n ): void {\n const codec = this.codecById(compId);\n const refFields = codec.refFields;\n if (\n refFields === undefined ||\n value === null ||\n typeof value !== \"object\"\n ) {\n return;\n }\n const v = value as Record<string, number>;\n for (let i = 0; i < refFields.length; i++) {\n const f = refFields[i] as string;\n const old = v[f];\n v[f] = old === 0 ? 0 : ((idMap.get(old) ?? 0) as number);\n }\n }\n\n private readResources(world: World, r: ByteReader): void {\n const resCount = r.u32();\n for (let i = 0; i < resCount; i++) {\n const rid = r.u32();\n const entry = this.resourceCodecs.get(rid);\n if (entry === undefined) {\n throw new Error(\n `serialize: no codec registered for resource id ${rid}`,\n );\n }\n const decoded = entry.codec.read(r.view, r.offset);\n r.offset = decoded.offset;\n world.setResource(entry.type, decoded.value);\n }\n }\n /**\n * Bytes for only the entities/components changed since the last `delta()` or\n * `snapshot()`/`restore()` baseline. Computed by an exact (epsilon-0) byte\n * diff of every alive entity's registered components against the per-Serializer\n * shadow captured at the last baseline. Emits removed-entity, then per-entity\n * added/changed and removed-component records, then resource diffs; entities\n * ascending, components ascending, so the output is a pure function of state\n * (never the store's dense order). Delta output is INDEPENDENT of whether\n * change tracking is enabled: the shadow diff is the source of truth.\n *\n * UNION MODEL: an entity is part of the serialized world only while it holds a\n * registered component. Removing an entity's LAST registered component (even if\n * the entity stays alive in the source world) is emitted as a removed-entity\n * record, so `applyDelta` despawns its replica, keeping the delta path\n * consistent with what a fresh `snapshot`/`restore` of the same source would\n * produce. To persist an otherwise-componentless entity across a snapshot,\n * keep at least one registered (tag) component on it.\n */\n delta(world: World): ArrayBuffer {\n const w = new ByteWriter();\n w.u32(MAGIC);\n w.u32(FORMAT_DELTA);\n w.u32(FORMAT_VERSION);\n\n const curr = this.aliveSorted(world);\n const currSet = new Set(curr);\n\n // Removed entities: present at baseline, absent now (ascending).\n const removedEntities: number[] = [];\n for (const idx of this.shadowAlive) {\n if (!currSet.has(idx)) removedEntities.push(idx);\n }\n removedEntities.sort((a, b) => a - b);\n\n w.u32(removedEntities.length);\n for (let i = 0; i < removedEntities.length; i++) w.u32(removedEntities[i]);\n\n // Per-entity component diff against the shadow (ascending entity, ascending\n // compId, both pure functions of state, never the store's dense order).\n const records: {\n idx: number;\n addedOrChanged: { compId: number; bytes: ArrayBuffer }[];\n removed: number[];\n }[] = [];\n\n for (let i = 0; i < curr.length; i++) {\n const idx = curr[i];\n const shadowRow = this.shadow.get(idx);\n const addedOrChanged: { compId: number; bytes: ArrayBuffer }[] = [];\n const removed: number[] = [];\n for (let j = 0; j < this.orderedComponentIds.length; j++) {\n const compId = this.orderedComponentIds[j];\n const def = this.defById(compId);\n const store = world.getStoreRaw(def);\n const presentNow = store.has(idx as Entity);\n const prevBytes = shadowRow?.get(compId);\n if (presentNow) {\n const bytes = this.componentBytes(world, compId, idx);\n // ADDED (not in shadow) or CHANGED (bytes differ). A markChanged that\n // did not change bytes emits nothing; the byte-verify guarantees the\n // delta is byte-identical regardless of which path produced the\n // candidate.\n if (prevBytes === undefined || !buffersEqual(prevBytes, bytes)) {\n addedOrChanged.push({ compId, bytes });\n }\n } else if (prevBytes !== undefined) {\n // REMOVED component (was in shadow, absent now).\n removed.push(compId);\n }\n }\n if (addedOrChanged.length > 0 || removed.length > 0) {\n records.push({ idx, addedOrChanged, removed });\n }\n }\n\n w.u32(records.length);\n for (let i = 0; i < records.length; i++) {\n const rec = records[i];\n w.u32(rec.idx);\n w.u32(rec.addedOrChanged.length);\n w.u32(rec.removed.length);\n for (let j = 0; j < rec.addedOrChanged.length; j++) {\n const { compId, bytes } = rec.addedOrChanged[j];\n w.u32(compId);\n // Per-component `_version` (same constant-0 rule as snapshot). The\n // shadow stores only the codec bytes, so the version is\n // emitted here, not embedded in `bytes`.\n w.u32(this.versionOf(compId));\n this.appendBytes(w, bytes);\n }\n for (let j = 0; j < rec.removed.length; j++) w.u32(rec.removed[j]);\n }\n\n this.writeResourceDelta(world, w);\n this.captureBaseline(world, curr);\n return w.finish();\n }\n\n // Serialize a single component into its own exact-length buffer (for shadow\n // storage and byte comparison).\n private componentBytes(\n world: World,\n compId: number,\n idx: number,\n ): ArrayBuffer {\n const scratch = new ByteWriter();\n const c = world.getStoreRaw(this.defById(compId)).getUnsafe(idx as Entity);\n scratch.writeComponent(this.codecById(compId), c, this.maxComponentBytes);\n return scratch.finish();\n }\n\n // Append a pre-serialized component's bytes verbatim (length-prefixed-free:\n // the codec's read consumes exactly its own bytes, so no length tag needed).\n private appendBytes(w: ByteWriter, bytes: ArrayBuffer): void {\n const src = new Uint8Array(bytes);\n w.ensure(src.length);\n new Uint8Array(w.buf).set(src, w.offset);\n w.offset += src.length;\n }\n\n // Resource diff: emit each changed/added resource (id + bytes), then removed\n // resource ids. Diffed against resourceShadow, byte-exact.\n private writeResourceDelta(world: World, w: ByteWriter): void {\n const ids = [...this.resourceCodecs.keys()].sort((a, b) => a - b);\n const changed: { rid: number; bytes: ArrayBuffer }[] = [];\n const removed: number[] = [];\n const presentNow = new Set<number>();\n for (let i = 0; i < ids.length; i++) {\n const rid = ids[i];\n const entry = this.resourceCodecs.get(rid);\n if (entry === undefined) continue;\n const value = world.tryGetResource(entry.type);\n const prev = this.resourceShadow.get(rid);\n if (value !== undefined) {\n presentNow.add(rid);\n const scratch = new ByteWriter();\n scratch.writeResource(entry.codec, value, this.maxComponentBytes);\n const bytes = scratch.finish();\n if (prev === undefined || !buffersEqual(prev, bytes)) {\n changed.push({ rid, bytes });\n }\n }\n }\n for (const rid of this.resourceShadow.keys()) {\n if (!presentNow.has(rid)) removed.push(rid);\n }\n changed.sort((a, b) => a.rid - b.rid);\n removed.sort((a, b) => a - b);\n w.u32(changed.length);\n for (let i = 0; i < changed.length; i++) {\n w.u32(changed[i].rid);\n this.appendBytes(w, changed[i].bytes);\n }\n w.u32(removed.length);\n for (let i = 0; i < removed.length; i++) w.u32(removed[i]);\n }\n /** Apply a `delta()` buffer to `world`, remapping refs through the live idMap. */\n applyDelta(world: World, buffer: ArrayBuffer): void {\n const r = new ByteReader(buffer);\n if (r.u32() !== MAGIC) throw new Error(\"serialize: bad magic\");\n if (r.u32() !== FORMAT_DELTA) {\n throw new Error(\"serialize: bad format (expected delta)\");\n }\n if (r.u32() !== FORMAT_VERSION) throw new Error(\"serialize: bad version\");\n\n const idMap = this.applyIdMap;\n\n // Removed entities: despawn + flush immediately so removals are visible\n // before re-adds. delta apply is a save-load boundary, not a mid-frame op,\n // so a flush here does not affect any running schedule.\n const removedCount = r.u32();\n for (let i = 0; i < removedCount; i++) {\n const oldIndex = r.u32();\n const e = idMap.get(oldIndex);\n if (e !== undefined && world.isAlive(e)) world.despawn(e);\n idMap.delete(oldIndex);\n }\n if (removedCount > 0) world.flush();\n\n // Changed records: decode into a temp structure, spawning unknown indices\n // FIRST so the idMap is complete before any ref remap (two-phase, like\n // restore).\n const recordCount = r.u32();\n const decoded: {\n target: Entity;\n addedOrChanged: { compId: number; value: unknown }[];\n removed: number[];\n }[] = [];\n\n for (let i = 0; i < recordCount; i++) {\n const oldIndex = r.u32();\n const addedOrChangedCount = r.u32();\n const removedCount2 = r.u32();\n let target = idMap.get(oldIndex);\n if (target === undefined) {\n target = world.spawn();\n idMap.set(oldIndex, target);\n }\n const addedOrChanged: { compId: number; value: unknown }[] = [];\n for (let j = 0; j < addedOrChangedCount; j++) {\n const compId = r.u32();\n // decodeComponent reads the per-component `_version`, decodes, and\n // upgrades through the migration chain (mirrors restore).\n const d = this.decodeComponent(r, compId);\n r.offset = d.offset;\n addedOrChanged.push({ compId, value: d.value });\n }\n const removed: number[] = [];\n for (let j = 0; j < removedCount2; j++) removed.push(r.u32());\n decoded.push({ target, addedOrChanged, removed });\n }\n\n for (let i = 0; i < decoded.length; i++) {\n const rec = decoded[i];\n for (let j = 0; j < rec.addedOrChanged.length; j++) {\n const { compId, value } = rec.addedOrChanged[j];\n this.remapRefs(compId, value, idMap);\n world.add(rec.target, this.defById(compId), value);\n }\n for (let j = 0; j < rec.removed.length; j++) {\n world.remove(rec.target, this.defById(rec.removed[j]));\n }\n }\n\n this.applyResourceDelta(world, r);\n\n if (r.offset !== buffer.byteLength) {\n throw new Error(\n `serialize: applyDelta consumed ${r.offset} of ${buffer.byteLength} bytes; ` +\n `likely a codec read/write byte mismatch or a migrated component missing readVersioned`,\n );\n }\n\n const alive = this.aliveSorted(world);\n this.captureBaseline(world, alive);\n }\n\n private applyResourceDelta(world: World, r: ByteReader): void {\n const changedCount = r.u32();\n for (let i = 0; i < changedCount; i++) {\n const rid = r.u32();\n const entry = this.resourceCodecs.get(rid);\n if (entry === undefined) {\n throw new Error(\n `serialize: no codec registered for resource id ${rid}`,\n );\n }\n const d = entry.codec.read(r.view, r.offset);\n r.offset = d.offset;\n world.setResource(entry.type, d.value);\n }\n const removedCount = r.u32();\n for (let i = 0; i < removedCount; i++) {\n const rid = r.u32();\n const entry = this.resourceCodecs.get(rid);\n if (entry !== undefined) world.unsetResource(entry.type);\n }\n }\n // captureBaseline (private): rebuild the shadow + shadowAlive\n // O(alive × components × bytes), run only on snapshot/restore/delta/applyDelta\n // calls (never per-frame unless the consumer calls delta per-frame).\n\n private captureBaseline(world: World, sortedIndices: number[]): void {\n const shadow = new Map<number, Map<number, ArrayBuffer>>();\n for (let i = 0; i < sortedIndices.length; i++) {\n const idx = sortedIndices[i];\n let row: Map<number, ArrayBuffer> | undefined;\n for (let j = 0; j < this.orderedComponentIds.length; j++) {\n const compId = this.orderedComponentIds[j];\n const store = world.getStoreRaw(this.defById(compId));\n if (!store.has(idx as Entity)) continue;\n if (row === undefined) {\n row = new Map();\n shadow.set(idx, row);\n }\n row.set(compId, this.componentBytes(world, compId, idx));\n }\n }\n this.shadow = shadow;\n this.shadowAlive = new Set(sortedIndices);\n\n const resourceShadow = new Map<number, ArrayBuffer>();\n for (const [rid, entry] of this.resourceCodecs) {\n const value = world.tryGetResource(entry.type);\n if (value === undefined) continue;\n const scratch = new ByteWriter();\n scratch.writeResource(entry.codec, value, this.maxComponentBytes);\n resourceShadow.set(rid, scratch.finish());\n }\n this.resourceShadow = resourceShadow;\n }\n}\n// jsonCodec: generic JSON codec for plain-data components\n// Slower, non-binary (UTF-8 via TextEncoder). A convenience so consumers can\n// serialize before hand-writing a binary codec; `refFields` still works (JSON\n// stores raw numeric ids, and entity ids are < 2^53 so they round-trip exact).\n//\n// Determinism caveat: JSON.stringify key order follows insertion order, so for\n// byte-identity the component object must have stable key order (true for plain\n// components built by a factory). For values containing -0, NaN, or floats whose\n// decimal round-trip differs, use the binary path; jsonCodec targets integer /\n// string plain data.\n\nconst enc = new TextEncoder();\nconst dec = new TextDecoder();\n\n/**\n * Generic JSON codec for plain-data components (slower, non-binary; UTF-8 via\n * TextEncoder). `refFields` still works (JSON stores raw numeric ids). Does NOT\n * round-trip `-0` (→ `0`), `NaN`/`Infinity` (→ `null`), or floats whose decimal\n * form differs; use a binary codec for those.\n */\nexport function jsonCodec<T>(refFields?: (keyof T)[]): ComponentCodec<T> {\n return {\n write(view: DataView, offset: number, c: T): number {\n const json = JSON.stringify(c);\n const bytes = enc.encode(json);\n view.setUint32(offset, bytes.length, true);\n new Uint8Array(\n view.buffer,\n view.byteOffset + offset + 4,\n bytes.length,\n ).set(bytes);\n return offset + 4 + bytes.length;\n },\n read(view: DataView, offset: number): { value: T; offset: number } {\n const len = view.getUint32(offset, true);\n const slice = new Uint8Array(\n view.buffer,\n view.byteOffset + offset + 4,\n len,\n );\n const value = JSON.parse(dec.decode(slice)) as T;\n return { value, offset: offset + 4 + len };\n },\n refFields,\n };\n}\n","// ComponentStore: sparse-set dense component storage\n// Iteration order is a deterministic function of the add/remove sequence. Do NOT\n// replace swap-delete with another compaction (e.g. tombstones): that would shift\n// iteration order, which downstream determinism depends on.\n\nimport type { EntityId } from \"./types\";\n\n/**\n * Default maximum entity count. The sparse Int32Array is pre-allocated to this\n * size, so each store pays `capacity × 4` bytes (256 KB at 65536). Removes the\n * cap as a practical concern for spawner-heavy moments.\n */\nexport const DEFAULT_MAX_ENTITIES = 65536;\n\nconst EMPTY = -1;\n\nexport class ComponentStore<T> {\n private readonly sparse: Int32Array;\n private readonly entities: EntityId[] = [];\n private readonly data: T[] = [];\n private count = 0;\n private readonly capacity: number;\n\n private pooling = false;\n private resetFn: ((c: T) => void) | null = null;\n private readonly freeList: T[] = [];\n\n // Deltas accumulate in dense store order on set/remove and drain on\n // drainChanges(). Untracked stores record nothing.\n private tracked = false;\n private readonly _added: EntityId[] = [];\n private readonly _removed: EntityId[] = [];\n private readonly _changed: EntityId[] = [];\n // Per-list callback dispatch cursors: how many _added/_removed entries the\n // onAdded/onRemoved fan-out has already fired. The delta lists drain only on\n // drainChanges() (once per frame), but flush() can run several times per frame\n // (the default Schedule flushes after every group), so without a cursor a\n // single add would re-fire its callback on every flush until the frame drain.\n private _addedFired = 0;\n private _removedFired = 0;\n\n // Bumped on every membership change (add/remove) AND object replacement (a\n // `set` on an existing entity replaces the stored object, invalidating cached\n // query tuples that hold the old reference). Lets a query rebuild only when\n // one of its own component stores changes.\n private _version = 0;\n\n constructor(capacity: number = DEFAULT_MAX_ENTITIES) {\n this.capacity = capacity;\n this.sparse = new Int32Array(capacity).fill(EMPTY);\n }\n\n /**\n * Enable component pooling for this store. On `remove`, the removed object is\n * passed through `reset` and pushed onto a free list; the next pooled\n * `acquire()` hands it back instead of allocating. Opt-in per store. Do not\n * enable it where callers rely on each add storing the exact object passed;\n * pooling aliases objects across entities.\n */\n enablePooling(reset: (c: T) => void): void {\n this.pooling = true;\n this.resetFn = reset;\n }\n\n /** Whether pooling is enabled for this store. */\n isPooling(): boolean {\n return this.pooling;\n }\n\n /**\n * Enable add/removed/changed tracking for this store. Idempotent. Default OFF;\n * an untracked store records nothing and pays a single already-false branch on\n * set()/remove(). Does NOT retroactively record existing members, only\n * post-enable transitions, matching event-bus \"from now on\" semantics. Deltas\n * accumulate in dense store order until drainChanges().\n */\n enableTracking(): void {\n this.tracked = true;\n }\n\n /** Whether tracking is enabled for this store. */\n isTracking(): boolean {\n return this.tracked;\n }\n\n /**\n * Pop a pooled (already-reset) object, or undefined if pooling is off or the\n * free list is empty. Used by `World.addComponent` to reuse component objects.\n */\n acquire(): T | undefined {\n return this.pooling ? this.freeList.pop() : undefined;\n }\n\n /** Number of objects currently parked in the free list (for tests/metrics). */\n pooledCount(): number {\n return this.freeList.length;\n }\n\n /**\n * Monotonic version, bumped on every add/remove (membership change) and on a\n * `set` that replaces an existing object. Read by the query engine to rebuild\n * a cached query only when one of its own component stores has changed.\n */\n get version(): number {\n return this._version;\n }\n\n /** Whether entity has this component. */\n has(id: EntityId): boolean {\n return (\n (id as number) < this.capacity && this.sparse[id as number] !== EMPTY\n );\n }\n\n /** Get component data. Returns undefined if not present. */\n get(id: EntityId): T | undefined {\n const idx = this.sparse[id as number];\n return idx !== EMPTY ? this.data[idx] : undefined;\n }\n\n /** Get component data without bounds check. Caller must ensure has(id). */\n getUnsafe(id: EntityId): T {\n return this.data[this.sparse[id as number]];\n }\n\n private outOfRange(method: string, id: EntityId): never {\n throw new Error(\n `ComponentStore.${method}(): entity id ${id} exceeds capacity ` +\n `(${this.capacity}). The sparse array cannot index it: this id was not ` +\n `produced by a World sized for it (see World maxEntities).`,\n );\n }\n\n /** Set (add or update) component data for entity. */\n set(id: EntityId, value: T): void {\n if ((id as number) >= this.capacity) this.outOfRange(\"set\", id);\n const idx = this.sparse[id as number];\n if (idx !== EMPTY) {\n this.data[idx] = value;\n } else {\n const dense = this.count++;\n this.sparse[id as number] = dense;\n this.entities[dense] = id;\n this.data[dense] = value;\n if (this.tracked) this._added.push(id);\n }\n // Bump on both add and object-replacement: a replaced object invalidates any\n // cached query tuple holding the old reference.\n this._version++;\n }\n\n /**\n * Record an explicit change for an entity that currently has the component.\n * No-op when untracked or absent. Coarse: no dedup; calling it twice on the\n * same entity records two entries. Not pruned on remove, so a changed-then-\n * removed id stays in iterChanged() until drainChanges(); re-check has() if\n * liveness matters.\n */\n markChanged(id: EntityId): void {\n if ((id as number) >= this.capacity) this.outOfRange(\"markChanged\", id);\n if (this.tracked && this.sparse[id as number] !== EMPTY) {\n this._changed.push(id);\n }\n }\n\n /**\n * Remove component from entity. Swap-delete to keep arrays dense. Returns\n * `true` if the entity had the component (membership changed), `false` if it\n * was absent.\n */\n remove(id: EntityId): boolean {\n if ((id as number) >= this.capacity) this.outOfRange(\"remove\", id);\n const idx = this.sparse[id as number];\n if (idx === EMPTY) return false;\n\n // Pooling: reset and park the removed object before it leaves the store.\n // Reading data[idx] here happens before the swap below overwrites it.\n if (this.pooling && this.resetFn !== null) {\n const removed = this.data[idx];\n this.resetFn(removed);\n this.freeList.push(removed);\n }\n\n // Capture the removed id BEFORE the swap-delete mutates the arrays; `id` is\n // the entity itself and is unaffected by compaction, so the recorded delta\n // is the exact membership loss in dense order.\n if (this.tracked) this._removed.push(id);\n\n const last = this.count - 1;\n if (idx !== last) {\n const lastEntity = this.entities[last];\n this.entities[idx] = lastEntity;\n this.data[idx] = this.data[last];\n this.sparse[lastEntity as number] = idx;\n }\n this.sparse[id as number] = EMPTY;\n this.entities.length = last;\n this.data.length = last;\n this.count = last;\n this._version++;\n return true;\n }\n\n /** Dense entity array; iterate for hot paths. Length is size(). */\n iterEntities(): ReadonlyArray<EntityId> {\n return this.entities;\n }\n\n /** Dense data array; iterate for hot paths. Length is size(). */\n iterData(): ReadonlyArray<T> {\n return this.data;\n }\n\n /** Entities that gained the component since drainChanges(), in dense order. */\n iterAdded(): ReadonlyArray<EntityId> {\n return this._added;\n }\n\n /** Entities that lost the component since drainChanges(), in dense order. */\n iterRemoved(): ReadonlyArray<EntityId> {\n return this._removed;\n }\n\n /** Entities marked changed since drainChanges(), in dense order. May include a changed-then-removed id (see markChanged). */\n iterChanged(): ReadonlyArray<EntityId> {\n return this._changed;\n }\n\n /** Count of _added entries the onAdded fan-out has already dispatched. */\n get addedFired(): number {\n return this._addedFired;\n }\n\n /** Count of _removed entries the onRemoved fan-out has already dispatched. */\n get removedFired(): number {\n return this._removedFired;\n }\n\n /** Advance the onAdded dispatch cursor (set by World.flush's callback fan-out). */\n setAddedFired(n: number): void {\n this._addedFired = n;\n }\n\n /** Advance the onRemoved dispatch cursor. */\n setRemovedFired(n: number): void {\n this._removedFired = n;\n }\n\n /** Truncate all three delta lists to length 0, resetting dispatch cursors. */\n drainChanges(): void {\n this._added.length = 0;\n this._removed.length = 0;\n this._changed.length = 0;\n this._addedFired = 0;\n this._removedFired = 0;\n }\n\n /** Number of entities with this component. */\n size(): number {\n return this.count;\n }\n\n /** Remove all entries. */\n clear(): void {\n for (let i = 0; i < this.count; i++) {\n this.sparse[this.entities[i] as number] = EMPTY;\n }\n this.entities.length = 0;\n this.data.length = 0;\n this.count = 0;\n this.freeList.length = 0;\n // Reset deltas so a cleared store starts fresh. `tracked` stays enabled\n // (opt-in survives clear, mirroring pooling). clear() does NOT push the\n // cleared members into _removed; it is a bulk teardown, not a per-frame\n // structural change, and consumers never observe deltas across a clear().\n this._added.length = 0;\n this._removed.length = 0;\n this._changed.length = 0;\n this._addedFired = 0;\n this._removedFired = 0;\n this._version++;\n }\n}\n","// Spatial Hash: uniform grid broad phase\n// Configurable cell size, Szudzik pairing for negative coordinates, and a\n// `queryRadius` broad-plus-narrow pass. Result arrays are passed in by reference,\n// so queries allocate nothing.\n//\n// Query dedup uses an `Int32Array` keyed by entity id plus a monotonic generation\n// counter (no per-query Set or Map allocation). This runs ~2-3.7x faster than a\n// `Map<Entity, number>` when one query runs per entity per frame, and a monotonic\n// counter never collides. That avoids the false-negative a position-derived\n// generation would risk: two queries at colliding positions could share a\n// generation, so one would skip an entity the other already marked.\n//\n// Three occupancy structures keep a query off cells nothing was inserted into, all\n// of them supersets of the true occupied set (so they can only skip cells that are\n// provably empty, never change a result):\n// * the frame stamp on each bucket, which makes `clear()` O(1);\n// * the occupied bounding box, which clamps a query's cell span;\n// * the per-column occupied row range, which clamps it again per column.\n\nimport { DEFAULT_MAX_ENTITIES } from \"./store\";\nimport type { Entity } from \"./types\";\n\n/** Direct-mapped column slots, indexed `cx & COL_MASK`. Aliasing two columns onto\n * one slot merges their row ranges, which is a superset, so results are unchanged. */\nconst COL_SLOTS = 256;\nconst COL_MASK = COL_SLOTS - 1;\n/** Clears between prunes. A bucket survives up to 2x this many idle frames. */\nconst SWEEP_PERIOD = 64;\nconst I32_MIN = -2147483648;\nconst I32_MAX = 2147483647;\n\n/** A grid bucket. `e` is retained across frames and `n` is the live prefix length;\n * `g` is the frame stamp, so a bucket from an earlier frame reads as empty. */\ninterface Cell {\n e: Entity[];\n n: number;\n g: number;\n}\n\nexport class SpatialHash {\n private invCellSize: number;\n private cells = new Map<number, Cell>();\n // `seen[entity]` holds the generation of the last query that visited it. Gens\n // are monotonic and start at 1, so the zero-initialised array reads as unseen.\n private generation = 0;\n private readonly seen: Int32Array;\n // Occupied bounding box in cell coordinates for the current frame; empty while\n // `occMaxCX < occMinCX`, which collapses every query's cell span to nothing.\n private occMinCX = 0;\n private occMaxCX = -1;\n private occMinCY = 0;\n private occMaxCY = -1;\n // Per column: [frame stamp, min occupied cy, max occupied cy].\n private readonly col = new Int32Array(COL_SLOTS * 3);\n // Frame stamp, never 0 (0 is the zero-filled \"never written\" reading of `col`)\n // and never past I32_MAX, so it stays a Smi and matches `col`'s int32 domain.\n private frameGen = 1;\n private sweepIn = SWEEP_PERIOD;\n\n /**\n * @param cellSize grid cell size in world units. Must be > 0.\n * @param maxEntities upper bound on entity ids inserted (sizes the dedup\n * array, `maxEntities * 4` bytes). Match the consuming World's capacity.\n */\n constructor(cellSize = 64, maxEntities: number = DEFAULT_MAX_ENTITIES) {\n if (!(cellSize > 0)) {\n throw new Error(`SpatialHash: cellSize must be > 0 (got ${cellSize})`);\n }\n this.invCellSize = 1 / cellSize;\n this.seen = new Int32Array(maxEntities);\n }\n\n // `| 0` keeps the counter in the same int32 domain as `seen`; skip 0 (= unseen).\n private nextGen(): number {\n this.generation = (this.generation + 1) | 0;\n if (this.generation === 0) this.generation = 1;\n return this.generation;\n }\n\n clear(): void {\n // O(1): bump the frame stamp, and every bucket, column range and bounding box\n // written by an earlier frame reads as empty. Nothing is walked per frame.\n // The cost is retention: a dead bucket is only reclaimed by the periodic\n // sweep, so an unbounded / roaming world holds the buckets touched in the last\n // 2 sweep periods rather than the last frame. Per-cell push order and per-cell\n // visit order are untouched, so a result array keeps both its membership and\n // its ORDER. `generation` is deliberately NOT reset: monotonic gens are what\n // keep the query dedup correct across frames.\n this.occMinCX = 0;\n this.occMaxCX = -1;\n this.occMinCY = 0;\n this.occMaxCY = -1;\n const fg = this.frameGen + 1;\n if (fg >= I32_MAX) {\n // Wrap. Every stamp restarts, so nothing may survive carrying an old one.\n this.cells.clear();\n this.col.fill(0);\n this.frameGen = 1;\n this.sweepIn = SWEEP_PERIOD;\n return;\n }\n this.frameGen = fg;\n if (--this.sweepIn <= 0) {\n this.sweepIn = SWEEP_PERIOD;\n this.cells.forEach(this.pruneStale, this);\n }\n }\n\n /** `Map.forEach` callback for the periodic sweep, invoked with the hash as\n * `thisArg` so it allocates no per-sweep closure. */\n private pruneStale(cell: Cell, key: number): void {\n if (this.frameGen - cell.g >= SWEEP_PERIOD) this.cells.delete(key);\n }\n\n insert(entity: Entity, x: number, y: number, radius: number): void {\n const seen = this.seen;\n if ((entity as number) >= seen.length) {\n throw new Error(\n `SpatialHash.insert(): entity id ${entity} exceeds maxEntities ` +\n `(${seen.length}). Construct the SpatialHash with a maxEntities ` +\n `that matches the consuming World's capacity.`,\n );\n }\n const cells = this.cells;\n const inv = this.invCellSize;\n const minCX = Math.floor((x - radius) * inv);\n const maxCX = Math.floor((x + radius) * inv);\n const minCY = Math.floor((y - radius) * inv);\n const maxCY = Math.floor((y + radius) * inv);\n\n if (this.occMaxCX < this.occMinCX) {\n this.occMinCX = minCX;\n this.occMaxCX = maxCX;\n this.occMinCY = minCY;\n this.occMaxCY = maxCY;\n } else {\n if (minCX < this.occMinCX) this.occMinCX = minCX;\n if (maxCX > this.occMaxCX) this.occMaxCX = maxCX;\n if (minCY < this.occMinCY) this.occMinCY = minCY;\n if (maxCY > this.occMaxCY) this.occMaxCY = maxCY;\n }\n\n const col = this.col;\n const fg = this.frameGen;\n // `col` is int32, so a row index past that domain is stored WIDENED to the\n // domain edge. Widening keeps the stored range a superset; truncating it\n // would wrap into a narrower range and drop results.\n const cLo = minCY < I32_MIN ? I32_MIN : minCY;\n const cHi = maxCY > I32_MAX ? I32_MAX : maxCY;\n\n for (let cx = minCX; cx <= maxCX; cx++) {\n const ci = (cx & COL_MASK) * 3;\n if (col[ci] !== fg) {\n col[ci] = fg;\n col[ci + 1] = cLo;\n col[ci + 2] = cHi;\n } else {\n if (cLo < col[ci + 1]) col[ci + 1] = cLo;\n if (cHi > col[ci + 2]) col[ci + 2] = cHi;\n }\n // Szudzik pairing, which handles negatives. `a` and `a * a + a` depend only\n // on cx, so both are hoisted out of the cy loop. Cell-index magnitude must\n // stay below ~sqrt(2^53) (~9.4e7) for `a * a` to remain an exact integer;\n // beyond that distinct cells collide.\n const a = cx >= 0 ? 2 * cx : -2 * cx - 1;\n const aa = a * a + a;\n for (let cy = minCY; cy <= maxCY; cy++) {\n const b = cy >= 0 ? 2 * cy : -2 * cy - 1;\n const key = a >= b ? aa + b : b * b + a;\n let cell = cells.get(key);\n if (cell === undefined) {\n cell = { e: [], n: 0, g: fg };\n cells.set(key, cell);\n } else if (cell.g !== fg) {\n cell.g = fg;\n cell.n = 0;\n }\n const n = cell.n;\n const items = cell.e;\n if (n < items.length) items[n] = entity;\n else items.push(entity);\n cell.n = n + 1;\n }\n }\n }\n\n /** Query all entities within a circle. Deduplicates via generation counter. */\n query(x: number, y: number, radius: number, results: Entity[]): void {\n results.length = 0;\n const queryGen = this.nextGen();\n const cells = this.cells;\n const seen = this.seen;\n const inv = this.invCellSize;\n\n let minCX = Math.floor((x - radius) * inv);\n let maxCX = Math.floor((x + radius) * inv);\n let minCY = Math.floor((y - radius) * inv);\n let maxCY = Math.floor((y + radius) * inv);\n if (minCX < this.occMinCX) minCX = this.occMinCX;\n if (maxCX > this.occMaxCX) maxCX = this.occMaxCX;\n if (minCY < this.occMinCY) minCY = this.occMinCY;\n if (maxCY > this.occMaxCY) maxCY = this.occMaxCY;\n\n const col = this.col;\n const fg = this.frameGen;\n for (let cx = minCX; cx <= maxCX; cx++) {\n const ci = (cx & COL_MASK) * 3;\n if (col[ci] !== fg) continue;\n let cyLo = minCY;\n let cyHi = maxCY;\n if (cyLo < col[ci + 1]) cyLo = col[ci + 1];\n if (cyHi > col[ci + 2]) cyHi = col[ci + 2];\n const a = cx >= 0 ? 2 * cx : -2 * cx - 1;\n const aa = a * a + a;\n for (let cy = cyLo; cy <= cyHi; cy++) {\n const b = cy >= 0 ? 2 * cy : -2 * cy - 1;\n const cell = cells.get(a >= b ? aa + b : b * b + a);\n if (cell === undefined || cell.g !== fg) continue;\n const items = cell.e;\n for (let i = 0, n = cell.n; i < n; i++) {\n const entity = items[i];\n if (seen[entity as number] !== queryGen) {\n seen[entity as number] = queryGen;\n results.push(entity);\n }\n }\n }\n }\n }\n\n /** Query + circle-circle narrow phase in one pass. `getPos` and `getRadius` are\n * called once per candidate and must not mutate the hash. */\n queryRadius(\n x: number,\n y: number,\n radius: number,\n getPos: (e: Entity) => { x: number; y: number } | undefined,\n getRadius: (e: Entity) => number,\n results: Entity[],\n ): void {\n results.length = 0;\n const queryGen = this.nextGen();\n const cells = this.cells;\n const seen = this.seen;\n const inv = this.invCellSize;\n\n let minCX = Math.floor((x - radius) * inv);\n let maxCX = Math.floor((x + radius) * inv);\n let minCY = Math.floor((y - radius) * inv);\n let maxCY = Math.floor((y + radius) * inv);\n if (minCX < this.occMinCX) minCX = this.occMinCX;\n if (maxCX > this.occMaxCX) maxCX = this.occMaxCX;\n if (minCY < this.occMinCY) minCY = this.occMinCY;\n if (maxCY > this.occMaxCY) maxCY = this.occMaxCY;\n\n const col = this.col;\n const fg = this.frameGen;\n for (let cx = minCX; cx <= maxCX; cx++) {\n const ci = (cx & COL_MASK) * 3;\n if (col[ci] !== fg) continue;\n let cyLo = minCY;\n let cyHi = maxCY;\n if (cyLo < col[ci + 1]) cyLo = col[ci + 1];\n if (cyHi > col[ci + 2]) cyHi = col[ci + 2];\n const a = cx >= 0 ? 2 * cx : -2 * cx - 1;\n const aa = a * a + a;\n for (let cy = cyLo; cy <= cyHi; cy++) {\n const b = cy >= 0 ? 2 * cy : -2 * cy - 1;\n const cell = cells.get(a >= b ? aa + b : b * b + a);\n if (cell === undefined || cell.g !== fg) continue;\n const items = cell.e;\n for (let i = 0, n = cell.n; i < n; i++) {\n const entity = items[i];\n if (seen[entity as number] === queryGen) continue;\n seen[entity as number] = queryGen;\n\n const pos = getPos(entity);\n if (!pos) continue;\n const r = getRadius(entity);\n const dx = pos.x - x;\n const dy = pos.y - y;\n const distSq = dx * dx + dy * dy;\n const combinedR = radius + r;\n if (distSq <= combinedR * combinedR) {\n results.push(entity);\n }\n }\n }\n }\n }\n}\n","/** Branded entity identifier. `EntityId` is a convenience alias. */\nexport type Entity = number & { readonly __brand: unique symbol };\nexport type EntityId = Entity;\n\n/**\n * A stable, storable reference to an entity = (index, generation), encoded as\n * one safe-integer number (index in the low bits, generation in the high bits;\n * safe while the World's `maxEntities` ≤ 2^21, which the World constructor\n * enforces). Unlike {@link Entity} (the bare dense index, recycled on despawn), a handle\n * also carries the index's generation at stamp time, so a handle to a despawned\n * entity fails to resolve even after the index is reused. Opaque: build with\n * `world.handleOf`, consume with `world.resolve` / `world.isHandleValid`. Do not\n * pack a generation into `Entity` itself: that would break `sparse[entity]`\n * O(1) indexing in the store and spatial hash.\n */\nexport type EntityHandle = number & { readonly __handleBrand: unique symbol };\n\n/**\n * A stable, storable reference to an entity = its dense index packed with the\n * generation it had when the ref was taken. The SAME runtime encoding as\n * {@link EntityHandle} (index in the low bits, generation in the high bits, one\n * safe integer), so a ref and a handle for the same entity are bit-identical and\n * resolve through the same generations side-array; they never fork. Unlike a\n * bare {@link Entity} (recycled on despawn), a ref carries the stamp generation,\n * so once the target is despawned (and its index possibly recycled) the ref no\n * longer matches the live generation and resolves to `null`. Encoded as one\n * safe-integer number so it can be stored inside plain component data and\n * compared with `===`. Build with `world.ref`, consume with `world.deref` /\n * `world.isRefValid`. {@link NULL_REF} (0) is the canonical \"points at nothing\".\n */\nexport type EntityRef = EntityHandle & { readonly __refBrand: unique symbol };\n\n/** The canonical empty reference. Resolves to `null`, never matches an entity. */\nexport const NULL_REF = 0 as EntityRef;\n\n/**\n * Token identifying a component type. Created via {@link defineComponent}.\n *\n * `create` / `reset` are optional:\n * - `defineComponent<T>(name)` builds component data at the call site\n * (`world.add`).\n * - `defineComponent<T>(name, create, reset)` uses a factory and is added with\n * `world.addComponent(entity, def, partial)`, with optional pooling on\n * despawn (the `reset` hook).\n */\nexport interface ComponentType<T> {\n readonly id: number;\n readonly name: string;\n readonly create?: () => T;\n readonly reset?: (component: T) => void;\n /** Phantom field to carry the data type; never read at runtime. */\n readonly _phantom?: T;\n /** Per-kind nominal brand (never set at runtime); makes token kinds mutually non-assignable. */\n readonly __kind?: \"component\";\n}\n\n/**\n * A component token created *with* a `create` factory (and `reset` hook). The\n * factory-using APIs (`world.addComponent` and `world.enablePooling`) require\n * this narrower type, so they are statically guaranteed a factory/reset exists\n * (no `data as T` cast, no runtime \"missing factory/reset\" throw).\n */\nexport interface PooledComponentType<T> extends ComponentType<T> {\n readonly create: () => T;\n readonly reset: (component: T) => void;\n}\n\n/**\n * A presence-only (\"tag\") component: a {@link ComponentType}<true> whose store\n * holds the shared constant `true` for every member rather than a per-entity\n * object. Branded with `readonly tag: true` so APIs that want to forbid data\n * components (or detect tags) can do so at the type level. Use with\n * `world.addTag` / `world.hasTag` / `world.removeTag`; it also participates in\n * queries exactly like any other component (the store membership is identical).\n * A tag is intentionally NOT a {@link PooledComponentType} (no `create`/`reset`),\n * so it can never be routed through the pooling reset path.\n */\nexport interface TagType extends ComponentType<true> {\n readonly tag: true;\n}\n\n/** Alias of {@link ComponentType}, for code that prefers the `Def` spelling. */\nexport type ComponentDef<T> = ComponentType<T>;\n\n/** Token identifying a resource (singleton) type. Created via {@link defineResource}. */\nexport interface ResourceType<T> {\n readonly id: number;\n readonly name: string;\n readonly _phantom?: T;\n /** Per-kind nominal brand. See {@link ComponentType.__kind}. */\n readonly __kind?: \"resource\";\n}\n\n/** Token identifying an event type. Created via {@link defineEvent}. */\nexport interface EventType<T = void> {\n readonly id: number;\n readonly name: string;\n readonly _phantom?: T;\n /** Per-kind nominal brand. See {@link ComponentType.__kind}. */\n readonly __kind?: \"event\";\n}\n\n/**\n * Token identifying a per-system local scratch slot. Created via\n * {@link defineLocal}. Unlike a resource, a local carries its own lazy\n * initializer; the first {@link World.local} call for the token builds the\n * value. Intended for private per-system state (counters, ring buffers,\n * cached scratch arrays) without reaching for a global resource.\n */\nexport interface LocalType<T> {\n readonly id: number;\n readonly name: string;\n /** Builds the initial value on first access. Called at most once per World. */\n readonly init: () => T;\n /** Phantom field to carry the data type; never read at runtime. */\n readonly _phantom?: T;\n /** Per-kind nominal brand. See {@link ComponentType.__kind}. */\n readonly __kind?: \"local\";\n}\n\n// Avoid a circular import: the World class lives in world.ts.\nimport type { World } from \"./world\";\n\nexport type { World };\n\n/**\n * A system is a plain function. The second argument is the frame delta; systems\n * that don't use it can be written as `(world) => void`. Both shapes are valid\n * `System` values.\n */\nexport type System = (world: World, dt: number) => void;\n\n/** Query result: a tuple of `[Entity, ...components]`. */\nexport type QueryResult<T extends unknown[]> = [Entity, ...T];\n/**\n * A {@link ComponentType} of *some* (erased) data type, for heterogeneous\n * collections of component defs where only the `.id` is read. `ComponentType<T>`\n * is invariant-to-contravariant in `T` under `strictFunctionTypes` (its `reset`\n * takes `T`), so a specific `ComponentType<{x}>` is NOT assignable to\n * `ComponentType<unknown>`; `unknown` would force a cast at every call site.\n * `any` is the canonical, and only, escape; it is confined to this single alias\n * (the value is never read through it, only the id). All public filter types\n * below build on this so `select(...)`/`any(...)` accept concrete components\n * without casts.\n */\n// biome-ignore lint/suspicious/noExplicitAny: heterogeneous, value-erased component collection (see the JSDoc above); only `.id` is read.\nexport type AnyComponentType = ComponentType<any>;\n\n/** Role a single wrapped component term plays inside a query spec. */\nexport type QueryTermKind = \"with\" | \"without\" | \"maybe\";\n\n/**\n * A component reference wrapped to mark its role inside a query spec. Built by\n * the `without` / `maybe` factories in query.ts (a bare def is treated as\n * `with` without wrapping).\n */\nexport interface QueryTerm<T> {\n readonly kind: QueryTermKind;\n readonly def: ComponentType<T>;\n}\n\n/**\n * A {@link QueryTerm} of some erased data type: the heterogeneous form a\n * `without(...)`/`maybe(...)` result flows into a {@link QueryArg} as. Its `def`\n * is an {@link AnyComponentType}, so the same variance rationale applies.\n */\nexport interface AnyQueryTerm {\n readonly kind: QueryTermKind;\n readonly def: AnyComponentType;\n}\n\n/**\n * An `any(...)` group: at least one of the listed defs must be present for an\n * entity to match. Contributes no value to the yield tuple. Built by the `any`\n * factory in query.ts. Stores defs as {@link AnyComponentType} so concrete\n * component types flow in without a cast.\n */\nexport interface AnyGroup {\n readonly kind: \"any\";\n readonly defs: AnyComponentType[];\n}\n\n/**\n * A single argument to `world.select(...)` / `compileSpec(...)`: a bare\n * {@link ComponentType} (required `with`), a {@link QueryTerm} (`without` /\n * `maybe`), or an {@link AnyGroup} (`any`). Built on {@link AnyComponentType} so\n * a specific `ComponentType<{x}>` / `QueryTerm<{x}>` flows in without a cast.\n */\nexport type QueryArg = AnyComponentType | AnyQueryTerm | AnyGroup;\nlet _nextComponentId = 0;\nlet _nextResourceId = 0;\nlet _nextEventId = 0;\nlet _nextLocalId = 0;\n\n/**\n * The shared singleton value every tag store entry points at; never a fresh\n * object, so a tag costs zero per-entity allocation. Exported for the store-fill\n * path and tests; never mutated.\n */\nexport const TAG_VALUE = true as const;\n\n/**\n * Define a new component type.\n *\n * Two call styles, distinguished at the type level:\n * defineComponent<T>(name) // data built at the call site\n * // -> ComponentType<T> (use world.add)\n * defineComponent<T>(name, create, reset) // factory + pooling hook\n * // -> PooledComponentType<T>\n * // (use world.addComponent / pooling)\n */\nexport function defineComponent<T>(name: string): ComponentType<T>;\nexport function defineComponent<T>(\n name: string,\n create: () => T,\n reset: (c: T) => void,\n): PooledComponentType<T>;\nexport function defineComponent<T>(\n name: string,\n create?: () => T,\n reset?: (c: T) => void,\n): ComponentType<T> {\n return { id: _nextComponentId++, name, create, reset } as ComponentType<T>;\n}\n\n/**\n * Define a zero-sized tag component. Unlike {@link defineComponent}, no data\n * object is ever created or stored: membership in the dense store IS the\n * component, and the store value is the module-level shared {@link TAG_VALUE}\n * (= true). Tag ids draw from the SAME counter as `defineComponent`, so a tag is\n * a fully ordinary component id for `world.store`, queries, the bitmask, and\n * `flush`. The `create`/`reset` fields are deliberately absent, so a tag is not\n * a {@link PooledComponentType} and cannot be pooled.\n */\nexport function defineTag(name: string): TagType {\n return { id: _nextComponentId++, name, tag: true } as TagType;\n}\n\n/** Define a new resource (singleton) type. */\nexport function defineResource<T>(name: string): ResourceType<T> {\n return { id: _nextResourceId++, name } as ResourceType<T>;\n}\n\n/** Define a new event type. */\nexport function defineEvent<T = void>(name: string): EventType<T> {\n return { id: _nextEventId++, name } as EventType<T>;\n}\n\n/**\n * Define a per-system local scratch slot.\n *\n * const Accum = defineLocal<{ n: number }>(\"frameAccum\", () => ({ n: 0 }));\n * const tick: System = (world) => { world.local(Accum).n++; };\n *\n * Each call produces a unique, process-wide id (same convention as\n * defineComponent / defineResource / defineEvent).\n */\nexport function defineLocal<T>(name: string, init: () => T): LocalType<T> {\n return { id: _nextLocalId++, name, init } as LocalType<T>;\n}\n","import { Bitmask } from \"./bitmask\";\nimport type { CommandBuffer } from \"./command-buffer\";\nimport { EventBus } from \"./events\";\nimport { IncrementalQuery } from \"./incremental-query\";\nimport { type CompiledQuery, parseQueryArgs, QueryEngine } from \"./query\";\nimport { ComponentStore, DEFAULT_MAX_ENTITIES } from \"./store\";\nimport {\n type AnyComponentType,\n type ComponentType,\n type Entity,\n type EntityHandle,\n type EntityId,\n type EntityRef,\n type LocalType,\n NULL_REF,\n type PooledComponentType,\n type QueryArg,\n type QueryResult,\n type ResourceType,\n TAG_VALUE,\n type TagType,\n} from \"./types\";\n\nexport class World {\n private nextId = 1; // 0 is reserved as \"no entity\"\n private readonly maxEntities: number;\n private readonly alive = new Set<EntityId>();\n private readonly recycled: EntityId[] = [];\n private readonly pendingDespawns: EntityId[] = [];\n // Bumped only when a despawn is applied in flush(); read by handleOf/resolve\n // to detect a handle held across a despawn and recycled id.\n private readonly generations: Uint32Array;\n private readonly indexBits: number; // ceil(log2(maxEntities)), >=1\n private readonly indexMask: number; // (2 ** indexBits) - 1\n // EntityRef reuses the exact (index, generation) packing as EntityHandle. The\n // reverse index is allocated only after enableBackrefs().\n private backrefsEnabled = false;\n // target index -> holder entities, in insertion order, de-duplicated.\n private backrefEdges: Map<number, Entity[]> | null = null;\n // holder index -> target indices it points at, so a despawned holder is swept\n // from every target's edge list during flush(). Allocated by enableBackrefs().\n private holderToTargets: Map<number, Set<number>> | null = null;\n // Indexed by component id (dense, from the module-level counter), plus a\n // compact list of created stores for flush/clear iteration. Array indexing is\n // ~2.5x faster than Map.get on the per-access hot path (get/has/add), with\n // identical semantics and iteration order.\n private readonly stores: (ComponentStore<unknown> | undefined)[] = [];\n private readonly activeStores: ComponentStore<unknown>[] = [];\n // A compact list of the stores opted into tracking, so clearChanges() touches\n // only opted-in stores. The callback maps stay null until onAdded/onRemoved is\n // used, so flush() checks one `!== null` branch.\n private readonly trackedStores: ComponentStore<unknown>[] = [];\n private addedCallbacks: Map<number, ((e: Entity) => void)[]> | null = null;\n private removedCallbacks: Map<number, ((e: Entity) => void)[]> | null = null;\n private readonly resources = new Map<number, unknown>();\n // String-keyed resources: an alternative to typed tokens (e.g. for quick\n // experimenting or porting a string-keyed resource map).\n private readonly stringResources = new Map<string, unknown>();\n // Per-system local scratch state, keyed by LocalType id. Lazily built on\n // first local() access; independent of resources.\n private readonly locals = new Map<number, unknown>();\n readonly events = new EventBus();\n private readonly queryEngine: QueryEngine;\n private _version = 0;\n // A derived per-entity component-signature mirror, built by enableBitmask()\n // and kept in sync on every World-API membership change. Stays null until\n // opted in. Signatures for hasAllMask are cached by def-id-list key.\n private bitmask: Bitmask | null = null;\n private readonly maskSigs = new Map<string, Uint32Array>();\n // Queries whose match set is maintained on add/remove instead of rebuilt on the\n // next access. `incrementalByComponent[id]` is the list to reconcile when\n // component `id` changes for an entity; `incrementalQueries` is the flat list\n // for flush/clear. `hasIncremental` gates mutation hooks to a single boolean\n // check when no incremental query is registered.\n private hasIncremental = false;\n private readonly incrementalByComponent: (IncrementalQuery[] | undefined)[] =\n [];\n private readonly incrementalQueries: IncrementalQuery[] = [];\n\n /**\n * Called inside flush() for each entity actually removed, before its\n * components are stripped (so the callback can still read them). Defaults to\n * null; set it to e.g. tear down a sprite or other external resource.\n */\n onBeforeDestroy: ((entity: Entity) => void) | null = null;\n\n /** Monotonic version, bumped on component add/remove and applied despawns. */\n get version(): number {\n return this._version;\n }\n\n /**\n * @param options.maxEntities Per-store sparse-array capacity and the spawn\n * ceiling. Defaults to {@link DEFAULT_MAX_ENTITIES} (65536). Raise it for a\n * world that can hold more live entities at once.\n */\n constructor(options?: { maxEntities?: number }) {\n this.maxEntities = options?.maxEntities ?? DEFAULT_MAX_ENTITIES;\n this.indexBits = Math.max(1, Math.ceil(Math.log2(this.maxEntities)));\n this.indexMask = 2 ** this.indexBits - 1;\n // Handle/ref pack gen (u32) into the high bits above indexBits, so the packed\n // value stays a safe integer only while indexBits + 32 <= 53.\n if (this.indexBits + 32 > 53) {\n throw new Error(\n `World: maxEntities ${this.maxEntities} too large; entity handles need ` +\n `maxEntities <= 2^21 (2097152) to stay safe integers.`,\n );\n }\n // Zero-filled generation per index (every fresh index is gen 0).\n this.generations = new Uint32Array(this.maxEntities);\n\n this.queryEngine = new QueryEngine({\n isAlive: (entity) => this.alive.has(entity),\n storeIfPresent: (id) => this.stores[id],\n // The per-entity component bitmask, when enabled, lets rebuildEntities\n // replace its per-store has() probe with one signature AND.\n bitmask: () => this.bitmask,\n });\n }\n /** Create a new entity immediately. Returns its id. */\n spawn(): EntityId {\n const id =\n this.recycled.length > 0\n ? (this.recycled.pop() as EntityId)\n : (this.nextId++ as EntityId);\n if ((id as number) >= this.maxEntities) {\n throw new Error(\n `World.spawn(): entity id ${id} exceeds maxEntities (${this.maxEntities}). ` +\n `Component sparse arrays cannot index this id. Construct the World with ` +\n `a larger { maxEntities } or audit for an entity leak.`,\n );\n }\n this.alive.add(id);\n return id;\n }\n\n /** Queue entity for removal. Applied on flush(). */\n despawn(id: EntityId): void {\n this.pendingDespawns.push(id);\n }\n\n /** Whether entity is currently alive. */\n isAlive(id: EntityId): boolean {\n return this.alive.has(id);\n }\n\n /** Number of alive entities. */\n get entityCount(): number {\n return this.alive.size;\n }\n\n /**\n * Apply deferred despawns. Called between system groups by the Schedule.\n * Removes all components from despawned entities and recycles their ids.\n */\n flush(): void {\n if (this.pendingDespawns.length > 0) {\n for (const id of this.pendingDespawns) {\n if (!this.alive.delete(id)) continue;\n if (this.onBeforeDestroy) this.onBeforeDestroy(id);\n for (const store of this.activeStores) {\n store.remove(id);\n }\n this._version++;\n // Bump the index's generation so any handle stamped at the old generation\n // fails to resolve, even once this index is recycled and reused. >>> 0\n // keeps it an explicit unsigned 32-bit value (Uint32Array wraps on store).\n this.generations[id as number] =\n (this.generations[id as number] + 1) >>> 0;\n this.recycled.push(id);\n // Drop the entity's whole signature row in one call (store removes above\n // already settled membership).\n if (this.bitmask) this.bitmask.clearEntity(id as number);\n // Sweep the despawned target's reverse-index edge: the \"who points at me\"\n // list for a now-dead target is meaningless. Holders are not deleted\n // and no holder component scan, so this introduces zero new entity\n // removals and cannot shift any store's swap-delete order.\n if (this.backrefsEnabled && this.backrefEdges !== null) {\n this.backrefEdges.delete(id as number);\n // Sweep this id where it was a HOLDER: drop it from every target's\n // edge list, so a despawned holder's edges don't linger.\n const targets = this.holderToTargets?.get(id as number);\n if (targets !== undefined) {\n for (const t of targets) {\n const holders = this.backrefEdges.get(t);\n if (holders !== undefined) {\n const at = holders.indexOf(id as Entity);\n if (at !== -1) {\n holders.splice(at, 1);\n if (holders.length === 0) this.backrefEdges.delete(t);\n }\n }\n }\n this.holderToTargets?.delete(id as number);\n }\n }\n // Drop the now-dead entity from any incremental query it is in. The\n // entity was alive.delete()'d and stripped from its stores above, so\n // reconcile() sees no match and swap-deletes it.\n if (this.hasIncremental) {\n for (let q = 0; q < this.incrementalQueries.length; q++) {\n this.incrementalQueries[q].reconcile(id as number);\n }\n }\n }\n this.pendingDespawns.length = 0;\n }\n // Change-tracking callbacks fire at one deterministic point, AFTER the\n // despawn loop fully settles (so callbacks observe a fully-applied frame).\n // Both maps are null until onAdded/onRemoved is used.\n if (this.addedCallbacks !== null)\n this.fireCallbacks(this.addedCallbacks, true);\n if (this.removedCallbacks !== null) {\n this.fireCallbacks(this.removedCallbacks, false);\n }\n }\n /** Get (or lazily create) the store for a component type. */\n store<T>(type: ComponentType<T>): ComponentStore<T> {\n let s = this.stores[type.id];\n if (s === undefined) {\n s = new ComponentStore<unknown>(this.maxEntities);\n this.stores[type.id] = s;\n this.activeStores.push(s);\n }\n return s as ComponentStore<T>;\n }\n\n /**\n * Add a component to an entity (direct style: the passed object is stored\n * as-is). Bumps the version unconditionally: unlike addComponent's in-place\n * merge, `add` *replaces* the stored object, so any cached query tuple holding\n * the old reference must be invalidated.\n */\n add(id: EntityId, type: TagType, data?: never): void;\n add<T>(id: EntityId, type: ComponentType<T>, data: T): void;\n add<T>(id: EntityId, type: ComponentType<T>, data: T): void {\n this.store(type).set(id, data);\n this._version++;\n if (this.bitmask) this.bitmask.set(id as number, type.id);\n if (this.hasIncremental) this.reconcileIncremental(type.id, id as number);\n }\n\n /** Remove a component from an entity. */\n remove<T>(id: EntityId, type: ComponentType<T>): void {\n const removed = this.stores[type.id]?.remove(id);\n if (removed) {\n this._version++;\n if (this.bitmask) this.bitmask.clear(id as number, type.id);\n if (this.hasIncremental) this.reconcileIncremental(type.id, id as number);\n }\n }\n\n /** Get a component. Returns undefined if not present. */\n get<T>(id: EntityId, type: ComponentType<T>): T | undefined {\n return this.store(type).get(id);\n }\n\n /** Get a component without bounds check. Caller must ensure entity has it. */\n getUnsafe<T>(id: EntityId, type: ComponentType<T>): T {\n return this.store(type).getUnsafe(id);\n }\n\n /** Whether entity has a component. */\n has<T>(id: EntityId, type: ComponentType<T>): boolean {\n return this.store(type).has(id);\n }\n\n /**\n * Get the first entry of a component store (e.g. a player singleton). Throws if\n * empty. Does NOT assert uniqueness; use {@link CompiledQuery.single} for that.\n */\n getFirst<T>(type: ComponentType<T>): T {\n const data = this.store(type).iterData();\n if (data.length === 0) {\n throw new Error(`Component \"${type.name}\" has no entries`);\n }\n return data[0];\n }\n /**\n * Add a factory component ({@link PooledComponentType}). If the entity\n * already has the component, the existing instance is reused; otherwise\n * a pooled object is reused if available, else a fresh one is built via the\n * factory. `data` (a partial) is then merged onto the instance. (Components\n * without a factory are added with {@link add}.)\n */\n addComponent<T extends object>(\n entity: Entity,\n def: PooledComponentType<T>,\n data?: Partial<T>,\n ): T {\n const store = this.store(def);\n let component = store.get(entity);\n if (component === undefined) {\n component = store.acquire() ?? def.create();\n store.set(entity, component);\n this._version++;\n if (this.bitmask) this.bitmask.set(entity as number, def.id);\n if (this.hasIncremental)\n this.reconcileIncremental(def.id, entity as number);\n if (data) Object.assign(component, data);\n } else if (data) {\n Object.assign(component, data);\n store.markChanged(entity);\n }\n return component;\n }\n\n /** Alias of get(): component or undefined. */\n getComponent<T>(entity: Entity, def: ComponentType<T>): T | undefined {\n return this.store(def).get(entity);\n }\n\n /** Alias of has(). */\n hasComponent<T>(entity: Entity, def: ComponentType<T>): boolean {\n return this.store(def).has(entity);\n }\n\n /** Remove a component. Bumps version when one was actually removed. */\n removeComponent<T>(entity: Entity, def: ComponentType<T>): void {\n if (this.stores[def.id]?.remove(entity)) {\n this._version++;\n if (this.bitmask) this.bitmask.clear(entity as number, def.id);\n if (this.hasIncremental)\n this.reconcileIncremental(def.id, entity as number);\n }\n }\n\n /** Get a component, throwing if missing. */\n getOrThrow<T>(entity: Entity, def: ComponentType<T>): T {\n const c = this.store(def).get(entity);\n if (c === undefined) {\n throw new Error(`Entity ${entity} missing component ${def.name}`);\n }\n return c;\n }\n /**\n * Add a tag to an entity. Equivalent to `add(entity, tag, true)` but takes no\n * data argument; the store value is the shared {@link TAG_VALUE}, so no data\n * object is allocated. Membership-gated version bump: bumps only when the tag\n * is newly added (matches addComponent's \"bump only when newly added\"\n * semantics; a tag has no object to replace, so re-adds are idempotent).\n */\n addTag(entity: Entity, tag: TagType): void {\n const store = this.store(tag);\n if (!store.has(entity)) {\n store.set(entity, TAG_VALUE);\n this._version++;\n if (this.bitmask) this.bitmask.set(entity as number, tag.id);\n }\n }\n\n /** Whether an entity has a tag. Alias of `has(entity, tag)`. */\n hasTag(entity: Entity, tag: TagType): boolean {\n return this.store(tag).has(entity);\n }\n\n /** Remove a tag. Bumps version only when one was actually removed. */\n removeTag(entity: Entity, tag: TagType): void {\n if (this.stores[tag.id]?.remove(entity)) {\n this._version++;\n if (this.bitmask) this.bitmask.clear(entity as number, tag.id);\n }\n }\n /**\n * Enable a per-entity component bitmask index for this world. Builds a\n * {@link Bitmask} sized to `maxEntities` and back-fills it from every existing\n * store, then keeps it in sync on every subsequent add/remove/despawn.\n * Idempotent. Pays nothing until called. Returns the world for chaining.\n *\n * Contract: the index mirrors only mutations made through the World API\n * (add/remove/addComponent/removeComponent/addTag/removeTag/despawn+flush). A\n * caller that pokes a raw store via `getStoreRaw`/`store(...).set(...)` bypasses\n * it, exactly like the query version counter; `hasMask` would then drift for\n * that entity. Use the World API for any entity you also query via the mask.\n */\n enableBitmask(): this {\n if (this.bitmask) return this;\n const bm = new Bitmask(this.maxEntities);\n // Back-fill from every existing store, in store-id order. Index `id` IS the\n // component id, and bit-set is idempotent, so the result is independent of\n // traversal order.\n for (let id = 0; id < this.stores.length; id++) {\n const s = this.stores[id];\n if (s === undefined) continue;\n const ents = s.iterEntities();\n for (let i = 0; i < ents.length; i++) bm.set(ents[i] as number, id);\n }\n this.bitmask = bm;\n return this;\n }\n\n /** Whether the bitmask index is enabled. */\n isBitmaskEnabled(): boolean {\n return this.bitmask !== null;\n }\n\n /**\n * O(1) membership test through the bitmask (requires {@link enableBitmask}).\n * Throws if the index is disabled. Semantically identical to `has`, but a\n * single word-and-test instead of a sparse lookup.\n */\n hasMask<T>(entity: Entity, def: ComponentType<T>): boolean {\n if (!this.bitmask) throw new Error(\"hasMask requires enableBitmask()\");\n return this.bitmask.has(entity as number, def.id);\n }\n\n /**\n * O(words) \"has ALL of these components\" test through the bitmask (requires\n * {@link enableBitmask}). `defs` is hashed into a reusable query signature on\n * first use and cached by the def-id list. Throws if disabled.\n */\n hasAllMask(entity: Entity, defs: readonly ComponentType<unknown>[]): boolean {\n if (!this.bitmask) throw new Error(\"hasAllMask requires enableBitmask()\");\n let key = \"\";\n const ids: number[] = [];\n for (let i = 0; i < defs.length; i++) {\n const id = defs[i].id;\n ids.push(id);\n key += i === 0 ? id : `,${id}`;\n }\n let sig = this.maskSigs.get(key);\n if (!sig) {\n sig = this.bitmask.signature(ids);\n this.maskSigs.set(key, sig);\n }\n return this.bitmask.hasAll(entity as number, sig);\n }\n /**\n * Compile an INCREMENTAL query. Accepts the same spec as {@link select}: bare\n * defs (required `with`), `without(...)` / `maybe(...)` terms, and `any(...)`\n * groups. Unlike `compileQuery`/`select`, its match set is MAINTAINED as\n * components are added/removed (and on despawn) rather than rebuilt on the next\n * access, eliminating the per-frame O(n) rebuild a system pays when it mutates\n * and then queries the same components every frame. Returns an\n * {@link IncrementalQuery} handle (`each` / `results` / `count` / `view`).\n *\n * Deliberately opt-in, for hot mutate-then-query systems:\n * - its iteration ORDER is the incremental \"append-on-match /\n * swap-delete-on-unmatch\" order, which is deterministic but different from\n * `query`/`compileQuery`/`select`;\n * - it allocates a per-query sparse index sized to `maxEntities` and adds a\n * reconcile to each membership-component add/remove (so it earns its keep\n * on a hot query, not on every query);\n * - it tracks only World-API mutations; a `getStoreRaw` write bypasses it,\n * like the bitmask.\n * Components present before this call are captured by a one-time initial scan.\n */\n compileIncremental(...args: QueryArg[]): IncrementalQuery {\n const { withIds, withoutIds, maybeIds, anyGroups, yieldPlan } =\n parseQueryArgs(args);\n const q = new IncrementalQuery(\n {\n isAlive: (e) => this.alive.has(e),\n storeIfPresent: (id) => this.stores[id],\n },\n this.maxEntities,\n withIds,\n withoutIds,\n maybeIds,\n anyGroups,\n yieldPlan,\n );\n q.rebuildFromStores();\n this.incrementalQueries.push(q);\n // Register only under membership components (with ∪ without ∪ any); a `maybe`\n // change never alters membership, so it must not trigger a reconcile.\n for (let i = 0; i < q.membershipDeps.length; i++) {\n const id = q.membershipDeps[i];\n let list = this.incrementalByComponent[id];\n if (list === undefined) {\n list = [];\n this.incrementalByComponent[id] = list;\n }\n list.push(q);\n }\n this.hasIncremental = true;\n return q;\n }\n\n private reconcileIncremental(componentId: number, entity: number): void {\n const qs = this.incrementalByComponent[componentId];\n if (qs === undefined) return;\n for (let i = 0; i < qs.length; i++) qs[i].reconcile(entity);\n }\n query<A>(a: ComponentType<A>): readonly QueryResult<[A]>[];\n query<A, B>(\n a: ComponentType<A>,\n b: ComponentType<B>,\n ): readonly QueryResult<[A, B]>[];\n query<A, B, C>(\n a: ComponentType<A>,\n b: ComponentType<B>,\n c: ComponentType<C>,\n ): readonly QueryResult<[A, B, C]>[];\n query<A, B, C, D>(\n a: ComponentType<A>,\n b: ComponentType<B>,\n c: ComponentType<C>,\n d: ComponentType<D>,\n ): readonly QueryResult<[A, B, C, D]>[];\n // 5+ components: the runtime is already variadic; this overload lifts the\n // type-level 4-cap (per-slot inference stops at 4, falling back to unknown[]).\n // `AnyComponentType` (not `unknown`) so specific component types flow in\n // without a cast; same variance reason as QueryArg (see types.ts).\n query(...defs: AnyComponentType[]): readonly QueryResult<unknown[]>[];\n query(...defs: ComponentType<unknown>[]): readonly QueryResult<unknown[]>[] {\n return this.queryEngine.query(defs);\n }\n\n queryFirst<A>(a: ComponentType<A>): QueryResult<[A]> | null {\n const results = this.query(a);\n return results.length > 0 ? results[0] : null;\n }\n\n each<A>(a: ComponentType<A>, fn: (e: Entity, a: A) => void): void;\n each<A, B>(\n a: ComponentType<A>,\n b: ComponentType<B>,\n fn: (e: Entity, a: A, b: B) => void,\n ): void;\n each<A, B, C>(\n a: ComponentType<A>,\n b: ComponentType<B>,\n c: ComponentType<C>,\n fn: (e: Entity, a: A, b: B, c: C) => void,\n ): void;\n each<A, B, C, D>(\n a: ComponentType<A>,\n b: ComponentType<B>,\n c: ComponentType<C>,\n d: ComponentType<D>,\n fn: (e: Entity, a: A, b: B, c: C, d: D) => void,\n ): void;\n // 5+ components: lifts the type-level 4-cap. The trailing arg is the callback;\n // the leading args are component defs (no per-slot inference beyond 4).\n // `AnyComponentType` for the variance reason documented on QueryArg.\n each(\n ...args: [\n ...defs: AnyComponentType[],\n fn: (e: Entity, ...c: never[]) => void,\n ]\n ): void;\n each(...args: unknown[]): void {\n const fn = args[args.length - 1] as (e: Entity, ...c: unknown[]) => void;\n const defs = args.slice(0, -1) as ComponentType<unknown>[];\n this.queryEngine.each(defs, fn);\n }\n\n /**\n * Resolve a query once and return a reusable handle. Prefer this over\n * `query`/`each` in per-frame hot loops: the handle skips the key derivation\n * and argument unpacking those entry points pay on every call. The handle\n * stays valid across structural changes and across `clear()`.\n */\n compileQuery<A>(a: ComponentType<A>): CompiledQuery<[A]>;\n compileQuery<A, B>(\n a: ComponentType<A>,\n b: ComponentType<B>,\n ): CompiledQuery<[A, B]>;\n compileQuery<A, B, C>(\n a: ComponentType<A>,\n b: ComponentType<B>,\n c: ComponentType<C>,\n ): CompiledQuery<[A, B, C]>;\n compileQuery<A, B, C, D>(\n a: ComponentType<A>,\n b: ComponentType<B>,\n c: ComponentType<C>,\n d: ComponentType<D>,\n ): CompiledQuery<[A, B, C, D]>;\n // 5+ components: lifts the type-level 4-cap (tuple falls back to unknown[]).\n // `AnyComponentType` for the variance reason documented on QueryArg.\n compileQuery(...defs: AnyComponentType[]): CompiledQuery<unknown[]>;\n compileQuery(...defs: ComponentType<unknown>[]): CompiledQuery<unknown[]> {\n return this.queryEngine.compile(defs);\n }\n\n /**\n * The filter-aware query entry point. Returns a reusable {@link CompiledQuery}\n * handle, like {@link compileQuery}, but accepts `without(...)` / `maybe(...)`\n * terms and `any(...)` groups alongside bare required defs, and lifts the\n * type-level 4-cap. A spec with no required (bare/`with`) component throws.\n *\n * A pure-`with` `select(...)` delegates to the same cache as\n * `query`/`compileQuery`, so the result reference is identical.\n */\n select<A>(a: ComponentType<A>): CompiledQuery<[A]>;\n select<A, B>(a: ComponentType<A>, b: ComponentType<B>): CompiledQuery<[A, B]>;\n select<A, B, C>(\n a: ComponentType<A>,\n b: ComponentType<B>,\n c: ComponentType<C>,\n ): CompiledQuery<[A, B, C]>;\n select<A, B, C, D>(\n a: ComponentType<A>,\n b: ComponentType<B>,\n c: ComponentType<C>,\n d: ComponentType<D>,\n ): CompiledQuery<[A, B, C, D]>;\n select(...args: QueryArg[]): CompiledQuery<unknown[]>;\n select(...args: QueryArg[]): CompiledQuery<unknown[]> {\n return this.queryEngine.compileSpec(args);\n }\n\n /** O(1) count of entities with a component. */\n count<T>(def: ComponentType<T>): number {\n return this.stores[def.id]?.size() ?? 0;\n }\n\n /** Drop all cached queries (memory reclaim). Retained handles keep working but rebuild independently. */\n clearQueryCache(): void {\n this.queryEngine.dropCaches();\n this.maskSigs.clear();\n }\n\n /**\n * Direct dense-store access for the rare hand-tuned loop. A raw `set`/`remove`\n * through it bypasses the bitmask and incremental-query indexes (maintained only\n * by the World mutators), so `hasMask` and incremental queries can drift for an\n * entity mutated this way. The version-gated query cache and change-tracking\n * (which live in the store) stay correct.\n */\n getStoreRaw<T>(def: ComponentType<T>): ComponentStore<T> {\n return this.store(def);\n }\n /**\n * Enable object pooling for a component's store. On despawn/remove the object\n * is reset and parked; the next addComponent reuses it. Only factory\n * components ({@link PooledComponentType}) can be pooled; the `reset` hook is\n * guaranteed by the type.\n */\n enablePooling<T>(def: PooledComponentType<T>): void {\n this.store(def).enablePooling(def.reset);\n }\n /**\n * Apply a {@link CommandBuffer}'s queued add/remove/addComponent/despawn ops\n * against this world, in record order, then clear the buffer. Delegates to the\n * same `add`/`remove`/`addComponent`/`despawn` methods, so version bumps,\n * pooling, and deferred-despawn timing are identical to immediate calls. Does\n * NOT call flush(): a queued despawn is applied as a deferred despawn (visible\n * on the next flush()), preserving despawn timing exactly.\n */\n applyCommands(buffer: CommandBuffer): void {\n buffer.flushInto(this);\n }\n /**\n * Opt a component type into added/removed/changed tracking. Idempotent.\n * A type never passed here records nothing. Tracking does NOT retroactively\n * record existing members, only post-enable transitions.\n */\n trackChanges<T>(def: ComponentType<T>): void {\n const s = this.store(def);\n if (!s.isTracking()) {\n s.enableTracking();\n this.trackedStores.push(s as ComponentStore<unknown>);\n }\n }\n\n /** Entities that gained `def` since the last clearChanges(), in dense order. */\n added<T>(def: ComponentType<T>): readonly Entity[] {\n return (\n (this.stores[def.id]?.iterAdded() as readonly Entity[] | undefined) ??\n _emptyEntities\n );\n }\n\n /** Entities that lost `def` since the last clearChanges(), in dense order. */\n removed<T>(def: ComponentType<T>): readonly Entity[] {\n return (\n (this.stores[def.id]?.iterRemoved() as readonly Entity[] | undefined) ??\n _emptyEntities\n );\n }\n\n /** Entities marked changed since the last clearChanges(), in dense order. */\n changed<T>(def: ComponentType<T>): readonly Entity[] {\n return (\n (this.stores[def.id]?.iterChanged() as readonly Entity[] | undefined) ??\n _emptyEntities\n );\n }\n\n /**\n * Record an explicit mutation of an existing component. No-op when untracked\n * or absent. Coarse: no dedup; calling it twice on the same entity records\n * two entries. Consumers needing a unique set must dedup themselves.\n */\n markChanged<T>(entity: Entity, def: ComponentType<T>): void {\n this.stores[def.id]?.markChanged(entity);\n }\n\n /**\n * Get a component and, if its store is tracked & the entity has it, record it\n * changed. Returns the live stored object (mutate it in place) or undefined if\n * absent. The ergonomic read-then-mark path for tracked mutable components.\n */\n getMut<T>(entity: Entity, def: ComponentType<T>): T | undefined {\n const s = this.stores[def.id] as ComponentStore<T> | undefined;\n if (s === undefined) return undefined;\n const c = s.get(entity);\n if (c !== undefined) s.markChanged(entity);\n return c;\n }\n\n /**\n * Drain all tracked stores' added/removed/changed lists. Call once per frame,\n * like events.clearAll(). Callbacks do NOT auto-drain, so this stays the\n * primary lifecycle hook; skipping it lets the delta lists grow unbounded.\n */\n clearChanges(): void {\n for (const s of this.trackedStores) s.drainChanges();\n }\n\n /**\n * Fire `fn(e)` for each entity that gained `def`, at one deterministic point\n * inside flush() (after structural changes settle). Auto-enables tracking for\n * `def`. Does NOT auto-drain; call clearChanges() each frame.\n */\n onAdded<T>(def: ComponentType<T>, fn: (entity: Entity) => void): void {\n this.trackChanges(def);\n if (this.addedCallbacks === null) this.addedCallbacks = new Map();\n const list = this.addedCallbacks.get(def.id);\n if (list) list.push(fn);\n else this.addedCallbacks.set(def.id, [fn]);\n }\n\n /**\n * Fire `fn(e)` for each entity that lost `def`, at one deterministic point\n * inside flush() (after structural changes settle). Auto-enables tracking for\n * `def`. Does NOT auto-drain; call clearChanges() each frame.\n */\n onRemoved<T>(def: ComponentType<T>, fn: (entity: Entity) => void): void {\n this.trackChanges(def);\n if (this.removedCallbacks === null) this.removedCallbacks = new Map();\n const list = this.removedCallbacks.get(def.id);\n if (list) list.push(fn);\n else this.removedCallbacks.set(def.id, [fn]);\n }\n\n // Iterate registered callbacks (Map insertion = registration order) and, per\n // component, its delta list in dense store order, fully reproducible.\n private fireCallbacks(\n map: Map<number, ((e: Entity) => void)[]>,\n isAdded: boolean,\n ): void {\n for (const [id, fns] of map) {\n const store = this.stores[id];\n if (store === undefined) continue;\n const list = isAdded ? store.iterAdded() : store.iterRemoved();\n // Fire only entries appended since the last flush this frame, then advance\n // the cursor; the delta list itself drains once per frame (clearChanges),\n // but flush() may run several times before then, so the cursor is what\n // keeps each transition firing exactly once.\n const from = isAdded ? store.addedFired : store.removedFired;\n for (let i = from; i < list.length; i++) {\n const e = list[i] as Entity;\n for (let j = 0; j < fns.length; j++) fns[j](e);\n }\n if (isAdded) store.setAddedFired(list.length);\n else store.setRemovedFired(list.length);\n }\n }\n /** Set a resource value, by typed token (canonical) or string key. */\n setResource<T>(type: ResourceType<T>, value: T): void;\n setResource<T>(key: string, value: T): void;\n setResource<T>(typeOrKey: ResourceType<T> | string, value: T): void {\n if (typeof typeOrKey === \"string\") {\n this.stringResources.set(typeOrKey, value);\n } else {\n this.resources.set(typeOrKey.id, value);\n }\n }\n\n /**\n * Get a resource value. By token it throws if unset; by string key it returns\n * undefined if unset.\n */\n getResource<T>(type: ResourceType<T>): T;\n getResource<T>(key: string): T | undefined;\n getResource<T>(typeOrKey: ResourceType<T> | string): T | undefined {\n if (typeof typeOrKey === \"string\") {\n return this.stringResources.get(typeOrKey) as T | undefined;\n }\n const val = this.resources.get(typeOrKey.id);\n if (val === undefined) {\n throw new Error(`Resource \"${typeOrKey.name}\" not set`);\n }\n return val as T;\n }\n\n /** Get a resource value by token, or undefined if not set. */\n tryGetResource<T>(type: ResourceType<T>): T | undefined {\n return this.resources.get(type.id) as T | undefined;\n }\n\n /** Remove a resource, by typed token or string key. The inverse of setResource; no-op if unset. */\n unsetResource<T>(type: ResourceType<T>): void;\n unsetResource(key: string): void;\n unsetResource<T>(typeOrKey: ResourceType<T> | string): void {\n if (typeof typeOrKey === \"string\") {\n this.stringResources.delete(typeOrKey);\n } else {\n this.resources.delete(typeOrKey.id);\n }\n }\n /**\n * Get (lazily initializing) this token's local scratch state. The value is\n * created via the token's `init` on first access for this World and then\n * returned by reference on every subsequent call, so mutations persist across\n * frames. Local state is private to whoever holds the token (typically one\n * system) and is independent of resources, components, and events.\n */\n local<T>(type: LocalType<T>): T {\n let v = this.locals.get(type.id);\n if (v === undefined && !this.locals.has(type.id)) {\n v = type.init();\n this.locals.set(type.id, v);\n }\n return v as T;\n }\n\n /**\n * Whether this local has been initialized in this World yet (i.e. `local()`\n * has been called for the token at least once since construction/clear).\n */\n hasLocal<T>(type: LocalType<T>): boolean {\n return this.locals.has(type.id);\n }\n\n /**\n * Reset a single local back to \"uninitialized\": the next `local()` call\n * rebuilds it from `init`. No-op if it was never initialized.\n */\n resetLocal<T>(type: LocalType<T>): void {\n this.locals.delete(type.id);\n }\n /** Despawn all entities and clear all stores, resources, and events. */\n clear(): void {\n this.pendingDespawns.length = 0;\n // Bump live ids' generations before dropping them so pre-clear handles/refs\n // can't resolve to a reused id once nextId is reset below.\n for (const id of this.alive) {\n this.generations[id as number] =\n (this.generations[id as number] + 1) >>> 0;\n }\n this.alive.clear();\n for (const store of this.activeStores) {\n store.clear();\n }\n // The bitmask index survives clear() (opt-in persists, like pooling and\n // tracking), but every bit must drop with the stores. A fresh Bitmask is the\n // simplest correct reset; cheap, since clear() is a world reset, not a\n // per-frame path. Cached signatures stay valid (bit positions are static).\n if (this.bitmask) this.bitmask = new Bitmask(this.maxEntities);\n this.resources.clear();\n this.stringResources.clear();\n // Per-system locals are DATA, not configuration: a cleared World forgets all\n // locals, so the next local() rebuilds from init. Touches only the new map,\n // empty for any consumer that never called local().\n this.locals.clear();\n this.events.clearAll();\n this.queryEngine.clear();\n // Incremental queries survive clear() (registration persists, like compiled\n // queries) but their match sets must empty with the stores; the add hooks\n // repopulate as entities are re-spawned. No-op when none are registered.\n for (let i = 0; i < this.incrementalQueries.length; i++) {\n this.incrementalQueries[i].clear();\n }\n // Change tracking: each ComponentStore.clear() already reset its own delta\n // lists and kept its `tracked` flag (opt-in survives clear, like pooling),\n // so trackedStores stays valid and intact. Drop only the callback maps so a\n // reused World does not keep stale onAdded/onRemoved closures.\n this.addedCallbacks = null;\n this.removedCallbacks = null;\n // Reissue ids from 1; generations are monotonic per index and not reset.\n this.nextId = 1;\n this.recycled.length = 0;\n // Reverse index: clear() resets DATA, not CONFIGURATION; drop every tracked\n // edge but keep backrefsEnabled, matching how clear() leaves pooling/tracking\n // opt-ins intact. No-op when backrefs were never enabled (map is null).\n if (this.backrefEdges !== null) this.backrefEdges.clear();\n if (this.holderToTargets !== null) this.holderToTargets.clear();\n }\n // Shared (index, generation) packing for both handles and refs: index in the\n // low indexBits, generation above. handleOf/ref/resolve/deref/unref all route\n // through these so the two encodings never fork.\n private pack(index: number, gen: number): number {\n return gen * (this.indexMask + 1) + index;\n }\n private unpackIndex(value: number): number {\n return value & this.indexMask;\n }\n private unpackGen(value: number): number {\n return Math.floor(value / (this.indexMask + 1));\n }\n\n /** Stamp the entity's current generation into a stable, storable handle. */\n handleOf(entity: Entity): EntityHandle {\n const index = entity as number;\n return this.pack(index, this.generations[index]) as EntityHandle;\n }\n\n /**\n * Resolve a handle to its entity, or null if the entity is no longer alive\n * with that generation (it was despawned, or despawned-and-recycled). The\n * returned number is the bare {@link Entity} index, usable with every existing\n * World/store API.\n */\n resolve(handle: EntityHandle): Entity | null {\n const h = handle as number;\n const index = this.unpackIndex(h);\n const gen = this.unpackGen(h);\n if (this.generations[index] !== gen) return null;\n if (!this.alive.has(index as Entity)) return null;\n return index as Entity;\n }\n\n /** Whether `resolve(handle)` would return a non-null entity. */\n isHandleValid(handle: EntityHandle): boolean {\n return this.resolve(handle) !== null;\n }\n // A ref is the SAME (index, generation) packing as a handle (see handleOf),\n // so the two never fork. Taking a ref is a pure read: it never bumps version\n // and never throws; a ref to a dead/never-spawned entity simply won't resolve.\n\n /**\n * Create a storable reference to `entity`, stamped with its current\n * generation. If backrefs are enabled and `holder` is supplied, registers a\n * reverse edge so `backrefs(entity)` will report `holder`. Pass `holder`\n * (the entity that stores the ref) whenever you store the ref in a component,\n * so the backref edge is tracked; enabling backrefs does not retroactively\n * index refs taken without a holder.\n */\n ref(entity: Entity): EntityRef;\n ref(entity: Entity, holder: Entity): EntityRef;\n ref(entity: Entity, holder?: Entity): EntityRef {\n const index = entity as number;\n const r = this.pack(index, this.generations[index]) as EntityRef;\n if (\n holder !== undefined &&\n this.backrefsEnabled &&\n this.backrefEdges !== null\n ) {\n // Register the (holder -> target) edge under the TARGET's index. Dedupe\n // keeps backrefs() a set; includes() is O(k) but k is tiny for the\n // surgical parent/child and projectile->owner fan-in this serves.\n let holders = this.backrefEdges.get(index);\n if (holders === undefined) {\n holders = [];\n this.backrefEdges.set(index, holders);\n }\n if (!holders.includes(holder)) holders.push(holder);\n // Mirror the edge under the holder so flush() can sweep it when the holder\n // despawns (see flush()).\n if (this.holderToTargets !== null) {\n let targets = this.holderToTargets.get(holder as number);\n if (targets === undefined) {\n targets = new Set();\n this.holderToTargets.set(holder as number, targets);\n }\n targets.add(index);\n }\n }\n return r;\n }\n\n /**\n * Resolve a ref to the live entity, or `null` if the target was despawned\n * (generation mismatch) or the ref is {@link NULL_REF}. Pure read: no\n * allocation, no version bump, no structural change. A recycled-and-respawned\n * index is alive but at a bumped generation, so the generation check catches\n * the stale-alias case (the whole point of a ref over a bare entity id).\n */\n deref(ref: EntityRef): Entity | null {\n if (ref === NULL_REF) return null;\n const r = ref as number;\n const index = this.unpackIndex(r);\n const gen = this.unpackGen(r);\n if (this.generations[index] !== gen) return null;\n if (!this.alive.has(index as Entity)) return null;\n return index as Entity;\n }\n\n /** Whether `ref` still points at a live entity. `deref(ref) !== null`. */\n isRefValid(ref: EntityRef): boolean {\n return this.deref(ref) !== null;\n }\n /**\n * Enable the reverse index. Idempotent. After this, every `ref(target,\n * holder)` records a (holder -> target) edge; `backrefs(target)` lists the\n * holders, and flush() sweeps edges whose target was despawned. Off by\n * default; when off, `ref()` does no edge bookkeeping and `backrefs()` returns\n * the shared empty array. Enabling it does NOT retroactively index refs taken\n * before the call.\n */\n enableBackrefs(): void {\n if (this.backrefsEnabled) return;\n this.backrefsEnabled = true;\n this.backrefEdges = new Map();\n this.holderToTargets = new Map();\n }\n\n /** Whether the reverse index is enabled. */\n hasBackrefs(): boolean {\n return this.backrefsEnabled;\n }\n\n /**\n * Entities that hold a (tracked) ref pointing at `target`, in deterministic\n * insertion order, de-duplicated, filtered to those still alive. Returns a\n * shared READ-ONLY empty array when backrefs are disabled or none point at\n * `target`; do not retain it across a structural change (flush() may sweep\n * the underlying list). Never throws.\n *\n * Contract: a holder is auto-swept only when the target dies. A holder is not\n * auto-removed when the holder itself despawns, so its edge can linger; this\n * method filters out despawned holders so they are never reported. A holder\n * index that has been recycled into a different live entity cannot be\n * distinguished and may still appear, so callers needing certainty should\n * `unref()` in the holder's own teardown or re-validate a stored EntityRef.\n */\n backrefs(target: Entity): readonly Entity[] {\n if (!this.backrefsEnabled || this.backrefEdges === null)\n return EMPTY_BACKREFS;\n const holders = this.backrefEdges.get(target as number);\n if (holders === undefined || holders.length === 0) return EMPTY_BACKREFS;\n // Common case: every holder is alive; return the stored array (no alloc).\n let allAlive = true;\n for (let i = 0; i < holders.length; i++) {\n if (!this.alive.has(holders[i])) {\n allAlive = false;\n break;\n }\n }\n if (allAlive) return holders;\n const live: Entity[] = [];\n for (let i = 0; i < holders.length; i++) {\n if (this.alive.has(holders[i])) live.push(holders[i]);\n }\n return live.length === 0 ? EMPTY_BACKREFS : live;\n }\n\n /**\n * Drop a previously-registered reverse edge (e.g. when a holder overwrites or\n * clears the ref field before the target dies). No-op if backrefs are off or\n * the edge is unknown. Order-preserving (indexOf + splice, not swap-remove) so\n * the remaining holder order stays a pure function of insertion/removal order.\n * Keeps the reverse index from leaking stale holders that outlive the ref but\n * not the target.\n */\n unref(ref: EntityRef, holder: Entity): void {\n if (!this.backrefsEnabled || this.backrefEdges === null) return;\n const index = this.unpackIndex(ref as number);\n const holders = this.backrefEdges.get(index);\n if (holders === undefined) return;\n const at = holders.indexOf(holder);\n if (at !== -1) {\n holders.splice(at, 1);\n if (holders.length === 0) this.backrefEdges.delete(index);\n }\n const targets = this.holderToTargets?.get(holder as number);\n if (targets !== undefined) {\n targets.delete(index);\n if (targets.size === 0) this.holderToTargets?.delete(holder as number);\n }\n }\n}\n\n// Shared read-only empty backrefs result: when the reverse index is disabled or\n// no holder points at a target, backrefs() hands back this single frozen array,\n// so the disabled path allocates nothing and returns a stable reference.\nconst EMPTY_BACKREFS: readonly Entity[] = Object.freeze([]);\n\n// Shared empty result for added/removed/changed reads of an untracked or\n// never-created component type: never allocates, never bumps version.\nconst _emptyEntities: readonly Entity[] = [];\n"],"mappings":"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"}
|