Skip to main content

Custom easing with Interpolator

Overview​

Interpolator<T> is the Luau interface for custom interpolation behavior in Rive; its C++ runtime implementation is named ScriptedInterpolator. This lesson follows a quadratic ease-in from its input factor to the final blended value. For the callback signatures without the walkthrough, use the Interpolation API reference.

If you are choosing where a script belongs, start with Rive script types. A custom interpolator handles easing; it does not replace a Node script's drawing or a Converter's data-binding transformation.

Runtime status

This protocol is tracked against released Web 2.42.1 -> C++ runtime-v0.1.384, with source pins documented in Runtime Compatibility Baseline.

Use it when linear interpolation is not enough and you need script-defined easing at the interpolation level. Editor availability must be checked separately: runtime support alone does not prove that your editor exposes an attachment workflow.

Follow the value through the easing curve​

The template below clamps the input factor to the range 0–1 and squares it. Squaring makes the early part of the transition progress more slowly. It then blends from 10 to 30 using that remapped factor:

Input factorSquared factorBlended value
0010
0.250.062511.25
0.50.2515
0.750.562521.25
1130

At the halfway point, linear interpolation would produce 20. This ease-in produces 15, then catches up to the same endpoint. In the template, transform remaps the factor and transformValue explicitly calls it before blending the two values. Use the exercise near the end of this lesson to check that calculation.


Type Shape​

export type Interpolator<T> = {
init: ((self: T, context: Context) -> boolean)?,
transform: ((self: T, factor: number) -> number)?,
transformValue: ((self: T, valueFrom: number, valueTo: number, factor: number) -> number)?,
} & T

Runtime callback behavior​

The public Interpolator interface lists both callbacks as required. The accepted runtime supplies fallbacks if either is absent; the template implements both.

  • transform(self, factor) -> number
  • transformValue(self, valueFrom, valueTo, factor) -> number

Runtime fallback behavior​

If a method is omitted or errors, runtime falls back to standard linear behavior.

  • Missing/failed transform -> returns original factor
  • Missing/failed transformValue -> uses from + (to - from) * factor

Template​

export type MyInterpolator = {
strength: Input<number>,
}

function transform(self: MyInterpolator, factor: number): number
local t = math.max(0, math.min(1, factor))
return t * t
end

function transformValue(self: MyInterpolator, valueFrom: number, valueTo: number, factor: number): number
local t = transform(self, factor)
return valueFrom + (valueTo - valueFrom) * t
end

return function(): Interpolator<MyInterpolator>
return {
transform = transform,
transformValue = transformValue,
strength = 1,
}
end

Exercise 1: Build a Quadratic Ease-In Mapper ⭐⭐​

Premise​

You are implementing interpolation math that should start slow and accelerate.

Starter Code​

local function transform(factor: number): number
-- TODO: clamp to [0, 1], then return quadratic ease-in
return factor
end

local function transformValue(valueFrom: number, valueTo: number, factor: number): number
-- TODO: map transform(factor) across [valueFrom, valueTo]
return valueFrom
end

local result = transformValue(10, 30, 0.5)
print(string.format("ANSWER: %.1f", result))

Expected output​

ANSWER: 15.0

Verify Your Answer​

Verify Your Answer

Knowledge Check​

Q:What happens if transformValue is not implemented in the scripted interpolator?

Next Steps​