Version: 0.15.1
Creator: Markus Madeja
Development: 2017-05-02 – 2019-08-20
Weekly downloads: 494
License: MIT

AnimationVideo

AnimationVideo is a javascript library to animate objects inside a canvas. The animation can be perfectly synced to music which can even be sought. Everything works without WebGl.

Examples

or in the index.html.

Table of Contents

Installation

Install it for example with

npm i animationvideo

or include the dist/animationvideo.umd.js directly into your project. It's recommended to import each needed component separately. Then you will need to install eases. You can install both together:

npm i animationvideo eases

General overview

The Engine of AnimationVideo will run Scenes that consists of Sprites that can be manipulated with Animations.

How to import

The best way to import components of AnimationVideo is the direct import of the modules.

import Engine from 'animationvideo/Engine.mjs'
import Norm from 'animationvideo/Scenes/Norm.mjs'
import FastBlur from 'animationvideo/Sprites/FastBlur.mjs'
import Image from 'animationvideo/Sprites/Image.mjs'
import Forever from 'animationvideo/Animations/Forever.mjs'
import ChangeTo from 'animationvideo/Animations/ChangeTo.mjs'
import QuadInOut from 'eases/quad-in-out'

This is possible with Webpack >= 4. For older packer you can use the main package and extract the needed components.

import AnimationVideo from "animationvideo";
const {
  Engine,
  Scenes: { Norm },
  Animations: { Forever, ChangeTo },
  Sprites: { Image, FastBlur },
  Easing: { QuadInOut }
} = AnimationVideo;

For simple web projects you can include the js-file directly and use the global AnimationVideo object.

<script src="dist/animationvideo.umd.js"></script>
<script>
  AnimationVideo.Engine(document.querySelector('canvas'))
    .switchScene(AnimationVideo.Scenes.Norm({
      reset: () => [
        [
          AnimationVideo.Sprites.Rect({ clear: true })
        ],
        [
          AnimationVideo.Sprites.Circle({ 
            scaleX: 0.5, 
            scaleY: 0.5,
            color: '#F00',
            animation: AnimationVideo.Animations.Forever([
              AnimationVideo.Animations.ChangeTo({
                color: '#00F'
              }, 1000),
              AnimationVideo.Animations.ChangeTo({
                color: '#F00'
              }, 1000)
            ])
          })
        ],
      ]
    }))
    .run()
</script>

Other examples are done in the index.html.

Example

Here is how the code looks like in an example:

import Engine from 'animationvideo/Engine.mjs'
import Norm from 'animationvideo/Scenes/Norm.mjs'
import FastBlur from 'animationvideo/Sprites/FastBlur.mjs'
import Image from 'animationvideo/Sprites/Image.mjs'
import Forever from 'animationvideo/Animations/Forever.mjs'
import ChangeTo from 'animationvideo/Animations/ChangeTo.mjs'
import QuadInOut from 'eases/quad-in-out'

// The Engine runs the scene "Norm"
new Engine({
  // automaticly adjust the size of the canvas
  autoSize: true,
  // set the target canvas
  canvas: document.querySelector("canvas"),
  // The Engine uses the scene "Norm"
  scene: new Norm({
    // load images beforehand
    images() {
      return { imageFile: "https://placekitten.com/400/400" };
    },
    // initialisation of the scene with sprites
    reset() {
      // the scene resets with two layers
      return [
        // first layer consits of a Image
        [
          new Image({
            image: "imageFile", // show image "imageFile" that was loaded before
            norm: true, // scale to full size
            animation: new Forever([
              // start animation
              // scale larger for 10 seconds with a easing
              new ChangeTo(
                {
                  scaleX: 1.3,
                  scaleY: 1.3
                },
                10000,
                QuadInOut
              ),
              // scale back smaller for 10 seconds with a easing
              new ChangeTo(
                {
                  scaleX: 1,
                  scaleY: 1
                },
                10000,
                QuadInOut
              )
            ])
          })
        ],
        // second layer consits of a blur effect
        [
          new FastBlur({
            compositeOperation: "lighter", // make a glow
            gridSize: 10, // the glow has the size of 10 times 10
            // pixel: true,
            darker: 0.5, // turn down the glow
            alpha: 0, // not visible
            animation: [
              // blend in the glow for half a second with easing
              new ChangeTo({ alpha: 1 }, 500, QuadInOut)
            ]
          })
        ]
      ];
    }
  })
}).run(); // start the engine

