# WorldQuery

> Talos next · Since 0.6; changed in 0.7

Read access to every entity plus the physics and navigation queries.

Reached in a behaviour as `ctx.world`.

## Signature

```ts
export interface WorldQuery {
  /**
   * Entities matching the filter. No filter returns everything. Order: slot order unless `sort` says
   * otherwise (see {@link QueryFilter.sort}); it is deterministic but not id order. `near` and `radius`
   * are inclusive (see {@link QueryFilter.near}).
   */
  query(filter?: QueryFilter): EntityHandle[]
  /** Look an entity up by scene id. */
  find(id: string): EntityHandle | null
  /**
   * The centre line of the road entity `id` (an entity with a `road` component), or null when `id`
   * is not a road. See {@link RoadLine}.
   */
  road(id: string): RoadLine | null
  /** The instances of an entity with an `instancedMesh` component (by id or handle), or null when it has none. See {@link Instances}. */
  instances(entity: string | EntityHandle): Instances | null
  /** Number of live entities. */
  readonly count: number
  /**
   * First physics hit along a ray, or null: a miss is `null`, never `undefined`. A hit is
   * `{ entity, point, normal, distance, instance? }` (see {@link Hit}).
   *
   * - `from`: the ray's start, world space. `dir`: its direction; it need not be normalised (it is
   *   normalised before the cast, so `distance` and `max` are in metres whatever its length). A zero or
   *   non-finite `dir` hits nothing and answers `null`.
   * - `max`: the longest the ray reaches, metres. Default (absent, `null` or `undefined`): no limit.
   * - `opts`: {@link CastOptions}: `triggers`, `exclude`, `excludeTags`, `layers`.
   *
   * Trigger volumes count as hits unless `opts.triggers` is false — pass that for a camera boom, a line
   * of sight or an aim ray, which should see through a volume the player walks through. An exact tie
   * between two hits goes to the entity whose id comes first (docs/API.md, "Projectiles in a game that
   * must agree across machines").
   */
  raycast(from: Vec3, dir: Vec3, max?: number, opts?: CastOptions): Hit | null
  /**
   * One `raycast` per ray, for a system-style `updateAll`: `from` and `dir` hold 3 numbers per ray (a
   * `Float32Array` such as {@link positions} answers, or an array of numbers). One entry per ray: the
   * entity the ray hit first, or `null` for a miss (never `undefined`); use `raycast` where the point,
   * normal or distance matter. `opts` apply to every ray, and `opts.excludeEach` holds one entity (or
   * `null`) per ray that only that ray passes through, such as each shooter's own capsule.
   */
  raycastMany(from: Float32Array | number[], dir: Float32Array | number[], max?: number, opts?: CastOptions & { excludeEach?: (string | EntityHandle | null)[] }): (EntityHandle | null)[]
  /**
   * The positions of `entities` (handles or ids), 3 numbers each, `[x0, y0, z0, x1, …]`, in the order
   * given. An entity that is gone, or an unknown id, reads as three NaN rather than throwing.
   */
  positions(entities: (string | EntityHandle)[]): Float32Array
  /**
   * For each point in `from`, the index in `to` of the nearest point within `radius`, or -1; both hold
   * 3 numbers per point. The distance, the inclusive radius and the tie rule are `query`'s: f32
   * distance rounded after the square root, and equal distances to the lower index (`query`'s stable
   * sort keeps entity order). So with `to` in `query`'s order, the pick is what
   * `query({ near, sort: "distance" })` puts first, near-ties included, on every machine. A negative
   * radius finds nothing. A NaN point is never nearest, and a `from` point does not skip itself when
   * `to` holds it too.
   */
  nearestMany(from: Float32Array | number[], to: Float32Array | number[], radius: number): Int32Array
  /** Like `raycast` but sweeping a shape. */
  shapeCast(shape: CastShape, from: Vec3, dir: Vec3, max?: number, opts?: CastOptions): Hit | null
  /**
   * Every entity whose collider `shape` overlaps at `position`, turned by `rotation` (a quaternion
   * `[x, y, z, w]`, default none), sorted by entity: the same order on every run. A static question:
   * nothing is swept and nothing moves, so it answers about the colliders as the last physics step
   * left them. Touching counts. `opts` are a cast's: `triggers` (default true here, as for a cast),
   * `exclude`, `excludeTags`, `layers`. Throws a `TypeError` for a shape that is none of the three.
   */
  overlap(shape: CastShape, position: Vec3, rotation?: Quat, opts?: CastOptions): EntityHandle[]
  /**
   * Who `entity`'s sensor (an `attach`ed entity with a trigger collider) touches as of this tick's
   * query, sorted by entity; null when it has no (resolved) sensor. A sensor queries its collider
   * every tick at the bone's pose and delivers `overlap` events: `name` "overlap", `data`
   * `{ sensor, other, phase: "begin" | "end" }` (entity ids), by sensor; within a sensor its ends,
   * then its begins, each by other.
   */
  overlaps(entity: EntityHandle | string): EntityHandle[] | null
  /**
   * Switches `entity`'s sensor on or off (it starts on). Off, it queries nothing and ends every pair
   * it held, with `end` events on this tick's pass; with `activeWhile` it also needs that animation
   * window open. Returns false when the entity has no sensor.
   */
  setSensor(entity: EntityHandle | string, on: boolean): boolean
  /**
   * The dynamic body a pick ray lands on first, or null — what "the thing I am pointing at" means for a
   * grab. The first thing the ray meets decides: a wall in front of a crate hides it, and a static or
   * kinematic body, one over `maxMass` or one without `tag` answers null rather than letting the ray
   * carry on. Exclude the picker.
   *
   * ```ts
   * const eye = ctx.entity.worldPosition; eye[1] += 1.6
   * const hit = ctx.world.pick(eye, aim, 2.5, { exclude: ctx.entity, tag: "grabbable" })
   * ```
   */
  pick(from: Vec3, dir: Vec3, max?: number, opts?: PickOptions): Hit | null
  /**
   * Start carrying `target`'s dynamic body at `holder` (any entity: a character, a hand, a crane hook).
   * True when it is now held. False, having changed nothing, when the target is gone, has no body, is not
   * dynamic, is the holder, or is over `maxMass`. A NaN, infinite or non-positive option throws a `RangeError`.
   *
   * The body stays a physics body: each tick it is given the velocity that brings it to its hold point,
   * so it still collides with everything except its holder, stops against walls (it never passes through
   * one), and pushes other bodies aside. When it falls more than `breakDistance` behind and keeps falling
   * behind — the holder walked away from a crate wedged in a doorway — the hold breaks and the body drops;
   * `heldBy` reads null from that tick. However a hold ends — a break, a `release`, a despawn — the engine
   * raises a `"hold-broken"` bus event ({@link BusHoldBroken}) saying which and why. A character's
   * controller passes through what it is holding.
   *
   * Holding something already held replaces that hold: a hand-over, or a new `offset`, is one more call.
   * Held state is part of the physics checkpoint, so `GET /snapshot` → `POST /snapshot` restores a carry.
   */
  hold(holder: EntityHandle | string, target: EntityHandle | string, opts?: HoldOptions): boolean
  /** Let `target` go; `opts.velocity` throws it. False if it was not held. */
  release(target: EntityHandle | string, opts?: ReleaseOptions): boolean
  /** Who is holding `target`, or null. */
  heldBy(target: EntityHandle | string): EntityHandle | null
  /** What `holder` is holding, in entity order; empty when nothing. */
  holding(holder: EntityHandle | string): EntityHandle[]
  /**
   * Navmesh path as a polyline, or null when unreachable. Throws `nav-undeclared` in a scene that
   * declares no navigation (no `meta.nav`, no `navagent`): navigation is opt-in, and such a scene
   * has no navmesh. Add `"nav": {}` to the scene's meta.
   */
  path(from: Vec3, to: Vec3): Vec3[] | null
  /**
   * Put another copy of an entity the scene already has, or of a prefab, into the world, and get a
   * handle to it.
   *
   * `like` is the scene id of a live entity, and the new entity is a full copy of it: its name,
   * its tags, its parent, its scale and every one of its components, wired the way the scene's
   * own entities are — a collider becomes a physics body the solver knows, a mesh becomes
   * something the renderer draws, a script gets its own behavior instance with its own `state`,
   * all within the tick that asked for it.
   *
   * `prefab` instead of `like` spawns a copy of a project prefab file, which need not be placed in
   * any scene: its root and every entity under it, the root's id as below and each other entity's
   * `"<root id>/<prefab entity id>"`, parented as the prefab has them, with `overrides` applied as a
   * scene instance's are. The handle is the root's; {@link EntityHandle.despawn} on it removes the
   * whole copy. The project's prefabs are read and checked once, at load, so a spawn parses nothing.
   *
   * Either way, what is spawned is a shape the contract already validated: an entity of the scene,
   * or a prefab file.
   *
   * **Ids.** Give one and it must be free, or this throws. Leave it out and the engine derives
   * `"<like>#1"`, `"<like>#2"`, … from a counter kept per source id. Both are deterministic: two
   * runs of the same scene making the same calls in the same order get the same ids and the same
   * entity slots, which is what the lockstep critic checks.
   *
   * Throws rather than returning null, so a spawn that did not happen cannot be mistaken for one
   * that did. The error's `name` is `SpawnError` and its message starts with the code:
   * `spawn-no-source`, `spawn-two-sources`, `spawn-unknown-source`, `spawn-unknown-prefab`,
   * `spawn-prefab-cycle`, `spawn-bad-override`, `spawn-duplicate-id`.
   *
   * The copy's behaviour runs `init` on this tick, after every `update` has returned, and is then
   * handed each event emitted this tick after this call (so an `emit` straight after the spawn
   * reaches its `onEvent` and the listeners its `init` subscribed); its first `update` is next tick.
   *
   * A spawned entity is runtime state, not a scene change. The scene file is untouched,
   * `GET /snapshot` carries the entity and `POST /snapshot` puts it back — and
   * {@link SessionHandle.restart} rebuilds from the scene as loaded, so a restart removes every
   * spawned entity and brings back every authored one.
   *
   * ```ts
   * const cone = ctx.world.spawn({ like: "cone-prototype", position: [4, 0, -12] })
   * cone.set("material", { baseColor: "#ff6600" })
   *
   * const imp = ctx.world.spawn({ prefab: "prefabs/imp.prefab.json", position: [2, 0, 5],
   *   overrides: { "root/script:chase/props/speed": 5 } })   // imp#1, and imp#1/<child> for each child
   * ```
   */
  spawn(options: SpawnOptions): EntityHandle
}
```

