Add motion to your apps with ease.

  • Light animation library for modern JavaScript.
  • Based on requestAnimationFrame.
  • Contains the most popular easing functions.


Example

App.js
import animare, { ease } from 'animare';

const ball = document.getElementById('ball');

animare({
  to: [100, 100],
  duration: 2000, // 🕐
  ease: [ease.linear, ease.out.bounce], // 📉
}, 
([x, y]) => {
  ball.style.left = x + '%';
  ball.style.top = y + '%';
});

Installation

Install using your package manager of choice to add animare to your project:


npm install animare

Aaaaand, you’re done! That was fast. 🐇

Usage

  • Syntax: animare(animationOptions, (animatedValues, animationInfo) => void)

  • animare is built to be a wrapper around requestAnimationFrame to make it easier to use.

  • With it, you can animate anything that has a number value (scroll position, color, text, etc).

  • Each animated value has its option (duration, delay, ease, etc)

import animare, { ease } from 'animare';

const element = document.getElementById('element');

animare(
  {
    from: [0, 0.5], // start values as [opacity, scale]
    to: [1, 1], // end values as [opacity, scale]
    duration: [1000, 500], // duration in ms for each value
    ease: ease.out.quart, // applies on all values
  },

  // values names can be anything
  ([opacity, scale], { isFinished }) => {
    element.style.opacity = opacity;
    element.style.transform = `scale(${scale})`;

    if (isFinished) {
      // do something when the animation is finished
    }
  }
);

Animation's Options

  • to

    Type
    
    to: number | number[]; // required
    
    

    End value\s of the animation.

  • from

    Type
    
    from?: number | number[] | ((index: number) => number);
    
    

    Start value\s of the animation.
    If a single number is passed, it will be used as the default for all animated values.
    If number[] is passed, make sure it has the same length as to.

  • delay

    Type
    
    delay?: number | number[] | ((index: number) => number);
    
    

    Delay before the animation starts in milliseconds.
    If a single number is passed, it will be used as the default for all animated values.

  • delayOnce

    Type
    
    delayOnce?: boolean | boolean[];
    
    

    Apply the delay only once, in case of repeating animations.
    If a single boolean is passed, it will be used as the default for all animated values.

  • duration

    Type
    
    duration?: number | number[] | ((index: number) => number);
    
    

    The duration of the animation's value/s is in milliseconds.
    If a single number is passed, it will be used as the default for all animated values.

  • direction

    Type
    
    type directionT = "normal" | "reverse" | "alternate" | "alternate-reverse";
    
    direction?: directionT | directionT[];
    
    

    Animation's direction for each value/s.
    If a single string is passed, it will be used as the default for all animated values.

  • repeat

    Type
    
    repeat?: number | number[] | ((i: number) => number);
    
    

    Repeats count after the first play.
    If a single number is passed, it will be used as the default for all animated values.
    for infinite ♾️ repeats use -1.

  • ease

    Type
    
    ease?: ((x: number) => number) | ((x: number) => number)[];
    
    

    Easing functions specify the rate of change of the number over time.\

    Info check out the ease plugin.

  • autoPlay

    Type
    
    autoPlay?: boolean;
    
    

    Play the animation automatically on initialization.

  • type

    Type
    
    type?: "wait" | "immediate";
    
    

    Playing behavior of the next animation in the timeline. when using .next().
    wait - wait for all animated values in the previous animations to be completed.
    immediate - play the next animated value immediately after the previous one is finished.

Animation's Callback

A function will be fired on every frame update and contains the animation's logic.

  • Two parameters will be passed to the callback function:

    1st param: Array of the animated values, the same length as to property.
    2nd param: An object of information about the animation.

    
    const onUpdate = ([v1, v2, v3 ...], { isFinished, fps, ... }) => {
      // Animation logic here
    }
    

2nd param

  • isFirstFrame: boolean
    True only at the first frame of the animation.

  • isFinished: boolean
    True only when the animation is finished.

  • progress: number[]
    The progress of each animated value is an array of numbers between 0 and 1.
    Resets on every repeat cycle.

  • timelineProgress: number
    Overall animation's progress includes repeats, delays, and timeline repeats.
    Returns -1 if the timeline ♾️ infinitely repeats.

  • timelineIndex: number[]
    The current timeline index of each animated value.

  • repeatCount: number[]
    A descending number represents the current repeat cycle of each animated value.

  • timelineRepeatCount: number[]
    A descending number represents the current timeline's repeat cycle of each animated value.

  • alternateCycle: number[]
    The current alternate cycle (1 or 2) of each animated value.
    For directions 'alternate' or 'alternate-reverse'

  • fps: number
    The current refresh rate.

  • time: number
    The progress time in milliseconds of the overall animation.

