CSS Tools

Cubic Bezier Generator

Use this free Cubic Bezier Generator to design custom CSS easing curves visually. Drag the two control points, watch a live animation preview, and copy the cubic-bezier() value straight into your stylesheet. No sign-up required.

Visual Curve Editor Live Preview 100% Free
Drag the green (P1) and red (P2) points inside the box, or edit numeric values. Preview updates live — generated CSS is ready to copy.
Control Points (0.00 — 1.00)
Origin: bottom-left
Animation Preview
cubic-bezier(0.25, 0.10, 0.25, 1.00) 1s
/* CSS will appear here */
Live Coordinates
Type or drag
P1
x: 0.25, y: 0.10
P2
x: 0.25, y: 1.00
Tip: Values are clamped between 0 and 1. Use presets for common easings.

Why You Are Here

Animation timing is the difference between an interface that feels considered and one that feels cheap. The duration matters, but the easing curve, how the motion accelerates and decelerates, is what people actually perceive as quality, even though almost nobody could name it.

The problem is that cubic-bezier(0.34, 1.56, 0.64, 1) tells you nothing by looking at it. Four decimals do not communicate motion. You have to see the curve and watch it play.

The first situation is that the built-in keywords are not enough. CSS gives you ease, ease-in, ease-out, ease-in-out, and linear. They are fine, but they are also the defaults everyone else uses, and ease in particular has a slightly dated, sluggish feel. A custom curve is how an interface develops a motion character of its own.

The second is design handoff. A motion designer specifies easing in After Effects or Figma, and you need the equivalent cubic-bezier() values to reproduce that feel in CSS rather than approximating by eye.

The third is simply learning. Dragging the handles and watching the animation respond teaches you how bezier curves work far faster than reading about control points.

What This Tool Does

The Cubic Bezier Generator gives you a visual curve editor with two draggable control points and a live animation preview.

Drag the handles to reshape the curve, or type exact coordinate values if you are matching a specification. The preview animation replays as you adjust, so you can feel the difference rather than guessing from numbers. Start from a preset if you want a known-good curve as a base.

When the motion feels right, copy the cubic-bezier() value into your stylesheet.

Everything runs in your browser. Nothing is uploaded or stored.

How Cubic Bezier Easing Works

A cubic bezier curve maps TIME (horizontal axis) to PROGRESS (vertical axis). The animation always starts at (0,0) and ends at (1,1). Those two points are fixed. What you control is the two points in between.

transition-timing-function: cubic-bezier(x1, y1, x2, y2);

/* x1, y1 = first control point, governs how the animation begins
   x2, y2 = second control point, governs how it ends */

Reading the curve is straightforward once you know what to look for. Where the curve is STEEP, progress is changing quickly, so the animation is moving fast. Where it is SHALLOW, the animation is slow. A curve that starts shallow and ends steep accelerates. One that starts steep and ends shallow decelerates.

The rule that catches everyone

X values must be between 0 and 1. Y values can be anything.

X represents time, and time cannot run backwards or extend past the animation's duration. If you enter an X value below 0 or above 1, the value is invalid and the browser discards the entire declaration. Your element will simply not animate, with no error message.
Y is where overshoot comes from

Y represents progress, and progress is allowed to exceed its endpoints. A Y value above 1 means the animation overshoots past its target and settles back. A Y value below 0 means it pulls backwards before moving forward. This is where snappy, spring-like motion comes from.

CSS Keyword Equivalents

Every built-in easing keyword is a cubic bezier underneath. These are exact.

Keyword

Equivalent cubic-bezier()

Character

linear

cubic-bezier(0, 0, 1, 1)

Constant speed, mechanical

ease

cubic-bezier(0.25, 0.1, 0.25, 1)

CSS default, gentle both ends

ease-in

cubic-bezier(0.42, 0, 1, 1)

Starts slow, ends fast

ease-out

cubic-bezier(0, 0, 0.58, 1)

Starts fast, ends slow

ease-in-out

cubic-bezier(0.42, 0, 0.58, 1)

Slow at both ends

Worth knowing: ease is the default for transitions when you do not specify a timing function, and it is rarely the best choice. It eases at both ends fairly symmetrically, which reads as slightly soft and dated. Most modern design systems replace it with a curve that decelerates more sharply.

Preset Curve Reference

Approximate cubic-bezier() equivalents for the standard easing families. These are the values used across most animation libraries.

Easing

cubic-bezier() Value

easeInSine

0.12, 0, 0.39, 0

