Skip to content

EneaEntertainment/animjs

Repository files navigation

AnimJS

Lighweight library which lets you tween multiple object's properties

Dependency: Runner

Features

  • tween, timeline, delay, wait
  • onStart(), onUpdate(), onRepeat(), onComplete() callbacks
  • manual tick
  • tweening array of numbers
  • seek time
  • time scale
  • animation groups
  • ability to provide custom easing functions

Installation

npm install --save-dev @enea-entertainment/animjs

NPM


Basic usage example

import { anim } from '@enea-entertainment/animjs';

const myObject =
    {
        alpha    : 0,
        rotation : Math.PI
    };

anim.to(myObject,
    {
        duration : 1,
        alpha    : 1,
        rotation : 0,
        ease     : 'sineInOut'
    });

Update loop

AnimJS doesn't come with built-in update loop, instead it encourages you to call anim.tick(); manually. Whenever you want to.

import { anim } from '@enea-entertainment/animjs';

mainUpdateLoop(deltaTime)
{
    // request animation frame

    anim.tick(deltaTime); // in seconds

    // update scene
    // render scene
}

or simply via setInterval();

import { anim } from '@enea-entertainment/animjs';

const delta = 16.7;

setInterval(()=>
{
    anim.tick(delta / 1000); // in seconds
}, delta);

Tween example

import { anim } from '@enea-entertainment/animjs';

const myObject =
    {
        x : 0,
        y : 50
    };

// by setting 'paused: true' we tell tween not to start immediately
const firstTween = anim.from(myObject,
    {
        paused : true,
        delay  : 1,
        y      : 0,

        onStart: () =>
        {
            console.log('First tween start');
        },

        onComplete: () =>
        {
            console.log('First tween complete');
        }
    });

anim.to(myObject,
    {
        duration    : 2,
        x           : 100,
        repeat      : 1,
        repeatDelay : 0.5,
        ease        : 'cubicOut',
        yoyoEase    : 'backInOut',

        onStart: () =>
        {
            console.log('Second tween start');
        },

        onUpdate: (target, progress) =>
        {
            // target   : returns tweened object (myObject in this case)
            // progress : returns value between 0 and 1
            console.log('Second tween update:', progress);
        },

        onComplete: () =>
        {
            console.log('Second tween complete');

            // now we run firstTween
            firstTween.paused = false;
        }
    });

For 'infinite' tween loop, provide

repeat: -1

Note: loop isn't really infinite, AnimJS internally uses very large number.

anim.fromTo(); method allows you to override object's start values

import { anim } from '@enea-entertainment/animjs';

const myObject =
    {
        x : 0,
        y : 1
    };

// myObject's x and y values will both start from 2
anim.fromTo(myObject,
    {
        x : 2,
        y : 2
    },
    {
        duration : 1,
        x        : 4,
        y        : 4,
        ease     : 'none'
    });

Timeline example

above shown tween example could be written in simpler form without pausing and resuming first tween by using anim.timeline();
Tweens in timeline are chained and second tween will start after first one has finished.

import { anim } from '@enea-entertainment/animjs';

const myObject =
    {
        x : 0,
        y : 50
    };

const timeline = anim.timeline({
    onStart: () =>
    {
        console.log('timeline start');
    },

    onComplete: () =>
    {
        console.log('timeline complete');
    }
});

timeline.to(myObject,
    {
        duration    : 2,
        x           : 100,
        repeat      : 1,
        repeatDelay : 0.5,
        ease        : 'cubicOut',
        yoyoEase    : 'backInOut',

        onStart: () =>
        {
            console.log('First tween start');
        },

        onComplete: () =>
        {
            console.log('First tween complete');
        }
    });

timeline.to(myObject,
    {
        delay : 1,
        y     : 10,

        onStart: () =>
        {
            console.log('Second tween start');
        },

        onComplete: () =>
        {
            console.log('Second tween complete');
        }
    });    

