export type ScalarToken = 'bool' | 'i8' | 'u8' | 'u8c' | 'i16' | 'u16' | 'i32' | 'u32' | 'f32' | 'f64' | 'eid'; export interface VecToken { readonly kind: 'vec'; readonly elem: E; readonly len: N; } export interface StaticStringToken { readonly kind: 'staticString'; readonly choices: C; } export interface ObjectToken { readonly kind: 'object'; readonly __t?: T; } export type RichToken = 'string'; export interface FieldSpec { readonly __fieldSpec: true; readonly token: F; readonly default: unknown; /** false ⇒ the field is excluded from snapshots/deltas (re-defaults on load). Default true. */ readonly persist?: boolean | undefined; } export type BaseFieldToken = ScalarToken | RichToken | VecToken | StaticStringToken | ObjectToken; export type FieldToken = BaseFieldToken | FieldSpec; /** Unwrap a {@link FieldSpec} to its inner token; a bare token passes through. */ export type TokenOf = F extends FieldSpec ? T : F; export declare const vec: (elem: E, len: N) => VecToken; export declare const vec2: (elem?: E) => VecToken; export declare const vec3: (elem?: E) => VecToken; export declare const vec4: (elem?: E) => VecToken; export declare const staticString: (...choices: C) => StaticStringToken; export declare const object: () => ObjectToken; /** The shape a user-declared default takes for token `F`. Vec defaults are PLAIN ARRAYS — one * value per lane — not the VecView accessor shape reads/writes use: a default is an input value, * and the descriptor runtime reads it by lane index. */ export type FieldDefault = F extends VecToken ? readonly ScalarValue[] : FieldValue; export declare const field: (token: F, opts: { default?: FieldDefault; persist?: boolean; }) => FieldSpec; declare const __brand: unique symbol; type Brand = T & { readonly [__brand]: B; }; export type EntityHandle = Brand; export type ComponentId = Brand; export type RelationId = Brand; export type SystemId = Brand; export type ArchetypeId = Brand; export type WorldId = Brand; export type EntityIndex = Brand; export type Tick = Brand; export type ScalarValue = T extends 'bool' ? boolean : T extends 'eid' ? EntityHandle : number; export interface VecView { readonly length: N; [index: number]: ScalarValue; x: ScalarValue; y: N extends 1 ? never : ScalarValue; z: N extends 1 | 2 ? never : ScalarValue; w: N extends 1 | 2 | 3 ? never : ScalarValue; } export interface ReadonlyVecView { readonly length: N; readonly [index: number]: ScalarValue; readonly x: ScalarValue; readonly y: N extends 1 ? never : ScalarValue; readonly z: N extends 1 | 2 ? never : ScalarValue; readonly w: N extends 1 | 2 | 3 ? never : ScalarValue; } export type FieldValue = F extends FieldSpec ? FieldValue : F extends 'string' ? string : F extends ScalarToken ? ScalarValue : F extends VecToken ? VecView : F extends StaticStringToken ? C[number] : F extends ObjectToken ? T : never; export type TypedArrayCtor = Int8ArrayConstructor | Uint8ArrayConstructor | Uint8ClampedArrayConstructor | Int16ArrayConstructor | Uint16ArrayConstructor | Int32ArrayConstructor | Uint32ArrayConstructor | Float32ArrayConstructor | Float64ArrayConstructor; export interface FieldDescriptor { readonly name: string; readonly token: FieldToken; /** null iff object-token (not column-backed). */ readonly ctor: TypedArrayCtor | null; readonly bytesPerElem: number; /** Slots per row: 1 scalar, N vec, 1 staticString index, 0 object. */ readonly stride: number; /** false for object-token AND 'string'; gates worker use. */ readonly shareable: boolean; /** * The sidecar kind for a non-column rich field; undefined for column-backed fields. * `ctor === null ⟺ rich !== undefined ⟺ shareable === false`. */ readonly rich?: 'string' | 'object'; readonly encode: (v: unknown) => number; readonly decode: (slot: number) => unknown; /** staticString only. */ readonly choices?: readonly string[]; readonly default: unknown; readonly needsExplicitInit: boolean; /** * false ⇒ the field is excluded from copy serialization (snapshot/delta value sections, the * structural stream's values-on-add, and relation-payload encodes); on load it re-defaults. * Reactivity (write log, changeVersion stamps) is unaffected — non-persisted writes still stamp. */ readonly persist: boolean; } export type StorageStrategy = 'packed' | 'sparse'; export interface ComponentOptions { readonly storage?: StorageStrategy; /** * false ⇒ every field of the component is excluded from snapshots/deltas (values re-default on * load). Membership (the signature bit) still persists. Type-inert, like `storage`. Default true. */ readonly persist?: boolean; } export type Schema = Readonly>; type FieldValueRW = F extends FieldSpec ? FieldValueRW : F extends VecToken ? RW extends 'r' ? ReadonlyVecView : VecView : F extends ObjectToken ? RW extends 'r' ? Readonly : T : FieldValue; export type ReadView = { readonly [K in keyof S]: FieldValueRW; }; export type WriteView = { -readonly [K in keyof S]: FieldValueRW; }; export interface ComponentDef { readonly schema: S; readonly fields: readonly FieldDescriptor[]; /** Assigned at world registration; UNREGISTERED (-1) until then. */ readonly id: ComponentId; readonly name: N; readonly options: Required; readonly __nominalBrand?: string; /** phantom carriers — never assigned a value; exist purely for inference. */ readonly __read?: ReadView; readonly __write?: WriteView; } export type SchemaOf = C extends ComponentDef ? S : never; export type ReadOf = ReadView>; export type WriteOf = WriteView>; export type SpawnTuple = ComponentDef> = readonly [ C, Partial>> ]; export type SpawnArg = ComponentDef | SpawnTuple; /** * Per-element constraint: when an arg is a `[def, values]` tuple, re-type its value slot as the partial * write view of THAT def's schema so each tuple's values are checked against its own component. */ export type SpawnArgFor = E extends readonly [infer C, unknown] ? C extends ComponentDef ? readonly [C, Partial>>] : E : E; export interface AccessorInstance { __idx: number; } export interface TypedArrayLike { readonly length: number; [index: number]: number; } export interface ColumnBinding { view: TypedArrayLike; readonly byteOffset: number; readonly element: string; } export type AccessorFactory = (columns: ReadonlyArray) => new () => WriteView & AccessorInstance & { __rebind(newBacking: SharedArrayBuffer | ArrayBuffer): void; }; export declare const NO_ENTITY: EntityHandle; export declare const NULL_ENTITY: EntityHandle; export declare const MAX_QUERY_ARITY = 8; export interface RelationDef