Test code at codesandbox.io

Engine

The Engine is the foundation of AnimationVideo that runs the system. It's a class that needs to be instantiated with new. The parameter is an object or a canvas.

import Engine from 'animationvideo/Engine.mjs'

// general setup
const engine = new Engine(canvasOrOptions);

// init with canvas 
const engine = new Engine(document.querySelector('canvas'));

// init with object
const engine = new Engine({
  // automatic scaling of the canvas - default false
  autoSize: false,
  // the canvas that is used by AnimationVideo
  canvas: null,
  // click event will be added to the canvas and send to an audio-scene
  clickToPlayAudio: false
  // the current scene
  scene: null,
});

Constructor option autoSize

This feature will auto scale the canvas. This dynamically creates a balance between quality and performance. You can fine tune the parameter. Setting this to false disable the auto-sizing (this is the default setting). Setting this to true enable the auto-sizing with the default values.

import Engine from 'animationvideo/Engine.mjs'

const engine = new Engine({
  // automatic scaling of the canvas - default false
  // can be true to set default values
  autoSize: {
    // enable/disable this feature
    enabled: true,
    // Best scaling factor (1 = size of drawable canvas is the size of the visible canvas)
    scaleLimitMin: 1,
    // Worst possible scaling factor
    scaleLimitMax: 8,
    // a value > 1. Larger values change the scale faster. 
    scaleFactor: 1.1,  
    // function that gets the visible width of the canvas in pixel
    referenceWidth: () => canvas.clientWidth, 
    // function that gets the visible height of the canvas in pixel
    referenceHeight: () => canvas.clientHeight, 
    // the current scale / the start scale
    currentScale: 1,
    // the time that the system stays at least in the current scale in ms
    waitTime: 800,
    // how many ms the system must be too slow till the scale gets worse (higher)
    offsetTimeLimitUp: 300,
    // how many ms the system must be too fast till the scale gets better (lower)
    offsetTimeLimitDown: 300,
    // the target time - how much time a frame of the main loop should take
    offsetTimeTarget: 1000 / 60,
    // if the time of a frame of the main loop is different than the "offsetTimeTarget",
    // it must be greater than "offsetTimeDelta" to be registered from the system
    offsetTimeDelta: 3,
    // adds events to recalculate the canvas size when the window
    // resizes/orientation changes
    registerResizeEvents: true,
    // adds events to disable the auto-size-system if the window/tab losses focus
    registerVisibilityEvents: true,
    // sets canvas width and height by setting the style attribute of the canvas
    setCanvasStyle: false,
    // start values for the waitTime and the offsetTime
    currentWaitedTime: 0,
    currentOffsetTime: 0
  },
  // don't forget to set canvas, scene...
  canvas: null //...
});

Commands

The instance of Engine has some functions to change the scenes.

import Engine from 'animationvideo/Engine.mjs'

// init with canvas 
const engine = new Engine(document.querySelector('canvas'));

// "recalculateCanvas" will trigger the scaling system of the auto-size-system
// (this will resize the canvas itself)
// after that it will trigger engine.resize()
engine.recalculateCanvas();

// "resize" will propagade a resize event to the sprite-objects of the current scene
engine.resize();

// "switchScene" will change the scene-object
engine.switchScene(scene);

// "run" starts the engine
engine.run( /* optional: object with parameter that are given to the init-function */ );

// "destroy" clean up the events, stops the main loop
// that was started with "run"
engine.destroy();

Scenes