easeOutSine

0.61, 1, 0.88, 1

easeInOutSine

0.37, 0, 0.63, 1

easeInQuad

0.11, 0, 0.5, 0

easeOutQuad

0.5, 1, 0.89, 1

easeInOutQuad

0.45, 0, 0.55, 1

easeInCubic

0.32, 0, 0.67, 0

easeOutCubic

0.33, 1, 0.68, 1

easeInOutCubic

0.65, 0, 0.35, 1

easeInQuart

0.5, 0, 0.75, 0

easeOutQuart

0.25, 1, 0.5, 1

easeInOutQuart

0.76, 0, 0.24, 1

easeInExpo

0.7, 0, 0.84, 0

easeOutExpo

0.16, 1, 0.3, 1

easeInOutExpo

0.87, 0, 0.13, 1

easeInCirc

0.55, 0, 1, 0.45

easeOutCirc

0, 0.55, 0.45, 1

easeInBack (undershoot)

0.36, 0, 0.66, -0.56

easeOutBack (overshoot)

0.34, 1.56, 0.64, 1

easeInOutBack

0.68, -0.6, 0.32, 1.6

Material Design curves

Purpose Value

Standard

0.4, 0.0, 0.2, 1

Decelerate (entering)

0.0, 0.0, 0.2, 1

Accelerate (exiting)

0.4, 0.0, 1, 1

Choosing Easing and Duration Together

A well-shaped curve at the wrong duration still feels wrong. These two decisions are inseparable, and the pairing below covers most interface work.

Element Duration

Suggested Easing

Reasoning

Button hover

150ms

ease-out

Must feel immediate

Button press

100ms

ease-out

Instant feedback

Tooltip appear

150ms

ease-out

Fast, unobtrusive

Dropdown open

200ms

ease-out

Quick, decisive

Dropdown close

150ms

ease-in

Exits faster than entries

Modal open

250ms

0.0, 0.0, 0.2, 1

Decelerates into place

Modal close

200ms

0.4, 0.0, 1, 1

Accelerates away

Accordion expand

250ms

ease-in-out

Smooth both directions

Page transition

300ms

0.4, 0.0, 0.2, 1

Larger movement, more time

Toast slide in

300ms

0.34, 1.56, 0.64, 1

Slight overshoot draws the eye

Loading spinner

800ms+

linear

Rotation must not pulse

Exits should be faster than entries

When something appears, the user needs a moment to register it. When it leaves, they have already moved on, and a slow exit feels like the interface is holding them up. Shortening the exit duration by a third is a reliable improvement.
Do not reverse a curve for the opposite direction

ease-out is right for entering because it decelerates into position. Using that same curve for exiting means the element speeds up and then crawls out of view, which feels wrong. Use ease-in for exits so the element accelerates away cleanly.

What Cubic Bezier Cannot Do

This is worth being precise about, because several easing tools list bounce and elastic presets that do not do what their names suggest.

A cubic bezier curve can overshoot its target ONCE and settle back. It CANNOT oscillate. True bounce, hitting the target, rebounding, hitting again with less energy, and repeating, requires the value to reverse direction multiple times, and a single cubic bezier is mathematically incapable of that shape.

Option one: keyframes

@keyframes bounce {
  0%   { transform: translateY(-100px); }
  50%  { transform: translateY(0); }
  70%  { transform: translateY(-20px); }
  85%  { transform: translateY(0); }
  92%  { transform: translateY(-6px); }
  100% { transform: translateY(0); }
}

Option two: the linear() function

This is the modern approach. It accepts an arbitrary list of progress stops, so it can describe oscillation that cubic-bezier() cannot.

transition-timing-function: linear(
  0, 0.25, 0.6, 0.9, 1, 0.95, 1
);

/* linear() is supported in current versions of Chrome, Firefox,
   Safari, and Edge. If you support older browsers, declare a
   cubic-bezier() fallback before it. */

Accessibility — Respecting Reduced Motion

Almost no easing tool mentions this, and it matters more than the curve you choose.

Some people experience genuine nausea, dizziness, or migraine from interface motion, particularly large movement, parallax, and zoom effects. Operating systems expose a reduce motion setting for exactly this reason, and CSS can read it.

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
Reducing rather than removing motion is often the better approach for functional animation. If a dropdown opening instantly makes the interface harder to follow, keep a very short fade rather than removing the transition entirely. What matters is eliminating large, sustained, or unexpected movement. Ship a reduced-motion rule on any site with meaningful animation. It takes eight lines.

