gsap-setup

Installation
SKILL.md

GSAP Setup and Best Practices

Proper GSAP setup ensures smooth development, optimal performance, and maintainable code. Learn installation, plugin registration, configuration, and industry best practices.

Installation

NPM Installation

# Core GSAP
npm install gsap

# React integration
npm install @gsap/react

# All plugins are included in gsap package
# No separate installation needed

CDN Installation

<!-- GSAP Core -->
<script src="https://cdn.jsdelivr.net/npm/gsap@3.13.0/dist/gsap.min.js"></script>

<!-- ScrollTrigger -->
<script src="https://cdn.jsdelivr.net/npm/gsap@3.13.0/dist/ScrollTrigger.min.js"></script>

<!-- Other plugins as needed -->
<script src="https://cdn.jsdelivr.net/npm/gsap@3.13.0/dist/Draggable.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.13.0/dist/Flip.min.js"></script>

ES Modules (CDN)

<script type="module">
  import gsap from 'https://cdn.jsdelivr.net/npm/gsap@3.13.0/index.js'
  import { ScrollTrigger } from 'https://cdn.jsdelivr.net/npm/gsap@3.13.0/ScrollTrigger.js'

  gsap.registerPlugin(ScrollTrigger)
</script>

Project Setup

Basic Setup

// gsap.js - Central GSAP configuration
import gsap from 'gsap'
import { ScrollTrigger } from 'gsap/ScrollTrigger'
import { Draggable } from 'gsap/Draggable'

// Register all plugins once
gsap.registerPlugin(ScrollTrigger, Draggable)

// Set global defaults
gsap.defaults({
  ease: 'power2.out',
  duration: 1
})

// Configure ScrollTrigger
ScrollTrigger.config({
  ignoreMobileResize: true,
  autoRefreshEvents: 'visibilitychange,DOMContentLoaded,load'
})

export { gsap }

Advanced Setup

// gsap.js
import gsap from 'gsap'

// Plugins (all shipped in the public `gsap` npm package; some were formerly members-only)
import { ScrollTrigger } from 'gsap/ScrollTrigger'
import { Observer } from 'gsap/Observer'
import { Draggable } from 'gsap/Draggable'
import { Flip } from 'gsap/Flip'
import { ScrollToPlugin } from 'gsap/ScrollToPlugin'

// Formerly members-only / bonus plugins
import { SplitText } from 'gsap/SplitText'
import { MorphSVGPlugin } from 'gsap/MorphSVGPlugin'
import { MotionPathPlugin } from 'gsap/MotionPathPlugin'
import { DrawSVGPlugin } from 'gsap/DrawSVGPlugin'
import { ScrambleTextPlugin } from 'gsap/ScrambleTextPlugin'
import { CustomEase } from 'gsap/CustomEase'
import { MotionPathHelper } from 'gsap/MotionPathHelper'

// Register all plugins
gsap.registerPlugin(
  ScrollTrigger,
  Observer,
  Draggable,
  Flip,
  ScrollToPlugin,
  SplitText,
  MorphSVGPlugin,
  MotionPathPlugin,
  DrawSVGPlugin,
  ScrambleTextPlugin,
  CustomEase,
  MotionPathHelper
)

// Global configuration
gsap.defaults({
  ease: 'power2.out',
  duration: 1,
  overwrite: 'auto'
})

// Ticker configuration
gsap.ticker.lagSmoothing(1000, 16)

// Custom ease definitions
CustomEase.create('smooth', 'M0,0 C0.5,0 0.5,1 1,1')

// Export configured gsap instance
export default gsap

Plugin Registration

Register Plugins

import gsap from 'gsap'
import { ScrollTrigger } from 'gsap/ScrollTrigger'
import { Draggable } from 'gsap/Draggable'

// Register all plugins at once
gsap.registerPlugin(ScrollTrigger, Draggable)

// Or register individually
gsap.registerPlugin(ScrollTrigger)
gsap.registerPlugin(Draggable)

Register with React Hook

import gsap from 'gsap'
import { useGSAP } from '@gsap/react'
import { ScrollTrigger } from 'gsap/ScrollTrigger'

