Cubic Bezier Generator: Engineering Precise CSS Animations
Motion design is not decoration — it is communication. A well-crafted easing curve tells the user that a modal is dismissible, that a button responds to touch, that a loading state is temporary. A poorly chosen ease-in-out applied uniformly to every transition communicates nothing but inattention. The cubic bezier generator gives you surgical control over every frame of your CSS animations.
The Mathematics of Easing Curves
A cubic Bézier curve is defined by four points: P0 (start), P1 (first control handle), P2 (second control handle), and P3 (end). In CSS cubic-bezier(), P0 is always (0, 0) and P3 is always (1, 1) — representing the start and end of both time and progress. You control only P1 and P2, each expressed as (x, y).
The parametric equations for a cubic Bézier curve are:
B(t) = (1−t)³·P0 + 3·(1−t)²·t·P1 + 3·(1−t)·t²·P2 + t³·P3
where t ∈ [0, 1]. The CSS animation engine samples this curve at each frame's time coordinate to determine progress. Because P1 and P2 can have y values outside [0, 1], the curve can overshoot — producing spring-like bounce effects that go beyond the final value before settling.
The x component of P1 and P2 must stay in [0, 1] (otherwise the function is not monotonic in time and the CSS spec disallows it). The y component has no such restriction, which is what enables elastic overshoot.
CSS Native Easing Functions vs. Custom Curves
CSS provides five named timing functions as syntactic sugar over cubic-bezier():
| CSS keyword | Equivalent cubic-bezier |
|---|---|
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) |
These presets cover common cases, but real interfaces demand more nuance. A bottom sheet sliding up from below feels more natural with a sharp ease-out (cubic-bezier(0.16, 1, 0.3, 1)) that decelerates quickly near its target. A confirmation badge popping in benefits from gentle overshoot (cubic-bezier(0.34, 1.56, 0.64, 1)). No named function maps to these behaviours.
How to Use the Generator
Control points panel — Drag P1 (the lower handle) and P2 (the upper handle) on the SVG canvas, or type values directly into the coordinate inputs. The curve updates in real time.
Preset library — Eight curated presets cover the most common interaction patterns:
- Snappy — fast start, smooth landing. Best for menus and drawers.
- Elastic — mild overshoot. Best for scale or position entrances.
- Bounce-soft — gentle deceleration with a single overshoot.
- Anticipate — brief negative motion before the main movement, adds physicality.
- Linear — constant velocity. Best for progress bars and loaders.
Animation preview — A dot traverses the curve in real time at the duration you set. Watch the velocity: steep sections mean fast motion, flat sections mean slow motion. The dot position on the vertical axis represents progress value (not just time), so overshoot is visible.
Copy button — Outputs the cubic-bezier(x1, y1, x2, y2) string ready to paste into any CSS property.
Where to Apply Custom Easing
/* Slide-in panel */
.panel {
transform: translateX(-100%);
transition: transform 320ms cubic-bezier(0.16, 1, 0.3, 1);
}
.panel.open {
transform: translateX(0);
}
/* Scale entrance for dialogs */
.dialog {
transform: scale(0.96);
opacity: 0;
transition:
transform 200ms cubic-bezier(0.34, 1.56, 0.64, 1),
opacity 150ms ease-out;
}
.dialog.visible {
transform: scale(1);
opacity: 1;
}
A key engineering practice: use different curves for enter and exit. Entrances should be fast-in (ease-out family) — the UI element rushes to the user. Exits should be fast-out (ease-in family) — the element retreats quickly so it does not block the next interaction.
CSS Animation vs. Web Animations API
cubic-bezier() works identically in both the CSS transition/animation syntax and the Web Animations API:
element.animate(
[{ transform: 'translateY(20px)', opacity: 0 },
{ transform: 'translateY(0)', opacity: 1 }],
{
duration: 300,
easing: 'cubic-bezier(0.16, 1, 0.3, 1)',
fill: 'forwards',
}
);
The WAAPI gives you programmatic control (play, pause, reverse, finish) without toggling CSS classes. For orchestrated sequences — staggered list items, multi-step transitions — it is far more maintainable than layered CSS delays.
Best Practices for Production Motion
Match duration to distance. A tooltip appearing near the cursor needs only 150–180 ms. A full-screen modal entrance can afford 280–350 ms. Long durations with linear curves feel sluggish; short durations with aggressive easing feel jarring.
Respect prefers-reduced-motion. Always wrap non-essential animations:
@media (prefers-reduced-motion: reduce) {
* { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }
}
Do not animate layout properties. width, height, padding, top, and left trigger layout recalculation on every frame. Stick to transform and opacity, which are composited by the GPU and run on a separate thread.
Test on real devices. The browser DevTools animation inspector and throttled CPU mode reveal jank that is invisible at full speed on a development machine.
Comparing Easing Tools
| Tool | Custom curve | Live preview | Copy CSS | Offline |
|---|---|---|---|---|
| This generator | ✓ | ✓ | ✓ | ✓ (browser) |
| Chrome DevTools | ✓ | ✓ | Manual | Requires DevTools |
| cubic-bezier.com | ✓ | ✓ | ✓ | ✗ |
| Framer Motion | Via code only | Via rendering | N/A | Requires install |
The developer utility here combines the key features in a single zero-setup interface, with the added benefit of curated presets that reflect real-world animation patterns rather than abstract demonstrations.