{ readonly id: RelationId; readonly name: string; readonly payload: P extends Schema ? P : null; readonly exclusive: boolean; readonly cascade: 'none' | 'deleteSubject' | 'removeRelation'; /** phantom payload carriers — never assigned a value; exist purely for inference. */ readonly __payloadRead?: P extends Schema ? ReadView

: never; readonly __payloadWrite?: P extends Schema ? WriteView

: never; } export interface RelationOptions { readonly exclusive?: boolean; readonly cascade?: 'none' | 'deleteSubject' | 'removeRelation'; } /** The wildcard target sentinel: `Pair(R, Wildcard)` matches every `R`-pair via the presence bit. */ export declare const Wildcard: unique symbol; export type WildcardToken = typeof Wildcard; export interface PairDef> { readonly relation: R; readonly target: EntityHandle | WildcardToken; /** Synthetic ComponentId minted at addPair; UNREGISTERED (-1) for a query-only pair. */ readonly id: ComponentId; /** A pair carries its relation's payload schema as its read/write views. */ readonly __read?: R extends RelationDef ? (P extends Schema ? ReadView

: Record) : Record; readonly __write?: R extends RelationDef ? (P extends Schema ? WriteView

: Record) : Record; } export interface ReadTerm { readonly __term: 'read'; readonly c: C; } export interface WriteTerm { readonly __term: 'write'; readonly c: C; } export interface HasTerm { readonly __term: 'has'; readonly c: C; } export interface WithoutTerm { readonly __term: 'without'; readonly c: C; } export interface OptionalTerm { readonly __term: 'optional'; readonly c: C; } export declare const read: (c: C) => ReadTerm; export declare const write: (c: C) => WriteTerm; export declare const has: (c: C) => HasTerm; export declare const without: (c: C) => WithoutTerm; export declare const optional: (c: C) => OptionalTerm; /** * Per-query options, passed like a term: `world.query(Health, { matchPrefabs: true })`. * In a prefab-enabled world (`createWorld({ prefabs: true })`) queries skip prefab template * entities by default; `matchPrefabs: true` matches templates AND instances. It contributes * nothing to the query element. No-op in a world without prefabs. */ export interface QueryOptionsTerm { readonly matchPrefabs: boolean; } export type QueryTerm = ReadTerm | WriteTerm | HasTerm | WithoutTerm | OptionalTerm | PairDef> | ComponentDef | QueryOptionsTerm; export type Has> = { readonly [K in CompKey]: ReadOf; }; export type HasWrite> = { [K in CompKey]: WriteOf; }; export type CompKey = C extends { name: infer N extends string; } ? N : never; type PairValue