// Register hook and plugins
gsap.registerPlugin(useGSAP, ScrollTrigger)

Conditional Registration

import gsap from 'gsap'

// Only register needed plugins
const useScrollTrigger = true
const useDraggable = false

if (useScrollTrigger) {
  import('gsap/ScrollTrigger').then(({ ScrollTrigger }) => {
    gsap.registerPlugin(ScrollTrigger)
  })
}

if (useDraggable) {
  import('gsap/Draggable').then(({ Draggable }) => {
    gsap.registerPlugin(Draggable)
  })
}

Global Configuration

Defaults

// Set global defaults
gsap.defaults({
  ease: 'power2.out',
  duration: 1,
  delay: 0,
  overwrite: 'auto',
  lazy: true
})

// Override defaults in individual tweens
gsap.to('.box', {
  x: 200,
  duration: 2,  // Overrides default
  ease: 'back.out(1.7)'  // Overrides default
})

Timeline Defaults

const tl = gsap.timeline({
  defaults: {
    ease: 'power2.out',
    duration: 1
  },
  paused: true,
  repeat: -1,
  yoyo: true
})

// All tweens in timeline inherit defaults
tl.to('.box1', { x: 100 })  // Uses defaults
  .to('.box2', { x: 200, ease: 'back.out' })  // Overrides ease

ScrollTrigger Config

ScrollTrigger.config({
  // Ignore mobile resize events (improves performance)
  ignoreMobileResize: true,

  // Custom auto-refresh events
  autoRefreshEvents: 'visibilitychange,DOMContentLoaded,load',

  // Default markers (development only)
  defaultMarkers: false,

  // Normalize scroll
  normalizeScroll: true
})

Development Setup

Development Configuration

// gsap.dev.js
import gsap from 'gsap'
import { ScrollTrigger } from 'gsap/ScrollTrigger'

gsap.registerPlugin(ScrollTrigger)

// Enable markers in development
if (process.env.NODE_ENV === 'development') {
  ScrollTrigger.config({
    defaultMarkers: true
  })

  // Log all tweens
  gsap.registerEffect({
    name: 'debugTween',
    effect: (targets, config) => {
      return gsap.to(targets, config)
    },
    extendTimeline: true
  })
}

export { gsap }

Production Configuration

// gsap.prod.js
import gsap from 'gsap'
import { ScrollTrigger } from 'gsap/ScrollTrigger'

gsap.registerPlugin(ScrollTrigger)

// Production optimizations
ScrollTrigger.config({
  ignoreMobileResize: true,
  autoRefreshEvents: 'visibilitychange,DOMContentLoaded,load'
})

// Disable markers
ScrollTrigger.config({
  defaultMarkers: false
})

export { gsap }

Project Structure

Feature-Based Structure

src/
├── gsap/
│   ├── gsap.js           # Central configuration
│   ├── animations.js     # Reusable animations
│   └── constants.js      # Eases, durations, etc.
├── components/
│   ├── Hero/
│   │   ├── Hero.jsx
│   │   └── heroAnimations.js
│   └── About/
│       ├── About.jsx
│       └── aboutAnimations.js

Animation Modules

// gsap/animations.js
import { gsap } from './gsap'

// Reusable entrance animation
export const entranceAnimation = (elements, options = {}) => {
  return gsap.from(elements, {
    opacity: 0,
    y: 30,
    stagger: 0.1,
    duration: 0.8,
    ease: 'power2.out',
    ...options
  })
}

// Reusable hover animation
export const hoverAnimation = (element, options = {}) => {
  const tl = gsap.timeline({ paused: true })

  tl.to(element, {
      scale: 1.1,
      duration: 0.3,
      ease: 'power2.out'
    })
    .to(element, {
      scale: 1,
      duration: 0.3,
      ease: 'power2.out'
    }, '+=0.5')

  return tl
}

Environment Configuration

Development vs Production

// gsap/config.js
const isDevelopment = process.env.NODE_ENV === 'development'

