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

@motly/gsap

v0.1.3

Published

GSAP plugin: motly primitives as registered GSAP effects.

Readme

@motly/gsap

motly's procedural bursts as GSAP effects. gsap.effects.burst(button, { spec }) returns an ordinary tween, so a burst sits in a timeline, scrubs, reverses, repeats, is driven by ScrollTrigger and is cleaned up by gsap.context() and useGSAP. You describe the burst as a JSON Spec; motly generates the shapes and draws them.

The docs have every Spec field with a live example, and real-world examples to copy.

Install

With a bundler:

npm install @motly/gsap gsap
import { gsap } from 'gsap';
import { Motly } from '@motly/gsap';

gsap.registerPlugin(Motly);

Importing registers nothing; registerPlugin does.

With script tags, as on CodePen, load GSAP first. The script build then registers itself and makes Motly a global:

<script src="https://cdn.jsdelivr.net/npm/gsap@3/dist/gsap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@motly/[email protected]"></script>

Loaded before GSAP, it only defines Motly; call gsap.registerPlugin(Motly) yourself.

A first burst

import { gsap } from 'gsap';
import { Motly, rand } from '@motly/gsap';

gsap.registerPlugin(Motly);

const spec = {
  kind: 'burst',
  count: 12,
  radius: [0, 90],
  restAt: 0.4,
  children: { kind: 'circle', radius: [rand(4, 9), 0], fill: 'deeppink', duration: 0.8 },
};

const button = document.querySelector('button');
button.addEventListener('click', () => gsap.effects.burst(button, { spec }));

// Or in a timeline, placed with GSAP's position parameter. This one plays as the page loads:
gsap
  .timeline()
  .to(button, { scale: 0.9, yoyo: true, repeat: 1, duration: 0.1 })
  .burst(button, { spec }, '<');

spec is the whole burst: pass a Spec exported from an editor as it is. rand, each and the named curves are exported from this package; with script tags they are Motly.rand and so on. gsap.effects.shape() and tl.shape() draw a single Element the same way, from a Spec such as { kind: 'star', points: 5, radius: [0, 40] }.

The vocabulary rule

Beside spec, vars takes four keys of motly's, seed, container, renderer and reducedMotion, described below. Every other key means what it means in any GSAP tween, and motly's own words for the burst live only in spec:

  • delay holds back the whole tween; spec.delay is a wait at the start of the burst, inside the tween's length, as it is when the Spec plays without GSAP.
  • ease warps the burst's time; spec.easing gives each property its curve. ease is 'none' unless you give one, so a Spec runs at its own pace rather than under GSAP's default ease.
  • duration stretches or squeezes the whole burst; without it, the tween lasts as long as the Spec.
  • repeat, yoyo, paused, onStart, onUpdate, onComplete and scrollTrigger work as on any tween.

keyframes, startAt, runBackwards and stagger do not apply to a burst: the types reject them, and given anyway they are ignored with a warning. Stagger bursts with a loop or with timeline positions.

Where a burst comes from

  • An element, a selector or a list: one burst from each element's centre, each with its own Seed. The centre is read when the tween starts from 0 moving forward, not per frame, so a burst stays where it began if the page scrolls.
  • { x, y } in viewport pixels, as clientX and clientY give:
addEventListener('pointerdown', (event) => {
  gsap.effects.burst({ x: event.clientX, y: event.clientY }, { spec });
});
  • seed: 7 draws the same bursts on every page load: the ith element or point draws from seed + i. Without it, each call draws a random Seed, which a repeat, a restart and a scrub all keep.
  • A selector or list that matches nothing warns and gives a tween as long as the Spec that draws nothing, so a timeline keeps its timing.

Where a burst is painted

By default, in an overlay the tween owns: fixed over the viewport, above the page, catching no clicks, and in the document only while the tween is between its ends.

container: '.card', an element or a selector, paints it inside that element instead, so it scrolls with it and is clipped by it: what a burst scrubbed by ScrollTrigger in a pinned section needs. The container must have a size; a static one is made relative while a burst is drawn in it, and set back once the last one is cleared. A selector that matches nothing warns and gives a tween as long as the Spec that draws nothing.

renderer is 'auto' by default, which keeps bursts under 50 Elements in SVG and paints larger ones on a canvas. 'svg' or 'canvas' forces one.

Cleanup

A burst never outlives its tween where GSAP reaches the tween:

  • At either end, nothing is left drawn.
  • tween.kill(), tween.revert(), tl.revert() and gsap.context().revert(), and so useGSAP when a component unmounts, clear a burst mid-flight.
  • tl.kill() on a timeline does not. GSAP does not tell a killed timeline's children, so a burst mid-flight stays drawn. Revert the timeline or its context instead, or kill the burst's own tween.
  • Give onInterrupt in vars. motly chains its own clear-up before yours there; replacing it later with tween.eventCallback('onInterrupt', fn) drops the clear-up, so a later kill() leaves the burst drawn. For the same reason, reading it back, through eventCallback() or tween.vars, gives motly's wrapper rather than your function.

Reduced motion

A viewer who prefers reduced motion sees the Spec's still Resting frame, at spec.restAt, for the tween's full length, so everything after it in a timeline keeps its timing. The preference is read each time the tween starts from 0, so changing it needs no reload; a repeat keeps the one it started with. reducedMotion: 'always' or 'never' in vars forces either, for a demo or a test.

This covers the bursts only. Your own tweens around them keep moving; wrap those in gsap.matchMedia() with (prefers-reduced-motion: reduce).

Types

Importing the package types gsap.effects.burst, gsap.effects.shape, tl.burst and tl.shape: spec must be a Spec of the right kind. BurstVars, ShapeVars, MotlyVars and RendererName are exported for vars built apart from the call.