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

@lpdsgn/gsap-spa-manager

v0.1.0

Published

Framework-agnostic GSAP animation manager for SPAs with automatic cleanup, persistence, and ScrollTrigger support

Readme

GSAP SPA Manager

A framework-agnostic GSAP animation manager for Single Page Applications with automatic cleanup, persistence, and ScrollTrigger support.

Features

  • Framework Agnostic - Works with Swup, Barba.js, Astro View Transitions, or standalone
  • Automatic Cleanup - Animations are automatically killed on page transitions
  • Persistence Support - Mark animations as persistent to survive page transitions
  • ScrollTrigger Management - Centralized ScrollTrigger registration and cleanup
  • Context Management - Uses gsap.context() for proper cleanup of side-effects
  • Multiple Formats - ESM, CJS, and UMD builds available
  • Debug Mode - Comprehensive logging for development

Installation

npm install gsap-spa-manager gsap
# or
pnpm add gsap-spa-manager gsap
# or
yarn add gsap-spa-manager gsap

Quick Start

Standalone Usage (No SPA Router)

import { AM } from 'gsap-spa-manager';
import { gsap } from 'gsap';

// Initialize (optional, enables debug mode)
AM.init({ debug: true });

// Create a simple animation
AM.animate('hero', gsap.from('.hero', { opacity: 0, y: 50 }));

// Create a timeline
const tl = AM.timeline('intro');
tl.from('.title', { opacity: 0 })
  .from('.subtitle', { opacity: 0 }, '-=0.3');

// Use setup for complex animations with cleanup
AM.setup('mySection', (ctx) => {
  gsap.to('.box', { rotation: 360, repeat: -1 });

  // Register side-effects with automatic cleanup
  const onClick = () => console.log('clicked');
  document.addEventListener('click', onClick);
  ctx?.add(() => () => document.removeEventListener('click', onClick));
});

// Cleanup when done
AM.cleanup('hero');

With Swup

import Swup from 'swup';
import { AM, swupAdapter } from 'gsap-spa-manager';

const swup = new Swup();
AM.init({
  debug: true,
  adapter: swupAdapter(swup)
});

// Animations will now automatically cleanup on page transitions
AM.setup('pageAnimations', () => {
  gsap.from('.content', { opacity: 0 });
});

With Barba.js

import barba from '@barba/core';
import { AM, barbaAdapter } from 'gsap-spa-manager';

barba.init();
AM.init({
  debug: true,
  adapter: barbaAdapter(barba)
});

With Astro View Transitions

import { AM, astroAdapter } from 'gsap-spa-manager';

// Astro adapter uses native DOM events, no router instance needed
AM.init({
  debug: true,
  adapter: astroAdapter()
});

// Optional: add delay before ScrollTrigger refresh
AM.init({
  adapter: astroAdapter({ refreshDelay: 100 })
});

UMD (Browser Global)

<script src="https://cdn.jsdelivr.net/npm/gsap"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap/ScrollTrigger"></script>
<script src="https://unpkg.com/gsap-spa-manager/dist/index.umd.js"></script>
<script>
  const { AM } = AnimationManager;
  AM.init({ debug: true });
  AM.animate('box', gsap.to('.box', { x: 100 }));
</script>

API Reference

AM.init(options)

Initialize the Animation Manager.

AM.init({
  debug: boolean,      // Enable debug logging (default: false)
  adapter: SPAAdapter  // Optional SPA adapter for automatic cleanup
});

AM.destroy()

Disconnect the adapter and force cleanup all animations.

AM.destroy();

AM.animate(key, animation, options?)

Register a GSAP animation (Tween or Timeline).

// Single animation
AM.animate('myAnimation', gsap.to('.el', { x: 100 }));

// Multiple animations under one key
AM.animate('myAnimations', [
  gsap.to('.el1', { x: 100 }),
  gsap.to('.el2', { y: 50 })
]);

// With persistence (survives page transitions)
AM.animate('persistent', gsap.to('.el', { x: 100 }), { persist: true });

AM.timeline(key, vars?, options?)

Create and register a GSAP Timeline.

const tl = AM.timeline('myTimeline', { paused: true });
tl.to('.el', { x: 100 })
  .to('.el', { y: 50 });

// Persistent timeline
const persistentTl = AM.timeline('navbar', { paused: true }, { persist: true });

AM.setup(key, setupFn, options?)

Execute a setup function within a gsap.context() for proper cleanup.