>, RW extends 'r' | 'w'> = P extends PairDef ? R extends RelationDef ? Pay extends Schema ? RW extends 'r' ? ReadView : WriteView : Record : Record : Record; export type TermElement = T extends WriteTerm ? { [K in CompKey]: WriteOf; } : T extends ReadTerm ? { [K in CompKey]: ReadOf; } : T extends OptionalTerm ? { [K in CompKey]: ReadOf | undefined; } : T extends HasTerm ? Record : T extends WithoutTerm ? Record : T extends PairDef> ? T extends { relation: { name: infer N extends string; }; } ? { [K in N]: PairValue; } : Record : T extends ComponentDef ? { [K in CompKey]: ReadOf; } : Record; export type UnionToIntersection = (U extends unknown ? (k: U) => void : never) extends (k: infer I) => void ? I : never; export type QueryElement = readonly QueryTerm[] extends Terms ? LooseQueryElement : UnionToIntersection<{ [I in keyof Terms]: TermElement; }[number]>; export type LooseQueryElement = Readonly>>> & { handle: EntityHandle; }; type ScalarColumnView = T extends 'f32' ? Float32Array : T extends 'f64' ? Float64Array : T extends 'i8' ? Int8Array : T extends 'bool' | 'u8' ? Uint8Array : T extends 'u8c' ? Uint8ClampedArray : T extends 'i16' ? Int16Array : T extends 'u16' ? Uint16Array : T extends 'i32' | 'eid' ? Int32Array : T extends 'u32' ? Uint32Array : never; export type ColumnViewOf = TokenOf extends infer T ? T extends ScalarToken ? ScalarColumnView : T extends VecToken ? ScalarColumnView : T extends StaticStringToken ? Uint8Array | Uint16Array | Uint32Array : never : never; /** The column-backed field names of a schema ('string'/object fields carry no column). */ export type ColumnFieldName = { [K in keyof S & string]: TokenOf extends 'string' | ObjectToken ? never : K; }[keyof S & string]; /** One pinned-column spec: a `[ComponentDef, fieldName]` pair. */ export type ColumnSpec = readonly [ComponentDef, string]; /** * Per-element constraint (the SpawnArgFor pattern): re-type each spec's field slot as the * column-backed field names of THAT spec's component, so `[Position, 'nope']` is a compile error. */ export type ColumnSpecFor