A scene controls what happens on the screen and in the engine. It uses Sprites and Animations.

Default

Default descries a Animation without sound on a canvas with a fixed size. In this canvas the coordinates of the top left corner is 0, 0 and the coordinate in the bottom right is the width, height of the canvas in pixels. This is the basic scene. All other scenes are based on this and add something special (f.e. add audio or the coordinates are special).

A scenes main task is to use the given layerManager to first move the objects of the layers and then to draw them.

There are a number of functions that are given to the constructor that are explained in this example. The functions can be combined in a object or a class:

import Engine from 'animationvideo/Engine.mjs'
import SceneDefault from 'animationvideo/Scenes/Default.mjs'

const engine = new Engine(document.querySelector('canvas'))

const classScene = new SceneDefault(class myScene { /*...same as in object...*/ });

const objectScene = new SceneDefault({
  // "images" is an optional object that returns a list of urls (images) with handlers.
  // The images will be loaded in parallel to calling "init". The scene will start
  // after every image is loaded and init is done.
  // can be a function that returns a object or a fixed object
  images: {
    'handlerName': 'http://image......' // list of images that will be loaded
  }

  // "init" is an optional function or async function and can return a promise.
  // It will be run when the engine sets this scene. The scene will start
  // after every image is loaded and init is done.
  // - engine is the engine object this scene is running in
  // - output is a object with canvas information
  //   output = {
  //     canvas: null,  // the canvas object
  //     context: null, // the context2d of the canvas
  //     width: 0,      // the width of the canvas
  //     height: 0,     // the height of the canvas
  //     ratio: 1       // the ratio between width and height
  //   }
  // - scene is the scene object this object is running in
  // - parameter are the parameter that are given from the 
  //   last scene or the start parameter
  // - imageManager is the object that loads the images
  async init({ engine, output, scene, parameter, imageManager }) {
    // optional: wait till all images are loaded
    // await imageManager.isLoadedPromise()

    // set events or do precalculation...
    // ...
  }

  // "destroy" is an optional function.
  // It will run when the engine's destroy is called or 
  // when the engine switches a scene.
  destroy({ engine, scene, output }) {
    // clean up code

    // return parameter for the next scene
    return {};
  }

  // "loading" is an optional function that replaces the loading animation
  // can be empty to disable any loading animation. F.e. loading() {}
  loading({ engine, scene, output, progress }) {
    // replace the loading screen
    const ctx = output.context;
    const loadedHeight =
      typeof progress === "number"
        ? Math.max(1, progress * output.h)
        : output.h;

    // clean the screen
    ctx.globalCompositeOperation = "source-over";
    ctx.globalAlpha = 1;
    ctx.clearRect(0, 0, output.w, output.h);

    ctx.fillStyle = "#aac";
    ctx.fillRect(0, output.h / 2 - loadedHeight / 2, output.w, loadedHeight);

    ctx.font = "20px Georgia";
    ctx.fillStyle = "#fff";
    ctx.textAlign = "left";
    ctx.textBaseline = "bottom";
    let text = progress;

    // isNumber
    if (!isNaN(parseFloat(progress)) && !isNaN(progress - 0)) {
      text = "Loading " + Math.round(100 * progress) + "%";
    }
    ctx.fillText(
      text,
      10 + Math.random() * 3,
      output.h - 10 + Math.random() * 3
    );

    engine && engine.normalizeContext(ctx);
  },

  // "endTime" can set the operational time of the animation in ms.
  // If the scene is running for "endTime" ms the scene 
  // will call the function "end".
  // By default the value is undefined and thus "end" will never be triggered.
  endTime: 1000,

  // The function "end" will be triggered if the animation is running
  // for "endTime" ms.
  end({ engine, scene, output, timePassed, totalTimePassed }) {
    // f.e. switch scene at the end of a cutscene
  }

  // "tickChunk" will set the interval in ms that will call "fixedUpdate".
  // Default value is 16.66666667.
  // can be a function or a fixed value
  tickChunk: 1000/60,

  // "tickChunk" will set the number of frames
  // that can be skipped while rendering
  // can be a function or a fixed value
  maxSkippedTickChunk: 3,

  // "tickChunkTolerance" will set the time in ms that will be ignored
  // if a frame misses the target tickChunk-time. Default value is 0.1
  // can be a function or a fixed value
  tickChunkTolerance: 0.1,

  // "fixedUpdate" is a optional function that will be 
  // called in fixed periodic intervals that is set in "tickChunk"
  // - engine is the engine object this scene is running in
  // - scene is the scene object this object is running in
  // - layerManager is the object that manages all objects that are in the scene
  // - output is a object with canvas information
  //   output = {
  //     canvas: null,  // the canvas object
  //     context: null, // the context2d of the canvas
  //     width: 0,      // the width of the canvas
  //     height: 0,     // the height of the canvas
  //     ratio: 1       // the ratio between width and height
  //   }
  // - timePassed is the time in ms that has passed since the last frame
  // - totalTimePassed is the time in ms that has passed since the start of the
  //   animation
  fixedUpdate({ engine, scene, layerManager, output, timePassed, totalTimePassed }) {
    // do collision
    // logic or handle events f.e.
    // if (keydown) layerManager.getById(0).addElements(this.createExplosion());
  }

  // "update" is a optional function that will be called once per frame
  // how often this function is called depends on the frame rate
  // - engine is the engine object this scene is running in
  // - scene is the scene object this object is running in
  // - layerManager is the object that manages all objects that are in the scene
  // - output is a object with canvas information
  //   output = {
  //     canvas: null,  // the canvas object
  //     context: null, // the context2d of the canvas
  //     width: 0,      // the width of the canvas
  //     height: 0,     // the height of the canvas
  //     ratio: 1       // the ratio between width and height
  //   }
  // - timePassed is the time in ms that has passed since the last frame
  // - totalTimePassed is the time in ms that has passed since the start of the
  //   animation
  update({ engine, scene, layerManager, output, timePassed, totalTimePassed }) {
    // set text of a object - f.e. the score
    // layerManager.getById(0).getById(0).text = this.score;

    // to draw something on the canvas every frame it's better to use
    // a callback/function in a layer of the layerManager
  }

  // "reset" sets the layers of the scene
  // will be called after the initialization and if there is a seek backwards
  reset({ engine, scene, layerManager, output }) {
    // - you can directly work with the layerManager
    // layerManager.clear();
    // layerManager.addLayer().addElements([ SPRITES ]);
    // return layerManager;

    // - or you can return a 2d-array that will be converted to layers
    // return [
    //  [ SPRITES IN LAYER 0 ],
    //  [ SPRITES IN LAYER 1 ]
    // ]
  }
});

