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
linear
ease-in
ease-out
ease-in-out
springpeak 1.36
bouncedip 0.5
elasticpeak 1.27
keyin → out ↑
See an easing move
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.
// <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()
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.
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).
// 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 ponce (on by default in scrollReveal, scrollCounter and scrollText), which keeps the furthest point reached.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.
A transform or position runs past its target and swings back, the feel a spring is for.
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.
bounce never passes 1. It reaches the end, falls back and lands again, so the end of a line retracts and redraws.
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.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.
| Name | Curve | Range | CSS | Engine |
|---|---|---|---|---|
| 'linear' | t. Progress out equals progress in: the same speed all the way. | 0 – 1 | linear | native or JS |
| 'ease-in' | t². Starts slow and speeds up, arriving at full speed. | 0 – 1 | exact cubic-bezier | native or JS |
| 'ease-out' | t(2 − t). Starts fast and slows to a stop. Reads as settling into place. | 0 – 1 | exact cubic-bezier | native 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 – 1 | linear() | 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.36 | linear() | 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 – 1 | linear() | JS |
| 'elastic' | 2^(−10t) sin(…) + 1. Shoots past 1 early and rings down to it. createElastic() at its defaults. | 0 – 1.27 | linear() | JS |
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.
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.
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.
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) });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.
| API | Import from | Default | Eases |
|---|---|---|---|
| scrollDraw | svg-scroll-draw | 'linear' | the drawn length |
| scrollAnimate | svg-scroll-draw | 'ease-out' | every prop, from → to |
| scrollParallax | svg-scroll-draw | 'linear' | the travel |
| scrollCounter | svg-scroll-draw | 'ease-out' | the number |
| scrollReveal | svg-scroll-draw/reveal | 'ease-out' | each element’s reveal |
| scrollText | svg-scroll-draw/text | 'ease-out' | each word, letter or line |
| scrollProgress | svg-scroll-draw/progress | 'linear' | --scroll-progress-eased only (--scroll-progress stays raw) |
| scrollVideo | svg-scroll-draw/video | 'linear' | the video time |
| scrollHorizontal | svg-scroll-draw/horizontal | 'linear' | the sideways travel |
| scrollSnap | svg-scroll-draw/snap | 'ease-in-out' | the glide to a section, over time |
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.Easing questions
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.
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.
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.
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.
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.
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.
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.