AM.setup('mySetup', (ctx) => {
  // All GSAP animations here are tracked
  gsap.to('.el', { x: 100 });
  gsap.from('.other', { opacity: 0 });

  // Register non-GSAP side-effects for automatic cleanup
  ctx?.add(() => {
    const handler = () => {};
    window.addEventListener('resize', handler);
    return () => window.removeEventListener('resize', handler);
  });
}, {
  persist: true,           // Survive cleanup
  scope: document.body     // Scope for GSAP selectors
});

AM.scroll(key, vars, options?)

Create and register a ScrollTrigger.

AM.scroll('myTrigger', {
  trigger: '.section',
  start: 'top center',
  end: 'bottom center',
  scrub: true,
  animation: gsap.to('.el', { x: 100 })
});

// Persistent ScrollTrigger
AM.scroll('navTrigger', {
  trigger: '.header',
  start: 'top top',
  pin: true
}, { persist: true });

AM.register(key, animation, options?)

Register an externally created animation. Useful when you need more control over animation creation.

const myTween = gsap.to('.el', { x: 100, paused: true });
AM.register('myTween', myTween);

// Register multiple animations
AM.register('batch', [tween1, tween2, timeline1]);

AM.registerScrollTriggers(key, triggers, options?)

Register externally created ScrollTriggers.

const st1 = ScrollTrigger.create({ trigger: '.a', ... });
const st2 = ScrollTrigger.create({ trigger: '.b', ... });
AM.registerScrollTriggers('myTriggers', [st1, st2]);

AM.cleanup(key, force?)

Cleanup a specific animation by key.

AM.cleanup('myAnimation');
AM.cleanup('persistentAnim', true); // Force cleanup even if persistent

AM.cleanupAll()

Cleanup all non-persistent animations.

AM.cleanupAll();

AM.forceCleanupAll()

Cleanup everything, including persistent animations.

AM.forceCleanupAll();

AM.refresh(keys?)

Refresh ScrollTriggers.

AM.refresh();              // Refresh all
AM.refresh('myTrigger');   // Refresh specific
AM.refresh(['a', 'b']);    // Refresh multiple

AM.removePersistence(key)

Remove persistence from an animation, making it eligible for cleanup.

AM.removePersistence('myAnimation');

AM.getStatus()

Get current manager status.

const status = AM.getStatus();
// {
//   animations: 5,
//   scrollTriggers: 3,
//   persistent: 2,
//   keys: ['hero', 'intro', ...],
//   persistentKeys: ['navbar', 'footer']
// }

AM.isActive(key)

Check if an animation/setup is active.

if (AM.isActive('hero')) {
  // Animation exists
}

AM.isPersistent(key)

Check if an animation is marked as persistent.

if (AM.isPersistent('navbar')) {
  // Won't be cleaned up on page transitions
}

AM.debug()

Show detailed debug information in the console (only works if debug mode is enabled).

AM.debug();

Creating Custom Adapters

You can create adapters for any SPA router:

import type { SPAAdapter } from 'gsap-spa-manager';

const myAdapter: SPAAdapter = {
  name: 'MyRouter',

  onBeforeSwap(callback) {
    // Called before page content is replaced
    myRouter.on('before:navigate', callback);
  },

  onAfterSwap(callback) {
    // Called after page content is replaced
    myRouter.on('after:navigate', callback);
  },

  destroy() {
    // Optional: cleanup when AM.destroy() is called
    myRouter.off('before:navigate');
    myRouter.off('after:navigate');
  }
};

AM.init({ adapter: myAdapter });

Best Practices

  1. Use setup() for complex animations - It provides automatic cleanup via gsap.context() and is ideal when you have multiple related animations and side-effects.

  2. Register all ScrollTriggers - Use AM.scroll() instead of ScrollTrigger.create() directly to ensure proper cleanup on page transitions.

  3. Use persistence sparingly - Only for animations that truly need to survive page transitions (e.g., navbar, persistent UI elements).

  4. Clean up manually when needed - Call AM.cleanup(key) when removing elements dynamically, not just on page transitions.

  5. Use debug mode during development - It helps track animation lifecycle and identify cleanup issues.

  6. Use unique keys - Keys are used to track and cleanup animations. Reusing keys will skip registration (useful for preventing duplicates).

TypeScript Support

Full TypeScript support with exported types:

import type {
  SPAAdapter,
  AnimationManagerOptions,
  AnimationOptions,
  SetupOptions,
  AstroAdapterOptions
} from 'gsap-spa-manager';

Browser Support

The UMD build exposes AnimationManager globally. The singleton instance AM is also available on window.AM for debugging in browser DevTools.

License

MIT