Machine

Machines: an animation as a value. A machine is what an animation does each frame, apart from what drives it: start() it, and the step it returns takes each frame's dt, in seconds, and gives that frame, { value, done }. Each run has its own state, so one machine can run any number of times.

  • Build one with a constructor: tween, spring, chase, decay, inertia, animate, keyframes; for a bag of values, springValues, inertiaValues, animateValues, springBlend and keyframesValues. Or with make, for a motion of your own.
  • Compose with map, concat, concatAll, forever, delay, holdAfter, startAt, clampDt and withSpan. A machine is Pipeable: m.pipe(Machine.delay(0.1)). Never spread one, which loses what makes it a machine.
  • Run one on the Frame loop with run, which steps every running machine in one pass a frame, or as a Stream over the Clock's ticks with toStream. Both give the same frames.
import * as Machine from "@wardic/core/Machine"

const fadeIn = Machine.tween(0, 1, { duration: 0.3, ease: "easeOut" }).pipe(Machine.delay(0.1))
// On the Frame loop, each Frame drawn:
yield* Machine.run(fadeIn, (frame) => {
  draw(frame.value)
})
// Or stepped by hand:
const step = fadeIn.start()
step(1 / 60) // { value: 0, done: false }: still in its delay

Classes

OptionError

Options an animation can't take, a negative duration say: its message names the field and what it expected, Expected a value greater than 0 then at ["stiffness"]. Thrown as the animation is built or started: a bug to fix, not a failure to handle. Machine.OptionError.

Extends

  • YieldableError<this> & object & Readonly<{ message: string; }>

Constructors

Constructor
new OptionError(args): OptionError;
Parameters
args
message

string

Returns

OptionError

Inherited from

Data.TaggedError("OptionError")<{ readonly message: string }>.constructor

Properties

message
message: string;
Inherited from

Data.TaggedError("OptionError").message

Interfaces

AnimateOptions

Options accepted by animate and animateValues.

Extends

Properties

delay?
readonly delay?: number;

Delay before the animation starts, in seconds. With animate's repeat / repeatType, or across keyframes' stops, it holds once, before the first Interval: Machine.delay.

Inherited from

TweenOptions.delay

duration?
readonly duration?: number;

Seconds it takes. Default 0.3.

Inherited from

TweenOptions.duration

ease?
readonly ease?: Definition;

How it eases, as Motion's ease: one of Motion's names ("easeOut"), a cubic Bézier's four numbers ([0.25, 0.1, 0.35, 1]), or a function. Default linear.

Inherited from

TweenOptions.ease

repeat?
readonly repeat?: number;

How many more times it plays after the first: a whole number, or Infinity for ever. Default 0. Each starts the moment the one before ends, or repeatDelay after; delay holds once, before the first.

Inherited from

Modifiers.repeat

repeatDelay?
readonly repeatDelay?: number;

Seconds between plays, as Motion's repeatDelay. Default 0. Each play but the last holds where it ended for this long; with an infinite repeat, every play does.

Inherited from

Modifiers.repeatDelay

repeatType?
readonly repeatType?: "reverse" | "loop" | "mirror";

How every other repeat runs, as Motion's repeatType. Default "loop".

  • "loop": each run starts at from again.
  • "reverse": every other run plays backwards in time, from to to from on the easing's curve reversed: an easeOut run comes back easing in.
  • "mirror": every other run plays from to to from on the same easing: an easeOut run comes back easing out.
Inherited from

Modifiers.repeatType

reverse?
readonly reverse?: boolean;

Plays it from to back to from; keyframes, through their stops from last to first. Default false.

Inherited from

Modifiers.reverse


DecayOptions

A decay's options: how quickly it slows, when it rests, and a delay. A bag is read once and kept by its identity: one changed after it's handed over isn't seen, so pass a new one.

Properties

delay?
readonly delay?: number;

Delay before the animation starts, in seconds.

friction?
readonly friction?: number;

How quickly it slows: higher stops sooner. Default 3.

restSpeed?
readonly restSpeed?: number;

At rest below this speed, per second. Default 0.1.


InertiaEdges

An axis's edges for inertiaVec: either may be left out.

Properties

max?
readonly max?: number;
min?
readonly min?: number;

InertiaOptions

An inertia's options: how far it glides and how it eases out, its edges and the spring back from them, and where it rests. Times in seconds, where Motion's timeConstant is in milliseconds. A bag is read once and kept by its identity: one changed after it's handed over isn't seen, so pass a new one.

Extended by

Properties

