gsap-scrolltrigger · bbeierle12 — Claude Code skill: scroll-driven animations
A skill for GSAP ScrollTrigger: tie animations to scroll position, pin sections, build parallax and snap points. Useful when a page has to react to scrolling.
npx skills add Bbeierle12/Skill-MCP-Claude --skill gsap-scrolltrigger -a claude-codeWhat gsap-scrolltrigger does
The skill covers the GSAP ScrollTrigger plugin: linking animation progress to scroll position, pinning a block in place, layering parallax and snapping between sections. It ships as reference code plus tables of values — start/end positions like top center or top 80%, scrub modes, toggleActions, and callbacks such as onEnter, onUpdate and onToggle.
Separate sections walk through pinning with pinSpacing, horizontal scrolling via xPercent, and snapping to timeline labels. Multi-layer parallax gets its own example, with a speed per layer.
GSAP itself has to be installed first: npm install gsap. Skip gsap.registerPlugin(ScrollTrigger) and none of the examples run — that is the usual first stumble. The skill text cuts off at the markers section, so there is nothing on debugging in it.
What it helps with
- tie animation progress to scroll position
- pin a section while the page scrolls
- build parallax from layers moving at different speeds
- snap between sections or timeline labels
- run horizontal panel scrolling inside a vertical page
Example prompts for the agent
- set up ScrollTrigger for a four-layer parallax section
- pin the block and scroll the panels horizontally with gsap
- add snapping to timeline labels and an onUpdate callback for the progress bar
How to install gsap-scrolltrigger
1Skills CLI (Vercel)
npx skills add Bbeierle12/Skill-MCP-Claude --skill gsap-scrolltrigger -a claude-code2Manually: put the files in place
~/.claude/skills/gsap-scrolltrigger/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/gsap-scrolltrigger/
1Skills CLI (Vercel)
npx skills add Bbeierle12/Skill-MCP-Claude --skill gsap-scrolltrigger -a codex2Manually: put the files in place
.agents/skills/gsap-scrolltrigger/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add Bbeierle12/Skill-MCP-Claude --skill gsap-scrolltrigger -a cursor2Manually: put the files in place
.cursor/skills/gsap-scrolltrigger/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install Bbeierle12/Skill-MCP-Claude gsap-scrolltrigger2Manually: put the files in place
.github/skills/gsap-scrolltrigger/SKILL.md1Skills CLI (Vercel)
npx skills add Bbeierle12/Skill-MCP-Claude --skill gsap-scrolltrigger -a gemini-cli2Platform CLI
gemini skills install https://github.com/Bbeierle12/Skill-MCP-Claude --path skills/gsap-scrolltriggerManually: put the files in place
.devin/skills/gsap-scrolltrigger/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add Bbeierle12/Skill-MCP-Claude --skill gsap-scrolltrigger -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
Questions about gsap-scrolltrigger
How do I install gsap-scrolltrigger in Claude?
Run npx skills add Bbeierle12/Skill-MCP-Claude --skill gsap-scrolltrigger -a claude-code. The skill file lands at ~/.claude/skills/gsap-scrolltrigger/SKILL.md.
What does gsap-scrolltrigger do?
It documents scroll-driven animation with the GSAP ScrollTrigger plugin: pinning, scrubbing, snapping and parallax. The agent pulls code samples and parameter values from it.
What is required for the examples to work?
GSAP installed with npm install gsap and a gsap.registerPlugin(ScrollTrigger) call in your code. Without registering the plugin the animations do not start.
Source text
SKILL.md · MIT
---
name: gsap-scrolltrigger
description: Scroll-based animations using GSAP ScrollTrigger plugin including pinning, scrubbing, snap points, and parallax effects. Use when creating scroll-driven animations, sticky sections, progress indicators, or parallax scrolling experiences.
---
# GSAP ScrollTrigger
Scroll-driven animations and interactions.
## Quick Start
```bash
npm install gsap
```
```javascript
import gsap from 'gsap';
import { ScrollTrigger } from 'gsap/ScrollTrigger';
gsap.registerPlugin(ScrollTrigger);
gsap.to('.box', {
x: 500,
scrollTrigger: {
trigger: '.box',
start: 'top center',
end: 'bottom center',
scrub: true
}
});
```
## Core Concepts
### Basic ScrollTrigger
```javascript
gsap.to('.element', {
x: 200,
scrollTrigger: {
trigger: '.element', // Element that triggers the animation
start: 'top center', // When trigger hits viewport center
end: 'bottom center', // When trigger leaves viewport center
toggleActions: 'play pause resume reset'
}
});
```
### Start/End Positions
```javascript
// Format: "trigger-position viewport-position"
start: 'top center' // Trigger's top hits viewport center
start: 'top 80%' // Trigger's top hits 80% down viewport
start: 'center center' // Trigger's center hits viewport center
start: 'bottom top' // Trigger's bottom hits viewport top
start: 'top top+=100' // Trigger's top hits 100px below viewport top
```
### Position Reference
| Value | Description |
|-------|-------------|
| `top` | Top edge |
| `center` | Center |
| `bottom` | Bottom edge |
| `80%` | 80% from top |
| `+=100` | Plus 100 pixels |
| `-=50` | Minus 50 pixels |
## Scrub Animations
### Basic Scrub
```javascript
// Animation progress tied to scroll position
gsap.to('.progress-bar', {
scaleX: 1,
scrollTrigger: {
trigger: '.content',
start: 'top top',
end: 'bottom bottom',
scrub: true // Directly linked to scroll
}
});
```
### Smooth Scrub
```javascript
gsap.to('.element', {
x: 500,
scrollTrigger: {
trigger: '.section',
scrub: 1, // 1 second smoothing
// scrub: 0.5 // 0.5 second smoothing
// scrub: 2 // 2 second smoothing (laggy feel)
}
});
```
### Scrub with Timeline
```javascript
const tl = gsap.timeline({
scrollTrigger: {
trigger: '.container',
start: 'top top',
end: '+=3000', // Scroll distance
scrub: 1,
pin: true
}
});
tl.to('.step1', { opacity: 1 })
.to('.step2', { opacity: 1 })
.to('.step3', { opacity: 1 });
```
## Pinning
### Basic Pin
```javascript
ScrollTrigger.create({
trigger: '.panel',
start: 'top top',
end: '+=500', // Pin for 500px of scroll
pin: true
});
```
### Pin with Animation
```javascript
gsap.to('.content', {
x: '-200%',
ease: 'none',
scrollTrigger: {
trigger: '.horizontal-section',
start: 'top top',
end: () => '+=' + document.querySelector('.horizontal-section').offsetWidth,
pin: true,
scrub: 1
}
});
```
### Pin Spacing
```javascript
ScrollTrigger.create({
trigger: '.section',
pin: true,
pinSpacing: true, // Default: adds space for pinned duration
// pinSpacing: false // No extra space (content overlaps)
// pinSpacing: '500px' // Custom spacing
});
```
## Toggle Actions
### Action Syntax
```javascript
// Format: "onEnter onLeave onEnterBack onLeaveBack"
toggleActions: 'play pause resume reset'
// Common combinations:
toggleActions: 'play none none none' // Play once
toggleActions: 'play reverse play reverse' // Toggle direction
toggleActions: 'restart none none none' // Restart each time
toggleActions: 'play complete reverse reset'
```
### Action Values
| Action | Effect |
|--------|--------|
| `play` | Play forward |
| `pause` | Pause |
| `resume` | Resume from paused |
| `reverse` | Play backward |
| `restart` | Restart from beginning |
| `reset` | Reset to start (no animation) |
| `complete` | Jump to end |
| `none` | Do nothing |
## Snap Points
### Basic Snap
```javascript
ScrollTrigger.create({
trigger: '.sections',
start: 'top top',
end: 'bottom bottom',
snap: 1 / 4 // Snap to quarters
});
```
### Snap to Labels
```javascript
const tl = gsap.timeline({
scrollTrigger: {
trigger: '.container',
scrub: 1,
snap: {
snapTo: 'labels',
duration: 0.5,
ease: 'power2.inOut'
}
}
});
tl.addLabel('intro')
.to('.a', { opacity: 1 })
.addLabel('middle')
.to('.b', { opacity: 1 })
.addLabel('end');
```
### Snap Configuration
```javascript
snap: {
snapTo: [0, 0.25, 0.5, 0.75, 1], // Snap to specific points
duration: { min: 0.2, max: 0.6 }, // Snap duration range
delay: 0, // Delay before snap
ease: 'power1.inOut', // Snap easing
directional: true // Snap in scroll direction
}
```
## Callbacks
### ScrollTrigger Callbacks
```javascript
ScrollTrigger.create({
trigger: '.section',
onEnter: () => console.log('Entered'),
onLeave: () => console.log('Left'),
onEnterBack: () => console.log('Entered from bottom'),
onLeaveBack: () => console.log('Left going up'),
onUpdate: (self) => console.log('Progress:', self.progress),
onToggle: (self) => console.log('Active:', self.isActive),
onRefresh: () => console.log('Refreshed')
});
```
### Progress-Based Updates
```javascript
ScrollTrigger.create({
trigger: '.section',
start: 'top bottom',
end: 'bottom top',
onUpdate: (self) => {
// self.progress: 0 to 1
// self.direction: 1 (down) or -1 (up)
// self.velocity: scroll speed
updateElement(self.progress);
}
});
```
## Parallax Effects
### Basic Parallax
```javascript
// Background moves slower than scroll
gsap.to('.background', {
yPercent: -50,
ease: 'none',
scrollTrigger: {
trigger: '.section',
scrub: true
}
});
// Foreground moves faster
gsap.to('.foreground', {
yPercent: 50,
ease: 'none',
scrollTrigger: {
trigger: '.section',
scrub: true
}
});
```
### Multi-Layer Parallax
```javascript
const layers = [
{ selector: '.layer-1', speed: -20 },
{ selector: '.layer-2', speed: -40 },
{ selector: '.layer-3', speed: -60 },
{ selector: '.layer-4', speed: -80 }
];
layers.forEach(layer => {
gsap.to(layer.selector, {
yPercent: layer.speed,
ease: 'none',
scrollTrigger: {
trigger: '.parallax-section',
start: 'top bottom',
end: 'bottom top',
scrub: true
}
});
});
```
## Horizontal Scrolling
### Horizontal Section
```javascript
const sections = gsap.utils.toArray('.panel');
gsap.to(sections, {
xPercent: -100 * (sections.length - 1),
ease: 'none',
scrollTrigger: {
trigger: '.horizontal-container',
pin: true,
scrub: 1,
snap: 1 / (sections.length - 1),
end: () => '+=' + document.querySelector('.horizontal-container').offsetWidth
}
});
```
## Markers (Development)
```javascript
ScrollTrigger.create({
trigger: '.section',
start: 'top center',
end: 'bottom center',
markers: true, // Show visual markers
// markers: { startColor: 'green', endColor: 'red', fontSize: '12px' }
});
```
## Batch Animations
### Stagger on Scroll
```javascript
ScrollTrigger.batch('.card', {
onEnter: (elements) => {
gsap.from(elements, {
opacity: 0,
y: 50,
stagger: 0.1,
duration: 0.5
});
},
start: 'top 85%'
});
```
### Batch Configuration
```javascript
ScrollTrigger.batch('.item', {
interval: 0.1, // Time between batches
batchMax: 3, // Max items per batch
onEnter: batch => gsap.to(batch, { opacity: 1, y: 0, stagger: 0.1 }),
onLeave: batch => gsap.to(batch, { opacity: 0, y: 20 }),
onEnterBack: batch => gsap.to(batch, { opacity: 1, y: 0 }),
onLeaveBack: batch => gsap.to(batch, { opacity: 0, y: -20 })
});
```
## Common Patterns
### Reveal on Scroll
```javascript
gsap.utils.toArray('.reveal').forEach(elem => {
gsap.from(elem, {
opacity: 0,
y: 50,
duration: 0.8,
scrollTrigger: {
trigger: elem,
start: 'top 80%',
toggleActions: 'play none none none'
}
});
});
```
### Progress Indicator
```javascript
gsap.to('.progress-bar', {
scaleX: 1,
transformOrigin: 'left center',
ease: 'none',
scrollTrigger: {
trigger: 'body',
start: 'top top',
end: 'bottom bottom',
scrub: 0.3
}
});
```
### Sticky Header Transform
```javascript
ScrollTrigger.create({
start: 'top -80',
onUpdate: (self) => {
if (self.direction === 1) {
gsap.to('.header', { y: -80, duration: 0.3 });
} else {
gsap.to('.header', { y: 0, duration: 0.3 });
}
}
});
```
## Temporal Collapse Patterns
### Countdown Scroll Reveal
```javascript
// Reveal countdown sections as user scrolls
const sections = ['days', 'hours', 'minutes', 'seconds'];
sections.forEach((section, i) => {
gsap.from(`.countdown-${section}`, {
opacity: 0,
scale: 0.8,
y: 50,
duration: 0.8,
ease: 'power3.out',
scrollTrigger: {
trigger: `.countdown-${section}`,
start: 'top 80%',
toggleActions: 'play none none none'
}
});
});
```
### Scroll-Based Time Dilation Effect
```javascript
gsap.timeline({
scrollTrigger: {
trigger: '.time-section',
start: 'top center',
end: 'bottom center',
scrub: 1
}
})
.to('.time-digit', {
textShadow: '0 0 50px #00F5FF, 0 0 100px #00F5FF',
scale: 1.1
})
.to('.particles', {
opacity: 1,
filter: 'blur(0px)'
}, '<');
```
## Performance Tips
```javascript
// Disable on mobile if needed
ScrollTrigger.matchMedia({
'(min-width: 768px)': function() {
// Desktop animations
},
'(max-width: 767px)': function() {
// Simpler mobile animations
}
});
// Refresh on resize
ScrollTrigger.refresh();
// Kill all ScrollTriggers
ScrollTrigger.killAll();
// Kill specific trigger
const st = ScrollTrigger.create({ ... });
st.kill();
```
## Reference
- See `gsap-fundamentals` for animation basics
- See `gsap-sequencing` for timeline composition
- See `gsap-react` for React integration with ScrollTrigger
© Bbeierle12 · MIT · Bbeierle12/Skill-MCP-Claude
Similar skills
Everything for Frontend and UI →gsap-scrolltrigger by other authors comes first.