tribunal-kit 3.0.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agent/ARCHITECTURE.md +99 -99
- package/.agent/GEMINI.md +52 -52
- package/.agent/agents/accessibility-reviewer.md +187 -220
- package/.agent/agents/ai-code-reviewer.md +199 -233
- package/.agent/agents/backend-specialist.md +215 -238
- package/.agent/agents/code-archaeologist.md +161 -181
- package/.agent/agents/database-architect.md +184 -207
- package/.agent/agents/debugger.md +191 -218
- package/.agent/agents/dependency-reviewer.md +103 -136
- package/.agent/agents/devops-engineer.md +218 -238
- package/.agent/agents/documentation-writer.md +201 -221
- package/.agent/agents/explorer-agent.md +160 -180
- package/.agent/agents/frontend-reviewer.md +160 -194
- package/.agent/agents/frontend-specialist.md +248 -237
- package/.agent/agents/game-developer.md +48 -52
- package/.agent/agents/logic-reviewer.md +116 -149
- package/.agent/agents/mobile-developer.md +200 -223
- package/.agent/agents/mobile-reviewer.md +162 -195
- package/.agent/agents/orchestrator.md +181 -211
- package/.agent/agents/penetration-tester.md +157 -174
- package/.agent/agents/performance-optimizer.md +183 -203
- package/.agent/agents/performance-reviewer.md +178 -211
- package/.agent/agents/precedence-reviewer.md +213 -0
- package/.agent/agents/product-manager.md +142 -162
- package/.agent/agents/product-owner.md +6 -25
- package/.agent/agents/project-planner.md +142 -162
- package/.agent/agents/qa-automation-engineer.md +225 -242
- package/.agent/agents/security-auditor.md +174 -194
- package/.agent/agents/seo-specialist.md +193 -213
- package/.agent/agents/sql-reviewer.md +161 -194
- package/.agent/agents/supervisor-agent.md +184 -203
- package/.agent/agents/swarm-worker-contracts.md +17 -17
- package/.agent/agents/swarm-worker-registry.md +46 -46
- package/.agent/agents/test-coverage-reviewer.md +160 -193
- package/.agent/agents/test-engineer.md +0 -21
- package/.agent/agents/type-safety-reviewer.md +175 -208
- package/.agent/patterns/generator.md +9 -9
- package/.agent/patterns/inversion.md +12 -12
- package/.agent/patterns/pipeline.md +9 -9
- package/.agent/patterns/reviewer.md +13 -13
- package/.agent/patterns/tool-wrapper.md +9 -9
- package/.agent/rules/GEMINI.md +63 -63
- package/.agent/scripts/append_flow.js +72 -0
- package/.agent/scripts/case_law_manager.py +525 -0
- package/.agent/scripts/compress_skills.py +167 -0
- package/.agent/scripts/consolidate_skills.py +173 -0
- package/.agent/scripts/deep_compress.py +202 -0
- package/.agent/scripts/minify_context.py +80 -0
- package/.agent/scripts/security_scan.py +1 -1
- package/.agent/scripts/skill_evolution.py +563 -0
- package/.agent/scripts/strip_tribunal.py +41 -0
- package/.agent/skills/agent-organizer/SKILL.md +100 -126
- package/.agent/skills/agentic-patterns/SKILL.md +0 -70
- package/.agent/skills/ai-prompt-injection-defense/SKILL.md +134 -160
- package/.agent/skills/api-patterns/SKILL.md +123 -215
- package/.agent/skills/api-security-auditor/SKILL.md +143 -177
- package/.agent/skills/app-builder/SKILL.md +334 -50
- package/.agent/skills/app-builder/templates/SKILL.md +13 -15
- package/.agent/skills/app-builder/templates/astro-static/TEMPLATE.md +16 -16
- package/.agent/skills/app-builder/templates/chrome-extension/TEMPLATE.md +22 -22
- package/.agent/skills/app-builder/templates/cli-tool/TEMPLATE.md +18 -18
- package/.agent/skills/app-builder/templates/electron-desktop/TEMPLATE.md +20 -20
- package/.agent/skills/app-builder/templates/express-api/TEMPLATE.md +17 -17
- package/.agent/skills/app-builder/templates/flutter-app/TEMPLATE.md +18 -18
- package/.agent/skills/app-builder/templates/monorepo-turborepo/TEMPLATE.md +21 -21
- package/.agent/skills/app-builder/templates/nextjs-fullstack/TEMPLATE.md +19 -19
- package/.agent/skills/app-builder/templates/nextjs-saas/TEMPLATE.md +26 -26
- package/.agent/skills/app-builder/templates/nextjs-static/TEMPLATE.md +26 -26
- package/.agent/skills/app-builder/templates/nuxt-app/TEMPLATE.md +19 -19
- package/.agent/skills/app-builder/templates/python-fastapi/TEMPLATE.md +18 -18
- package/.agent/skills/app-builder/templates/react-native-app/TEMPLATE.md +20 -20
- package/.agent/skills/appflow-wireframe/SKILL.md +95 -121
- package/.agent/skills/architecture/SKILL.md +169 -331
- package/.agent/skills/authentication-best-practices/SKILL.md +139 -173
- package/.agent/skills/bash-linux/SKILL.md +129 -154
- package/.agent/skills/behavioral-modes/SKILL.md +8 -69
- package/.agent/skills/brainstorming/SKILL.md +436 -104
- package/.agent/skills/building-native-ui/SKILL.md +152 -174
- package/.agent/skills/clean-code/SKILL.md +331 -360
- package/.agent/skills/code-review-checklist/SKILL.md +0 -62
- package/.agent/skills/config-validator/SKILL.md +115 -141
- package/.agent/skills/csharp-developer/SKILL.md +468 -528
- package/.agent/skills/database-design/SKILL.md +104 -369
- package/.agent/skills/deployment-procedures/SKILL.md +119 -145
- package/.agent/skills/devops-engineer/SKILL.md +295 -332
- package/.agent/skills/devops-incident-responder/SKILL.md +87 -113
- package/.agent/skills/doc.md +5 -5
- package/.agent/skills/documentation-templates/SKILL.md +27 -63
- package/.agent/skills/edge-computing/SKILL.md +131 -157
- package/.agent/skills/extract-design-system/SKILL.md +108 -134
- package/.agent/skills/framer-motion-expert/SKILL.md +111 -855
- package/.agent/skills/frontend-design/SKILL.md +151 -499
- package/.agent/skills/game-design-expert/SKILL.md +79 -105
- package/.agent/skills/game-engineering-expert/SKILL.md +96 -122
- package/.agent/skills/geo-fundamentals/SKILL.md +97 -124
- package/.agent/skills/github-operations/SKILL.md +279 -314
- package/.agent/skills/gsap-expert/SKILL.md +119 -826
- package/.agent/skills/i18n-localization/SKILL.md +113 -138
- package/.agent/skills/intelligent-routing/SKILL.md +167 -127
- package/.agent/skills/lint-and-validate/SKILL.md +16 -52
- package/.agent/skills/llm-engineering/SKILL.md +344 -357
- package/.agent/skills/local-first/SKILL.md +128 -154
- package/.agent/skills/mcp-builder/SKILL.md +92 -118
- package/.agent/skills/mobile-design/SKILL.md +213 -219
- package/.agent/skills/motion-engineering/SKILL.md +184 -0
- package/.agent/skills/nextjs-react-expert/SKILL.md +99 -698
- package/.agent/skills/nodejs-best-practices/SKILL.md +498 -559
- package/.agent/skills/observability/SKILL.md +293 -330
- package/.agent/skills/parallel-agents/SKILL.md +96 -122
- package/.agent/skills/performance-profiling/SKILL.md +217 -254
- package/.agent/skills/plan-writing/SKILL.md +92 -118
- package/.agent/skills/platform-engineer/SKILL.md +97 -123
- package/.agent/skills/playwright-best-practices/SKILL.md +137 -162
- package/.agent/skills/powershell-windows/SKILL.md +112 -146
- package/.agent/skills/project-idioms/SKILL.md +87 -0
- package/.agent/skills/python-patterns/SKILL.md +15 -35
- package/.agent/skills/python-pro/SKILL.md +148 -754
- package/.agent/skills/react-specialist/SKILL.md +123 -827
- package/.agent/skills/readme-builder/SKILL.md +23 -85
- package/.agent/skills/realtime-patterns/SKILL.md +269 -304
- package/.agent/skills/red-team-tactics/SKILL.md +18 -51
- package/.agent/skills/rust-pro/SKILL.md +623 -701
- package/.agent/skills/seo-fundamentals/SKILL.md +129 -154
- package/.agent/skills/server-management/SKILL.md +164 -190
- package/.agent/skills/shadcn-ui-expert/SKILL.md +181 -206
- package/.agent/skills/skill-creator/SKILL.md +24 -56
- package/.agent/skills/sql-pro/SKILL.md +579 -633
- package/.agent/skills/supabase-postgres-best-practices/SKILL.md +35 -66
- package/.agent/skills/swiftui-expert/SKILL.md +151 -176
- package/.agent/skills/systematic-debugging/SKILL.md +92 -118
- package/.agent/skills/tailwind-patterns/SKILL.md +516 -576
- package/.agent/skills/tdd-workflow/SKILL.md +111 -137
- package/.agent/skills/test-result-analyzer/SKILL.md +33 -73
- package/.agent/skills/testing-patterns/SKILL.md +512 -573
- package/.agent/skills/trend-researcher/SKILL.md +30 -71
- package/.agent/skills/ui-ux-pro-max/SKILL.md +8 -41
- package/.agent/skills/ui-ux-researcher/SKILL.md +51 -91
- package/.agent/skills/vue-expert/SKILL.md +127 -866
- package/.agent/skills/vulnerability-scanner/SKILL.md +354 -269
- package/.agent/skills/web-accessibility-auditor/SKILL.md +168 -193
- package/.agent/skills/web-design-guidelines/SKILL.md +25 -61
- package/.agent/skills/webapp-testing/SKILL.md +119 -145
- package/.agent/skills/whimsy-injector/SKILL.md +58 -132
- package/.agent/skills/workflow-optimizer/SKILL.md +28 -68
- package/.agent/workflows/api-tester.md +151 -151
- package/.agent/workflows/audit.md +127 -138
- package/.agent/workflows/brainstorm.md +110 -110
- package/.agent/workflows/changelog.md +112 -112
- package/.agent/workflows/create.md +124 -124
- package/.agent/workflows/debug.md +165 -189
- package/.agent/workflows/deploy.md +180 -189
- package/.agent/workflows/enhance.md +128 -151
- package/.agent/workflows/fix.md +114 -135
- package/.agent/workflows/generate.md +13 -4
- package/.agent/workflows/migrate.md +160 -160
- package/.agent/workflows/orchestrate.md +168 -168
- package/.agent/workflows/performance-benchmarker.md +114 -123
- package/.agent/workflows/plan.md +173 -173
- package/.agent/workflows/preview.md +80 -80
- package/.agent/workflows/refactor.md +161 -183
- package/.agent/workflows/review-ai.md +101 -129
- package/.agent/workflows/review.md +116 -116
- package/.agent/workflows/session.md +94 -94
- package/.agent/workflows/status.md +79 -79
- package/.agent/workflows/strengthen-skills.md +138 -139
- package/.agent/workflows/swarm.md +179 -179
- package/.agent/workflows/test.md +189 -211
- package/.agent/workflows/tribunal-backend.md +94 -113
- package/.agent/workflows/tribunal-database.md +95 -115
- package/.agent/workflows/tribunal-frontend.md +96 -118
- package/.agent/workflows/tribunal-full.md +93 -133
- package/.agent/workflows/tribunal-mobile.md +95 -119
- package/.agent/workflows/tribunal-performance.md +110 -133
- package/.agent/workflows/ui-ux-pro-max.md +122 -143
- package/README.md +30 -1
- package/bin/tribunal-kit.js +175 -12
- package/package.json +25 -4
- package/.agent/skills/api-patterns/api-style.md +0 -42
- package/.agent/skills/api-patterns/auth.md +0 -24
- package/.agent/skills/api-patterns/documentation.md +0 -26
- package/.agent/skills/api-patterns/graphql.md +0 -41
- package/.agent/skills/api-patterns/rate-limiting.md +0 -31
- package/.agent/skills/api-patterns/response.md +0 -37
- package/.agent/skills/api-patterns/rest.md +0 -40
- package/.agent/skills/api-patterns/security-testing.md +0 -122
- package/.agent/skills/api-patterns/trpc.md +0 -41
- package/.agent/skills/api-patterns/versioning.md +0 -22
- package/.agent/skills/app-builder/agent-coordination.md +0 -71
- package/.agent/skills/app-builder/feature-building.md +0 -53
- package/.agent/skills/app-builder/project-detection.md +0 -34
- package/.agent/skills/app-builder/scaffolding.md +0 -118
- package/.agent/skills/app-builder/tech-stack.md +0 -40
- package/.agent/skills/architecture/context-discovery.md +0 -43
- package/.agent/skills/architecture/examples.md +0 -94
- package/.agent/skills/architecture/pattern-selection.md +0 -68
- package/.agent/skills/architecture/patterns-reference.md +0 -50
- package/.agent/skills/architecture/trade-off-analysis.md +0 -77
- package/.agent/skills/brainstorming/dynamic-questioning.md +0 -360
- package/.agent/skills/database-design/database-selection.md +0 -43
- package/.agent/skills/database-design/indexing.md +0 -39
- package/.agent/skills/database-design/migrations.md +0 -48
- package/.agent/skills/database-design/optimization.md +0 -36
- package/.agent/skills/database-design/orm-selection.md +0 -30
- package/.agent/skills/database-design/schema-design.md +0 -56
- package/.agent/skills/frontend-design/animation-guide.md +0 -331
- package/.agent/skills/frontend-design/color-system.md +0 -329
- package/.agent/skills/frontend-design/decision-trees.md +0 -418
- package/.agent/skills/frontend-design/motion-graphics.md +0 -306
- package/.agent/skills/frontend-design/typography-system.md +0 -363
- package/.agent/skills/frontend-design/ux-psychology.md +0 -1116
- package/.agent/skills/frontend-design/visual-effects.md +0 -383
- package/.agent/skills/intelligent-routing/router-manifest.md +0 -65
- package/.agent/skills/mobile-design/decision-trees.md +0 -516
- package/.agent/skills/mobile-design/mobile-backend.md +0 -491
- package/.agent/skills/mobile-design/mobile-color-system.md +0 -420
- package/.agent/skills/mobile-design/mobile-debugging.md +0 -122
- package/.agent/skills/mobile-design/mobile-design-thinking.md +0 -357
- package/.agent/skills/mobile-design/mobile-navigation.md +0 -458
- package/.agent/skills/mobile-design/mobile-performance.md +0 -767
- package/.agent/skills/mobile-design/mobile-testing.md +0 -356
- package/.agent/skills/mobile-design/mobile-typography.md +0 -433
- package/.agent/skills/mobile-design/platform-android.md +0 -666
- package/.agent/skills/mobile-design/platform-ios.md +0 -561
- package/.agent/skills/mobile-design/touch-psychology.md +0 -537
- package/.agent/skills/nextjs-react-expert/1-async-eliminating-waterfalls.md +0 -312
- package/.agent/skills/nextjs-react-expert/2-bundle-bundle-size-optimization.md +0 -240
- package/.agent/skills/nextjs-react-expert/3-server-server-side-performance.md +0 -490
- package/.agent/skills/nextjs-react-expert/4-client-client-side-data-fetching.md +0 -264
- package/.agent/skills/nextjs-react-expert/5-rerender-re-render-optimization.md +0 -581
- package/.agent/skills/nextjs-react-expert/6-rendering-rendering-performance.md +0 -432
- package/.agent/skills/nextjs-react-expert/7-js-javascript-performance.md +0 -684
- package/.agent/skills/nextjs-react-expert/8-advanced-advanced-patterns.md +0 -150
- package/.agent/skills/vulnerability-scanner/checklists.md +0 -121
|
@@ -1,901 +1,194 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: gsap-expert
|
|
3
|
-
description: GreenSock Animation Platform (GSAP 3.12+) mastery. Core tweens, timelines, ScrollTrigger,
|
|
3
|
+
description: GreenSock Animation Platform (GSAP 3.12+) mastery. Core tweens, timelines, ScrollTrigger, ScrollSmoother, plugins, React useGSAP hook, responsive animations, performance. Use when building scroll-driven animations, complex sequencing, SVG morphing, or any animation beyond CSS capabilities.
|
|
4
4
|
allowed-tools: Read, Write, Edit, Glob, Grep
|
|
5
|
-
version:
|
|
6
|
-
last-updated: 2026-
|
|
7
|
-
applies-to-model: gemini-
|
|
5
|
+
version: 3.2.0
|
|
6
|
+
last-updated: 2026-04-07
|
|
7
|
+
applies-to-model: gemini-3-1-pro, claude-3-7-sonnet
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
-
# GSAP Expert —
|
|
10
|
+
# GSAP Expert — 3.12+ Dense Reference
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
## Hallucination Traps (Read First)
|
|
13
|
+
- ❌ `gsap.registerPlugin(ScrollTrigger)` optional → ✅ **REQUIRED** before any use — must call before component mounts
|
|
14
|
+
- ❌ `easeInOut`, `Power2.easeOut` (GSAP 2 syntax) → ✅ `"power2.inOut"` (string, GSAP 3)
|
|
15
|
+
- ❌ `raw useEffect` for GSAP in React → ✅ `useGSAP` from `@gsap/react` — handles cleanup automatically
|
|
16
|
+
- ❌ Timeline position as 2nd arg → ✅ position is the **3rd** arg: `tl.to(el, { x: 100 }, "<")`
|
|
17
|
+
- ❌ `markers: true` in production → ✅ Debug only — never ship. `gsap.config({ markers: false })`
|
|
18
|
+
- ❌ Animate `width`, `height`, `top`, `left` → ✅ Only `x`, `y`, `scale`, `rotation`, `opacity` (GPU composited)
|
|
19
|
+
- ❌ 1 ScrollTrigger per list item → ✅ Use `ScrollTrigger.batch()` for lists — 1 battery per N items
|
|
20
|
+
- ❌ `dependencies` option spelled `deps` → ✅ option is `dependencies` (not `deps`)
|
|
21
|
+
- ❌ GSAP in Next.js Server Components → ✅ Always `"use client"` — GSAP is browser-only
|
|
14
22
|
|
|
15
23
|
---
|
|
16
24
|
|
|
17
|
-
##
|
|
25
|
+
## Core Tweens
|
|
18
26
|
|
|
19
|
-
|
|
27
|
+
```javascript
|
|
28
|
+
gsap.to(".box", { x: 100, opacity: 1, duration: 1, ease: "power2.out" });
|
|
29
|
+
gsap.from(".box", { y: -50, opacity: 0, duration: 0.8 });
|
|
30
|
+
gsap.fromTo(".box", { x: -100 }, { x: 0, duration: 1, ease: "expo.out" });
|
|
31
|
+
gsap.set(".box", { transformOrigin: "center center", willChange: "transform" });
|
|
20
32
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
gsap.
|
|
24
|
-
|
|
25
|
-
// gsap.from() — animate FROM target TO current state
|
|
26
|
-
gsap.from(".box", { opacity: 0, y: 50, duration: 0.8 });
|
|
27
|
-
|
|
28
|
-
// gsap.fromTo() — explicit start AND end (most predictable)
|
|
29
|
-
gsap.fromTo(".box",
|
|
30
|
-
{ opacity: 0, y: 30 }, // from
|
|
31
|
-
{ opacity: 1, y: 0, duration: 1 } // to
|
|
32
|
-
);
|
|
33
|
-
|
|
34
|
-
// gsap.set() — instant property set, no animation
|
|
35
|
-
gsap.set(".box", { transformOrigin: "center center" });
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
### Easing
|
|
39
|
-
|
|
40
|
-
GSAP eases follow a `name.type` pattern. The names: `power1`–`power4`, `back`, `bounce`, `elastic`, `circ`, `expo`, `sine`, `steps`.
|
|
41
|
-
|
|
42
|
-
```js
|
|
43
|
-
// Types: .in, .out, .inOut
|
|
44
|
-
ease: "power3.inOut" // smooth acceleration + deceleration
|
|
45
|
-
ease: "back.out(1.7)" // overshoot by 1.7 (default)
|
|
46
|
-
ease: "elastic.out(1, 0.3)" // amplitude, period
|
|
47
|
-
ease: "steps(5)" // stepped animation (sprite sheets)
|
|
48
|
-
ease: "none" // linear
|
|
49
|
-
|
|
50
|
-
// ❌ HALLUCINATION TRAP: These do NOT exist in GSAP 3+
|
|
51
|
-
// ease: "easeInOut" — jQuery syntax, NOT GSAP
|
|
52
|
-
// ease: "Power2.easeOut" — GSAP 2 syntax, DEPRECATED
|
|
53
|
-
// ease: "Cubic.easeIn" — GSAP 2 syntax, DEPRECATED
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
### Duration & Stagger
|
|
57
|
-
|
|
58
|
-
```js
|
|
59
|
-
// Duration is in seconds (NOT milliseconds like CSS/JS setTimeout)
|
|
60
|
-
gsap.to(".items", {
|
|
61
|
-
x: 100,
|
|
62
|
-
duration: 0.6, // 0.6 seconds
|
|
63
|
-
stagger: 0.1, // 0.1s between each element
|
|
64
|
-
|
|
65
|
-
// Advanced stagger object
|
|
66
|
-
stagger: {
|
|
67
|
-
each: 0.1, // time between each
|
|
68
|
-
from: "center", // "start", "center", "end", "edges", "random", or index
|
|
69
|
-
grid: "auto", // for grid layouts
|
|
70
|
-
ease: "power2.in", // ease the stagger distribution itself
|
|
71
|
-
amount: 0.8, // total stagger time (alternative to `each`)
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
### Defaults
|
|
77
|
-
|
|
78
|
-
```js
|
|
79
|
-
// Set project-wide defaults — DRY animation config
|
|
80
|
-
gsap.defaults({
|
|
81
|
-
duration: 0.8,
|
|
82
|
-
ease: "power2.out",
|
|
83
|
-
overwrite: "auto", // auto-kill conflicting tweens on same target
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
// Per-tween overrides always win
|
|
87
|
-
gsap.to(".box", { x: 100, duration: 1.5 }); // uses 1.5, not 0.8
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
### Callbacks & Control
|
|
91
|
-
|
|
92
|
-
```js
|
|
93
|
-
const tween = gsap.to(".box", {
|
|
94
|
-
x: 200,
|
|
95
|
-
onStart: () => console.log("started"),
|
|
96
|
-
onUpdate: (self) => console.log(self.progress()),
|
|
97
|
-
onComplete: () => console.log("done"),
|
|
98
|
-
onReverseComplete: () => console.log("reversed"),
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
// Control methods
|
|
102
|
-
tween.pause();
|
|
103
|
-
tween.resume();
|
|
104
|
-
tween.reverse();
|
|
105
|
-
tween.seek(0.5); // jump to 0.5 seconds
|
|
106
|
-
tween.progress(0.5); // jump to 50%
|
|
107
|
-
tween.kill(); // destroy and garbage collect
|
|
33
|
+
// Stagger (multiple elements)
|
|
34
|
+
gsap.from(".item", { opacity: 0, y: 30, stagger: 0.08, ease: "power3.out" });
|
|
35
|
+
gsap.from(".item", { opacity: 0, stagger: { each: 0.1, from: "center", grid: "auto" } });
|
|
108
36
|
```
|
|
109
37
|
|
|
110
38
|
---
|
|
111
39
|
|
|
112
|
-
##
|
|
113
|
-
|
|
114
|
-
### Sequencing
|
|
115
|
-
|
|
116
|
-
```js
|
|
117
|
-
const tl = gsap.timeline({
|
|
118
|
-
defaults: { duration: 0.5, ease: "power2.out" },
|
|
119
|
-
onComplete: () => console.log("Sequence done"),
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
tl.to(".title", { opacity: 1, y: 0 })
|
|
123
|
-
.to(".subtitle", { opacity: 1, y: 0 }) // plays AFTER .title
|
|
124
|
-
.to(".cta", { scale: 1, opacity: 1 }); // plays AFTER .subtitle
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
### Position Parameter (Critical Concept)
|
|
40
|
+
## Timelines
|
|
128
41
|
|
|
129
|
-
|
|
42
|
+
```javascript
|
|
43
|
+
const tl = gsap.timeline({ defaults: { ease: "power2.out", duration: 0.6 } });
|
|
130
44
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
.
|
|
134
|
-
.to(".
|
|
135
|
-
.to(".d", { x: 100 }, "-=0.3") // 0.3s before previous ends (overlap)
|
|
136
|
-
.to(".e", { x: 100 }, "+=0.5") // 0.5s after previous ends (gap)
|
|
137
|
-
.to(".f", { x: 100 }, 2) // absolute: at exactly 2 seconds
|
|
138
|
-
.to(".g", { x: 100 }, "<0.2") // 0.2s after previous animation's START
|
|
139
|
-
.to(".h", { x: 100 }, ">-0.1"); // 0.1s before previous animation's END
|
|
45
|
+
tl.from(".hero-title", { y: 60, opacity: 0 })
|
|
46
|
+
.from(".hero-sub", { y: 40, opacity: 0 }, "-=0.4") // overlap 0.4s
|
|
47
|
+
.from(".hero-cta", { scale: 0.9, opacity: 0 }, "<0.1") // 0.1s after prev starts
|
|
48
|
+
.to(".hero-img", { x: 0, opacity: 1 }, 0.3); // absolute 0.3s into tl
|
|
140
49
|
|
|
141
|
-
//
|
|
142
|
-
//
|
|
143
|
-
//
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
50
|
+
// Position symbols:
|
|
51
|
+
// "<" → same start time as previous tween
|
|
52
|
+
// ">" → after previous ends
|
|
53
|
+
// "-=0.5" → 0.5s before previous ends (overlap)
|
|
54
|
+
// "+=0.5" → 0.5s after previous ends (gap)
|
|
55
|
+
// "2" → absolute 2s from timeline start
|
|
147
56
|
|
|
148
|
-
|
|
149
|
-
tl.
|
|
150
|
-
.to(".title", { opacity: 1 })
|
|
151
|
-
.addLabel("middle")
|
|
152
|
-
.to(".content", { opacity: 1 })
|
|
153
|
-
.to(".sidebar", { x: 0 }, "middle") // starts at the "middle" label
|
|
154
|
-
.to(".footer", { y: 0 }, "middle+=0.3"); // 0.3s after the "middle" label
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
### Nesting Timelines
|
|
158
|
-
|
|
159
|
-
```js
|
|
160
|
-
function introAnimation() {
|
|
161
|
-
const tl = gsap.timeline();
|
|
162
|
-
tl.from(".hero-title", { y: 60, opacity: 0 })
|
|
163
|
-
.from(".hero-sub", { y: 40, opacity: 0 }, "-=0.3");
|
|
164
|
-
return tl;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
function contentAnimation() {
|
|
168
|
-
const tl = gsap.timeline();
|
|
169
|
-
tl.from(".card", { y: 80, opacity: 0, stagger: 0.15 });
|
|
170
|
-
return tl;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
// Master timeline nests sub-timelines
|
|
174
|
-
const master = gsap.timeline();
|
|
175
|
-
master
|
|
176
|
-
.add(introAnimation())
|
|
177
|
-
.add(contentAnimation(), "-=0.4"); // overlap by 0.4s
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
### Playback Control
|
|
181
|
-
|
|
182
|
-
```js
|
|
183
|
-
const tl = gsap.timeline({ paused: true, repeat: -1, yoyo: true });
|
|
184
|
-
|
|
185
|
-
tl.play();
|
|
186
|
-
tl.pause();
|
|
187
|
-
tl.reverse();
|
|
188
|
-
tl.restart();
|
|
189
|
-
tl.timeScale(2); // 2× speed
|
|
190
|
-
tl.seek("middle"); // jump to label
|
|
191
|
-
tl.totalProgress(); // 0–1 across all repeats
|
|
57
|
+
// Runtime control
|
|
58
|
+
tl.play(); tl.pause(); tl.reverse(); tl.seek(1.5); tl.timeScale(2); // 2x speed
|
|
192
59
|
```
|
|
193
60
|
|
|
194
61
|
---
|
|
195
62
|
|
|
196
|
-
##
|
|
197
|
-
|
|
198
|
-
### Registration (Required)
|
|
63
|
+
## ScrollTrigger
|
|
199
64
|
|
|
200
|
-
```
|
|
65
|
+
```javascript
|
|
201
66
|
import { gsap } from "gsap";
|
|
202
67
|
import { ScrollTrigger } from "gsap/ScrollTrigger";
|
|
68
|
+
gsap.registerPlugin(ScrollTrigger); // REQUIRED — call once at module level
|
|
203
69
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
// ❌ HALLUCINATION TRAP: ScrollTrigger MUST be registered before use
|
|
207
|
-
// Forgetting gsap.registerPlugin() is the #1 GSAP bug in AI-generated code
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
### Basic Scroll-Linked Animation
|
|
211
|
-
|
|
212
|
-
```js
|
|
213
|
-
gsap.to(".parallax-bg", {
|
|
214
|
-
y: -200,
|
|
70
|
+
// Basic scroll-triggered animation
|
|
71
|
+
gsap.from(".section", {
|
|
215
72
|
scrollTrigger: {
|
|
216
|
-
trigger: ".
|
|
217
|
-
start: "top
|
|
218
|
-
end: "bottom
|
|
219
|
-
scrub:
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
```
|
|
224
|
-
|
|
225
|
-
### Start / End Syntax
|
|
226
|
-
|
|
227
|
-
```
|
|
228
|
-
start: "top center" // trigger's top hits viewport's center
|
|
229
|
-
start: "top 80%" // trigger's top hits 80% from viewport top
|
|
230
|
-
start: "top top" // trigger's top hits viewport's top
|
|
231
|
-
start: "center center" // trigger's center hits viewport's center
|
|
232
|
-
start: "top bottom-=100" // 100px before trigger's top hits viewport's bottom
|
|
233
|
-
```
|
|
234
|
-
|
|
235
|
-
### Pinning
|
|
236
|
-
|
|
237
|
-
```js
|
|
238
|
-
ScrollTrigger.create({
|
|
239
|
-
trigger: ".sticky-section",
|
|
240
|
-
start: "top top",
|
|
241
|
-
end: "+=1000", // pin for 1000px of scrolling
|
|
242
|
-
pin: true, // locks element in place
|
|
243
|
-
pinSpacing: true, // adds equivalent space below (default: true)
|
|
244
|
-
anticipatePin: 1, // reduces jank — pre-calculates pin
|
|
245
|
-
});
|
|
246
|
-
```
|
|
247
|
-
|
|
248
|
-
### Scrub
|
|
249
|
-
|
|
250
|
-
```js
|
|
251
|
-
// scrub: true — instant scrub (direct 1:1 with scroll)
|
|
252
|
-
// scrub: 0.5 — smoothed scrub (0.5 second lag behind scroll position)
|
|
253
|
-
// scrub: 3 — heavy smoothing (3 second catch-up, cinematic feel)
|
|
254
|
-
|
|
255
|
-
gsap.to(".progress-bar", {
|
|
256
|
-
scaleX: 1,
|
|
257
|
-
scrollTrigger: {
|
|
258
|
-
trigger: ".article",
|
|
259
|
-
start: "top top",
|
|
260
|
-
end: "bottom bottom",
|
|
261
|
-
scrub: 0.3,
|
|
262
|
-
}
|
|
263
|
-
});
|
|
264
|
-
```
|
|
265
|
-
|
|
266
|
-
### Refresh & Cleanup (Critical)
|
|
267
|
-
|
|
268
|
-
```js
|
|
269
|
-
// Force recalculation after DOM changes (images loaded, content injected)
|
|
270
|
-
ScrollTrigger.refresh();
|
|
271
|
-
|
|
272
|
-
// Batch refresh after many DOM mutations
|
|
273
|
-
ScrollTrigger.refresh(true); // "safe" mode — deferred to next tick
|
|
274
|
-
|
|
275
|
-
// Kill ALL ScrollTriggers (page transitions, SPA navigation)
|
|
276
|
-
ScrollTrigger.killAll();
|
|
277
|
-
|
|
278
|
-
// Kill a specific instance
|
|
279
|
-
const st = ScrollTrigger.create({ /* ... */ });
|
|
280
|
-
st.kill();
|
|
281
|
-
|
|
282
|
-
// ❌ HALLUCINATION TRAP: Failing to kill ScrollTriggers on unmount
|
|
283
|
-
// causes memory leaks, zombie listeners, and broken scroll behavior
|
|
284
|
-
// in SPAs (Next.js, Nuxt, SvelteKit, Remix)
|
|
285
|
-
```
|
|
286
|
-
|
|
287
|
-
### Callbacks
|
|
288
|
-
|
|
289
|
-
```js
|
|
290
|
-
ScrollTrigger.create({
|
|
291
|
-
trigger: ".section",
|
|
292
|
-
start: "top center",
|
|
293
|
-
end: "bottom center",
|
|
294
|
-
onEnter: () => console.log("entered from above"),
|
|
295
|
-
onLeave: () => console.log("left going down"),
|
|
296
|
-
onEnterBack: () => console.log("entered from below"),
|
|
297
|
-
onLeaveBack: () => console.log("left going up"),
|
|
298
|
-
onToggle: (self) => console.log("active:", self.isActive),
|
|
299
|
-
onUpdate: (self) => console.log("progress:", self.progress),
|
|
300
|
-
onRefresh: (self) => console.log("recalculated"),
|
|
301
|
-
});
|
|
302
|
-
```
|
|
303
|
-
|
|
304
|
-
---
|
|
305
|
-
|
|
306
|
-
## gsap-plugins — Plugin Ecosystem
|
|
307
|
-
|
|
308
|
-
### Registration Pattern (All Plugins)
|
|
309
|
-
|
|
310
|
-
```js
|
|
311
|
-
import { gsap } from "gsap";
|
|
312
|
-
import { Flip } from "gsap/Flip";
|
|
313
|
-
import { Draggable } from "gsap/Draggable";
|
|
314
|
-
import { ScrollToPlugin } from "gsap/ScrollToPlugin";
|
|
315
|
-
|
|
316
|
-
gsap.registerPlugin(Flip, Draggable, ScrollToPlugin);
|
|
317
|
-
|
|
318
|
-
// ❌ HALLUCINATION TRAP: Every plugin MUST be registered
|
|
319
|
-
// ❌ HALLUCINATION TRAP: Some plugins require a GSAP Club license
|
|
320
|
-
// (ScrollSmoother, SplitText, Inertia, ScrambleText, MorphSVG, DrawSVG,
|
|
321
|
-
// MotionPath, Physics2D, PhysicsProps, CustomBounce, CustomWiggle)
|
|
322
|
-
// Free plugins: ScrollTrigger, Flip, Draggable, ScrollToPlugin, Observer,
|
|
323
|
-
// TextPlugin, MotionPathPlugin, EasePack, CustomEase, GSDevTools (trial)
|
|
324
|
-
```
|
|
325
|
-
|
|
326
|
-
### Flip Plugin (FLIP Technique)
|
|
327
|
-
|
|
328
|
-
```js
|
|
329
|
-
// 1. Capture current state
|
|
330
|
-
const state = Flip.getState(".cards");
|
|
331
|
-
|
|
332
|
-
// 2. Make DOM change (reparent, reclass, reorder)
|
|
333
|
-
container.classList.toggle("grid-layout");
|
|
334
|
-
|
|
335
|
-
// 3. Animate from old state to new state
|
|
336
|
-
Flip.from(state, {
|
|
337
|
-
duration: 0.6,
|
|
338
|
-
ease: "power2.inOut",
|
|
339
|
-
stagger: 0.05,
|
|
340
|
-
absolute: true, // uses position:absolute during animation
|
|
341
|
-
onComplete: () => console.log("Flip done"),
|
|
342
|
-
});
|
|
343
|
-
```
|
|
344
|
-
|
|
345
|
-
### Draggable
|
|
346
|
-
|
|
347
|
-
```js
|
|
348
|
-
Draggable.create(".slider-handle", {
|
|
349
|
-
type: "x", // "x", "y", "x,y", "rotation"
|
|
350
|
-
bounds: ".slider-track", // constrain to parent
|
|
351
|
-
inertia: true, // requires InertiaPlugin (Club)
|
|
352
|
-
edgeResistance: 0.65, // resistance at bounds edges
|
|
353
|
-
onDrag: function () {
|
|
354
|
-
console.log("x:", this.x); // `this` = Draggable instance
|
|
73
|
+
trigger: ".section",
|
|
74
|
+
start: "top 80%", // "triggerEdge viewportEdge"
|
|
75
|
+
end: "bottom 20%",
|
|
76
|
+
scrub: 1, // smooth scrubbing (seconds to catch up) | true = instant
|
|
77
|
+
pin: true, // pin element during scroll
|
|
78
|
+
anticipatePin: 1, // prevents jump on pin
|
|
79
|
+
markers: false, // NEVER true in production
|
|
355
80
|
},
|
|
356
|
-
|
|
357
|
-
console.log("endX:", this.endX); // projected landing position
|
|
358
|
-
},
|
|
359
|
-
snap: {
|
|
360
|
-
x: (val) => Math.round(val / 50) * 50, // snap to 50px grid
|
|
361
|
-
},
|
|
362
|
-
});
|
|
363
|
-
```
|
|
364
|
-
|
|
365
|
-
### ScrollToPlugin
|
|
366
|
-
|
|
367
|
-
```js
|
|
368
|
-
gsap.to(window, {
|
|
369
|
-
duration: 1,
|
|
370
|
-
scrollTo: { y: "#section-3", offsetY: 80 },
|
|
371
|
-
ease: "power2.inOut",
|
|
81
|
+
y: 100, opacity: 0,
|
|
372
82
|
});
|
|
373
83
|
|
|
374
|
-
//
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
});
|
|
379
|
-
```
|
|
380
|
-
|
|
381
|
-
### ScrollSmoother (Club GreenSock)
|
|
382
|
-
|
|
383
|
-
```js
|
|
384
|
-
// ⚠️ Club GreenSock plugin — requires license
|
|
385
|
-
import { ScrollSmoother } from "gsap/ScrollSmoother";
|
|
386
|
-
|
|
387
|
-
// HTML structure required:
|
|
388
|
-
// <div id="smooth-wrapper">
|
|
389
|
-
// <div id="smooth-content"> ...page... </div>
|
|
390
|
-
// </div>
|
|
391
|
-
|
|
392
|
-
const smoother = ScrollSmoother.create({
|
|
393
|
-
wrapper: "#smooth-wrapper",
|
|
394
|
-
content: "#smooth-content",
|
|
395
|
-
smooth: 1.5, // seconds of smoothing
|
|
396
|
-
effects: true, // enables data-speed and data-lag
|
|
397
|
-
normalizeScroll: true, // prevents mobile address bar jank
|
|
398
|
-
});
|
|
399
|
-
```
|
|
400
|
-
|
|
401
|
-
### Observer
|
|
402
|
-
|
|
403
|
-
```js
|
|
404
|
-
import { Observer } from "gsap/Observer";
|
|
405
|
-
|
|
406
|
-
Observer.create({
|
|
407
|
-
target: window,
|
|
408
|
-
type: "wheel,touch,pointer",
|
|
409
|
-
onUp: () => goToNextSlide(),
|
|
410
|
-
onDown: () => goToPrevSlide(),
|
|
411
|
-
tolerance: 10, // pixel threshold before firing
|
|
412
|
-
preventDefault: true,
|
|
413
|
-
wheelSpeed: -1, // invert wheel direction
|
|
414
|
-
});
|
|
415
|
-
```
|
|
416
|
-
|
|
417
|
-
### SplitText (Club GreenSock)
|
|
418
|
-
|
|
419
|
-
```js
|
|
420
|
-
// ⚠️ Club GreenSock plugin — requires license
|
|
421
|
-
import { SplitText } from "gsap/SplitText";
|
|
422
|
-
|
|
423
|
-
const split = new SplitText(".hero-heading", {
|
|
424
|
-
type: "chars,words,lines",
|
|
425
|
-
linesClass: "split-line",
|
|
84
|
+
// Batch — for lists (1 ST instance per group, not per item)
|
|
85
|
+
ScrollTrigger.batch(".card", {
|
|
86
|
+
onEnter: (elements) => gsap.from(elements, { opacity: 0, y: 40, stagger: 0.08 }),
|
|
87
|
+
start: "top 85%",
|
|
426
88
|
});
|
|
427
89
|
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
rotateX: -60,
|
|
432
|
-
stagger: 0.02,
|
|
433
|
-
duration: 0.6,
|
|
434
|
-
ease: "back.out(1.7)",
|
|
435
|
-
onComplete: () => split.revert(), // CLEANUP — restore original DOM
|
|
90
|
+
// Pin + scrub storytelling
|
|
91
|
+
const tl = gsap.timeline({
|
|
92
|
+
scrollTrigger: { trigger: ".scene", pin: true, scrub: true, end: "+=3000" }
|
|
436
93
|
});
|
|
94
|
+
tl.from(".layer-1", { x: -200 }).from(".layer-2", { x: 200 }, "<");
|
|
437
95
|
|
|
438
|
-
//
|
|
439
|
-
//
|
|
440
|
-
```
|
|
441
|
-
|
|
442
|
-
### CustomEase
|
|
443
|
-
|
|
444
|
-
```js
|
|
445
|
-
import { CustomEase } from "gsap/CustomEase";
|
|
446
|
-
|
|
447
|
-
CustomEase.create("myBounce", "M0,0 C0.14,0 0.27,0.58 0.32,0.82 ...");
|
|
448
|
-
gsap.to(".box", { x: 300, ease: "myBounce" });
|
|
449
|
-
```
|
|
450
|
-
|
|
451
|
-
### GSDevTools
|
|
452
|
-
|
|
453
|
-
```js
|
|
454
|
-
// Debug timeline visually — NEVER ship to production
|
|
455
|
-
import { GSDevTools } from "gsap/GSDevTools";
|
|
456
|
-
|
|
457
|
-
GSDevTools.create({ animation: masterTimeline });
|
|
458
|
-
```
|
|
459
|
-
|
|
460
|
-
---
|
|
461
|
-
|
|
462
|
-
## gsap-utils — Utility Functions
|
|
463
|
-
|
|
464
|
-
```js
|
|
465
|
-
// clamp — constrain a value between min and max
|
|
466
|
-
gsap.utils.clamp(0, 100, 150); // 100
|
|
467
|
-
|
|
468
|
-
// mapRange — remap value from one range to another
|
|
469
|
-
gsap.utils.mapRange(0, 100, 0, 1, 50); // 0.5
|
|
470
|
-
|
|
471
|
-
// normalize — convert a value in a range to 0–1
|
|
472
|
-
gsap.utils.normalize(0, 500, 250); // 0.5
|
|
473
|
-
|
|
474
|
-
// interpolate — blend between values
|
|
475
|
-
gsap.utils.interpolate(0, 100, 0.75); // 75
|
|
476
|
-
gsap.utils.interpolate("red", "blue", 0.5); // blends colors
|
|
477
|
-
gsap.utils.interpolate({ x: 0 }, { x: 100 }, 0.5); // { x: 50 }
|
|
478
|
-
|
|
479
|
-
// random — random value (can be snapped)
|
|
480
|
-
gsap.utils.random(0, 100); // float
|
|
481
|
-
gsap.utils.random(0, 100, 5); // snapped to nearest 5
|
|
482
|
-
gsap.utils.random([10, 20, 30]); // pick from array
|
|
483
|
-
|
|
484
|
-
// snap — snap value to nearest increment or array value
|
|
485
|
-
gsap.utils.snap(10, 23); // 20
|
|
486
|
-
gsap.utils.snap([0, 50, 100], 38); // 50
|
|
487
|
-
|
|
488
|
-
// toArray — convert selector/NodeList to a real array (safe)
|
|
489
|
-
const boxes = gsap.utils.toArray(".box"); // always returns an Array
|
|
490
|
-
|
|
491
|
-
// selector — scoped querySelector factory
|
|
492
|
-
const q = gsap.utils.selector(myRef);
|
|
493
|
-
gsap.to(q(".title"), { opacity: 1 }); // only searches within myRef
|
|
494
|
-
|
|
495
|
-
// wrap — wrap index around an array
|
|
496
|
-
const colors = ["red", "green", "blue"];
|
|
497
|
-
gsap.utils.wrap(colors, 5); // "blue" (wraps around)
|
|
498
|
-
|
|
499
|
-
// pipe — compose multiple utility functions
|
|
500
|
-
const clampAndRound = gsap.utils.pipe(
|
|
501
|
-
gsap.utils.clamp(0, 100),
|
|
502
|
-
Math.round
|
|
503
|
-
);
|
|
504
|
-
clampAndRound(125.7); // 100
|
|
96
|
+
// Cleanup — MANDATORY on SPA route unmount
|
|
97
|
+
ScrollTrigger.killAll(); // in component cleanup / router onChange
|
|
505
98
|
```
|
|
506
99
|
|
|
507
100
|
---
|
|
508
101
|
|
|
509
|
-
##
|
|
510
|
-
|
|
511
|
-
### The `useGSAP` Hook (Official)
|
|
102
|
+
## React Integration (`useGSAP`)
|
|
512
103
|
|
|
513
|
-
```
|
|
104
|
+
```tsx
|
|
514
105
|
import { useGSAP } from "@gsap/react";
|
|
515
106
|
import { gsap } from "gsap";
|
|
107
|
+
import { ScrollTrigger } from "gsap/ScrollTrigger";
|
|
108
|
+
import { useRef } from "react";
|
|
516
109
|
|
|
517
|
-
//
|
|
518
|
-
// useEffect does not scope selectors, does not auto-cleanup, and causes
|
|
519
|
-
// double-animation bugs in React 18+ Strict Mode
|
|
110
|
+
gsap.registerPlugin(ScrollTrigger); // once, outside component
|
|
520
111
|
|
|
521
|
-
function HeroSection() {
|
|
522
|
-
const
|
|
112
|
+
export function HeroSection() {
|
|
113
|
+
const container = useRef<HTMLDivElement>(null);
|
|
523
114
|
|
|
524
115
|
useGSAP(() => {
|
|
525
|
-
// All
|
|
116
|
+
// ✅ All GSAP code here is automatically scoped & cleaned up
|
|
526
117
|
gsap.from(".hero-title", { y: 60, opacity: 0, duration: 0.8 });
|
|
527
|
-
gsap.from(".hero-sub", { y: 40, opacity: 0, duration: 0.6, delay: 0.3 });
|
|
528
|
-
}, { scope: containerRef }); // scope = auto querySelector boundary
|
|
529
|
-
|
|
530
|
-
return (
|
|
531
|
-
<div ref={containerRef}>
|
|
532
|
-
<h1 className="hero-title">Welcome</h1>
|
|
533
|
-
<p className="hero-sub">Subtitle</p>
|
|
534
|
-
</div>
|
|
535
|
-
);
|
|
536
|
-
}
|
|
537
|
-
```
|
|
538
|
-
|
|
539
|
-
### Dependency Array (Re-running Animations)
|
|
540
|
-
|
|
541
|
-
```jsx
|
|
542
|
-
useGSAP(() => {
|
|
543
|
-
gsap.to(".counter", { innerText: count, snap: { innerText: 1 } });
|
|
544
|
-
}, { dependencies: [count], scope: containerRef });
|
|
545
|
-
|
|
546
|
-
// ❌ HALLUCINATION TRAP: The option is called `dependencies`, NOT `deps`
|
|
547
|
-
```
|
|
548
118
|
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
gsap.from(".box", { x: -100, opacity: 0 });
|
|
555
|
-
}, containerRef); // scope
|
|
556
|
-
|
|
557
|
-
return () => ctx.revert(); // CLEANUP — kills all tweens and ScrollTriggers
|
|
558
|
-
}, []);
|
|
559
|
-
|
|
560
|
-
// gsap.context() is GSAP's own cleanup mechanism
|
|
561
|
-
// ctx.revert() kills every tween and ScrollTrigger created inside it
|
|
562
|
-
```
|
|
563
|
-
|
|
564
|
-
### Refs vs. Selectors
|
|
565
|
-
|
|
566
|
-
```jsx
|
|
567
|
-
// ✅ Preferred: useRef + scope
|
|
568
|
-
const boxRef = useRef(null);
|
|
569
|
-
useGSAP(() => {
|
|
570
|
-
gsap.to(boxRef.current, { x: 100 });
|
|
571
|
-
}, { scope: containerRef });
|
|
572
|
-
|
|
573
|
-
// ✅ Also fine: class selectors when scoped
|
|
574
|
-
useGSAP(() => {
|
|
575
|
-
gsap.to(".box", { x: 100 }); // scoped to containerRef
|
|
576
|
-
}, { scope: containerRef });
|
|
577
|
-
|
|
578
|
-
// ❌ BAD: Global selectors without scope
|
|
579
|
-
useGSAP(() => {
|
|
580
|
-
gsap.to(".box", { x: 100 }); // matches ALL .box elements globally
|
|
581
|
-
});
|
|
582
|
-
```
|
|
119
|
+
gsap.from(".hero-card", {
|
|
120
|
+
scrollTrigger: { trigger: ".hero-card", start: "top 80%" },
|
|
121
|
+
y: 40, opacity: 0, stagger: 0.1,
|
|
122
|
+
});
|
|
123
|
+
}, { scope: container, dependencies: [] }); // re-runs when dependencies change
|
|
583
124
|
|
|
584
|
-
|
|
125
|
+
return <div ref={container}><h1 className="hero-title">...</h1></div>;
|
|
126
|
+
}
|
|
585
127
|
|
|
586
|
-
|
|
587
|
-
// Animations must only run on the client
|
|
128
|
+
// With cleanup for dynamic content:
|
|
588
129
|
useGSAP(() => {
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
},
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
"use client"; // ← required at top of component file
|
|
595
|
-
|
|
596
|
-
// ❌ HALLUCINATION TRAP: Do NOT import GSAP in server components
|
|
597
|
-
// GSAP requires `window` and `document` — it will crash on the server
|
|
598
|
-
```
|
|
599
|
-
|
|
600
|
-
---
|
|
601
|
-
|
|
602
|
-
## gsap-performance — Performance Optimization
|
|
603
|
-
|
|
604
|
-
### Transforms Over Layout Properties (Critical)
|
|
605
|
-
|
|
606
|
-
```js
|
|
607
|
-
// ✅ GPU-accelerated (composited — no layout recalculation)
|
|
608
|
-
gsap.to(".box", { x: 100, y: 50, rotation: 45, scale: 1.2, opacity: 0.5 });
|
|
609
|
-
|
|
610
|
-
// ❌ TRIGGERS LAYOUT REFLOW (expensive — avoid animating these)
|
|
611
|
-
gsap.to(".box", { width: 200, height: 100, top: 50, left: 100, padding: 20 });
|
|
612
|
-
|
|
613
|
-
// ❌ HALLUCINATION TRAP: AI often generates `{ left: 100 }` instead of `{ x: 100 }`
|
|
614
|
-
// x/y use CSS transform: translate(), which is GPU-composited
|
|
615
|
-
// left/top trigger layout recalculation on every frame = jank
|
|
616
|
-
```
|
|
617
|
-
|
|
618
|
-
### `will-change` Management
|
|
619
|
-
|
|
620
|
-
```js
|
|
621
|
-
// GSAP auto-applies will-change: transform during animation
|
|
622
|
-
// Do NOT manually add will-change to many elements — it wastes GPU memory
|
|
623
|
-
|
|
624
|
-
// For known long-running animations, apply manually and remove after:
|
|
625
|
-
gsap.set(".persistent-animation", { willChange: "transform" });
|
|
626
|
-
// ... animation runs ...
|
|
627
|
-
gsap.set(".persistent-animation", { willChange: "auto" }); // release GPU memory
|
|
628
|
-
```
|
|
629
|
-
|
|
630
|
-
### Batching & `gsap.ticker`
|
|
631
|
-
|
|
632
|
-
```js
|
|
633
|
-
// Use gsap.ticker instead of requestAnimationFrame for sync
|
|
634
|
-
gsap.ticker.add((time, deltaTime, frame) => {
|
|
635
|
-
// Runs in sync with GSAP's internal RAF loop
|
|
636
|
-
// Use for particle systems, canvas drawing, etc.
|
|
637
|
-
});
|
|
638
|
-
|
|
639
|
-
// Throttle ticker to 30fps (for low-power devices)
|
|
640
|
-
gsap.ticker.fps(30);
|
|
641
|
-
|
|
642
|
-
// Lazy rendering (default: true) — GSAP batches reads/writes
|
|
643
|
-
// Only disable if you need synchronous layout reads mid-animation
|
|
644
|
-
gsap.ticker.lagSmoothing(500, 33); // smooth large frame drops
|
|
645
|
-
```
|
|
646
|
-
|
|
647
|
-
### ScrollTrigger Performance
|
|
648
|
-
|
|
649
|
-
```js
|
|
650
|
-
// ❌ BAD: One ScrollTrigger per item in a long list
|
|
651
|
-
document.querySelectorAll(".item").forEach(item => {
|
|
652
|
-
ScrollTrigger.create({ trigger: item, /* ... */ }); // 100+ instances = jank
|
|
653
|
-
});
|
|
654
|
-
|
|
655
|
-
// ✅ BETTER: Use ScrollTrigger.batch()
|
|
656
|
-
ScrollTrigger.batch(".item", {
|
|
657
|
-
onEnter: (elements) => {
|
|
658
|
-
gsap.from(elements, { opacity: 0, y: 50, stagger: 0.1 });
|
|
659
|
-
},
|
|
660
|
-
onLeave: (elements) => {
|
|
661
|
-
gsap.to(elements, { opacity: 0 });
|
|
662
|
-
},
|
|
663
|
-
});
|
|
664
|
-
|
|
665
|
-
// ❌ HALLUCINATION TRAP: Never use `markers: true` in production
|
|
666
|
-
// It injects visible debug DOM elements
|
|
667
|
-
```
|
|
668
|
-
|
|
669
|
-
### Overwrite Modes
|
|
670
|
-
|
|
671
|
-
```js
|
|
672
|
-
// Prevent conflicting tweens from stacking
|
|
673
|
-
gsap.to(".box", { x: 100, overwrite: "auto" });
|
|
674
|
-
|
|
675
|
-
// Modes:
|
|
676
|
-
// "auto" — kill only conflicting properties on same target (recommended)
|
|
677
|
-
// true — kill ALL tweens on same target
|
|
678
|
-
// false — allow stacking (default, can cause jank)
|
|
130
|
+
const ctx = gsap.context(() => {
|
|
131
|
+
gsap.from(".item", { opacity: 0, stagger: 0.05 });
|
|
132
|
+
}, container);
|
|
133
|
+
return () => ctx.revert(); // explicit cleanup if needed beyond useGSAP scope
|
|
134
|
+
}, { scope: container, dependencies: [items] });
|
|
679
135
|
```
|
|
680
136
|
|
|
681
137
|
---
|
|
682
138
|
|
|
683
|
-
##
|
|
684
|
-
|
|
685
|
-
### Vue 3 (Composition API)
|
|
686
|
-
|
|
687
|
-
```vue
|
|
688
|
-
<script setup>
|
|
689
|
-
import { ref, onMounted, onUnmounted } from "vue";
|
|
690
|
-
import { gsap } from "gsap";
|
|
691
|
-
import { ScrollTrigger } from "gsap/ScrollTrigger";
|
|
692
|
-
|
|
693
|
-
gsap.registerPlugin(ScrollTrigger);
|
|
139
|
+
## Responsive Animations (`gsap.matchMedia`)
|
|
694
140
|
|
|
695
|
-
|
|
696
|
-
|
|
141
|
+
```javascript
|
|
142
|
+
// Replaces window.matchMedia listeners + resize handlers
|
|
143
|
+
const mm = gsap.matchMedia();
|
|
697
144
|
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
scrollTrigger: { trigger: ".box", start: "top 80%" },
|
|
703
|
-
});
|
|
704
|
-
}, containerRef.value); // scope to component root
|
|
145
|
+
mm.add("(min-width: 768px)", () => {
|
|
146
|
+
gsap.to(".sidebar", { x: 0, duration: 0.5 });
|
|
147
|
+
// Return cleanup function
|
|
148
|
+
return () => gsap.set(".sidebar", { x: -300 });
|
|
705
149
|
});
|
|
706
150
|
|
|
707
|
-
|
|
708
|
-
|
|
151
|
+
mm.add("(max-width: 767px)", () => {
|
|
152
|
+
gsap.to(".mobile-menu", { y: 0, duration: 0.4 });
|
|
709
153
|
});
|
|
710
|
-
</script>
|
|
711
|
-
|
|
712
|
-
<template>
|
|
713
|
-
<div ref="containerRef">
|
|
714
|
-
<div class="box">Animated</div>
|
|
715
|
-
</div>
|
|
716
|
-
</template>
|
|
717
|
-
```
|
|
718
|
-
|
|
719
|
-
### Svelte
|
|
720
154
|
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
gsap.registerPlugin(ScrollTrigger);
|
|
728
|
-
|
|
729
|
-
let container;
|
|
730
|
-
let ctx;
|
|
731
|
-
|
|
732
|
-
onMount(() => {
|
|
733
|
-
ctx = gsap.context(() => {
|
|
734
|
-
gsap.from(".box", { y: 60, opacity: 0, duration: 0.8 });
|
|
735
|
-
}, container);
|
|
155
|
+
// In React — use inside useGSAP
|
|
156
|
+
useGSAP(() => {
|
|
157
|
+
const mm = gsap.matchMedia();
|
|
158
|
+
mm.add("(prefers-reduced-motion: no-preference)", () => {
|
|
159
|
+
gsap.from(".hero", { y: 100, duration: 1 });
|
|
736
160
|
});
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
ctx?.revert(); // cleanup on component destroy
|
|
161
|
+
mm.add("(prefers-reduced-motion: reduce)", () => {
|
|
162
|
+
gsap.set(".hero", { opacity: 1 }); // instant, no animation
|
|
740
163
|
});
|
|
741
|
-
</script>
|
|
742
|
-
|
|
743
|
-
<div bind:this={container}>
|
|
744
|
-
<div class="box">Animated</div>
|
|
745
|
-
</div>
|
|
746
|
-
```
|
|
747
|
-
|
|
748
|
-
### Universal Cleanup Rules
|
|
749
|
-
|
|
750
|
-
```
|
|
751
|
-
✅ ALWAYS use gsap.context() in framework components
|
|
752
|
-
✅ ALWAYS call ctx.revert() on unmount/destroy/cleanup
|
|
753
|
-
✅ ALWAYS call ScrollTrigger.kill() or .killAll() on route changes (SPA)
|
|
754
|
-
✅ ALWAYS scope selectors to the component root
|
|
755
|
-
|
|
756
|
-
❌ NEVER leave orphaned ScrollTriggers after navigation
|
|
757
|
-
❌ NEVER use global selectors without scoping in component frameworks
|
|
758
|
-
❌ NEVER forget to revert SplitText instances (corrupts DOM)
|
|
759
|
-
```
|
|
760
|
-
|
|
761
|
-
---
|
|
762
|
-
|
|
763
|
-
## Common Animation Patterns
|
|
764
|
-
|
|
765
|
-
### Fade-In On Scroll (Batch)
|
|
766
|
-
|
|
767
|
-
```js
|
|
768
|
-
ScrollTrigger.batch(".fade-in", {
|
|
769
|
-
onEnter: (elements) => {
|
|
770
|
-
gsap.fromTo(elements,
|
|
771
|
-
{ opacity: 0, y: 40 },
|
|
772
|
-
{ opacity: 1, y: 0, duration: 0.6, stagger: 0.1, ease: "power2.out" }
|
|
773
|
-
);
|
|
774
|
-
},
|
|
775
|
-
start: "top 85%",
|
|
776
|
-
});
|
|
777
|
-
```
|
|
778
|
-
|
|
779
|
-
### Horizontal Scroll Section
|
|
780
|
-
|
|
781
|
-
```js
|
|
782
|
-
const sections = gsap.utils.toArray(".panel");
|
|
783
|
-
|
|
784
|
-
gsap.to(sections, {
|
|
785
|
-
xPercent: -100 * (sections.length - 1),
|
|
786
|
-
ease: "none",
|
|
787
|
-
scrollTrigger: {
|
|
788
|
-
trigger: ".horizontal-container",
|
|
789
|
-
pin: true,
|
|
790
|
-
scrub: 1,
|
|
791
|
-
snap: 1 / (sections.length - 1),
|
|
792
|
-
end: () => "+=" + document.querySelector(".horizontal-container").offsetWidth,
|
|
793
|
-
},
|
|
794
|
-
});
|
|
795
|
-
```
|
|
796
|
-
|
|
797
|
-
### Magnetic Button
|
|
798
|
-
|
|
799
|
-
```js
|
|
800
|
-
const btn = document.querySelector(".magnetic-btn");
|
|
801
|
-
|
|
802
|
-
btn.addEventListener("mousemove", (e) => {
|
|
803
|
-
const { left, top, width, height } = btn.getBoundingClientRect();
|
|
804
|
-
const x = (e.clientX - left - width / 2) * 0.3;
|
|
805
|
-
const y = (e.clientY - top - height / 2) * 0.3;
|
|
806
|
-
gsap.to(btn, { x, y, duration: 0.3, ease: "power2.out" });
|
|
807
|
-
});
|
|
808
|
-
|
|
809
|
-
btn.addEventListener("mouseleave", () => {
|
|
810
|
-
gsap.to(btn, { x: 0, y: 0, duration: 0.5, ease: "elastic.out(1, 0.3)" });
|
|
811
|
-
});
|
|
812
|
-
```
|
|
813
|
-
|
|
814
|
-
### Counter / Number Ticker
|
|
815
|
-
|
|
816
|
-
```js
|
|
817
|
-
const obj = { val: 0 };
|
|
818
|
-
gsap.to(obj, {
|
|
819
|
-
val: 12847,
|
|
820
|
-
duration: 2,
|
|
821
|
-
ease: "power1.out",
|
|
822
|
-
snap: { val: 1 },
|
|
823
|
-
onUpdate: () => {
|
|
824
|
-
document.querySelector(".counter").textContent = obj.val.toLocaleString();
|
|
825
|
-
},
|
|
826
164
|
});
|
|
827
165
|
```
|
|
828
166
|
|
|
829
167
|
---
|
|
830
168
|
|
|
831
|
-
##
|
|
169
|
+
## Plugin Reference
|
|
832
170
|
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
❌ Blocked: [blocking issues requiring fix, or "None"]
|
|
844
|
-
─────────────────────────────────────────────────
|
|
845
|
-
VBC status: PENDING → VERIFIED
|
|
846
|
-
Evidence: [test output / lint pass / compile success]
|
|
847
|
-
```
|
|
848
|
-
|
|
849
|
-
**VBC (Verification-Before-Completion) is mandatory.**
|
|
850
|
-
Do not mark status as VERIFIED until concrete terminal evidence is provided.
|
|
171
|
+
| Plugin | Use For | Registration |
|
|
172
|
+
|--------|---------|-------------|
|
|
173
|
+
| `ScrollTrigger` | Scroll-driven animations | `gsap.registerPlugin(ScrollTrigger)` |
|
|
174
|
+
| `ScrollSmoother` | Smooth native scroll momentum | Requires `ScrollTrigger` + Club GSAP |
|
|
175
|
+
| `Flip` | Stateful layout morphing (FLIP technique) | `gsap.registerPlugin(Flip)` |
|
|
176
|
+
| `Draggable` | Interactive drag/sort/resize | `gsap.registerPlugin(Draggable)` |
|
|
177
|
+
| `SplitText` | Character/word/line text splits | Call `.revert()` after use to prevent SEO damage |
|
|
178
|
+
| `DrawSVG` | SVG stroke-dasharray animations | Club GSAP |
|
|
179
|
+
| `MorphSVG` | SVG path morphing | Club GSAP |
|
|
180
|
+
| `ScrollToPlugin` | Programmatic scroll-to | `gsap.registerPlugin(ScrollToPlugin)` |
|
|
851
181
|
|
|
852
182
|
---
|
|
853
183
|
|
|
854
|
-
##
|
|
855
|
-
|
|
856
|
-
AI coding assistants often fall into specific bad habits when generating GSAP code. These are strictly forbidden:
|
|
857
|
-
|
|
858
|
-
1. **GSAP v2 Syntax:** Using `TweenMax`, `TweenLite`, `TimelineMax`, `TimelineLite`, `Power2.easeOut`, or `CSSPlugin`. These are ALL deprecated in GSAP 3+. The correct API is `gsap.to()`, `gsap.timeline()`, and `ease: "power2.out"`.
|
|
859
|
-
2. **Missing Plugin Registration:** Every GSAP plugin MUST be registered with `gsap.registerPlugin()` before use. This includes ScrollTrigger, Flip, Draggable, etc.
|
|
860
|
-
3. **Missing Cleanup:** Every `gsap.context()` must have a corresponding `.revert()` on unmount. Every `ScrollTrigger` must be `.kill()`ed. Orphaned animations cause memory leaks.
|
|
861
|
-
4. **Layout Props Instead of Transforms:** Animating `width`, `height`, `top`, `left`, `margin`, `padding` instead of `x`, `y`, `scale`, `rotation`. Layout props trigger expensive reflows.
|
|
862
|
-
5. **Using `useEffect` Instead of `useGSAP`:** In React, always prefer the official `@gsap/react` `useGSAP` hook. It handles scoping, cleanup, and React 18+ Strict Mode.
|
|
863
|
-
6. **Hallucinating Easing Names:** `easeInOut`, `Cubic.easeIn`, `easeOutBounce` do NOT exist. Correct format: `power2.inOut`, `bounce.out`, `elastic.out(1, 0.3)`.
|
|
864
|
-
7. **Confusing `duration` Units:** GSAP uses seconds. CSS uses milliseconds. `duration: 300` in GSAP means 5 minutes, not 300ms.
|
|
865
|
-
8. **Shipping `markers: true`:** Debug markers must never reach production.
|
|
866
|
-
9. **Hallucinated Imports:** Using `import gsap from "gsap"` (default import) instead of `import { gsap } from "gsap"` (named import). Both work, but named is the documented standard.
|
|
867
|
-
10. **Inventing Plugin Names:** Only use real GSAP plugins. There is no `ParallaxPlugin`, `FadePlugin`, or `AnimatePlugin`.
|
|
868
|
-
|
|
869
|
-
---
|
|
184
|
+
## Performance Rules
|
|
870
185
|
|
|
871
|
-
## 🏛️ Tribunal Integration (Anti-Hallucination)
|
|
872
|
-
|
|
873
|
-
**Slash command: `/review` or `/tribunal-full`**
|
|
874
|
-
**Active reviewers: `logic-reviewer` · `security-auditor` · `performance-optimizer`**
|
|
875
|
-
|
|
876
|
-
### ❌ Forbidden AI Tropes
|
|
877
|
-
|
|
878
|
-
1. **Blind Assumptions:** Never make an assumption without documenting it clearly with `// VERIFY: [reason]`.
|
|
879
|
-
2. **Silent Degradation:** Catching and suppressing GSAP errors without logging or handling.
|
|
880
|
-
3. **Context Amnesia:** Forgetting the user's constraints (e.g., generating Club plugin code when the user has a free license).
|
|
881
|
-
4. **Over-Animating:** Adding animations to every element "because it looks cool." Every animation must serve a UX purpose.
|
|
882
|
-
|
|
883
|
-
### ✅ Pre-Flight Self-Audit
|
|
884
|
-
|
|
885
|
-
Review these questions before confirming output:
|
|
886
186
|
```
|
|
887
|
-
✅
|
|
888
|
-
|
|
889
|
-
✅
|
|
890
|
-
✅
|
|
891
|
-
✅
|
|
892
|
-
✅
|
|
893
|
-
|
|
894
|
-
✅ Did I respect prefers-reduced-motion for accessibility?
|
|
187
|
+
✅ Animate: x, y, scale, rotation, skewX/Y, opacity (GPU composited transforms)
|
|
188
|
+
❌ Never: width, height, top, left, padding, margin (triggers layout/paint)
|
|
189
|
+
✅ Use willChange: "transform" on elements that will animate
|
|
190
|
+
✅ overwrite: "auto" to kill conflicting tweens automatically
|
|
191
|
+
✅ ScrollTrigger.batch() for lists — NOT 1 instance per item
|
|
192
|
+
✅ gsap.ticker.lagSmoothing(0) in high-framerate contexts (optional)
|
|
193
|
+
❌ Don't animate SVG path 'd' attribute directly — use MorphSVG plugin
|
|
895
194
|
```
|
|
896
|
-
|
|
897
|
-
### 🛑 Verification-Before-Completion (VBC) Protocol
|
|
898
|
-
|
|
899
|
-
**CRITICAL:** You must follow a strict "evidence-based closeout" state machine.
|
|
900
|
-
- ❌ **Forbidden:** Declaring a task complete because the output "looks correct."
|
|
901
|
-
- ✅ **Required:** You are explicitly forbidden from finalizing any task without providing **concrete evidence** (terminal output, passing tests, compile success, or equivalent proof) that your output works as intended.
|