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

@wix/motion

v2.1.7

Published

Low-level, web-first, animation toolkit, with support for triggered, scroll-driven, pointer-tracking, WAAPI & CSS animations.

Downloads

1,448

Readme

@wix/motion

Low-level, web-native animation engine — WAAPI, CSS, scroll-driven, and pointer-tracking animations with a single dependency.

npm version bundle size license

Why Motion?

  • Native-first — Built directly on the Web Animations API and CSS Animations.
  • ViewTimeline — First-class scroll-driven animations via the ViewTimeline API, with a scrub fallback when the API is unavailable.
  • Pointer-drivenpointer-move animations map cursor (x, y) progress to effects, with optional transition smoothing.
  • Custom effects — Plug in programmatic render callbacks — no preset registration required.
  • Dual rendering — Choose CSS for declarative effects or WAAPI for fine-grained control, using the same options shape.
  • Performancefastdom batches DOM reads/writes; no requestAnimationFrame loop (except for customEffect callbacks).
  • Pluggable presetsregisterEffects() accepts any effect module. Use @wix/motion-presets or create your own.

Install

npm install @wix/motion

Quick Start

Time-based animation (WAAPI)

import { getWebAnimation } from '@wix/motion';

const animation = getWebAnimation(document.getElementById('hero'), {
  keyframeEffect: {
    name: 'fade-up',
    keyframes: [
      { opacity: 0, transform: 'translateY(20px)' },
      { opacity: 1, transform: 'translateY(0)' },
    ],
  },
  duration: 600,
  easing: 'ease-out',
});

animation.play();

Scroll-driven (ViewTimeline)

import { getWebAnimation } from '@wix/motion';

const scrollRoot = document.getElementById('scrollRoot')!;

const animation = getWebAnimation(
  document.getElementById('parallax'),
  {
    keyframeEffect: {
      name: 'parallax',
      keyframes: [{ transform: 'translateY(80px)' }, { transform: 'translateY(-80px)' }],
    },
    startOffset: { name: 'cover', offset: { value: 0, unit: 'percentage' } },
    endOffset: { name: 'cover', offset: { value: 100, unit: 'percentage' } },
  },
  { trigger: 'view-progress', element: scrollRoot },
);

Scroll-driven (polyfill / custom scrubbing)

import { getScrubScene } from '@wix/motion';

const scrollRoot = document.getElementById('scrollRoot')!;

const scenes = getScrubScene(
  document.getElementById('parallax'),
  {
    keyframeEffect: {
      name: 'parallax',
      keyframes: [{ transform: 'translateY(80px)' }, { transform: 'translateY(-80px)' }],
    },
    startOffset: { name: 'cover', offset: { value: 0, unit: 'percentage' } },
    endOffset: { name: 'cover', offset: { value: 100, unit: 'percentage' } },
  },
  { trigger: 'view-progress', element: scrollRoot },
);
// Drive each scene's `effect(scene, progress)` from your own scroll/IO listener
// when ViewTimeline is unavailable.

Quickstart examples use keyframeEffect (inline keyframes) so they run without registering presets.

Animation Modes

| Mode | Driver | API | | -------------- | ----------------------------- | ---------------------------------------------- | | Time-based | Duration + easing | getWebAnimation() / getCSSAnimation() | | Scroll-driven | ViewTimeline / external scrub | getScrubScene() with view-progress trigger | | Pointer-driven | Mouse / touch position | getScrubScene() with pointer-move trigger |

Core API

| Function | Purpose | | -------------------- | ----------------------------------------------------------- | | getWebAnimation() | Create WAAPI-backed animations (time- or scroll-linked) | | getCSSAnimation() | Generate CSS animation descriptors for stylesheet injection | | getScrubScene() | Build scroll-polyfill or pointer-driven scrub scenes | | prepareAnimation() | Pre-measure / mutate DOM via fastdom before animating | | getAnimation() | Auto-select CSS (if present) or WAAPI path | | getSequence() | Coordinate staggered groups with easing-based offsets | | registerEffects() | Register named effect modules into the global registry |

See docs/api/ for full signatures and options.

Custom Effects

Three ways to define what an animation does:

  1. Inline keyframes — pass keyframeEffect: { name, keyframes } directly. Zero registration.
  2. Custom callback — pass customEffect: (element, progress) => void for full programmatic control per frame.
  3. Named presets — pass namedEffect: { type: '…', …params } referencing effects you've registered via registerEffects() (use @wix/motion-presets or your own modules).

Sequences and Staggering

getSequence() plays multiple animations with staggered start times. Pass offset (ms between each start) and an optional offsetEasing to shape how the offsets are distributed across the sequence.

import { getSequence } from '@wix/motion';

const sequence = getSequence(
  { offset: 150, offsetEasing: 'quadIn' },
  Array.from(document.querySelectorAll('.card')).map((el) => ({
    target: el,
    options: {
      duration: 600,
      easing: 'ease-out',
      keyframeEffect: {
        name: 'fade-up',
        keyframes: [
          { opacity: 0, transform: 'translateY(20px)' },
          { opacity: 1, transform: 'translateY(0)' },
        ],
      },
    },
  })),
);

sequence.play();

See docs/api/get-sequence.md for the full stagger model.

ViewTimeline and Polyfills

Motion is built around progressive enhancement:

  • Native path — when window.ViewTimeline is available, getWebAnimation() with a view-progress trigger returns a WAAPI animation linked to the scroll timeline.
  • Polyfill pathgetScrubScene() with view-progress returns ScrubScrollScene[] objects exposing start, end, viewSource, and effect(scene, progress). Drive these from your own IntersectionObserver/scroll listener. If using @wix/interact, its bundled scroll polyfill - fizban - handles this automatically.
  • Pointer smoothingScrubPointerScene accepts transitionDuration and transitionEasing so pointer-tracking effects don't snap to the cursor.

Performance Notes

  • prepareAnimation() runs fastdom measure/mutate phases before the animation starts, avoiding layout thrash.
  • The CSS rendering path (getCSSAnimation) offloads work to the compositor thread.
  • No requestAnimationFrame loop runs unless a customEffect callback is used.

Browser Support

Modern evergreen browsers with Web Animations API support (Chrome, Edge, Firefox, Safari). The ViewTimeline API is used where available; pair getScrubScene() with an external driver for older browsers.

Related Packages

Motion is the engine layer. The other packages in this repo build on top of it:

  • @wix/interact — declarative, config-driven interaction layer built on Motion.
  • @wix/motion-presets — ready-made effect catalog (entrance, ongoing, scroll, mouse, background-scroll).

Documentation

License

MIT