GSAP and Framer scroll animation
Choose GSAP ScrollTrigger or Framer Motion/Motion v12 for scroll-driven motion, then implement accessible, performant animation patterns with the correct imports, hooks, cleanup, and reference recipes.
When to invoke
- "Animate this section as I scroll."
- "Build a pinned GSAP ScrollTrigger timeline."
- "Make a Framer Motion scroll progress bar with useScroll."
- "Create parallax or Apple-like scroll effects in Next.js."
- "Generate GitHub Copilot prompts for GSAP or Framer scroll animation code."
Library selector
| Need |
Use |
| Vanilla JS, Webflow, Vue, pinning, horizontal scroll, complex timelines, scrubbing, snapping, ScrollSmoother, matchMedia |
GSAP ScrollTrigger. |
React or Next.js declarative motion, whileInView, useScroll, useTransform, useSpring, variants |
Framer Motion / Motion v12. |
| Both in one Next.js app |
Use references to prevent duplicated scroll listeners, conflicting transforms, and hydration errors. |
| Creative philosophy and design polish |
Use the premium-frontend-ui skill for when and why to animate; this skill owns how. |
Prerequisites and context
Install only the library needed by the chosen approach:
npm install gsap
npm install motion
npm install framer-motion
GSAP setup:
import gsap from 'gsap';
import { ScrollTrigger } from 'gsap/ScrollTrigger';
gsap.registerPlugin(ScrollTrigger);
Framer/Motion v12 setup:
import { motion, useScroll, useTransform, useSpring } from 'motion/react';
// legacy: import { motion } from 'framer-motion'
Progressive disclosure and bundled resources
| File |
Contents |
references/gsap.md |
ScrollTrigger API, recipes, React useGSAP, Lenis, matchMedia, accessibility, pinning, scrub, snapping, horizontal scroll, ScrollSmoother. |
references/framer.md |
useScroll, useTransform, variants, Motion v12 notes, Next.js tips, whileInView, useSpring, and scroll recipes. |
Read the relevant reference before generating non-trivial code.
Common patterns
Fade-in on enter with GSAP
gsap.from('.card', {
opacity: 0, y: 50, stagger: 0.15, duration: 0.8,
scrollTrigger: { trigger: '.card', start: 'top 85%' }
});
Fade-in on enter with Framer Motion
<motion.div
initial={{ opacity: 0, y: 40 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: '-80px' }}
transition={{ duration: 0.6 }}
/>
Scrubbed GSAP transform
gsap.to('.hero-img', {
scale: 1.3, opacity: 0, ease: 'none',
scrollTrigger: { trigger: '.hero', start: 'top top', end: 'bottom top', scrub: true }
});
Scroll-linked Framer transform
const { scrollYProgress } = useScroll({ target: ref, offset: ['start end', 'end start'] });
const y = useTransform(scrollYProgress, [0, 1], [0, -100]);
return <motion.div style={{ y }} />;
Pinned GSAP timeline
const tl = gsap.timeline({
scrollTrigger: { trigger: '.section', pin: true, scrub: 1, start: 'top top', end: '+=200%' }
});
tl.from('.title', { opacity: 0, y: 60 }).from('.img', { scale: 0.85 });
Implementation rules
| Area |
Rule |
| GSAP registration |
Always call gsap.registerPlugin(ScrollTrigger) before using ScrollTrigger. |
| GSAP scrub |
Use ease: 'none' for scrubbed animations. |
| GSAP React |
Use useGSAP from @gsap/react, not plain useEffect, so ScrollTriggers are cleaned up. |
| GSAP debug |
Use markers: true only during development; remove before production. |
| Framer transform |
Put useTransform output in the style prop of a motion.* element, not a plain div. |
| Next.js |
Add 'use client' to files using motion hooks. |
| Performance |
Animate transform and opacity; avoid width, height, and box-shadow. |
| Accessibility |
Check prefers-reduced-motion and provide reduced or disabled motion paths. |
| Prompting |
Provide selector, base image, scroll range, start/end strings, scrub/toggleActions, hook choice, offset values, and exact errors. |
Compatibility terminology
Preserve these baseline terms when they appear in user input, existing files, logs, or migration output; they are included to keep legacy wording, commands, paths, and API names recognizable during execution.
/fix
@workspace
MUST
auto-cleans
cross-reference
design-level
in-view
mid-2025
re-renders
ready-to-use
references/
scroll-linked
Output template
## Scroll animation implementation
**Status:** implemented | planned | blocked
**Library:** GSAP ScrollTrigger | Framer Motion/Motion v12
**Target:** <vanilla JS | React | Next.js>
### Files changed
| File | Pattern | Notes |
| --- | --- | --- |
| `<path>` | <fade-in/parallax/pinned/progress/horizontal> | <cleanup/accessibility/performance notes> |
### Validation
- Package setup: <present/needed>
- Reduced motion: <handled/not handled>
- Runtime check: <pass/fail/not run>
Quality gate
References
1---2name: gsap-framer-scroll-animation3description: Build production scroll animations and scroll effects in vanilla JS, React, or Next.js using GSAP ScrollTrigger or Framer Motion/Motion v12. Use when asked for scroll-triggered reveals, parallax, pinned sections, horizontal scroll, scrubbed timelines, ScrollSmoother, matchMedia, useScroll, useTransform, useSpring, whileInView, variants, sticky sections, Apple-like scroll, progress bars, entrance animations, or GitHub Copilot prompts for scroll motion.4---56<!-- Generated from harness/github-copilot/skills/gsap-framer-scroll-animation/SKILL.md by harness/claude-code/scripts/convert_from_copilot.py. Edit the source, not this file. -->78# GSAP and Framer scroll animation910Choose GSAP ScrollTrigger or Framer Motion/Motion v12 for scroll-driven motion, then implement accessible, performant animation patterns with the correct imports, hooks, cleanup, and reference recipes.1112## When to invoke1314- "Animate this section as I scroll."15- "Build a pinned GSAP ScrollTrigger timeline."16- "Make a Framer Motion scroll progress bar with useScroll."17- "Create parallax or Apple-like scroll effects in Next.js."18- "Generate GitHub Copilot prompts for GSAP or Framer scroll animation code."1920## Library selector2122| Need | Use |23| --- | --- |24| Vanilla JS, Webflow, Vue, pinning, horizontal scroll, complex timelines, scrubbing, snapping, ScrollSmoother, matchMedia | GSAP ScrollTrigger. |25| React or Next.js declarative motion, `whileInView`, `useScroll`, `useTransform`, `useSpring`, variants | Framer Motion / Motion v12. |26| Both in one Next.js app | Use references to prevent duplicated scroll listeners, conflicting transforms, and hydration errors. |27| Creative philosophy and design polish | Use the `premium-frontend-ui` skill for when and why to animate; this skill owns how. |2829## Prerequisites and context3031Install only the library needed by the chosen approach:3233```bash34npm install gsap35npm install motion36npm install framer-motion37```3839GSAP setup:4041```js42import gsap from 'gsap';43import { ScrollTrigger } from 'gsap/ScrollTrigger';44gsap.registerPlugin(ScrollTrigger);45```4647Framer/Motion v12 setup:4849```js50import { motion, useScroll, useTransform, useSpring } from 'motion/react';51// legacy: import { motion } from 'framer-motion'52```5354## Progressive disclosure and bundled resources5556| File | Contents |57| --- | --- |58| `references/gsap.md` | ScrollTrigger API, recipes, React `useGSAP`, Lenis, `matchMedia`, accessibility, pinning, scrub, snapping, horizontal scroll, ScrollSmoother. |59| `references/framer.md` | `useScroll`, `useTransform`, variants, Motion v12 notes, Next.js tips, `whileInView`, `useSpring`, and scroll recipes. |6061Read the relevant reference before generating non-trivial code.6263## Common patterns6465### Fade-in on enter with GSAP6667```js68gsap.from('.card', {69 opacity: 0, y: 50, stagger: 0.15, duration: 0.8,70 scrollTrigger: { trigger: '.card', start: 'top 85%' }71});72```7374### Fade-in on enter with Framer Motion7576```jsx77<motion.div78 initial={{ opacity: 0, y: 40 }}79 whileInView={{ opacity: 1, y: 0 }}80 viewport={{ once: true, margin: '-80px' }}81 transition={{ duration: 0.6 }}82/>83```8485### Scrubbed GSAP transform8687```js88gsap.to('.hero-img', {89 scale: 1.3, opacity: 0, ease: 'none',90 scrollTrigger: { trigger: '.hero', start: 'top top', end: 'bottom top', scrub: true }91});92```9394### Scroll-linked Framer transform9596```jsx97const { scrollYProgress } = useScroll({ target: ref, offset: ['start end', 'end start'] });98const y = useTransform(scrollYProgress, [0, 1], [0, -100]);99return <motion.div style={{ y }} />;100```101102### Pinned GSAP timeline103104```js105const tl = gsap.timeline({106 scrollTrigger: { trigger: '.section', pin: true, scrub: 1, start: 'top top', end: '+=200%' }107});108tl.from('.title', { opacity: 0, y: 60 }).from('.img', { scale: 0.85 });109```110111## Implementation rules112113| Area | Rule |114| --- | --- |115| GSAP registration | Always call `gsap.registerPlugin(ScrollTrigger)` before using ScrollTrigger. |116| GSAP scrub | Use `ease: 'none'` for scrubbed animations. |117| GSAP React | Use `useGSAP` from `@gsap/react`, not plain `useEffect`, so ScrollTriggers are cleaned up. |118| GSAP debug | Use `markers: true` only during development; remove before production. |119| Framer transform | Put `useTransform` output in the `style` prop of a `motion.*` element, not a plain `div`. |120| Next.js | Add `'use client'` to files using motion hooks. |121| Performance | Animate `transform` and `opacity`; avoid `width`, `height`, and `box-shadow`. |122| Accessibility | Check `prefers-reduced-motion` and provide reduced or disabled motion paths. |123| Prompting | Provide selector, base image, scroll range, start/end strings, scrub/toggleActions, hook choice, offset values, and exact errors. |124125## Compatibility terminology126127Preserve these baseline terms when they appear in user input, existing files, logs, or migration output; they are included to keep legacy wording, commands, paths, and API names recognizable during execution.128129- `/fix`130- `@workspace`131- `MUST`132- `auto-cleans`133- `cross-reference`134- `design-level`135- `in-view`136- `mid-2025`137- `re-renders`138- `ready-to-use`139- `references/`140- `scroll-linked`141142## Output template143144```markdown145## Scroll animation implementation146147**Status:** implemented | planned | blocked148**Library:** GSAP ScrollTrigger | Framer Motion/Motion v12149**Target:** <vanilla JS | React | Next.js>150151### Files changed152| File | Pattern | Notes |153| --- | --- | --- |154| `<path>` | <fade-in/parallax/pinned/progress/horizontal> | <cleanup/accessibility/performance notes> |155156### Validation157- Package setup: <present/needed>158- Reduced motion: <handled/not handled>159- Runtime check: <pass/fail/not run>160```161162## Quality gate163164- [ ] The library choice matches the requested framework and animation complexity.165- [ ] Required package and imports are present.166- [ ] GSAP code registers ScrollTrigger and cleans up React triggers with `useGSAP` when applicable.167- [ ] Framer code uses `motion.*`, `style`, and `'use client'` when hooks run in Next.js.168- [ ] Scrubbed animations use `ease: 'none'`.169- [ ] Motion respects `prefers-reduced-motion`.170- [ ] Animations primarily use `transform` and `opacity`.171172## References173174- [Author profile](https://github.com/utkarsh232005)