Methods

  • play()

    Start playing the animation in the direction direction.
    If the animation is already playing or paused, it will be restarted.

    Note play() will match the direction property.

  • reverse()

    Start playing the animation in the reverse direction direction.
    If the animation is already playing or paused, it will be restarted.

    Note reverse() will reverse the direction property.

  • pause()

    Pause the animation if it is playing at the moment.

  • resume()

    Resume the animation if it is paused.
    If the animation is not paused, it will be played from the beginning.

  • stop(stopAtStart = true)

    Stop the animation at the beginning or the end.

    Warning the animation will not be stopped immediately, it may take 1 or 2 frames to stop.

  • setOptions(animationOptions, animationIndex?: number) => void

    Change the animation's initial options for a specific animation in the timeline.

    Warning setting new options while the animation is playing sometimes may cause unexpected results.

  • getOptions(animationIndex?: number) => animationOptions

    Get the animation's current options object for a specific animation in the timeline.

  • setTimelineOptions({ repeat?: number, speed?: number }) => void

    Set or change the timeline's initial options.

Timeline

Sometimes you need to do multi-step animation, you can do that using the .next() method.
.next() uses the same callback with updated options.

If from is not specified, it will pick up the value from the previous animation.

Note duration, ease, and type properties are inherited from the previous animation.

Tip If you have multiple values with different durations and delays some of them may finish before the others. you can customize the timeline playing behavior by using the type property.

Warning using repeat: -1 ♾️ property in one of the animations in the timeline will block the next one from playing.

import animare, { ease } from 'animare';

const ball = document.getElementById('ball');

const myAnimation = animare(
  {
    to: [100, 100],
    duration: 2000, // 🕐
    ease: [ease.linear, ease.out.bounce], // 〽️
  },
  ([x, y]) => {
    ball.style.left = x + '%';
    ball.style.top = y + '%';
  }
);

myAnimation.next({ to: [100, 0], delay: 500 }); // ⏭️ play this next
myAnimation.next({ to: [0, 100], delay: 500 }); // ⏭️
myAnimation.next({ to: [0, 0], delay: 500 }); // ⏭️

myAnimation.setTimelineOptions({ repeat: -1 }); // ♾️ infinite timeline repeat

Events

animare provides some events out of the box.

  • onStart

    Syntax: (callback: Function) => Function
    Listen to the animation's start event.

    Warning onStart will not be fired for autoPlay animations.

    const scrollAnimation = animare({ to: 300, autoPlay: false }, ([scroll]) => {
      window.scroll({ top: scroll });
    });
    
    // will be called every time the animation starts
    const unsubscribe = scrollAnimation.onStart(() => {
      console.log('start scrolling');
    });
    
    // somewhere else in your code
    scrollAnimation.start(); // 🚀 start the animation
    
    unsubscribe(); // 🛑 stop listening

  • onProgress

    Syntax: (at: number, callback: Function) => Function
    Will be fired every time the animation reaches specific progress.

    Warning onProgress will not be fired in case of ♾️ infinite repeats.

    const scrollAnimation = animare({ to: 300 }, ([scroll]) => {
      window.scroll({ top: scroll });
    });
    
    // will be called every time the animation reaches half of the duration
    const unsubscribe = scrollAnimation.onProgress(0.5, () => {
      console.log('half way');
    });
    
    unsubscribe(); // 🛑 stop listening

  • asyncOnProgress

    Syntax: (at: number) => Promise
    Wait for the animation to reach specific progress.

    Warning asyncOnProgress will not be fired in case of ♾️ infinite repeats.

    // inside async function
    
    const scrollAnimation = animare({ to: 300 }, ([scroll]) => {
      window.scroll({ top: scroll });
    });
    
    // wait for the animation to reach 50%
    await scrollAnimation.onProgress(0.5, () => {
      console.log('half way');
    });

  • onFinish

    Syntax: (callback: Function) => Function
    Listen to the animation's finish event.

  • asyncOnFinish

    Syntax: () => Promise
    Wait for the animation to finish.

React Hook

React users can use the hook useAnimare by importing it from animare/react. This hook returns the animation's object to use in your React component.

App.jsx
import animare, { ease } from 'animare';
import { useAnimare } from 'animare/react';

function MyComponent() {
  const ballAnimation = useAnimare(() => {
    const ball = document.getElementById('ball');

    const options = {
      to: 1,
      duration: 1000,
      ease: ease.out.quad,
      autoPlay: false,
    };

    const onUpdate = ([scale]) => {
      ball.style.transform = `scale(${scale})`;
    };

    return animare(options, onUpdate);
  });

  const onClick = () => {
    ballAnimation?.play();
  };

  // ...
}