It is also possible to start tweens in timeline at the same time by providing 3rd parameter - label{string}

All tweens groupped by labelB will start after all tweens in label labelA have finished.

import { anim } from '@enea-entertainment/animjs';

const myObject =
    {
        a1 : 0,
        a2 : 0,

        b1 : 0,
        b2 : 0
    };

const timeline = anim.timeline({
    onStart: () =>
    {
        console.log('timeline start');
    },

    onComplete: () =>
    {
        console.log('timeline complete');
    }
});

// a1 will finish after one second
timeline.to(myObject,
    {
        duration : 1,
        a1       : 1,

        onComplete: () =>
        {
            console.log('a1 complete');
        }
    }, 'labelA');

// a2 will finish after two seconds
timeline.to(myObject,
    {
        duration : 2,
        a2       : 1,

        onComplete: () =>
        {
            console.log('a2 complete');
        }
    }, 'labelA');

// then b1 will start
// b1 will finish after 4 seconds, notice repeat param
timeline.to(myObject,
    {
        duration : 1,
        b1       : 1,
        repeat   : 3,

        onComplete: () =>
        {
            console.log('b1 complete');
        }
    }, 'labelB');

// b2 will finish 2 seconds after labelA has finished
timeline.to(myObject,
    {
        duration : 2,
        b2       : 1,

        onComplete: () =>
        {
            console.log('b2 complete');
        }
    }, 'labelB');

Tweening array of numbers

Just like numbers, you can also tween arrays

import { anim } from '@enea-entertainment/animjs';

const myObject =
    {
        a : [3, 2, 1],
        b : new Float32Array(3),
        c : [0, 8, 9],
        d : 0
    };

anim.to(myObject,
    {
        a : [1, 2, 3],
        b : [4, 5, 6],
        c : [7], // only first value will be tweened
        d : 10,

        onComplete: () =>
        {
            console.log(myObject.a);
            console.log(myObject.b);
            console.log(myObject.c);
            console.log(myObject.d);

            // outputs {object}

            // myObject.a [1, 2, 3]
            // myObject.b [4, 5, 6]
            // myObject.c [7, 8, 9]
            // myObject.d 10
        }
    });

Tween seek

Jumps to a specific time

import { anim } from '@enea-entertainment/animjs';

const myTween = anim.to({ value: 0 },
    {
        paused   : true,
        duration : 4,
        value    : 10,

        onUpdate: (target) =>
        {
            console.log(target.value);
        }
    });

// outputs: 5
myTween.seek(2);

Time scale

time scale can be used to speed up or slow down tweens. You can either set it globally or per tween

import { anim } from '@enea-entertainment/animjs';

// global time scale
// all tweens will be affected, playing at double speed
anim.timeScale = 2;

or individually

import { anim } from '@enea-entertainment/animjs';

const tween = anim.to({ value: 0 },
    {
        duration : 1,
        value    : 1,
    });

// tween will play at double speed
// and will finish in 0.5 seconds
tween.timeScale = 2;

Built-in easing functions

'none' == 'linear' | 'back' | 'bounce' | 'circ' | 'cubic' | 'elastic' | 'expo' | 'quad' | 'quart' | 'quint' | 'sine'


Easing

could be written in different ways, all of them are valid

ease: 'sineIn'
ease: 'sineOut'
ease: 'sineInOut'
import { Easing } from '@enea-entertainment/animjs';

ease: Easing.sineIn
ease: Easing.sineOut
ease: Easing.sineInOut
import { Easing } from '@enea-entertainment/animjs';

ease: Easing.sine.in
ease: Easing.sine.out
ease: Easing.sine.inOut

Custom easing function

import { anim } from '@enea-entertainment/animjs';

function stepped(time, steps)
{
    return Math.max(0, Math.min(1, (((steps * time) | 0) + 1) * (1 / steps)));
}

const myObject =
    {
        x : 0
    };