bounceDamping?
readonly bounceDamping?: number;

The bounce spring's damping. Default 10.

bounceStiffness?
readonly bounceStiffness?: number;

The bounce spring's stiffness at an edge. Default 500.

max?
readonly max?: number;
min?
readonly min?: number;

The edges: past one, the glide springs back to it. None by default.

modifyTarget?
readonly modifyTarget?: (ideal) => number;

Moves where the glide rests, called once with where it would: snapping a flick to a grid, say.

Parameters
ideal

number

Returns

number

power?
readonly power?: number;

How far the glide carries, as a multiple of the velocity: it rests at initial + power × velocity. Default 0.8.

restDelta?
readonly restDelta?: number;

The glide is done within this of where it rests, and the bounce within this of its edge. Default 0.5.

restSpeed?
readonly restSpeed?: number;

The bounce rests below this speed, per second. Default 2.

timeConstant?
readonly timeConstant?: number;

The glide's time constant, in seconds: it eases out as e^(−t / timeConstant). Default 0.325.


InertiaValuesOptions

inertiaValues' options: InertiaOptions, each key's velocity when it has none of its own, and a delay.

Extends

Properties

bounceDamping?
readonly bounceDamping?: number;

The bounce spring's damping. Default 10.

Inherited from

InertiaOptions.bounceDamping

bounceStiffness?
readonly bounceStiffness?: number;

The bounce spring's stiffness at an edge. Default 500.

Inherited from

InertiaOptions.bounceStiffness

delay?
readonly delay?: number;

Seconds each key holds where it starts before it glides. Default 0.

max?
readonly max?: number;
Inherited from

InertiaOptions.max

min?
readonly min?: number;

The edges: past one, the glide springs back to it. None by default.

Inherited from

InertiaOptions.min

modifyTarget?
readonly modifyTarget?: (ideal) => number;

Moves where the glide rests, called once with where it would: snapping a flick to a grid, say.

Parameters
ideal

number

Returns

number

Inherited from

InertiaOptions.modifyTarget

power?
readonly power?: number;

How far the glide carries, as a multiple of the velocity: it rests at initial + power × velocity. Default 0.8.

Inherited from

InertiaOptions.power

restDelta?
readonly restDelta?: number;

The glide is done within this of where it rests, and the bounce within this of its edge. Default 0.5.

Inherited from

InertiaOptions.restDelta

restSpeed?
readonly restSpeed?: number;

The bounce rests below this speed, per second. Default 2.

Inherited from

InertiaOptions.restSpeed

timeConstant?
readonly timeConstant?: number;

The glide's time constant, in seconds: it eases out as e^(−t / timeConstant). Default 0.325.

Inherited from

InertiaOptions.timeConstant

velocity?
readonly velocity?: number;

A key's velocity when velocity gives it none, per second. Default 0.


InertiaValuesStart

inertiaValues' run: each key's velocity, else the options', per second.

Properties

velocity?
readonly velocity?: Readonly<Record<string, number>>;

InertiaVecOptions

Options for inertiaVec: InertiaOptions for both axes, with each axis's edges.

Extends

Properties

bounceDamping?
readonly bounceDamping?: number;

The bounce spring's damping. Default 10.

Inherited from

InertiaOptions.bounceDamping

bounceStiffness?
readonly bounceStiffness?: number;

The bounce spring's stiffness at an edge. Default 500.

Inherited from

InertiaOptions.bounceStiffness

modifyTarget?
readonly modifyTarget?: (ideal) => number;

Moves where the glide rests, called once with where it would: snapping a flick to a grid, say.

Parameters
ideal

number

Returns

number

Inherited from

InertiaOptions.modifyTarget

power?
readonly power?: number;

How far the glide carries, as a multiple of the velocity: it rests at initial + power × velocity. Default 0.8.

Inherited from

InertiaOptions.power

restDelta?
readonly restDelta?: number;

The glide is done within this of where it rests, and the bounce within this of its edge. Default 0.5.

Inherited from

InertiaOptions.restDelta

restSpeed?
readonly restSpeed?: number;

The bounce rests below this speed, per second. Default 2.

Inherited from

InertiaOptions.restSpeed

timeConstant?
readonly timeConstant?: number;

The glide's time constant, in seconds: it eases out as e^(−t / timeConstant). Default 0.325.

Inherited from

InertiaOptions.timeConstant

x?
readonly x?: InertiaEdges;
y?
readonly y?: InertiaEdges;

KeyframesOptions

