Skip to main content

Overview

The interpolate() function creates an interpolator function that maps values from an input range to an output range. It’s a lower-level utility that powers the transform() function and useTransform() hook.

Import

import { interpolate } from "motion"

Signature

interpolate<T>(
  input: number[],
  output: T[],
  options?: InterpolateOptions<T>
): (v: number) => T

Parameters

input
number[]
required
A linear series of numbers defining the input range. Must be the same length as the output range.
output
T[]
required
A series of values defining the output range. Can be:
  • Numbers
  • Colors (hex, rgb, rgba, hsl, hsla)
  • Strings with embedded numbers
  • Complex strings with multiple values
  • Objects and arrays (with the same structure)
options
InterpolateOptions<T>
Optional configuration object

Options

interface InterpolateOptions<T> {
  clamp?: boolean
  ease?: EasingFunction | EasingFunction[]
  mixer?: MixerFactory<T>
}
clamp
boolean
default:"true"
Clamp output values to within the defined output range. Set to false to allow extrapolation.
ease
EasingFunction or EasingFunction[]
Easing function(s) to apply during interpolation. If array, must be one item shorter than the ranges.
mixer
MixerFactory<T>
Custom mixer function for interpolating between output values.

Return Value

interpolator
(v: number) => T
A function that takes an input value and returns the corresponding interpolated output value.

Examples

Basic Interpolation

Create a simple number interpolator:
import { interpolate } from "motion"

const opacityInterpolator = interpolate(
  [0, 100],
  [0, 1]
)

opacityInterpolator(0)    // 0
opacityInterpolator(50)   // 0.5
opacityInterpolator(100)  // 1

Color Interpolation

Interpolate between colors:
import { interpolate } from "motion"

const colorInterpolator = interpolate(
  [0, 100],
  ["#ff0000", "#0000ff"]
)

colorInterpolator(0)    // "rgba(255, 0, 0, 1)"
colorInterpolator(50)   // "rgba(128, 0, 128, 1)"
colorInterpolator(100)  // "rgba(0, 0, 255, 1)"

Multi-Stop Interpolation

Create interpolators with multiple breakpoints:
import { interpolate } from "motion"

const scaleInterpolator = interpolate(
  [0, 50, 100],
  [0.5, 1, 0.5]
)

scaleInterpolator(0)    // 0.5
scaleInterpolator(25)   // 0.75
scaleInterpolator(50)   // 1
scaleInterpolator(75)   // 0.75
scaleInterpolator(100)  // 0.5

With Easing

Apply easing functions:
import { interpolate } from "motion"

const easedInterpolator = interpolate(
  [0, 100],
  [0, 100],
  {
    ease: (t) => t * t // Quadratic ease-in
  }
)

easedInterpolator(50)  // 25 (not 50, due to easing)

Per-Segment Easing

Apply different easing to each segment:
import { interpolate } from "motion"

const multiEaseInterpolator = interpolate(
  [0, 50, 100],
  [0, 100, 0],
  {
    ease: [
      (t) => t * t,                    // Ease in
      (t) => 1 - Math.pow(1 - t, 2)   // Ease out
    ]
  }
)

Without Clamping

Allow values outside the defined range:
import { interpolate } from "motion"

const extrapolatingInterpolator = interpolate(
  [0, 100],
  [0, 1],
  { clamp: false }
)

extrapolatingInterpolator(-50)   // -0.5 (extrapolated)
extrapolatingInterpolator(150)   // 1.5 (extrapolated)

String with Units

Interpolate strings containing numbers:
import { interpolate } from "motion"

const paddingInterpolator = interpolate(
  [0, 100],
  ["0px", "50px"]
)

paddingInterpolator(50)  // "25px"

Complex Strings

Interpolate complex CSS values:
import { interpolate } from "motion"

const shadowInterpolator = interpolate(
  [0, 100],
  [
    "0px 0px 0px rgba(0, 0, 0, 0)",
    "10px 10px 20px rgba(0, 0, 0, 0.5)"
  ]
)

const shadow = shadowInterpolator(50)
// "5px 5px 10px rgba(0, 0, 0, 0.25)"

Supported Value Types

Basic numeric interpolation:
interpolate([0, 100], [0, 1])
Supports multiple color formats:
  • Hex: "#ff0000", "#f00"
  • RGB: "rgb(255, 0, 0)"
  • RGBA: "rgba(255, 0, 0, 1)"
  • HSL: "hsl(0, 100%, 50%)"
  • HSLA: "hsla(0, 100%, 50%, 1)"
Automatically extracts and interpolates numbers:
interpolate([0, 100], ["0px", "100px"])
interpolate([0, 100], ["0deg", "360deg"])
Interpolates all numbers in complex strings:
interpolate(
  [0, 100],
  [
    "translate(0px, 0px) scale(1)",
    "translate(100px, 50px) scale(1.5)"
  ]
)

Behavior Details

Range Direction

If the input range is descending (highest to lowest), both ranges are automatically reversed:
const interpolator = interpolate(
  [100, 0],  // Descending
  [0, 1]
)

// Internally reversed to: [0, 100] → [1, 0]
interpolator(100)  // 0
interpolator(0)    // 1

Single Value

If only one input/output pair is provided, returns a constant function:
const constant = interpolate([0], [100])
constant(0)     // 100
constant(1000)  // 100

Identical Values

If all output values are identical, returns the last value:
const same = interpolate([0, 100], [42, 42])
same(50)  // 42

Zero Delta Range

If input values are identical, special handling applies:
const zeroDelta = interpolate([50, 50], [0, 1])
zeroDelta(49)  // 0 (before range)
zeroDelta(50)  // 1 (at or after range)

Performance

The interpolate() function creates the interpolator once and can be called repeatedly with minimal overhead. Interpolators are optimized for performance.

Optimization Tips

Create interpolators outside render loops or animation frames:
// Good: Create once
const interpolator = interpolate([0, 100], [0, 1])

// Use repeatedly
for (let i = 0; i < 100; i++) {
  const value = interpolator(i)
}
Custom mixer functions run frequently. Keep them lightweight:
// Avoid expensive operations in mixers
const mixer = (from, to) => (v) => {
  // Keep this fast!
  return from + (to - from) * v
}
The default mixers for numbers, colors, and strings are highly optimized. Only use custom mixers when necessary.

API Reference

MixerFactory Type

type Mixer<T> = (v: number) => T

type MixerFactory<T> = (from: T, to: T) => Mixer<T>
Custom mixer functions receive two values from the output range and return a function that interpolates between them:
const customMixer: MixerFactory<number> = (from, to) => {
  return (progress) => {
    // progress is 0-1 for the segment from `from` to `to`
    return from + (to - from) * progress
  }
}

Differences from transform()

Featureinterpolate()transform()
ReturnsInterpolator functionValue or function
Immediate modeNoYes
UsageLower-levelHigher-level
Typical useInternal/advancedPublic API

transform

Higher-level transformation function

useTransform

Transform motion values in React

Build docs developers (and LLMs) love