Gathering detailed insights and metrics for spring-easing
Gathering detailed insights and metrics for spring-easing
Gathering detailed insights and metrics for spring-easing
Gathering detailed insights and metrics for spring-easing
Quick and easy spring animation. Works with other animation libraries (gsap, animejs, framer motion, motion one, @okikio/animate, etc...) or the Web Animation API (WAAPI).
npm install spring-easing
78.8
Supply Chain
100
Quality
75.9
Maintenance
100
Vulnerability
99.6
License
Module System
Min. Node Version
Typescript Support
Node Version
NPM Version
68 Stars
180 Commits
1 Forks
2 Watching
4 Branches
3 Contributors
Updated on 13 Nov 2024
TypeScript (64.8%)
JavaScript (31.78%)
CSS (2.47%)
HTML (0.58%)
Dockerfile (0.38%)
Cumulative downloads
Total Downloads
Last day
-16.3%
216
Compared to previous day
Last week
-10.6%
1,178
Compared to previous week
Last month
5.4%
4,948
Compared to previous month
Last year
88.8%
24,067
Compared to previous year
28
NPM | Deno | GitHub | Docs | License
Quick and easy spring animations. Works with other animation libraries (gsap, animejs, @okikio/animate, motion one, framer motion, etc...) or the Web Animation API (WAAPI), you can learn more in the Usage section.
spring-easing
works by generating arrays of frame
's which when placed in linear order creates a smooth spring like animation.
A
frame
represent a single frame of an animation
Note: the
spring-easing
package also supports 4 extra variants ofspring
, namelyspring-in
,spring-out
,spring-out-in
, andspring-in-out
, you can use these easing to create some really unique spring like animations.
You can create animation's like this with spring-easing
,
Check out the spring easing variants on Codepen.
Attention: This entire library is a lightweight version of the
CustomEasing
implemented in@okikio/animate
, which supports only string and number interpolation. If you'd like the completeCustomEasing
with color interpolation, complex value interpolation, and more, go through the source code as a Github Gist, which is licensed under the MIT license.
1npm install spring-easing
1yarn add spring-easing
or
1pnpm install spring-easing
1import { SpringEasing } from "https://deno.land/x/spring_easing/mod.ts";
1import { SpringEasing } from "spring-easing"; 2// or 3import SpringEasing from "spring-easing";
You can also use it directly through a script tag:
1<script src="https://unpkg.com/spring-easing" type="module"></script> 2<script type="module"> 3 // You can then use it like this 4 const { SpringEasing } = window.SpringEasing; 5</script>
You can also use it via a CDN, e.g.
1import { SpringEasing } from "https://esm.run/spring-easing"; 2// or 3import { SpringEasing } from "https://esm.sh/spring-easing"; 4// or 5import { SpringEasing } from "https://unpkg.com/spring-easing"; 6// or 7import { SpringEasing } from "https://cdn.skypack.dev/spring-easing"; 8// or 9import { SpringEasing } from "https://deno.bundlejs.com/file?q=spring-easing"; 10// or any number of other CDN's
Note: I cannot guarantee that every animation library works with
spring-easing
, for example, if an animation library doesn't support array values as keyframes, it won't work well withspring-easing
.
The libraries that have been tested are:
Animation Library | Support | Demo |
---|---|---|
GSAP | ✅ Yes - Wrap Method | Codepen |
animejs | ✅ Yes - Array Keyframes | Codepen |
Framer Motion | ✅ Yes - Array Keyframes | Codepen |
Motion One | ✅ Yes - Array Keyframes | Codepen |
@okikio/animate | ✅ Yes - Array Keyframes | Codepen |
Web Animation API (WAAPI) | ✅ Yes - Array Keyframes | Codepen |
Linear Easing (CSS) | ✅ Yes - CSS Spring Easing | Codepen |
Linear Easing (WAAPI) | ✅ Yes - CSS Spring Easing | Codepen |
e.g.
1import anime from "animejs";
2import { SpringEasing, SpringOutFrame } from "spring-easing";
3
4// Note: this is the return value of `SpringEasing` and `GenerateSpringFrames`
5let [translateX, duration] = SpringEasing([0, 250], {
6 easing: "spring-out-in(1, 100, 10, 0)",
7 // You can change the size of Array for the SpringEasing function to generate
8 numPoints: 200,
9 // The number of decimal places to round, final values in the generated Array
10 // This option doesn't exist on `GenerateSpringFrames`
11 decimal: 5,
12});
13
14anime({
15 targets: "div",
16
17 // Using spring easing animate from [0 to 250] using `spring-out-in`
18 translateX,
19
20 // You can interpolate between strings
21 // You can set the easing without an easing options object
22 // You can interpolate between more than 2 values
23 // Remember the `0` index of `SpringEasing` is an array of spring animation keyframes
24 rotate: SpringEasing(
25 ["0turn", 1, 0, 0.5],
26 [SpringOutFrame, 1, 100, 10, 0]
27 )[0],
28
29 // TIP... Use linear easing for the proper springy effect
30 easing: "linear",
31
32 // The optimal duration for this specific spring configuration, e.g. mass, velocity, damping, etc...
33 duration,
34});
Or
1import { CSSSpringEasing } from "spring-easing"; 2 3let [easings, duration] = CSSSpringEasing({ 4 easing: "spring-out-in(1, 100, 10, 0)", 5 // The number of decimal places to round to 6 decimal: 5, 7}); 8 9document.querySelector('div').animate({ 10 // Using spring easing animate from [0 to 250] using `spring-out-in` 11 translate: ["0", "250px"], 12 13 // You can interpolate between strings 14 // You can set the easing without an easing options object 15 // You can interpolate between more than 2 values 16 // Remember the `0` index of `SpringEasing` is an array of spring animation keyframes 17 rotate: ["0turn", "1turn", "0turn", "0.5turn"], 18}, { 19 // TIP... Use linear easing for the proper springy effect 20 easing: `linear(${easings})`, 21 22 // The optimal duration for this specific spring configuration, e.g. mass, velocity, damping, etc... 23 duration, 24});
Note: make sure to read the comments above, as they are valuable resources for understanding what is happening.
Check out this demo on Codepen
A couple sites/projects that use spring-easing
:
postcss-spring-easing
NEW
CSS Spring Easing & support for thelinear()
easing functionCSSSpringEasing
Generates a string that represents a set of values used with the linear-easing function to replicate spring animations, you can check out the linear-easing playground here https://linear-easing-generator.netlify.app/ Or check out a demo on Codepen https://codepen.io/okikio/pen/vYVaEXM
CSS Spring Easing has 4 properties they are
easing
(all spring frame functions are supported),numPoints
(the size of the Array the frmae function should create),decimal
(the number of decimal places of the values within said Array) andquality
(how detailed/smooth the spring easing should be)..
Properties Default Value easing
spring(1, 100, 10, 0)
numPoints
50
decimal
3
quality
0.85
CSSSpringEasing
is meant to be used with thelinear-easing()
function to replicate spring animations. It is based on the work done by Jake Archibald in his Linear Easing Generator.Note: This feature will only work on versions of browsers from ~a month ago (
Chrome & Edge 113
, andFirefox 112
) except forSafari
which doesn't support it yet.
1import { CSSSpringEasing } from "spring-easing"; 2 3let [easing, duration] = CSSSpringEasing({ 4 easing: "spring-out-in(1, 100, 10, 0)", 5 6 // You can change the size of Array for the SpringEasing function to generate 7 numPoints: 200, 8 9 // The number of decimal places to round, final values in the generated Array 10 // This option doesn't exist on {@link GenerateSpringFrames} 11 decimal: 5, 12 13 // How detailed/smooth the spring easing should be 14 // 0 means not smooth at all (shorter easing string) 15 // 1 means as smooth as possible (this means the resulting easing will be a longer string) 16 quality: 0.85, 17}); 18 19document.querySelector("div").animate( 20 { 21 translate: ["0px", "250px"], 22 rotate: ["0turn", "1turn", "0turn", "0.5turn"], 23 }, 24 { 25 easing: `linear(${easing})`, 26 27 // The optimal duration for this specific spring 28 duration, 29 } 30);
Note: You can also use custom easings with
CSSSpringEasing
e.g.1import { 2 CSSSpringEasing, 3 limit, 4 registerEasingFunctions, 5} from "spring-easing"; 6 7registerEasingFunctions({ 8 bounce: (t) => { 9 let pow2: number, 10 b = 4; 11 while (t < ((pow2 = Math.pow(2, --b)) - 1) / 11) {} 12 return ( 13 1 / Math.pow(4, 3 - b) - 7.5625 * Math.pow((pow2 * 3 - 2) / 22 - t, 2) 14 ); 15 }, 16 elastic: (t, params: number[] = []) => { 17 let [amplitude = 1, period = 0.5] = params; 18 const a = limit(amplitude, 1, 10); 19 const p = limit(period, 0.1, 2); 20 if (t === 0 || t === 1) return t; 21 return ( 22 -a * 23 Math.pow(2, 10 * (t - 1)) * 24 Math.sin( 25 ((t - 1 - (p / (Math.PI * 2)) * Math.asin(1 / a)) * (Math.PI * 2)) / p 26 ) 27 ); 28 }, 29}); 30 31CSSSpringEasing("bounce"); // ["0, 0.013, 0.015, 0.006 8.1%, 0.046 13.5%, 0.06, 0.062, 0.054, 0.034, 0.003 27%, 0.122, 0.206 37.8%, 0.232, 0.246, 0.25, 0.242, 0.224, 0.194, 0.153 56.8%, 0.039 62.2%, 0.066 64.9%, 0.448 73%, 0.646, 0.801 83.8%, 0.862 86.5%, 0.95 91.9%, 0.978, 0.994, 1", ...] 32CSSSpringEasing("elastic(1, 0.5)"); // ["0, -0.005 32.4%, 0.006 40.5%, 0.034 51.4%, 0.033 56.8%, 0.022, 0.003, -0.026 64.9%, -0.185 75.7%, -0.204, -0.195, -0.146, -0.05, 0.1 89.2%, 1", ...]
getOptimizedPoints
This function generates an optimized set of points to be used with the
linear-easing()
function using the Ramer-Douglas-Peucker algorithm and rounds the x and y values of the resulting points.1import { getOptimizedPoints } from "spring-easing"; 2 3const points = [ 4 [0, 0], 5 [0.1, 0.2], 6 [0.5, 1], 7 [0.9, 0.2], 8 [1, 0], 9]; 10const round = 2; 11const simplify = 0.1; 12 13console.log(getOptimizedPoints(points, simplify, round)); //= [[0, 0], [0.5, 1], [1, 0]]
getLinearSyntax
This function converts a given set of points into an array of strings in a this format
["value percent%", ...]
e.g.["0", "0.25 13.8%", "0.6 45.6%", "0.1", "0.4 60%", ...]
. It's used to generate the syntax for thelinear-easing
function.1import { getLinearSyntax } from "spring-easing"; 2 3const points = [ 4 [0, 0], 5 [0.1, 0.2], 6 [0.5, 1], 7 [0.9, 0.2], 8 [1, 0], 9]; 10const round = 2; 11 12console.log(getLinearSyntax(points, round)); //= [ '0', '0.2 10%', '1', '0.2 90%', '0' ]
RE-INSTATED
Added batch version ofSpringEasing
and the Interpolation functions which use a new syntax.The other version of
spring-easing
interpolation functions follow this syntax(t, values, decimal) => string | number | any
, batch interpolation function use this new syntax(arr_t, values, decimal) => string[] | number[] | any[]
.The key difference between both syntaxes are the parameters each function takes and the return value of each function.
The older syntax returned instantaneous frame values at a specific t-value, but the new syntax returns all the frames that make the entire animation, allowing for performance optimizations that couldn't be done before.
For the most part this shouldn't leave too much of an effect, but for those high-perf. applications this new batch synatax should prove useful. e.g.
1function batchInterpolateNumber( 2 arr_t: number[], 3 values: number[], 4 decimal = 3 5) { 6 // nth index 7 const n = values.length - 1; 8 9 return arr_t.map((t) => { 10 // The current index given t 11 const i = limit(Math.floor(t * n), 0, n - 1); 12 13 const start = values[i]; 14 const end = values[i + 1]; 15 const progress = (t - i / n) * n; 16 17 return toFixed(scale(progress, start, end), decimal); 18 }); 19} 20 21BatchSpringEasing([0, 250], `spring`, batchInterpolateNumber);
RE-INSTATED
There is a newtoAnimationFrames
function that converts interpolation functions written in this style(t, values, decimal) => { ... }
to work inBatchSpringEasing
. e.g.
1import { 2 BatchSpringEasing, 3 toAnimationFrames, 4 toFixed, 5 scale, 6 limit, 7} from "spring-easing"; 8 9function interpolateNumber(t: number, values: number[], decimal = 3) { 10 // nth index 11 const n = values.length - 1; 12 13 // The current index given t 14 const i = limit(Math.floor(t * n), 0, n - 1); 15 16 const start = values[i]; 17 const end = values[i + 1]; 18 const progress = (t - i / n) * n; 19 20 return toFixed(scale(progress, start, end), decimal); 21} 22 23function interpolatePixels(t: number, values: number[], decimal = 3) { 24 const result = interpolateNumber(t, values, decimal); 25 return `${result}px`; 26} 27 28BatchSpringEasing([0, 250], "spring", toAnimationFrames(interpolatePixels));
NEW
Optimized perf. of spring generation w/ help from @jakearchibald
NEW
mass
,stiffness
,damping
, andvelocity
now have a smaller minimum limit of0.0001
instead of0.1
REVERT
The new interpolation syntax has been reverted and removed;instantNumber
, etc... functions have been renamed tointerpolateNumber
, etc...
NEW
Re-introduced instantaneous interpolation functions. e.g.1import { 2 interpolateNumber, 3 interpolateString, 4 interpolateSequence, 5 interpolateComplex, 6} from "spring-easing";
These functions represent the interpolated value at a specific instance in time, where time is represented by
t
with a range of0
to1
. You can use these functions as building blocks to create your own custom interpolation functions.
NEW
(deprecated)interpolateUsingIndex
is now an alias ofinterpolateSequence
, it still keeps the same functionality. The recommendation is to useinterpolateSequence
instead ofinterpolateUsingIndex
, but you can still keep usinginterpolateUsingIndex
, but beware it can be removed in future versions.
NEW
Re-introduced instantaneous interpolation functions. e.g.1import { 2 instantNumber, 3 instantString, 4 instantSequence, 5 instanceComplex, 6} from "spring-easing";
These functions represent the interpolated value at a specific instance in time, where time is represented by
t
with a range of0
to1
. You can use these functions as building blocks to create your own custom interpolation functions.
BREAKING CHANGE
Interpolation functions use a new syntax.In older versions of
spring-easing
interpolation functions used to follow a syntax called the instantaneous interpolation function(t, values, decimal) => string | number | any
, the new syntax is called interpolation function(frames, values, decimal) => string[] | number[] | any[]
.The key difference between both syntaxes are the parameters each function takes and the return value of each function.
The older syntax returned instantaneous frame values at a specific t-value, but the new syntax returns all the frames that make the entire animation, allowing for performance optimizations that couldn't be done before.
For the most part this shouldn't leave too much of an effect as all the built-in interpolation functions have been updated to use the new synatax. e.g.
1function interpolateNumber(frames: number[], values: number[], decimal = 3) { 2 // nth index 3 const n = values.length - 1; 4 5 return frames.map((t) => { 6 // The current index given t 7 const i = limit(Math.floor(t * n), 0, n - 1); 8 9 const start = values[i]; 10 const end = values[i + 1]; 11 const progress = (t - i / n) * n; 12 13 return toFixed(scale(progress, start, end), decimal); 14 }); 15} 16 17SpringEasing([0, 250], `spring`, interpolateNumber);
NEW
There is a newtoAnimationFrames
function that be used on instantaneous interpolation functions, to transform them into complete animation interpolation functions. e.g.
1import { 2 SpringEasing, 3 toAnimationFrames, 4 toFixed, 5 scale, 6 limit, 7} from "spring-easing"; 8 9function interpolateNumber(t: number, values: number[], decimal = 3) { 10 // nth index 11 const n = values.length - 1; 12 13 // The current index given t 14 const i = limit(Math.floor(t * n), 0, n - 1); 15 16 const start = values[i]; 17 const end = values[i + 1]; 18 const progress = (t - i / n) * n; 19 20 return toFixed(scale(progress, start, end), decimal); 21} 22 23function interpolatePixels(t: number, values: number[], decimal = 3) { 24 const result = interpolateNumber(t, values, decimal); 25 return `${result}px`; 26} 27 28SpringEasing([0, 250], "spring", toAnimationFrames(interpolatePixels));
NEW
Easily register new easing functions. e.g.1import { SpringEasing, registerEasingFunction } from "spring-easing"; 2 3registerEasingFunction("linear", (t) => t); 4registerEasingFunctions({ 5 quad: (t) => Math.pow(t, 2), 6 cubic: (t) => Math.pow(t, 3), 7}); 8 9SpringEasing([0, 250], "linear"); 10 11SpringEasing([0, 250], "quad");
NEW
SpringEasing now support interpolating between strings. It treats the units of the first value as the units for the rest of the values to interpolate between. e.g.1SpringEasing(["0turn", "1px", "18rem", "125deg", 25], ...)
Important All the values above get transformed to
["0turn", "1turn", "18turn", "125turn", "25turn"]
, before being interpolated.
NEW
interpolateStrings
,interpolateUsingIndex
, andinterpolateComplex
, are now built-in, they allow for supporting string keyframes.
NEW
Custom interpolation functions are now supported. e.g.
1import { interpolateNumber, toFixed, scale, limit } from "spring-easing"; 2// ... 3export function interpolateColor(t: number, values: string[], decimal = 3) { 4 const color = transpose(...values.map((v) => rgba(v))).map( 5 (colors: number[], i) => { 6 const result = interpolateNumber(t, colors); 7 return i < 3 ? Math.round(result) : toFixed(result, decimal); 8 } 9 ); 10 11 return `rgba(${color.join()})`; 12} 13 14SpringEasing(["red", "green", "#4f4"], "spring", interpolateColor);
Important The logic for color interpolation is defined in this tests/utils/interpolate-color.ts.
The API of spring-easing
is pretty straight forward, the SpringEasing
function generates an array of values using a frame functions, which in turn creates the effect of spring easing.
To use this properly make sure to set the easing animation option to "linear".
Check out a demo of SpringEasing
at https://codepen.io/okikio/pen/MWEdzNg
SpringEasing
has 3 properties they are easing
(all the easings from EasingFunctions are supported on top of frame functions like SpringFrame
, SpringFrameOut
, etc..), numPoints
(the size of the Array the frame function should create), and decimal
(the number of decimal places of the values within said Array).
Properties | Default Value |
---|---|
easing | spring(1, 100, 10, 0) |
numPoints | 50 |
decimal | 3 |
By default, Spring Easing support easings in the form,
constant | accelerate | decelerate | accelerate-decelerate | decelerate-accelerate |
---|---|---|---|---|
spring / spring-in | spring-out | spring-in-out | spring-out-in |
All Spring easing's can be configured using theses parameters,
spring-*(mass, stiffness, damping, velocity)
Each parameter comes with these defaults
Parameter | Default Value |
---|---|
mass | 1 |
stiffness | 100 |
damping | 10 |
velocity | 0 |
To understand what each of the parameters of SpringEasing
mean and how they work I suggest looking through the SpringEasing API Documentation
Note: the return value of the
SpringEasing
function is actually[Array of keyframes, duration]
, in that order.
For a full understanding of what is happening in the library, pleace check out the API site for detailed API documentation.
Chrome | Edge | Firefox | Safari | IE |
---|---|---|---|---|
4+ | 12+ | 4+ | 4+ | 10+ |
Native support for spring-easing
is great as it doesn't use any browser specific or nodejs specific API's, you should be good to use spring-easing
in any environment.
Note:
CSSSpringEasing
is meant for browsers which have support for thelinear()
easing function, which as of right now isChrome & Edge 113
+Firefox 112
, Safari doesn't support it yet.
I encourage you to use pnpm to contribute to this repo, but you can also use yarn or npm if you prefer.
Install all necessary packages
1npm install
Then run tests
1npm test
Build project
1npm run build
Preview API Docs
1npm run typedoc && npm run preview
Note: this project uses Conventional Commits standard for commits, so, please format your commits using the rules it sets out.
See the LICENSE file for license rights and limitations (MIT).
The CSSSpringEasing
, getOptimizedPoints
and getLinearSyntax
function are based of the work done by Jake Archibald in his Linear Easing Generator
and are thus licensed under the Apache License 2.0.
No vulnerabilities found.
No security vulnerabilities found.