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
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
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
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
damping?
readonly damping?: number;How damped it is: higher settles sooner, with less overshoot. Default 26.
Inherited from
delay?
readonly delay?: number;Delay before the animation starts, in seconds.
Inherited from
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
from?
readonly from?: number;Where it starts. Default 0.
Inherited from
mass?
readonly mass?: number;The mass it moves: heavier is slower. Default 1.
Inherited from
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
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
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
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
velocity?
readonly velocity?: number;The velocity it starts with, per second. Default 0.
Inherited from
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
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.
timeis 0 at its first frame, then wall time, astime's.deltais 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
delayorvelocitysteers 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
delayholds 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?
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
easelist 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 holdsjump
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 springscroll
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?
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?
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
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 })