The pack
steering
function steering(): Pack<{ steering: SteeringApi }>
The steering pack: the behaviours a moving thing blends to decide where to go. An agent is a
position, a velocity and a list of behaviours as DATA, stepped on the fixed clock. It is headless —
bind an agent to a roster handle and it drives it, or read agent.pos and do what you like.
Functions
dampAngle
function dampAngle(cur: number, target: number, k: number): number
Shortest-arc angle damp (handles the ±π wrap).
integrateAgent
function integrateAgent(a: Agent3d, ctx: StepCtx, dt: number, solveSteering: boolean): void
Integrate one agent for a fixed step, then damp its body language.
neighborsBrute
function neighborsBrute(agents: Agent3d[], self: number, radius: number, k: number, outIdx: Int32Array, outD2: Float32Array): number
Brute-force nearest-k neighbours within radius, written into outIdx/outD2; returns the count. Small flocks (40 agents or fewer) use it instead of the hash.
writePose
function writePose(a: Agent3d, alpha: number): void
Damp the heading toward the velocity (never snap) and write the pose onto
the render handle, interpolated between the last two sim steps by alpha.
Classes
Agent2d
class Agent2d
One steered point on a 2D world's plane. Get one from game.steering.agents2d.spawn(), or spawn2d().
readonly core: Agent3d— The 3D agent underneath, on the ground plane: its x is this one's x and its z this one's y.constructor(core: Agent3d, behaviors: Behavior2dSpec[])get id(): number— The agent's number in its system.get x(): number— World x. Setting it moves the agent there (no sweep). Moves it to world x at once.set x(v: number)— World x. Setting it moves the agent there (no sweep). Moves it to world x at once.get y(): number— World y. Setting it moves the agent there (no sweep). Moves it to world y at once.set y(v: number)— World y. Setting it moves the agent there (no sweep). Moves it to world y at once.get vx(): number— Velocity x, units a second. Sets velocity x.set vx(v: number)— Velocity x, units a second. Sets velocity x.get vy(): number— Velocity y, units a second. Sets velocity y.set vy(v: number)— Velocity y, units a second. Sets velocity y.get pos(): Vec2— The position, as a new point.get speed(): number— The speed, units a second.get heading(): number— The heading the agent faces, radians, 0 along +x and turning toward +y (the 2Drot), damped toward its velocity.get maxSpeed(): number— The top speed, world units a second. Live. Sets the top speed.set maxSpeed(v: number)— The top speed, world units a second. Live. Sets the top speed.get maxForce(): number— The steering force budget. Live. Sets the force budget.set maxForce(v: number)— The steering force budget. Live. Sets the force budget.get behaviors(): ReadonlyArray<Behavior2dSpec>— The behaviours, in 2D; setting them replaces the core's. Replaces the behaviours, translated for the core.set behaviors(list: ReadonlyArray<Behavior2dSpec>)— The behaviours, in 2D; setting them replaces the core's. Replaces the behaviours, translated for the core.get dead(): boolean— True afterkill().kill(): void— Remove the agent; its system drops it on the next tick (the handle is yours to kill).
Agent3d
class Agent3d
One steered point-mass vehicle. A game gets one from agents.spawn() or
agents.flock(); each fixed step it blends its behaviours into a force,
integrates, and writes its pose onto its render handle.
readonly id: number— The agent's number in its system: 1 for the first spawned, counting up.Agents3d.clear()starts the count again. 0 for an agent made on its own.pos: Vec3— The position, in world units.prev: Vec3— The position at the previous fixed step — used for render interpolation.vel: Vec3— The velocity, in world units each second.maxSpeed: number— The top speed, in world units each second. Default 6.maxForce: number— The steering force budget each step. Default 20.mass: number— The mass. The force divides by it to give the acceleration. Default 1.behaviors: BehaviorSpec[]— The behaviours, sorted by priority — avoidance claims the force budget first.handle: { x: number; y: number; z: number; yaw?: number; pitch?: number; roll?: number } | null— The render handle the agent writes its pose onto, or null.tickEvery: number— Steering is solved every Nth fixed step; the velocity integrates on every step. Default 1.turnRate: number— Radians each second the heading damps toward the velocity. Default 6.maxPitch: number— The pitch clamp, in radians. Default PI/2.bank: number— Banks the body into turns: roll proportional to lateral steering. 0 = none.panicSpeed: number— Multiplier onmaxSpeedwhile panicking. Default 2.5.ground: { at: (x: number, z: number) => number; offset: number; slope: boolean } | null— Glues the body to a surface — seeAgentConfig.ground. Null for flyers and swimmers.yaw: number— The body orientation, in radians. Damped toward the velocity each step.pitch: number— The body pitch, in radians. Damped toward the velocity each step.roll: number— The body roll, in radians. Set bybankin turns.panic: number— Seconds of panic left: a strong repulsor push scatters a shoal atpanicSpeedtimes the top speed.wx: number— wander target on the projected sphere (persisted for a smooth walk).wy: number— The Y of the wander target on the projected sphere.wz: number— The Z of the wander target on the projected sphere.followD: number— follow-behaviour progress along its path (world distance).avoidSide: number— avoid-behaviour hysteresis: the committed dodge side (±1) + its hold timer, so the agent arcs around an obstacle on ONE side instead of jittering.avoidHold: number— Seconds the committed dodge side is held before it can flip.navPath: Vec3[] | null— navigate-behaviour state: the current A* waypoint list + cursor + timers.navIdx: number— The cursor intonavPath— the waypoint being steered for.navTimer: number— Seconds until the navigate behaviour plans a new path.navGoalX: number— The XZ goal the current path was planned for — a drifted goal starts a re-plan.navGoalZ: number— The Z of the goal the current path was planned for, in world units.phase: number— per-instance wiggle phase (fish tail / wing flap) — rides a spare slot.rng: Rng— The agent's own random stream, a kernelRng: it drives wander and the body phase.snapshot()andrestore()roll it back.dead: boolean— True afterkill().force: Vec3— last accumulated steering force (for gizmos).constructor(c: AgentConfig = {}, id = 0, rng?: Rng)—idis the agent's number in its system andrngits random stream.Agents3d.spawnsupplies both; an agent made on its own is number 0 and seeds its stream fromc.seed(default 0), so give it one.get speed(): number— The current speed, in world units each second.kill(): void— Marks the agent dead. The system removes it on the next tick.
Agents2d
class Agents2d
The 2D agent system: spawn and flock 2D agents, add fields and obstacles in the world's coordinates, and step them
on the fixed clock. The steering pack makes one (game.steering.agents2d) and ticks it with the 3D one; code
without a game makes its own and calls tick(dt).
readonly core: Agents3d— The 3D system underneath, its agents on the ground plane.constructor(opts: Agents2dOptions = {})spawn(config: Agent2dConfig & { preset?: keyof typeof AGENT_PRESETS }): Agent2d— One 2D agent. Apresetnames a starting config fromAGENT_PRESETS(their numbers are in the 3D presets' units: a pixel world setsmaxSpeed,maxForceand the flock's radius of its own).flock(config: Agent2dConfig & { preset?: keyof typeof AGENT_PRESETS }, nOrHandles: number | ReadonlyArray<Handle2d>): Agent2d[]— A flock ofnagents sharing a config, or one bound to each ofhandles. Seeded as the 3Dflockseeds.attractor(o: { pos?: Vec2; follow?: Vec2; radius: number; strength: number; falloff?: 'linear' | 'invsq' }): Field3d— A field that pulls agents in: atpos, or riding a 2D object itfollows.kill()removes it.repulsor(o: { pos?: Vec2; follow?: Vec2; radius: number; strength: number; falloff?: 'linear' | 'invsq'; panic?: number }): Field3d— A field that pushes agents away (and can make them panic).kill()removes it.obstacle(o: { circle?: { x: number; y: number; r: number }; rect?: { x: number; y: number; w: number; h: number } }): Obstacle3d— A solid theavoidbehaviour steers around: a circle, or a rectangle.kill()removes it.get agents(): ReadonlyArray<Agent2d>— Every live 2D agent.get count(): number— The number of live agents.tick(dt: number): void— Advance bydtseconds and write each agent's pose onto its handle.clear(): void— Drop every agent, field and obstacle.
Agents3d
class Agents3d
The agent system: owns the agents, the fields and the obstacles, and steps them all on a fixed clock. The
steering pack makes one (game.steering.agents) and ticks it in the kernel's simulate step; code without a game
makes its own with new Agents3d({ rng }) and calls tick(dt) or step(dt). spawn() and flock() add agents.
readonly agents: Agent3d[]— Every live agent. Dead ones are removed each tick.readonly fields: Field3d[]— Every live field — attractors and repulsors.readonly obstacles: Obstacle3d[]— Every live obstacle.debug: boolean— gizmos through game.debug (velocity/force/neighbours) when true.constructor(opts: AgentsOptions = {})spawn(config: AgentConfig & { preset?: keyof typeof AGENT_PRESETS }): Agent3d— Creates one agent from a config and adds it to the system. Apresetnames a starting config fromAGENT_PRESETSthat the config's own fields override (itsbehaviorsreplace the preset's). Its number is the next one; with noseedits random stream is this system's fork for that number. Throws on an unknown preset.flock(config: AgentConfig & { preset?: keyof typeof AGENT_PRESETS }, nOrHandles: number | Array<AgentConfig['handle']>): Agent3d[]— A flock ofnagents sharing a config (or bind to existing handles). With aseed, member i is seededseed + i; without one each takes the streamspawngives it, so two flocks of one config do not move in step.attractor(o: Omit<FieldOptions, 'mode'>): Field3d— Adds a field that pulls agents in. Returns its handle;kill()removes it.repulsor(o: Omit<FieldOptions, 'mode'>): Field3d— Adds a field that pushes agents away. Returns its handle;kill()removes it.obstacle(o: ObstacleOptions): Obstacle3d— Adds a solid theavoidbehaviour steers around. Returns its handle;kill()removes it.tick(dt: number): void— Advance bydtseconds: runs wholefixedStepsteps (at most 3 a call,dtclamped to 0.1 s), then writes each agent's pose onto its handle, interpolated by the time left over. Thesteeringpack calls it from the kernel's simulate step with afixedStepequal to the game's, so each call runs exactly one step.step(dt: number, stepIdx = 0): void— One fixed simulation step (public for dist tests).clear(): void— Drop every agent, field and obstacle (render handles are yours to kill). Lets a demo tear a scene down and rebuild another. Agent numbering starts again at 1, so a scene rebuilt with the same spawns wanders as it did the first time.get count(): number— The number of live agents.
Field3d
class Field3d
A force field that pulls agents in or pushes them away. Get one from agents.attractor() or agents.repulsor().
pos: Vec3— The centre, in world units. Ignored whilefollowis set.follow: { x: number; y: number; z: number } | null— A live object the field tracks, or null to stay atpos.radius: number— The reach of the field, in world units.strength: number— The strength of the force the field applies.falloff: 'linear' | 'invsq'— How the strength drops with distance: 'linear' or 'invsq'.mode: 'attract' | 'repel'— 'attract' pulls agents in; 'repel' pushes them away.panic: number— Seconds of panic a strong push from this repulsor arms; 0 never panics. Default 2.dead: boolean— True afterkill().constructor(o: FieldOptions)at(): Vec3— Returns the live centre — the followed object when set, elsepos.kill(): void— Marks the field dead. The system removes it on the next tick.
Obstacle3d
class Obstacle3d
A solid the avoid behaviour steers around — a sphere or a box, tested in the XZ plane (its height is ignored). Get one from agents.obstacle().
sphere: { center: Vec3; radius: number } | null— The sphere bounds, or null when the obstacle is a box.box: { min: Vec3; max: Vec3 } | null— The box bounds, or null when the obstacle is a sphere.dead: boolean— True afterkill().constructor(o: ObstacleOptions)kill(): void— Marks the obstacle dead. The system removes it on the next tick.
SpatialHash3
class SpatialHash3
A counting-sort uniform grid for k-nearest neighbour queries. The agent system builds and owns one; a game does not need to.
flat: boolean— drop the Y dimension for surface-bound swarms (ground crowds).constructor(cellSize: number, capacity: number, tablePow = 12)build(agents: Agent3d[]): void— Rebuild from the live agent positions (indices 0..n-1).query(agents: Agent3d[], self: number, radius: number, k: number, outIdx: Int32Array, outD2: Float32Array): number— Nearest up-to-k neighbours of agentselfwithinradius, written intooutIdx(indices) /outD2(squared distances); returns the count.
Constants
AGENT_PRESETS
const AGENT_PRESETS: Record<string, () => AgentConfig>
Named agent configs — firefly, fish, shoal, hunter, bird, patrol. Each is a factory that returns a fresh config, so a caller can change one safely.
Types
Agent2dConfig
interface Agent2dConfig
What a 2D agent is made from: the 3D agent's tuning, in the world's own units, with 2D positions and behaviours.
pos?: Vec2— The start position. Default the origin.vel?: Vec2— The start velocity. Default zero.maxSpeed?: number— The top speed, world units a second. Default 6, which a pixel world will want far higher.maxForce?: number— The steering force budget each step. Default 20; scale it withmaxSpeed.mass?: number— The mass. Default 1.behaviors?: Behavior2dSpec[]— The behaviours the agent blends, in priority order of their kinds.handle?: Handle2d | null— A 2D handle to write x, y (androt, withturn) onto each frame.turn?: boolean— Turn the handle to face where it is heading. Default true; false for a side-view sprite that must stay upright.turnRate?: number— Radians a second the heading damps toward the velocity (never snaps). Default 6.seed?: number— The seed for the agent's own wander. Default: the system's stream for its number.tickEvery?: number— Steering solved every Nth fixed step (LOD); velocity integrates always. Default 1.panicSpeed?: number— Multiplier onmaxSpeedwhile panicking from a strong repulsor push. Default 2.5.
AgentConfig
interface AgentConfig
Tuning for one agent — what agents.spawn() takes. Every field is optional.
pos?: Vec3— The start position. Default the origin.vel?: Vec3— The start velocity. Default zero.maxSpeed?: number— The top speed, in world units each second. Default 6.maxForce?: number— The steering force budget each step. Default 20.mass?: number— The mass. Default 1.behaviors?: BehaviorSpec[]— The behaviours the agent blends, in data form.handle?: { x: number; y: number; z: number; yaw?: number; pitch?: number; roll?: number } | null— A render handle to write x/y/z and yaw/pitch/roll onto each frame.seed?: number— The seed for the agent's own random stream, which drives its wander. Default: a stream of the game's own for this agent's number, so the game's seed decides it and a replay wanders the same. Give one to pin this agent's wander whatever the game.tickEvery?: number— Steering solved every Nth fixed step (LOD); velocity integrates always.turnRate?: number— Radians/sec the heading damps toward velocity (never snaps).maxPitch?: number— Max pitch (radians) — clamp for flyers/swimmers.bank?: number— Bank into turns: roll ∝ lateral steering (0 = none).panicSpeed?: number— Multiplier onmaxSpeedwhile the agent panics after a strong repulsor push (seeFieldOptions.panic). Default 2.5; 1 keeps its top speed.ground?: { at: (x: number, z: number) => number; offset?: number; slope?: boolean } | null— GROUND agents: glue the body to a surface. Steering owns XZ; after each step the Y is SNAPPED toat(x,z) + offset(walkers, monsters, herds —atcan return terrain OR a ramp/plank/platform top).slope: truealso pitches the body to the surface gradient so it climbs ramps convincingly.
Agents2dOptions
interface Agents2dOptions
What Agents2d takes: the 3D system's options. Its hash runs flat, and its cell grows to the widest flock.
fixedStep?: number— The simulation step, in seconds. Default 1/60; thesteeringpack passes the game's own step.rng?: Rng— The stream agents without aseeddraw from. Thesteeringpack passes a fork of the game's.
AgentsOptions
interface AgentsOptions
Tuning for the agent system: fixedStep is the simulation step in seconds (default 1/60); hashCell is the spatial-hash cell size in world units (default 8).
fixedStep?: number— The simulation step, in seconds. Default 1/60; thesteeringpack passes the game's own step.hashCell?: number— The spatial-hash cell size, in world units. Default 8. A query looks one cell either side, so the cell grows to the widest flock radius it is asked for: a pixel world's flock of fifty finds its neighbours whatever this says.flat?: boolean— Hash on the ground plane only, for agents that never leave it (the 2D system, a crowd on flat ground). Default false.rng?: Rng— The stream agents without aseedtake their own from: each gets a fork of it labelled with its number, so what it draws never depends on what the others did. Thesteeringpack passes a fork of the game'srng, which is what makes a game and its replay wander the same. DefaultcreateRng(0).
Behavior2dSpec
type Behavior2dSpec = | (BehaviorBase & { kind: 'seek'; target: Target2d }) | (BehaviorBase & { kind: 'flee'; target: Target2d; radius?: number }) | (BehaviorBase & { kind: 'arrive'; target: Target2d; slowRadius?: number; tolerance?: number }) | (BehaviorBase & { kind: 'pursue'; target: Agent2d; maxPredict?: number }) | (BehaviorBase & { kind: 'evade'; target: Agent2d; maxPredict?: number; radius?: number }) | (BehaviorBase & { kind: 'wander'; radius?: number; distance?: number; jitter?: number }) | (BehaviorBase & { kind: 'follow'; path: ReadonlyArray<Vec2>; closed?: boolean; lookAhead?: number; loop?: boolean; speed?: number }) | (BehaviorBase & { kind: 'flock'; separation?: number; alignment?: number; cohesion?: number; radius?: number; neighbors?: number; separationRadius?: number }) | (BehaviorBase & { kind: 'avoid'; lookAhead?: number; radius?: number; hold?: number }) | (BehaviorBase & { kind: 'contain'; rect?: { x: number; y: number; w: number; h: number }; circle?: { x: number; y: number; r: number }; soft?: number }) | (BehaviorBase & { kind: 'leader'; leader: Agent2d; behind?: number; slowRadius?: number }) | (BehaviorBase & { kind: 'edge'; walkable: (x: number, y: number) => boolean; lookAhead?: number }) | (BehaviorBase & { kind: 'navigate'; grid: PathPlanner2d; target: Target2d; repathEvery?: number; arrive?: number; tolerance?: number; radius?: number; reach?: number; partial?: boolean }) | (BehaviorBase & { kind: 'flow'; field: FlowSource2d }) | (BehaviorBase & { kind: 'custom'; fn: (agent: Agent2d, out: Vec2, dt: number) => void })
One 2D steering behaviour, as data: the 3D behaviours that make sense on a plane, in the world's own coordinates.
follow takes the path's points; contain a rectangle or a circle; navigate a 2D planner (nav's NavGrid2d);
flow a 2D field. The tuning is the 3D behaviour's: see BehaviorSpec.
BehaviorBase
interface BehaviorBase
The two settings every behaviour shares: how hard it pulls and when it gets its turn at the force budget.
weight?: number— Multiplier on the behaviour's force before it joins the agent's total. Default 1.priority?: number— Order in which behaviours claim the agent'smaxForcebudget, highest first; once it is spent the rest get nothing. Default 4 for avoid, terrain, ceiling, contain and edge, 2 for flock and leader, 1 for the others.
BehaviorSpec
type BehaviorSpec = | (BehaviorBase & { kind: 'seek'; target: TargetLike }) | (BehaviorBase & { kind: 'flee'; target: TargetLike; radius?: number }) | (BehaviorBase & { kind: 'arrive'; target: TargetLike; slowRadius?: number; tolerance?: number }) | (BehaviorBase & { kind: 'pursue'; target: Agent3d; maxPredict?: number }) | (BehaviorBase & { kind: 'evade'; target: Agent3d; maxPredict?: number; radius?: number }) | (BehaviorBase & { kind: 'wander'; radius?: number; distance?: number; jitter?: number; vertical?: number }) | (BehaviorBase & { kind: 'follow'; path: Path3d; lookAhead?: number; loop?: boolean; speed?: number }) | (BehaviorBase & { kind: 'flock'; separation?: number; alignment?: number; cohesion?: number; radius?: number; neighbors?: number; separationRadius?: number }) | (BehaviorBase & { kind: 'avoid'; lookAhead?: number; radius?: number; hold?: number }) | (BehaviorBase & { kind: 'terrain'; clearance: number; groundAt: (x: number, z: number) => number; lookAhead?: number }) | (BehaviorBase & { kind: 'ceiling'; below: number | ((x: number, z: number) => number); margin?: number }) | (BehaviorBase & { kind: 'contain'; box?: { min: Vec3; max: Vec3 }; sphere?: { center: Vec3; radius: number }; soft?: number }) | (BehaviorBase & { kind: 'leader'; leader: Agent3d; behind?: number; slowRadius?: number }) // Stay ON a walkable surface (planks/platforms/ledges): whisker-samples a // predicate ahead + to the sides and turns back from any edge. XZ-planar. | (BehaviorBase & { kind: 'edge'; walkable: (x: number, z: number) => boolean; lookAhead?: number }) // Plan a path to a (moving) target over any planner — the built-in NavGrid // (A* over a NavGrid, or any other PathPlanner) — re-planning on a timer / // when the goal drifts; steer along the smoothed waypoints. `radius` is the // agent's body: the route is planned for radius + reach, so turning for the // next waypoint `reach` early still keeps the body `radius` clear of walls, // and with a planner that offers `clear` (a NavGrid) the agent turns for the // next waypoint as soon as its body can reach it straight. `reach` is how near // a waypoint counts as reached (default max(maxSpeed × 0.2, 1), or at most a // quarter of `radius` when one is given). `partial` (default true) asks the planner, when the goal cannot be // reached, for a route to the reachable point nearest it, so a chaser walls in as close as it can; false heads // straight for the goal instead and leaves the walls to avoidance. | (BehaviorBase & { kind: 'navigate'; grid: PathPlanner; target: TargetLike; repathEvery?: number; arrive?: number; tolerance?: number; radius?: number; reach?: number; partial?: boolean }) // Flow field: sample a precomputed direction toward the goal (O(1)) — the // horde-chase behaviour (one field, N followers + separation). | (BehaviorBase & { kind: 'flow'; field: FlowSource }) | (BehaviorBase & { kind: 'custom'; fn: (agent: Agent3d, out: Vec3, dt: number) => void })
One steering behaviour, as data: a kind plus its tuning, with an optional weight and priority. An agent blends a list of these.
FieldOptions
interface FieldOptions
Tuning for a field — what agents.attractor() and agents.repulsor() take.
pos?: Vec3— The centre of the field. Default the origin.follow?: { x: number; y: number; z: number }— A live object the field tracks — a render handle, an agent or a camera.radius: number— The reach of the field, in world units.strength: number— The strength of the force.falloff?: 'linear' | 'invsq'— How the strength drops with distance: 'linear' or 'invsq' (default).mode?: 'attract' | 'repel'— 'attract' (default) pulls agents in; 'repel' pushes them away.panic?: number— Seconds of panic a repulsor gives an agent whose push passes half the field's strength (it then runs atpanicSpeedtimes its top speed). Default 2; 0 never panics. Attractors ignore it.
FlowSource
type FlowSource = { dirAt(x: number, z: number): { x: number; z: number } } | ((x: number, z: number) => { x: number; z: number })
What the flow behaviour samples: a direction toward the goal at a point on the ground plane (world X and Z),
any length, zero where there is none. nav's 3D FlowField is one as it is; a function adapts any other field,
such as nav's weighted FlowGrid ((x, z) => { const s = grid.steer(x, z); return { x: s.x, z: s.y }; })
or nav's 2D FlowField2d.
FlowSource2d
type FlowSource2d = { dirAt(x: number, y: number): Vec2 } | ((x: number, y: number) => Vec2)
A direction field a flow behaviour samples: an object with dirAt(x, y), or the function itself.
Handle2d
interface Handle2d
A 2D render handle the agent drives: its x and y, and its rot when turn is on. A roster handle is one.
x: number— World x.y: number— World y.rot: number— The turn, radians, 0 facing +x.
ObstacleOptions
interface ObstacleOptions
The shape of an obstacle — give a sphere or a box. What agents.obstacle() takes.
sphere?: { center: Vec3; radius: number }— A sphere: a centre and a radius, in world units.box?: { min: Vec3; max: Vec3 }— An axis-aligned box: min and max corners, in world units.avoidreads its X and Z extent; given with a sphere, the box is used.
SteeringApi
interface SteeringApi
game.steering: the game's agent system and shortcuts onto it.
readonly agents: Agents3d— The agent system: spawn, flock, fields (attractor,repulsor), obstacles,clear.spawn(config: AgentConfig & { preset?: keyof typeof AGENT_PRESETS }): Agent3d— One agent. Apresetnames a starting config fromAGENT_PRESETS; the config's own fields override it.flock(config: AgentConfig & { preset?: keyof typeof AGENT_PRESETS }, nOrHandles: number | Array<AgentConfig['handle']>): Agent3d[]— Many agents sharing a config, or bound to existing handles.readonly all: ReadonlyArray<Agent3d>— Every live agent.readonly presets: ReadonlyArray<string>— The named presets a game can start from.readonly agents2d: Agents2d— The 2D agent system: the same behaviours on a 2D world's plane, in its own x and y (spawn,flock,attractor,repulsor,obstacle,clear). Stepped with the 3D one; its agents and the 3D ones never meet.spawn2d(config: Agent2dConfig & { preset?: keyof typeof AGENT_PRESETS }): Agent2d— One 2D agent, driving a 2D handle's x, y androt.flock2d(config: Agent2dConfig & { preset?: keyof typeof AGENT_PRESETS }, nOrHandles: number | ReadonlyArray<Handle2d>): Agent2d[]— Many 2D agents sharing a config, or one on each ofhandles.
Target2d
type Target2d = Vec2 | Agent2d | (() => Vec2)
Where a 2D behaviour aims: a point, another 2D agent, or a function read every step (a moving object).
TargetLike
type TargetLike = Vec3Like | Agent3d | (() => Vec3Like)
A steering target: a fixed point, another agent (tracked live), or a fn.
Vec2
interface Vec2
A point or a direction in a 2D world: x right, y down, the world's own units.
x: number— Across, rightward.y: number— Down the screen.
Vec3
interface Vec3
A 3D point or vector (x, y, z), in world units.
x: number— The X component, in world units.y: number— The Y component, in world units.z: number— The Z component, in world units.


