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.0.2

Published

Animation definition and implementation

Readme

@qyu/anim-core

Animation definition and implementation

Definitions

// animation does not hold state or progress, instead it's exported as <Point>
// animation also does not specify initial point
type Anim<Point> = {
    // is animation finished in the point
    finished(point: Point): boolean
    // emit animation in point
    emit(point: Point): void
    // emit difference between points
    emitdiff(point_from: Point, point_to: Point): void
    // progress point by specified amount of abstract time units
    step(point: Point, timepassed: number): void
}

Implemented Animations

Linear Animation

// linear animation
// initial position is passed in initial point
const line = anim_new_line({
    target: 50,
    // positive number, speed of displacement decline
    velocity: 0.1,
    // will be called on .emit
    effect(state) {
        console.log("linear animation", { state })
    }
})

const line_point = {
    state: 0
} as const

Spring Animation

// harmonic damped oscillator
// initial position and drive is passed in initial point
const spring = anim_new_spring({
    target: 100,
    natfreq: 0.01,
    dampratio: 0.6,

    // end conditions
    // precision is optional, theese are default values
    // end if Math.abs(velocity) <= precision.velocity and displacement < precision.displacement
    precision: {
        velocity: 0.001,
        displacement: 0.01
    },

    // will be called on .emit
    effect(state, velocity) {
        console.log("spring animation", { state, velocity })
    }
})

const spring_point = {
    state: -50,
    velocity: 10
} as const

Playback Animation Modifier

// will multiply timepassed by 2 on .step function
const fastspring = anim_new_playback({
    src: spring,
    multiplier: 2
})

Sequence Animation

// spring will be emitted after line
// initial .emit will also activate effect for spring, it won't call in futher in .emitdiff
// overshoot is always ignored, so sequence.step(initpoint, 1000000) will only pass line animation
const sequence = anim_new_sequence([line, spring] as const)

const sequence_point = {
    // all animations of index <= mergeptr will be merged into one
    // will increase as animation progressess
    // imagine you have sequence of 3 linear animations with targets of [100, 50, 20]
    // as animation progresses towards second child,
    // conditions change and you now want to pass the same state to different path [150, 20, 40]
    // because of merge - it will emit first and second animation simultaniously
    // so both first and second lines will be moving towards corrected targets
    mergeptr: 0,
    children: [line_point, spring_point] as const
} as const

Strict Sequence Animation

// same as sequence, just does not merge animations on update
const sequence_strict = anim_new_sequence_strict([line, spring] as const)

const sequence_strict_point = {
    children: [line_point, spring_point] as const
} as const

Merge Animation

// animations will be moving simultaniously
const merge = anim_new_merge([line, spring] as const)
const mergemap = anim_new_mergemap({ line, spring } as const)

const merge_point = [line_point, spring_point] as const
const mergemap_point = { line: line_point, spring: spring_point } as const

Loop Animation

// will go to the end, then restart
const loop = anim_new_loop({
    src: line,
    // point that loop will be using to restart
    initpoint: line_point
})

const loop_point = {
    // when animation ends, will restart and decrease if remaining > 0
    // will do first iteration regardless
    remaining: 1,
    child: line_point
} as const

Pipe Animation Modifier

// make line compatible with spring point
const line_piped = anim_new_pipe<AnimLine_Point, AnimSpring_Point>({
    src: line,

    pipei: point_src => ({
        state: point_src.state
    }),

    pipeo: point_input => ({
        state: point_input.state,
        velocity: 0.1
    })
})

Chain Animation

// unlike sequence, children of chain share the same point, so they need to be compatible
// will execute line animation, then will give final point of it to spring animation
// if you try to update the path such as you would do with sequence - it won't reemit processed animations
const chain = anim_new_chain([line_piped, spring] as const)

const chain_point = {
    // index of active animation
    ptr: 0,
    // shared point
    child: spring_point
} as const

ChainMap Animation

// basically chain with threads
// animations that share thread share point
// will emit spring, then line, then line_piped using spring's point
// points should be compatible inside of the single thread
// if you're emitting line animation (index 1), and want to pass point to a different path with updated spring
// it will merge spring and line animation into one
const chainmap = anim_new_chainmap([
    { a: spring } as const,
    { b: line } as const,
    { a: line_piped } as const
] as const)

const chainmap_point = {
    // index of active element
    ptr: 0,

    children: {
        b: line_point,
        a: spring_point,
    } as const
} as const

Implemented Animation Emitters

Interval Emitter

// definition
type EmitterInterval<Point> = {
    // get current point
    point(): Point
    // is emitter still active
    active(): boolean
    // interrupt
    hardstop(): void
    // update according to current time and interrupt
    softstop(): void
}

// Frame Scheduler is api for scheduling frames
const fscheduler_node = fscheduler_new_frame(Date, setTimeout, clearTimeout)
const fscheduler_browser = fscheduler_new_frame(performance, requestAnimationFrame, cancelAnimationFrame)

// emits animation immediately, then emits difference each animation frame until finish
const controls_frame = emitter_new_interval({
    anim: line,
    point: line_point,
    scheduler: fscheduler_node,

    // optional, wraps anim emittment
    batch: cb => cb()
})

Manual Emitter

// controls for manual emitter
type EmitterManual<Point> = {
    // get current point
    point(): Point
    // is animation finished
    finished(): boolean
    // make a step
    step(timepassed: number): void
}

// emits animation immediately, then emits difference each time .step is called
const controls_manual = emitter_new_manual({
    anim: line,
    point: line_point,

    // optional, wraps anim emittment
    batch: cb => cb()
})