Runs 100% in your browser — nothing is uploaded
CSS Cubic Bezier Generator
Drag two handles to shape an animation curve, watch it run on a live preview, then copy the cubic-bezier(). Includes 25+ easing presets, overshoot curves, steps() output, and snippets for CSS, SCSS, Tailwind and Framer Motion.
In short: what a cubic-bezier curve is, and what this tool does
A CSS cubic-bezier() timing function describes how an animation gets from its start value to its end value. It takes four numbers — cubic-bezier(x1, y1, x2, y2) — the coordinates of two control points. The horizontal axis is elapsed time (0 to 1) and the vertical axis is animation progress (0 to 1). This generator lets you drag those two points, preview the result on a real animation, and copy the CSS.
- The curve is fixed at both ends: it always starts at (0, 0) and ends at (1, 1). Only the two control points move.
- X must stay in 0–1 because time cannot run backwards. Y can go below 0 or above 1 — that is how you get anticipation and overshoot.
- Steeper means faster. A steep section is a fast part of the animation; a flat section is a slow part.
- The CSS keywords are just aliases:
ease is cubic-bezier(0.25, 0.1, 0.25, 1), ease-in-out is cubic-bezier(0.42, 0, 0.58, 1), and linear is the straight diagonal.
steps() is the other kind: it jumps in discrete increments instead of interpolating. Switch modes with the tab above the editor.
- Everything is local: the maths, the preview and the code generation run in your browser. Nothing is uploaded.
How to build a custom easing curve
Three steps, about a minute.
1
Start from a preset
Pick something close to what you want — ease-out for things arriving, ease-in for things leaving, easeOutBack for a playful overshoot. The preset loads its four values into the editor.
2
Drag the two handles
Reshape the curve by dragging the pink and purple points, or type exact values. Pull a handle past the top or bottom edge to overshoot. Handles are keyboard accessible — Tab to one, then use the arrow keys.
3
Preview, then copy
Press Play to run the curve on a real animation and turn on Compare to check it against a reference easing. Then copy it as CSS, SCSS, a Tailwind entry or a Framer Motion array — or share the permalink.
How to read the curve
The graph is not a picture of the motion path — it is a picture of progress over time.
This is the single most common misreading. If you animate an element horizontally, the curve does not show the shape it travels along. The X axis is time and the Y axis is how much of the animation is done. So a curve that shoots up quickly and then flattens means the element covers most of its distance early and then eases into place — an ease-out.
- Straight diagonal — constant speed. This is
linear, and it looks mechanical for anything representing physical movement.
- Flat then steep — starts slow, accelerates. An ease-in. Use it for elements leaving the screen.
- Steep then flat — starts fast, decelerates. An ease-out. Use it for elements arriving, menus opening, and almost every enter transition.
- Flat, steep, flat — an S-curve. An ease-in-out. Use it for moving something between two on-screen positions.
- Rises above the top edge — progress passes 100% and comes back. The element overshoots its target and settles.
- Dips below the bottom edge — progress goes negative first. The element pulls back before moving, like winding up.
Cubic bezier values for every common easing
The CSS keywords, the standard easings.net set, and the overshoot curves — with their exact values. Press Try to load one into the editor.
transition-timing-function vs animation-timing-function
Same value, meaningfully different behaviour. This trips people up constantly.
Fixing the double-easing problem
If a three-stop keyframe animation feels wrong, set animation-timing-function: linear on the element and put the real curve inside each keyframe block instead. That way each segment gets exactly the easing you intended.
Where overshoot curves silently stop working
A curve with Y above 1 or below 0 is valid CSS, but the property being animated still has its own limits.
The timing function produces a progress value, and the browser then interpolates the property using it. If the resulting value is outside what the property accepts, it gets clamped — so the overshoot disappears without any error.
Practical rule: use overshoot curves on transforms. If you want a bouncy fade, animate scale with the overshoot curve and opacity with a plain ease-out.
Frequently asked questions
Cubic bezier easing, answered.
What is cubic-bezier() in CSS?
cubic-bezier() is a CSS timing function that describes how an animation’s progress changes over its duration. It takes four numbers — cubic-bezier(x1, y1, x2, y2) — which are the coordinates of two control points. The curve always starts at (0, 0) and ends at (1, 1); the horizontal axis is elapsed time and the vertical axis is how far along the animation is.
A straight diagonal line is linear. A curve that rises steeply then flattens is an ease-out. It is accepted anywhere a timing function is: transition-timing-function, animation-timing-function, the transition and animation shorthands, and the easing option of the Web Animations API.
Can cubic-bezier values be greater than 1 or negative?
The Y values can be anything, including negative numbers and values above 1 — that is exactly how you get overshoot and anticipation. cubic-bezier(0.34, 1.56, 0.64, 1) overshoots the target and settles back.
The X values must stay between 0 and 1, because they represent time and time cannot run backwards. A value outside that range makes the whole declaration invalid and the browser falls back to the property’s previous value. This generator clamps X automatically and lets you drag Y outside the unit square.
What are the cubic-bezier values for ease, ease-in, ease-out and ease-in-out?
The CSS keywords are exact aliases for specific curves:
linear = cubic-bezier(0, 0, 1, 1)
ease = cubic-bezier(0.25, 0.1, 0.25, 1)
ease-in = cubic-bezier(0.42, 0, 1, 1)
ease-out = cubic-bezier(0, 0, 0.58, 1)
ease-in-out = cubic-bezier(0.42, 0, 0.58, 1)
Worth knowing: ease is not symmetrical. It accelerates gently and then decelerates for much longer, which is why it often feels sluggish at the end. If you want a symmetrical S-curve, use ease-in-out.
Why can’t cubic-bezier() produce a real bounce or spring?
A cubic bezier with fixed endpoints can only change direction once, so it can overshoot and settle a single time. A true bounce or a damped spring crosses the target several times, which needs multiple oscillations that a single cubic curve cannot express.
For those, you have three options: CSS @keyframes with several stops, the linear() timing function with a list of sampled points, or a spring physics library. This tool covers single-overshoot curves, which handle the vast majority of UI motion.
What is the difference between steps() and cubic-bezier()?
cubic-bezier() interpolates smoothly. steps(n, jumpterm) advances in n discrete jumps with no motion in between — useful for sprite-sheet animations, typewriter effects and ticking counters.
The jump term controls where the jumps happen. jump-end (the default) holds the start value first. jump-start jumps immediately. jump-none spreads n−1 jumps so the animation reaches both endpoints. jump-both jumps at both ends, so it never sits on either endpoint. The old step-start and step-end keywords are shorthands for steps(1, jump-start) and steps(1, jump-end).
Which easing should I use for UI animations?
For an element entering the screen or a state that appears, use an ease-out curve so it arrives fast and settles gently — cubic-bezier(0.16, 1, 0.3, 1) is a popular choice. For something leaving, use ease-in so it accelerates away and you do not have to wait for it. For a move between two on-screen positions, use ease-in-out.
Reserve overshoot curves for playful, attention-drawing moments — a success checkmark, a like button. And avoid linear for anything that represents physical movement; keep it for continuous things like spinners and progress bars.
How do I use a custom cubic-bezier in Tailwind CSS?
In Tailwind v3, add it under theme.extend.transitionTimingFunction in tailwind.config.js, then use it as a class like ease-smooth. In Tailwind v4 you declare it as a CSS variable such as --ease-smooth inside your @theme block, and the utility is generated for you.
The Tailwind tab in this generator outputs both forms with your current curve filled in.
Does animation-timing-function apply to the whole animation or each keyframe?
Per keyframe segment. If you set animation-timing-function on the element, the curve is applied between every pair of adjacent keyframes — not once across the whole animation. So a three-stop keyframe animation runs the easing twice, which usually is not what you wanted.
Set animation-timing-function inside individual keyframe blocks to control each segment separately. transition-timing-function, by contrast, applies once across the whole transition.
Do easing curves respect prefers-reduced-motion?
Not on their own — a timing function has no idea about user preferences. You have to handle it yourself, and you should. Wrap your motion in @media (prefers-reduced-motion: reduce) and either shorten durations dramatically or replace movement with a plain opacity fade.
Overshoot and bounce curves are the ones most likely to cause discomfort, so those are the first to drop for users who have asked for less motion.
Is this cubic bezier generator free, and is my data uploaded?
It is completely free with no sign-up. Everything — the curve maths, the preview and the code generation — runs in your browser with JavaScript. Nothing is uploaded, and the page keeps working offline once loaded. Your recent curves are stored only in your own browser’s local storage, and you can clear them at any time by clearing site data.