Plugins

  • ease

    animare comes with a few predefined easing functions.

    Info Check out easings.net to learn more about the available easing functions.

    Tip Use animare-ease-visualizer tool to create custom easing functions.

    Warning ease.custom accepts only strings generated by animare-ease-visualizer tool.

    import { ease } from 'animare'
    
    ease.linear // default
    
    // ease in                        ease out                          ease in-out
    ease.in.bounce                    ease.out.bounce                   ease.inOut.bounce
    ease.in.circ                      ease.out.circ                     ease.inOut.circ
    ease.in.cubic                     ease.out.cubic                    ease.inOut.cubic
    ease.in.elastic                   ease.out.elastic                  ease.inOut.elastic
    ease.in.expo                      ease.out.expo                     ease.inOut.expo
    ease.in.sine                      ease.out.sine                     ease.inOut.sine
    ease.in.quad                      ease.out.quad                     ease.inOut.quad
    ease.in.quart                     ease.out.quart                    ease.inOut.quart
    ease.in.quint                     ease.out.quint                    ease.inOut.quint
    ease.in.back(c: number)           ease.out.back(c: number)          ease.inOut.back(c: number)
    ease.in.poly(n: number)           ease.out.poly(n: number)          ease.inOut.poly(n: number)
    ease.in.wobble(bounciness = 1)    ease.out.wobble(bounciness = 1)   ease.inOut.wobble(bounciness = 1)
    
    // ⚠️ The spring easing function will only look smooth at certain parameters.
    ease.spring({
      mass?: number,
      stiffness?: number,
      damping?: number,
      velocity?: number,
      duration?: number
    });
    
    ease.steps(stepsNumber?: number, start?: true);
    
    ease.cubicBezier(X1: number, Y1: number, X2: number, Y2: number); // same as CSS
    
    // ⚠️ accepts only strings generated by `animare-ease-visualizer` tool.
    ease.custom(d: string); // d is SVG's path attribute
    
    // custom easing functions from an array of generated points.
    ease.fromPoints(array: Float32List);

  • organize

    The more you have animated values, the more it gets difficult to know what is what.

    // long-length animated values are hard to read and maintain.
    
    import animare from 'animare';
    
    animare(
      {
        from: [23, 25, 35, 34, 4, 45, 34, 45, 43, 45, 341, 34, 545],
        to: [243, 22, 55, 226, 24, 61, 34, 45, 15, 45, 56, 13, 114],
        duration: [500, 1000, 200, 2000, 1500, 500, 600, 700, 900, 1100, 360, 550, 400],
        delay: [50, 100, 200, 250, 300, 350, 400, 450, 500, 550, 600, 650, 700],
      },
      ([a, b, c, d, e, f, g, h, i, j, k, l, m]) => {
        // ...
      }
    );

    organize is a utility function that helps you to organize your animated values.
    organize also handles color animations.

    import animare, { organize } from 'animare';
    
    const options = organize({
      x: { from: 20, to: 100, duration: 1500 },
      y: { from: 10, to: 200, duration: 1000 },
      width: { from: 200, to: 500, duration: 1000 },
      height: { from: 150, to: 300, duration: 1000 },
      color: { from: 'red', to: 'orange', duration: 1000 },
      rotate: { to: 360, duration: 1000 },
      scale: { from: 1, to: 2 },
    });
    
    animare(
      {
        from: options.from,
        to: options.to,
        duration: options.duration,
      },
    
      (values, { progress }) => {
        const { x, y, width, height, color, rotate, scale } = options.get(values);
        // get the progress of rotate.
        const rotateProgress = progress[options.indexOf('rotate')];
        // ...
      }
    );

  • colorToArr

    Colors are made of numbers rgb(255, 0, 0) so you can animate them by animating each color's channel RGB.
    But sometimes you want to animate a hex color #ff0000 or even a named color red.
    For that, you can use colorToArr plugin to convert a color to an array of numbers.

    Tip organize plugin can handle color animations for you.

    import animare, { colorToArr } from 'animare';
    
    const element = document.getElementById('element');
    
    animare(
      {
        from: colorToArr('red'), // ➡️ [255, 0, 0]
        to: colorToArr('#ff00ff'), // ➡️ [255, 0, 255]
        duration: 1000,
      },
    
      ([r, g, b]) => {
        element.style.backgroundColor = `rgb(${r}, ${g}, ${b})`;
      }
    );