spline
stableInterpolation and curve functions for animations and paths, including Bezier, Catmull-Rom, Hermite splines, arc-length sampling, and 2D path utilities.
use plugin spline::{lerp, bezier_quadratic, bezier_cubic, …} Functions (13)
- lerp Linear interpolation between two values
- bezier_quadratic Evaluate a quadratic Bezier curve
- bezier_cubic Evaluate a cubic Bezier curve
- bezier_tangent Compute the tangent of a cubic Bezier
- bezier_point_2d Evaluate a 2D cubic Bezier returning {x,y}
- catmull_rom Evaluate a 1D Catmull-Rom spline
- catmull_rom_2d Evaluate a 2D Catmull-Rom spline returning {x,y}
- hermite Evaluate a cubic Hermite spline
- evaluate_path Evaluate a polyline path at parameter t
- tangent Get the normalised tangent of a path at t
- closest_point Find the closest point on a path to a 2D point
- arc_length_estimate Estimate the arc length of a path
- sample_uniform Resample a path at evenly-spaced arc lengths
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"]}")
}