keyframes' and keyframesValues' options: a tween's, its ease one easing or one per stretch between stops (wrapping round when there are fewer, as Motion's), each stop's place in times, and the repeats, over the whole run of stops.

Extends

Properties

delay?
readonly delay?: number;

Delay before the animation starts, in seconds. With animate's repeat / repeatType, or across keyframes' stops, it holds once, before the first Interval: Machine.delay.

Inherited from

TweenOptions.delay

duration?
readonly duration?: number;

Seconds it takes. Default 0.3.

Inherited from

TweenOptions.duration

ease?
readonly ease?: 
  | Definition
  | readonly Definition[];
repeat?
readonly repeat?: number;

How many more times it plays after the first: a whole number, or Infinity for ever. Default 0. Each starts the moment the one before ends, or repeatDelay after; delay holds once, before the first.

Inherited from

Modifiers.repeat

repeatDelay?
readonly repeatDelay?: number;

Seconds between plays, as Motion's repeatDelay. Default 0. Each play but the last holds where it ended for this long; with an infinite repeat, every play does.

Inherited from

Modifiers.repeatDelay

repeatType?
readonly repeatType?: "reverse" | "loop" | "mirror";

How every other repeat runs, as Motion's repeatType. Default "loop".

  • "loop": each run starts at from again.
  • "reverse": every other run plays backwards in time, from to to from on the easing's curve reversed: an easeOut run comes back easing in.
  • "mirror": every other run plays from to to from on the same easing: an easeOut run comes back easing out.
Inherited from

Modifiers.repeatType

reverse?
readonly reverse?: boolean;

Plays it from to back to from; keyframes, through their stops from last to first. Default false.

Inherited from

Modifiers.reverse

times?
readonly times?: readonly number[];

Each stop's place in the run, from 0 (its start) to 1 (its duration), in order, as Motion's times: [0, 0.2, 1] reaches the second of three stops a fifth of the way in. Used when there's one per stop; otherwise the stops are evenly spaced.


Machine

An animation as a value: what it does each frame, apart from what drives it. Build one with a constructor or make, never as a literal: a literal, or a spread of a machine, isn't one.

Extends

  • Pipeable
  • Inspectable

Type Parameters

F

F extends Frame<unknown>

Properties

~@wardic/core/Machine
readonly "~@wardic/core/Machine": object;
_F
readonly _F: Covariant<F>;
settles
readonly settles: boolean;

Whether a run ends at its first settled Frame. chase doesn't: its Frame reports rest, but the run goes on until it's removed. Nor does forever, whose Frames never settle.

span
readonly span: Span;

The span each run gets, on either driver: its name and attributes, for traces and logs.

start
readonly start: () => (dt) => F;

One run: a step from each tick's dt (seconds, as the Clock reports it) to that tick's Frame. Each run holds its own state, so a machine can be started any number of times.

Returns

(dt) => F


Modifiers

How a tween repeats: repeat, repeatType and repeatDelay, and reverse.

Extended by

Properties

repeat?
readonly repeat?: number;

How many more times it plays after the first: a whole number, or Infinity for ever. Default 0. Each starts the moment the one before ends, or repeatDelay after; delay holds once, before the first.

repeatDelay?
readonly repeatDelay?: number;

Seconds between plays, as Motion's repeatDelay. Default 0. Each play but the last holds where it ended for this long; with an infinite repeat, every play does.

repeatType?
readonly repeatType?: "reverse" | "loop" | "mirror";

How every other repeat runs, as Motion's repeatType. Default "loop".

  • "loop": each run starts at from again.
  • "reverse": every other run plays backwards in time, from to to from on the easing's curve reversed: an easeOut run comes back easing in.
  • "mirror": every other run plays from to to from on the same easing: an easeOut run comes back easing out.
reverse?
readonly reverse?: boolean;

Plays it from to back to from; keyframes, through their stops from last to first. Default false.


PointPhysics

A two-axis inertia's frame: its point, and each axis's velocity there.

Extends

Properties

done
readonly done: boolean;

Whether it has settled: true on its last Frame.

Inherited from

Frame.done

value
readonly value: Point;

The value this tick.

Inherited from

Frame.value

velocity
readonly velocity: Point;

ResolvedTween

A tween's options with every default filled in.

Properties

delay
readonly delay: number;

Seconds before it moves.

duration
readonly duration: number;

The duration, at least Number.EPSILON, so a zero duration still divides.

ease
readonly ease: Easing;

Its ease, resolved to the curve.

seconds
readonly seconds: number;

The duration as given (0 for an instant tween): its span's, and what keyframes splits.


