Splines: One Smooth Path Through Many Points

A single Bézier curve handles a handful of control points beautifully — but a camera flight, a racing line, or a winding mountain road wants to pass through dozens of waypoints. Pile them all onto one Bézier and the curve turns wild and uncontrollable (high-degree Béziers wobble, and nudging one point warps the whole thing). The fix is a spline: chain many short curve segments end-to-end, each governed by just a few nearby points, into one continuous path. The art is in the joins.

Chaining segments, and the price of the joins

Step 1 — chop the long list into short segments. Given waypoints P_0, P_1, P_2, \dots, P_n, don't fit one giant curve. Fit a sequence of little pieces C_1, C_2, \dots, each a low-degree (usually cubic) curve covering one stretch of the path. Segment C_k ends where segment C_{k+1} begins. Each piece is cheap and local — moving one waypoint disturbs only the segments touching it, not the entire curve.

Step 2 — make the pieces actually meet: C^0. The very least we demand is that consecutive segments share their endpoint, so the path has no gaps:

C_k(1) = C_{k+1}(0).

This is C^0 continuity — the position matches at the join. It is enough to look connected, but the curve can still have a sharp corner there, like two roads meeting at a kink.

Step 3 — kill the kink: match the tangents, C^1. A corner is a sudden change of direction — the velocity vector jumps. Demand instead that the first derivatives agree at the join:

C_k'(1) = C_{k+1}'(0).

Now the pieces leave and arrive along the same tangent line at the same speed: no kink. This is C^1 continuity — smooth direction. For a moving camera or a car, this is usually the minimum that looks right.

Step 4 — match the bend too: C^2. Go one derivative further and require the second derivatives to agree,

C_k''(1) = C_{k+1}''(0),

so the curvature (how hard the path is bending) matches across the join too. This is C^2 continuity — visually very smooth, the gold standard for camera rails and the racing line where even a subtle change in how sharply you're turning would be felt.

Step 5 — but where do the tangents come from? To enforce C^1 we need each join's tangent. Picking these by hand for fifty waypoints is misery. We want a scheme that chooses the tangents for us from the points alone — and, ideally, one whose curve actually touches every waypoint rather than merely drifting near it.

Step 6 — the game favourite: Catmull–Rom. The Catmull–Rom spline does exactly that. It is interpolating — the curve passes through every control point, not just close to it (unlike a plain Bézier's interior handles, which only pull the curve). And it sets each waypoint's tangent automatically from its two neighbours: the tangent at P_i points along the line from the point before it to the point after it,

T_i = \tfrac{1}{2}\,(P_{i+1} - P_{i-1}).

That single rule — "head in the direction your neighbours suggest" — gives a C^1 path through all the points with zero tangent bookkeeping by the author. Drop in a list of points; out comes a smooth, on-the-rails curve. Each segment between P_i and P_{i+1} is a cubic built from the four points P_{i-1}, P_i, P_{i+1}, P_{i+2}, and its endpoint tangents are the T_i, T_{i+1} above — so adjacent segments share a tangent at the shared point, and C^1 comes free.

A spline is one path assembled from many low-degree curve segments joined end-to-end through a long list of control points.

Splines are everywhere a smooth path is needed. A cutscene camera is almost always a Catmull–Rom (or Bézier) spline through a handful of placed keyframes: the designer drops cameras at interesting spots and the spline glides between them.

A racing AI's ideal line is a spline threaded through apexes the designer (or an optimiser) marks around the track — here C^2 matters, because a discontinuity in curvature is a discontinuity in steering, which the physics and the player both feel as a jolt.

And procedural roads and rivers in open worlds are splines through scattered control nodes: the spline defines the centre-line, then a mesh is extruded along it. Same maths, three industries — drop points, demand the right continuity, glide.

Run a point along the whole spline

Five waypoints, one continuous Catmull–Rom curve through all of them. Each interior point's tangent (the faint arrow) is computed from its neighbours by T_i = \tfrac12(P_{i+1}-P_{i-1}) — you never set it. Slide t to run the moving dot along the whole path, segment by segment; it crosses each waypoint exactly when t reaches it. Spread the waypoints out with the slider and watch the curve re-thread them while still passing through each one — that's interpolation, and the smooth handover at every join is C^1 in action.