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 🙏

© 2026 – Pkg Stats / Ryan Hefner

rpi-animations

v1.1.6

Published

rpi-animations

Readme

rpi-animations

Tiny, event-driven building blocks for running LED/pixel animations in Node.js. The documentation is generated by ChatGPT given the complete code.

The package exposes two classes:

  • Animation — a base class that provides a render loop (frequency-capped), lifecycle handling (start/stop), duration/iteration limits, cancellation, and event hooks.
  • AnimationQueue — a simple FIFO runner that executes animations one after another and emits idle when the queue is empty.

Under the hood, Animation uses the sleep module and Node’s event system (events).


Install

npm install rpi-animations

Quick start

1) Create your own animation

Extend Animation and implement render(). You can use renderFrequency, duration, or iterations to control the loop.

const { Animation } = require('rpi-animations');

class Blink extends Animation {
  constructor(opts = {}) {
    super({ name: 'Blink', renderFrequency: 100, ...opts }); // 10 FPS
    this.on = false;
  }

  render() {
    // Called by the loop at most once per renderFrequency
    this.on = !this.on;
    // ...write pixel buffer or call your renderer here...
    // e.g. ws281x.render(this.on ? redBuffer : blackBuffer)
    this.debug('Blink render', this.on);
  }
}

// Run for ~2 seconds then stop
const anim = new Blink({ duration: 2000, debug: true });
anim.run().then(() => console.log('Blink finished'));

2) Queue multiple animations

const { Animation, Queue } = require('rpi-animations');

class Fade extends Animation {
  constructor(opts = {}) {
    super({ name: 'Fade', renderFrequency: 33, iterations: 60, ...opts }); // ~30 FPS, 60 frames
    this.i = 0;
  }
  render() {
    // compute brightness from this.i (0..59)
    const t = this.i / (this.iterations - 1);
    // ...render with t...
    this.i++;
  }
}

const q = new Queue({ debug: true });

q.on('idle', () => {
  console.log('Queue is idle');
});

// Enqueue a few animations
q.enqueue(new Fade({ name: 'Intro' }));
q.enqueue(new Fade({ name: 'Outro' }));

Concepts

Animation loop

Animation maintains an internal loop that:

  • Calls your render() no more often than renderFrequency (ms).
  • Stops automatically when any of these conditions are met:
    • cancel() was called,
    • duration elapsed (ms),
    • iterations reached (number of frames rendered — increased after each successful render()).

Timing

  • renderFrequency (number, ms): maximum render rate. If omitted, render() can be called as fast as the loop runs.
  • duration (number, ms): total time to keep looping before resolving.
  • iterations (number): how many times to render before resolving.

You can pass timing both in the constructor and to run({ duration, priority }). If supplied to run, they temporarily override the instance values.

Cancellation

Call cancel() on an animation to request a stop. The loop observes the flag and resolves the pending run() promise. Several events fire (see below).

Priority

Animation instances have a priority property (defaults to 'normal'). The included Queue currently executes animations in FIFO order and does not re-order by priority. The field is available for consumers that want to build a priority-aware scheduler.


API

Class: Animation (extends EventEmitter)

Constructor

new Animation({
  name = 'Noname',
  renderFrequency,   // number (ms), optional
  iterations,        // number, optional
  duration,          // number (ms), optional
  priority = 'normal',
  debug              // boolean | function, optional
})
  • debug:
    • If a function, it will be called for internal logs.
    • If truthy (e.g. true), logs go to console.log.
    • Otherwise, logging is disabled (no-op).

Methods

  • render()void
    Implement in subclasses. Called by the loop at most once per renderFrequency.
  • run(options?)Promise<void>
    Starts the animation (start()), runs the loop, then calls stop(). Optionally override { duration, priority }.
  • start() / stop()Promise<void>
    Lifecycle hooks that emit events (started, stopped). Default implementations just resolve and emit.
  • cancel()void
    Requests cancellation and emits (cancelling, canceling) immediately. The loop then emits (cancelled, canceled) when observed.
  • sleep(ms)void
    Synchronous sleep using Sleep.msleep(ms). You normally don’t need this; the render cadence is handled internally.
  • next(loop)void
    Schedules the next iteration via setImmediate(loop). Override if you want a different scheduling strategy.
  • loop()Promise<void>
    Internal loop that throttles calls to render() and resolves on cancel/duration/iterations.

Properties

  • name string
  • priority string
  • duration? number
  • iterations? number
  • renderFrequency? number
  • iteration number — internal counter (increments after each render when iterations is set)
  • cancelled boolean — internal flag
  • renderTime? Date — last render timestamp
  • debug function — logger (no-op by default)

Events

Emitted by an Animation instance:

  • started — after start() resolves.
  • stopped — after stop() resolves.
  • cancelling / canceling — when cancel() is called.
  • cancelled / canceled — when the loop notices cancelled === true and resolves.

Both British and American spellings are emitted for convenience.


Class: Queue (extends EventEmitter)

A minimal FIFO scheduler that runs animations sequentially.

Constructor

new Queue({ debug })  // debug works like in Animation (fn | truthy | falsy)

Methods

  • enqueue(animation)void
    Adds an Animation instance to the queue. If the queue was idle, it starts processing.
  • dequeue()Promise<void>
    Internal: runs the head animation via animation.run() and recurses until the queue is empty.
  • run()Promise<void>
    Convenience alias that begins processing (equivalent to calling dequeue()).

Events

  • idle — emitted when the queue becomes empty after processing all animations.

Integration tips

  • Combine rpi-animations with your pixel rendering layer (e.g. rpi-ws281x or your own driver). Keep drawing inside render(); store any shared state on the instance.
  • Prefer iterations for frame-counted animations (fade across N frames), and duration for time-based ones (run for T milliseconds).
  • If you need a different scheduling (e.g. setTimeout at a fixed step), override next(loop).

Example: Blink + Fade with a Queue

const { Animation, Queue } = require('rpi-animations');

class Blink extends Animation {
  constructor(opts = {}) {
    super({ name: 'Blink', renderFrequency: 100, iterations: 20, ...opts });
    this.on = false;
  }
  render() { this.on = !this.on; }
}

class Fade extends Animation {
  constructor(opts = {}) {
    super({ name: 'Fade', renderFrequency: 33, iterations: 60, ...opts });
    this.i = 0;
  }
  render() { this.i++; }
}

const q = new Queue({ debug: (...a) => console.log('[queue]', ...a) });
q.on('idle', () => console.log('All animations done'));

q.enqueue(new Blink());
q.enqueue(new Fade());

License

ISC