RunOptions

run's options: the token the run joins, so Supersede.end ends it with the others.

Properties

supersede
readonly supersede: Supersede;

Span

A machine's span: a name and its attributes, opened by a driver once per run.

Properties

attributes
readonly attributes: Readonly<Record<string, unknown>>;
name
readonly name: string;

SpanOptions

withSpan's options, Effect's { attributes }.

Properties

attributes?
readonly attributes?: Readonly<Record<string, unknown>>;

SpringOptions

A spring's options: its physics (stiffness, damping, mass) or its time (duration or visualDuration, with bounce), where it starts and how fast, its rest thresholds, and a delay. A bag is read once and kept by its identity: one changed after it's handed over isn't seen, so pass a new one.

Extended by

Properties

bounce?
readonly bounce?: number;

How much a spring set by time bounces: 0 none, toward 1 a lot. Default 0.3 with a duration, 0 with a visualDuration; alone, it's a 0.8 s duration spring.

damping?
readonly damping?: number;

How damped it is: higher settles sooner, with less overshoot. Default 26.

delay?
readonly delay?: number;

Delay before the animation starts, in seconds.

duration?
readonly duration?: number;

A spring set by time: it lands on its target at duration seconds, from rest, its stiffness and damping solved from it and bounce. Within 0.01 to 10 s. A stiffness, damping or mass given beside wins over it, and so does a visualDuration.

from?
readonly from?: number;

Where it starts. Default 0.

mass?
readonly mass?: number;

The mass it moves: heavier is slower. Default 1.

restDelta?
readonly restDelta?: number;

At rest within this of its target. By default, as Motion's: 0.5 for a move of 5 or more, 0.005 for one shorter (an opacity, a scale, a nudge), by each value's distance each time its target changes.

restSpeed?
readonly restSpeed?: number;

At rest below this speed, per second. By default, as Motion's: 2 for a move of 5 or more, 0.01 for one shorter.

stiffness?
readonly stiffness?: number;

How stiff it is: higher is snappier. Default 170.

velocity?
readonly velocity?: number;

The velocity it starts with, per second. Default 0.

visualDuration?
readonly visualDuration?: number;

A spring set by time that has done most of its move by visualDuration seconds, and ends at rest after, keeping the velocity it's handed. With bounce, or alone.


SpringValuesStart

springValues' run: each key's start and velocity, else the options'.

Properties

from?
readonly from?: Readonly<Record<string, number>>;
velocity?
readonly velocity?: Readonly<Record<string, number>>;

TweenOptions

A tween's options: its duration, ease and delay. A bag is read once and kept by its identity: one changed after it's handed over isn't seen, so pass a new one.

Extended by

Properties

delay?
readonly delay?: number;

Delay before the animation starts, in seconds. With animate's repeat / repeatType, or across keyframes' stops, it holds once, before the first Interval: Machine.delay.

duration?
readonly duration?: number;

Seconds it takes. Default 0.3.

ease?
readonly ease?: Definition;

How it eases, as Motion's ease: one of Motion's names ("easeOut"), a cubic Bézier's four numbers ([0.25, 0.1, 0.35, 1]), or a function. Default linear.

Variables

CATCH_UP_DT

const CATCH_UP_DT: number;

The step startAt catches up in: a 60 Hz frame.


clampDt

const clampDt: {
  (max): <F>(self) => Machine<F>;
  <F>(self, max): Machine<F>;
};

self with each dt held to max before its step: for a machine built with make. The constructors hold theirs to MAX_DT.

Call Signature

(max): <F>(self) => Machine<F>;
Parameters
max

number

Returns

<F>(self) => Machine<F>

Call Signature

<F>(self, max): Machine<F>;
Type Parameters
F

F extends Frame<unknown>

Parameters
self

Machine<F>

max

number

Returns

Machine<F>


concat

const concat: {
  <G>(that): <F>(self) => Machine<G | F>;
  <F, G>(self, that): Machine<F | G>;
};

that after self, on the frame after self settles: concatAll of the two. A self that never settles never reaches that. Keeps self's span.

Call Signature

<G>(that): <F>(self) => Machine<G | F>;
Type Parameters
G

G extends Frame<unknown>

Parameters
that

Machine<G>

Returns

<F>(self) => Machine<G | F>

Call Signature

<F, G>(self, that): Machine<F | G>;
Type Parameters
F

F extends Frame<unknown>

G

G extends Frame<unknown>

Parameters
self

Machine<F>

that

Machine<G>

Returns

Machine<F | G>

Example

