A spicy JavaScript tweening/animation engine with 0 dependencies and a tiny size.
Paprika 🌶 is a bare-bones, low-level library for the browser and node.js which applies an interpolation between two numbers using an easing equation over a discrete amount of time.
import { Mixer, Spice } from 'paprika-tween';
import { Cubic } from 'paprika-tween/easing';
// Create some spices with properties to interpolate
const spice1 = new Spice({
duration: 100,
from: { x: 0, y: 0 },
to: { x: 200, y: 200 },
// Easing equation to calculate the interpolation
easing: Cubic.InOut,
render: ({ x, y }) => {
// Do something with `x` and `y`
}
});
const spice2 = new Spice({
duration: 100,
from: { gamma: 1.0 },
to: { gamma: 2.2 },
render: ({ gamma }) => {
// Do something with `gamma`
},
onEnd: (props) => {
// Fired when the interpolation ends
}
});
const mixer = new Mixer();
// Put the spices in the mixer
mixer.add(spice1, spice2)
// And start the tweening at the time 0
.start(0);
// Advance to time 25
mixer.frame(25);
Paprika 🌶 does not request an animation frame to move the tween forwards. You should call the frame()
method by using
requestAnimationFrame()
or an instance of the
Mortar class.
Or you can use a sweet paprika.
import { sweet } from 'paprika-tween';
sweet({
duration: 500,
delay: 50,
from: { size: 0 },
to: { size: 10 },
render: ({ size }) => { ... }
});
In the browser, you can load Paprika 🌶 from a CDN or you can download the minified JS file and store it in your application.
URL | Type |
---|---|
https://unpkg.com/paprika-tween | ESM |
https://unpkg.com/paprika-tween/dist/paprika-tween.iife.min.js | IIFE |
If you are using JavaScript modules, then you can import Paprika 🌶 by its URL:
<script type="module">
import { Mixer, Spice, Recipe, Mortar, sweet } from 'https://unpkg.com/paprika-tween';
</script>
If you prefer using Paprika 🌶 as a global variable, you can load the IIFE variant which
exposes the global variable Paprika
.
<script src="https://unpkg.com/dist/paprika-tween.iife.min.js"></script>
<script>
const { Mixer, Spice, Recipe, Mortar, sweet } = Paprika;
</script>
If you are building your app using node.js (or writing a node.js app), you can install Paprika 🌶 using npm:
npm install paprika-tween
and then load it using ECMAScript modules
import { Mixer, Spice, Recipe, Mortar, sweet } from 'paprika-tween';
or as a CommonJS module:
const { Mixer, Spice, Recipe, Mortar, sweet } = require('paprika-tween');
There are several ways to use Paprika 🌶.
A Spice is the minimum tweenable object. It can be tweened alone, or by adding it to a Recipe or to a Mixer:
const spice = new Spice({
duration: 45,
from: { size: 10 },
to: { size: 520 },
render: ({ size }) => {
console.log(size);
}
});
// Start the tweening at the time 0
spice.start(0);
spice.frame(15);
spice.frame(33);
A Recipe can contain one or more spices, that will be tweened in sequence.
const spice1 = new Spice({ ... });
const spice2 = new Spice({ ... });
const recipe = new Recipe({ onEnd: () => {} });
recipe.add(spice1, spice2)
// Start the tweening at performance.now()
.start();
recipe.frame(performance.now());
A Mixer can contain any number of spices or recipes, and all of them will be tweened at the same time.
const spice = new Spice({ ... });
const recipe = new Recipe()
.add(new Spice({ ... }), new Spice({ ... }));
const mixer = new Mixer();
mixer.add(spice, recipe);
// Start the tweening
mixer.start(2000);
mixer.frame(2500);
To perform an animation of a Spice, Recipe or Mixer, you can use the method
requestAnimationFrame()
to call the method render()
on each frame update.
const recipe = new Recipe({ onEnd: () => cancelAnimationFrame(rafID) });
recipe.add(new Spice({ ... }), new Spice({ ... }));
const mixer = new Mixer();
mixer.add(recipe)
.start();
function loop(timestamp) {
mixer.frame(timestamp);
rafID = requestAnimationFrame(loop);
}
let rafID = requestAnimationFrame(loop);
The Mortar class can also perform an animation for a given frames per second on a more performant way by ensuring that the animation is run at the same speed regardless of the device and network conditions.
const spice = new Spice({ ... });
const mixer = new Mixer();
mixer.add(spice)
.start();
const mortar = new Mortar(time => mixer.frame(time), 15);
mortar.start();
The sweet()
function starts automatically
an animation, which returns a Promise
that can be chained by using its method .then()
or the await
keyword.
Chained animations using the returned function sweetie()
will reuse the spice
created by sweet()
.
const { sweetie, spice } = await sweet({
duration: 2000,
from: { width: 100 },
to: { width: 200 }
render: ({ width }) => { ... }
});
await sweetie({
to: { width: 0 }
});
await sweetie({
duration: 1000,
to: { width: 300 }
});
Every spice needs an easing equation to calculate the amount of progression of a property over time. The default easing equation is linear (no easing applied).
You can use your custom easing equation:
import { Spice } from 'paprika-tween';
const spice1 = new Spice({
from: { z: 10 },
to: { z: 55 },
// `v` is a float number between 0 (start) and 1 (end)
easing: (v) => Math.random() * v
});
Or one of the functions provided by in the Paprika package:
import { Spice } from 'paprika-tween';
import { Exponential } from 'paprika-tween/easing';
const spice1 = new Spice({
from: { z: 10 },
to: { z: 55 },
easing: Exponential.Out
});
If you are using Paprika as a standalone library, you can get the easing equations from a CDN or download the minified JS file.
CDN URL | Type |
---|---|
https://unpkg.com/paprika-tween/dist/easing.min.js | ESM |
https://unpkg.com/paprika-tween/dist/easing.iife.min.js | IIFE |
<script type="module">
import { Cubic, Exponential, Quadratic } from 'https://unpkg.com/paprika-tween/dist/easing.min.js';
</script>
Paprika 🌶 runs in any JavaScript environment that supports the following features:
performance.now()
requestAnimationFrame()
async
- Nullish coalescing assignment
??=
You should provide your own polyfills in case any of these features are missing, like a
polyfill for requestAnimationFrame()
in node.js,
or use a transpiler when building your application.
Paprika 🌶 is distributed under the MIT license.