tool / easingprogress in, progress out

Easing functions visualizer

Pick an easing, or build a spring, bounce or elastic one with your own numbers. See its curve, watch a line draw and a marker move with it, set it beside another, and copy the code for scrollDraw, scrollAnimate, React or plain CSS.

Named easings
7
Factories
3
Code outputs
4
Gzipped
11.6 KB
Fig. 1 — the seven named easings on one scale: progress in across, progress out up, dashed at 1. Spring and elastic pass 1 before they settle; bounce touches it and falls back.
01The tool

See an easing move

easing
compare with
00.511.500.51progress in →out ↑1 · the endovershoot 1.36

A · 'spring'1

B · 'ease-out'1

out · A 1 · B 1

  • A · 'spring' overshoots to 1.36 at 0.35 · first reaches 1 at 0.2 · then falls back to 0.95 · ends at 1
  • B · 'ease-out' reaches 1 only at the end · ends at 1

Your system asks for reduced motion, so the library shows every drawing, and the scroll box’s markers, finished and does not move them. The plot, the slider, the marker under each drawing and the code still follow the easing.

main.js5 lines
// <div id="drawing"><svg viewBox="…"><path d="…" /></svg></div>

import { scrollDraw } from 'svg-scroll-draw';

scrollDraw('#drawing', { easing: 'spring' });

On real scroll · scroll inside the box, no seek()

A · 'spring'
B · 'ease-out'

The box’s whole scroll is progress 0 to 1 here: trigger from its top at the box’s top to its bottom at the box’s bottom. The markers are scrollAnimate moving left from 0% to 100%, so past 1 they run beyond the 1 mark.

02The model

Progress in, eased progress out

A scroll animation has one number behind it: how far the reader has scrolled through the trigger window, from 0 to 1. That is the progress in, and it is clamped, so it never leaves 0–1. The easing turns it into the progress the animation shows. With linear the two are the same; with ease-out the first half of the scroll does three quarters of the work (fig. 2).

Fig. 2 — ten equal steps of scroll in, and where each easing sends them out. The upright line is 1, the end.
per-frame.js4 lines
// What scrollDraw's JavaScript engine does with one path, every frame:
const t = clamp((scroll - start) / (end - start), 0, 1); // progress in
const p = easing(t);                                      // eased progress out
path.style.strokeDashoffset = length * (1 - p);           // drawn to p
Scrolling back
The easing is a function of the scroll position, not of time, so scrolling back runs the same curve backwards and stopping holds the frame. Scrolling faster plays it faster, along the same curve. The exception is once (on by default in scrollReveal, scrollCounter and scrollText), which keeps the furthest point reached.
03Past 1

Overshoot: past the end and back

The progress in stays between 0 and 1, but the progress out does not have to. spring reaches 1.36 at 0.35 of the way and elastic 1.27 at 0.17, then both settle at 1. The library does not clamp them on the way out, so whatever the progress drives goes past its end, unless the browser stops it there: opacity never goes above 1, and a video’s time stops at its last frame.

move

A transform or position runs past its target and swings back, the feel a spring is for.

draw

A line drawing’s dash slides beyond the end of the path, so the start of the line clears by the overshoot (a quarter of it at 1.25) and fills back in. Watch the start of the line in the visualizer with elastic.

dip

bounce never passes 1. It reaches the end, falls back and lands again, so the end of a line retracts and redraws.

once
With once: true, svg-scroll-draw 2.23.2 and earlier keep the highest eased value reached. In scrollDraw, scrollAnimate, scrollReveal and scrollCounter (the last two have once on by default) that freezes spring and elastic on their overshoot, so a counter to 100 stops near 127 with elastic, and it flattens bounce’s dips. 2.23.3 keeps the furthest scroll progress instead and eases it after, as scrollText already did, so the curve plays out and settles at 1.
047 names · 3 factories

Every easing, and how to write one

A named easing is a string; a factory is a function from svg-scroll-draw that returns one with your numbers. spring, bounce and elastic are the three factories at their defaults. Only the four names marked native or JS can let scrollDraw and scrollAnimate hand the animation to the browser’s own scroll timeline, and only when no other option needs the JavaScript engine; the rest always run on the library’s JavaScript engine.

NameCurveRangeCSSEngine
'linear't. Progress out equals progress in: the same speed all the way.0 – 1linearnative or JS
'ease-in't². Starts slow and speeds up, arriving at full speed.0 – 1exact cubic-beziernative or JS
'ease-out't(2 − t). Starts fast and slows to a stop. Reads as settling into place.0 – 1exact cubic-beziernative or JS
'ease-in-out'2t² to ½, then −1 + (4 − 2t)t. Slow at both ends, fastest in the middle, exactly half way at 0.5.0 – 1linear()native or JS
'spring'1 − cos(2.5πt)(1 − t)^2.2. Runs past 1 and swings back, like a spring letting go. createSpring() at its defaults.0 – 1.36linear()JS
'bounce'rise, then 2 dips. Reaches 1, falls back to 0.5, then 0.75, landing at 1. Never goes past 1. createBounce() at its defaults.0 – 1linear()JS
'elastic'2^(−10t) sin(…) + 1. Shoots past 1 early and rings down to it. createElastic() at its defaults.0 – 1.27linear()JS
spring

createSpring({ tension = 2.5, friction = 2.2 })

Frequency and damping of the swing past 1.

tension How many half-swings fit in the run. Higher swings more often.

friction How fast the swing dies away. Higher settles sooner and overshoots less.

bounce