engine.switchScene(objectScene).run();

Layers

A scenes main task is to use the given layerManager to first move the objects of the Layers and to draw them.

import Engine from 'animationvideo/Engine.mjs';
import SceneDefault from 'animationvideo/Scenes/Default.mjs';
import Rect from 'animationvideo/Sprites/Rect.mjs';

new Engine({
  canvas: document.querySelector('canvas'), 
  scene: new SceneDefault({
    // get the first layerManager at reset
    reset({layerManager}) {

      // --- layerManager functions ---
      // clear all elements
      layerManager.clear();

      // add a layer and save the layer in this object
      this.layerBackground = layerManager.addLayer();

      // add a number of layers
      [this.layerScroll1, this layerScroll2] = layerManager.addLayers(2);

      // add a layer and save the id
      this.layerMainId = layerManager.addLayerId();

      // add more then one layer at the same time and save ids
      // returns an array
      this.layerForgroundIds = layerManager.addLayerIds(3);

      // get a layer by a id
      this.layerMain = layerManager.getById(this.layerMainId);

      // loop through the objects of the layers
      layerManager.forEach(({ element, isFunction, layer, index }) => {
        // element is the current object
        // isFunction is true if element is a function
        // layer is the current layer
        // index is the id/position in the layer
      });

      // give number of layers
      console.log(layerManager.count());

      // --- layer function ---
      // add a sprite to the layer and save it
      this.spriteMainRect = this.layerMain.addElement(new Rect());
      // it can be a function
      this.spriteMainFunction = this.layerMain.addElement(
        function ({ engine, scene, layerManager, layer, output, totalTimePassed }) {
          output.context.drawImage(...)
          // return true will remove this function from the layer
          return totalTimePassed > 1000 
        }
      );

      // add a sprite to the layer and return only the id
      const elementId = this.addElementForId(new Rect());

      // add an array of sprites
      [this.spriteMainRect2, this.spriteMainRect3] = this.layerMain.addElements([
        new Rect({...}),
        new Rect({...})
      ]);

      // add array of sprite to the layer and return only the ids
      const elementIds = this.layerMain.addElementsForIds([new Rect(),....]);

      // remove a element of this layer
      this.layerMain.deleteByElement(this.spriteMainRect3);

      // remove a element of this layer by the id of the element
      this.layerMain.deleteById(elementId);

      // loop through the objects of a layer
      this.layerMain.forEach(({ element, isFunction, layer, index }) => {
        // element is the current object
        // isFunction is true if element is a function
        // layer is the current layer
        // index is the id/position in the layer

        // f.e. call all reset methods of the element of the layer
        !isFunction && element.reset && element.reset()
      });

      // get a object by the id from a layer
      this.spriteFirst = this.layerMain.getById(0)

      // get a id by the elment of a layer
      this.spriteFirstID = this.layerMain.getByElement(this.spriteFirst)

      // output the number of elements in the layer
      console.log(this.layerMain.count());

      // empty the layer
      this.layerBackground.clear()

      return layerManager;
    }
  })
}).run()

