Cubic Bezier Generator
Drag an easing curve, preview the motion and copy cubic-bezier() — plus a modern linear() spring & bounce generator — on this device.
Drag a handle, or focus one and use the arrow keys to move by 0.01 (hold Shift for 0.1).
Motion preview is paused because your system requests reduced motion — press Play to run it once.
cubic-bezier(0.42, 0, 0.58, 1)ease-[cubic-bezier(0.42,0,0.58,1)]linear() easing is Baseline 2024 — older browsers ignore it. Keep a cubic-bezier() fallback for wider support.
This curve leaves 0–1 (overshoot/anticipation) — great for playful motion; verify it doesn't clip your layout.
Do it offline:$ cat easing.css >> src/tokens.css
How to use it
- Pick a preset chip — the five CSS keywords or the easings.net set — or keep the default ease-in-out.
- Drag either handle in the curve pane — or focus a handle and nudge it with the arrow keys, 0.01 a press and 0.1 with Shift — or set x1, y1, x2 and y2 by number.
- Watch the sample element run the timing on the preview track, and set the preview duration.
- Copy the cubic-bezier() value, switch to its custom-property or Tailwind form, download a .css file, or share a link.
- Open the linear() tab, choose spring or bounce, tune the physics, and copy the generated linear() easing.
Shape a CSS easing curve by dragging its two control handles, or type the four cubic-bezier() coefficients, and a sample element eases across the preview using the exact value you copy. A second tab turns spring and bounce physics into a modern linear() easing — motion one cubic-bezier() cannot describe. Presets, paste-to-import and a shareable permalink are built in, and every number is worked out on this device.
How it works
A cubic-bezier() easing is one cubic Bezier curve from P0 at (0, 0) to P3 at (1, 1), bent by two control points — (x1, y1) near the start, (x2, y2) near the end. Its X axis is time and its Y axis is progress, so the browser reads progress off the curve. Time runs forward, which is why each X is held between 0 and 1; Y has no limit, and a point below 0 or above 1 makes the curve overshoot.
One cubic segment bends only so far, so it cannot trace a spring that reverses or a ball that bounces. The linear() function fills the gap: it lists value-and-position stops the browser joins with straight lines, turning any shape into a dense polyline. The tool samples the physics and prints the fewest stops that still trace the motion.
Examples
Default ease-in-out — the curve the editor opens oncubic-bezier(0.42, 0, 0.58, 1)This symmetric ease-in-out loads first, so the preview is never frozen — progress starts slow, quickens through the middle and settles gently.
Overshoot "back" curve — cubic-bezier(0.68, -0.55, 0.27, 1.55)cubic-bezier(0.68, -0.55, 0.27, 1.55)y1 = -0.55 and y2 = 1.55 sit outside 0 to 1, so the element winds back before it starts and coasts past its mark. The editor keeps it and raises an overshoot note — legal CSS unless the motion clips.
Spring → linear() — mass 1, stiffness 100, damping 10linear(0, 0.0131 1.3%, 0.0494 2.6%, 0.1044 3.9%, 0.1738 5.19%, 0.2537 6.49%, 0.4305 9.09%, 0.6105 11.69%, 0.6959 12.99%, 0.7759 14.29%, 0.8494 15.58%, 0.9155 16.88%, 0.9735 18.18%, 1.0234 19.48%, 1.0649 20.78%, 1.0985 22.08%, 1.1244 23.38%, 1.1431 24.68%, 1.1553 25.97%, 1.1616 27.27%, 1.1629 28.57%, 1.1531 31.17%, 1.1184 35.06%, 1.0336 42.86%, 1.0023 46.75%, 0.9828 50.65%, 0.9744 54.55%, 0.977 61.04%, 1.0012 76.62%, 1.0037 89.61%, 1)On the linear() tab a damped spring becomes copyable CSS: it climbs past 1 to about 1.16 before settling, and the editor reports "Reduced 78 samples to 31 stops."
Bounce → linear() — four bounces, damping 10linear(0, 0.0069 1.8%, 0.0278 3.61%, 0.0625 5.41%, 0.1111 7.21%, 0.1736 9.02%, 0.25 10.82%, 0.3403 12.62%, 0.4444 14.43%, 0.5625 16.23%, 0.6944 18.03%, 0.8403 19.84%, 1 21.64%, 0.9201 22.91%, 0.8472 24.19%, 0.7813 25.46%, 0.7222 26.74%, 0.6701 28.01%, 0.625 29.29%, 0.5868 30.56%, 0.5556 31.84%, 0.5313 33.11%, 0.5139 34.39%, 0.5035 35.66%, 0.5 36.94%, 0.5035 38.21%, 0.5139 39.49%, 0.5313 40.77%, 0.5556 42.04%, 0.5868 43.32%, 0.625 44.59%, 0.6701 45.87%, 0.7222 47.14%, 0.7813 48.42%, 0.8472 49.69%, 0.9201 50.97%, 1 52.24%, 0.9236 54.04%, 0.8611 55.85%, 0.8125 57.65%, 0.7778 59.45%, 0.7569 61.26%, 0.75 63.06%, 0.7569 64.86%, 0.7778 66.67%, 0.8125 68.47%, 0.8611 70.27%, 0.9236 72.08%, 1 73.88%, 0.9453 75.79%, 0.9063 77.7%, 0.8828 79.62%, 0.875 81.53%, 0.8828 83.44%, 0.9063 85.36%, 0.9453 87.27%, 1 89.18%, 0.9653 90.98%, 0.9444 92.79%, 0.9375 94.59%, 0.9444 96.39%, 0.9653 98.2%, 1)Bounce draws gravity arcs whose peaks halve each time — 0.5, 0.25, 0.125 then 0.0625 of the drop — so progress returns to 1 at every landing. Curved arcs need many segments, so this one needs 63 stops ("Reduced 121 samples to 63 stops.").
Every example on this page is executed against the same engine that powers the tool, on every build.
Gotchas worth knowing
A control point's X cannot leave 0 and 1
Time runs forward, so an X outside 0 to 1 is invalid CSS; a pasted cubic-bezier(1.2, 0, 0.58, 1) is refused, not repaired.
A Y beyond 0 and 1 is allowed on purpose
Progress may overshoot and return, so a y1 or y2 outside the band is kept, never clamped — the way a back easing anticipates and overshoots.
A linear() value gets long, and that is expected
Curves need many short segments; the simplifier drops the redundant ones, yet a lively motion still prints dozens.
The preview obeys a reduced-motion request
Ask the system for less motion and the sample element loads still, drawing the curve until you press Play.
linear() is a 2024 baseline
linear() reached Baseline in 2024, so older engines ignore it; place a plain cubic-bezier() before it as the fallback.
linear() comes out but does not go back in
A generated linear() cannot be turned back into spring or bounce settings, so import takes cubic-bezier() values and easing keywords only.
Common errors
could not parse near `foo` — expected a number for the y1 coefficient.- A non-numeric coefficient stops the import at that token, and its offset rides along so Jump to error selects the spot.
cubic-bezier() needs exactly 4 numbers — found 3.- It takes four coefficients — x1, y1, x2, y2 — and the message names how many the parser counted.
The first control point's X (1.2) must be between 0 and 1 — CSS rejects a cubic-bezier() whose X is below 0 or above 1.- An explicit X out of range is refused on paste, never silently pulled in; dragging keeps X in range.
Input is larger than the 1,024-character limit for this tool. To add a saved easing to a stylesheet use the CLI: cat easing.css >> src/tokens.css- The import row takes one easing value, not a stylesheet; past 1,024 characters it shows this banner, whose CLI line appends a saved easing.
FAQ
What is a cubic-bezier easing?
It is a CSS timing function: one cubic Bezier curve from (0, 0) to (1, 1). Its two control points set how progress speeds up and slows down, and the four numbers they make are the cubic-bezier() value.
What is CSS linear() and when do springs and bounces need it?
linear() lists value-and-position stops joined by straight lines, so it can approximate a shape one cubic curve cannot — one that reverses or repeats. Springs and bounces do, so the tool renders them as a linear() polyline, not a cubic-bezier().
Why must a control point's X stay between 0 and 1?
The X axis of an easing is time, which advances at a fixed forward pace, so an X below 0 or above 1 would place progress outside the transition. The spec forbids it, so the editor keeps X within 0 to 1 while Y stays free to overshoot.
Keyboard shortcuts
- ⌘/Ctrl + C
- Copy the current cubic-bezier() or linear() value while nothing is selected.
- ⌘/Ctrl + Shift + C
- Copy the easing value even when text is selected.
- ⌘/Ctrl + S
- Save a .css download instead of the browser's save-page dialog.
- ? or ⌘/Ctrl + /
- Open the shortcut overlay.
- t
- Cycle the color theme unless a field is focused.
- Esc
- Dismiss the topmost dialog; the curve stays put.