LiveValue

Live values: values derived from other values as they change, each an effect/reactivity Atom an element's style can follow. transform maps one through ranges, follow and spring follow one on a transition, velocity tracks how fast one moves, scroll gives a container's scroll, time the time since it started, and eachFrame calls you every frame. A binding wraps them in its own reactive values, as Solid's createSpring and createTransform do.

import * as LiveValue from "@wardic/core/LiveValue"

const pointerX = Atom.make(0)
const x = yield* LiveValue.spring(pointerX, { stiffness: 300, damping: 30 })
const opacity = yield* LiveValue.transform(x, [0, 200], [1, 0])

Its exports also name types the module doesn't export: its internal types.

Interfaces

Followed

A Live value that follows another on a transition: what follow and spring make. Read as any Atom of a number; beside a writable Atom of yours, the one Atom jump takes.

Extends

  • Atom<number>

Properties

[FollowedBrand]
readonly [FollowedBrand]: true;

FollowSkips

What a Follow value lands at once, as a jump, rather than animating to.

Extended by

Properties

skipAnimations?
readonly skipAnimations?: boolean;

Every change of the source lands at once, as a jump (Motion's transition skipAnimations): a Skipped animation. Default false.

skipInitialAnimation?
readonly skipInitialAnimation?: boolean;

The source's first change lands at once, as a jump, and only the changes after it animate (Motion's skipInitialAnimation): for a source set once after it starts, as a scroll position restored after the app mounts. Default false.


MixedTransformOptions

transform's options with a mixer: its outputs any type the mixer blends.

Extends

Type Parameters

O

O

Properties

clamp?
readonly clamp?: boolean;

Hold the first and last output outside the input's range. Default true, as Motion's is.

Inherited from

TransformOptions.clamp

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

How each stretch of the input range eases, as Motion's useTransform's ease: one easing for every stretch, or a list, one each, linear for any it's short of. Default linear. A descending range's stretches take it reversed, as Motion's.

Inherited from

TransformOptions.ease

mixer
readonly mixer: Mixer<O>;

How two outputs blend, as Motion's mixer: made once per stretch from its two outputs, read through the stretch's ease. Given, it takes the place of the InterpolatorRegistry's blends, so the outputs can be any type it blends. Default: the registry's, of numbers and strings.

Overrides

TransformOptions.mixer


ScrollValues

What scroll gives: Motion's four values, each an Atom.

Properties

scrollX
readonly scrollX: Atom<number>;

How far the container is scrolled across, in the Environment's units.

scrollXProgress
readonly scrollXProgress: Atom<number>;

Progress across, 0 to 1 (through the offsets, with target or offset on axis: "x").

scrollY
readonly scrollY: Atom<number>;

How far the container is scrolled down.

scrollYProgress
readonly scrollYProgress: Atom<number>;

Progress down, 0 to 1 (through the offsets, with target or offset on axis: "y", the default).


SpringOptions

spring's options: Machine.spring's, and the skips.

Extends

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.

Inherited from

SpringOptions.bounce

damping?
readonly damping?: number;

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

Inherited from

SpringOptions.damping

delay?
readonly delay?: number;

Delay before the animation starts, in seconds.

Inherited from

SpringOptions.delay

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.

Inherited from

SpringOptions.duration

from?
readonly from?: number;

Where it starts. Default 0.

Inherited from

SpringOptions.from

mass?
readonly mass?: number;

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

Inherited from

SpringOptions.mass

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.

Inherited from

SpringOptions.restDelta

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.

Inherited from

SpringOptions.restSpeed

skipAnimations?
readonly skipAnimations?: boolean;

Every change of the source lands at once, as a jump (Motion's transition skipAnimations): a Skipped animation. Default false.

Inherited from

FollowSkips.skipAnimations

skipInitialAnimation?
readonly skipInitialAnimation?: boolean;

The source's first change lands at once, as a jump, and only the changes after it animate (Motion's skipInitialAnimation): for a source set once after it starts, as a scroll position restored after the app mounts. Default false.

Inherited from

FollowSkips.skipInitialAnimation

stiffness?
readonly stiffness?: number;

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

Inherited from

SpringOptions.stiffness

velocity?
readonly velocity?: number;

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

Inherited from

SpringOptions.velocity

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.

Inherited from

SpringOptions.visualDuration


TransformOptions

transform's options.

Extended by

Type Parameters

O

O = number | string

Properties

clamp?
readonly clamp?: boolean;