Norm

This scene is similar to the Default-scene. But the coordinates are different: the middle of the canvas will be at 0, 0, left and bottom of the canvas at -1, -1 and the top right is at 1, 1. In addition the Norm has a function named transformPoint(x,y) that will transform normal x, y coordinates of the canvas (f.e. mouse position) into Norm-coordinates.

import Animationvideo from "animationvideo";
const {
  Engine,
  Scenes: { Norm },
  Animations: { Forever, ChangeTo },
  Sprites: { Circle, FastBlur },
  Easing: { CubicInOut }
} = Animationvideo;

// The Engine runs the scene "Norm"
new Engine({
  // enable autoSize
  autoSize: true,
  // set canvas
  canvas: document.querySelector("canvas"),
  // The Engine uses the scene "Norm"
  scene: new Norm(
    class myExample {
      // mouse event that we will bind
      eventMouseMove(e) {
        // use transforPoint to transform mouse coordinates to internal Norm-ccordinates
        [this.mx, this.my] = this.scene.transformPoint(e.offsetX, e.offsetY);
      }

      init({ engine, output, scene }) {
        // set values we need for position tracking
        this.mx = 1;
        this.my = 0.5;
        this.scene = scene;

        // add mouse move event
        output.canvas.addEventListener(
          "mousemove",
          this.eventMouseMove.bind(this)
        );
      }

      destroy({ output }) {
        // don't forget to clean up
        output.canvas.removeEventListener("mousemove", this.eventMouseMove);
      }

      reset({ layerManager }) {
        // background will be a feedback effect
        layerManager.addLayer().addElement(
          new FastBlur({
            alpha: 0.9,
            scaleX: 10,
            scaleY: 10,
            darker: 0.3,
            clear: true,
            pixel: true
          })
        );

        // above is a circle that will move to the mouse every 500ms
        this.layerMove = layerManager.addLayer();
        layerManager.addLayer().addElements([
          new Circle({
            x: this.mx,
            y: this.my,
            scaleX: 0.1,
            scaleY: 0.1,
            color: "#F00",
            animation: new Forever(
              [
                new ChangeTo(
                  {
                    x: () => this.mx,
                    y: () => this.my
                  },
                  500,
                  CubicInOut
                )
              ]
            )
          })
        ]);
        return layerManager;
      }
    }
  )
}).run(); // start the engine