= P extends readonly [infer C, string] ? C extends ComponentDef ? readonly [C, ColumnFieldName] : P : P; /** The factory's `views` tuple: each spec's field token resolved to its typed-array view type. */ export type ColumnViews = { [I in keyof Specs]: Specs[I] extends readonly [ComponentDef, infer F] ? F extends keyof S ? ColumnViewOf : never : never; }; /** The per-binding meta box: identity-stable across rebinds; `count` is the live row count. */ export interface BoundColumnsMeta { readonly count: number; /** * Slots-per-row for each spec, in spec order: 1 for a scalar field, N for a `vecN`. Read ONCE * outside the hot loop to index a vec view without hardcoding its arity — `const s = meta.strides[i]`, * then `view[r * s + axis]`. The same value the {@link QueryChunk} cursor exposes via `stride()`. */ readonly strides: readonly number[]; } export interface QueryChunk { /** Rows in this chunk (the archetype's dense row count). Iterate `0..count`. */ readonly count: number; /** Dense row→EntityHandle list (row `r`'s entity is `entities[r]`). */ readonly entities: Uint32Array; /** The live typed column view for `def.field`. Stride-1 scalars index by row directly. */ column(def: ComponentDef, field: string): ArrayLike & { [i: number]: number; }; /** Slots per row for `def.field` (1 scalar, N vec): row `r` starts at `r * stride`. */ stride(def: ComponentDef, field: string): number; } export type DerivedQuery = Terms['length'] extends 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 ? Query : LooseQuery; export interface Query { readonly terms: Terms; /** Iterate every matching entity; `e` is the pooled element (do NOT store it across iterations). */ each(fn: (e: QueryElement & { handle: EntityHandle; }) => void): void; [Symbol.iterator](): Iterator & { handle: EntityHandle; }>; /** Opt-in SoA fast path: one reused {@link QueryChunk} per matched hot archetype, with * raw typed column views + a row span. Bypasses the per-row accessor AND the reactivity write log. */ eachChunk(fn: (chunk: QueryChunk) => void): void; /** Pinned columns: resolve each `[ComponentDef, field]` spec's column views ONCE per matched hot * archetype, invoke `factory(views, meta)` to mint a persistent runner (per-frame inputs via the runner's * `ctx` argument), and return a `run(ctx)` that re-checks the bindings and runs each archetype's runner. See the runtime doc on the * core LiveQuery for the full contract (self-contained factory, `ctx` deps, `meta.count`, codegen + CSP fallback). */ bindColumns(...args: [ ...specs: { [I in keyof Specs]: ColumnSpecFor; }, factory: (views: ColumnViews, meta: BoundColumnsMeta) => (ctx: Ctx) => void ]): (ctx: Ctx) => void; /** * Compile an ergonomic `.each` body into the codegen'd column loop `bindColumns` runs — without naming * columns or restating the math. It reads the callback's source, rewrites `e..` to direct * typed-array indexing, and lands near `eachChunk` (~1.5 ns/entity) instead of the per-row proxy * (~10 ns/entity). Unlike `bindColumns`, it PRESERVES reactivity: a written component feeds `.changed()` * and observers exactly as the accessor would (free when no consumer is registered). Pure speedup — the * analyzer is conservative and falls back to the unchanged proxy `.each` (identical result) for any body * it cannot prove safe (non-straight-line, non-numeric-scalar field, row-filtered query, blocked * `new Function`, etc.). Call ONCE and reuse the returned runner per frame. */ compile(body: (e: QueryElement & { handle: EntityHandle; }, ctx: Ctx) => void): (ctx: Ctx) => void; /** * Derive a narrower query: the cached query for [...this query's terms, ...terms] — pure sugar * over `world.query` with the merged term list, riding the same canonical-hash dedup (deriving * is reference-identical to writing the combined query directly). Flavors are per cached query, * NOT inherited from this one. Combined arity past MAX_QUERY_ARITY degrades to LooseQuery. */ derive(): this; derive(...terms: [N0]): DerivedQuery<[...Terms, N0]>; derive(...terms: [N0, N1]): DerivedQuery<[...Terms, N0, N1]>; derive(...terms: [N0, N1, N2]): DerivedQuery<[...Terms, N0, N1, N2]>; derive(...terms: [N0, N1, N2, N3]): DerivedQuery<[...Terms, N0, N1, N2, N3]>; derive(...terms: [N0, N1, N2, N3, N4]): DerivedQuery<[...Terms, N0, N1, N2, N3, N4]>; derive(...terms: [N0, N1, N2, N3, N4, N5]): DerivedQuery<[...Terms, N0, N1, N2, N3, N4, N5]>; derive(...terms: [N0, N1, N2, N3, N4, N5, N6]): DerivedQuery<[...Terms, N0, N1, N2, N3, N4, N5, N6]>; /** 8+ new terms: combined arity is necessarily past the cap → LooseQuery (the catch-all). */ derive(...terms: QueryTerm[]): LooseQuery; /** Flavor declarations (chainable). */ added(): this; removed(): this; changed(...components: ComponentDef[]): this; /** Flavor result iterators (entities entered/left/changed this frame). */ eachAdded(fn: (e: QueryElement & { handle: EntityHandle; }) => void): void; eachRemoved(fn: (index: number, handle: EntityHandle) => void): void; eachChanged(fn: (e: QueryElement & { handle: EntityHandle; }) => void): void; /** Count of currently-matching entities. O(1). */ readonly count: number; } export interface LooseQuery { readonly terms: readonly QueryTerm[]; each(fn: (e: EL & { handle: EntityHandle; }) => void): void; [Symbol.iterator](): Iterator; /** Opt-in SoA fast path: see {@link Query.eachChunk}. */ eachChunk(fn: (chunk: QueryChunk) => void): void; /** Pinned columns: see {@link Query.bindColumns}. */ bindColumns(...args: [ ...specs: { [I in keyof Specs]: ColumnSpecFor; }, factory: (views: ColumnViews, meta: BoundColumnsMeta) => (ctx: Ctx) => void ]): (ctx: Ctx) => void; /** Compile an `.each` body into the fast column loop: see {@link Query.compile}. */ compile(body: (e: EL & { handle: EntityHandle; }, ctx: Ctx) => void): (ctx: Ctx) => void; /** See {@link Query.derive}. Arity is already past the cap, so the result stays loose. */ derive(...terms: QueryTerm[]): LooseQuery; /** Flavor declarations (chainable). */ added(): this; removed(): this; changed(...components: ComponentDef[]): this; eachAdded(fn: (e: EL & { handle: EntityHandle; }) => void): void; eachRemoved(fn: (index: number, handle: EntityHandle) => void): void; eachChanged(fn: (e: EL & { handle: EntityHandle; }) => void): void; /** Count of currently-matching entities. O(1). */ readonly count: number; } export interface WorldQuery { (...terms: [T0]): Query<[T0]>; (...terms: [T0, T1]): Query<[T0, T1]>; (...terms: [T0, T1, T2]): Query<[T0, T1, T2]>; (...terms: [T0, T1, T2, T3]): Query<[T0, T1, T2, T3]>; (...terms: [T0, T1, T2, T3, T4]): Query<[T0, T1, T2, T3, T4]>; (...terms: [T0, T1, T2, T3, T4, T5]): Query<[T0, T1, T2, T3, T4, T5]>; (...terms: [T0, T1, T2, T3, T4, T5, T6]): Query<[T0, T1, T2, T3, T4, T5, T6]>; (...terms: [T0, T1, T2, T3, T4, T5, T6, T7]): Query<[T0, T1, T2, T3, T4, T5, T6, T7]>; /** 9+: degraded overload — returns a LooseQuery whose element is the typed LooseQueryElement and * whose `each` is generic-on-element for the explicit Has/HasWrite escape hatch. Compile * time stays bounded: the catch-all stops the variadic fold entirely. */ (...terms: QueryTerm[]): LooseQuery; } export {}; //# sourceMappingURL=index.d.ts.map