Hold the first and last output outside the input's range. Default true, as Motion's is.

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

How each stretch of the input range eases, as Motion's useTransform's ease: one easing for every stretch, or a list, one each, linear for any it's short of. Default linear. A descending range's stretches take it reversed, as Motion's.

mixer?
readonly mixer?: Mixer<O>;

How two outputs blend, as Motion's mixer: made once per stretch from its two outputs, read through the stretch's ease. Given, it takes the place of the InterpolatorRegistry's blends, so the outputs can be any type it blends. Default: the registry's, of numbers and strings.

Type Aliases

FollowOptions

type FollowOptions = FollowTransition & FollowSkips;

follow's options: its transition, and the skips.


FollowTransition

type FollowTransition = 
  | object & Omit<SpringOptions, "from">
  | object & TweenOptions
  | object & InertiaOptions;

A follow's transition, in seconds, as Motion's useFollowValue's: a spring (one with no type is), a tween, or an inertia. What it leaves out is Motion's follower's: a spring's physics 100 / 10 / 1 unless it's set by time, at rest within 0.001 and below 0.01 a second (an inertia's too), and a tween's 0.3 s easeInOut. Its delay holds the value where it is at each change of the source, then it goes on toward the latest: a debounce, as Motion's.


Mixer

type Mixer<O> = (from, to) => (t) => O;

A blend between two outputs, as Motion's MixerFactory: made once per stretch, then read at each progress through it, 0 to 1.

Type Parameters

O

O

Parameters

from

O

to

O

Returns

(t) => O

Variables

eachFrame

const eachFrame: (callback) => Effect.Effect<void, never, FrameLoop | Scope.Scope>;

Calls callback every frame with the frame's time and delta, in milliseconds, as Motion's useAnimationFrame: for what a frame draws itself, a canvas or a 3D scene. It keeps the Clock ticking every frame while it runs; its run ends with the Scope.

  • time is 0 at its first frame, then wall time, as time's.
  • delta is the frame's own, held to 1–40 ms, so the first frame after the app was hidden steps 40 ms, not minutes.

A throw from callback ends the run: a binding catches it first.

Parameters

callback

(time, delta) => void

Returns

Effect.Effect<void, never, FrameLoop | Scope.Scope>

Example

yield* LiveValue.eachFrame((time) => draw(context, time))

follow

const follow: (source, options?, skipped?) => Effect.Effect<Followed, never, 
  | FrameLoop
  | AtomRegistry.AtomRegistry
| Scope.Scope>;

A value that follows source on a transition, as Motion's followValue: it starts where the source is, and from each change on, a run toward the source runs on the Frame loop until it rests there; nothing runs while it rests.

  • A spring with no delay or velocity steers toward the source, read afresh every step, keeping its velocity through a change.
  • Anything else starts again at the step after a change, from where it has got to: a tween with its full duration, an inertia gliding again, a spring with the transition's velocity, or its own. Several changes in one frame start it once.
  • A delay holds it where it is at every change, then it goes on toward the latest: a source that never rests doesn't move it until it does.

At its source already, a change starts nothing. With skipInitialAnimation, the source's first change is a jump; with skipAnimations, or while skipped() says so, every change is. Its run and its subscription end with the Scope.

Parameters

source

Atom.Atom<number>

options?

FollowOptions

skipped?

() => boolean

Returns

Effect.Effect<Followed, never, | FrameLoop | AtomRegistry.AtomRegistry | Scope.Scope>

Example

const eased = yield* LiveValue.follow(target, { type: "tween", duration: 0.4, ease: "easeOut" })

interpolate

const interpolate: Interpolate;

The mapping transform applies, as a plain function, Motion's interpolate: an input at input[i] gives output[i], and one between two stops blends their outputs by its progress between them, through the InterpolatorRegistry or the mixer given, resolved once. input and output are as long, one stop or more. As Motion's:

  • one stop, or two with one output, gives that output;
  • a descending range is mapped reversed, both lists, its ease list too;
  • a stretch of no length gives its second output at or past it, and, the first one, its first output before it;
  • outside the range the ends hold, unless clamp: false, which carries the first or last stretch on.

Example

const width = yield* LiveValue.interpolate([0, 1, 2], ["0px", "80px", "120px"])
width(1.5) // "100px"
width(3) // "120px": the end holds

jump

const jump: {
  (value): (atom) => Effect<void, never, AtomRegistry>;
  (atom, value): Effect<void, never, AtomRegistry>;
};

