# GSAP Animation System (Punch animations) This project uses GSAP for scroll-driven punch animations (zoom in/out effects) via shortcodes. The system is intentionally minimal and focused on high-quality image reveals. ## Architecture Overview The animation system is split into two main parts: 1. **Animations Library** ([`gsap-animations.js`](../src/assets/scripts/bundle/gsap-animations.js)) - Reusable zoom presets: `punchIn`, `punchOut` - Default variables with simple override merging - `shouldAnimate()` utility respecting `prefers-reduced-motion` 2. **Content Animations** ([`gsap-shortcode-init.js`](../src/assets/scripts/bundle/gsap-shortcode-init.js)) - Scroll-triggered animations in markdown/blog posts - Paired shortcode reads JSON config and passes it through. The shortcode also passes arguments for a Tailwind class name. - We must remember that this is the only function of Tailwind that we use and that we should consult files in ([`our design tokens`](../src/assets/css/global/global.css)), and be mindful of the fact that these animations will exist as containers of ([`prose.css`](../src/assets/css/global/blocks/prose.css)). --- # For Content Authors See [GSAP_USAGE.md](./GSAP_USAGE.md) for shortcode usage. ## Quick Start ### Punch In Animation ```markdown {% gsapScrollAnim { "animationType": "punchIn", "focalX": 75, "focalY": 25, "startZoom": 1, "endZoom": 2.5 } %} [{ "src": "/images/detail-photo.jpg", "alt": "Macro photography showing fine detail" }] {% endgsapScrollAnim %} ``` --- # For Developers ## Configuration Options All parameters are optional with sensible defaults and fully passed through: ```javascript { "animationType": "punchIn", // punchIn or punchOut "scrollStart": "top 80%", // Timeline start "scrollEnd": "bottom 20%", // Timeline end "scrub": true, // Tie progress to scroll "containerClass": "gsap-container", "spillingInto": false, // false | true | 'prose' | 'bleed' "pin": true, "markers": false, // Punch-specific overrides "focalX": 50, // 0-100 (% from left) "focalY": 50, // 0-100 (% from top) "startZoom": 1, // 1 for punchIn, 2.5 for punchOut "endZoom": 2.5, // 2.5 for punchIn, 1 for punchOut "ease": "power2.inOut" } ``` ## Image Format Images are defined as JSON array inside the paired shortcode: ```json [{ "src": "/path/to/image.jpg", "alt": "Required alt text", "caption": "Optional caption text" }, { "src": "/path/to/image2.jpg", "alt": "Second image", "caption": "Another caption" }] ``` Images are automatically optimized via Eleventy Image plugin (WebP/JPEG, responsive sizes). ## Example ### Zoom In to Focal Point Draw attention to a specific detail in a high-resolution photograph: ```markdown {% gsapScrollAnim { "animationType": "zoomIn", "focalX": 75, "focalY": 25, "startZoom": 1, "endZoom": 2.5 } %} [{ "src": "/images/detail-photo.jpg", "alt": "Macro photography showing fine detail" }] {% endgsapScrollAnim %} ``` **Zoom Parameters:** - `focalX` (0-100): Horizontal focal point percentage from left (default: 50) - `focalY` (0-100): Vertical focal point percentage from top (default: 50) - `startZoom`: Initial scale (default: 1 = 100%) - `endZoom`: Final scale (default: 2.5 = 250%) **zoomIn**: Starts with full image visible, zooms into the focal point **zoomOut**: Starts zoomed into focal point, pulls back to show full image High-resolution images (up to 3200px) are automatically loaded for zoom animations to preserve detail when scaled. ## ScrollTrigger Settings ### scrollStart / scrollEnd Control when the animation begins and ends relative to viewport: - `"top bottom"` - Element's top enters viewport bottom - `"top 80%"` - Element's top at 80% viewport height - `"center center"` - Element center aligns with viewport center - `"bottom top"` - Element bottom exits viewport top Default: `scrollStart: "top 80%"`, `scrollEnd: "bottom 20%"` ### scrub When `true` (default), animation progress is tied directly to scroll position, enabling bidirectional playback. When `false`, animation plays once when scroll position crosses `scrollStart` threshold. ## CSS Customization Default wrapper class: `.gsap-container` Generated structure: ```html
...
...
``` Add custom styles in your CSS: ```css .gsap-container.featured-image { max-width: 1200px; margin: 0 auto; } .gsap-item { margin-bottom: 2rem; } ``` ## Accessibility - Respects `prefers-reduced-motion` - animations disabled automatically - All images require `alt` text - ScrollTrigger callbacks maintain proper ARIA states ## Turbo Drive Compatibility Animations are automatically cleaned up and re-initialized on Turbo navigation: - Contexts reverted before page change - ScrollTrigger instances killed - Re-initialized after new page loads ## Debugging Enable debug markers to visualize scroll trigger points: ```markdown {% gsapScrollAnim { "animationType": "fadeIn", "markers": true } %} [...] {% endgsapScrollAnim %} ``` This shows colored markers in viewport indicating trigger start/end positions. ## Performance - Animations use GPU-accelerated properties (`transform`, `opacity`) - `will-change` applied for optimization - ScrollTrigger efficiently batches calculations - Contexts properly cleaned up on navigation ## Files - Library: `src/assets/scripts/bundle/gsap-animations.js` - Shortcode initializer: `src/assets/scripts/bundle/gsap-shortcode-init.js` - Shortcode: `src/_config/shortcodes/gsap.js` - CSS: `src/assets/css/global/utilities/gsap-animations.css`