Skip to content

easing

stable

Animation 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, …}
39 functions Graphics
/ filter jk navigate Esc clear
Functions (39)
  1. linear Linear interpolation (no easing)
  2. ease_in_quad Quadratic ease-in
  3. ease_out_quad Quadratic ease-out
  4. ease_in_out_quad Quadratic ease-in-out
  5. ease_in_cubic Cubic ease-in
  6. ease_out_cubic Cubic ease-out
  7. ease_in_out_cubic Cubic ease-in-out
  8. ease_in_quart Quartic ease-in
  9. ease_out_quart Quartic ease-out
  10. ease_in_out_quart Quartic ease-in-out
  11. ease_in_quint Quintic ease-in
  12. ease_out_quint Quintic ease-out
  13. ease_in_out_quint Quintic ease-in-out
  14. ease_in_sine Sine ease-in
  15. ease_out_sine Sine ease-out
  16. ease_in_out_sine Sine ease-in-out
  17. ease_in_expo Exponential ease-in
  18. ease_out_expo Exponential ease-out
  19. ease_in_out_expo Exponential ease-in-out
  20. ease_in_circ Circular ease-in
  21. ease_out_circ Circular ease-out
  22. ease_in_out_circ Circular ease-in-out
  23. ease_in_back Back ease-in (slight overshoot)
  24. ease_out_back Back ease-out (slight overshoot)
  25. ease_in_out_back Back ease-in-out
  26. ease_in_elastic Elastic ease-in
  27. ease_out_elastic Elastic ease-out
  28. ease_in_out_elastic Elastic ease-in-out
  29. ease_in_bounce Bounce ease-in
  30. ease_out_bounce Bounce ease-out
  31. ease_in_out_bounce Bounce ease-in-out
  32. spring Spring physics easing with damping and frequency
  33. smoothstep Hermite smoothstep interpolation
  34. smootherstep Ken Perlin's smootherstep (C2 continuous)
  35. clamp Clamps a value to a range
  36. ease_by_name Calls any easing function by string name
  37. lerp Linear interpolation between two values
  38. inverse_lerp Inverse of lerp: value to t
  39. 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
enespt-br