tool / cubic-beziercss · javascript
Cubic-bezier generator
Drag the two control points, or type the numbers, and watch the curve race against ease or any named easing. Then copy the cubic-bezier() for CSS, or the same curve as a JavaScript easing function for svg-scroll-draw.
- CSS keywords
- 5
- Named curves
- 24
- Code outputs
- 3
- Gzipped
- 11.6 KB
Make a cubic-bezier easing
Start from a CSS keyword, one of svg-scroll-draw’s own easings or one of 24 named curves, then drag P1 and P2. The markers race over the duration you pick, the line is drawn by scrollDraw with your curve as its easing, and the browser check compares the JavaScript function with your browser’s own cubic-bezier().
Drag P1 or P2. Or focus one (Tab) and use the arrow keys: 0.01 a press, 0.1 with Shift. x stays between 0 and 1.
P1 (x1, y1) · P2 (x2, y2) · x is time, y is progress
A · easeOutBack1
B · ease (CSS)1
scrollDraw · easing: your curve1
progress · A 1 · B 1
- A · easeOutBack overshoots to 1.098 at 0.57 · half way at time 0.13
- B · ease (CSS) half way at time 0.29
- Browser check comparing your browser’s own cubic-bezier() with the JavaScript function…
Your system asks for reduced motion, so Play jumps to the end and the library shows the drawing finished. The editor, the time slider, the markers and the code still follow the curve.
/* easeOutBack, cubic-bezier(0.34, 1.56, 0.64, 1). It runs past the end to
1.098 and comes back. */
:root {
--ease-out-back: cubic-bezier(0.34, 1.56, 0.64, 1);
}
/* A transition: add .is-moved and the card moves along the curve. */
.card {
transition: transform 1s var(--ease-out-back);
}
.card.is-moved {
transform: translateX(240px);
}
/* A keyframe animation: the badge rises into place as the page loads. */
.badge {
animation: rise 1s var(--ease-out-back) both;
}
@keyframes rise {
from { transform: translateY(24px); }
}
/* Outside 0 to 1 a transform keeps going, while opacity and colours stop at
their limits. */How cubic-bezier() works
A cubic Bézier curve has four points. In an easing, the first is pinned at (0, 0), the start, and the last at (1, 1), the end; cubic-bezier(x1, y1, x2, y2) places the two between, P1 and P2. The curve leaves P0 heading for P1 and arrives at P3 from the direction of P2, and the further a point is from its end, the harder it pulls (fig. 1). Across is time, up is progress.
Both coordinates are cubics in a parameter s that runs along the curve. The browser knows the time, not s, so to ease time t it solves x(s) = t first and then reads y(s). The generator’s function does the same, with Newton–Raphson and bisection where the curve is flat. For ease:
// cubic-bezier(x1, y1, x2, y2), at a parameter s from 0 to 1:
x(s) = 3·x1·s·(1 − s)² + 3·x2·s²·(1 − s) + s³ // time
y(s) = 3·y1·s·(1 − s)² + 3·y2·s²·(1 − s) + s³ // progress
// To ease time t: solve x(s) = t for s, then return y(s).| Time t | Solved s | Progress y(s) | Newton steps |
|---|---|---|---|
| 0.25 | 0.4095 | 0.4085 | 3 |
| 0.5 | 0.6996 | 0.8024 | 4 |
| 0.75 | 0.8739 | 0.9605 | 4 |
cubic-bezier() with x1 or x2 outside 0–1 as invalid and drops the declaration. With both inside, x(s) never runs backwards, so each moment has one progress. The editor keeps x in range and lets y go anywhere from −5 to 5.cubic-bezier(1, 0, 0, 1) stops in x at its middle: the slope of x(s) is 0 at s = 0.5, where a Newton step would divide by zero. Near there the function halves the interval instead: at time 0.4999 it drops Newton at once and halves 14 times.Below 0 and past 1
Time stays between 0 and 1; progress does not have to. A y1 or y2 above 1 makes the motion run past its end and come back: easeOutBack peaks at 1.098 at time 0.57. Below 0 it pulls back before it sets off: easeInOutBack does both, down to -0.105 and up to 1.105. The editor draws those stretches of the curve in the accent.
A transform or a length goes past its end value and comes back.
Opacity is clamped to 0–1 and each colour channel to its range, so past the end they hold at the end.
In scrollDraw the dash slides beyond the end of the path, so past 1 the start of the line clears for a moment and fills back in, and below 0 a piece of its far end shows before the line begins. Try easeOutBack and easeInBack in the generator and watch the ends of the line.
linear() through many points, or svg-scroll-draw’s createBounce, createSpring and createElastic, all in the easing visualizer.once: true, svg-scroll-draw 2.23.2 and earlier keep the highest eased value reached in scrollDraw, scrollAnimate, scrollReveal and scrollCounter, so an easing that overshoots freezes on its peak: easeOutBack’s line stays short at its start, and a card stays 1.098 of the way along. 2.23.3 keeps the furthest scroll progress instead and eases it after, as scrollText already did, so the curve plays out and ends at 1.Named curves and their cubic-bezier values
The CSS keywords, as the CSS Easing spec defines them, beside svg-scroll-draw’s easings of the same name. Only linear is the same curve in both.
| Keyword | cubic-bezier | svg-scroll-draw’s own |
|---|---|---|
| ease | cubic-bezier(0.25, 0.1, 0.25, 1) | No easing of that name. |
| ease-in | cubic-bezier(0.42, 0, 1, 1) | 'ease-in' is t², up to 0.069 away. |
| ease-out | cubic-bezier(0, 0, 0.58, 1) | 'ease-out' is t(2 − t), up to 0.069 away. |
| ease-in-out | cubic-bezier(0.42, 0, 0.58, 1) | 'ease-in-out' is two quadratics, up to 0.012 away. |
| linear | cubic-bezier(0, 0, 1, 1) | 'linear', the same. |
The named curves are Robert Penner’s easing equations, as the cubic-béziers usually published for them. Most are close copies, not the equation itself; the third column says how close.
| Name | cubic-bezier | Off its equation by | Exactly |
|---|---|---|---|
| Sine | |||
| easeInSine | cubic-bezier(0.12, 0, 0.39, 0) | up to 0.008 | — |
| easeOutSine | cubic-bezier(0.61, 1, 0.88, 1) | up to 0.008 | — |
| easeInOutSine | cubic-bezier(0.37, 0, 0.63, 1) | up to 0.002 | — |
| Quad | |||
| easeInQuad | cubic-bezier(0.11, 0, 0.5, 0) | up to 0.002 | cubic-bezier(0.333333, 0, 0.666667, 0.333333) |
| easeOutQuad | cubic-bezier(0.5, 1, 0.89, 1) | up to 0.002 | cubic-bezier(0.333333, 0.666667, 0.666667, 1) |
| easeInOutQuad | cubic-bezier(0.45, 0, 0.55, 1) | up to 0.006 | — |
| Cubic | |||
| easeInCubic | cubic-bezier(0.32, 0, 0.67, 0) | up to 0.003 | cubic-bezier(0.333333, 0, 0.666667, 0) |
| easeOutCubic | cubic-bezier(0.33, 1, 0.68, 1) | up to 0.003 | cubic-bezier(0.333333, 1, 0.666667, 1) |
| easeInOutCubic | cubic-bezier(0.65, 0, 0.35, 1) | up to 0.01 | — |
| Quart | |||
| easeInQuart | cubic-bezier(0.5, 0, 0.75, 0) | up to 0.006 | — |
| easeOutQuart | cubic-bezier(0.25, 1, 0.5, 1) | up to 0.006 | — |
| easeInOutQuart | cubic-bezier(0.76, 0, 0.24, 1) | up to 0.03 | — |
| Quint | |||
| easeInQuint | cubic-bezier(0.64, 0, 0.78, 0) | up to 0.02 | — |
| easeOutQuint | cubic-bezier(0.22, 1, 0.36, 1) | up to 0.02 | — |
| easeInOutQuint | cubic-bezier(0.83, 0, 0.17, 1) | up to 0.04 | — |
| Expo | |||
| easeInExpo | cubic-bezier(0.7, 0, 0.84, 0) | up to 0.02 | — |
| easeOutExpo | cubic-bezier(0.16, 1, 0.3, 1) | up to 0.02 | — |
| easeInOutExpo | cubic-bezier(0.87, 0, 0.13, 1) | up to 0.04 | — |
| Circ | |||
| easeInCirc | cubic-bezier(0.55, 0, 1, 0.45) | up to 0.002 | — |
| easeOutCirc | cubic-bezier(0, 0.55, 0.45, 1) | up to 0.002 | — |
| easeInOutCirc | cubic-bezier(0.85, 0, 0.15, 1) | up to 0.04 | — |
| Back | |||
| easeInBack | cubic-bezier(0.36, 0, 0.66, -0.56) | up to 0.005 | cubic-bezier(0.333333, 0, 0.666667, -0.567193) |
| easeOutBack | cubic-bezier(0.34, 1.56, 0.64, 1) | up to 0.005 | cubic-bezier(0.333333, 1.567193, 0.666667, 1) |
| easeInOutBack | cubic-bezier(0.68, -0.6, 0.32, 1.6) | up to 0.04 | — |
ease-in and ease-out to CSS, within 0.0000002 of t² and t(2 − t). 6 of Penner’s equations are cubics (Quad, Cubic and Back, in and out), so the last column gives them exactly. The in-out ones are two curves joined at the middle, and sine, expo and circ are not polynomials, so no cubic-bezier is exact for them.A cubic-bezier in svg-scroll-draw
svg-scroll-draw’s easing option takes a name or any function of t, in scrollDraw, scrollAnimate, scrollReveal, scrollText, scrollCounter and every other API that eases. Paste the generated cubicBezier() and pass what it returns. In a scroll animation, time is the scroll position through the trigger window, so the curve decides how much of the motion each stretch of scroll gets.
import { scrollDraw, scrollAnimate } from 'svg-scroll-draw';
import { scrollReveal } from 'svg-scroll-draw/reveal';
// cubicBezier() is the function the generator writes (the scrollDraw tab).
const easeOutBack = cubicBezier(0.34, 1.56, 0.64, 1);
scrollDraw('#logo', { easing: easeOutBack });
scrollAnimate('#card', { props: { transform: ['scale(0.8)', 'scale(1)'] }, easing: easeOutBack });
scrollReveal('.feature', { easing: easeOutBack });
// svg-scroll-draw's own ease-in and ease-out are exact cubic-béziers: use the names.
scrollDraw('#chart', { easing: 'ease-out' }); // cubic-bezier(0.333333, 0.666667, 0.666667, 1)linear, ease-in, ease-out or ease-in-out, by name, and no other option needs JavaScript. A function always runs on the JavaScript engine. So when your curve is one of the library’s quadratics, the generator writes the name.svg-scroll-draw/aos, svg-scroll-draw/scrollreveal) animate with CSS transitions, so their easing takes the cubic-bezier() string itself, and so does AOS’s data-aos-easing attribute.Cubic-bezier questions
What is cubic-bezier() in CSS?
A CSS easing function given by four numbers, cubic-bezier(x1, y1, x2, y2). They place the two control points of a Bézier curve that runs from (0, 0) to (1, 1), with time across and progress up. Use it wherever CSS takes an easing: transition-timing-function, animation-timing-function, the transition and animation shorthands, or the easing of element.animate(). The keywords are cubic-béziers too: ease is cubic-bezier(0.25, 0.1, 0.25, 1).
How do I write a custom easing function in JavaScript?
An easing function takes time t from 0 to 1 and returns progress. For a cubic-bezier, solve x(s) = t for the curve parameter s, then return y(s). Newton–Raphson finds s in a few steps where the curve is not flat in x; bisection takes over where it is, and always finishes because x(s) never falls. The scrollDraw tab above writes the whole function, about 30 lines with no imports, and it works with any library that takes (t) => number.
Why must x1 and x2 be between 0 and 1?
Because x is time. CSS treats a cubic-bezier() with x1 or x2 outside 0–1 as invalid, so the browser drops the whole declaration. Inside that range x(s) never runs backwards, so every moment of time has exactly one progress. The y values have no limit, which is what lets a curve overshoot.
How do I make an overshoot or “back” easing with cubic-bezier?
Put a y outside 0–1. easeOutBack, cubic-bezier(0.34, 1.56, 0.64, 1), runs on to 1.098 and settles back at 1; a y below 0 pulls back before it starts. The curve’s y is a cubic in s, so it turns at most twice: one cubic-bezier can pull back once and overshoot once, as easeInOutBack does, but cannot bounce or ring. For that, use CSS linear() with many points, or svg-scroll-draw’s createBounce, createSpring and createElastic.
What is the difference between ease, ease-in-out and linear?
linear is cubic-bezier(0, 0, 1, 1): the same speed throughout. ease-in-out is cubic-bezier(0.42, 0, 0.58, 1), slow at both ends and symmetric, so it is half way at half time. ease, cubic-bezier(0.25, 0.1, 0.25, 1), speeds up early and spends most of its time slowing down: at half time it is already 0.802 of the way. ease is the default for both transitions and animations.
What are the cubic-bezier values for easeInOutCubic, easeOutCubic and the other named easings?
easeInOutCubic is usually written cubic-bezier(0.65, 0, 0.35, 1), easeOutCubic cubic-bezier(0.33, 1, 0.68, 1) and easeOutQuart cubic-bezier(0.25, 1, 0.5, 1); section 4 lists all 24. Most are approximations of Robert Penner’s equations, off by up to 0.04. 6 of the equations are cubic polynomials and so are exactly a cubic-bezier: easeOutCubic is exactly cubic-bezier(0.333333, 1, 0.666667, 1).
Can I use a cubic-bezier with svg-scroll-draw?
Yes. Every svg-scroll-draw API that takes easing takes a function of t, so pass the generated cubicBezier(…) function: scrollDraw('#logo', { easing: cubicBezier(0.34, 1.56, 0.64, 1) }). A function runs on the library’s JavaScript engine. svg-scroll-draw’s own 'ease-in' and 'ease-out' are exactly cubic-bezier(0.333333, 0, 0.666667, 0.333333) and cubic-bezier(0.333333, 0.666667, 0.666667, 1); the CSS keywords with the same names are different curves, up to 0.069 away.
Springs, bounces and every easing svg-scroll-draw names: the easing visualizer. Everything else in svg-scroll-draw 2.23.3: the docs.