Phaser AE

Steering Behaviours and Flocking

Free packv3.0.0-52D and 3DLogic

Agents that decide where to go on their own: birds that flock, fish that scatter from a shark, guards that patrol round pillars, a horde pouring along a flow field. Each is a position, a velocity and a list of behaviours, blended every fixed step into one force, in a 3D world or on a 2D one.

This is a Free pack. Every phaser.io account can use it in their games.

Released October 14, 2026 · updated October 19, 2026

Steering Behaviours and Flocking: a screenshot of its demo
A note about these graphics

Expansion packs don't come with graphics. This screenshot is one way of drawing what the pack does, made for its demo: none of the sprites, tiles or backgrounds in it are in the pack.

That's by design. A pack is a game's logic, mechanics and effects, and it works with whatever art you give it. Some packs draw effects, backdrops or 3D scenes of their own, but none carries a game's sprites.

So the look is yours. Make the art on phaser.io, bring your own, or let your agent draw it in code: the same pack can look like anything.

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 2D rot), 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 after kill().
  • 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 on maxSpeed while panicking. Default 2.5.
  • ground: { at: (x: number, z: number) => number; offset: number; slope: boolean } | null — Glues the body to a surface — see AgentConfig.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 by bank in turns.
  • panic: number — Seconds of panic left: a strong repulsor push scatters a shoal at panicSpeed times 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 into navPath — 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 kernel Rng: it drives wander and the body phase. snapshot() and restore() roll it back.
  • dead: boolean — True after kill().
  • force: Vec3 — last accumulated steering force (for gizmos).
  • constructor(c: AgentConfig = {}, id = 0, rng?: Rng) — id is the agent's number in its system and rng its random stream. Agents3d.spawn supplies both; an agent made on its own is number 0 and seeds its stream from c.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. A preset names a starting config from AGENT_PRESETS (their numbers are in the 3D presets' units: a pixel world sets maxSpeed, maxForce and the flock's radius of its own).
  • flock(config: Agent2dConfig & { preset?: keyof typeof AGENT_PRESETS }, nOrHandles: number | ReadonlyArray<Handle2d>): Agent2d[] — A flock of n agents sharing a config, or one bound to each of handles. Seeded as the 3D flock seeds.
  • attractor(o: { pos?: Vec2; follow?: Vec2; radius: number; strength: number; falloff?: 'linear' | 'invsq' }): Field3d — A field that pulls agents in: at pos, or riding a 2D object it follows. 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 the avoid behaviour 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 by dt seconds 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. A preset names a starting config from AGENT_PRESETS that the config's own fields override (its behaviors replace the preset's). Its number is the next one; with no seed its 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 of n agents sharing a config (or bind to existing handles). With a seed, member i is seeded seed + i; without one each takes the stream spawn gives 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 the avoid behaviour steers around. Returns its handle; kill() removes it.
  • tick(dt: number): void — Advance by dt seconds: runs whole fixedStep steps (at most 3 a call, dt clamped to 0.1 s), then writes each agent's pose onto its handle, interpolated by the time left over. The steering pack calls it from the kernel's simulate step with a fixedStep equal 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 while follow is set.
  • follow: { x: number; y: number; z: number } | null — A live object the field tracks, or null to stay at pos.
  • 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 after kill().
  • constructor(o: FieldOptions)
  • at(): Vec3 — Returns the live centre — the followed object when set, else pos.
  • 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 after kill().
  • 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 agent self within radius, written into outIdx (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 with maxSpeed.
  • 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 (and rot, with turn) 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 on maxSpeed while 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 on maxSpeed while the agent panics after a strong repulsor push (see FieldOptions.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 to at(x,z) + offset (walkers, monsters, herds — at can return terrain OR a ramp/plank/platform top). slope: true also 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; the steering pack passes the game's own step.
  • rng?: Rng — The stream agents without a seed draw from. The steering pack 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; the steering pack 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 a seed take their own from: each gets a fork of it labelled with its number, so what it draws never depends on what the others did. The steering pack passes a fork of the game's rng, which is what makes a game and its replay wander the same. Default createRng(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's maxForce budget, 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 at panicSpeed times 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. avoid reads 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. A preset names a starting config from AGENT_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 and rot.
  • flock2d(config: Agent2dConfig & { preset?: keyof typeof AGENT_PRESETS }, nOrHandles: number | ReadonlyArray<Handle2d>): Agent2d[] — Many 2D agents sharing a config, or one on each of handles.

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.