Transformers are used to take a value, transform it in some way, and then return it. Because all transformers have the same signature, they can be easily composed.


import { transform } from "popmotion";


As pure functions, transformers can be used in any situation where you want to change one value into another.

However, they’re particularly useful with the action pipe method. For instance, here we can easily compose some functions that will ensure that the tween‘s output will always be a valid RGB value:

import { tween, transform } from "popmotion";
const { pipe, clamp } = transform;

tween({ to: 255 })
  .pipe(clamp(0, 255), Math.round)
  .start(v => console.log(v));

Preset transformers


Returns a function that, when given a value, returns that value appended with the provided unit.

appendUnit(unit: string[])

const convertToPx = appendUnit("px");
convertToPx(5); // '5px'


Takes the offset of the provided value from from, and applies it to to.

applyOffset(from: number, to: number) applyOffset(to: number)

// With two arguments
applyOffset(0, 10)(20); // 30

// With one argument
const offsetFromFirst = applyOffset(10);
offsetFromFirst(20); // 10
offsetFromFirst(21); // 11


Returns a function that, provided a progress value from 0 to 1, will return a resolved number from the provided bezier array.

Can resolve either 3 or 4 bezier points. For more points, the original implementation can be used.

bezier(...points: number[])

const resolveBezier = bezier(0, 1, 2, 3);

resolveBezier(0); // 0
resolveBezier(0.5); // 1.5
resolveBezier(1); // 3


Given two colors, returns a function that takes a progress value (0 - 1) and returns a correctly blended color.

Watch Computer Color is Broken for more information.

blendColor(colorA <String | Object>, colorB <String | Object>)

const blendRedToBlue = blendColor("#f00", "#00f");
blendRedToBlue(0.5); // Returns blended object with rgba properties


Returns a function that restricts given values to within the provided range.

clamp(min: number, max: number)

const rgbRange = clamp(0, 255);
rgbRange(256); // 255


Conditionally applies a transformer if check returns true.

const constrainWithSpring = conditional(v => v < 0, nonlinearSpring(50, 0));


Returns a function that, when passed a value, interpolates from the inputRange to the outputRange.

An optional array of easing functions can be passed as the third argument, otherwise linear interpolation will be used by default.

Provided values outside the given ranges will be clamped to the output range limits.

Note: The inputRange must be in linear order. ie [100, 200, 300] and [100, 0] are valid, whereas [100, 50, 200] is not.

interpolate(inputRange: number[], outputRange: number[], ease: Easing[])

const invert = interpolate([0, 100], [100, 0]);
invert(75); // 25

const foo = interpolate([0, 50, 100], [0, 0.5, 0]);
foo(75); // 0.25


Used to compose other transformers, from left to right. The first argument passed to the returned function will be the value and any subsequent arguments will be passed to all functions unaltered.

pipe(...funcs:(v: any) => any[])

const rgbType = pipe(clamp(0, 255), Math.round);

rgbType(12.25); // 12


Will smooth a value over time.

smooth(strength: number)

Note: As smooth maintains an internal state, it must be initialised individually for every numerical value you wish to smooth.


Given a number or an array of two or more numbers, returns a function that will snap a given value to the nearest multiple or to the nearest number in the array.

snap(positions: number[])

const snapToIntervals = snap(45);
snapToIntervals(89); // 90

const snapToArbitraryDegrees = snap([0, 90, 270, 360]);
snapToArbitraryDegrees(75); // 90


Given a number of steps and a range, returns a function that will fix a given value to the specific number of discrete steps within that range.

steps(steps: number, min: number, max: number)

const threeStep = steps(3, 0.4);
threeStep(0.1); // 0
threeStep(0.4); // 0.5
threeStep(0.9); // 1


Creates a spring that, given an elasticity (a value less than 1) and an origin, will treat the provided value as a displacement.

linearSpring(elasticity: number, origin: number)


Creates a spring that has a non-linear effect on the displacement - the greater the displacement, the greater effect on the provided value.

nonlinearSpring(elasticity: number, origin: number)


A function that can generate new static springs like linearSpring and nonlinearSpring.

This function is actually used to create those functions:

const linearSpring = generateStaticSpring();
const nonlinearSpring = generateStaticSpring(Math.sqrt);
generateStaticSpring(alterDisplacement: (displacement: number) => number)
  => (elasticity: number, origin: number)


Accepts an object of named transformers that expects v of the same structure. Applies those transformers to the corresponding property in v and outputs.

transformMap(map: { [key: string]: (v: any) => any })

const foo = transformMap({
  x: v => v + "px",
  y: v => v + "%"

foo({ x: 5, y: 10 }); // { x: '5px', y: '10%' }


Wraps a number around.

wrap(min: number, max: number)

physics({ velocity: 1000 })
  .pipe(wrap(100, 400))
  .start(v => console.log(v));