hypnagaga_old/docs/GSAP_USAGE.md

6.7 KiB

GSAP Animation System

This project uses GSAP for scroll-driven and UI animations, designed for low-friction animated storytelling.

Architecture

1. Shared Effects Library (gsap-effects.js)

Contains reusable animation effects and emotional presets.

2. Content Animations (gsap-shortcode-init.js)

Handles scroll-triggered animations in markdown/blog posts via shortcodes.

3. UI Component Animations (mix-nav-animations.js)

Handles interactive animations for navigation, buttons, and UI elements.


For Content Authors (Markdown/Posts)

Basic Usage

Simple fade-in animation:

{% gsapScrollAnim {
  "animationType": "fadeIn"
} %}
[{
  "src": "/path/to/image.jpg",
  "alt": "Description"
}]
{% endgsapScrollAnim %}

Available Animation Types

  • fadeIn - Fade in from below
  • fadeInUp - Fade in from further below
  • fadeInDown - Fade in from above
  • scaleIn - Scale up from small
  • slideInLeft - Slide in from left
  • slideInRight - Slide in from right
  • parallax - Parallax scroll effect
  • stagger - Multiple items animate in sequence
  • zoomIn - Zoom into image focal point
  • zoomOut - Zoom out from focal point
  • shake - Shake back and forth
  • tremble - Subtle continuous trembling
  • wobble - Wobble rotation
  • pulse - Continuous pulsing scale

Zoom Animations with Focal Points

{% gsapScrollAnim {
  "animationType": "zoomIn",
  "focalX": 30,
  "focalY": 40,
  "startZoom": 1,
  "endZoom": 2.5,
  "scrub": true
} %}
[{
  "src": "/path/to/high-res-image.jpg",
  "alt": "Image to zoom"
}]
{% endgsapScrollAnim %}
  • focalX / focalY: 0-100 (percentage of image dimensions)
  • startZoom / endZoom: Scale values (1 = normal size)

Emotional Presets (New!)

Create emotional storytelling without technical details:

Jumpscare

{% gsapScrollAnim {
  "emotion": "jumpscare"
} %}
[{ "src": "/scary-image.jpg", "alt": "Boo!" }]
{% endgsapScrollAnim %}

Sudden appearance + shake + tremble (like an arrow hitting its mark)

Anticipation

{% gsapScrollAnim {
  "emotion": "anticipation",
  "scrub": false
} %}
[{ "src": "/windup.jpg", "alt": "Getting ready" }]
{% endgsapScrollAnim %}

Pull back, then spring forward (like winding up before a punch)

Dread

{% gsapScrollAnim {
  "emotion": "dread"
} %}
[{ "src": "/ominous.jpg", "alt": "Something's coming" }]
{% endgsapScrollAnim %}

Slow reveal with unsettling movement

Relief

{% gsapScrollAnim {
  "emotion": "relief"
} %}
[{ "src": "/safe-now.jpg", "alt": "Phew" }]
{% endgsapScrollAnim %}

Gentle fade in with settling motion

Tension

{% gsapScrollAnim {
  "emotion": "tension"
} %}
[{ "src": "/suspense.jpg", "alt": "Building suspense" }]
{% endgsapScrollAnim %}

Slow zoom with subtle shake

Excitement

{% gsapScrollAnim {
  "emotion": "excitement",
  "scrub": false
} %}
[{ "src": "/celebration.jpg", "alt": "Yay!" }]
{% endgsapScrollAnim %}

Bouncy entrance with energy


Effect Composition (Advanced)

Combine multiple effects to create custom emotions:

{% gsapScrollAnim {
  "effects": ["fadeIn", "shake", "tremble"]
} %}
[{ "src": "/custom-combo.jpg", "alt": "Custom animation" }]
{% endgsapScrollAnim %}

Effects apply in sequence and can overlap.


Scroll Control Options

scrub (default: true)

  • true - Animation tied to scroll position (smooth)
  • false - Animation plays once when triggered

scrollStart (default: "top 80%")

When animation begins:

  • "top 80%" - When element's top hits 80% down viewport
  • "center center" - When element center hits viewport center
  • "bottom 20%" - When element bottom hits 20% down viewport

scrollEnd (default: "bottom 20%")

When animation completes (for scrubbed animations)

pin (default: false)

Pin the element in place during animation:

{% gsapScrollAnim {
  "animationType": "zoomIn",
  "pin": true,
  "scrollEnd": "+=500"
} %}

markers (default: false)

Show debug markers (for development):

{% gsapScrollAnim {
  "animationType": "fadeIn",
  "markers": true
} %}

Multiple Images

{% gsapScrollAnim {
  "animationType": "stagger"
} %}
[{
  "src": "/image1.jpg",
  "alt": "First",
  "caption": "Image 1"
}, {
  "src": "/image2.jpg",
  "alt": "Second",
  "caption": "Image 2"
}, {
  "src": "/image3.jpg",
  "alt": "Third",
  "caption": "Image 3"
}]
{% endgsapScrollAnim %}

Tips for Storytelling

  1. Use emotions first - "emotion": "jumpscare" is easier than combining effects manually
  2. Scrub for slow reveals - Set "scrub": true for scroll-controlled drama
  3. No scrub for punchy moments - Set "scrub": false for quick actions
  4. Pin for focus - Use "pin": true to hold attention on an element
  5. Zoom needs high-res - Zoom animations automatically request larger image sizes
  6. Compose for unique feels - Combine effects when presets don't fit: "effects": ["fadeIn", "wobble"]

For Developers

Adding New Effects

Edit gsap-effects.js:

export const effects = {
  myNewEffect: (element, config = {}) => ({
    from: {
      opacity: 0,
      rotationY: 90
    },
    to: {
      opacity: 1,
      rotationY: 0,
      ease: 'power2.out',
      ...config
    }
  })
};

Adding Emotional Presets

export const emotions = {
  myEmotion: (element, config = {}) => {
    const tl = gsap.timeline();
    tl.from(element, { /* initial state */ })
      .to(element, { /* first animation */ })
      .to(element, { /* second animation */ }, '-=0.5'); // overlap
    return tl;
  }
};

UI Component Animations

Create component-specific files like mix-nav-animations.js:

import gsap from 'gsap';
import { shouldAnimate } from './gsap-effects.js';

function initMyComponentAnimations() {
  if (!shouldAnimate()) return;
  
  document.querySelectorAll('.my-element').forEach(el => {
    el.addEventListener('mouseenter', () => {
      gsap.to(el, { scale: 1.1, duration: 0.2 });
    });
  });
}

// Turbo-compatible initialization
document.addEventListener('DOMContentLoaded', initMyComponentAnimations);
if (window.Turbo) {
  document.addEventListener('turbo:load', initMyComponentAnimations);
}

Accessibility

All animations respect prefers-reduced-motion. Users with this preference will see static content without animations.


Debugging

Enable markers to see scroll trigger points:

{% gsapScrollAnim {
  "animationType": "fadeIn",
  "markers": true
} %}

Check browser console for warnings about missing animation types or configuration errors.