const trip = there.pipe(Machine.concat(back))

delay

const delay: {
  (seconds): <F>(self) => Machine<F>;
  <F>(self, seconds): Machine<F>;
};

A wait before self starts: for seconds, each frame is the frame self starts at; then self steps on with the time left over. A negative seconds starts it that far in. delay(0) is self. Keeps self's span.

Call Signature

(seconds): <F>(self) => Machine<F>;
Parameters
seconds

number

Returns

<F>(self) => Machine<F>

Call Signature

<F>(self, seconds): Machine<F>;
Type Parameters
F

F extends Frame<unknown>

Parameters
self

Machine<F>

seconds

number

Returns

Machine<F>

Example

const late = Machine.spring(1).pipe(Machine.delay(0.2))

holdAfter

const holdAfter: {
  (seconds): <F>(self) => Machine<F>;
  <F>(self, seconds): Machine<F>;
};

A wait after self settles: its settled frame for seconds more, then it settles. A self that never settles, or a hold of 0 or less, is returned as it is. Keeps self's span.

Call Signature

(seconds): <F>(self) => Machine<F>;
Parameters
seconds

number

Returns

<F>(self) => Machine<F>

Call Signature

<F>(self, seconds): Machine<F>;
Type Parameters
F

F extends Frame<unknown>

Parameters
self

Machine<F>

seconds

number

Returns

Machine<F>

Example

const pause = Machine.tween(0, 1, { duration: 0.3 }).pipe(Machine.holdAfter(1))

keyframesValues

const keyframesValues: (stops, options?) => Effect.Effect<Machine<Frame<Values>>, never, InterpolatorRegistry>;

A bag of values through each key's stops, as Motion's keyframes, each key blended as its Environment blends it, as animateValues' are. One run drives every key: its duration, ease (one, or one per stretch) and repeats are the bag's. Each key has its own stops, at their places in times when there's one per stop, evenly spaced otherwise. A key with one stop holds it, and one with none is left out. Building it needs the InterpolatorRegistry, once.

Parameters

stops

Readonly<Record<string, ReadonlyArray<number | string>>>

options?

KeyframesOptions

Returns

Effect.Effect<Machine<Frame<Values>>, never, InterpolatorRegistry>


map

const map: {
  <F, G>(f): (self) => Machine<G>;
  <F, G>(self, f): Machine<G>;
};

self with each frame mapped by f. Keeps self's span.

Call Signature

<F, G>(f): (self) => Machine<G>;
Type Parameters
F

F extends Frame<unknown>

G

G extends Frame<unknown>

Parameters
f

(frame) => G

Returns

(self) => Machine<G>

Call Signature

<F, G>(self, f): Machine<G>;
Type Parameters
F

F extends Frame<unknown>

G

G extends Frame<unknown>

Parameters
self

Machine<F>

f

(frame) => G

Returns

Machine<G>

Example

const turn = Machine.spring(1).pipe(Machine.map((frame) => ({ ...frame, value: frame.value * 360 })))

MAX_DT

const MAX_DT: 0.5 = 0.5;

The most time a machine moves in one step: 0.5 s. A frame that took longer, such as the first after the app was hidden, moves it 0.5 s, and the animation plays the rest out from there, where Motion's jumps to its end. Every constructor holds each step to it.


MAX_DURATION

const MAX_DURATION: 20 = 20;

How long durationOf lets a run go to settle: 20 s, as Motion's maxGeneratorDuration.


resolveTween

const resolveTween: (options) => ResolvedTween;

A tween's options with its defaults filled in: 0.3 s, no delay, linear. A negative or non-finite duration or delay, or an ease that's none of Motion's names, four numbers or a function, throws an OptionError. For a tween you step yourself, as @wardic/dom's layout animations do. A bag is resolved once and kept by its identity: one changed after it's handed over isn't seen, so pass a new one.

Parameters

options

TweenOptions

Returns

ResolvedTween


run

const run: {
  <F>(sink): (self) => Effect<F, never, FrameLoop>;
  <F>(sink, options): (self) => Effect<F | typeof Superseded, never, FrameLoop>;
  <F>(self, sink): Effect<F, never, FrameLoop>;
  <F>(self, sink, options): Effect<F | typeof Superseded, never, FrameLoop>;
};

Runs self on the Frame loop, from its next tick, handing each frame to sink. It succeeds with the settled frame; one that never settles runs until it's interrupted, and interrupting removes it at once. A frame handed to sink is the run's until the next tick: copy one to keep it. Given { supersede }, it ends with the other runs given the same token, succeeding with Supersede.Superseded.

