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

@qyu/anim-core

v1.2.0

Published

Animation definition and implementation

Readme

@qyu/anim-core

Animation definition and implementation

Concept

  • Animation is one-way transition from initial Point to Target through Path
  • Anim interface represents Path and Target of the definition
  • Point is externalised and represents absolute state of the animation
  • Anim has method .emit to emit from point and .step that returns new Point after some time passed
import * as ac from "@qyu/anim-core"

const line = ac.anim_new_line({
    target: 50,
    velocity: 0.1,

    // will run when animation changes state
    effect(state) {
        console.log("linear animation", { state })
    }
})

let now_line_point = {
    state: 0
} as const

line.emit(now_line_point)

{
    const next_line_point = line.step(now_line_point, 100)

    line.emitdiff(now_line_point, next_line_point)

    now_line_point = next_line_point
}

Animation Flow

  • Create Anim and initial Point compatible with Anim
  • Call .emit at the beginning
  • Every tick do .step(now_point, timepassed) and emit new point with .emitdiff(last_point, now_point)
  • Check .finished(now_point) and if Anim is not finished yet - repeat
  • If config changes - update Anim and continue using same Point. That process is called adapting the animation
  • emitter_new_interval does most of the work for you
import * as ac from "@qyu/anim-core"

let point = { state: 0 }

const start = function (target: number, velocity: number): VoidFunction {
    const line = ac.anim_new_line({
        target,
        velocity,

        effect(state) {
            console.log("linear animation", { state })
        }
    })

    // will run animation automatically
    const emitter = ac.emitter_new_interval({
        point,
        anim: line,
    })

    // cleanup
    return () => {
        emitter.softstop()

        point = emitter.point()
    }
}

// start the animation
const cleanup = start(150, 0.1)

// will restart it after 1 second
setTimeout(() => {
    cleanup()

    // change speed and target of the animation
    start(-50, 0.5)
}, 1000)

Implemented Animations

  • Library implements multiple kinds of animations to create complex compositions
  • anim_new_line simple linear animation (A -> A1)
  • anim_new_spring spring based animation (A -> A1)
  • anim_new_merge merge the animations (A | B -> A1 | B1)
  • anim_new_mergemap merge the animations, but different format of the Point (a: A | b: B -> a: A1 | b: B1)
  • anim_new_loop reapeating animation ((A -> A1) * n)
  • anim_new_sequence emit animations in sequence, on adapt - merge already finished steps (A -> A1 & B -> B1)
  • anim_new_sequence_strict emit animations in sequence, emits only one-at-a-time (no merge on adapt) (A -> A1 & B -> B1)
  • anim_new_chain emit sequence of animations with shared Point (later step starts where earlier ends) (A -> A1 -> A2)
  • anim_new_chainmap same as normal chain, but allows having multiple threads with optional gaps (a: A | b: B -> a: A1 -> a: A2 | b: B1)
  • anim_new_playback speed up or slow down the animation
  • anim_new_pipe convert Point of animation to be compatible with others (eg. for running chain of incompatible animations)
import * as ac from "@qyu/anim-core"

let point = {
    ptr: 0,
    child: {
        state: 0,
        velocity: 0,
    }
} satisfies ac.AnimChain_Point<ac.AnimSpring_Point>

const start = function(base: number): VoidFunction {
    let i = 0

    // state will reach the base in the first animation
    // then it will go to -base in the second animation
    const anim = ac.anim_new_chain([
        ac.anim_new_spring({
            dampratio: 0.9,
            natfreq: 5e-3,
            target: base,

            precision: {
                velocity: 0.1,
                displacement: 1,
            },

            effect: (state, velocity) => {
                // only print every 10th update
                if (++i % 10 === 0) {
                    console.log("first animation", state, velocity)
                }
            }
        }),

        ac.anim_new_spring({
            target: base,
            natfreq: 1e-2,
            dampratio: 0.1,

            effect: (state, velocity) => {
                // only print every 10th update
                if (++i % 10 === 0) {
                    console.log("second animation", state, velocity)
                }
            }
        })
    ])

    console.log("Init Animation")

    const emitter = ac.emitter_new_interval({
        point,
        anim,
    })

    return () => {
        emitter.softstop()

        point = emitter.point()
    }
}

const cleanup = start(1000)

setTimeout(() => {
    cleanup()

    // update to new targets
    // spring will maintain it's speed at this point
    start(2000)
}, 5000)

Emitters

  • Emitter is something that runs your animation
  • emitter_new_manual will make you press .step manually, does not provide much functionality
  • emitter_new_interval will run you animation every frame according to FrameScheduler
    • FrameScheduler could be provided at .scheduler, by default it is based on requestAnimationFrame in browser fallbacks to setTimeout
    • batch function allows to add a batching function that will be used for every tick
    • hooks allow to add hooks for emitter