Skip to main content

curves-and-paths

Use this skill when working with curves and paths in Phaser 4. Covers splines, bezier curves, lines, ellipses, path followers, and mathematical curve types. Triggers on: curve, path, spline, bezier, path follower.

Source facts

Repository
phaserjs/phaser
Last source activity
April 10, 2026 at 12:38
Detected SKILL.md language
English
Stars
40,490
Forks
7,173

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
curves-and-paths
description
Use this skill when working with curves and paths in Phaser 4. Covers splines, bezier curves, lines, ellipses, path followers, and mathematical curve types. Triggers on: curve, path, spline, bezier, path follower.
# Curves and Paths > Creating paths from curves, getting points along them, drawing them with Graphics, and making sprites follow paths automatically using PathFollower in Phaser 4. **Key source paths:** `src/curves/`, `src/curves/path/`, `src/gameobjects/pathfollower/`, `src/gameobjects/components/PathFollower.js` **Related skills:** ../sprites-and-images/SKILL.md, ../graphics-and-shapes/SKILL.md, ../tweens/SKILL.md ## Quick Start ```js // In a Scene's create() method: // 1. Create a Path starting at (50, 300) const path = this.add.path(50, 300); // 2. Add curves to the path path.lineTo(200, 100); path.splineTo([ new Phaser.Math.Vector2(300, 400), new Phaser.Math.Vector2(500, 200) ]); path.lineTo(700, 300); // 3. Draw the path using Graphics const graphics = this.add.graphics(); graphics.lineStyle(2, 0xffffff, 1); path.draw(graphics, 64); // 4. Create a PathFollower sprite that moves along the path const follower = this.add.follower(path, 50, 300, 'ship'); follower.startFollow({ duration: 5000, rotateToPath: true, repeat: -1, yoyo: true }); ``` ## Core Concepts ### Path A `Phaser.Curves.Path` is a container that combines multiple Curves into one continuous compound curve. Curves in a Path do not need to be connected end-to-end. Only the order of curves affects point calculations along the path. Created via factory: `this.add.path(x, y)` where x/y is the starting point. Key properties: - `curves` -- array of `Phaser.Curves.Curve` objects in the Path - `startPoint` -- `Vector2`, the defined starting position - `autoClose` -- boolean, if true `getPoints()` appends the first point at the end - `defaultDivisions` -- number (default: 12), divisions per curve when calling `getPoints()` - `name` -- string, empty by default, for developer use ### Curves All curve types extend `Phaser.Curves.Curve` (the base class). Every curve supports: - `getPoint(t, out)` -- get a point at position t (0-1) based on curve parameterization - `getPointAt(u, out)` -- get a point at position u (0-1) based on arc length (evenly spaced) - `getPoints(divisions, stepRate, out)` -- array of points along the curve - `getSpacedPoints(divisions, stepRate, out)` -- array of equidistant points by arc length - `getDistancePoints(distance)` -- points spaced by pixel distance - `getLength()` -- total arc length in pixels - `getBounds(out, accuracy)` -- bounding Rectangle - `getTangent(t, out)` / `getTangentAt(u, out)` -- unit tangent vector - `getStartPoint(out)` / `getEndPoint(out)` -- first/last points - `getRandomPoint(out)` -- random point on the curve - `draw(graphics, pointsTotal)` -- render the curve onto a Graphics object - `active` -- boolean, when false the parent Path skips this curve ### PathFollower A `Phaser.GameObjects.PathFollower` is a Sprite with the `Components.PathFollower` mixin. It uses an internal Tween (a number counter from 0 to 1) to advance along a Path each frame. Created via factory: `this.add.follower(path, x, y, texture, frame)` The PathFollower component provides: - `path` -- the `Phaser.Curves.Path` being followed - `pathTween` -- the internal Tween driving movement - `pathOffset` -- `Vector2`, offset added to path coordinates - `pathVector` -- `Vector2`, current position on the path - `pathDelta` -- `Vector2`, distance traveled since last frame - `rotateToPath` -- boolean, auto-rotate to face path direction - `pathRotationOffset` -- number (degrees), added to auto-rotation ## Common Patterns ### Creating Paths with Chained Curves Path has convenience methods that create curves starting from the previous end point: ```js const path = this.add.path(100, 500); path.lineTo(300, 100); // straight line path.cubicBezierTo(500, 100, 350, 50, 450, 50); // cubic bezier (endX, endY, cp1X, cp1Y, cp2X, cp2Y) path.quadraticBezierTo(700, 400, 600, 100); // quadratic bezier (endX, endY, cpX, cpY) path.splineTo([ // spline through points new Phaser.Math.Vector2(750, 300), new Phaser.Math.Vector2(600, 500) ]); path.ellipseTo(50, 80, 0, 270, false, 0); // ellipse arc (xRadius, yRadius, startAngle, endAngle, clockwise, rotation) path.circleTo(40); // shortcut for ellipseTo with equal radii and 0-360 // Jump to a new position without drawing (creates a gap) path.moveTo(400, 400); path.lineTo(500, 400); // Close the path by connecting end to start path.closePath(); ``` ### Adding Standalone Curve Objects ```js const path = new Phaser.Curves.Path(0, 0); // Add pre-constructed curve objects const line = new Phaser.Curves.Line(new Phaser.Math.Vector2(0, 0), new Phaser.Math.Vector2(200, 200)); path.add(line); const spline = new Phaser.Curves.Spline([ 200, 200, 300, 100, 400, 300 ]); path.add(spline); const ellipse = new Phaser.Curves.Ellipse(400, 300, 100, 60, 0, 360, false, 0); path.add(ellipse); ``` ### Getting Points Along a Path ```js // Array of points (uses defaultDivisions per curve) const points = path.getPoints(); // With explicit divisions per curve const detailed = path.getPoints(32); // Equally spaced points along the entire path const spaced = path.getSpacedPoints(100); // Single point at normalized position (0-1) const midpoint = path.getPoint(0.5); // Tangent vector at a position const tangent = path.getTangent(0.5); // Total path length in pixels const length = path.getLength(); // Bounding rectangle const bounds = path.getBounds(); ``` ### Drawing Paths with Graphics ```js const graphics = this.add.graphics(); // Draw entire path graphics.lineStyle(2, 0x00ff00, 1); path.draw(graphics, 64); // 64 = points per curve for smoothness // Draw individual curves graphics.lineStyle(1, 0xff0000, 1); path.curves[0].draw(graphics, 32); // Draw debug points const points = path.getSpacedPoints(50); points.forEach(p => { graphics.fillStyle(0xffff00, 1); graphics.fillCircle(p.x, p.y, 3); }); ``` ### PathFollower Sprite ```js const path = this.add.path(100, 200); path.lineTo(400, 400); path.lineTo(700, 200); // Create follower const enemy = this.add.follower(path, 100, 200, 'enemy'); // Start following with config enemy.startFollow({ duration: 3000, // ms to traverse path positionOnPath: true, // snap to path start position rotateToPath: true, // auto-rotate to face direction rotationOffset: 90, // offset added to auto-rotation (degrees) repeat: -1, // -1 = infinite repeat yoyo: true, // reverse on each repeat from: 0, // start position on path (0-1) to: 1, // end position on path (0-1) startAt: 0, // initial seek position ease: 'Sine.easeInOut' // any valid Phaser ease }); // Control during playback enemy.pauseFollow(); enemy.resumeFollow(); enemy.stopFollow(); enemy.isFollowing(); // returns boolean // Change path at runtime enemy.setPath(newPath); enemy.setPath(newPath, { duration: 2000 }); // auto-starts // Set rotation independently enemy.setRotateToPath(true, 90); // (value, offsetDegrees) ``` ### PathFollower with Simple Duration ```js // Shorthand: pass just a duration number enemy.startFollow(5000); // Equivalent to: enemy.startFollow({ duration: 5000 }); ``` ## All Curve Types | Curve | Class | Constructor Params | Description | |---|---|---|---| | Line | `Phaser.Curves.Line` | `(p0, p1)` Vector2 endpoints, or `([x0,y0,x1,y1])` | Straight line segment between two points | | Spline | `Phaser.Curves.Spline` | `(points)` array of Vector2, flat numbers, or nested arrays | Catmull-Rom spline through control points | | CubicBezier | `Phaser.Curves.CubicBezier` | `(p0, p1, p2, p3)` or `([x0,y0,...x3,y3])` | Cubic Bezier with start, 2 control points, end | | QuadraticBezier | `Phaser.Curves.QuadraticBezier` | `(p0, p1, p2)` or `([x0,y0,...x2,y2])` | Quadratic Bezier with start, 1 control point, end | | Ellipse | `Phaser.Curves.Ellipse` | `(x, y, xRadius, yRadius, startAngle, endAngle, clockwise, rotation)` or config object | Elliptical arc; angles in degrees; yRadius defaults to xRadius | ### Ellipse Curve Properties The Ellipse curve has get/set properties for runtime modification: - `x`, `y` -- center position - `xRadius`, `yRadius` -- radii - `startAngle`, `endAngle` -- in degrees (get/set convert to/from radians internally) - `clockwise` -- boolean - `rotation` -- in radians - `angle` -- rotation in degrees (alternative to `rotation`) - `setWidth(value)` / `setHeight(value)` -- sets radius to value/2 ## API Quick Reference ### Path (`Phaser.Curves.Path`) | API | Type | Description | |---|---|---| | `add(curve)` | method | Append any Curve to the path | | `lineTo(x, y)` | method | Add a Line from current end point | | `splineTo(points)` | method | Add a Spline from current end point | | `cubicBezierTo(x, y, cp1X, cp1Y, cp2X, cp2Y)` | method | Add CubicBezier from current end point | | `quadraticBezierTo(x, y, cpX, cpY)` | method | Add QuadraticBezier from current end point | | `ellipseTo(xR, yR, start, end, cw, rot)` | method | Add Ellipse arc from current end point | | `circleTo(radius, clockwise, rotation)` | method | Shortcut for ellipseTo with equal radii | | `moveTo(x, y)` | method | Move end point without drawing (creates gap) | | `closePath()` | method | Add Line from end to start if not already closed | | `getPoint(t, out)` | method | Point at normalized position (0-1) on entire path | | `getPoints(divisions, stepRate)` | method | Array of points, divisions per curve | | `getSpacedPoints(divisions)` | method | Equidistant points along entire path | | `getRandomPoint(out)` | method | Random point anywhere on the path | | `getStartPoint(out)` | method | Path starting point | | `getEndPoint(out)` | method | Path ending point | | `getTangent(t, out)` | method | Unit tangent vector at position t | | `getCurveAt(t)` | method | Return the Curve at normalized position t | | `getLength()` | method | Total path length in pixels | | `getCurveLengths()` | method | Array of cumulative curve lengths | | `getBounds(out, accuracy)` | method | Bounding Rectangle | | `draw(graphics, pointsTotal)` | method | Draw all curves onto a Graphics object | | `toJSON()` / `fromJSON(data)` | method | Serialization | | `updateArcLengths()` | method | Force recalculation of cached lengths | | `destroy()` | method | Clear internal references | ### Base Curve (`Phaser.Curves.Curve`) | API | Type | Description | |---|---|---| | `getPoint(t, out)` | method | Point at parameter t (0-1) -- abstract, each subclass implements | | `getPointAt(u, out)` | method | Point at arc-length position u (0-1) -- evenly spaced | | `getPoints(divisions, stepRate, out)` | method | Array of points | | `getSpacedPoints(divisions, stepRate, out)` | method | Equidistant points by arc length | | `getDistancePoints(distance)` | method | Points spaced by pixel distance | | `getLength()` | method | Total curve arc length | | `getTangent(t, out)` / `getTangentAt(u, out)` | method | Unit tangent vector | | `getTFromDistance(distance)` | method | Convert pixel distance to t value | | `draw(graphics, pointsTotal)` | method | Render onto Graphics (default 32 points) | | `getBounds(out, accuracy)` | method | Bounding Rectangle | | `active` | `boolean` | When false, parent Path skips this curve | | `defaultDivisions` | `number` | Default 5 for standalone curves | | `arcLengthDivisions` | `number` | Precision for arc length calculations (default 100) | ### PathFollower Component | API | Type | Description | |---|---|---| | `setPath(path, config)` | method | Set a new Path (optionally auto-start) | | `startFollow(config, startAt)` | method | Begin following; config = duration number or PathConfig | | `pauseFollow()` | method | Pause movement | | `resumeFollow()` | method | Resume paused movement | | `stopFollow()` | method | Stop following | | `isFollowing()` | method | Returns true if actively moving on path | | `setRotateToPath(value, offset)` | method | Enable/disable auto-rotation with offset | | `path` | `Path` | Current path reference | | `pathTween` | `Tween` | Internal tween driving movement | | `pathOffset` | `Vector2` | Offset from path coordinates | | `pathVector` | `Vector2` | Current position on the path |
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub