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

pure-animation

v0.0.9

Published

Functional animation library

Downloads

6

Readme

pure-animation

Animation Library which understands animation as a function of time. It has many helpers to work with such animations.

Example of usage

Codesandbox with block animation that can be paused and reversed

Contents

Glossary

Animation - it's a function from time to some value.

type Animation<AnimatedValue> = (time: number) => AnimatedValue;

Animated Value - value return by function

Time - any numeric value. You can use for it different possible numbers:

  • index of element in array
  • ammount of milliseconds after start of the animation
  • current frame index

API

always

function always<T>(constant: T): Animation<T>

Given some constant returns animation that always returns this constant.

Example:

const always10 = always(10);
always10(0); // 10
always10(1); // 10
always10(2); // 10

bounded

bounded<R>(minTime: number, maxTime: number, animation: Animation<R>): Animation<R>

Creates new animation that:

  • will return animation(minTime) if time <= minTime.
  • will return animation(maxTime) if time >= maxTime
  • will return animation(time) otherwise

Example:

const opacityAnimation = (time) => time / 100;
const appearAnimation = bounded(0, 100, opacityAnimation);

appearAnimation(-10); // 0
appearAnimation(0); // 0
appearAnimation(5); // 0.05
appearAnimation(100); // 1
appearAnimation(120); // 120

chain

function chain<T>([t0, animation0], [t1, animation1], ...): Animation<T>

You can use this function to create chains of the different animations.

// frameIndex should be from 0 to 100
const opacityFrom0To1 = (frameIndex: number) => frameIndex / 100;
const opacityFrom1To0 = (frameIndex: number) => 1 - frameIndex / 100;

const notificationAnimation = chain(
  [0, opacityFrom0To1], // from frame 0 to 100 (exclusive) it will appear
  [100, () => 1], // after frame 100 to 200 (exclusive) it will return 1
  [200, opacityFrom1To0] // after frame 200 it will fade out.
);

notificationAnimation(-10); // 0, since -10 < 0 chained function will return opacityFrom0To1(0).
notificationAnimation(5); // 0.05, since opacityFrom0To1(5) => 0.05
notificationAnimation(120); // 1, since () => 1 always returns 1
notificationAnimation(210); // 0.9, ince opacityFrom1To0(210 - 200) => 0.9

RESTRICTION values passed to chain function should be in order of time increasing. Next function will NOT work correctly:

const notificationAnimation = chain(
  [200, opacityFrom1To0],
  [0, opacityFrom0To1],
  [100, () => 1]
);

cos

function cos(startTime: number, endTime: number, minValue: number, maxValue: number): Animation<number>;

This function returns animation simmilar to ease-in-out animation that changes from minValue to maxValue, when time changes from startTime to maxTime.

Example:

const opacityAnimation = cos(
  0, // animation start from time 0
  60, // animation finishes when time is 60
  0, // animation will equal to 0 when time <= startTime
  1 // animation will equal to 1 when time >= endTime.
); // animation will return values from 0 to 1 when startTime < time < endTime

opacityAnimation(-1); // 0
opacityAnimation(0); // 0
opacityAnimation(1); // 0.000685
opacityAnimation(30); // 0.5
opacityAnimation(55); // 0.9829
opacityAnimation(60); // 1
opacityAnimation(61); // 1

fromArray

function fromArray<T>(array: T[]): Animation<T>

You can use this function to create animation of array items. Index of array is treated as a time.

const daysAnimation = fromArray([
  "monday",
  "tuesday",
  "wednesday",
  "thursday",
  "friday",
  "saturday",
  "sunday",
]);

daysAnimation(-1); // 'monday'
daysAnimation(0); // 'monday'
daysAnimation(0.5); // 'monday'
daysAnimation(1); // 'tuesday'
daysAnimation(6); // 'sunday'
daysAnimation(6.5); // 'sunday'
daysAnimation(25); // 'sunday'

identity

identity: Animation<number>

This is animation that returns time.

Same as:

const identity = (time) => time;

You can use it as parameter to create other functions that will be more useful.

const boundedTimeAnimation = bounded(0, 20, identity);

boundedTimeAnimation(-10); // 0
boundedTimeAnimation(0); // 0
boundedTimeAnimation(5); // 5
boundedTimeAnimation(20); // 20
boundedTimeAnimation(25); // 25

linear

function linear(x0: number, x1: number, y0: number, y1: number, x: number): number;

Returns y coordinate of the point on the line that passes (x0, y0) and (x1, y1) and has x coordinate equal to x.

const celsiusToFahrenheit = (celsius) => linear(0, 10, 32, 50, ceilsius);
celsiusToFahrenheit(0); // 32
celsiusToFahrenheit(10); // 50
celsiusToFahrenheit(36.6); // 97.88

map

map<T, R>(transform: (value: T) => R, animation: Animation<T>): Animation<R>

Creates animation which will return transform(animation(time)) for each time.

Example:

const offsetAnimation = (time: number) => time * 10 + 10;
const offsetPixelAnimation = map((offset) => `${offset}px`, offsetAnimation);

offsetPixelAnimation(100); // '1010px'

mapTime

mapTime<T>(transformTime: (newTime: number) => number, animation: Animation<T>): Animation<T>

Transforms newTime parameter before passing to the animation.

You can use it in order to create slow-mo effects. Example:

const opacityAnimation = (time) => time / 100 + 0.1;
const slowMoOpacityAnimation = mapTime(
  (fastTime) => fastTime / 100,
  opacityAnimation
);

mergeMap

function mergeMap<A, B, ...Rest>(
  merge: (a: A, b: B, ...restAnimatedValues) => R
  aAnimation: Animation<A>,
  bAnimation: Animation<B>,
  ...restAnimations,
): Animation<R>

You can create animation by combining of values of other animations

Example:

const temperatureAnimation = (year) => {
  switch (year) {
    case 2021:
      return 60;
    case 2025:
      return 40;
    case 2030:
      return 30;
    default:
      return 25;
  }
};
const populationAnimation = (year) => {
  return 7_500_000_000 + year * 100_000_000;
};

const temperatureAndPopulationAnimation = mergeMap(
  (temperature, population) => ({ temperature, population }),
  temperatureAnimation,
  populationAnimation
);

temperatureAndPopulationAnimation(2021); // { temperature: 60, population: 7500000000}
temperatureAndPopulationAnimation(2022); // { temperature: 25, population: 7600000000}

switchMap

switchMap<T, R>(
  createAnimation: (value: T) => Animation<R>,
  animation: Animation<T>
): Animation<R>

You can use animated value to create new animation and apply it. See example below:

const scrollAnimation = () => window.scrollY;
const scrolledBasedPosition = switchMap((scroll) => {
  if (scroll < 100) return () => 1000;
  if (scroll > 200) return () => -1000;
  return (time) => time / 100;
}, scrollAnimation);
scrolledBasedPosition(10); // will return 1000 if scroll < 100
scrolledBasedPosition(250); // will return -1000 if scroll > 200
scrolledBasedPosition(150); // will return 1.5