Test code at codesandbox.io

Audio

This scene is similar to the Default-scene. In addition to the Default-scene-functions you have to set an "audioElement". "end" is automatically called without giving "endTime".

import Animationvideo from "animationvideo";
const {
  Engine,
  Scenes: { Audio },
  Animations: { ChangeTo, Wait, Remove },
  Sprites: { Rect, Path, StarField, FastBlur },
  Easing: { QuadInOut, ElasticOut, BounceOut, QuadOut }
} = Animationvideo;

new Engine({
  // clicking on the canvas will start the audio
  clickToPlayAudio: true,
  // the canvas for the animation
  canvas: document.querySelector("canvas"),
  // The Engine uses the scene "Audio"
  scene: new Audio({
    // audio element that plays the music
    audioElement: document.querySelector("audio"),
    // function that runs when the audio ends
    end() {
      window.alert("audio done");
    },
    // show totalTimePassed
    update({ totalTimePassed }) {
      const tickElement = document.getElementById("tick");
      if (tickElement) {
        tickElement.innerText = Math.round(totalTimePassed);
      }
    },
    // initialisation of the scene with sprites
    reset() {
      return [
        // first layer is the background
        [
          new Rect({
            color: "#117",
            animation: [
              500,
              new ChangeTo({ color: "#88C" }, 1000),
              new Wait(14500),
              new ChangeTo({ color: "#C88" }, 300),
              new ChangeTo({ color: "#FCC" }, 3000)
            ]
          })
        ],
        // effect rects
        [
          new Rect({
            color: "#66b",
            width: 100,
            x: -100,
            animation: [
              500,
              new ChangeTo({ x: 100 }, 1000, ElasticOut),
              new Wait(14500),
              new ChangeTo({ alpha: 0 }, 300),
              new Remove()
            ]
          }),
          new Rect({
            color: "#66b",
            width: 100,
            x: 800,
            animation: [
              500,
              new ChangeTo({ x: 600 }, 1000, ElasticOut),
              new Wait(14500),
              new ChangeTo({ alpha: 0 }, 300),
              new Remove()
            ]
          }),
          new Rect({
            color: "#449",
            width: 100,
            x: -100,
            animation: [
              500,
              new ChangeTo({ x: 200 }, 1000, ElasticOut),
              new Wait(14500),
              new ChangeTo({ alpha: 0 }, 300),
              new Remove()
            ]
          }),
          new Rect({
            color: "#449",
            width: 100,
            x: 800,
            animation: [
              500,
              new ChangeTo({ x: 500 }, 1000, ElasticOut),
              new Wait(14500),
              new ChangeTo({ alpha: 0 }, 300),
              new Remove()
            ]
          }),
          new Rect({
            color: "#227",
            width: 100,
            x: -100,
            animation: [
              500,
              new ChangeTo({ x: 300 }, 1000, ElasticOut),
              new Wait(14500),
              new ChangeTo({ alpha: 0 }, 300),
              new Remove()
            ]
          }),
          new Rect({
            color: "#227",
            width: 100,
            x: 800,
            animation: [
              500,
              new ChangeTo({ x: 400 }, 1000, ElasticOut),
              new Wait(14500),
              new ChangeTo({ alpha: 0 }, 300),
              new Remove()
            ]
          })
        ],
        // logo that morphs
        [
          new Path({
            path:
              "M123.3 5.5c-5.7 1.3-10.9 4.8-14.6 9.8-9 12.1-4.8 31 8.6 37.8L121 55v47.7l-4 3.2c-3.7 3-5.3 3.4-19.9 5.7l-15.9 2.5-3.6-2.5c-8.3-5.6-24.3-6.2-31.6-1.1-2.8 1.9-4.3 3.9-5 6.5l-1 3.7-9.7 1.6c-12 2-16.5 4.8-20.5 12.7-3.5 6.9-4.8 13.8-4.8 25.4 0 10 2.3 16.9 7.2 21.3 2.2 2.1 68.6 37.5 80.3 42.9l5 2.3 36-2.9c19.8-1.6 39.2-3.1 43-3.4 40.2-3.1 37.7-2.8 42.2-6.2 5.5-4.2 7.5-12.4 6.3-25.1-1-9.5-2.5-12.8-20.3-43.8-20.4-35.6-22.3-38.4-29.1-41.9-3.3-1.7-6.9-3.9-8-5-5.8-5.1-13.9-7.1-23.7-5.8l-5.6.8-.6-14c-1.2-25.1-1.3-24.2 3.2-26.5 14.2-7.3 17.6-27.4 6.8-39.7-2.2-2.5-5.1-5.1-6.6-5.8-4.7-2.5-12.2-3.3-17.8-2.1z",
            color: "#000",
            borderColor: "#FFF",
            lineWidth: 3,
            x: 270,
            y: 30,
            alpha: 0,
            scaleY: 0.7,
            rotationInDegree: -5,
            animation: [
              // wait 2000 ms
              2000,
              // intro
              new ChangeTo(
                {
                  rotationInDegree: 0,
                  scaleY: 1,
                  alpha: 1
                },
                1500,
                BounceOut
              ),
              new Wait(500),
              new ChangeTo(
                {
                  x: 260,
                  y: 20,
                  scaleX: 1.1,
                  scaleY: 1.1
                },
                4000,
                QuadInOut
              ),
              new Wait(1000),
              // morph
              new ChangeTo(
                {
                  path:
                    "M384,48.734c-70.692,0-128,57.308-128,128c0-70.692-57.308-128-128-128s-128,57.308-128,128c0,137.424,188.048,252.681,241.805,282.821c8.823,4.947,19.567,4.947,28.39,0C323.952,429.416,512,314.158,512,176.734C512,106.042,454.692,48.734,384,48.734z",
                  scaleX: 0.5,
                  scaleY: 0.5
                },
                1000,
                BounceOut
              ),
              new Wait(6000),
              new ChangeTo(
                {
                  x: 215,
                  y: -25,
                  scaleX: 0.7,
                  scaleY: 0.7
                },
                6500,
                QuadInOut
              )
            ]
          })
        ],
        // effect stars
        [
          new StarField({
            moveX: 0,
            animation: [
              4000,
              new ChangeTo({ moveY: -4 }, 1000, QuadInOut),
              new Wait(2000),
              new ChangeTo({ moveY: 0 }, 200, QuadOut),
              new Wait(3300),
              new ChangeTo(
                {
                  moveX: 4,
                  moveY: -2
                },
                1000,
                QuadInOut
              ),
              new Wait(3000),
              new ChangeTo(
                {
                  moveX: 0,
                  moveY: 0
                },
                200,
                QuadOut
              ),
              new Remove()
            ]
          })
        ],
        // last layer consits of a blur effect
        [
          new FastBlur({
            compositeOperation: "lighter", // make a glow
            gridSize: 10, // the glow has the size of 10 times 10
            // pixel: true,
            darker: 0.5, // turn down the glow
            alpha: 0, // not visible
            animation: [
              // wait 2000 ms
              2000,
              // blend in the half visible glow
              new ChangeTo({ alpha: 0.4 }, 1500, QuadInOut)
            ]
          })
        ]
      ];
    }
  })
}).run(); // start the engine

