Skip to content
Plugins (190)

spline

stable

Interpolation and curve functions for animations and paths, including Bezier, Catmull-Rom, Hermite splines, arc-length sampling, and 2D path utilities.

use plugin spline
13 functions Graphics
Runs with the native Zolo host

Plugin snippets can be edited in the Playground, but native capabilities are executed locally with the Zolo CLI.

/ filter jk navigate Esc clear
Functions (13)
  1. lerp Linear interpolation between two values
  2. bezier_quadratic Evaluate a quadratic Bezier curve
  3. bezier_cubic Evaluate a cubic Bezier curve
  4. bezier_tangent Compute the tangent of a cubic Bezier
  5. bezier_point_2d Evaluate a 2D cubic Bezier returning {x,y}
  6. catmull_rom Evaluate a 1D Catmull-Rom spline
  7. catmull_rom_2d Evaluate a 2D Catmull-Rom spline returning {x,y}
  8. hermite Evaluate a cubic Hermite spline
  9. evaluate_path Evaluate a polyline path at parameter t
  10. tangent Get the normalised tangent of a path at t
  11. closest_point Find the closest point on a path to a 2D point
  12. arc_length_estimate Estimate the arc length of a path
  13. sample_uniform Resample a path at evenly-spaced arc lengths

From import to result

  1. 01Import only what you use
  2. 02Copy the smallest example
  3. 03Run it with the Zolo CLI

Overview

spline is a dependency-free math toolkit for interpolation and smooth curves, the kind of work that powers animation easing, camera paths, and motion along a track. It is stateless: there are no handles or objects to keep around — every function takes plain numbers (or a table of {x, y} points) and returns plain numbers or a fresh {x, y} table, so you can call it on the fly inside a render or update loop.

Two layers live here. The low-level scalar evaluators (lerp, bezier_*, catmull_rom, hermite) sample a single curve at a parameter t in [0, 1] and have explicit _2d variants that return a point. The path layer (evaluate_path, tangent, closest_point, arc_length_estimate, sample_uniform) operates over a whole polyline of points, treating t as a normalised position from start (0.0) to end (1.0). Reach for the scalar functions when you control the curve's control points directly, and the path functions when you already have a sequence of points to follow.

Common patterns

Drive a value along a cubic Bezier and orient it with the tangent at the same t:

use plugin spline::{bezier_cubic, bezier_tangent}

let t = 0.35
let value = bezier_cubic(0.0, 0.2, 0.9, 1.0, t)
let slope = bezier_tangent(0.0, 0.2, 0.9, 1.0, t)
print("value={value} slope={slope}")

Walk a 2D path frame by frame, sampling its position and facing direction:

use plugin spline::{evaluate_path, tangent}

let path = [
  #{"x": 0.0, "y": 0.0},
  #{"x": 5.0, "y": 2.0},
  #{"x": 10.0, "y": 0.0}
]
let steps = 4
for i in 0..steps {
  let t = i / steps
  let pos = evaluate_path(path, t)
  let dir = tangent(path, t)
  print("pos=({pos["x"]},{pos["y"]}) facing=({dir["x"]},{dir["y"]})")
}

Measure a path and then drop evenly-spaced markers along it by arc length:

use plugin spline::{arc_length_estimate, sample_uniform}

let path = [
  #{"x": 0.0, "y": 0.0},
  #{"x": 3.0, "y": 4.0},
  #{"x": 6.0, "y": 0.0}
]
print("length: {arc_length_estimate(path, 100)}")
for _, pt in sample_uniform(path, 6) {
  print("marker at x={pt["x"]} y={pt["y"]}")
}

Linear interpolation between two values

Returns the linear interpolation between a and b at parameter t (0.0 = a, 1.0 = b).

use plugin spline::{lerp}

let mid = lerp(0.0, 100.0, 0.5)
print(mid)

let eased = lerp(10.0, 20.0, 0.25)
print(eased)

Stepping t across a loop produces a simple linear animation:

use plugin spline::{lerp}

let steps = 5
for i in 0..steps {
  let t = i / steps
  print("frame {i}: {lerp(0.0, 100.0, t)}")
}

Evaluate a quadratic Bezier curve

Evaluates a quadratic Bezier curve with control points p0, p1, p2 at parameter t.

use plugin spline::{bezier_quadratic}

let y = bezier_quadratic(0.0, 50.0, 100.0, 0.5)
print(y)

Evaluate a cubic Bezier curve

Evaluates a cubic Bezier curve with four control points at parameter t.

use plugin spline::{bezier_cubic}

let v = bezier_cubic(0.0, 0.0, 1.0, 1.0, 0.5)
print(v)

Compute the tangent of a cubic Bezier

