What it does
A path is written as { start, segments }. Each segment is one shape continuing from the current point: a line to a
point, a quad or cubic bezier, an arc round a centre to an angle (going past 360 degrees keeps orbiting, and a
second radius makes it an ellipse), a spiral whose radius glides to a new size over a number of turns, or a wave
that rides a straight chord while swinging to either side as a sine or a zigzag. Each segment can carry its own ease,
and the whole run can have one too, so an enemy can dawdle in and then whip round a loop.
new Path(data) bakes the route once into arc-length tables. After that, getPoint(t) gives the place a fraction of
the way along by length and getAngle(t) the direction of travel, cheap enough for hundreds of followers to call every
frame, and getPoint can reuse an object you pass so nothing is allocated. Path.fromJSON takes a JSON string or the
data.
The bake can transform the authored coordinates. flipX mirrors every x about a vertical line, flipY every y about a
horizontal one, and offset moves the whole route, so one attack run written for the left of the screen serves the
right as well, and offset copies let a formation fly one route side by side.
Features
- Six segment kinds — lines, quadratic and cubic beziers, elliptical arcs, spirals and sine or zigzag waves.
- Chained — each segment starts where the last ended, so routes read like directions.
- Eases per segment and per run — any named easing from the maths pack, or your own function.
- Plain JSON — for level files, config tables and wave plans.
- Mirror and move —
flipX,flipYandoffset, applied once at the bake. - Even speed — arc-length tables, with the sample count per segment yours to raise.
- Fast queries —
getPointandgetAnglefor many followers every frame.
Good for
- Shoot-'em-ups, with enemy attack runs that loop and swoop, in the style of 1942 or Gradius, mirrored for each side of the screen.
- Wave tables and level files that need routes as data alongside spawn times and enemy types.
- Patrol routes for guards and creatures, written once and reused.
- Racing lines for computer opponents on a circuit.
- Cut-scene moves where a character or camera follows a set route.
Make it yours
The route is the data, so changing a level means editing JSON. Each Path also takes flipX, flipY, offset and
samplesPerSegment (48 by default; more for long or tight segments). Two different uses: a shooter whose wave table
holds one attack run, baked twice, once as written and once with flipX at the centre of the screen, so enemies peel
in from both sides; and a racing game whose computer cars follow a closed circuit of arcs and lines read from the
track's level file.
A quick look
An attack run of a line, an eased arc and a wave, baked as written and mirrored:
import { Path } from '@phaser-ae/path-notation';
const run = { start: [-40, 80], segments: [
{ line: [200, 80] },
{ arc: { center: [200, 160], to: 450 }, ease: 'easeInOutSine' },
{ wave: { to: [520, 300], amplitude: 30, cycles: 3 } },
] };
const fromLeft = new Path(run), fromRight = new Path(run, { flipX: W / 2 });
const p = fromLeft.getPoint(t);
Works with
track— networks of routes with junctions, built from this notation.scrolling-shooter— shooter rules whose enemy routes are written in it.track-racer— racing rules whose circuits are built from it.path— moves an object along a single geometry shape, without authoring a chain.path-3d— for curves in 3D with frames.
Good to know
- It is 2D only.
- A segment is sampled into short straight pieces, so between samples a point lies on the chord; raise
samplesPerSegmentfor long, tight curves. - Eases change where
tlands, so an eased route is no longer even in speed. - It computes places and angles; moving objects along the route is your game's, or a pack built on it.