Test code at codesandbox.io

NormAudio

This scene is similar to the Audio-scene. But the coordinates are different: the middle of the canvas will be at 0, 0, left and bottom of the canvas at -1, -1 and the top right is at 1, 1. In addition the Norm has a function named transformPoint(x,y) that will transform normal x, y coordinates of the canvas (f.e. mouse position) into Norm-coordinates. See Norm for more information.

Sprites

Sprites are the objects that are drawn on the screen. They are the main ingredient of an animation.

Image

Renders an image to the canvas. Can be a real image or the reference to an image loaded with the images routine of the scene.

import Animationvideo from "animationvideo";
const {
  Engine,
  Scenes: { Default },
  Sprites: { Image },
} = Animationvideo;

new Engine({
  canvas: document.querySelector("canvas"),
  scene: new Default({
    // load images beforehand
    images() {
      return { imageFile: "https://placekitten.com/400/400" };
    },
    // initialisation of the scene with sprites
    reset() {
      return [[
        new Image({
          enabled: true,
          image: 'imageFile', // name of the key of the image defined in "images"
          x: 0, // position of the image
          y: 0, 
          width: undefined, // width and height of the image. Undefined to take
          height: undefined, // it from the original image.
          rotation: 0, // use rotationInDegree to give values in degree
          scaleX: 1, // scalling of the image
          scaleY: 1,
          alpha: 1, // transparency
          compositeOperation: 'source-over',
          position: Image.CENTER, // or Image.LEFT_TOP - pivot of the image
          frameX: 0, // left corner of the sprite that will be cut out from an image
          frameY: 0, // top corner of the sprite that will be cut out from an image
          frameWidth: 0, // width of the sprite that will be cut out from an image
          frameHeight: 0, // height of the sprite that will be cut out from an image
          norm: false, // resize the image, so it hits the corner of the canvas
          animation: undefined
        })
      ]]
    }
  })
}).run();