createBounce({ bounces = 3, decay = 0.5 })

How many times it lands, and how far it falls back each time.

bounces Rounded to a whole number, at least 1. It counts the first rise: 3 is the rise and two dips.

decay Dip i falls back to 1 − decay^i. Kept between 0.01 and 0.99.

elastic

createElastic({ amplitude = 1, period = 0.4 })

How far past 1 it shoots, and how fast it rings.

amplitude Higher shoots further past 1, and sooner. Values under 1 count as 1.

period Length of one oscillation, as a fraction of the run. Values under 0.1 count as 0.1.

main.js10 lines
import { scrollDraw, createSpring } from 'svg-scroll-draw';

// A named easing:
scrollDraw('#logo', { easing: 'ease-out' });

// A factory, with your own numbers:
scrollDraw('#logo', { easing: createSpring({ tension: 3, friction: 1.8 }) });

// Or any function of t, from 0 to 1:
scrollDraw('#logo', { easing: (t) => 1 - Math.pow(1 - t, 3) });
0510 APIs

Where easing goes, and its default

Every API below takes the same easing option, a name or a function. The defaults differ: drawing and scrubbing default to linear, things that arrive default to ease-out. All of them ease the scroll progress, except scrollSnap, which eases its glide to the next section over time, and scrollDraw with autoplay, which runs on time too.

APIImport fromDefaultEases
scrollDrawsvg-scroll-draw'linear'the drawn length
scrollAnimatesvg-scroll-draw'ease-out'every prop, from → to
scrollParallaxsvg-scroll-draw'linear'the travel
scrollCountersvg-scroll-draw'ease-out'the number
scrollRevealsvg-scroll-draw/reveal'ease-out'each element’s reveal
scrollTextsvg-scroll-draw/text'ease-out'each word, letter or line
scrollProgresssvg-scroll-draw/progress'linear'--scroll-progress-eased only (--scroll-progress stays raw)
scrollVideosvg-scroll-draw/video'linear'the video time
scrollHorizontalsvg-scroll-draw/horizontal'linear'the sideways travel
scrollSnapsvg-scroll-draw/snap'ease-in-out'the glide to a section, over time
autoplay
In svg-scroll-draw 2.23.2 and earlier, a scrollDraw with autoplay whose other options CSS can express (linear or one of the three eases, no callbacks, no once, no stagger, the default trigger) is handed to the browser’s native scroll timeline where there is one, and follows the scroll instead of playing over its duration. 2.23.3 always plays it on time.
Reduced motion
For readers who ask their system for less motion, scrollDraw and scrollAnimate show the end state at once, whatever the easing.
067 questions

Easing questions

Q1

What is an easing function?

A function that takes the progress of an animation, from 0 at the start to 1 at the end, and returns the progress to show. It keeps 0 at 0 and 1 at 1 and changes the speed in between: ease-out moves quickly at first and slows to a stop, ease-in does the reverse. In a scroll animation the progress in comes from the scroll position, so the easing decides how much of the motion each stretch of scroll gets.

Q2

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

ease-in starts slow and speeds up (t²), ease-out starts fast and slows down (t(2 − t)), and ease-in-out is slow at both ends and fastest in the middle, passing exactly 0.5 at the half-way point. In svg-scroll-draw all three are quadratics, not the cubic-bézier curves of the CSS keywords with the same names: ease-in and ease-out differ from those by up to 0.069.

Q3

How do I make a spring easing?

Pass easing: 'spring', or build your own with createSpring({ tension, friction }) from svg-scroll-draw. tension (default 2.5) sets how often it swings and friction (default 2.2) how quickly the swing dies away. At the defaults it overshoots to 1.36 at 0.35 of the way through, then settles at 1.

Q4

How do I make a bounce easing?

Pass easing: 'bounce', or createBounce({ bounces, decay }). It rises to 1, falls back and lands again, and never goes past 1. bounces (default 3) counts the first rise, so the default is a rise and two dips; each dip falls back to 1 − decay^i, which at the default decay of 0.5 is 0.5, then 0.75.

Q5

What is overshoot, and why does my animation go past its end?

Some easings return more than 1 on the way: spring reaches 1.36 and elastic 1.27. A movement then passes its target and comes back, which is the springy feel. On a line drawing, progress past 1 pushes the dash beyond the end of the path, so the start of the line clears for a moment and fills back in. If nothing should pass its end, use ease-out or bounce.

Q6

Can I use my own easing function?

Yes. easing takes any function of t, where t runs from 0 to 1, for example (t) => 1 - Math.pow(1 - t, 3) for a cubic ease-out. A custom function, like spring, bounce and elastic, keeps the animation on the JavaScript engine. Only linear, ease-in, ease-out and ease-in-out can be handed to the browser’s native scroll timeline, and only by scrollDraw and scrollAnimate when no other option needs the JavaScript engine.

Q7

Can I use these easings in CSS?

linear is the CSS keyword. The library’s ease-in and ease-out are cubic-béziers with their x controls at 1/3 and 2/3: cubic-bezier(0.333333, 0, 0.666667, 0.333333) and cubic-bezier(0.333333, 0.666667, 0.666667, 1) match them to within 0.0000003. ease-in-out, spring, bounce and elastic have no single cubic-bezier, but a CSS linear() function through enough points follows them closely, overshoot included. The visualizer’s CSS tab writes it, with how far it can be from the curve.

Use an easing on words: the text animation generator. On your own drawing: the SVG path viewer. All of svg-scroll-draw 2.23.3: the docs.