关于 gsap-master
面向 GSAP v3 动画实现的技能,供制作交互界面动效的开发者参考。内容涵盖时间线组织、滚动与手势交互、文本和 SVG 动画,以及性能、无障碍和框架清理实践。
主要功能
- 01组织 Tween 与 Timeline
- 02实现滚动触发动画
- 03处理拖拽与手势交互
- 04制作文本和 SVG 动画
- 05考虑性能与减少动态效果偏好
适用场景
- 01构建页面滚动叙事
- 02制作拖拽式轮播或滑块
- 03添加分步文本揭示效果
- 04在 React 或 Next.js 中管理动画清理
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ su69ar/ rdnax-gsap-master --skill gsap-master安装后在 Claude Code 中输入/gsap-master确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
README.mdreferences/DEBUG_CHECKLIST.mdGSAP_CORE.mdGSAP_RECIPES.mdGSDEVTOOLS.mdNEXTJS_REACT_PATTERNS.mdPHYSICS_PLUGINS.mdTEXT_ANIMATIONS.mdUI_INTERACTIONS.mdscripts/make-gsap-starter.sh详细介绍
GSAP Master Skill(Antigravity)
适用范围与基本规则
你是一名符合生产要求的 GSAP v3 工程师。你交付的交互式 UI 动效具备以下特点:
- 性能(避免布局抖动,保持 60 fps,优化指针交互)
- 可维护性(时间轴架构、模块化函数、清晰的标签)
- 无障碍性(prefers-reduced-motion、易于理解的动效、清晰可见的焦点)
- 框架安全性(React/Next.js 清理,避免重新渲染时重复创建触发器)
GSAP Core 处理 Tween/Timeline 和实用工具/工具。插件用于扩展功能。
许可说明:GSAP 表示,现在整个库都可免费使用(历史上部分插件仅供 Club 成员使用)。 切勿推荐盗版或破解插件。
1) 激活触发条件
用户提及以下内容时自动激活:
GSAP、Tween、Timeline、缓动、错开、关键帧、修饰器、ScrollTrigger、pin/scrub/snap、 ScrollSmoother、ScrollTo、SplitText、ScrambleText、TextPlugin、Flip、Draggable、Inertia、Observer、 MotionPath、MorphSVG、DrawSVG、物理效果、光标跟随、悬停微交互、 Next.js/React 清理、SSR、性能/卡顿、磁吸按钮、3D 倾斜、卡片堆叠、 滑动卡片、加入购物车、彩纸特效、加载骨架屏、工具提示、上下文菜单、 UI 交互、微交互、手势、下拉刷新、轮播图吸附、 文本动画、字符动画、单词动画、逐行显示、打字机效果、 乱码文本、打字效果、文本拆分、错开文本、文本遮罩显示、 gsap core、时间轴控制、实用工具、quickTo、quickSetter、matchMedia、 gsap.context、gsap.effects、ticker、GSDevTools、调试、动画检查器、 Physics2D、PhysicsProps、速度、重力、加速度、摩擦力、粒子。
2) 输出约定(必须交付的内容)
用户要求实现动画时,输出:
- 动效方案(目标、触发条件、状态、时长、缓动)
- 实现(先提供最精简的可运行代码)
- 架构(时间轴映射、标签、可复用函数/模块)
- 响应式与无障碍性(matchMedia + 减少动态效果时的备用方案)
- 性能说明(quickTo/quickSetter、避免布局抖动、批处理)
- 调试清单(标记/刷新/清理/重复创建)
优先提供一个“良好的 MVP”,然后再增强。
3) 插件覆盖范围图(完整)
滚动插件
| 插件 | 描述 | 使用场景 |
|---|---|---|
| ScrollTrigger | 在滚动时触发/擦动/固定/吸附动画 | 大多数滚动动画 |
| ScrollTo | 以编程方式平滑滚动 | 导航、CTA 按钮 |
| ScrollSmoother | 基于原生滚动的平滑滚动 + 视差效果 | 丝滑的滚动体验 |
| Observer | 统一检测滚轮/触摸/指针手势 | 滚动劫持、滑动手势 |
UI/交互
| 插件 | 描述 | 使用场景 |
|---|---|---|
| Flip | 基于 FLIP 的布局过渡 | 网格重排、模态框扩展、共享元素 |
| Draggable | 拖拽交互 | 轮播图、滑块、卡片 |
| InertiaPlugin | 动量/速度滑行 | 拖拽后的惯性物理效果 |
文本
| 插件 | 描述 | 使用场景 |
|---|---|---|
| SplitText | 拆分字符/单词/行以制作动画 | 错开显示文本 |
| ScrambleText | 随机文本解码效果 | 科技感标题 |
| TextPlugin | 输入/替换文本内容 | 计数器、动态标签 |
SVG
| 插件 | 描述 | 使用场景 |
|---|---|---|
| DrawSVG | 绘制描边动画 | 线稿、签名 |
| MorphSVG | 在 SVG 路径之间变形 | 形状过渡 |
| MotionPath | 沿 SVG 路径制作动画 | 沿曲线运动 |
| MotionPathHelper | 可视化编辑路径(开发工具) | 开发工作流 |
物理 / 缓动 / 工具
| 插件 | 描述 | 使用场景 |
|---|---|---|
| Physics2D | 2D 物理模拟 | 弹道运动、粒子 |
| PhysicsProps | 为任意属性添加物理效果 | 自然的属性动画 |
| CustomEase | 定义自定义缓动曲线 | 打造独特的动效风格 |
| CustomWiggle | 振荡 / 摇摆缓动 | 抖动、振动效果 |
| CustomBounce | 自定义弹跳缓动 | 逼真的弹跳 |
| EasePack | 额外的内置缓动 | 扩展缓动库 |
| GSDevTools | 可视化时间轴调试界面 | 开发工作流 |
渲染库
| 插件 | 描述 | 使用场景 |
|---|---|---|
| PixiPlugin | 为 Pixi.js 对象添加动画 | Canvas/WebGL 渲染 |
| EaselPlugin | 为 EaselJS 对象添加动画 | CreateJS canvas |
React 集成
| 助手 | 描述 | 使用场景 |
|---|---|---|
| useGSAP() | 官方 React Hook | React/Next.js 应用 |
4) GSAP 核心精通(始终适用的基础知识)
4.1 基本构件
gsap.to(target, { x: 100, duration: 1 }); // animate TO values
gsap.from(target, { opacity: 0 }); // animate FROM values
gsap.fromTo(target, { x: 0 }, { x: 100 }); // explicit from→to
gsap.set(target, { x: 0, opacity: 1 }); // instant set (no animation)
优先使用变换属性(x、y、scale、rotation),而不是布局属性(top、left、width、height)。
4.2 时间轴(任何不简单的动画都默认使用)
const tl = gsap.timeline({ defaults: { ease: "power3.out", duration: 0.6 } });
tl.from(".hero-title", { y: 30, autoAlpha: 0 })
.from(".hero-subtitle", { y: 20, autoAlpha: 0 }, "<0.1")
.from(".hero-cta", { scale: 0.9, autoAlpha: 0 }, "<0.15");
规则:
- 每个“交互单元”(首屏 / 区块 / 组件)使用一个时间轴
- 使用标签和位置参数,而不是脆弱的延迟
- 使用
defaults保持一致,并有意覆盖默认值
4.3 位置参数
tl.to(a, {...}) // appends at end
tl.to(b, {...}, "<") // starts same time as previous
tl.to(c, {...}, ">") // starts after previous ends
tl.to(d, {...}, "+=0.3") // wait 0.3s after last end
tl.to(e, {...}, "label") // starts at label
4.4 关键工具
- keyframes:在单个补间动画中实现多步骤动画
- modifiers:逐帧变换数值(高级)
- snapping:使用
snap工具实现网格对齐 - utils:
gsap.utils.mapRange()、clamp()、snap()、toArray() - matchMedia:响应式动画编排
- context:为框架提供作用域清理
5) 性能工具包(不可妥协)
5.1 指针 / 鼠标交互
// ❌ BAD: Creates new tween every event
window.addEventListener("pointermove", (e) => {
gsap.to(".cursor", { x: e.clientX, y: e.clientY });
});
// ✅ GOOD: Reuses quickTo instances
const xTo = gsap.quickTo(".cursor", "x", { duration: 0.2, ease: "power3" });
const yTo = gsap.quickTo(".cursor", "y", { duration: 0.2, ease: "power3" });
window.addEventListener("pointermove", (e) => { xTo(e.clientX); yTo(e.clientY); });
// ✅ GOOD: Ultra-fast direct updates (no tween)
const setX = gsap.quickSetter(".cursor", "x", "px");
const setY = gsap.quickSetter(".cursor", "y", "px");
window.addEventListener("pointermove", (e) => { setX(e.clientX); setY(e.clientY); });
5.2 避免布局抖动
// ❌ BAD: Mixed reads and writes
elements.forEach(el => {
const rect = el.getBoundingClientRect(); // read
gsap.set(el, { x: rect.width }); // write
});
// ✅ GOOD: Batch reads, then writes
const rects = elements.map(el => el.getBoundingClientRect()); // all reads
elements.forEach((el, i) => gsap.set(el, { x: rects[i].width })); // all writes
5.3 ScrollTrigger 使用规模规则
- 减少触发器数量;尽可能批量显示元素
- 使用由布局驱动的数值时,设置
invalidateOnRefresh - 对相似元素列表使用
ScrollTrigger.batch()
6) 精通 ScrollTrigger(核心滚动动画)
ScrollTrigger 支持基于滚动触发、滚动同步、固定、吸附等功能。
6.1 基本模式
// Pattern A: Inline scrollTrigger
gsap.to(".box", {
x: 500,
scrollTrigger: {
trigger: ".box",
start: "top 80%",
end: "top 30%",
scrub: 1,
markers: true // dev only
}
});
// Pattern B: Timeline + ScrollTrigger.create
const tl = gsap.timeline();
tl.from(".item", { y: 50, autoAlpha: 0, stagger: 0.1 });
ScrollTrigger.create({
animation: tl,
trigger: ".section",
start: "top 70%",
toggleActions: "play none none reverse"
});
6.2 固定式叙事(时间轴 + 滚动同步)
const tl = gsap.timeline();
tl.from(".panel1", { autoAlpha: 0, y: 20 })
.to(".panel1", { autoAlpha: 0 })
.from(".panel2", { autoAlpha: 0, y: 20 }, "<");
ScrollTrigger.create({
animation: tl,
trigger: ".story",
start: "top top",
end: "+=2000",
scrub: 1,
pin: true,
invalidateOnRefresh: true
});
6.3 列表批处理
ScrollTrigger.batch(".card", {
onEnter: (elements) => gsap.from(elements, { y: 30, autoAlpha: 0, stagger: 0.1 }),
start: "top 85%"
});
6.4 水平滚动区块
const sections = gsap.utils.toArray(".panel");
gsap.to(sections, {
xPercent: -100 * (sections.length - 1),
ease: "none",
scrollTrigger: {
trigger: ".horizontal-container",
pin: true,
scrub: 1,
end: () => "+=" + document.querySelector(".horizontal-container").offsetWidth
}
});
6.5 响应式 + 减少动态效果(必需)
gsap.matchMedia().add({
"(prefers-reduced-motion: no-preference) and (min-width: 768px)": () => {
// Desktop animations
gsap.from(".hero", {
y: 50, autoAlpha: 0,
scrollTrigger: { trigger: ".hero", start: "top 80%" }
});
},
"(prefers-reduced-motion: reduce)": () => {
// Reduced motion: instant visibility, no animation
gsap.set(".hero", { autoAlpha: 1 });
}
});
7) ScrollTo(程序化滚动)
使用 ScrollTo 平滑导航到锚点 / 区块。
gsap.registerPlugin(ScrollToPlugin);
// Scroll to element
gsap.to(window, { duration: 1, scrollTo: "#pricing", ease: "power2.out" });
// Scroll to position
gsap.to(window, { duration: 1, scrollTo: { y: 500, autoKill: true } });
// With offset
gsap.to(window, { scrollTo: { y: "#section", offsetY: 80 } });
8) ScrollSmoother(平滑滚动 + 特效)
ScrollSmoother 基于原生滚动实现平滑和视差效果。
gsap.registerPlugin(ScrollTrigger, ScrollSmoother);
// Required HTML structure:
// <div id="smooth-wrapper">
// <div id="smooth-content">...content...</div>
// </div>
const smoother = ScrollSmoother.create({
wrapper: "#smooth-wrapper",
content: "#smooth-content",
smooth: 1.5, // seconds for smoothing
effects: true // enable data-speed/data-lag attributes
});
// HTML: <div data-speed="0.5">Slow parallax</div>
// <div data-speed="2">Fast parallax</div>
// <div data-lag="0.5">Trailing effect</div>
注意事项:
- 必须与 ScrollTrigger 协调,并在布局变化后调用
refresh() - 始终提供减少动态效果的备用方案
- 使用
normalizeScroll: true确保移动设备上的一致性
9) Observer(手势统一处理)
使用 Observer 将滚轮 / 触摸 / 指针事件统一为一致的“意图”信号。
gsap.registerPlugin(Observer);
Observer.create({
target: window,
type: "wheel,touch,pointer",
onUp: () => goToPrevSection(),
onDown: () => goToNextSection(),
tolerance: 50,
preventDefault: true
});
使用场景:
- 类似滚动劫持的分步区块(注意无障碍支持)
- 由触控板手势触发的时间轴
- 自定义滑动导航
10) Flip(布局过渡)
当元素布局发生变化时(网格重排、模态框展开、共享元素过渡),使用 Flip。
gsap.registerPlugin(Flip);
// 1. Capture state
const state = Flip.getState(".cards");
// 2. Change layout (DOM/CSS)
container.classList.toggle("grid");
// 3. Animate from old state
Flip.from(state, {
duration: 0.6,
ease: "power2.inOut",
stagger: 0.05,
absolute: true,
onEnter: elements => gsap.fromTo(elements, { autoAlpha: 0 }, { autoAlpha: 1 }),
onLeave: elements => gsap.to(elements, { autoAlpha: 0 })
});
11) Draggable + InertiaPlugin(惯性拖动)
gsap.registerPlugin(Draggable, InertiaPlugin);
Draggable.create(".slider", {
type: "x",
bounds: ".container",
inertia: true, // requires InertiaPlugin
snap: value => Math.round(value / 200) * 200, // snap to 200px intervals
onDrag: function() { console.log(this.x); },
onThrowComplete: () => console.log("Throw complete")
});
自制惯性(如果 InertiaPlugin 不可用):
let velocity = 0;
let lastX = 0;
Draggable.create(".element", {
type: "x",
onDrag: function() {
velocity = this.x - lastX;
lastX = this.x;
},
onDragEnd: function() {
// DIY momentum with exponential decay
gsap.to(this.target, {
x: `+=${velocity * 10}`,
duration: Math.abs(velocity) * 0.1,
ease: "power2.out"
});
}
});
12) 文本:SplitText / ScrambleText / TextPlugin
12.1 SplitText
gsap.registerPlugin(SplitText);
const split = new SplitText(".headline", { type: "chars,words,lines" });
gsap.from(split.chars, {
y: 20,
autoAlpha: 0,
stagger: 0.02,
duration: 0.4,
ease: "power3.out"
});
// Cleanup (important for responsive)
// split.revert();
自制替代方案(如有需要):
function splitIntoSpans(el) {
const text = el.textContent;
el.innerHTML = text.split('').map(char =>
char === ' ' ? ' ' : `<span class="char">${char}</span>`
).join('');
return el.querySelectorAll('.char');
}
12.2 ScrambleText
gsap.registerPlugin(ScrambleTextPlugin);
gsap.to(".title", {
duration: 1.5,
scrambleText: {
text: "DECODED MESSAGE",
chars: "XO",
revealDelay: 0.5
}
});
12.3 TextPlugin
gsap.registerPlugin(TextPlugin);
gsap.to(".counter", {
duration: 2,
text: { value: "100%", delimiter: "" },
ease: "none"
});
13) SVG:DrawSVG / MorphSVG / MotionPath
13.1 DrawSVG
gsap.registerPlugin(DrawSVGPlugin);
gsap.from(".line-path", {
drawSVG: 0, // or "0%" / "50% 50%"
duration: 2,
ease: "power2.inOut"
});
13.2 MorphSVG
gsap.registerPlugin(MorphSVGPlugin);
gsap.to("#shape1", {
morphSVG: "#shape2",
duration: 1,
ease: "power2.inOut"
});
13.3 MotionPath
gsap.registerPlugin(MotionPathPlugin);
gsap.to(".element", {
duration: 5,
motionPath: {
path: "#curve-path",
align: "#curve-path",
alignOrigin: [0.5, 0.5],
autoRotate: true
},
ease: "none"
});
14) Physics2D / PhysicsProps
gsap.registerPlugin(Physics2DPlugin, PhysicsPropsPlugin);
// 2D physics (velocity, angle, acceleration, gravity)
gsap.to(".ball", {
duration: 3,
physics2D: {
velocity: 500,
angle: -60,
gravity: 500
}
});
// Physics for any property
gsap.to(".element", {
duration: 2,
physicsProps: {
x: { velocity: 100, acceleration: 50 },
rotation: { velocity: 360 }
}
});
15) 缓动:CustomEase / CustomWiggle / CustomBounce
gsap.registerPlugin(CustomEase, CustomWiggle, CustomBounce);
// Custom SVG path ease
CustomEase.create("myEase", "M0,0 C0.25,0.1 0.25,1 1,1");
gsap.to(".el", { x: 100, ease: "myEase" });
// Wiggle ease
CustomWiggle.create("myWiggle", { wiggles: 6, type: "easeOut" });
gsap.to(".el", { rotation: 20, ease: "myWiggle" });
// Custom bounce
CustomBounce.create("myBounce", { strength: 0.7, squash: 2 });
gsap.to(".el", { y: 300, ease: "myBounce" });
16) GSDevTools(调试 UI)
gsap.registerPlugin(GSDevTools);
// Attach to a specific timeline
const tl = gsap.timeline();
tl.to(".box", { x: 500 })
.to(".box", { rotation: 360 });
GSDevTools.create({ animation: tl });
// Or attach to global timeline
GSDevTools.create();
17) Next.js / React(生产环境模式)
17.1 黄金法则:卸载时清理
使用 gsap.context() 限定选择器的作用范围,并还原所有更改。
"use client";
import { useLayoutEffect, useRef } from "react";
import gsap from "gsap";
import ScrollTrigger from "gsap/ScrollTrigger";
gsap.registerPlugin(ScrollTrigger);
export function SectionAnim() {
const root = useRef(null);
useLayoutEffect(() => {
if (!root.current) return;
const ctx = gsap.context(() => {
const tl = gsap.timeline({ defaults: { ease: "power3.out", duration: 0.8 } });
tl.from(".title", { y: 18, autoAlpha: 0 })
.from(".item", { y: 14, autoAlpha: 0, stagger: 0.06 }, "<0.1");
gsap.from(".reveal", {
y: 24, autoAlpha: 0,
scrollTrigger: { trigger: ".reveal", start: "top 85%" }
});
}, root);
return () => ctx.revert();
}, []);
return (
<section ref={root}>
<h2 className="title">Title</h2>
<div className="item">A</div>
<div className="item">B</div>
<div className="reveal">Reveal</div>
</section>
);
}
17.2 官方 useGSAP hook
"use client";
import { useRef } from "react";
import gsap from "gsap";
import { useGSAP } from "@gsap/react";
import ScrollTrigger from "gsap/ScrollTrigger";
gsap.registerPlugin(ScrollTrigger);
export function AnimatedSection() {
const container = useRef(null);
useGSAP(() => {
gsap.from(".box", {
y: 50,
autoAlpha: 0,
scrollTrigger: { trigger: ".box", start: "top 80%" }
});
}, { scope: container });
return (
<div ref={container}>
<div className="box">Content</div>
</div>
);
}
17.3 SSR 安全性
- 将动画组件放在仅客户端文件中
- 不要在副作用之外访问
window/document - 在需要时使用
typeof window !== 'undefined'保护条件
17.4 响应式编排
useLayoutEffect(() => {
const mm = gsap.matchMedia();
mm.add("(min-width: 768px)", () => {
// Desktop animations
gsap.from(".hero", { x: -100 });
return () => { /* cleanup */ };
});
mm.add("(max-width: 767px)", () => {
// Mobile animations
gsap.from(".hero", { y: 50 });
return () => { /* cleanup */ };
});
return () => mm.revert();
}, []);
18) 调试检查清单(照原文使用)
核心问题
- 目标是否真实存在? 仔细检查选择器/ref(拼写错误、作用域、SSR)。确认动画运行时元素已存在。
- DOM 时序:在 React/Next.js 中,确保代码在挂载后运行(客户端组件、useLayoutEffect、refs 不为 null)。
- CSS 冲突:检查是否有覆盖
transform/opacity/visibility/display/transition的规则。 - 重复运行:使用
gsap.context()和ctx.revert(),避免叠加补间/ScrollTrigger。
时间轴问题
- 序列看起来不对? 使用标签和位置参数(
<、>、+=0.2),而不是手动延迟。 - 默认值与补间变量:确保时间轴默认值没有意外覆盖补间。
- 放慢速度以便检查:
gsap.globalTimeline.timeScale(0.5)。
ScrollTrigger 问题
- 启用调试:
markers: true(仅开发环境)。 - 验证起始/结束位置:确保起始/结束位置与布局和元素高度相符。
- 布局变化后刷新:图片/字体/动态内容稳定后调用
ScrollTrigger.refresh()。 - 自定义滚动容器:不使用 window 时,统一设置
scroller。 - 固定时跳动/抖动:尝试
anticipatePin,检查布局偏移,并考虑invalidateOnRefresh。
性能问题
- 指针/鼠标卡顿:不要为每个事件都创建补间。使用
quickTo/quickSetter。 - 触发器过多:减少数量,使用批处理,并整合时间轴。
- 避免布局抖动:先批量读取,再批量写入;优先使用变换。
- 开销较大的属性:尽可能避免使用
top/left/width/height。
19)“插件不可用”策略
如果用户无法使用某个插件(受政策/离线条件限制):
- 首先提供官方插件方案
- 使用 GSAP 核心功能 + CSS/JS 提供 DIY 替代方案
- 明确说明限制:边缘情况、可维护性、性能、跨浏览器一致性
切勿推荐破解/盗版插件。
20) 即用型交互方案
悬停微交互
const el = document.querySelector(".btn");
el.addEventListener("mouseenter", () =>
gsap.to(el, { scale: 1.03, duration: 0.2, overwrite: "auto" })
);
el.addEventListener("mouseleave", () =>
gsap.to(el, { scale: 1.00, duration: 0.25, overwrite: "auto" })
);
光标跟随(高性能)
const xTo = gsap.quickTo(".cursor", "x", { duration: 0.2, ease: "power3" });
const yTo = gsap.quickTo(".cursor", "y", { duration: 0.2, ease: "power3" });
window.addEventListener("pointermove", (e) => { xTo(e.clientX); yTo(e.clientY); });
磁性按钮
const btn = document.querySelector(".magnetic");
const strength = 0.3;
btn.addEventListener("mousemove", (e) => {
const rect = btn.getBoundingClientRect();
const x = e.clientX - rect.left - rect.width / 2;
const y = e.clientY - rect.top - rect.height / 2;
gsap.to(btn, { x: x * strength, y: y * strength, duration: 0.3 });
});
btn.addEventListener("mouseleave", () => {
gsap.to(btn, { x: 0, y: 0, duration: 0.5, ease: "elastic.out(1, 0.3)" });
});
滚动时显示
gsap.from(".reveal", {
y: 24, autoAlpha: 0, duration: 0.8, ease: "power3.out",
scrollTrigger: {
trigger: ".reveal",
start: "top 85%",
toggleActions: "play none none reverse"
}
});
列表交错显示
gsap.from(".list-item", {
y: 30,
autoAlpha: 0,
duration: 0.6,
stagger: 0.1,
ease: "power3.out",
scrollTrigger: { trigger: ".list", start: "top 80%" }
});
视差主视觉区
gsap.to(".hero-bg", {
yPercent: 30,
ease: "none",
scrollTrigger: {
trigger: ".hero",
start: "top top",
end: "bottom top",
scrub: true
}
});
此技能附带的参考资料
参见:
- references/GSAP_CORE.md
- references/GSAP_RECIPES.md
- references/UI_INTERACTIONS.md
- references/TEXT_ANIMATIONS.md
- references/PHYSICS_PLUGINS.md
- references/NEXTJS_REACT_PATTERNS.md
- references/GSDEVTOOLS.md
- references/DEBUG_CHECKLIST.md