How-to
How to find the easing curve of any animation
Find the easing curve a site uses: the DevTools easing editor, getAnimations() and getKeyframes(), GSAP eases as cubic-bezier, and linear() springs.
Two animations with the same duration and the same distance can feel completely different. The difference is the easing curve. It is the reason one site's menu feels quick and expensive while another's feels sluggish, and it is the hardest part to copy by eye.
The good news: the browser has to know the curve to play the animation, so you can usually read it directly. This guide covers where to look in Chrome, how to read it from the console, how to translate GSAP eases into CSS, and what to do with spring curves.
Step 1: look in the Styles pane
For CSS transitions and keyframe animations, the curve is sitting in the stylesheet.
- Inspect the element. Right-click it and choose Inspect.
- Find the timing function. In Elements > Styles, look at
transition,transition-timing-function,animationoranimation-timing-function. Expand the shorthand with the small triangle if needed. If the rule only applies on hover, click :hov and tick:hoverfirst. - Open the easing editor. Click the small curve icon next to the value. A popover shows the curve, the two control points and a moving preview dot. Drag a point and the value in Styles updates, which tells you what each number does.
- Check the keyframes. For a
@keyframesanimation, click the animation name to jump to the rule. Individual keyframes can set their ownanimation-timing-function, which overrides the one on the element for that segment.
That last point catches people out. A bounce animation might use ease-in on the way down and ease-out on the way up, set inside the keyframes. The element's own animation shorthand will not tell you that.
Step 2: read it from the console
When the stylesheet is minified, spread across many rules, or the animation was created with element.animate(), the console is quicker. document.getAnimations() returns every running CSS animation, CSS transition and Web Animations API animation.
The quick version reads the effect-level easing:
document.getAnimations().map(a => a.effect.getComputedTiming().easing);
// e.g. ["cubic-bezier(0.22, 1, 0.36, 1)", "linear", "ease-out"]
If you see linear for something that clearly is not linear, the easing is set per keyframe. That is always the case for CSS animations, where animation-timing-function applies to each keyframe interval. Read it from the keyframes instead:
document.getAnimations().forEach(a => {
const name = a.animationName || a.transitionProperty || a.id || 'animation';
const perKeyframe = a.effect.getKeyframes().map(k => `${k.offset}: ${k.easing}`);
console.log(name, a.effect.target, {
effect: a.effect.getComputedTiming().easing,
keyframes: perKeyframe
});
});
Run it while the animation is playing, or pause it first in the Animations panel (More tools > Animations), because finished animations without a fill drop out of the list. To scope it to one element, select it in Elements and use $0.getAnimations(). Our guide to inspecting CSS animations in Chrome DevTools covers the panel in more detail.
Know the CSS keywords
Half the time, the answer is a keyword. It helps to know what each one really is, because the easing editor and the console may show either form:
| Keyword | Same as |
|---|---|
ease (the default) | 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) |
linear | cubic-bezier(0, 0, 1, 1) |
If a site uses ease, it may simply mean nobody chose a curve. The distinctive feel you noticed is more likely to come from a custom cubic-bezier(), a per-keyframe ease, or a JavaScript library.
Step 3: if the site uses GSAP
If getAnimations() returns nothing for an element that is clearly moving, and you can see inline style values changing in the Elements panel, it is probably a JavaScript library. GSAP is the most common. GSAP does not create browser animation objects, so DevTools cannot show its easing.
If the site exposes gsap on window (many bundled sites do not), you can ask GSAP directly:
gsap.getTweensOf($0).map(t => t.vars.ease);
// e.g. ["power2.out"] (undefined means the default ease)
Once you have the name, you can translate it into CSS. GSAP's power eases correspond to the classic polynomial eases, and these cubic-bezier() values are widely used approximations of them:
| GSAP ease | Classic name | Approximate cubic-bezier |
|---|---|---|
none | linear | linear |
power1.out (GSAP default) | easeOutQuad | cubic-bezier(0.25, 0.46, 0.45, 0.94) |
power1.in | easeInQuad | cubic-bezier(0.55, 0.085, 0.68, 0.53) |
power2.out | easeOutCubic | cubic-bezier(0.215, 0.61, 0.355, 1) |
power2.inOut | easeInOutCubic | cubic-bezier(0.645, 0.045, 0.355, 1) |
power3.out | easeOutQuart | cubic-bezier(0.165, 0.84, 0.44, 1) |
power4.out | easeOutQuint | cubic-bezier(0.23, 1, 0.32, 1) |
expo.out | easeOutExpo | cubic-bezier(0.19, 1, 0.22, 1) |
back.out(1.7) | easeOutBack | cubic-bezier(0.175, 0.885, 0.32, 1.275) |
A cubic Bézier can only approximate these curves, but at interface durations the difference is hard to see. Eases with several bounces, like bounce.out or elastic.out, cannot be expressed as one cubic-bezier(). For those, use linear().
Step 4: springs and linear()
Spring animations from libraries like Framer Motion or React Spring do not follow a fixed curve. They are simulated. When the motion is exported to CSS, or when a site uses CSS directly, you will often see it as a linear() function with many stops, something like this:
.panel {
transition: transform 600ms linear(
0, 0.009, 0.035 2.1%, 0.141, 0.281 6.7%, 0.723 12.9%, 0.938 16.7%,
1.017, 1.077, 1.121, 1.149 24.3%, 1.159, 1.163, 1.161, 1.154 29.9%,
1.129 32.8%, 1.051 39.6%, 1.017 43.1%, 0.991, 0.977 51%, 0.974 53.8%,
0.975 57.1%, 0.997 69.8%, 1.003 76.9%, 1
);
}
Each number is the output progress at a point in time. Values above 1 are the overshoot. You cannot read a spring's stiffness and damping back out of it exactly, but you do not need to: copying the linear() string copies the motion. linear() is supported in current Chrome, Firefox and Safari. Our article on the CSS linear() easing function explains how to generate and simplify these lists.
Step 5: if nothing above works
Some motion leaves no curve to read. Lottie files redraw an SVG or canvas. Custom requestAnimationFrame loops compute values on the fly. Some GSAP builds are bundled with no global gsap object. In those cases, you have to record the values as they change while the animation plays.
The Capture Motion extension records the animation while it plays. Pick an element, play its animation, and it records the keyframes, durations, delays and easing of every animated property. It works with CSS transitions and keyframes, the Web Animations API, GSAP and Lottie, and hover animations are triggered with a real :hover state. The popup shows the result in CSS, React and GSAP tabs, so you can copy the curve in the form you need, or paste the capture into the Capture Motion Figma plugin as a Figma Motion timeline. Capture and preview need no account; a free account lets you copy or download.
Reading a curve once you have it
A few rules of thumb for cubic-bezier(x1, y1, x2, y2):
- Small x1, large y1 (like
0.22, 1): a fast start that settles slowly. This is the "premium" ease-out most product sites use for entrances. - y2 above 1: overshoot. The element passes its target and comes back.
- Symmetric points (like
0.645, 0.045, 0.355, 1): ease-in-out, best for things that move from one resting place to another.
For a fuller tour of the curve shapes and when to use each, read CSS easing functions explained. And if you want to copy the whole animation, not just its curve, see how to copy an animation from any website.
Questions
How do I see what easing a website uses?
Inspect the animated element in Chrome DevTools and look at the transition or animation in the Styles pane. Click the curve icon next to the timing function to see the curve. For exact values, run document.getAnimations() in the console and read the easing from the timing and the keyframes.
Why does getTiming().easing say linear when the animation clearly is not?
For CSS animations, animation-timing-function is applied to each keyframe, not to the whole effect. The effect-level easing reads linear, and the real curve is in the easing field of each keyframe from getKeyframes().
What is GSAP's default ease?
In GSAP 3 the default ease is power1.out, which is close to the classic easeOutQuad curve, cubic-bezier(0.25, 0.46, 0.45, 0.94).
Can a spring animation be written as CSS easing?
Yes, approximately. The linear() easing function takes a list of points and can trace a spring curve, including overshoot and bounce. It is supported in current versions of Chrome, Firefox and Safari.
