npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

fast-animation-tool

v0.6.8

Published

The fast animation tool with zero dependencies.

Downloads

7

Readme

Web's fastest and most lightweight animation tool.

When it comes to raw animation speed FAT outperforms every single web animation library out there and also provides flexible animation capabilities like scenes, sequences, transforms, coloring, controlling and easing.

Installation Guide  •  API Reference  •  Examples  •  Custom Builds  •  Benchmark Ranking

Get Latest (Stable Release):

All Features:

The flags DEBUG and PROFILER are also available in fat.js for non-production use.

It is also very simple to make a Custom Build

Benchmark Ranking

Library Comparison: Benchmark "Bouncing Balls"

"Animate" (2000 Bouncing Balls)

"Transforms" (2000 Bouncing Balls)

"Colors" (2000 Flashing Balls)

Browser: Chrome (Desktop), Test Duration: 30 sec (median value) * Memory Heap: The size of memory the animations requires to execute ** Memory Allocation: The amount of memory which was allocated during animation runtime

Library Comparison: Benchmark "Bouncing Balls"

Installation

HTML / Javascript
<html>
<head>
    <script src="fat.min.js"></script>
</head>
...

Note: Use fat.min.js for production and fat.js for development.

Use latest stable release from CDN:

<script src="https://cdn.jsdelivr.net/gh/nextapps-de/fat@master/fat.min.js"></script>

Use a specific version from CDN:

<script src="https://cdn.jsdelivr.net/gh/nextapps-de/[email protected]/fat.min.js"></script>

Common JS

In your code include as follows:

var Fat = require("Fat");

AMD

var Fat = require("./fat.min.js");

API Overview

The namespace "Fat" is also the default scene (global scene).

Global methods / Scene methods:

  • Fat.animate(selector | elements, styles | preset, options, callback)
  • Fat.transform(selector | elements, styles, options, callback)
  • Fat.filter(selector | elements, styles, options, callback)
  • Fat.transition(selector | elements, styles, options, callback)
  • Fat.native(selector | elements, styles, options, callback)
  • Fat.destroy()

Control methods:

  • Scene.set(selector | elements, styles, force?)
  • Scene.set(selector | elements, style, value, force?)
  • Scene.remove(selector | elements, styles)
  • Scene.pause(boolean: toggle)
  • Scene.reverse(boolean: toggle)
  • Scene.start(boolean: toggle)
  • Scene.finish()
  • Scene.reset()
  • Scene.loop(int: count)
  • Scene.shift(int: ms)
  • Scene.seek(float: position)
  • Scene.speed(float: ratio)

Scene Options

Animation Options

Basic Usage

Fat.animate(selector[] | elements[], styles[]{}, options{}, callback)

Fat.animate("#mydiv", { left: "100px" },{ /* options */ });

Pass in an element, an array of elements or a dom query selector.

Fat.animate("#mydiv", { 
    left: "100px", 
    top: "100px"
},{ 
    delay: 1000,
    duration: 2000,
    ease: "easeInOut",
    callback: function(){ 
        // "this" refers to #mydiv
        console.log(this.style.left);
    }
});

See all available options above.

Pass in custom options for each style property:

Fat.animate("#mydiv", { 
    left: {
        from: 0,
        to: 100,
        unit: "%",
        duration: 2000,
        ease: "linear"
    },
    top: {
        from: 0,
        to: "100%",
        duration: 2000,
        ease: "quadIn",
        delay: 2000
    }
});

Passing a unit parameter is slightly faster.

"From-To-Unit" Shortcut property: [from, to, unit]:

Fat.animate("#mydiv", {
    left: [0, 100, "%"], // from 0%  to 100%
    top: [0, "100%"],
});

Alternatively pass the callback function as the last parameter:

Fat.animate("#mydiv", { 
    left: "100px", 
    top: "100px" 
},{ 
    delay: 2000,
    duration: 2000,
    ease: "easeInOut"

}, function(){
    
    // done
});
Fat.animate("#mydiv", { top: "100px" }, function(){
    // done
});
Fat.animate("#mydiv", "slideInTop", function(){
    // done
});

Delay an animation until the target element comes into view (e.g. by scrolling):

Fat.animate("#mydiv", { top: "100px" }, { delay: "view" });

Relative Values:

Calculate values depending on the current state:

// current left + 100px
Fat.animate("#mydiv", { left: "+=100px" });
// double of current top
Fat.animate("#mydiv", { top: "*=2" });
// current left - 100px
Fat.animate("#mydiv", { left: "-=100px", });
// half of current top
Fat.animate("#mydiv", { top: "/=2" });

Toggle values depending on the current state:

// toggle current left (100% or 0%)
Fat.animate("#mydiv", { left: "!=100%" });

Transform

Separate notation provides the best performance:

Fat.animate("#mydiv", { 
    translateX: "100px",
    translateY: "100px"
});

same as:

Fat.transform("#mydiv", { ... });

alternatively:

Fat.animate("#mydiv", { 
    "transform": "translate(100px, 100px)"
});

same as:

Fat.transform("#mydiv", "translate(100px, 100px)");

Colors

Fat.animate("#mydiv", { 
    color: "#f00",
    backgroundColor: "rgba(0, 255, 0, 1)",
    borderColor: "hsla(0, 100%, 100%, 1)"
});

Separate notation provides the best performance:

Fat.animate("#mydiv", { 
    colorR: 0,
    colorG: 0,
    colorB: 0,
    colorA: 0,
    backgroundColorA: "100%",
    borderColorB: 255
});

Filter

Separate notation provides the best performance:

Fat.animate("#mydiv", { 
    brightness: 0.5,
    contrast: 0.5,
    hue: "180deg"
});

You can use the shorthand hue as hue-rotate

same as:

Fat.filter("#mydiv", { ... });

alternatively:

Fat.animate("#mydiv", { 
    "filter": "brightness(0.5) contrast(0.5) hue(180deg)"
});

same as:

Fat.filter("#mydiv", "brightness(0.5) contrast(0.5) hue(180deg)");

Easing

Built-in easing:

  • linear
  • easeIn, easeOut, easeInOut (refers to: quadIn, quadOut, quadInOut)
  • cubicIn, cubicOut, cubicInOut
  • quartIn, quartOut, quartInOut
  • quintIn, quintOut, quintInOut
  • sineIn, sineOut, sineInOut
  • expoIn, expoOut, expoInOut
  • circIn, circOut, circInOut
  • backIn, backOut, backInOut
  • snap

Static (Pre-Cached) vs. Dynamic Easing

There are two ways to define easing functions. When your easing is a static curve (like easeIn, backInOut, elastic, etc.) you should define the easing via Fat.ease["myEasing"] = fn() and simply pass the name as string within the Fat.animate options. This will prefetch all the calculations, so you are free to use really heavy easing definitions without any performance drawbacks.

When you want to use dynamic easing, which depends on runtime calculations, you should pass the easing function directly to the Fat.animate options. In this case the easing calculation will not prefetch. This allows you to control easing programmatically and adding logic during runtime.

Define custom static easing function (1-parameter style):

Fat.ease["linear"] = function(x){
    return x;
};

x: current progress (0.0 - 1.0)

Define custom static easing function (4-parameter style):

Fat.ease["linear"] = function(t, b, c, d){
    return b + (c - b) * (t / d);
};

t: current time, b: from value, c: to value, d: duration

Apply the custom static easing:

Fat.animate("#mydiv", { left: "100px" },{ ease: "linear" });

Use cubic bezier:

Fat.animate("#mydiv", { left: "100px" },{ ease: "cubic(0, 1, 0, 1)" });

Shorthand array notation for a bezier is recommended:

... ,{ ease: [0, 1, 0, 1] });

Define custom dynamic easing function (1-parameter style):

Fat.animate("#mydiv", { left: "100px" },{ ease: function(x){
    // doing some crazy calculations depends on runtime
    return x;
}});

Define custom dynamic easing function (4-parameter style):

Fat.animate("#mydiv", { left: "100px" },{ ease: function(t, b, c, d){
    // doing some crazy calculations depends on runtime
    return x;
}});

Custom Property / Renderer

Fat.animate(custom_object[]{}, custom_property[]{}, options{})

Note: You can't use more than one custom property per animation on a HTML element. Instead when animating custom object properties there are no limits.

Just add a property with the name "custom":

Fat.animate("#mydiv", { 
    custom: "50%" 
},{  
    ease: "cubicInOut", 
    step: function(progress, current){
        this.style.left = current;
    }
});

Handle unit separately:

Fat.animate("#mydiv", { 
    custom: 50 
},{ 
    ease: "cubicInOut", 
    step: function(progress, current){
        this.style.left = current + "%";
    }
});

Pass in custom object/function as first parameter instead of an element:

Fat.animate({ 
    obj: document.getElementById("mydiv") 
},{ 
    custom: 50
 },{
    ease: "cubicInOut",
    step: function(progress, current){
        // "this" refers to the custom object
        this.obj.style.left = current + "%";
    }
});

You can also use sequences:

... [custom: 50, custom: 0, custom: 100, custom: 0]

This way it is possible to pass custom data, logic and renderer through each animation job, e.g.:

var handler = {
    unit: "%",
    obj: document.getElementById("mydiv"),
    set: function(property, value){ 
        this.obj.style[property] = value + this.unit;
    }
};

Fat.animate(handler, { custom: 50 },{
    ease: "cubicInOut",
    step: function(progress, current){
        // "this" refers to handler
        this.set("left", current);
    }
});

You can also use array of objects/handlers:

Fat.animate([handler1, handler2, handler3], ...

If you don't need the from/to transition values at all, another scenario could be:

function cubicInOut(x) {
    return ((x *= 2) <= 1 ? x*x*x : (x -= 2) *x*x + 2) / 2;
}

Fat.animate({ ease: cubicInOut },{ custom: true },{
    step: function(progress){
        var current = this.ease(progress);
        // console.log(current);
    }
});

alternatively:

Fat.animate({},{ custom: true },{ step: function(progress){
    var current = cubicInOut(progress);
    // console.log(current);
}});

or:

Fat.animate({},{ custom: 1 },{
    ease: cubicInOut, 
    step: function(progress, current){
        // console.log(current);
    }
});

Tween custom object properties:

function draw(){
    this.obj.style[this.property] = this.value;
}

var custom = {
    value: 0,
    property: "left",
    obj: document.getElementById("#mydiv")
};

Fat.animate(custom, { value: "50%" },{
    duration: 2000,
    ease: "cubicInOut",
    step: draw
});

Sequences

Fat.animate("#mydiv", [
    { left: "100%" },   // 1st animation, 2000ms
    { top: "100%" },    // 2nd animation, 2000ms
    { left: 0 },        // 3rd animation, 2000ms
    { top: 0 }          // 4th animation, 2000ms
],{
    callback: function(){ alert("Next Loop") },
    delay: 2000,
    loop: -1 // infinite
});

Use custom options per style property:

Fat.animate("#mydiv", [{   
    left: { // 1st animation
        from: 0,
        to: 100,
        unit: "%",
        duration: 2000
    }
},{   
    top: { // 2nd animation
        to: "100%",
        duration: 2000,
        ease: "easeInOut",
        delay: 0
    }
},  
...

Keyframes

Fat.animate("#mydiv", {
    "25%":  { left: "100%" },   //  0 ->  25%, 500ms
    "50%":  { top: "100%" },    // 25 ->  50%, 500ms
    "75%":  { left: 0 },        // 50 ->  75%, 500ms
    "100%": { top: 0 }          // 75 -> 100%, 500ms
},{
    callback: function(){ alert("Next Loop") },
    delay: 2000,
    loop: -1 // infinite
});

Use custom options per style property:

Fat.animate("#mydiv", {
    "0%": {   
        left: {
            to: "100%",
            ease: "easeIn"
        }
    }, 
    "100%": {   
        top: {
            to: "0%",
            ease: "easeOut"
        }
    }
},   
...

Presets (Effects)

Fat.animate("#mydiv", "fadeOut");

Combine multiple presets (ordered):

Fat.animate("#mydiv", "fadeOut zoomOut rollOutRight");

Also usable with sequences:

Fat.animate("#mydiv", ["slideInTop", "zoomIn"]);

Define custom preset:

Fat.preset["fade-out-down"] = { 
    opacity: 0, 
    translateY: "100%"
};

Use custom preset:

Fat.animate("#mydiv", "fade-out-down");

Builtin Presets:

  • fadeIn, fadeOut, fadeToggle
  • slideInLeft, slideOutLeft, slideToggleLeft
  • slideInRight, slideOutRight, slideToggleRight
  • slideInTop, slideOutTop, slideToggleTop
  • slideInBottom, slideOutBottom, slideToggleBottom
  • zoomIn, zoomOut, zoomToggle
  • rollOutRight (clockwise), rollInRight, rollToggleRight
  • rollOutLeft (opposite), rollInLeft, rollToggleLeft
  • blurIn, blurOut, blurToggle
  • scrollUp, scrollDown, scrollLeft, scrollRight

Scenes (Groups)

Get the global scene (default):

var scene = Fat.animate(element, { left: "100%" });

Create a new scene:

var scene = Fat.create();

Add animations to a scene:

scene.animate(element, { left: "100%" });

Destroy scene:

scene.destroy();

Useful Example

Considering the following example:

var scene_1 = Fat.animate(element_1, { left: "100%" });
var scene_2 = Fat.animate(element_2, { left: "100%" });
var scene_3 = Fat.animate(element_3, { left: "100%" });

// this will also destroy scene_2 and scene_3:

scene_1.destroy();

All variables points to the same global scene on which is "Fat" basically based on.

This is the correct workaround:

var scene_1 = Fat.create().animate(element_1, { left: "100%" });
var scene_2 = Fat.create().animate(element_2, { left: "100%" });
var scene_3 = Fat.create().animate(element_3, { left: "100%" });

// this will just destroy scene_1:

scene_1.destroy();

Do not massively create new scenes and also do not create them by default. A large amount of parallel scenes results in a performance drawback.

Controls

Fat internally points to default global scene, so you can use all scene methods on Fat accordingly.

Update single style:

scene.set("#mydiv", "left", "0%");

Update multiple styles:

scene.set("#mydiv", { top: 0, left: 0 });

Remove all animations from an object:

scene.remove("#mydiv");

Remove a specific animation from an object:

scene.remove("#mydiv", "left");

Remove a list of specific animations from an object:

scene.remove("#mydiv", ["top", "left"]);

Pause a scene:

scene.pause();

alternatively:

scene.start(false);

Play a scene:

scene.start();

alternatively:

scene.pause(false);

Revert playback (toggle):

scene.reverse();

alternatively set direction:

scene.reverse(false);

Reset playback state and jump back to the start:

scene.reset();

Finish and also execute callback:

scene.finish();

Set playback speed:

scene.speed(0.5); // half
scene.speed(1);   // normal
scene.speed(2);   // double
scene.speed(-2);  // double (reversed direction)

Seek a scene to a specific position:

scene.seek(0);   // start
scene.seek(0.5); // middle
scene.seek(1);   // end

Shift a scene relative to the current position (by milliseconds):

scene.shift(2000); // current + 2000 ms
scene.shift(-500); // current - 500 ms

Looping Sequences & Reversed Direction

When looping sequences and also have reversed animation direction (e.g. by setting speed < 0) you have to pass a from-to declaration pair for each style, otherwise the from-value gets lost when looping back from reversed direction.

var scene = Fat.animate(element, [{
    left: { from: "0%", to: "50%" }
},{
    left: { from: "50%", to: "0%" }
}],{
    loop: -1
});

scene.reverse();

alternatively use from-to-unit shorthand:

var scene = Fat.animate(element, [{
    left: [0, 50, "%"]
},{
    left: [50, 0, "%"]
}],{
    loop: -1
});

scene.reverse();

alternatively use relative toggle:

var scene = Fat.animate(element, [{
    left: "!=50%"
},{
    left: "!=0%"
}],{
    loop: -1
});

scene.reverse();

Scroll

Scroll document/element to a specific position (vertically):

Fat.animate(element, { scrollTop: 500 });

Scroll horizontally:

Fat.animate(element, { scrollLeft: 500 });

Scroll in both directions scroll: [x, y]:

Fat.animate(element, { scroll: [500, 500] });

Use relative values:

Fat.animate(element, { scroll: "+=50" });

Paint

Schedule a task to perform during next animation frame:

Fat.paint(function(time){

    console.log("Now: " + time);
});

Schedule a task with a delay and keep the paint id:

var id = Fat.paint(function(time){

    console.log("Now: " + time);
    
}, 2000);

Remove the above scheduled task from the queue:

Fat.cancel(id);

Loop a task with every animation frame:

Fat.paint(function(time){

    console.log("Now: " + time);
    return true;
});

Just return true to keep the loop alive. Return false or return nothing to break the loop.

Init (Options)

Considering the following example:

Fat.animate(element, { top: "100%" }, function(){
    
    this.style.top = 0; // this style change will be shadowed
    
    Fat.animate(this, { top: "100%" });
});

This is called animation loop, the callback creates a new animation on the same objects style property. Technically the callback executes during the last frame of the first animation. So there is still running an animation on this property and will be inherited by the next animation loop.

During the callback, external changes on the same style property which is going to be animated will be shadowed by the animation loop inheritance.

When the style change did not happened externally (e.g. by a different tool) use set method to get best performance:

Fat.animate(element, { top: "100%" }, function(){
    
    Fat.set(this, "top", 0).animate(this, { top: "100%" });
});

Otherwise, to solve this situation you have to add the init option:

Fat.animate(element, { top: "100%" }, function(){
    
    this.style.top = 0; // external change somewhere happens
    
    Fat.animate(this, { top: "100%" }, { init: true });
});

Again, this issue only occurs when using animation loops mixed with manual style changes on the same style property during the callback right before the new animation loop is called.

Strict (Options)

Considering the following example:

Fat.animate("#mydiv", { top: "100%" }, { duration: 2000 }, function(){
    console.log("long");
});

// next animation will override the above one:

Fat.animate("#mydiv", { top: "100%" }, { duration: 400 }, function(){
    console.log("short");
});

When you perform different animations on the same object style properties to run in parallel there is a concurrency issue. By default a dupe animation inherits the old one, so the old animation is not existing anymore. Accordingly to the example from above the console just logs "short".

To force duped animations you have to add the strict option:

// this animation cannot be overridden:

Fat.animate("#mydiv", { top: "100%" }, { duration: 2000, strict: true }, function(){
    console.log("long");
});

Fat.animate("#mydiv", { top: "100%" }, { duration: 400 }, function(){
    console.log("short");
});

Now the console logs "short" after 400ms and "long" after 2000ms. Although same properties cannot have two different values, so always the most early started animation gets prioritized actually.

Force (Options)

Considering the following example:

#mydiv{ top: 0px !important }
Fat.animate("#mydiv", { top: "100%" });

The css style declaration from above has the keyword !important and is preventing normal style changes.

To solve this you have to add the force option:

Fat.animate("#mydiv", { top: "100%" }, { force: true });

Render Engines

These is an experimental feature. All engines are stand-alone, you can make a custom build just with your favorite pick.

Use CSS Transitions:

Fat.transition("#mydiv", { 
    left: "100px",
    top: "100px"
},{ 
    delay: 1000,
    duration: 2000,
    ease: "easeInOut",
    callback: function(){ 
        // done
        console.log(this.style.left);
    }
});

Use Web Animation API:

Fat.native("#mydiv", { 
    left: "100px",
    top: "100px"
},{ 
    delay: 1000,
    duration: 2000,
    ease: "easeInOut",
    callback: function(){ 
        // done
        console.log(this.style.left);
    }
});

Debug

Do not use DEBUG in production builds.

If you get issues, you can temporary set the DEBUG flag to true on top of fat.js:

DEBUG = true;

This enables console logging of several processes. Just open the browsers console to make this information visible.

Profiler Stats

Do not use PROFILER in production builds.

To collect some performance statistics of your scenes you need to temporary set the PROFILER flag to true on top of fat.js:

PROFILER = true;

This enables profiling of several processes.

An array of all profiles is available on:

window.stats;

You can also just open the browsers console and enter this line to get stats.

The index of the array corresponds to the scene.id.

Get stats from a specific scene:

scene.stats;

The returning stats payload is divided into several categories. Each of these category provides its own statistic values.

Profiler Stats Properties

Custom Builds

You need Node.js including Node Package Manager (NPM)

Install Dependencies:

npm install

Full Build:

npm run build

Light Build:

npm run build-light

Compact Build:

npm run build-compact

Custom Build:

npm run build-custom SUPPORT_EASE_IN_CUBIC=true SUPPORT_CONTROL=true

On custom builds each build flag will be set to false by default.

Alternatively (Custom Build):

node compile support_control=true

The custom build will be saved to fat.custom.xxxxx.js (the "xxxxx" is a hash based on the used build flags).

Supported Build Flags


Copyright 2019 Nextapps GmbH Released under the Apache 2.0 License