You can also use Sprite Sheets. You can cut out a single Sprite with frameX, frameY, frameWidth, frameHeight. See the ImageFrame-Animation for an example.

Rect

Renders a rectangle in a color. Can be used in a short form to clear the screen.

import Animationvideo from "animationvideo";
const {
  Engine,
  Scenes: { Default },
  Sprites: { Rect },
} = Animationvideo;

new Engine({
  canvas: document.querySelector("canvas"),
  scene: new Default({
    reset() {
      return [[
        new Rect({
          enabled: true,
          x: 0, // Position - default upper left corner
          y: 0,
          width: undefined, // Size - default full screen
          height: undefined,
          rotation: 0, // rotation in radian. Use rotationInDegree to give values in degree
          alpha: 1, // transparency
          compositeOperation: 'source-over',
          color: "#fff", // color of the rect
          borderColor: undefined, // optional border color - undefined to disable the border
          lineWidth: 1, // size of the border
          clear: false, // clear the rect instead of filling with color
          animation: undefined
        })
      ],
      [
        new Rect({ clear:true }) // <- short form to clear the full canvas
      ]]
    }
  })
}).run();

Circle

Renders a circle in a color.

import Animationvideo from "animationvideo";
const {
  Engine,
  Scenes: { Default },
  Sprites: { Circle },
} = Animationvideo;

new Engine({
  canvas: document.querySelector("canvas"),
  scene: new Default({
    reset() {
      return [[
        new Cirlce({
          enabled: true,
          x: 0, // Position - default upper left corner
          y: 0,
          scaleX: 1., // scalling of the cirlce
          scaleY: 1.,
          rotation: 0, // rotation in radian. Use rotationInDegree to give values in degree
          alpha: 1, // transparency
          compositeOperation: 'source-over',
          color: "#fff", // color of the rect
          animation: undefined
        })
      ]]
       // position
      x: 0,
      y: 0,
      // rotation
      rotation: (value, givenParameter) => {
        return ifNull(
          value,
          ifNull(
            givenParameter.rotationInRadian,
            ifNull(givenParameter.rotationInDegree, 0) * degToRad
          )
        );
      }
    }
  })
}).run();

Path

Text

Callback

FastBlur

StarField

Group

Canvas

Particle

Emitter

Scroller

Animations

Sequence

Loop

Forever

State

Wait

WaitDisabled

ChangeTo

Move

Image

ImageFrame

Shake

Callback

If

Once

ShowOnce

End

EndDisable

Remove

TODO

License

MIT