~3 min read

Splines and Procedural Paths

The built-in Splines package in Unity 6, Bezier/B-Spline curves, Cinemachine SplineDolly, and spawning along a path.

Unity 6 has a built-in Splines package (com.unity.splines). Previously, for rail cameras, tracks, and AI patrols you had to write Bezier math by hand or install asset-store plugins. Not anymore.

What the package provides

  • SplineContainer — a node container for one or more curves (Catmull-Rom, Bezier, B-Spline).
  • Spline Tool in the Scene View — you draw points with the mouse and drag tangents.
  • SplineExtrude — extrudes a mesh along a spline (a ready-made road/pipe).
  • SplineInstantiate — places prefabs along a curve (fences, posts, trees).
  • SplineAnimate — animates a Transform along a spline (moving platforms, AI on rails).
  • Cinemachine SplineDolly — a camera on rails.
Web

An SVG path with the M, L, C, Q commands. Or the GSAP MotionPath plugin for animation along a curve.

Unity

A Spline stores control points and tangents, and the engine interpolates. EvaluatePosition(t) / EvaluateTangent(t) give the point and direction at the parameter t ∈ [0, 1].

Basic work with a spline from code

using UnityEngine;
using UnityEngine.Splines;
using Unity.Mathematics;

public class SplineWalker : MonoBehaviour
{
    [SerializeField] private SplineContainer container;
    [SerializeField] private float speed = 2f;

    private float _t;

    private void Update() {
        _t += Time.deltaTime * speed * (1f / container.CalculateLength());
        if (_t > 1f) _t -= 1f;

        // EvaluatePosition / EvaluateTangent work with Unity.Mathematics types
        float3 pos = container.EvaluatePosition(_t);
        float3 tangent = container.EvaluateTangent(_t);

        transform.position = pos;
        if (math.lengthsq(tangent) > 0.0001f) {
            transform.rotation = Quaternion.LookRotation(tangent);
        }
    }
}

The spline itself is created on a GameObject via Add Component → Spline → Spline Container. Then in the Scene View you enable the Spline Tool (T) and place points.

CalculateLength() for constant speed

The parameter t ∈ [0, 1] is the normalized parameter of the spline, not distance. If you just do _t += Time.deltaTime, the speed will be uneven (faster on short segments). Divide by CalculateLength() to get a constant speed in m/s.

SplineAnimate — animation without code

If you want the “simple” way: add a SplineAnimate component to the moving object and assign the spline.

Parameters:

  • Method — Distance / Time / Linear / Ease in/out.
  • Duration / Max Speed — duration or maximum speed.
  • Alignment — None / SplineElement / SplineObject / World — how to orient the object.
  • Loop — Loop / Ping Pong / Once.

Ideal for moving platforms, elevators, and AI on rails.

SplineInstantiate — placing prefabs

A scene with a fence of 30 posts? Previously you placed them by hand in the editor or wrote a script. Now:

  1. Make a single post a prefab.
  2. On the spline, add SplineInstantiate.
  3. In Items, specify the prefab + density.
  4. Click Update — Unity multiplies the posts along the curve.

The Spacing (distance between instances), Position Offset Range, and Rotation Offset Range fields provide randomization for a natural-looking layout.

Cinemachine SplineDolly — a camera on rails

In Cinemachine 3 + Splines there is a ready-made integration:

  1. In the scene — a SplineContainer (draw the camera track).
  2. On the CinemachineCamera, add a CinemachineSplineDolly.
  3. In Spline, set your SplineContainer.
  4. Camera Position — the parameter t (can be animated via Timeline or Animator).
  5. Auto Dolly — automatically follows the Tracking Target and keeps the camera at the nearest point on the spline.
using Unity.Cinemachine;

public class CutsceneCamera : MonoBehaviour
{
    [SerializeField] private CinemachineSplineDolly dolly;
    [SerializeField] private float duration = 5f;

    private float _t;

    public void Play() { _t = 0f; enabled = true; }

    private void Update() {
        _t += Time.deltaTime / duration;
        dolly.CameraPosition = Mathf.Clamp01(_t);
        if (_t >= 1f) enabled = false;
    }
}

Ideal for intro/outro cutscenes, fly-throughs, and moving the camera through a level.

SplineExtrude — procedural roads and pipes

SplineExtrude takes a 2D cross-section (for example, a circle) and sweeps it along the spline. The output is a ready-made mesh.

Use cases:

  • Roads — a thick rectangular cross-section.
  • Pipelines — a circle.
  • Cave walls — an irregular mesh segment.
// Parameters in the Inspector:
// - Spline: SplineContainer
// - Radius: the radius of the extruded mesh
// - Sides: the number of cross-section sides (round = 16+)
// - Range: which part of the spline to extrude
// - Segments per Unit: mesh density
  1. Snap to splineSplineUtility.GetNearestPoint(spline, queryPoint, out float t) finds the nearest point. Used in “snap to road” logic.
  2. Patrol AI along a spline — the enemy patrols via SplineAnimate in Ping Pong mode. EvaluateTangent gives it a direction so it looks forward.
  3. Scrolling parallax — a sprite moves along a spline that provides a non-linear path.
  4. Cursor over a map — a UI element moves along a drawn route curve.

When NOT to use Splines

  • If you only have straight lines — a Vector3 array is cheaper and simpler.
  • Paths that change dynamically every frame — SplineContainer is not optimized for infinite modification (it works, but slower than custom math).
  • Grids of hundreds of splines in a frame — for procedural tracks the Job System is better (see the next chapter).