Interpolator

The kinds of value Wardic blends: numbers, arrays of numbers, numbers with units ("10px"), and complex values, strings with numbers among other text, as a shadow's or a path's. Each is an Entry: how an endpoint of its kind is read, written, and blended with another. An Environment registers these in its InterpolatorRegistry beside its own kinds, as @wardic/dom adds its colours, and you can register yours.

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

// A kind of your own: angles in turns, `"0.25turn"`.
const turns: Interpolator.Entry<number, string> = {
  name: "turns",
  parse: (value) => (typeof value === "string" && value.endsWith("turn") ? Option.some(parseFloat(value)) : Option.none()),
  format: (amount) => `${amount}turn`,
  blend: (from, to) => Option.some((t) => `${from + (to - from) * t}turn`),
}

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

Interfaces

Complex

A complex value, read: the text around its tokens, and the tokens, numbers and its Environment's kinds, in order. parts.length === tokens.length + 1.

Properties

parts
readonly parts: readonly string[];
tokens
readonly tokens: readonly ComplexToken[];

ComplexOptions

The spans and kinds of token an Environment names in its complex values.

Properties

text?
readonly text?: readonly RegExp[];

Patterns for spans that are only text: matched whole, before tokens and numbers, so the digits in them are never numbers; kept as text; and counted when two values match. No capturing groups. None by default: core names no Environment's syntax, and @wardic/dom's are its own.

tokens?
readonly tokens?: readonly TokenKind<any>[];

Kinds of token besides numbers: each a pattern, and the Interpolator its tokens are read, blended and written through. Two values blend with the same count of each kind, the n-th token of a kind with the n-th of that kind. None by default: @wardic/dom's colours are its own.


Entry

A kind of value the registry can blend: how an endpoint of it is read and written, and how two of it blend.

  • parse reads an endpoint of the kind, any value at all: Some of what it read, None for a value of another kind, its type checked first. An endpoint it reads is this kind's, and one it rejects isn't: reading is matching. The registry parses once, when an animation is built, never per frame.
  • format writes a read value back: what each frame writes with.
  • blend takes two read endpoints, once, and returns the function each frame calls with its progress t, which blends and writes. Work on the pair, comparing two structures or settling a unit, happens here, once. None when the pair can't blend: a Discrete pair, which the registry switches at the first frame, with a warning.

The built-in kinds (a number, an array, a unit string, a complex value) are registered as an Environment is set up, beside its own, as @wardic/dom's colours, and yours can be too.

Type Parameters

Decoded

Decoded

Encoded

Encoded

Properties

blend
readonly blend: (from, to) => Option<(t) => Encoded>;

Two read endpoints' blend: the closure the frame calls with t, or None. Pure, and so is the closure: a blend is kept and shared, so one pair's closure serves every element animating it, and state kept between calls would leak from one to the next.

Parameters
from

Decoded

to

Decoded

Returns

Option<(t) => Encoded>

format
readonly format: (value) => Encoded;

Writes a read value back.

Parameters
value

Decoded

Returns

Encoded

name
readonly name: string;

Unique name for the value kind, e.g. "number", "unit".

parse
readonly parse: (value) => Option<Decoded>;

Reads an endpoint of the kind: Some of it read, or None for any other value.

Parameters
value

unknown

Returns

Option<Decoded>


KindToken

A token of one of an Environment's kinds, read: its kind, its Interpolator's name, and the value that Interpolator read.

Properties

kind
readonly kind: string;
value
readonly value: unknown;

TokenKind

A kind of token an Environment names in its complex values besides numbers: what one looks like, and the Interpolator that reads, blends and writes it, usually the one it registers for a value of that kind on its own, as @wardic/dom's colours. Its tokens are told apart by that Interpolator's name.

Type Parameters

Decoded

Decoded = any

Properties

entry
readonly entry: Entry<Decoded, string>;

How a token of the kind reads (parse), blends and writes (format).

pattern
readonly pattern: RegExp;

What a token of the kind looks like: matched case-insensitively, after the text spans and before numbers. No capturing groups: the parse splits a string around its tokens.

Type Aliases

ComplexToken

type ComplexToken = number | KindToken;

A complex value's token, read: a number, or a token of one of its Environment's kinds.

Variables

array

const array: Entry<ReadonlyArray<number>, ReadonlyArray<number>>;

Interpolates fixed-length numeric arrays element-wise (e.g. RGB tuples): it reads an array of numbers as it is.


complex

const complex: Entry<Complex, string>;

The complex value kind with no text spans and no kinds of token: core's own (see complexWith).


defaults

const defaults: ReadonlyArray<Entry<any, any>>;

The kinds core ships, in the order a pair is tried: number and array first, unit before complex, so "10px" is a unit, and complex last, for the strings the others didn't take. An Environment adds its own among them, as @wardic/dom's colours before unit.


number

const number: Entry<number, number>;

Interpolates plain numbers: it reads any number as it is, NaN and the infinities too.


unit

const unit: Entry<ParsedUnit, string | number>;

A number with a unit, "10px" to "20px", "0%" to "100%", or a bare number paired with one, 0 to "10px": the unit is taken from whichever endpoint has one, and each frame blends the number and writes it with the unit. unit.parse reads a string or a number (" 10px " is { value: 10, unit: "px" }, 120 is { value: 120, unit: "" }), and unit.format writes one back ("10px").

Two different units, both present ("10px", "1em"), can't blend: a Discrete pair, switched at the first frame, with a warning.

Functions

complexWith()

function complexWith(options): Entry<Complex, string>;

The complex value kind, for an Environment's text spans and kinds of token: a string with numbers or tokens among other text, as a path's, a shadow's or a gradient's, blended token by token, as Motion's mixComplex. Two blend when they hold the same count of each kind and the start has at least as many numbers as the target: the n-th number with the n-th, and the n-th token of a kind with the n-th of it, written in the target's text: a shadow with a colour and three lengths blends into another with a colour and three lengths, wherever each writes its colour. Any other two can't: a Discrete pair, switched to the target at the first frame, with a warning.

Two paths with the same commands morph; paths with different commands don't. Register it last, so the specific kinds win: "10px" is a unit, and a lone colour @wardic/dom's colour kind. As Motion's, an arc command's flags are blended as numbers, so an arc path can pass through invalid flags.

Its parse reads a string into its parts and tokens, and its format writes them back, numbers in JavaScript's shortest form, so "M0.50,1e3" writes back as "M0.5,1000".

Parameters

options

ComplexOptions

Returns

Entry<Complex, string>

Example

// An Environment's colours as a kind of token among the numbers, as `@wardic/dom`'s are:
const complex = Interpolator.complexWith({ tokens: [{ pattern: colorPattern, entry: colorEntry }] })

unitOf()

function unitOf(value): Option<string>;

The unit of a number-with-unit string, as the unit kind reads it ("" for a bare number), or None for another string ("auto", "M0,0 L1,1"). Two strings whose units differ, both present, can't blend.

Parameters

value

string

Returns

Option<string>