animaly
Documentation menu

Reference

API reference

Every export of @animaly/dom 0.1 with its signature, its options and their defaults. Signatures are simplified from the published type definitions.

animate

One function animates elements, motion values, numbers, strings, objects and sequences. The first argument decides which overload applies. Every call returns Controls for all the values it started.

animate overloads
import type { AnimateOptions, Controls, ElementOptions, MotionValue, ObjectValues, Target, ValueKeyframes, ValueOptions, Values } from "@animaly/dom";

declare function animate(target: Target, values: Values, options?: ElementOptions): Controls;
declare function animate<T extends number | string>(value: MotionValue<T>, keyframes: ValueKeyframes<T>, options?: ValueOptions<T>): Controls;
declare function animate(from: number, to: ValueKeyframes<number>, options?: ValueOptions<number>): Controls;
declare function animate(from: string, to: ValueKeyframes<string>, options?: ValueOptions<string>): Controls;
declare function animate<Subject extends object>(target: Subject | readonly Subject[], values: ObjectValues, options?: ValueOptions<Subject>): Controls;

export type { AnimateOptions };
animate elements
import { animate } from "@animaly/dom";

animate(".button", { scale: [1, 0.95, 1], backgroundColor: "#7c3aed" }, { duration: 0.25 });
animate a number
import { animate } from "@animaly/dom";

animate(0, 1, { type: "spring", onUpdate: (latest) => console.log(latest) });
animate a sequence
import { animate } from "@animaly/dom";

animate([
  [".title", { y: [20, 0], opacity: [0, 1] }, { duration: 0.4 }],
  [".lede", { opacity: [0, 1] }, { at: "-0.2" }],
]);

Callbacks

onComplete runs when every value of the call finishes. On elements, onUpdate receives each value and its property name; on values, numbers and objects it receives the latest value or the whole object.

onUpdate on elements gets each value and its name
import { animate } from "@animaly/dom";

animate(".box", { x: 100, opacity: 0.5 }, {
  onUpdate: (latest, name) => console.log(name, latest),
  onComplete: () => console.log("done"),
});

AnimateOptions

type picks the driver. Without it, single values tween and arrays play as keyframes. delay takes seconds or a stagger.

AnimateOptions
import type { Ease, InertiaOptions, KeyframeOptions, SpringOptions } from "@animaly/core";
import type { Stagger } from "@animaly/dom";

type Delay = number | Stagger;

type TweenAnimation = { type?: "tween" | "keyframes"; delay?: Delay } & Omit<KeyframeOptions, "delay">;
type SpringAnimation = { type: "spring"; delay?: Delay } & Omit<SpringOptions, "delay">;
type InertiaAnimation = { type: "inertia"; delay?: Delay } & Omit<InertiaOptions, "delay">;

type AnimateOptions = TweenAnimation | SpringAnimation | InertiaAnimation;

export type { AnimateOptions, Ease };

Tween and keyframes

Tween and keyframe options
OptionTypeDefaultWhat it does
durationnumber0.3Seconds.
easeEase | Ease[]"easeInOut"linear, easeIn, easeOut, easeInOut, four bezier numbers or a function. An array sets one ease per keyframe segment.
timesnumber[]noneOffsets from 0 to 1, one per keyframe.
repeatnumber0How many extra times to play.
repeatType"loop" | "reverse" | "mirror""loop"How each repeat plays.
repeatDelaynumber0Seconds between repeats.
delaynumber | Stagger0Seconds before starting.
Tween options
import { animate } from "@animaly/dom";

animate(".loader", { rotate: 360 }, {
  duration: 1,
  ease: "linear",
  repeat: 4,
  repeatType: "loop",
  repeatDelay: 0,
});

Spring

Spring options
OptionTypeDefaultWhat it does
stiffnessnumber100Higher is snappier.
dampingnumber10Higher settles with less bounce.
massnumber1Higher is heavier and slower.
velocitynumbernoneStarting velocity in units per second. Retargeting keeps the current velocity.
durationnumbernoneSeconds; settles the spring at a fixed duration instead of using stiffness.
restDeltanumbernoneDistance from the target that counts as at rest.
restSpeednumbernoneSpeed below which the spring counts as at rest.
Spring options
import { animate } from "@animaly/dom";

animate(".sheet", { y: 0 }, { type: "spring", stiffness: 300, damping: 30, mass: 1, velocity: 0, restDelta: 0.5 });

Inertia

Inertia options
OptionTypeDefaultWhat it does
velocitynumbernoneStarting velocity in units per second.
powernumber0.8How far the value travels for a given velocity.
timeConstantnumber325Milliseconds; higher glides longer.
min, maxnumbernoneLimits; past them a spring bounces the value back.
bounceStiffnessnumber500Stiffness of that bounce.
bounceDampingnumber10Damping of that bounce.
modifyTarget(ideal) => numbernoneChange where the value comes to rest, for example to snap to a grid.
restDeltanumber0.5Distance that counts as at rest.
Inertia options
import { animate } from "@animaly/dom";

animate(".puck", { x: 0 }, { type: "inertia", velocity: 900, power: 0.8, timeConstant: 325, min: -200, max: 200 });

Controls

time is in seconds and counts from the call, including delays. Negative speed plays backwards, for every driver except inertia. Controls are awaitable.

Controls
type Controls = {
  time: number;
  speed: number;
  readonly duration: number;
  readonly finished: Promise<void>;
  pause(): void;
  play(): void;
  stop(): void;
  complete(): void;
  cancel(): void;
  then(onResolve?: () => unknown, onReject?: (reason: unknown) => unknown): Promise<unknown>;
};

