Easings

An easing is the curve a tween moves along — slow start, gentle settle, overshoot, steps. Every tween (animate, .animateTo() / .animateFrom(), Timeline) takes the same easing: a curve name, a cubic bezier, steps(n) or a function.

  • make an animation start fast and settle gently
  • overshoot the target and come back, or bounce
  • use a CSS cubic-bezier() curve
  • move in steps instead of smoothly
  • give each style property its own curve
  • shape a number of your own with an easing curve

At a glance

TypeScript
const card = UIColumn().style({ width: 120, height: 80, bgColor: '#4f7cff' })
UIScreen(card).style({ alignItems: 'center', justifyContent: 'center' }).open()

card.animateTo({ width: 300, duration: 400, easing: 'outCubic' })              // a named curve
card.animateTo({ height: 120, duration: 400, easing: [0.34, 1.56, 0.64, 1] })   // CSS cubic-bezier: overshoots, settles
card.animateTo({ opacity: 0.4, duration: 400, easing: 'steps(4)' })            // four jumps

const snappy = cubicBezier(0.2, 0.8, 0.2, 1)           // an Easing function
console.log(snappy(0.5).toFixed(3), easeOut(0.5))       // 0.946 0.75

Pick a curve: ease-out, overshoot, bounce, steps (EasingInput)

TypeScript
type Easing = (t: number) => number   // linear progress 0..1 → eased progress
type EasingInput =
  | string                  // a name below, 'ease', 'cubic-bezier(x1, y1, x2, y2)', 'steps(n)'
  | [x1, y1, x2, y2]        // a cubic bezier, the numbers of CSS cubic-bezier()
  | Easing                  // any function

The named curves (the easings.net set):

TypeScript
linear     smoothstep
inSine     outSine     inOutSine       inQuad     outQuad     inOutQuad
inCubic    outCubic    inOutCubic      inQuart    outQuart    inOutQuart
inExpo     outExpo     inOutExpo       inCirc     outCirc     inOutCirc
inBack     outBack     inOutBack       inElastic  outElastic  inOutElastic
inBounce   outBounce   inOutBounce
  • in / out / inOut, easeIn / easeOut / easeInOut and ease-in / ease-out / ease-in-out name the quadratics (inQuad / outQuad / inOutQuad); 'ease' is CSS's cubic-bezier(0.25, 0.1, 0.25, 1).
  • 'steps(n)' holds each of n levels and jumps at the end of each step; 'steps(n, start)' (or jump-start) jumps at the start; a bare 'steps' is one step.
  • The Back and Elastic curves overshoot the target and come back; Bounce bounces off it.
  • In a props bag (animateTo, Timeline.add) easing may also be a per-prop map: { width: 'outExpo', opacity: 'linear' } — a prop left out takes the default.
  • An unknown name logs [tween] unknown easing "…" — using linear and runs linear.
Note

the default of every tween with a target is cubic-bezier(0.42, 0, 0.58, 1), CSS's ease-in-out. The string 'ease-in-out' is the quadratic inOutQuad, a hair off it (0.125 vs 0.129 a quarter of the way). animate() defaults to 'linear'.

Note

a function crosses to the native evaluator as 65 samples joined by straight lines, with the endpoints pinned to 0 and 1. A name or a [x1, y1, x2, y2] tuple is evaluated exactly — prefer it when the curve has one. On the web (Web Lite) the browser plays an element's track: a bezier or steps is its CSS twin, a named or function curve a CSS linear() of 25 points.

Ease a number of your own: easeIn / easeOut / easeInOut

TypeScript
easeIn(t): number       // quadratic accelerate: t²  — slow start, fast finish
easeOut(t): number      // quadratic decelerate: 1 − (1 − t)²  — fast start, slow settle
easeInOut(t): number    // easeIn for the first half, mirrored for the second

All three are plain quadratic curves — the same as the names 'in' / 'out' / 'inOut', which a tween evaluates without sampling. easeOut is what most UI motion wants (respond immediately, settle gently).

A curve from CSS or a design tool: cubicBezier

TypeScript
cubicBezier(x1: number, y1: number, x2: number, y2: number): Easing

Builds an easing from two control points — the same parameters as CSS cubic-bezier(x1, y1, x2, y2), so any curve from a CSS easing gallery ports directly. The returned function is reusable; create it once, not per tween. As a tween's easing, the tuple [x1, y1, x2, y2] is the same curve without the sampling.

  • x1 / x2 must stay in 0..1 (they parameterize time).
  • y1 / y2 may go outside 0..1 — that's how you get overshoot (back/spring feels): eased progress temporarily exceeds 1, so the animated value passes to and comes back.
  • Endpoints are exact: input 0 returns 0, input 1 returns 1.
  • cubicBezier(a, a, b, b) (control points on the diagonal) returns a plain linear easing.

See also

  • animate — free values and the Animation handle
  • Timeline — choreography, per-track easing
  • Styling — .animateTo() / .animateFrom() on UI elements
  • Classes — the transitions of $class blocks