easing
stableAnimation easing functions and interpolation utilities, covering all standard easing curves (quad, cubic, quart, quint, sine, expo, circ, back, elastic, bounce), spring physics, smoothstep, lerp, and value remapping.
use plugin easing::{linear, ease_in_quad, ease_out_quad, …} Functions (39)
- linear Linear interpolation (no easing)
- ease_in_quad Quadratic ease-in
- ease_out_quad Quadratic ease-out
- ease_in_out_quad Quadratic ease-in-out
- ease_in_cubic Cubic ease-in
- ease_out_cubic Cubic ease-out
- ease_in_out_cubic Cubic ease-in-out
- ease_in_quart Quartic ease-in
- ease_out_quart Quartic ease-out
- ease_in_out_quart Quartic ease-in-out
- ease_in_quint Quintic ease-in
- ease_out_quint Quintic ease-out
- ease_in_out_quint Quintic ease-in-out
- ease_in_sine Sine ease-in
- ease_out_sine Sine ease-out
- ease_in_out_sine Sine ease-in-out
- ease_in_expo Exponential ease-in
- ease_out_expo Exponential ease-out
- ease_in_out_expo Exponential ease-in-out
- ease_in_circ Circular ease-in
- ease_out_circ Circular ease-out
- ease_in_out_circ Circular ease-in-out
- ease_in_back Back ease-in (slight overshoot)
- ease_out_back Back ease-out (slight overshoot)
- ease_in_out_back Back ease-in-out
- ease_in_elastic Elastic ease-in
- ease_out_elastic Elastic ease-out
- ease_in_out_elastic Elastic ease-in-out
- ease_in_bounce Bounce ease-in
- ease_out_bounce Bounce ease-out
- ease_in_out_bounce Bounce ease-in-out
- spring Spring physics easing with damping and frequency
- smoothstep Hermite smoothstep interpolation
- smootherstep Ken Perlin's smootherstep (C2 continuous)
- clamp Clamps a value to a range
- ease_by_name Calls any easing function by string name
- lerp Linear interpolation between two values
- inverse_lerp Inverse of lerp: value to t
- remap Remaps a value from one range to another
Overview
easing is a stateless math library for animation: every easing function takes a
normalized progress value t in the range [0.0, 1.0] and returns an eased
value in approximately the same range. There are no handles or objects to manage
— each call is a pure function, so you can compute a curve point on demand inside
an animation loop, a shader-style routine, or a tween. The plugin bundles the
full Robert Penner set (quad through bounce) plus spring physics, Perlin's
smootherstep, and a small kit of interpolation helpers (lerp, inverse_lerp,
remap, clamp).
The mental model is two layers: pick a curve to shape how a value progresses
over time, then feed that eased t into lerp (or remap) to map it onto the
actual range you care about — pixels, colors, angles, anything. Some curves
(back, elastic) intentionally overshoot the [0, 1] range to produce "pop"
and rubber-band effects.
Common patterns
Shape progress with a curve, then map it onto a pixel range with lerp:
use plugin easing::{ease_in_out_cubic, lerp}
let t = 0.25
let x = lerp(100.0, 500.0, ease_in_out_cubic(t))
print("x = {x}")
Choose the easing curve at runtime by name (e.g. from animation config):
use plugin easing::{ease_by_name, lerp}
let curve = "ease_out_bounce"
let t = 0.6
let y = lerp(0.0, 300.0, ease_by_name(curve, t))
print("y = {y}")
Normalize an input range, ease it, and remap it onto an output range:
use plugin easing::{inverse_lerp, ease_out_quad, lerp, clamp}
let raw = 128.0
let t = clamp(inverse_lerp(0.0, 255.0, raw))
let alpha = lerp(0.0, 1.0, ease_out_quad(t))
print("alpha = {alpha}")
Linear interpolation (no easing)
Returns t unchanged. Use it as a baseline, a default, or whenever you want a
constant-rate transition with no acceleration.
use plugin easing::{linear, lerp}
let pos = lerp(0.0, 100.0, linear(0.5))
print(pos) // 50.0
Quadratic ease-in
Quadratic ease-in (t * t). Accelerates from zero — slow start, fast finish.
use plugin easing::{ease_in_quad}
print(ease_in_quad(0.5)) // 0.25
Quadratic ease-out
Quadratic ease-out. Decelerates to the target — fast start, slow finish.
use plugin easing::{ease_out_quad}
print(ease_out_quad(0.5)) // 0.75
Quadratic ease-in-out
Quadratic ease-in-out: accelerates through the first half, decelerates through the second.
use plugin easing::{ease_in_out_quad}
print(ease_in_out_quad(0.25)) // 0.125
print(ease_in_out_quad(0.5)) // 0.5
Cubic ease-in
Cubic ease-in (t^3). Stronger acceleration than quadratic.
use plugin easing::{ease_in_cubic}
print(ease_in_cubic(0.5)) // 0.125
Cubic ease-out
Cubic ease-out. Stronger deceleration than quadratic — a common, natural-feeling "settle" curve for UI.
use plugin easing::{ease_out_cubic, lerp}
let y = lerp(0.0, 200.0, ease_out_cubic(0.5))
print(y) // 175.0
Cubic ease-in-out
Cubic ease-in-out: symmetric acceleration then deceleration, more pronounced than the quadratic variant.
use plugin easing::{ease_in_out_cubic, lerp}
let x = lerp(100.0, 500.0, ease_in_out_cubic(0.25))
print(x) // ~116.0
Quartic ease-in
Quartic ease-in (t^4). More dramatic acceleration than cubic.
use plugin easing::{ease_in_quart}
print(ease_in_quart(0.5)) // 0.0625
Quartic ease-out
Quartic ease-out. Sharp early movement that eases firmly into the target.
use plugin easing::{ease_out_quart}
print(ease_out_quart(0.5)) // 0.9375
Quartic ease-in-out
Quartic ease-in-out: symmetric, stronger than cubic.
use plugin easing::{ease_in_out_quart}
print(ease_in_out_quart(0.5)) // 0.5
Quintic ease-in
Quintic ease-in (t^5). The strongest polynomial acceleration in this set.
use plugin easing::{ease_in_quint}
print(ease_in_quint(0.5)) // 0.03125
Quintic ease-out
Quintic ease-out. The strongest polynomial deceleration in this set.
use plugin easing::{ease_out_quint}
print(ease_out_quint(0.5)) // 0.96875
Quintic ease-in-out
Quintic ease-in-out: the most aggressive symmetric polynomial curve here.
use plugin easing::{ease_in_out_quint}
print(ease_in_out_quint(0.5)) // 0.5
Sine ease-in
Sine-based ease-in (1 - cos(t * π/2)). A gentle, natural acceleration.
use plugin easing::{ease_in_sine}
print(ease_in_sine(0.5)) // ~0.293
Sine ease-out
Sine-based ease-out (sin(t * π/2)). A soft deceleration.
use plugin easing::{ease_out_sine}
print(ease_out_sine(0.5)) // ~0.707
Sine ease-in-out
Sine ease-in-out (-(cos(π t) - 1) / 2). Produces a smooth, organic-feeling
curve well suited to looping motion.
use plugin easing::{ease_in_out_sine, lerp}
let y = lerp(0.0, 200.0, ease_in_out_sine(0.75))
print(y) // ~170.7
Exponential ease-in
Exponential ease-in (2^(10t - 10)). A very abrupt acceleration. Returns exactly
0.0 at t = 0.
use plugin easing::{ease_in_expo}
print(ease_in_expo(0.0)) // 0.0
print(ease_in_expo(0.5)) // ~0.03125
Exponential ease-out
Exponential ease-out (1 - 2^(-10t)). A very abrupt deceleration. Returns
exactly 1.0 at t = 1.
use plugin easing::{ease_out_expo}
print(ease_out_expo(1.0)) // 1.0
print(ease_out_expo(0.5)) // ~0.96875
Exponential ease-in-out
Exponential ease-in-out. Snaps in and out around the midpoint. Pinned to exactly
0.0 at t = 0 and 1.0 at t = 1.
use plugin easing::{ease_in_out_expo}
print(ease_in_out_expo(0.0)) // 0.0
print(ease_in_out_expo(1.0)) // 1.0
Circular ease-in
Circular ease-in based on the arc of a circle (1 - sqrt(1 - t^2)). Starts very
slowly, then accelerates sharply toward the end.
use plugin easing::{ease_in_circ}
print(ease_in_circ(0.5)) // ~0.134
Circular ease-out
Circular ease-out. Accelerates sharply at the start, then eases into the target along a circular arc.
use plugin easing::{ease_out_circ}
print(ease_out_circ(0.5)) // ~0.866
Circular ease-in-out
Circular ease-in-out: a slow-fast-slow profile with the steep circular middle.
use plugin easing::{ease_in_out_circ}
print(ease_in_out_circ(0.5)) // 0.5
Back ease-in (slight overshoot)
Back ease-in: the value dips slightly below zero before accelerating forward, creating an anticipatory "wind-up" before movement.
use plugin easing::{ease_in_back}
print(ease_in_back(0.3)) // < 0.0 (wind-up)
Back ease-out (slight overshoot)
Back ease-out: the value overshoots past the target, then settles back. Great for a "pop" when an element arrives.
use plugin easing::{ease_out_back}
print(ease_out_back(0.8)) // > 1.0 (overshoot)
print(ease_out_back(1.0)) // 1.0 (settles at target)
Back ease-in-out
Back ease-in-out: anticipatory wind-up at the start and overshoot at the end.
use plugin easing::{ease_in_out_back, lerp}
let y = lerp(0.0, 100.0, ease_in_out_back(0.9))
print(y) // overshoots above 100 before settling
Elastic ease-in
Elastic ease-in: the value oscillates with growing amplitude before springing toward the target — a rubber-band wind-up.
use plugin easing::{ease_in_elastic}
print(ease_in_elastic(0.5)) // small oscillating value
Elastic ease-out
Elastic ease-out: overshoots and oscillates around the target with decaying
amplitude before settling. Pinned to 0.0 at t = 0 and 1.0 at t = 1.
use plugin easing::{ease_out_elastic, lerp}
let y = lerp(0.0, 200.0, ease_out_elastic(0.5))
print(y)
Elastic ease-in-out
Elastic ease-in-out: rubber-band oscillation on both ends of the transition.
use plugin easing::{ease_in_out_elastic}
print(ease_in_out_elastic(0.25))
print(ease_in_out_elastic(0.75))
Bounce ease-in
Bounce ease-in: a ball-drop bounce concentrated at the start of the transition.
use plugin easing::{ease_in_bounce}
print(ease_in_bounce(0.5))
Bounce ease-out
Bounce ease-out: simulates a ball settling with several bounces at the end of the transition.
use plugin easing::{ease_out_bounce, lerp}
let y = lerp(0.0, 300.0, ease_out_bounce(0.9))
print(y)
Bounce ease-in-out
Bounce ease-in-out: bouncing at both the start and the end of the transition.
use plugin easing::{ease_in_out_bounce}
print(ease_in_out_bounce(0.25))
print(ease_in_out_bounce(0.75))
Spring physics easing with damping and frequency
Physics-based spring easing: 1 - exp(-damping * t) * cos(frequency * t * 2π).
A higher damping settles faster; a higher frequency oscillates more. Unlike
the named curves, this one takes tuning parameters so you can dial the feel.
use plugin easing::{spring, lerp}
let t = 0.6
let y = lerp(0.0, 100.0, spring(t, 5.0, 2.0))
print(y)
A stiffer, faster-settling spring:
use plugin easing::{spring}
print(spring(0.4, 12.0, 1.0))
Hermite smoothstep interpolation
Hermite interpolation (t^2 * (3 - 2t)). Smoother than linear and C1 continuous
at the edges — a shader and procedural-generation staple.
use plugin easing::{smoothstep}
print(smoothstep(0.0)) // 0.0
print(smoothstep(0.5)) // 0.5
print(smoothstep(1.0)) // 1.0
Ken Perlin's smootherstep (C2 continuous)
Ken Perlin's improved smoothstep (t^3 * (t * (6t - 15) + 10)). C2 continuous —
zero first and second derivative at 0 and 1, which makes it ideal for noise
and terrain blending where seams must be invisible.
use plugin easing::{smootherstep, lerp}
print(smootherstep(0.5)) // 0.5
let blend = lerp(0.0, 1.0, smootherstep(0.3))
print(blend)
Clamps a value to a range
Clamps t to the range [min, max]. Both bounds are optional and default to
min = 0.0 and max = 1.0, so a bare clamp(t) keeps a progress value inside
the unit interval.
use plugin easing::{clamp}
print(clamp(1.5)) // 1.0
print(clamp(-0.2)) // 0.0
Clamp into a custom range:
use plugin easing::{clamp}
print(clamp(5.0, 0.0, 10.0)) // 5.0
print(clamp(42.0, 0.0, 10.0)) // 10.0
Calls any easing function by string name
Evaluates any of the registered easing curves selected by its string name.
Useful when the curve is chosen at runtime — from a config file, animation data,
or user input. Unknown names raise an error.
use plugin easing::{ease_by_name}
print(ease_by_name("ease_out_cubic", 0.6))
Iterate over a set of curves chosen at runtime:
use plugin easing::{ease_by_name}
let curves = ["ease_in_quad", "ease_out_bounce", "smoothstep"]
let t = 0.6
for name in curves {
print("{name} -> {ease_by_name(name, t)}")
}
Linear interpolation between two values
Linearly interpolates between a and b by t: returns a at t = 0 and b
at t = 1. This is the workhorse you feed an eased t into to map a curve onto
a real range.
use plugin easing::{lerp, ease_in_out_cubic}
let x = lerp(100.0, 500.0, ease_in_out_cubic(0.25))
print(x) // ~116.0
Inverse of lerp: value to t
The inverse of lerp: returns the t for which lerp(a, b, t) == value.
Normalizes a value from the [a, b] range into [0, 1]. Returns 0.0 when
a and b are equal.
use plugin easing::{inverse_lerp}
print(inverse_lerp(0.0, 200.0, 50.0)) // 0.25
print(inverse_lerp(100.0, 200.0, 150.0)) // 0.5
Remaps a value from one range to another
Remaps value from the input range [in_min, in_max] onto the output range
[out_min, out_max]. Equivalent to
lerp(out_min, out_max, inverse_lerp(in_min, in_max, value)). Returns out_min
when the input range is degenerate.
use plugin easing::{remap}
// Convert a 0-255 byte value to 0.0-1.0
print(remap(0.0, 255.0, 0.0, 1.0, 128.0)) // ~0.502
Map degrees Celsius onto Fahrenheit:
use plugin easing::{remap}
print(remap(0.0, 100.0, 32.0, 212.0, 37.0)) // 98.6