Call Signature

<F>(sink): (self) => Effect<F, never, FrameLoop>;
Type Parameters
F

F extends Frame<unknown>

Parameters
sink

Sink<F>

Returns

(self) => Effect<F, never, FrameLoop>

Call Signature

<F>(sink, options): (self) => Effect<F | typeof Superseded, never, FrameLoop>;
Type Parameters
F

F extends Frame<unknown>

Parameters
sink

Sink<F>

options

RunOptions

Returns

(self) => Effect<F | typeof Superseded, never, FrameLoop>

Call Signature

<F>(self, sink): Effect<F, never, FrameLoop>;
Type Parameters
F

F extends Frame<unknown>

Parameters
self

Machine<F>

sink

Sink<F>

Returns

Effect<F, never, FrameLoop>

Call Signature

<F>(
   self, 
   sink, 
   options
): Effect<F | typeof Superseded, never, FrameLoop>;
Type Parameters
F

F extends Frame<unknown>

Parameters
self

Machine<F>

sink

Sink<F>

options

RunOptions

Returns

Effect<F | typeof Superseded, never, FrameLoop>

Example

const landed = yield* Machine.run(Machine.spring(200), (frame) => {
  moveTo(frame.value)
})

startAt

const startAt: {
  (at): <F>(self) => Machine<F>;
  <F>(self, at): Machine<F>;
};

self started partway through: its first frame steps it from its start to at() seconds in, a 60 Hz frame at a time, and every frame after steps as usual. at is read once a run, at its first frame. A negative at() is a start still to come: it holds at its start that long. For an animation that began before the app's code loaded, as a server-rendered one does, taken over where it has got to. Keeps self's span, and whether it settles.

Call Signature

(at): <F>(self) => Machine<F>;
Parameters
at

LazyArg<number>

Returns

<F>(self) => Machine<F>

Call Signature

<F>(self, at): Machine<F>;
Type Parameters
F

F extends Frame<unknown>

Parameters
self

Machine<F>

at

LazyArg<number>

Returns

Machine<F>

Example

const resumed = Machine.tween(0, 1, { duration: 1 }).pipe(Machine.startAt(() => elapsedSeconds))

withSpan

const withSpan: {
  (name, options?): <F>(self) => Machine<F>;
  <F>(self, name, options?): Machine<F>;
};

self under the span name, with options.attributes, in place of its own: its runs' traces and logs carry that name.

Call Signature

(name, options?): <F>(self) => Machine<F>;
Parameters
name

string

options?

SpanOptions

Returns

<F>(self) => Machine<F>

Call Signature

<F>(
   self, 
   name, 
   options?
): Machine<F>;
Type Parameters
F

F extends Frame<unknown>

Parameters
self

Machine<F>

name

string

options?

SpanOptions

Returns

Machine<F>

Example

const bounce = Machine.spring(1).pipe(Machine.withSpan("app.bounce", { attributes: { card: id } }))

Functions

animate()

function animate(
   from, 
   to, 
   options?
): Machine<Frame<number>>;

A tween that repeats: repeat plays it again, repeatType turns every other play ("reverse", "mirror"), and reverse swaps its ends. delay holds once, before the first play, as Motion's does, and repeatDelay after each play but the last, where it ended. Each play starts the moment the one before ends; a finite repeat settles once the last ends, and repeat: Infinity never settles.

Parameters

from

number

to

number

options?

AnimateOptions = NO_OPTIONS

Returns

Machine<Frame<number>>

Example

const breathe = Machine.animate(1, 1.08, { duration: 1.2, ease: "easeInOut", repeat: Infinity, repeatType: "mirror" })

animateValues()

function animateValues(
   from, 
   to, 
   options?
): Effect<Machine<Frame<Values>>, never, InterpolatorRegistry>;

A bag of values tweened from from to to, each key blended as its Environment blends it: numbers, unit strings, complex values, and its own kinds, such as @wardic/dom's colours. One tween drives every key, so the repeats and delay apply to the whole bag. A pair that can't blend switches at the first frame; the Environment can hold a key until the last, as @wardic/dom does a key that hides an element. Building it needs the InterpolatorRegistry, once.

Parameters

from

Readonly<Values>

to

Readonly<Values>

options?

AnimateOptions = NO_OPTIONS

Returns

Effect<Machine<Frame<Values>>, never, InterpolatorRegistry>

Example

const fade = yield* Machine.animateValues({ opacity: 0, color: "#bf616a" }, { opacity: 1, color: "#a3be8c" }, { duration: 0.3 })

