HandyTools Hub

Cubic Bezier Generator

Design CSS timing functions visually and copy the cubic-bezier value

Drag the two control points to shape the curve. Horizontal stays within the box; vertical can overshoot for bounce effects.

Your curve

Linear (reference)

 

A cubic-bezier generator lets you design a CSS timing function visually by dragging two control points, then copy out the exact cubic-bezier(x1, y1, x2, y2) value. The editor clamps the horizontal coordinates to the unit box, allows the vertical coordinates to leave it for overshoot, and previews the curve with a real CSS transition so you can judge the feel before pasting it into a stylesheet.

Reading the Curve

The timing function is a cubic Bézier with fixed endpoints P0 = (0,0) and P3 = (1,1). The two handles set P1 = (x1, y1) and P2 = (x2, y2). For a given time progress x, the browser finds the curve parameter t where x(t) = x, then returns y(t):

x(t) = 3(1−t)²t·x1 + 3(1−t)t²·x2 + t³
y(t) = 3(1−t)²t·y1 + 3(1−t)t²·y2 + t³

Because x1 and x2 are constrained to [0,1], x(t) rises monotonically, so exactly one t solves each x. The dashed diagonal on the canvas is the linear function y = x, the reference against which every curve is compared.

Step by Step

  1. Start from a preset — click ease, ease-in-out, easeOutBack, or any of the other built-ins to load known control points.
  2. Drag a handle — pull either circular control point. Horizontal drag is clamped to the unit box; vertical drag is not.
  3. Watch the live value — the cubic-bezier(...) output updates on every pointer move.
  4. Play the preview — animate the sample dot with your exact value and compare it against the linear dot beside it.
  5. Copy — click copy and paste the value into transition-timing-function or animation-timing-function.

Worked Examples: Three Easings at 50% Time

PresetValueOutput progress at half the durationCharacter
easecubic-bezier(0.25, 0.1, 0.25, 1)y ≈ 0.802Slightly ahead of linear, soft finish
easeOutBackcubic-bezier(0.175, 0.885, 0.32, 1.275)y ≈ 1.068Already past the target at 50%; peaks near 1.087
easeInExpocubic-bezier(0.95, 0.05, 0.795, 0.035)y ≈ 0.037Barely moves, then rushes at the end

The easeOutBack numbers are the useful ones to remember: over a 400 ms transition it overshoots the final position by roughly 9% around 63% of the way through, then eases back. Shorten the duration and the bounce reads as a snap; lengthen it and the overshoot looks sluggish.

Overshoot, Anticipation, and the x/y Rule

The x/y asymmetry is not a quirk of this tool — it is the CSS specification. The browser needs x(t) to be a function, so x1 and x2 must lie in [0,1]; the generator clamps them for you. y1 and y2 may be any real number:

  • y > 1 — the element travels beyond its destination and returns. Used for toasts, modals, and button pops.
  • y < 0 — the element moves backwards before starting forward. Used for anticipation, like a wind-up before a swipe.
  • Both — easeInOutBack combines a dip below 0 with an overshoot above 1.

Accuracy and Limits

  • The value is rounded to four decimal places before it is printed, matching the precision at which these curves are normally shared.
  • The on-screen curve is sampled by solving for t numerically (Newton-Raphson, eight iterations). At extreme control-point values the visual curve and the browser’s may differ by a sub-pixel trace, but the printed CSS value is exact.
  • The tool outputs only the timing function. It does not generate the transition or @keyframes block, choose a duration, or decide which property to animate.
  • A curve cannot fix a non-animatable property, and it cannot make display fade. This tool designs motion, it does not make the property animatable.

From Curve to Stylesheet

The generated string is just the timing function, so it drops straight into any transition or animation:

.button { transition: transform 180ms cubic-bezier(0.175, 0.885, 0.32, 1.275); }
@keyframes pop { from { transform: scale(0.9); } to { transform: scale(1); } }
.toast { animation: pop 320ms cubic-bezier(0.68, -0.55, 0.265, 1.55) both; }

Two habits make this easier. First, match the curve to the distance and duration: a strong overshoot over a long transition reads as a wobble, while the same curve at 150 ms reads as a snap. Second, keep a small set of house curves in CSS variables, such as --ease-snappy and --ease-bounce, so separate components animate consistently instead of each inventing its own feel.

Common Mistakes

  • Overshooting everything. A UI where buttons, cards, and modals all bounce feels noisy. Reserve overshoot for one or two focal interactions per view.
  • Copying a curve without its duration. The feel comes from the pair; easeOutBack at 150 ms and at 800 ms are completely different effects.
  • Assuming a negative y is invalid. It is not — it is anticipation, and browsers render it. The tool allows it deliberately.
  • Trusting a translate preview for every property. Motion on transform says little about how opacity or color will interpolate, because the curve applies to each property independently.

Frequently Asked Questions

What do the four numbers in cubic-bezier(x1, y1, x2, y2) mean?

They are the coordinates of the two control points of a cubic Bézier curve anchored at (0,0) and (1,1): (x1, y1) is the first control point and (x2, y2) the second. The x axis is time progress and the y axis is the animation's output progress, so the shape of the curve defines how the motion speeds up and slows down.

Why can y go above 1 or below 0 while x cannot?

Control-point x must stay within [0,1] because time cannot run backwards — the curve has to remain a function of progress. Control-point y is free: values above 1 make the animation overshoot its target before settling back (easeOutBack), and values below 0 pull it backwards first (easeInBack). That is exactly how bounce and anticipation are built.

How do I make an animation overshoot or bounce?

Drag the second control point above the top edge of the box so y2 is greater than 1. `cubic-bezier(0.175, 0.885, 0.32, 1.275)` peaks at about 8.7% past the final value, then returns. For anticipation, drag the first control point below the bottom so y1 is negative.

Is the preview a real CSS animation or a simulation?

It is real. The demo dot is animated with a genuine `transition` using your exact cubic-bezier value, running next to a linear reference dot. What you see is what the browser will actually render, including any overshoot.

Why does a cubic-bezier timing function seem to do nothing on some properties?

Timing functions only interpolate properties that are animatable. Discrete properties such as `display` switch at the midpoint no matter what curve you supply, and non-animatable properties snap instantly. If nothing moves, the property itself is the problem, not the easing.

How do I reproduce an easing from a design system exactly?

Design systems usually publish the four control-point numbers. Either paste them mentally into the editor by dragging, or start from the closest built-in preset and nudge one handle at a time. The output value is what matters, so copy the `cubic-bezier(...)` string rather than trying to match it by eye.

Reviewed by the HandyTools Hub team · Last updated