Common Mistakes to Avoid

Using an X Value Outside 0 to 1

Overshoot comes from the Y values, not the X values. If you set an X below 0 or above 1 trying to create a spring effect, the cubic-bezier() value becomes invalid and the browser silently discards the whole declaration. Your element will not animate at all, and there will be no console error explaining why. If a transition suddenly stops working after you adjust a curve, check the X values first.
Animating Properties That Force Layout Recalculation

The easing curve is irrelevant if the animation is dropping frames. Animating width, height, top, left, margin, or padding forces the browser to recalculate layout on every frame, which is expensive. Animating transform and opacity does not, because those can be handled by the compositor. Use transform: translate() instead of left, and transform: scale() instead of width, wherever the effect allows.
Making the Duration Long Enough to Notice the Curve

There is a temptation to slow an animation down so the carefully designed easing is visible. Resist it. Most interface transitions should sit between 150ms and 400ms. Beyond roughly half a second, an interaction starts to feel like it is lagging rather than animating, no matter how good the curve is. The easing determines how the motion feels; the duration determines whether the user experiences it as responsive or slow.

Quick Reference

Item Value

X range

0 to 1 (required)

Y range

Any value

Y above 1

Overshoot

Y below 0

Undershoot

ease

0.25, 0.1, 0.25, 1

ease-out

0, 0, 0.58, 1

Entry

Decelerate

Exit

Accelerate, and shorter

Typical duration

150 to 400ms

Animate

transform, opacity

True bounce

Use linear() or keyframes

Always ship

prefers-reduced-motion

 

 

 

 

 

Frequently Asked Questions

What is a cubic bezier generator?

A cubic bezier generator is a free online tool for designing custom CSS easing curves visually. Instead of guessing at four decimal values, you drag two control points on a graph and watch a live animation preview respond immediately. This Cubic Bezier Generator then gives you the cubic-bezier() value to copy into your stylesheet.

What do the four numbers in cubic-bezier() mean?

They are the coordinates of two control points: cubic-bezier(x1, y1, x2, y2). The first pair shapes the beginning of the animation and the second pair shapes the end. The curve maps time on the horizontal axis to animation progress on the vertical axis, and its shape determines where the motion speeds up and slows down.

Why does my animation stop working when I change the values?

Almost certainly because an X value fell outside the 0 to 1 range. X represents time, which cannot run backwards or exceed the duration, so any X below 0 or above 1 makes the entire declaration invalid and the browser ignores it, with no error message. Y values have no such restriction and can go above 1 or below 0 freely.

How do I create a bounce or spring effect?

For a single overshoot, set the second Y value above 1. A curve like cubic-bezier(0.34, 1.56, 0.64, 1) pushes past the target and settles back, which reads as a snappy spring. For true bounce with multiple rebounds, cubic-bezier() is mathematically incapable of it, because it cannot oscillate. Use @keyframes or the newer linear() timing function instead.

What is the difference between ease-in and ease-out?

ease-in starts slowly and accelerates, which suits elements leaving the screen. ease-out starts quickly and decelerates, which suits elements arriving. The common mistake is using the same curve in both directions. Entrances should decelerate into place and exits should accelerate away, so they need different curves rather than one reversed.

What is a good duration for CSS animations?

Most interface transitions belong between 150ms and 400ms. Hover states and small feedback work best around 100 to 150ms. Dropdowns and tooltips suit 150 to 250ms. Modals and page-level transitions can stretch to 300 or 400ms because they involve more movement. Past about 500ms, interactions begin to feel sluggish regardless of the easing curve.

Which easing should I use for a modal or dropdown?

Use a decelerating curve for opening, so the element slows as it settles: cubic-bezier(0.0, 0.0, 0.2, 1) works well. Use an accelerating curve for closing, so it speeds away: cubic-bezier(0.4, 0.0, 1, 1). Make the closing duration shorter than the opening duration, since users have already moved on mentally by the time something is dismissed.

Do I need to worry about accessibility with animations?

Yes. Interface motion can trigger nausea, dizziness, and migraine in some people, which is why operating systems provide a reduce-motion preference. Wrap a @media (prefers-reduced-motion: reduce) rule around shortened or disabled transitions so those users get a calmer experience. This Cubic Bezier Generator helps you design the motion; the reduced-motion rule ensures it is not forced on people who cannot tolerate it.

Comments

Login to leave a comment

No comments yet. Be the first to comment!