chase()

function chase(getTarget, options?): Machine<Physics>;

A spring that follows a moving target: getTarget() is read every step, so it tracks a cursor, a scroll position or a target that changes often. Its frames report rest, but it never settles: a run ends only when it's removed.

Parameters

getTarget

() => number

options?

SpringOptions = NO_OPTIONS

Returns

Machine<Physics>

Example

const follow = Machine.chase(() => pointer.x, Spring.gentle)

concatAll()

function concatAll<F>(intervals): Machine<F>;

Machines played one after another, as one run: each starts on the frame after the one before it settles, so a long sequence runs up to a frame a seam behind wall time. For tweens back to back, exactly on time, use keyframes. A machine that never settles, a chase or a forever, is the last one reached. One machine is returned as it is. Keeps the first's span.

Type Parameters

F

F extends Frame<unknown>

Parameters

intervals

readonly [Machine<F>, Machine<F>]

Returns

Machine<F>

Example

const there = Machine.tween(0, 100, { duration: 0.3 })
const back = Machine.tween(100, 0, { duration: 0.3 })
const trip = Machine.concatAll([there, back])

decay()

function decay(
   initial, 
   velocity, 
   options?
): Machine<Physics>;

A decay: from initial at velocity, slowing by friction, to rest velocity / friction away, whatever the frame rate.

Parameters

initial

number

velocity

number

options?

DecayOptions = NO_OPTIONS

Returns

Machine<Physics>

Example

const coast = Machine.decay(x, 900, { friction: 4 })

decayVec()

function decayVec(
   initial, 
   velocity, 
   options
): Machine<Frame<Point>>;

A decay on two axes together: a point each frame, settling once both rest.

Parameters

initial

Point

velocity

Point

options

DecayOptions

Returns

Machine<Frame<Point>>


durationOf()

function durationOf<F>(self): number;

How long a run of self takes to settle, in seconds: Infinity for one that doesn't, a chase or a forever, or hasn't by MAX_DURATION. It runs the machine to find out, up to 1,200 steps a call.

Type Parameters

F

F extends Frame<unknown>

Parameters

self

Machine<F>

Returns

number

Example

Machine.durationOf(Machine.spring(1, Spring.gentle)) // ≈ 1.1

forever()

function forever<F>(self): Machine<F>;

self started again each time it settles, for ever, so a run never settles. Each restart is up to a frame behind wall time; animate's repeat: Infinity is exact. A self that never settles is returned as it is. Keeps self's span.

Type Parameters

F

F extends Frame<unknown>

Parameters

self

Machine<F>

Returns

Machine<F>


inertia()

function inertia(
   initial, 
   velocity, 
   options?
): Machine<Physics>;

An inertia: a glide from initial at velocity toward initial + power × velocity, or where modifyTarget moves that, easing out over timeConstant; where it would pass min or max, or starts past one, it springs back to that edge. What a drag's release runs.

Parameters

initial

number

velocity

number

options?

InertiaOptions = NO_OPTIONS

Returns

Machine<Physics>

Example

// A flick that rests on a 100 px grid, within 0 and 800.
const snap = Machine.inertia(x, velocity, { modifyTarget: (end) => Math.round(end / 100) * 100, min: 0, max: 800 })

inertiaValues()

function inertiaValues(
   from, 
   options?, 
   start?
): Machine<MultiPhysics>;

Inertia on a bag of numbers, as a transition's type: "inertia": one glide per key from from, at its velocity in start.velocity (else options.velocity, else 0), on the shared options, after options.delay, settling once every key rests. It takes no target: each key rests where its glide does, through modifyTarget, held within min and max. With no velocity, a key rests where it starts.

Each frame carries a per-key velocity beside value, and is rewritten every tick: copy a frame to keep it.

Parameters

from

Readonly<Record<string, number>>

options?

InertiaValuesOptions = NO_OPTIONS

start?

InertiaValuesStart = NO_START

Returns

Machine<MultiPhysics>


inertiaVec()

function inertiaVec(
   initial, 
   velocity, 
   options?
): Machine<PointPhysics>;

Inertia on two axes together: a point each frame, each axis with its own edges, settling once both rest. What a drag's release runs; an animation that takes the release over starts from its velocity.

Parameters

initial

Point

velocity

Point

options?

InertiaVecOptions = NO_OPTIONS

Returns

Machine<PointPhysics>


isMachine()

function isMachine(u): u is Machine<Frame<unknown>>;

Whether u is a machine (built by make or a constructor).