Sets atom to value at once, not as motion, as Motion's MotionValue.jump: a spring whose output it is ends its run there with no velocity, and rests there until its source next changes, then springs from there; a velocity of it reads the jump as no motion. atom is a spring's output, or a writable Atom of yours.

Call Signature

(value): (atom) => Effect<void, never, AtomRegistry>;
Parameters
value

number

Returns

(atom) => Effect<void, never, AtomRegistry>

Call Signature

(atom, value): Effect<void, never, AtomRegistry>;
Parameters
atom

Followed | Writable<number, number>

value

number

Returns

Effect<void, never, AtomRegistry>

Example

yield* LiveValue.jump(x, 0) // back to the start, without a spring

scroll

const scroll: (options?) => Effect.Effect<ScrollValues, never, Probe | Scope.Scope>;

A container's scroll as Motion's four values, as useScroll: how far it's scrolled on each axis, and the progress through its range, or, with a target or an offset, through the offsets the target passes on axis. Each is set within the scroll's own event, so a value derived from one is written in the frame that shows the scroll. The container's listeners are held while the Scope is.

Parameters

options?

ScrollOptions

Returns

Effect.Effect<ScrollValues, never, Probe | Scope.Scope>

Example

const { scrollYProgress } = yield* LiveValue.scroll({ container })

time

const time: () => Effect.Effect<Atom.Atom<number>, never, 
  | FrameLoop
  | AtomRegistry.AtomRegistry
| Scope.Scope>;

Milliseconds since it started, as Motion's useTime: wall time, minutes the app spent hidden included. It keeps the Clock ticking every frame while it runs; its run ends with the Scope.

Returns

Effect.Effect<Atom.Atom<number>, never, | FrameLoop | AtomRegistry.AtomRegistry | Scope.Scope>

Example

const rotate = yield* LiveValue.transform(yield* LiveValue.time(), [0, 4000], [0, 360], { clamp: false })

transform

const transform: {
  <O>(source, input, output, options?): Effect<Atom<O>, never, InterpolatorRegistry>;
  <O>(source, input, output, options): Effect<Atom<O>, never, InterpolatorRegistry>;
};

source mapped through ranges, as interpolate maps a number: an Atom that follows source, mapped afresh at each change.

Call Signature

<O>(
   source, 
   input, 
   output, 
   options?
): Effect<Atom<O>, never, InterpolatorRegistry>;
Type Parameters
O

O extends string | number

Parameters
source

Atom<number>

input

readonly number[]

output

readonly O[]

options?

TransformOptions<O>

Returns

Effect<Atom<O>, never, InterpolatorRegistry>

Call Signature

<O>(
   source, 
   input, 
   output, 
   options
): Effect<Atom<O>, never, InterpolatorRegistry>;
Type Parameters
O

O

Parameters
source

Atom<number>

input

readonly number[]

output

readonly O[]

options

MixedTransformOptions<O>

Returns

Effect<Atom<O>, never, InterpolatorRegistry>

Example

const scale = yield* LiveValue.transform(scrollY, [0, 300], [1, 0.8])

velocity

const velocity: (source) => Effect.Effect<Atom.Atom<number>, never, 
  | FrameLoop
  | AtomRegistry.AtomRegistry
| Scope.Scope>;

How fast source is changing, in its units a second, as Motion's useVelocity: 0 to begin with, and from each change on, each frame's change over the frame's time, until a frame finds no change, sets 0 and stops. Nothing runs while the source rests. A velocity is a value too: velocity(velocity(x)) is acceleration. Its run ends with the Scope.

Parameters

source

Atom.Atom<number>

Returns

Effect.Effect<Atom.Atom<number>, never, | FrameLoop | AtomRegistry.AtomRegistry | Scope.Scope>

Example

const speed = yield* LiveValue.velocity(scrollY)

Functions

spring()

function spring(
   source, 
   options?, 
   skipped?
): Effect<Followed, never, Scope | FrameLoop | AtomRegistry>;

A value that follows source on a spring, as Motion's useSpring: follow's spring, options a spring's, and Motion's follower's for what it leaves out: 100 / 10 / 1 unless it's set by time, at rest within 0.001 and below 0.01 a second.

Parameters

source

Atom<number>

options?

SpringOptions = {}

skipped?

() => boolean

Returns

Effect<Followed, never, Scope | FrameLoop | AtomRegistry>

Example

const smooth = yield* LiveValue.spring(scrollYProgress, { visualDuration: 0.3 })