Skip to content

@web-engine-dev/splines

Comprehensive spline and curve library providing 8 curve types, path utilities, and mesh deformation for the web-engine-dev ecosystem. Used throughout the engine for camera rails, animation curves, terrain paths, procedural geometry, and cinematic sequencing.

Layer 1 · Standalone (no ECS dependency)

Features

  • 8 Curve Types: Bezier, Catmull-Rom, B-Spline, Hermite, NURBS, Linear, Cardinal, Kochanek-Bartels (TCB)
  • Arc-Length Parameterization: Constant-speed traversal via Gauss-Legendre quadrature lookup tables
  • SplinePath: Composite paths from multiple curve segments with automatic knot joining
  • SplineFollower: Entities follow paths with configurable speed, looping, and ping-pong modes
  • SplineMeshDeformer: Bend meshes along spline paths (roads, rivers, pipes)
  • SplineProjector: Nearest-point queries for distance calculations
  • 2D & 3D Support: All utilities work with both 2D and 3D splines
  • Adaptive Sampling: Curvature-based sampling places more points in tight curves

Installation

bash
npm install @web-engine-dev/splines
# or
pnpm add @web-engine-dev/splines

Quick Start

typescript
import { CatmullRomCurve, SplinePath, SplineFollower } from '@web-engine-dev/splines';
import { Vec3 } from '@web-engine-dev/math';

// Create a Catmull-Rom curve through control points
const curve = new CatmullRomCurve([
  new Vec3(0, 0, 0),
  new Vec3(5, 3, 0),
  new Vec3(10, 0, 5),
  new Vec3(15, 2, 0),
]);

// Evaluate position and tangent at parameter t
const position = curve.evaluate(0.5);
const tangent = curve.tangent(0.5);

// Get arc length for constant-speed traversal
const totalLength = curve.arcLength();

// Build a composite path from multiple segments
const path = new SplinePath();
path.addSegment(curve);

// Follow a path at constant speed
const follower = new SplineFollower(path, {
  speed: 5.0,
  loop: true,
  mode: 'pingPong',
});

Curve Types

Curve TypeContinuityBest ForKey Property
BezierC0 (cubic: C1)Artist-controlled paths, UI curvesIntuitive control point manipulation
Catmull-RomC1Camera rails, waypoint pathsPasses through all control points
B-SplineC2Smooth surfaces, animation curvesApproximating — never overshoots
HermiteC1Physics trajectories, controlled arcsExplicit tangent control at endpoints
NURBSC2CAD-quality curves, precise geometryWeighted control — exact circles/conics
CardinalC1Tension-tuned pathsSingle tension parameter (0 = Catmull-Rom)
Kochanek-BartelsC1Animation with overshoot/anticipationTension + Continuity + Bias per point
LinearC0Debug visualization, grid pathsCheapest — no computation needed

Unified Interface

All 8 curve types implement the same SplineCurve interface:

typescript
interface SplineCurve {
  evaluate(t: number): Vec3; // Position at parameter t
  tangent(t: number): Vec3; // Tangent direction at t
  arcLength(): number; // Total arc length
  closestPoint(p: Vec3): number; // Nearest t to point p
}

This means SplineFollower, SplineMeshDeformer, and SplineProjector work identically regardless of curve type. Swapping from Catmull-Rom to B-Spline requires zero consumer code changes.

Arc-Length Parameterization

Raw spline parameters (t = 0 to 1) produce non-uniform speed. Arc-length parameterization builds a lookup table using Gauss-Legendre quadrature that maps uniform distance to the correct t parameter:

typescript
// Without arc-length: entity moves faster through less-curved segments
const raw = curve.evaluate(t);

// With arc-length: constant-speed traversal
const sampler = new SplineSampler(curve);
const uniform = sampler.evaluateAtDistance(distance);

ECS Integration

typescript
import { SplineComponent, SplineFollowerComponent } from '@web-engine-dev/splines';

// Attach a spline to an entity
world.insert(entity, SplineComponent, {
  curve: myCatmullRomCurve,
});

// Make an entity follow a spline path
world.insert(entity, SplineFollowerComponent, {
  speed: 5.0,
  loop: true,
});

Dependencies

  • @web-engine-dev/math — Vector and matrix types

Proprietary software. All rights reserved.