Parameters

u

unknown

Returns

u is Machine<Frame<unknown>>


keyframes()

function keyframes(stops, options?): Machine<Frame<number>>;

A tween through a list of stops, as Motion's keyframes: each stretch between two stops eased whole by ease (one, or one per stretch, wrapping round), each stop at its place in times (evenly spaced without one per stop). The repeats run the whole list: repeat plays it again, "reverse" plays every other pass backwards, "mirror" every other pass through the stops from last to first, and reverse every pass so. One stop, or none, holds still. delay holds once, before the first.

Parameters

stops

readonly number[]

options?

KeyframesOptions = NO_OPTIONS

Returns

Machine<Frame<number>>

Example

const shake = Machine.keyframes([0, -12, 12, -6, 6, 0], { duration: 0.5 })

make()

function make<F>(fields): Machine<F>;

A machine from its fields: a run's start, whether it settles, and its span. For a motion of your own; the constructors cover the common ones.

Type Parameters

F

F extends Frame<unknown>

Parameters

fields
settles

boolean

span

Span

start

() => (dt) => F

Returns

Machine<F>

Example

// A blink: 1 and 0 by turns, twice a second, for ever.
const blink = Machine.make({
  settles: false,
  span: { name: "app.blink", attributes: {} },
  start: () => {
    let time = 0
    return (dt) => {
      time += dt
      return { value: Math.floor(time * 2) % 2, done: false }
    }
  },
})

spring()

function spring(target, options?): Machine<Physics>;

A spring toward target, from options.from (0 by default), settling at rest. A moving target is chase's.

Parameters

target

number

options?

SpringOptions = NO_OPTIONS

Returns

Machine<Physics>

Example

const pop = Machine.spring(1, { from: 0.8, stiffness: 400, damping: 15 })

springBlend()

function springBlend(
   from, 
   to, 
   options?
): Effect<Machine<Frame<Values>>, never, InterpolatorRegistry>;

A bag of values blended from from to to by one spring's progress: the spring runs from rest on a 0 to 100 progress, and each key is blended at progress / 100. It's how a spring moves values that aren't numbers, a colour or a unit string, as Motion's spring does.

  • The progress spans 0 to 100, as a number going 100 would, so restDelta and restSpeed mean the same for both, and a string key beside an x going 0 to 100 lands with it.
  • It starts from rest: options.from and options.velocity don't move it.
  • Past 1, a key does what its blend does past 1: a number or a unit string overshoots, and @wardic/dom's colour holds at its target. A pair that can't blend switches at its first frame.

Parameters

from

Readonly<Values>

to

Readonly<Values>

options?

SpringOptions = NO_OPTIONS

Returns

Effect<Machine<Frame<Values>>, never, InterpolatorRegistry>


springValues()

function springValues(
   target, 
   options?, 
   start?
): Machine<MultiPhysics>;

A bag of numbers sprung toward target: one spring per key on the shared options, from start's from and velocity (else options.from and options.velocity, else 0), settling once every key rests.

Each frame carries a per-key velocity beside value; a settled key reports 0. Seeding from and velocity from a frame of the run before keeps its velocity when the target changes. Each frame is rewritten every tick: copy one, or its records, to keep it; the settled frame is stable.

Parameters

target

Readonly<Record<string, number>>

options?

SpringOptions = NO_OPTIONS

start?

SpringValuesStart = NO_START

Returns

Machine<MultiPhysics>

Example

const card = Machine.springValues({ x: 120, y: 40, scale: 1.1 }, Spring.stiff, { from: { x: 0, y: 0, scale: 1 } })

toStream()

function toStream<F>(self): Stream<F, never, Clock>;

self as a Stream over the Clock's ticks: a frame a tick, through its settled frame when it settles. Each subscriber gets a run of its own, and each frame is its to keep. For one value in an Effect program; run steps every running machine in one pass a frame, which is cheaper for many.

Type Parameters

F

F extends Frame<unknown>

Parameters

self

Machine<F>

Returns

Stream<F, never, Clock>

Example

yield* Machine.toStream(fadeIn).pipe(Stream.runForEach((frame) => Effect.sync(() => draw(frame.value))))

tween()

function tween(
   from, 
   to, 
   options
): Machine<Frame<number>>;

A tween from from to to over options.duration, eased by its ease, after its delay.

Parameters

from

number

to

number

options

TweenOptions

Returns

Machine<Frame<number>>

Example

const slide = Machine.tween(0, 240, { duration: 0.4, ease: "easeInOut" })