export type { Controls };
Use the controls
import { animate } from "@animaly/dom";

const controls = animate(".panel", { x: 300 }, { duration: 2 });

controls.pause();
controls.time = 0.5;
controls.speed = 2;
controls.play();

await controls.finished;
console.log("done");

stagger

Stagger options
OptionTypeDefaultWhat it does
durationnumber0.1Seconds between neighbours (the first argument).
from"first" | "last" | "center" | number"first"Which element starts.
startDelaynumber0Seconds added to every delay.
easeEasenoneSpreads the delays along an ease instead of evenly.
stagger
import type { Ease } from "@animaly/core";

type StaggerOptions = { startDelay?: number; from?: "first" | "last" | "center" | number; ease?: Ease };

declare function stagger(duration?: number, options?: StaggerOptions): (index: number, total: number) => number;

export type { StaggerOptions };
Stagger from the center
import { animate, stagger } from "@animaly/dom";

animate(".dot", { scale: [1, 1.5, 1] }, { duration: 0.5, delay: stagger(0.08, { from: "center", startDelay: 0.2 }) });
A stagger is a plain function
import { stagger } from "@animaly/dom";

const delay = stagger(0.1, { from: "last" });
console.log([0, 1, 2, 3].map((index) => delay(index, 4).toFixed(1))); // ["0.3", "0.2", "0.1", "0.0"]

Sequences

Pass an array of segments and labels to animate. at takes seconds, "+0.5" or "-0.2" relative to the previous segment, "<" for the previous segment's start, or a label.

Sequences
import type { AnimateOptions, Target, Values } from "@animaly/dom";

type At = number | string;
type Segment = readonly [Target, Values] | readonly [Target, Values, AnimateOptions & { at?: At }];
type Label = string | { name: string; at: At };
type Sequence = readonly (Segment | Label)[];
type SequenceOptions = { repeat?: number; delay?: number; defaultTransition?: AnimateOptions };

export type { Sequence, SequenceOptions };
Sequence options
import { animate } from "@animaly/dom";

animate(
  [
    [".a", { x: 100 }],
    "middle",
    [".b", { x: 100 }, { at: "middle" }],
  ],
  { repeat: 1, delay: 0.2, defaultTransition: { duration: 0.3, ease: "easeOut" } },
);

motionValue

Returns a MotionValue with get, set, jump, getVelocity, getPrevious, isAnimating, stop, destroy and on. See motion values for every method.

motionValue
import type { MotionValue } from "@animaly/dom";

declare function motionValue(initial: number): MotionValue<number>;
declare function motionValue(initial: string): MotionValue<string>;

export type { MotionValue };
Create and animate a motion value
import { animate, motionValue } from "@animaly/dom";

const x = motionValue(0);
x.on("change", (latest) => console.log(latest));
animate(x, 100, { type: "spring" });

createAnimator and sharedAnimator

The exported animate and motionValue use one shared animator. createAnimator makes an independent one with its own engine and settings; sharedAnimator returns the shared one.

Animator options
OptionTypeDefaultWhat it does
schedulerSchedulerbrowser framesWhere frame times come from; pass a ManualScheduler from @animaly/core in tests.
maxAcceleratednumber0How many elements may run as CSS animations at once. The default 0 keeps everything on the JS path; a positive number opts calls that only touch x, y, rotate, scale and opacity into the CSS path.
colorMix"linear" | "squared""linear"How colors are mixed between keyframes.
createAnimator
import type { Scheduler } from "@animaly/core";
import type { Animator } from "@animaly/dom";

type AnimatorOptions = { scheduler?: Scheduler; maxAccelerated?: number; colorMix?: "linear" | "squared" };

declare function createAnimator(options?: AnimatorOptions): Animator;
declare function sharedAnimator(): Animator;

export type { AnimatorOptions };
An animator with its own settings
import { createAnimator } from "@animaly/dom";

const animator = createAnimator({ maxAccelerated: 0, colorMix: "squared" });

animator.animate(".tile", { x: 80, backgroundColor: "#ec4899" }, { duration: 0.4 });
Ask the shared animator about an element
import { animate, sharedAnimator } from "@animaly/dom";

const box = document.querySelector<HTMLElement>(".box")!;
animate(box, { x: 200 }, { duration: 1 });

setTimeout(() => {
  const animator = sharedAnimator();
  console.log(animator.isAnimating(box, "x"), Math.round(animator.valueOf(box, "x") ?? 0));
}, 300);

canAnimate and parseColor

canAnimate(element, name) tells you whether a property name can be animated on an element: transforms, CSS properties, CSS variables and SVG attributes. parseColor returns red, green, blue and alpha.

Check a property name before animating it
import { canAnimate } from "@animaly/dom";

const box = document.querySelector<HTMLElement>(".box")!;

console.log(canAnimate(box, "x")); // true
console.log(canAnimate(box, "--accent")); // true
console.log(canAnimate(box, "notAProperty")); // false
Parse a color into channels
import { parseColor } from "@animaly/dom";

console.log(parseColor("#7c3aed")); // [124, 58, 237, 1]
console.log(parseColor("rgba(236, 72, 153, 0.5)")); // [236, 72, 153, 0.5]

parseColor accepts hex, rgb(), rgba(), hsl() and hsla(). Named colors such as red throw an error.