export const config = {
  // Enable debug tools in development
  debug: isDevelopment,

  // Performance optimizations
  performance: !isDevelopment,

  // Animation speed multiplier (for testing)
  speedMultiplier: isDevelopment ? 0.5 : 1,

  // Easing presets
  eases: {
    ui: 'power2.out',
    entrance: 'back.out(1.7)',
    exit: 'power2.in',
    playful: 'elastic.out(1, 0.3)'
  },

  // Duration presets
  durations: {
    fast: 0.3,
    normal: 0.8,
    slow: 1.5
  }
}

export default config

Best Practices

1. Register Plugins Once

// ✅ Register all plugins in one place
gsap.registerPlugin(ScrollTrigger, Draggable, Flip)

// ❌ Don't register multiple times
import { ScrollTrigger } from 'gsap/ScrollTrigger'
gsap.registerPlugin(ScrollTrigger)  // In one file

import { ScrollTrigger } from 'gsap/ScrollTrigger'
gsap.registerPlugin(ScrollTrigger)  // In another file - redundant!

2. Use Named Exports

// ✅ Use named exports for tree-shaking
import { gsap } from 'gsap'
import { ScrollTrigger } from 'gsap/ScrollTrigger'

// ❌ Avoid default imports when possible
import gsap from 'gsap'  // Can't be tree-shaken as effectively

3. Centralize Configuration

// ✅ Central GSAP configuration
// gsap.js
import gsap from 'gsap'
import { ScrollTrigger } from 'gsap/ScrollTrigger'

gsap.registerPlugin(ScrollTrigger)
gsap.defaults({ ease: 'power2.out', duration: 1 })

export default gsap

// Import configured gsap
import gsap from './gsap'

// ❌ Scattered configuration
import gsap from 'gsap'
gsap.defaults({ ease: 'power2.out' })  // In one file

import gsap from 'gsap'
import { ScrollTrigger } from 'gsap/ScrollTrigger'
gsap.registerPlugin(ScrollTrigger)  // In another file

4. Set Global Defaults

// ✅ Use defaults for consistency
gsap.defaults({
  ease: 'power2.out',
  duration: 1
})

// All tweens inherit these defaults
gsap.to('.box', { x: 200 })
gsap.from('.modal', { opacity: 0 })

// ❌ Repeating values
gsap.to('.box', { x: 200, ease: 'power2.out', duration: 1 })
gsap.from('.modal', { opacity: 0, ease: 'power2.out', duration: 1 })

5. Use Timelines for Sequences

// ✅ Use timeline for sequences
const tl = gsap.timeline()
tl.to('.box1', { x: 100 })
  .to('.box2', { x: 100 })
  .to('.box3', { x: 100 })

// Easy to control
tl.play()
tl.reverse()
tl.kill()

// ❌ Separate tweens
gsap.to('.box1', { x: 100, delay: 0 })
gsap.to('.box2', { x: 100, delay: 1 })
gsap.to('.box3', { x: 100, delay: 2 })

6. Clean Up Animations

// ✅ Clean up when component unmounts
function MyComponent() {
  useGSAP(() => {
    const tl = gsap.timeline()
    tl.to('.box', { x: 200 })

    // Automatically cleaned up
  })

  return <div className="box"></div>
}

// ❌ Memory leaks
function MyComponent() {
  useEffect(() => {
    const tl = gsap.timeline()
    tl.to('.box', { x: 200 })
    // Never cleaned up!
  }, [])

  return <div className="box"></div>
}

7. Test on Low-End Devices

// ✅ Performance considerations
gsap.to('.many-boxes', {
  x: 100,
  duration: 1,
  ease: 'power2.out',  // Simpler ease, better performance
  stagger: 0.05,           // Distribute load
  onComplete: () => {
    // Clean up when done
    gsap.killTweensOf('.many-boxes')
  }
})

// ❌ Too complex for low-end devices
gsap.to('.many-boxes', {
  x: 100,
  duration: 1,
  ease: 'elastic.out(1, 0.3)',  // Complex, slow
  stagger: 0.01  // Too many tweens
})

8. Use Appropriate Eases

// ✅ Match ease to use case
gsap.from('.modal', {
  opacity: 0,
  scale: 0.8,
  ease: 'back.out(1.7)',  // Attention-grabbing entrance
  duration: 0.5
})

