FreeToGenerate.com

100% free · no sign-up · everything in your browser

Drag either handle. The x of a handle is clamped to 0–1 because CSS requires it; y is free, which is what lets a curve overshoot.

These two are conventions rather than CSS keywords — they are here because their y values leave 0–1, which is legal.

transition-timing-function: cubic-bezier(0.25, 0.1, 0.25, 1);

This curve, measured

Error if the solve is skipped
28.74%
Worst at input progress
0.404
Output progress reaches
0.0001.000
Goes outside 0–1
no

A cubic Bézier is parametric: x and y are both functions of a hidden parameter. Feeding the time straight in as that parameter, instead of solving for it, is the usual bug — the first row is how wrong it would be here.

Also available in: Español · Português · Français · العربية

Cubic bezier generator

Build a CSS easing curve by dragging its two handles — and see the one thing about cubic-bezier() that trips up almost every hand-written implementation.

What is a cubic-bezier easing curve?

CSS animations and transitions need a rule for how progress is distributed over time. `linear` spreads it evenly; anything more interesting is a curve. `cubic-bezier(x1, y1, x2, y2)` lets you draw that curve yourself by placing two control points between a fixed start at (0, 0) and a fixed end at (1, 1).

The CSS Easing specification is precise about what the axes mean: “Input progress values serve as x values of the curve, whilst the y values are the output progress values.” So x is how far through the duration you are, and y is how far through the movement. A curve that rises steeply at the start and flattens out is a thing that starts fast and glides to a stop.

The four familiar keywords are just named curves. `ease` is cubic-bezier(0.25, 0.1, 0.25, 1), `ease-in` is (0.42, 0, 1, 1), `ease-out` is (0, 0, 0.58, 1) and `ease-in-out` is (0.42, 0, 0.58, 1). Anything you can drag here is as legitimate as those.

How to use the cubic bezier generator

  1. Drag either handle. The curve redraws as you move, and the CSS updates with it. Handles are focusable, so arrow keys nudge by 0.01 and shift-arrow by 0.1 if you would rather be precise than quick.
  2. Try a preset, or push past the box. The five CSS keywords are one click away. The two overshooting presets pull the curve outside the 0–1 square on purpose, which is legal and is what makes a movement spring past its target and settle back.
  3. Play it, then copy it. The preview animates with the actual CSS, so the browser does the easing and you are watching the real thing rather than a re-implementation. Copy gives you a complete transition-timing-function declaration.

The bug this page is really about

A cubic Bézier is a parametric curve. Both x and y are functions of a hidden parameter — call it s — that runs from 0 to 1 and is neither time nor progress. Evaluating the easing at time t therefore takes two steps: solve x(s) = t for s, then return y(s).

Skipping that solve and feeding the time straight in as the parameter is the most common way hand-written easing code goes wrong, and it is not a subtle error. On `ease`, the browser's own default, the shortcut is wrong by 28.74% of the entire animation range, worst at 40% of the way through. On `ease-in` and `ease-out` it is 22.96%.

There is a trap in checking your own code, too. `ease-in-out` is nearly symmetric, so the error largely cancels and comes out at 2.86% — small enough to look like a rounding difference. And cubic-bezier(0, 0, 1, 1) is worse: it evaluates to a perfectly straight line, so it looks like the safe case to test against, and the shortcut is still 9.62% wrong on it, because x(s) there works out to 3s² − 2s³ rather than s.

In fact the shortcut is exact for exactly one family of curves: x1 = 1/3 and x2 = 2/3. Those are the only control points that make x(s) the identity, and so the only ones where the parameter genuinely is the time. Every other curve needs the solve.

The panel under the editor measures this for whatever curve you have made, because the size of the error depends entirely on the curve.

Honest limitations

The x values are clamped to 0–1 and the y values are not, which is the specification's rule rather than a decision made here: the grammar is cubic-bezier(<number [0,1]>, <number>, <number [0,1]>, <number>). That asymmetry is not arbitrary. With both x controls inside the unit interval, x(s) is guaranteed to increase, so every moment in time has exactly one point on the curve — verified over 200,000 random pairs with no counterexample. Push an x outside the range and that guarantee breaks, which is why CSS rejects it. Leaving y free costs nothing and buys the overshoot.

The overshoot is real and worth seeing: the back-out preset reaches an output progress of 1.0869 before settling, and back-in dips to −0.0969 first. Those two presets are widely used conventions, not part of CSS, and the page labels them that way.

The solver is Newton-Raphson with a bisection fallback, which is what browser engines use. It is checked by substitution rather than against a second implementation — the parameter it returns is fed back through x and required to reproduce the time to within one part in a million, over 40,000 random curves and on the flat-ended curves where Newton stalls and bisection has to take over.

This editor covers cubic-bezier only. CSS also has `linear()` with arbitrary stops, and the `steps()` family, and neither is a Bézier — they need a different editor and are not silently approximated here.

48 assertions cover the keyword values, the solver, the monotonicity guarantee and its counterexample, the published error figures and the formatting.

Why is it free?

It is a curve, a solver and a text box, all running in your browser. Nothing is uploaded, there is no account, and the preview uses the browser's own animation rather than anything served from here.

The measurement panel is not a paid extra either — it is the reason the page exists.