@blinn-motion/core is the engine every adapter shares. It’s pure and DOM-free; you only need it directly when writing your own adapter or tooling.

Render

sample(doc, t)

Resolve a whole MotionDoc at time t (seconds) into a backend-agnostic RenderNode[] — every transform, color and vertex is a final number.
import { sample } from "@blinn-motion/core";

const tree = sample(doc, 0.8);

computeLayer(layer, t)

Resolve a single layer’s animated state at t → a LayerState. sample is built on this.

walk(tree, fn) · findNode(tree, id)

Traverse or look up resolved nodes.
import { walk, findNode } from "@blinn-motion/core";

walk(tree, (node) => { /* visit every resolved node */ });
const badge = findNode(tree, "badge");

Ticker

The shared playback clock that adapters build their player on. It owns time, looping, rate and the per-frame callback.
import { Ticker, sample } from "@blinn-motion/core";

const ticker = new Ticker({
  duration: doc.duration,  // seconds
  loop: true,
  rate: 1,                 // speed multiplier
  onframe: (t, fraction) => paint(sample(doc, t)),
});

ticker.play();
ticker.pause();
ticker.toggle();
ticker.seek(0.8);
ticker.seekFraction(0.5);
ticker.loop = false;
duration
number
required
Timeline length in seconds.
loop
boolean
default:"false"
Restart at the end.
rate
number
default:"1"
Playback speed multiplier.
onframe
(t: number, fraction: number) => void
Called every frame with current time and progress.

Helpers

The core also exports the pure math the engine runs on:
GroupExports
EasingcubicBezier, springFn, makeEasing, EasingFn
ColorparseColor, rgbaToCss, rgbaToHex, lerpRgba, lerpColor, clamp
InterpolationvalueKind, interp, applyOp, interpKeys, evalTrack
ShapespolygonVertices, starVertices, arcVertices, verticesToClipPath
PaintresolvePaint, resolveStroke, resolveEffects, resolveText
import { cubicBezier, lerpColor, VERSION } from "@blinn-motion/core";

cubicBezier([0.42, 0, 0.58, 1], 0.5);        // eased progress
lerpColor("#3B82F6FF", "#8B5CF6FF", 0.5);    // midpoint color
VERSION;                                      // "0.1.0"
Writing a new adapter? You only need sample (or computeLayer) and Ticker. Everything else is there so you don’t reimplement easing, color or shape math.