What it does
You describe a network as named nodes and directed edges. An edge with no via is a straight line; otherwise it is a
chain of path-notation segments from its start node to its end node: lines, quadratic and cubic curves, arcs, spirals
and waves. A node with no outgoing edges is a goal, and one with no incoming edges a spawn, unless you name them
yourself. new Track bakes the whole network once into arc-length tables, so walkers keep an even speed round the
tightest curve.
track.spawn(speed) puts a walker on the network. Each step advance(dt) moves it by arc length, carrying it across
junctions, and you read its x, y and angle for the sprite. At a junction the walker asks its chooser first, if it
has one, and otherwise draws a branch weighted by each edge's weight, which you can change live to bias a junction.
distanceToGoal is the distance left along the track to the nearest goal, so finding the walker closest to the exit is
one comparison.
Everything is deterministic. Unnamed spawns and weighted branches draw from the walker's stream or the track's, and a
fork of the game's stream makes the game's seed decide every route. A walker's state snapshots as JSON-safe data.
distanceToTrack measures how far a point is from any edge, which keeps a tower from being built on the road.
Features
- Nodes and directed edges — a network in plain data, with spawns and goals found for you or named.
- Curved edges — lines, quadratic and cubic curves, arcs, spirals and waves in path notation.
- Even speed — walkers move by arc length, with a live
speedto slow or boost them. - Branching by weight or policy — weighted draws you can change live, or a chooser for a points switch, a player's choice or a shortest-route rule.
- Distance to goal — for turrets that aim at the leader and for progress bars.
- Staggered starts —
startDiststarts a walker part-way along, spacing out a wave. - Placement checks —
distanceToTrackkeeps buildings off the route. - Transforms at bake —
flipX,flipYandoffsetmirror and move a whole layout. - Ready to draw — each edge carries a polyline sampled about every 8 units.
- Seeded and saveable — branch streams from a seed, and walker snapshots as JSON.
Good for
- Tower defence, with paths that fork and rejoin and towers that target the leader.
- Patrol routes with forks in a stealth or strategy game.
- Trains and carts on rails, with points the player switches.
- Top-down race circuits, as the centre line racers follow.
- Conveyors and fairground rides that follow a fixed path through a level.
- 3D games on the ground plane, reading the walker's
yas Z.
Make it yours
The network is data, and the walkers take options: from a named spawn, their own rng, a startDist and a choose
policy. The track takes flipX, flipY, offset, samplesPerSegment (48 by default, at least 8) and a default
rng.
Two different uses: a tower-defence map whose path forks round a lake, with three in four walkers taking the top
branch, towers aiming at the walker with the lowest distanceToGoal, and distanceToTrack refusing tower spots too
close to the road; and a train set where a chooser reads a points switch the player flips, on a loop with no goal so
the trains run for ever.
A quick look
A fork weighted three to one, and a walker moving a sprite:
import { Track } from '@phaser-ae/track';
const track = new Track({
nodes: { in: [0, 300], fork: [400, 300], top: [800, 120], bot: [800, 480], out: [1200, 300] },
edges: [
{ from: 'in', to: 'fork' },
{ from: 'fork', to: 'top', via: [{ quad: [[600, 120], [800, 120]] }], weight: 3 },
{ from: 'fork', to: 'bot', via: [{ quad: [[600, 480], [800, 480]] }] },
{ from: 'top', to: 'out' }, { from: 'bot', to: 'out' },
],
}, { rng: game.rng.fork('track') });
const w = track.spawn(140, { startDist: 30 });
game.step('wave', dt => { if (w.advance(dt)) leak(); sprite.x = w.x; sprite.y = w.y; sprite.rotation = w.angle; });
Works with
path-notation— the curve notation its edges are written in.track-racer— top-down circuit racing built on it.steering— free movement and flocking, rather than fixed routes.nav— flow fields for movement across open ground.pseudo-roadandroad-data— pseudo-3D racing roads with splits and merges.rail-route— on-rails camera routes through 3D legs and branches.rail— a chain of balls pushed along one path.
Good to know
- The graph is fixed once built, and only weights change: build a new
Trackfor a new layout. - Edges are one-way; a two-way road is two edges.
distanceToTrackscans every edge: fine for placement checks, not a per-frame query for hundreds of objects.- A walker stops at a goal, and a loop is a graph with no goal.
- There are no events and no collisions between walkers: read
done,edgeanddistanceToGoalafteradvance, and space walkers out withstartDist.






