Craft Custom cubic-bezier() Easing Curves, Visually

Drag the two control points to shape a timing curve, watch a sample element move in real time, and copy the exact cubic-bezier() value straight into your CSS transitions and keyframe animations.

cubic-bezier(0.25, 0.10, 0.25, 1.00)
0.25
0.10
0.25
1.00
Duration 1.0s
progress at 50% time: peak velocity: overshoot:

The blue ball is animated by inverting x→t with Newton-Raphson each frame, exactly as a browser maps elapsed time to animation progress.

How the curve maps time to motion

A CSS cubic-bezier(x1, y1, x2, y2) defines a curve with fixed endpoints P0 = (0, 0) and P3 = (1, 1) plus two draggable control points P1 and P2. The horizontal axis is the fraction of elapsed time, and the vertical axis is animation progress. The catch is that the curve is parametric: both coordinates are functions of a hidden parameter t, given by the cubic Bezier basis B(t) = 3(1−t)²t·P1 + 3(1−t)t²·P2 + t³. Because x(t) is not the same as the time fraction, the browser must first solve x(t) = elapsed for t, then evaluate y(t) to get the progress.

This tool reproduces that solver. For a target x it runs a few Newton-Raphson iterations using the analytic derivative x′(t) = 3(1−t)²(x1) + 6(1−t)t(x2−x1) + 3t²(1−x2), then falls back to a bisection (binary search) whenever the slope is near zero or the guess escapes [0, 1] — the same numerically-robust hybrid WebKit uses in UnitBezier. The resulting y is the eased progress. Sampling this across the frame produces the ball's live position, the mid-point progress readout, the peak instantaneous velocity, and how far the curve overshoots past 1 (the springy "back" effect). Only y is allowed outside [0, 1]; x stays clamped to [0, 1] because time cannot run backwards, which is why the P1x and P2x sliders are bounded there. Everything runs locally in your browser with no network calls, so you can iterate on an easing curve in a tight loop and paste the finished timing function directly into a transition or @keyframes rule.

Related Tools