What it does
new Path3d(points) makes a centripetal Catmull-Rom curve through your points, which passes through every one without
the loops and overshoots a plainer spline can make. The curve is baked by arc length, so at(t) and atDist(d) give
an even pace: a rider set to a steady speed really does move steadily, through gentle sweeps and tight bends alike.
frame(t) gives the place and a frame there: the direction of travel, a normal carried along the curve without
flipping, and the third axis between them. That is what you need to orient a car, a train or a camera along the path,
and because the normal is carried rather than recomputed at each point, it does not suddenly twist at the top of a loop
or on a straight. points(count) spreads points evenly along the path for drawing the rail.
DynamicPath3d is the rolling form, for routes nobody authored. Your game adds waypoints ahead as it goes and trims
what is behind, and the rider follows by absolute distance. A segment is only baked once the point after it exists,
so nothing the rider is on reshapes underneath it, and the frame carries on from the last bake, so it never pops when a
point is added.
Features
- Smooth curves through points — centripetal Catmull-Rom, open or closed.
- Even speed — positions by fraction of length or by distance.
- Twist-free frames — direction, normal and binormal at any point, carried along the path.
- Rail drawing — evenly spaced points for a track, a wire or a trail.
- Rolling paths — waypoints added ahead and trimmed behind, ridden by distance without reshaping.
- Pure maths — no world or renderer needed, so it runs in tests and tools.
Good for
- Roller coasters and rail rides, where a car must stay upright through loops and corkscrews.
- Train and tram games on a fixed track.
- Camera fly-throughs for title screens, intros and cut scenes.
- On-rails shooters, where the camera follows a set route through the level.
- Drones and creatures weaving through a city or across a landscape on a route made as they go.
- 3D patrols that loop a closed path.
Make it yours
A Path3d takes its points, whether it is closed, and how many samples to bake per segment (24 by default; more for
smoother frames). A DynamicPath3d takes its sample count (16 by default) and grows as you add points. How the frame
orients your object is your game's choice: forward along the tangent and up along the normal for a coaster car, or the
normal ignored for a camera that should stay level.
Two different uses: a closed coaster circuit laid through a few dozen points, with the car placed and turned by the frame each step; and a drone whose route is extended a waypoint ahead every second and trimmed behind it, ridden at a steady distance per frame.
A quick look
A closed track ridden at a steady speed, with the car oriented by the frame:
const track = new Path3d(points, { closed: true });
step(dt => {
s = (s + speed * dt) % track.length;
const f = track.frame(s / track.length);
car.x = f.x; car.y = f.y; car.z = f.z;
orient(car, [f.tx, f.ty, f.tz], [f.nx, f.ny, f.nz]); // the game's own: the tangent forward, the normal up
});
Works with
steering— agents that steer and follow these paths.path— the 2D equivalent, along any geometry shape.path-notation— 2D routes authored as chained segments.track— networks of curves that branch at junctions.
Good to know
- The curve passes through every point but cannot hold a perfectly straight line; place points close together for a straight stretch.
- A rolling path's ridable end stays about two waypoints behind the last one added.
- It does not move objects for you: your game reads the place and frame and sets its object.