Import: `import type { WorldQuery } from "@argus/api"`

## Members

| Member | Signature | Description |
|---|---|---|
| `query` | `query(filter?: QueryFilter): EntityHandle[]` | Entities matching the filter. No filter returns everything. Order: slot order unless `sort` says otherwise (see {@link QueryFilter.sort}); it is deterministic but not id order. `near` and `radius` are inclusive (see {@link QueryFilter.near}). |
| `find` | `find(id: string): EntityHandle \| null` | Look an entity up by scene id. |
| `road` | `road(id: string): RoadLine \| null` | The centre line of the road entity `id` (an entity with a `road` component), or null when `id` is not a road. See {@link RoadLine}. |
| `instances` | `instances(entity: string \| EntityHandle): Instances \| null` | The instances of an entity with an `instancedMesh` component (by id or handle), or null when it has none. See {@link Instances}. |
| `count` | `readonly count: number` | Number of live entities. |
| `raycast` | `raycast(from: Vec3, dir: Vec3, max?: number, opts?: CastOptions): Hit \| null` | First physics hit along a ray, or null: a miss is `null`, never `undefined`. A hit is `{ entity, point, normal, distance, instance? }` (see {@link Hit}). - `from`: the ray's start, world space. `dir`: its direction; it need not be normalised (it is   normalised before the cast, so `distance` and `max` are in metres whatever its length). A zero or   non-finite `dir` hits nothing and answers `null`. - `max`: the longest the ray reaches, metres. Default (absent, `null` or `undefined`): no limit. - `opts`: {@link CastOptions}: `triggers`, `exclude`, `excludeTags`, `layers`. Trigger volumes count as hits unless `opts.triggers` is false — pass that for a camera boom, a line of sight or an aim ray, which should see through a volume the player walks through. An exact tie between two hits goes to the entity whose id comes first (docs/API.md, "Projectiles in a game that must agree across machines"). |
| `raycastMany` | `raycastMany(from: Float32Array \| number[], dir: Float32Array \| number[], max?: number, opts?: CastOptions & { excludeEach?: (string \| EntityHandle \| null)[] }): (EntityHandle \| null)[]` | One `raycast` per ray, for a system-style `updateAll`: `from` and `dir` hold 3 numbers per ray (a `Float32Array` such as {@link positions} answers, or an array of numbers). One entry per ray: the entity the ray hit first, or `null` for a miss (never `undefined`); use `raycast` where the point, normal or distance matter. `opts` apply to every ray, and `opts.excludeEach` holds one entity (or `null`) per ray that only that ray passes through, such as each shooter's own capsule. |
| `positions` | `positions(entities: (string \| EntityHandle)[]): Float32Array` | The positions of `entities` (handles or ids), 3 numbers each, `[x0, y0, z0, x1, …]`, in the order given. An entity that is gone, or an unknown id, reads as three NaN rather than throwing. |
| `nearestMany` | `nearestMany(from: Float32Array \| number[], to: Float32Array \| number[], radius: number): Int32Array` | For each point in `from`, the index in `to` of the nearest point within `radius`, or -1; both hold 3 numbers per point. The distance, the inclusive radius and the tie rule are `query`'s: f32 distance rounded after the square root, and equal distances to the lower index (`query`'s stable sort keeps entity order). So with `to` in `query`'s order, the pick is what `query({ near, sort: "distance" })` puts first, near-ties included, on every machine. A negative radius finds nothing. A NaN point is never nearest, and a `from` point does not skip itself when `to` holds it too. |
| `shapeCast` | `shapeCast(shape: CastShape, from: Vec3, dir: Vec3, max?: number, opts?: CastOptions): Hit \| null` | Like `raycast` but sweeping a shape. |
| `overlap` | `overlap(shape: CastShape, position: Vec3, rotation?: Quat, opts?: CastOptions): EntityHandle[]` | Every entity whose collider `shape` overlaps at `position`, turned by `rotation` (a quaternion `[x, y, z, w]`, default none), sorted by entity: the same order on every run. A static question: nothing is swept and nothing moves, so it answers about the colliders as the last physics step left them. Touching counts. `opts` are a cast's: `triggers` (default true here, as for a cast), `exclude`, `excludeTags`, `layers`. Throws a `TypeError` for a shape that is none of the three. |
| `overlaps` | `overlaps(entity: EntityHandle \| string): EntityHandle[] \| null` | Who `entity`'s sensor (an `attach`ed entity with a trigger collider) touches as of this tick's query, sorted by entity; null when it has no (resolved) sensor. A sensor queries its collider every tick at the bone's pose and delivers `overlap` events: `name` "overlap", `data` `{ sensor, other, phase: "begin" \| "end" }` (entity ids), by sensor; within a sensor its ends, then its begins, each by other. |
| `setSensor` | `setSensor(entity: EntityHandle \| string, on: boolean): boolean` | Switches `entity`'s sensor on or off (it starts on). Off, it queries nothing and ends every pair it held, with `end` events on this tick's pass; with `activeWhile` it also needs that animation window open. Returns false when the entity has no sensor. |
| `pick` | `pick(from: Vec3, dir: Vec3, max?: number, opts?: PickOptions): Hit \| null` | The dynamic body a pick ray lands on first, or null — what "the thing I am pointing at" means for a grab. The first thing the ray meets decides: a wall in front of a crate hides it, and a static or kinematic body, one over `maxMass` or one without `tag` answers null rather than letting the ray carry on. Exclude the picker. `ts const eye = ctx.entity.worldPosition; eye[1] += 1.6 const hit = ctx.world.pick(eye, aim, 2.5, { exclude: ctx.entity, tag: "grabbable" }) ``` |
| `hold` | `hold(holder: EntityHandle \| string, target: EntityHandle \| string, opts?: HoldOptions): boolean` | Start carrying `target`'s dynamic body at `holder` (any entity: a character, a hand, a crane hook). True when it is now held. False, having changed nothing, when the target is gone, has no body, is not dynamic, is the holder, or is over `maxMass`. A NaN, infinite or non-positive option throws a `RangeError`. The body stays a physics body: each tick it is given the velocity that brings it to its hold point, so it still collides with everything except its holder, stops against walls (it never passes through one), and pushes other bodies aside. When it falls more than `breakDistance` behind and keeps falling behind — the holder walked away from a crate wedged in a doorway — the hold breaks and the body drops; `heldBy` reads null from that tick. However a hold ends — a break, a `release`, a despawn — the engine raises a `"hold-broken"` bus event ({@link BusHoldBroken}) saying which and why. A character's controller passes through what it is holding. Holding something already held replaces that hold: a hand-over, or a new `offset`, is one more call. Held state is part of the physics checkpoint, so `GET /snapshot` → `POST /snapshot` restores a carry. |
| `release` | `release(target: EntityHandle \| string, opts?: ReleaseOptions): boolean` | Let `target` go; `opts.velocity` throws it. False if it was not held. |
| `heldBy` | `heldBy(target: EntityHandle \| string): EntityHandle \| null` | Who is holding `target`, or null. |
| `holding` | `holding(holder: EntityHandle \| string): EntityHandle[]` | What `holder` is holding, in entity order; empty when nothing. |
| `path` | `path(from: Vec3, to: Vec3): Vec3[] \| null` | Navmesh path as a polyline, or null when unreachable. Throws `nav-undeclared` in a scene that declares no navigation (no `meta.nav`, no `navagent`): navigation is opt-in, and such a scene has no navmesh. Add `"nav": {}` to the scene's meta. |
| `spawn` | `spawn(options: SpawnOptions): EntityHandle` | Put another copy of an entity the scene already has, or of a prefab, into the world, and get a handle to it. `like` is the scene id of a live entity, and the new entity is a full copy of it: its name, its tags, its parent, its scale and every one of its components, wired the way the scene's own entities are — a collider becomes a physics body the solver knows, a mesh becomes something the renderer draws, a script gets its own behavior instance with its own `state`, all within the tick that asked for it. `prefab` instead of `like` spawns a copy of a project prefab file, which need not be placed in any scene: its root and every entity under it, the root's id as below and each other entity's `"<root id>/<prefab entity id>"`, parented as the prefab has them, with `overrides` applied as a scene instance's are. The handle is the root's; {@link EntityHandle.despawn} on it removes the whole copy. The project's prefabs are read and checked once, at load, so a spawn parses nothing. Either way, what is spawned is a shape the contract already validated: an entity of the scene, or a prefab file. **Ids.** Give one and it must be free, or this throws. Leave it out and the engine derives `"<like>#1"`, `"<like>#2"`, … from a counter kept per source id. Both are deterministic: two runs of the same scene making the same calls in the same order get the same ids and the same entity slots, which is what the lockstep critic checks. Throws rather than returning null, so a spawn that did not happen cannot be mistaken for one that did. The error's `name` is `SpawnError` and its message starts with the code: `spawn-no-source`, `spawn-two-sources`, `spawn-unknown-source`, `spawn-unknown-prefab`, `spawn-prefab-cycle`, `spawn-bad-override`, `spawn-duplicate-id`. The copy's behaviour runs `init` on this tick, after every `update` has returned, and is then handed each event emitted this tick after this call (so an `emit` straight after the spawn reaches its `onEvent` and the listeners its `init` subscribed); its first `update` is next tick. A spawned entity is runtime state, not a scene change. The scene file is untouched, `GET /snapshot` carries the entity and `POST /snapshot` puts it back — and {@link SessionHandle.restart} rebuilds from the scene as loaded, so a restart removes every spawned entity and brings back every authored one. `ts const cone = ctx.world.spawn({ like: "cone-prototype", position: [4, 0, -12] }) cone.set("material", { baseColor: "#ff6600" }) const imp = ctx.world.spawn({ prefab: "prefabs/imp.prefab.json", position: [2, 0, 5],   overrides: { "root/script:chase/props/speed": 5 } })   // imp#1, and imp#1/<child> for each child ``` |

## Example

The tested fixture `fixtures/recipes/collectible-and-goal/scenes/behaviors/collectible.ts`.

```ts
import type { Behavior } from "@argus/api"

/**
 * A coin the player collects by walking into it.
 *
 * It says so once, as `collected`, and leaves the world. Counting is somebody else's job —
 * `goal-exit.ts` — so a coin never needs to know how many there are.
 *
 * The contact is `onTrigger`, which needs three things in the scene: a collider with
 * `isTrigger: true` (the volume), a `trigger` component (what fires), and a body on the player —
 * the character controller's capsule is one.
 */
interface State {
  collected: boolean
}

interface Props {
  /** Tag the toucher must carry. Default `player`. */
  playerTag?: string
}

export default {
  init(ctx) {
    if (typeof ctx.state.collected !== "boolean") ctx.state.collected = false
  },

  onTrigger(ctx, trigger) {
    if (ctx.state.collected || !trigger.entering) return
    if (!trigger.other.hasTag(ctx.props.playerTag ?? "player")) return
    ctx.state.collected = true
    // The `goal` component on this coin has the same id, so the playtester and the HUD agree.
    ctx.events.emit("collected", { goal: ctx.entity.id })
    // Last: after `despawn` every member of this entity's handles throws.
    ctx.entity.despawn()
  },
} satisfies Behavior<State, Props>
```