anim.to(myObject,
    {
        x    : 10,
        ease : (time) => { return stepped(time, 5); },

        onUpdate: () =>
        {
            // outputs: 2, 4, 6, 8, 10
            console.log(myObject.x);
        }
    });

Delaying code execution

Because AnimJS tick(); is updated manually, sometimes you might want to use AnimJS instead of setTimeout(); to delay code execution.

Either using anim.delay(); where 1st parameter is callback and 2nd parameter is required delay (in seconds)

import { anim } from '@enea-entertainment/animjs';

myMethod()
{
    anim.delay(()=>
    {
        // some code
    }, 1);
}

or by using anim.wait(); which returns promise

import { anim } from '@enea-entertainment/animjs';

anim.wait(1).then(()=>
{
    // some code
});

or

import { anim } from '@enea-entertainment/animjs';

async myMethod()
{
    await anim.wait(1);

    // some code
}

Animation groups

Tweens, timelines and delays can be grouped together and then paused, resumed or killed at once

import { anim } from '@enea-entertainment/animjs';

const enum TweenGroup
    {
        INTRO,
        GAME
    }

const introTween1 = anim.to({value : 0},
    {
        duration : 1,
        group    : TweenGroup.INTRO
        value    : 1,
    });
 
const introTween2 = anim.to({value : 2},
    {
        duration : 1,
        group    : TweenGroup.INTRO
        value    : 3,
    });   

// kills all tweens in TweenGroup.INTRO
anim.group.get(TweenGroup.INTRO)?.kill();

Stopping tween, timeline, delay

import { anim } from '@enea-entertainment/animjs';

const myObject =
    {
        x : 0,
        y : 0,

        scale:
            {
                x : 1,
                y : 1
            }
    };

const tween1 = anim.to(myObject,
    {
        x : 1,
        y : 1
    });

// kills tween1
tween1.kill();

const tween2 = anim.to(myObject.scale,
    {
        x : 2,
        y : 2
    });

// kills all running tweens of myObject.scale
anim.killTweensOf(myObject.scale);

// or
// tween2.kill();

similarly you can kill entire timeline (which will also kill all its tweens)

timeline.kill();

Killing all tweens, timelines, delays at once:

anim.killAll();

Tween or timeline can be marked as protected
Such tweens/timlines will not be killed by anim.killAll(); or tween.kill();

import { anim } from '@enea-entertainment/animjs';

const tween = anim.to(myObject,
    {
        protected : true,

        onComplete: ()=>
        {
            console.log('tween complete');
        }
    });

// tween will not be stopped    
anim.killAll();
tween.kill();

To protect anim.delay(); set its protected property after initialization

import { anim } from '@enea-entertainment/animjs';

const myDelay = anim.delay(()=>
    {
        console.log('delay complete');
    }, 1);

myDelay.protected = true;


// delay will not be stopped    
anim.killAll();
myDelay.kill();

However, if you later decide to stop also protected tweens, timelines or delays, pass true to kill(); method

    anim.killAll(true);

    // or

    tween.kill(true);
    timeline.kill(true);
    myDelay.kill(true);

AnimJS default settings

feel free to override any of these

import { anim } from '@enea-entertainment/animjs';

console.log(anim.defaults);

// outputs {object}:

// delay: 0
// duration: 1
// ease: "none"
// paused: false
// protected: false
// repeat: 0
// repeatDelay: 0
// yoyo: false

Webpack ProvidePlugin

Provides anim so you don't have to import it everywhere

const webpack = require('webpack');

plugins:
[
    new webpack.ProvidePlugin({
        anim : ['@enea-entertainment/animjs', 'anim']
    })
]

TODO

  • repeat whole timeline
  • timeline.seek()
  • timeline.restart()

Thank you

  • AnimJS is based on tweenr by Matt DesLauriers (@mattdesl)
  • Robert Penner for easing functions see terms of use
  • Hugh Kennedy (@hughsk) for an-array check

License

MIT, see LICENSE for details.

About

Lighweight library which lets you tween multiple object's properties

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published