PathResource
Create reusable, high-performance path data for animations
PathResource provides a reusable, serializable container for SVG path data with pre-baked sampling for O(log n) performance. Share one PathResource across multiple animations for optimal efficiency.
Overview
PathResource solves a common problem: when animating multiple elements along the same path, or sampling a path repeatedly, recalculating path data is wasteful. PathResource pre-bakes the path into evenly-spaced points, enabling:
- O(log n) sampling - Binary search instead of iterating
- Reusability - One resource, many animations
- Serialization - Save/load for .fmtion export
- Rich queries - Position, tangent, closest point, slicing
Creating a PathResource
From SVG Path String
import { PathResource } from 'faster-motion';
const path = new PathResource({
path: 'M 0,100 C 50,0 150,0 200,100 S 350,200 400,100',
bakeInterval: 5, // Distance between baked points (default: 5px)
closed: false // Auto-detected if not specified
});
console.log(path.length); // Total path length in pixelsFrom DOM Element
// From SVG path element
const path = PathResource.fromElement(
document.querySelector('#my-path'),
{ bakeInterval: 5 }
);
// From selector (returns array for multiple matches)
const paths = PathResource.fromSelector('.flight-path');Constructor Options
| Option | Type | Default | Description |
|---|---|---|---|
path | string | SVGPathElement | Required | SVG path data or element |
bakeInterval | number | 5 | Distance between baked points in pixels |
closed | boolean | Auto | Whether path is closed (auto-detected from Z command) |
id | string | Auto | Unique identifier (auto-generated if not provided) |
Sampling Methods
getPointAt(progress)
Sample the path at a normalized position (0-1).
const path = new PathResource({ path: 'M 0,0 L 100,0 L 100,100' });
// Get point at 50% along path
const point = path.getPointAt(0.5);
console.log(point.x, point.y); // Position
console.log(point.angle); // Tangent angle in radians
console.log(point.tangentX); // Normalized tangent X
console.log(point.tangentY); // Normalized tangent Y
console.log(point.progress); // 0.5
console.log(point.distance); // Absolute distance in pixelsTry it: Path Sampling
const path = new PathResource({
path: 'M 50,150 C 50,50 350,50 350,150'
});
// Sample at different positions
[0, 0.25, 0.5, 0.75, 1].forEach(progress => {
const point = path.getPointAt(progress);
// Draw marker at point.x, point.y
});getPointAtDistance(distance)
Sample at an absolute distance along the path.
const point = path.getPointAtDistance(50); // 50 pixels from startgetClosestPoint(x, y)
Find the closest point on the path to any coordinate.
const result = path.getClosestPoint(mouseX, mouseY);
console.log(result.x, result.y); // Closest point on path
console.log(result.progress); // 0-1 position on path
console.log(result.distanceToPoint); // Distance from query pointTry it: Closest Point
const path = new PathResource({
path: 'M 50,100 Q 200,20 350,100 T 650,100'
});
canvas.addEventListener('mousemove', (e) => {
const closest = path.getClosestPoint(e.offsetX, e.offsetY);
// Draw line from mouse to closest.x, closest.y
});getSamples(count)
Get evenly-spaced samples along the path.
// Get 10 evenly-spaced points
const samples = path.getSamples(10);
samples.forEach(sample => {
console.log(sample.x, sample.y, sample.angle);
});getOffsetPoint(progress, offsetX, offsetY)
Get a position offset from the path at a given progress.
// Get point 20px perpendicular to path at 50% progress
const offset = path.getOffsetPoint(0.5, 0, 20);
console.log(offset.x, offset.y);| Parameter | Description |
|---|---|
offsetX | Offset along the tangent direction (forward/backward) |
offsetY | Offset perpendicular to tangent (left/right of path) |
Path Operations
slice(startProgress, endProgress)
Extract a portion of the path as an SVG path string.
// Get the middle 50% of the path
const middlePath = path.slice(0.25, 0.75);
console.log(middlePath); // "M 75,50 L 125,50 ..."Try it: Path Slicing
const path = new PathResource({
path: 'M 50,100 C 150,20 250,180 350,100'
});
// Animate sliders to change start/end
const slicedPath = path.slice(startValue, endValue);
// Render slicedPath to show visible portionreverse()
Create a new PathResource with the path direction reversed.
const reversedPath = path.reverse();
const point = reversedPath.getPointAt(0); // Now at original endsubPath(startProgress, endProgress)
Create a new PathResource from a portion of the path.
// Create PathResource for just the first half
const firstHalf = path.subPath(0, 0.5);
console.log(firstHalf.length); // Half the original lengthProperties
| Property | Type | Description |
|---|---|---|
id | string | Unique identifier |
pathData | string | Original SVG path data |
length | number | Total path length in pixels |
bounds | Bounds | Bounding box { x, y, width, height } |
closed | boolean | Whether path is closed |
center | Vec2 | Center point of bounding box |
pointCount | number | Number of baked points |
baked | BakedPath | Internal baked data (advanced use) |
parsed | ParsedPath | Parsed structure (advanced use) |
const path = new PathResource({
path: 'M 0,0 L 100,0 L 100,100 L 0,100 Z'
});
console.log(path.length); // 400 (perimeter of square)
console.log(path.closed); // true
console.log(path.bounds); // { x: 0, y: 0, width: 100, height: 100 }
console.log(path.center); // { x: 50, y: 50 }Serialization
PathResource can be serialized for storage or .fmtion export.
toJSON()
const json = path.toJSON();
// {
// id: "path-123",
// pathData: "M 0,0 L 100,100",
// closed: false
// }fromJSON()
const restored = PathResource.fromJSON(json);Note: Baked data is not serialized - it's regenerated on load to minimize file size.
Sharing Paths
One of PathResource's key benefits is sharing across multiple animations:
// Create once
const orbitPath = new PathResource({
path: 'M 200,100 A 100,100 0 1,1 200,300 A 100,100 0 1,1 200,100',
closed: true
});
// Use for multiple planets
PathFollow.to('#mercury', { path: orbitPath, duration: 2000 });
PathFollow.to('#venus', { path: orbitPath, duration: 3500 });
PathFollow.to('#earth', { path: orbitPath, duration: 5000 });
// Also use for path visualization
TrimPath.to('#orbit-ring', { path: orbitPath, end: 100 });TypeScript Support
import { PathResource, SampleResult, ClosestPointResult, Bounds } from 'faster-motion';
interface PathResourceOptions {
path: string | SVGPathElement;
bakeInterval?: number;
closed?: boolean;
id?: string;
}
const path: PathResource = new PathResource({
path: 'M 0,0 L 100,100'
});
const sample: SampleResult = path.getPointAt(0.5);
const closest: ClosestPointResult = path.getClosestPoint(50, 50);
const bounds: Bounds = path.bounds;See Also
- Path Sampling - Low-level sampling utilities
- PathFollow - Animate elements along paths
- TrimPath - Animate path stroke visibility