Skip to content

Animation ​

Animations are declarative: an animate prop carries track specs, they ride the command stream once, and the render thread interpolates every frame per vsync — zero JS work per frame, no React re-render. createAnimation() mints a spec with an attached controller for imperative playback control.

Native animation — interpolated progress demos
tsx
import { createAnimation } from "@scumble/react";
import type { AnimationController, ControlledAnimationSpec } from "@scumble/react";

Every shape (and Canvas/Group) accepts animate with one track per property and many tracks per node. Plain track specs work as-is; null/false array entries are filtered, and an empty array (or null) clears the node's animations.

tsx
import { Canvas, Rect, createAnimation } from "@scumble/react";

const spin = createAnimation({
  property: "rotate",
  from: 0,
  to: 360,
  duration: 3000,
  iterations: Infinity,
});

export function SpinScene() {
  return (
    <Canvas style={{ width: "100%", height: 200 }}>
      <Rect x={60} y={60} width={80} height={80} color="#f59e0b" animate={spin} />
    </Canvas>
  );
}

createAnimation ​

Mint a controllable animation spec: the return value is a plain track spec usable directly as animate, with .controller as the imperative surface. No hooks, no refs — a spec held in user code is stable across re-renders by construction.

ts
function createAnimation(spec: AnimationTrackSpec): ControlledAnimationSpec;

Control dispatches ride the owning canvas's invoke lane (canvases register themselves while mounted; a dispatch broadcasts to every live canvas — the one holding the handle executes). Native completion events fire on the canvas root and are demuxed back to controller.onFinish by handle.

AnimationTrackSpec — track fields ​

FieldTypeDefaultDescription
propertyAnimatedPropertyName—The animated property — one of the 16 below. Required.
fromnumber | Color | [number, number]—Start value — sugar for a two-keyframe track. A [sx, sy] pair for scale; a Color for the color properties.
tonumber | Color | [number, number]—End value. See from.
keyframesKeyframeSpec[]—Explicit keyframes — the alternative to from/to.
durationnumber300Milliseconds per iteration.
delaynumber0Milliseconds before the first iteration.
iterationsnumber1Iteration count; Infinity/negative = infinite.
autoReversebooleanfalseEven iterations forward, odd reversed — CSS alternate.
fill"none" | "forwards""none"What happens after the last iteration: return to base values, or pin the end value.
easingEasingSpec"linear"Track-default easing; keyframes without their own inherit it.
cxnumber0rotate/scale pivot center x.
cynumber0rotate/scale pivot center y.

EasingSpec is a preset name — "linear", "ease-in", "ease-out", "ease-in-out", "step-start", "step-end" — or cubic-bezier control points [x1, y1, x2, y2].

KeyframeSpec — keyframe fields ​

FieldTypeDefaultDescription
offsetnumber—Position within one iteration, [0, 1]. Omitted offsets are evened out; the first/last are pinned to 0/1.
valuenumber—Scalar value slot.
value2number—Second scalar slot — scale's sy.
colorColor—Color slot (the color properties use this instead of the scalars).
easingEasingSpec—Easing of the segment starting at this keyframe; omitted → the track's.

Animatable properties ​

The 16 properties accepted as property (AnimatedPropertyName):

PropertyValue typeNotes
opacitynumber0–1 alpha.
translateXnumberX offset (px).
translateYnumberY offset (px).
rotatenumberDegrees (not radians); pivots at the track's cx/cy.
scalenumber | [number, number]Uniform, or [sx, sy].
pathStartnumber<Path> trim start — [0, 1] path-length fraction.
pathEndnumber<Path> trim end — [0, 1] fraction.
fillColorColorFill color.
strokeColorColorStroke color.
xnumberLeft edge (rect-family, <Image>, <Paragraph>).
ynumberTop edge.
widthnumberWidth.
heightnumberHeight.
cxnumberCenter x (<Circle>, <Ellipse>).
cynumberCenter y.
rnumberRadius (<Circle>).

AnimationController ​

The imperative surface on a createAnimation() spec — the spec itself. Control is node-granular: one handle steers all of the node's tracks.

ts
spin.controller.pause();
spin.controller.seekTo(1500);
spin.controller.onFinish(() => console.log("done"));
MemberSignatureDescription
handlereadonly handle: stringThe minted playback handle — what the native tree registers.
pausepause(): voidFreeze in place (the overlay holds; the driver goes idle).
playplay(): voidResume from the freeze, or restart an idle/finished node from t=0.
seekToseekTo(timeMs: number): voidJump the timeline (ms, delay counts); repaints immediately.
cancelcancel(): voidDrop the tracks and return to base values (fires no finish event).
onFinishonFinish(callback: (() => void) | null): voidSet (or, with null, clear) the natural-completion callback.

ControlledAnimationSpec ​

The return type of createAnimation() — a full AnimationTrackSpec with a minted playback handle and controller attached:

ts
interface ControlledAnimationSpec extends AnimationTrackSpec {
  controller: AnimationController;
}

Hand it to any node's animate prop as-is; use .controller from event handlers for imperative playback control. Plain track specs (without a controller) remain valid animate values — they just run uncontrolled, start to finish.

Released under the Apache License 2.0.