// ❌ Wrong ease for context
gsap.from('.modal', {
  opacity: 0,
  scale: 0.8,
  ease: 'elastic.out(1, 0.3)',  // Too much for modal
  duration: 0.5
})

9. Implement Responsive Animations

// ✅ Responsive with matchMedia
const mm = gsap.matchMedia()

mm.add('(min-width: 768px)', () => {
  gsap.to('.box', { x: 200, duration: 1 })
})

mm.add('(max-width: 767px)', () => {
  gsap.to('.box', { x: 100, duration: 1 })
})

// ❌ Not responsive
gsap.to('.box', { x: 200, duration: 1 })  // Same for all screens

10. Use Selectors Wisely

// ✅ Scoped selectors
const q = gsap.utils.selector('.container')
gsap.to(q('.box'), { x: 200 })

// Or in React
useGSAP(() => {
  gsap.to('.box', { x: 200 })
}, { scope: container })

// ❌ Global selectors
gsap.to('.box', { x: 200 })  // Affects ALL .box elements

Common Mistakes

1. Not Registering Plugins

// ❌ Plugin won't work
import { ScrollTrigger } from 'gsap/ScrollTrigger'
gsap.to('.box', {
  scrollTrigger: { trigger: '.box' }
})

// ✅ Register plugin first
import { ScrollTrigger } from 'gsap/ScrollTrigger'
gsap.registerPlugin(ScrollTrigger)
gsap.to('.box', {
  scrollTrigger: { trigger: '.box' }
})

2. Using Wrong Import Style

// ❌ Can't be tree-shaken
import gsap from 'gsap'

// ✅ Use named imports
import { gsap } from 'gsap'

3. Conflicting Tweens

// ❌ Two tweens fighting
gsap.to('.box', { x: 100, duration: 2 })
gsap.to('.box', { x: 200, duration: 1 })

// ✅ Use overwrite or kill first
gsap.to('.box', { x: 100, duration: 2, overwrite: true })
// Or
gsap.killTweensOf('.box', 'x')
gsap.to('.box', { x: 200, duration: 1 })

4. Forgetting Cleanup

// ❌ Memory leaks
useEffect(() => {
  gsap.to('.box', { x: 200 })
}, [])

// ✅ Use useGSAP in React
useGSAP(() => {
  gsap.to('.box', { x: 200 })
}, { scope: container })

5. Not Testing Performance

// ❌ Works on dev machine, slow on others
gsap.to('.many-complex-elements', {
  filter: 'blur(10px)',
  duration: 1
})

// ✅ Test and optimize
gsap.to('.many-complex-elements', {
  opacity: 0.8,  // Simpler property
  duration: 1
})

Performance Checklist

  • Register plugins once at app entry
  • Use named exports for tree-shaking
  • Set global defaults for consistency
  • Use timelines for sequences
  • Clean up animations when done
  • Test on low-end devices
  • Use appropriate eases
  • Implement responsive animations
  • Scope selectors to prevent conflicts
  • Use transform properties over layout properties
  • Stagger animations to distribute load
  • Avoid filters on many elements
  • Kill tweens before creating new ones
  • Use ScrollTrigger toggleActions over scrub when possible
  • Refresh ScrollTrigger after DOM changes

Quick Reference

Task Solution
Install GSAP npm install gsap
Import core import { gsap } from 'gsap'
Import plugin import { ScrollTrigger } from 'gsap/ScrollTrigger'
Register plugins gsap.registerPlugin(ScrollTrigger)
Set defaults gsap.defaults({ ease, duration })
CDN script <script src="https://cdn.jsdelivr.net/npm/gsap@3.13.0/dist/gsap.min.js">
React integration npm install @gsap/react
React hook import { useGSAP } from '@gsap/react'
Formerly members-only plugin Install from gsap (v3.13+) and follow https://gsap.com/community/standard-license/
Tree-shaking Use named exports
Cleanup useGSAP or manual kill()
Weekly Installs
1
First Seen
6 days ago
Installed on
amp1
cline1
opencode1
cursor1
kimi-cli1
warp1