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

@pyreon/kinetic

v0.18.0

Published

CSS-transition-based animation components for Pyreon

Readme

@pyreon/kinetic

CSS-first animation library for Pyreon. Enter/exit transitions, staggered animations, height collapse, and list reconciliation — all in ~3KB gzipped.

Why Kinetic?

Most animation libraries run their own JavaScript animation loop on the main thread. Kinetic takes a different approach: it delegates all interpolation to the browser's CSS transition engine (compositor thread for transform/opacity), and only handles orchestration — mount/unmount lifecycle, stagger timing, height measurement, and list diffing.

The result: GPU-composited 60/120 FPS animations with a 3.2KB footprint.

How It Compares

| Library | Gzipped | Engine | Enter/Exit | Stagger | List Recon. | Collapse | Reduced Motion | | ---------------------- | ---------- | ------------------- | ---------- | ------- | ----------- | -------- | -------------- | | @pyreon/kinetic | 3.2 KB | CSS transitions | Yes | Yes | Yes | Yes | Yes | | Motion (framer-motion) | ~34 KB | JS (rAF + WAAPI) | Yes | Yes | Yes | Quirky | Yes | | @react-spring/web | ~16-24 KB | JS (spring physics) | Yes | Partial | Yes | Manual | Yes | | react-transition-group | ~5 KB | CSS classes | Yes | No | Yes | No | No | | AutoAnimate | ~2.5 KB | JS (FLIP) | Yes | No | Yes | No | Yes |

Key advantages:

  • 10x smaller than Motion for CSS-transition use cases
  • CSS-first: transform/opacity run on GPU compositor thread, not main thread
  • Only library combining CSS transitions + stagger + collapse + list reconciliation
  • 122 presets available via @pyreon/kinetic-presets

Install

bun add @pyreon/kinetic

Quick Start

import { kinetic, fade, slideUp } from '@pyreon/kinetic'
import { signal } from '@pyreon/reactivity'

// Create animated components at module level
const FadeDiv = kinetic('div').preset(fade)
const SlideSection = kinetic('section').preset(slideUp)

// Use with signals for reactive show/hide
const show = signal(true)

FadeDiv({ show: show(), children: 'Hello, world!' })

API

kinetic(tag)

Creates an animated component. tag can be any HTML element string or Pyreon component.

kinetic('div') // HTML element
kinetic('section') // Any HTML tag
kinetic(MyComponent) // Pyreon component

Returns a renderable Pyreon component with chain methods attached. Default mode: transition.

Chain Methods

All methods return a new component (immutable). The tag generic flows through, preserving HTML attribute types.

// Style-based animation config
.enter(styles)            // CSSProperties applied at enter start
.enterTo(styles)          // CSSProperties applied after first frame
.enterTransition(value)   // CSS transition string for enter
.leave(styles)            // CSSProperties applied at leave start
.leaveTo(styles)          // CSSProperties applied after first frame
.leaveTransition(value)   // CSS transition string for leave

// Class-based animation config
.enterClass({ active?, from?, to? })
.leaveClass({ active?, from?, to? })

// Apply a preset (spreads style + class props)
.preset(preset)

// Behavior config
.config(opts)             // appear, unmount, timeout (+ mode-specific)
.on(callbacks)            // onEnter, onAfterEnter, onLeave, onAfterLeave

// Mode switches
.collapse(opts?)          // Height animation mode
.stagger(opts?)           // Staggered children mode
.group()                  // Key-based list reconciliation mode

Four Modes

Transition (default)

Single element enter/leave with CSS transitions.

const FadeDiv = kinetic('div').preset(fade)

FadeDiv({ show: isOpen, children: 'Content' })

Collapse

Height animation with overflow: hidden. Measures scrollHeight automatically.

const Accordion = kinetic('div').collapse()
const FancyAccordion = kinetic('section').collapse({
  transition: 'height 400ms cubic-bezier(0.4, 0, 0.2, 1)',
})

Accordion({ show: isExpanded, children: 'Expandable content' })

Stagger

Staggered entrance/exit for child elements.

const StaggerList = kinetic('ul').preset(slideUp).stagger({ interval: 75 })

StaggerList({
  show: isVisible,
  children: [
    h('li', { key: '1' }, 'Item 1'),
    h('li', { key: '2' }, 'Item 2'),
    h('li', { key: '3' }, 'Item 3'),
  ],
})

Group

Key-based enter/exit — adding a child triggers enter animation, removing triggers leave + unmount. No show prop.

const AnimatedList = kinetic('ul').preset(fade).group()

AnimatedList({ children: items.map((item) => h('li', { key: item.id }, item.text)) })

Inline Configuration

Build animations without presets:

const SlidePanel = kinetic('aside')
  .enter({ opacity: 0, transform: 'translateX(-100%)' })
  .enterTo({ opacity: 1, transform: 'translateX(0)' })
  .enterTransition('all 300ms ease-out')
  .leave({ opacity: 1, transform: 'translateX(0)' })
  .leaveTo({ opacity: 0, transform: 'translateX(-100%)' })
  .leaveTransition('all 200ms ease-in')

Class-Based Transitions

Works with Tailwind CSS, CSS modules, or any class-based approach:

const TailwindFade = kinetic('div')
  .enterClass({ active: 'transition-opacity duration-300', from: 'opacity-0', to: 'opacity-100' })
  .leaveClass({ active: 'transition-opacity duration-200', from: 'opacity-100', to: 'opacity-0' })

Lifecycle Callbacks

FadeDiv({
  show: isOpen,
  onEnter: () => console.log('entering'),
  onAfterEnter: () => console.log('entered'),
  onLeave: () => console.log('leaving'),
  onAfterLeave: () => console.log('left'),
  children: 'Content',
})

Accessibility

Kinetic automatically detects prefers-reduced-motion: reduce. When enabled, animations are skipped instantly — callbacks still fire, but no visual animation occurs. No configuration needed.

Built-in Presets

Six presets are included in the core package:

import { fade, scaleIn, slideUp, slideDown, slideLeft, slideRight } from '@pyreon/kinetic'

For 122 presets, factories, and composition utilities, install @pyreon/kinetic-presets.

Composition with Rocketstyle

Kinetic and rocketstyle compose naturally:

import rocketstyle from '@pyreon/rocketstyle'

const Button = rocketstyle()({ component: 'button', name: 'Button' }).theme({
  primaryColor: 'blue',
})

const AnimatedButton = kinetic(Button).preset(fade)

// Has both rocketstyle props AND kinetic props
AnimatedButton({ show: isVisible, primary: true, size: 'large', children: 'Click me' })

Peer Dependencies

| Package | Version | | ------------------ | -------- | | @pyreon/core | >= 0.0.1 | | @pyreon/reactivity | >= 0.0.1 |

License

MIT