Returns the derivative (tangent) of a cubic Bezier at parameter t. Useful for orienting objects moving along a curve.

use plugin spline::{bezier_tangent}

let slope = bezier_tangent(0.0, 0.33, 0.66, 1.0, 0.5)
print("tangent: {slope}")

Evaluate a 2D cubic Bezier returning {x,y}

Evaluates a 2D cubic Bezier curve and returns {x, y} at parameter t.

use plugin spline::{bezier_point_2d}

let pt = bezier_point_2d(0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.5)
print("x={pt["x"]} y={pt["y"]}")

Trace the whole curve by sampling it at several values of t:

use plugin spline::{bezier_point_2d}

let steps = 4
for i in 0..steps {
  let t = i / steps
  let p = bezier_point_2d(0.0, 0.0, 0.0, 10.0, 10.0, 10.0, 10.0, 0.0, t)
  print("({p["x"]}, {p["y"]})")
}

Evaluate a 1D Catmull-Rom spline

Evaluates a Catmull-Rom spline through four control points at t. Passes exactly through p1 and p2, making it useful for smooth paths through known points.

use plugin spline::{catmull_rom}

let v = catmull_rom(0.0, 1.0, 3.0, 4.0, 0.5)
print(v)

Evaluate a 2D Catmull-Rom spline returning {x,y}

Evaluates a 2D Catmull-Rom spline and returns {x, y} at parameter t.

use plugin spline::{catmull_rom_2d}

let pt = catmull_rom_2d(0.0, 0.0, 1.0, 0.0, 2.0, 1.0, 3.0, 1.0, 0.5)
print("x={pt["x"]} y={pt["y"]}")

Evaluate a cubic Hermite spline

Evaluates a cubic Hermite spline between p0 and p1 with tangents m0 and m1 at parameter t. Gives direct control over entry and exit slopes.

use plugin spline::{hermite}

let v = hermite(0.0, 1.0, 1.0, 0.0, 0.5)
print(v)

Evaluate a polyline path at parameter t

Evaluates a polyline path (table of {x, y} points) at normalised parameter t (0.0 = start, 1.0 = end) and returns {x, y}.

use plugin spline::{evaluate_path}

let path = [
  #{"x": 0.0, "y": 0.0},
  #{"x": 1.0, "y": 1.0},
  #{"x": 2.0, "y": 0.0}
]
let pt = evaluate_path(path, 0.5)
print("x={pt["x"]} y={pt["y"]}")

Get the normalised tangent of a path at t

Returns the normalised tangent direction {x, y} of the polyline path at parameter t. Useful for orienting sprites or objects along a path.

use plugin spline::{tangent}

let path = [
  #{"x": 0.0, "y": 0.0},
  #{"x": 1.0, "y": 1.0}
]
let dir = tangent(path, 0.5)
print("dx={dir["x"]} dy={dir["y"]}")

Find the closest point on a path to a 2D point

Finds the closest point on the path to the 2D query point (px, py). Returns {t, distance} where t is the path parameter of the closest point.

use plugin spline::{closest_point}

let path = [
  #{"x": 0.0, "y": 0.0},
  #{"x": 10.0, "y": 0.0}
]
let result = closest_point(path, 5.0, 3.0)
print("t={result["t"]} dist={result["distance"]}")

Feed the returned t back into evaluate_path to get the actual snapped point:

use plugin spline::{closest_point, evaluate_path}

let path = [
  #{"x": 0.0, "y": 0.0},
  #{"x": 10.0, "y": 0.0},
  #{"x": 10.0, "y": 10.0}
]
let hit = closest_point(path, 8.0, 4.0)
let snapped = evaluate_path(path, hit["t"])
print("snapped to x={snapped["x"]} y={snapped["y"]}")

Estimate the arc length of a path

Estimates the arc length of the polyline path by sampling it at segments intervals. Higher segments gives a more accurate result.

use plugin spline::{arc_length_estimate}

let path = [
  #{"x": 0.0, "y": 0.0},
  #{"x": 3.0, "y": 4.0}
]
let length = arc_length_estimate(path, 100)
print("length: {length}")

Resample a path at evenly-spaced arc lengths

Resamples the path into count evenly-spaced points by arc length. Returns a table of {x, y} tables, useful for placing objects uniformly along a curve.

use plugin spline::{sample_uniform}

let path = [
  #{"x": 0.0, "y": 0.0},
  #{"x": 5.0, "y": 0.0},
  #{"x": 10.0, "y": 5.0}
]
let samples = sample_uniform(path, 5)
for _, pt in samples {
  print("x={pt["x"]} y={pt["y"]}")
}

Global index

Find your way through Zolo

Try an idea

Start here

9 results

9 results

en