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

animation-composition

v2.2.0

Published

Compose Sprite Animation Layers

Downloads

4

Readme

Animation

Opts

  • canvas: The canvas element for the animation to use
  • layers: An Array of Layers composed however you'd like
  • loop (optional default: true)
  • ticksPerFrame (optional default: 0): How many frame delay you would like in each 60 frame/sec call. e.g. 1 ticksPerFrame is ~30fps
  • debug (optional default: false): If you'd like to offset Layers or receive console logs
  • debugOffset (optional default: 0): This only takes effect if debug is true. This is the amount of pixels to offset the layers for debugging.
  • paused (optional default: false): Do not play animation. Allows manual step through using animation.next(). If true ticksPerFrame is always set to 0
  • onerror (optional): If there is an error this function will be called

Methods

  • instance.destroy: Destroy instance and stop RAF timer
  • instance.next: If paused, render next frame

Layers

BaseLayer

This is a base class that can be extended. This base class is the base for all Layer Types included in this library.

Opts

  • name (optional): this can be used for debugging

Interface Methods are:

  • render(canvas, frameIndex) You will use this to manipulate the Canvas in any way you'd like. Be aware this canvas could have data in it based on previous layers in the animation.

Preset Default Methods:

  • getFrames() { return 0; }
  • preload() { return Promise.resolve(); }

ColorLayer (extends BaseLayer)

Color Layer will give a flat full canvas color fill. I built this for my use with MaskLayer to color fill a mask image.

Opts

  • color: a CanvasRenderingContext2D.fillStyle

EXAMPLE:

const colorLayer = new ColorLayer({ color: 'rgba(51, 170, 51, .7)' });

Layer (extends BaseLayer)

Layer is an image layer. This is used as an animation layer base for animating across multiple images.

Opts

One of the following are required:

  • images: An array of one or more image URLs to be used
  • sprite: An object to describe the sprite sheet
    • sheet: The URL to the sprite sheet
    • size: width of a frame (only with is supported right now)
    • frames: Number of frames in the animation (this allows a sheet to have empty frames)
  • sizeRef (optional): an optional reference to a Layer type to be used

EXAMPLE:

const border = new Layer({
  images: [ '/ripple-web/border/ripple_border_00.png', '/ripple-web/border/ripple_border_01.png' ]
});

MaskLayer (extends BaseLayer)

MaskLayer is used to cleverly compose global canvas masking to apply masks to certain layers. This does have some hard limitations;

  • Mask layers must be grouped together if there is more than one. Example:
OK: [ shapeLayer1, mask1, mask2, shapeLayer2 ]

NOT VALID: [ mask1, shapeLayer1, mask2, shapeLayer2 ]

Technical explanation. Canvas only allows global mask composition, this means that any layer data already written to the canvas will affect the mask. To work around that we first find all the mask layers in the animation and render those first (top to bottom, writing new data below existing data). After masks we write nonmask layers to the canvas being careful to place data correctly below or above. If needed we could allow nongrouped mask layers, but it was not needed for my usage.

Opts

  • mask: A Layer that will be used as the mask source. This can be an animation.
  • layers: An array of Layers to be masked using the source.

EXAMPLE:

const avatarMask = new Layer({
  images: [ '/ripple-web/mask/ripple_00.png', '/ripple-web/mask/ripple_01.png' ],
});
const avatarImageLayer = new Layer({ images: [ '/ripple-web/avatar.png' ], sizeRef: avatarMask });
const avatarLayer = new MaskLayer({ mask: avatarMask, layers: [ avatarImageLayer ]});

Utils

imageStringIterator(path, startNumber, endNumber)

This Util is used to iterate over a number of images at a specific path.

Arguments

  • path: Path with XX representing the number to be replaced
  • startNumber: what to start at
  • endNumber: what to end at

EXAMPLE:

import AnimationComposition from 'animation-composition';
const { Utils } = AnimationComposition;
const { imageStringIterator } = Utils;

console.log(
  imageStringIterator(`/ripple/border/ripple_XX_xhdpi.png`, 0, 29)
);

// [
//   '/ripple/border/ripple_00_xhdpi.png',
//   '/ripple/border/ripple_01_xhdpi.png',
//   ...
//   '/ripple/border/ripple_29_xhdpi.png',
// ]

Library Example

import AnimationComposition from 'animation-composition';
const { Animation, Layer, MaskLayer, ColorLayer, Utils } = AnimationComposition;
const { imageStringIterator } = Utils;

const PATH = '/FAKE/PATH/';
const color = '#c0ffee';
const avatarImage = `${PATH}/myAvatar.png`;

const canvas = document.querySelector('canvas');

const border = new Layer({
  images: imageStringIterator(`${PATH}ripple-web/border/ripple_border_XX_xhdpi.png`, 0, 29)
});

const colorLayer = new ColorLayer({ color });
const fill = new Layer({
  images: imageStringIterator(`${PATH}ripple-web/fill/ripple_fill_XX_xhdpi.png`, 0, 29)
});
const participantLayer = new MaskLayer({ name: 'participantLayer', mask: fill, layers: [ colorLayer ]});

const avatarMask = new Layer({ images: imageStringIterator(`${PATH}ripple-web/mask/ripple_mask_XX_xhdpi.png`, 0, 29) });
const avatarImageLayer = new Layer({ images: [ avatarImage ], sizeRef: avatarMask });
const avatarLayer = new MaskLayer({ mask: avatarMask, layers: [ avatarImageLayer ]});

new Animation({
  ticksPerFrame: 1,
  canvas,
  layers: [ border, participantLayer, avatarLayer ],
});