@polymorphism-tech/morph-spec 4.15.0 → 4.17.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.
Files changed (100) hide show
  1. package/README.md +2 -2
  2. package/bin/morph-spec.js +4 -0
  3. package/bin/task-manager.js +999 -962
  4. package/claude-plugin.json +1 -1
  5. package/docs/CHEATSHEET.md +1 -1
  6. package/docs/QUICKSTART.md +1 -1
  7. package/framework/agents/ai-agents/vector-search-expert.md +247 -233
  8. package/framework/agents/backend/ms-agent-expert.md +2 -1
  9. package/framework/agents/backend/neon-expert.md +397 -0
  10. package/framework/agents/frontend/gsap-animator.md +131 -0
  11. package/framework/agents.json +1175 -1077
  12. package/framework/commands/morph-preflight.md +200 -192
  13. package/framework/hooks/claude-code/session-start/inject-morph-context.js +1 -1
  14. package/framework/rules/gsap-standards.md +13 -0
  15. package/framework/rules/neon-standards.md +25 -0
  16. package/framework/skills/level-0-meta/mcp-registry.json +1 -1
  17. package/framework/skills/level-0-meta/morph-agent-teams/SKILL.md +472 -472
  18. package/framework/skills/level-0-meta/morph-init/SKILL.md +30 -11
  19. package/framework/skills/level-0-meta/morph-post-implementation/SKILL.md +5 -5
  20. package/framework/skills/level-0-meta/morph-tool-usage-guide/SKILL.md +5 -5
  21. package/framework/skills/level-0-meta/morph-tool-usage-guide/references/tools-per-phase.md +7 -7
  22. package/framework/skills/level-1-workflows/morph-phase-codebase-analysis/SKILL.md +24 -24
  23. package/framework/skills/level-1-workflows/morph-phase-design/SKILL.md +12 -12
  24. package/framework/skills/level-1-workflows/morph-phase-implement/SKILL.md +9 -9
  25. package/framework/skills/level-1-workflows/morph-phase-plan/SKILL.md +1 -1
  26. package/framework/skills/level-1-workflows/morph-phase-tasks/SKILL.md +1 -1
  27. package/framework/skills/level-1-workflows/morph-phase-tasks/references/task-planning-patterns.md +143 -143
  28. package/framework/skills/level-1-workflows/morph-phase-uiux/SKILL.md +1 -1
  29. package/framework/skills/level-1-workflows/morph-scope-escalation/SKILL.md +1 -1
  30. package/framework/standards/STANDARDS.json +184 -107
  31. package/framework/standards/ai-agents/production.md +1 -0
  32. package/framework/standards/ai-agents/setup.md +3 -2
  33. package/framework/standards/ai-agents/workflows.md +1 -0
  34. package/framework/standards/architecture/vertical-slice/vertical-slice.md +4 -4
  35. package/framework/standards/backend/database/postgresql/database.md +58 -78
  36. package/framework/standards/backend/dotnet/scalar-ui.md +172 -172
  37. package/framework/standards/backend/dotnet/vsa-handler-patterns.md +274 -274
  38. package/framework/standards/backend/integrations/asaas/asaas-api.md +1 -1
  39. package/framework/standards/backend/integrations/clerk/clerk-auth.md +23 -21
  40. package/framework/standards/frontend/design-system/animations.md +9 -0
  41. package/framework/standards/frontend/gsap/gsap-core.md +463 -0
  42. package/framework/standards/frontend/gsap/gsap-plugins.md +294 -0
  43. package/framework/standards/frontend/gsap/gsap-scrolltrigger.md +318 -0
  44. package/framework/standards/frontend/nextjs/motion-patterns.md +1 -0
  45. package/framework/standards/frontend/nextjs/nextjs-patterns.md +47 -37
  46. package/framework/standards/infrastructure/docker/easypanel-deploy.md +4 -8
  47. package/framework/standards/infrastructure/neon/neon-pgrag.md +239 -0
  48. package/framework/standards/infrastructure/neon/neon-pgvector.md +236 -0
  49. package/framework/standards/infrastructure/neon/neon-semantic-kernel.md +310 -0
  50. package/framework/standards/infrastructure/neon/neon-setup.md +186 -0
  51. package/framework/standards/integration/mcp/mcp-tools.md +32 -34
  52. package/framework/templates/README.md +18 -18
  53. package/framework/templates/REGISTRY.json +49 -96
  54. package/framework/templates/code/dotnet/abstractions/api-endpoint.cs +7 -7
  55. package/framework/templates/code/dotnet/backend/repository.cs +148 -148
  56. package/framework/templates/code/dotnet/contracts/contracts-vsa.cs +2 -2
  57. package/framework/templates/code/dotnet/database/vector-entity.cs +93 -0
  58. package/framework/templates/code/dotnet/feature/endpoint.cs.hbs +1 -1
  59. package/framework/templates/code/sql/{supabase-migration.sql → postgresql-migration.sql} +8 -17
  60. package/framework/templates/code/sql/{supabase-migration.template.sql → postgresql-migration.template.sql} +10 -13
  61. package/framework/templates/code/sql/{rls-policy.sql → postgresql-rls-policy.sql} +8 -8
  62. package/framework/templates/code/typescript/contracts.ts +167 -168
  63. package/framework/templates/context/CONTEXT.md +3 -3
  64. package/framework/templates/docs/proposal.md +6 -6
  65. package/framework/templates/docs/ui-components.md +1 -1
  66. package/framework/templates/feature/decisions.md +121 -121
  67. package/framework/templates/feature/recap.md +145 -145
  68. package/framework/templates/feature/tasks.md +199 -199
  69. package/framework/templates/frontend/nextjs/gsap-scroll-section.tsx.hbs +44 -0
  70. package/framework/templates/infrastructure/docker/docker-compose.template.yml +50 -67
  71. package/framework/templates/infrastructure/docker/dockerfile-api.dockerfile +38 -38
  72. package/framework/templates/infrastructure/docker/dockerfile-web.dockerfile +48 -48
  73. package/framework/templates/infrastructure/docker/easypanel.template.json +46 -54
  74. package/framework/templates/infrastructure/github/README.md +56 -56
  75. package/framework/templates/integrations/semantic-kernel-neon.cs +125 -0
  76. package/framework/workflows/README.md +1 -1
  77. package/framework/workflows/docs/full-morph.md +69 -69
  78. package/package.json +1 -1
  79. package/src/commands/agents/dispatch-agents.js +19 -15
  80. package/src/commands/project/setup-infra-cmd.js +1 -1
  81. package/src/commands/state/advance-phase.js +5 -0
  82. package/src/commands/tasks/task.js +3 -0
  83. package/src/core/state/state-manager.js +45 -1
  84. package/src/core/templates/template-registry.js +1 -66
  85. package/src/lib/detectors/index.js +2 -2
  86. package/src/lib/generators/architecture-scanner.js +640 -640
  87. package/src/lib/installers/mcp-installer.js +1 -1
  88. package/src/lib/tasks/task-classifier.js +15 -1
  89. package/src/lib/tasks/test-runner.js +5 -1
  90. package/src/lib/validators/content/content-validator.js +9 -10
  91. package/src/lib/validators/validation-runner.js +7 -5
  92. package/src/scripts/setup-infra.js +60 -30
  93. package/framework/agents/backend/supabase-expert.md +0 -256
  94. package/framework/rules/supabase-standards.md +0 -29
  95. package/framework/standards/infrastructure/supabase/mcp-setup.md +0 -142
  96. package/framework/standards/infrastructure/supabase/supabase-auth.md +0 -176
  97. package/framework/standards/infrastructure/supabase/supabase-custom-jwt.md +0 -206
  98. package/framework/standards/infrastructure/supabase/supabase-pgvector.md +0 -169
  99. package/framework/standards/infrastructure/supabase/supabase-rls.md +0 -184
  100. package/framework/standards/infrastructure/supabase/supabase-storage.md +0 -153
@@ -0,0 +1,463 @@
1
+ ---
2
+ scope: frontend-nextjs-ui
3
+ layer: 3
4
+ keywords: gsap, animation, timeline, tween, useGSAP, greensock, transform
5
+ load_when: gsap-animator active
6
+ ---
7
+
8
+ # GSAP Core & React Integration
9
+
10
+ Reference guide for implementing animations in Next.js projects using GSAP and the official @gsap/react bindings. Covers core APIs, React integration via useGSAP, timeline sequencing, utility functions, performance, accessibility, and the decision boundary with Framer Motion.
11
+
12
+ ---
13
+
14
+ ## Section 1: When to Use GSAP vs Framer Motion
15
+
16
+ | Need | Use | Why |
17
+ |---|---|---|
18
+ | Simple enter/exit, layout animations, gestures | Framer Motion | Declarative, React-native, less boilerplate |
19
+ | ScrollTrigger (pin, scrub, parallax) | GSAP | No Framer equivalent for scroll-linked progress |
20
+ | SVG morphing, path drawing | GSAP | MorphSVG, DrawSVG plugins |
21
+ | Complex multi-step timelines | GSAP | Position parameter, labels, nested timelines |
22
+ | SplitText, scramble effects | GSAP | Premium plugins, no Framer equivalent |
23
+ | Drag with physics/inertia | GSAP | Draggable + InertiaPlugin |
24
+ | AnimatePresence (mount/unmount) | Framer Motion | GSAP has no declarative mount/unmount |
25
+
26
+ **CRITICAL RULE:** Never animate the same DOM element with both GSAP and Framer Motion simultaneously. They will fight for control of inline styles. Choose one library per element and stick with it.
27
+
28
+ ---
29
+
30
+ ## Section 2: Installation
31
+
32
+ ```bash
33
+ npm install gsap @gsap/react
34
+ ```
35
+
36
+ GSAP 3.12+ includes Flip, Observer, and ScrollToPlugin for free. Premium plugins (SplitText, MorphSVG, DrawSVG, MotionPath, Draggable, InertiaPlugin) require a Club GreenSock license — install via `gsap@npm:@gsap/shockingly`.
37
+
38
+ ### Plugin Registration
39
+
40
+ Register plugins **once** at app init (e.g., `providers.tsx` or `layout.tsx`), not inside individual components:
41
+
42
+ ```typescript
43
+ 'use client';
44
+ import gsap from 'gsap';
45
+ import { ScrollTrigger } from 'gsap/ScrollTrigger';
46
+ import { Flip } from 'gsap/Flip';
47
+
48
+ gsap.registerPlugin(ScrollTrigger, Flip);
49
+ ```
50
+
51
+ Registering inside components causes redundant calls on every mount and risks race conditions if multiple components register different plugins.
52
+
53
+ ---
54
+
55
+ ## Section 3: Core Animation APIs
56
+
57
+ ### Tween Methods
58
+
59
+ ```typescript
60
+ 'use client';
61
+ import gsap from 'gsap';
62
+
63
+ // Animate FROM current state TO target
64
+ gsap.to('.box', { x: 200, opacity: 1, duration: 0.5 });
65
+
66
+ // Animate FROM target TO current state
67
+ gsap.from('.box', { x: -200, opacity: 0, duration: 0.5 });
68
+
69
+ // Explicit start and end states
70
+ gsap.fromTo('.box',
71
+ { x: -200, opacity: 0 },
72
+ { x: 200, opacity: 1, duration: 0.5 }
73
+ );
74
+
75
+ // Instantly set properties (no animation)
76
+ gsap.set('.box', { x: 0, opacity: 1 });
77
+ ```
78
+
79
+ ### Transform Shorthand Aliases
80
+
81
+ GSAP provides shorthand aliases that map directly to CSS transforms:
82
+
83
+ | Alias | CSS Equivalent |
84
+ |---|---|
85
+ | `x`, `y` | `translateX()`, `translateY()` |
86
+ | `xPercent`, `yPercent` | `translateX(%)`, `translateY(%)` |
87
+ | `rotation` | `rotate()` |
88
+ | `scale`, `scaleX`, `scaleY` | `scale()`, `scaleX()`, `scaleY()` |
89
+ | `skewX`, `skewY` | `skewX()`, `skewY()` |
90
+
91
+ ### autoAlpha
92
+
93
+ Use `autoAlpha` instead of `opacity`. It behaves identically to `opacity` but automatically sets `visibility: hidden` when the value reaches 0, removing the element from the accessibility tree and preventing invisible click targets.
94
+
95
+ ```typescript
96
+ 'use client';
97
+ import gsap from 'gsap';
98
+
99
+ // Element becomes visibility:hidden at autoAlpha:0
100
+ gsap.to('.overlay', { autoAlpha: 0, duration: 0.3 });
101
+
102
+ // Reveal: sets visibility:visible then animates opacity
103
+ gsap.to('.overlay', { autoAlpha: 1, duration: 0.3 });
104
+ ```
105
+
106
+ ---
107
+
108
+ ## Section 4: React/Next.js Integration
109
+
110
+ The `useGSAP()` hook from `@gsap/react` is the canonical pattern for GSAP in React. It replaces manual `useEffect` + `gsap.context()` cleanup.
111
+
112
+ ```typescript
113
+ 'use client';
114
+ import { useRef } from 'react';
115
+ import { useGSAP } from '@gsap/react';
116
+ import gsap from 'gsap';
117
+
118
+ function AnimatedComponent() {
119
+ const containerRef = useRef<HTMLDivElement>(null);
120
+
121
+ useGSAP(() => {
122
+ gsap.to('.box', { x: 100, rotation: 360, duration: 1 });
123
+ }, { scope: containerRef }); // scopes selectors to this container
124
+
125
+ return (
126
+ <div ref={containerRef}>
127
+ <div className="box">Animated</div>
128
+ </div>
129
+ );
130
+ }
131
+ ```
132
+
133
+ ### Scope Refs
134
+
135
+ **ALWAYS** pass `{ scope: containerRef }` to `useGSAP`. This scopes all string selectors (e.g., `'.box'`) to descendants of that container, preventing your animations from accidentally targeting elements in other components.
136
+
137
+ ### contextSafe for Event Handlers
138
+
139
+ Animations created outside the `useGSAP` callback (e.g., in click handlers) must be wrapped with `contextSafe()` to ensure proper cleanup:
140
+
141
+ ```typescript
142
+ 'use client';
143
+ import { useRef } from 'react';
144
+ import { useGSAP } from '@gsap/react';
145
+ import gsap from 'gsap';
146
+
147
+ function ClickAnimated() {
148
+ const containerRef = useRef<HTMLDivElement>(null);
149
+
150
+ const { contextSafe } = useGSAP({ scope: containerRef });
151
+
152
+ const handleClick = contextSafe(() => {
153
+ gsap.to('.box', { rotation: '+=360', duration: 0.6 });
154
+ });
155
+
156
+ return (
157
+ <div ref={containerRef}>
158
+ <div className="box" onClick={handleClick}>Click me</div>
159
+ </div>
160
+ );
161
+ }
162
+ ```
163
+
164
+ ### Dependencies Array
165
+
166
+ Pass a dependencies array as the second element of the options to re-run the animation when values change:
167
+
168
+ ```typescript
169
+ 'use client';
170
+ import { useState, useRef } from 'react';
171
+ import { useGSAP } from '@gsap/react';
172
+ import gsap from 'gsap';
173
+
174
+ function ResponsiveAnimation() {
175
+ const containerRef = useRef<HTMLDivElement>(null);
176
+ const [isOpen, setIsOpen] = useState(false);
177
+
178
+ useGSAP(() => {
179
+ gsap.to('.panel', { height: isOpen ? 'auto' : 0, duration: 0.4 });
180
+ }, { scope: containerRef, dependencies: [isOpen] });
181
+
182
+ return (
183
+ <div ref={containerRef}>
184
+ <button onClick={() => setIsOpen(!isOpen)}>Toggle</button>
185
+ <div className="panel">Content</div>
186
+ </div>
187
+ );
188
+ }
189
+ ```
190
+
191
+ ### Cleanup
192
+
193
+ `useGSAP` handles cleanup automatically. When the component unmounts, all GSAP animations created inside the callback are reverted and killed. There is no need to manually call `.kill()` or `.revert()`.
194
+
195
+ **CRITICAL:** All GSAP code MUST be in `'use client'` components. GSAP cannot run server-side — it depends on the DOM and `window` object.
196
+
197
+ ---
198
+
199
+ ## Section 5: Timeline Sequencing
200
+
201
+ `gsap.timeline()` sequences multiple animations with precise timing control.
202
+
203
+ ### Position Parameter Syntax
204
+
205
+ | Syntax | Meaning |
206
+ |---|---|
207
+ | `1` | At absolute time 1 second |
208
+ | `"+=0.5"` | 0.5s after the end of the previous animation |
209
+ | `"-=0.2"` | 0.2s before the end of the previous animation (overlap) |
210
+ | `"reveal"` | At the label named "reveal" |
211
+ | `"<"` | At the start of the previous animation |
212
+ | `">"` | At the end of the previous animation |
213
+ | `"<0.2"` | 0.2s after the start of the previous animation |
214
+
215
+ ### Complete Timeline Example
216
+
217
+ ```typescript
218
+ 'use client';
219
+ import { useRef } from 'react';
220
+ import { useGSAP } from '@gsap/react';
221
+ import gsap from 'gsap';
222
+ import { durations } from '@/lib/design-tokens';
223
+
224
+ function HeroTimeline() {
225
+ const containerRef = useRef<HTMLDivElement>(null);
226
+
227
+ useGSAP(() => {
228
+ const tl = gsap.timeline({
229
+ defaults: { duration: durations.base, ease: 'power2.out' },
230
+ });
231
+
232
+ tl.from('.hero-bg', { autoAlpha: 0, scale: 1.1 })
233
+ .addLabel('reveal')
234
+ .from('.hero-title', { y: 40, autoAlpha: 0 }, 'reveal')
235
+ .from('.hero-subtitle', { y: 30, autoAlpha: 0 }, 'reveal+=0.15')
236
+ .from('.hero-cta', { y: 20, autoAlpha: 0 }, '>-0.1')
237
+ .from('.hero-badges', { autoAlpha: 0, stagger: 0.08 }, '<0.2');
238
+
239
+ // Nested timeline
240
+ const cardsTl = gsap.timeline({ defaults: { duration: durations.fast } });
241
+ cardsTl.from('.card', { y: 60, autoAlpha: 0, stagger: 0.1 });
242
+
243
+ tl.add(cardsTl, 'reveal+=0.4');
244
+ }, { scope: containerRef });
245
+
246
+ return (
247
+ <div ref={containerRef}>
248
+ <div className="hero-bg" />
249
+ <h1 className="hero-title">Title</h1>
250
+ <p className="hero-subtitle">Subtitle</p>
251
+ <button className="hero-cta">Get Started</button>
252
+ <div className="hero-badges">
253
+ <span className="card">A</span>
254
+ <span className="card">B</span>
255
+ <span className="card">C</span>
256
+ </div>
257
+ </div>
258
+ );
259
+ }
260
+ ```
261
+
262
+ ### Playback Controls
263
+
264
+ ```typescript
265
+ const tl = gsap.timeline({ paused: true });
266
+
267
+ tl.play(); // play from current position
268
+ tl.pause(); // pause at current position
269
+ tl.reverse(); // play in reverse
270
+ tl.restart(); // restart from beginning
271
+ tl.progress(0.5); // jump to 50%
272
+ tl.seek('reveal'); // jump to label
273
+ ```
274
+
275
+ ---
276
+
277
+ ## Section 6: Utility Functions
278
+
279
+ `gsap.utils` provides composable helper functions. Omitting the last value argument returns a reusable function.
280
+
281
+ ```typescript
282
+ 'use client';
283
+ import gsap from 'gsap';
284
+
285
+ // Convert NodeList/selector to array
286
+ const items = gsap.utils.toArray<HTMLElement>('.items');
287
+
288
+ // Clamp value between min and max
289
+ gsap.utils.clamp(0, 100, 150); // 100
290
+ const clamp0to100 = gsap.utils.clamp(0, 100); // reusable
291
+ clamp0to100(150); // 100
292
+
293
+ // Map value from one range to another
294
+ gsap.utils.mapRange(0, 1, 0, 100, 0.5); // 50
295
+ const normalize = gsap.utils.mapRange(0, 1, 0, 100); // reusable
296
+
297
+ // Snap to nearest grid value
298
+ gsap.utils.snap(10, 23); // 20
299
+ const snapTo5 = gsap.utils.snap(5); // reusable
300
+
301
+ // Interpolate between two values
302
+ gsap.utils.interpolate(0, 100, 0.5); // 50
303
+
304
+ // Compose utility functions into a pipeline
305
+ const process = gsap.utils.pipe(
306
+ gsap.utils.clamp(0, 100),
307
+ gsap.utils.snap(5)
308
+ );
309
+ process(103); // 100 (clamped), then 100 (snapped)
310
+
311
+ // Scoped selector (useful in components)
312
+ const q = gsap.utils.selector(containerRef.current);
313
+ gsap.to(q('.title'), { y: -20 });
314
+ ```
315
+
316
+ ---
317
+
318
+ ## Section 7: Performance
319
+
320
+ - **Animate ONLY transform properties** (`x`, `y`, `scale`, `rotation`) and `opacity` — these use the GPU compositor and skip layout/paint.
321
+ - **AVOID layout-triggering properties** (`width`, `height`, `top`, `left`, `margin`, `padding`) — they cause full layout recalculation.
322
+ - Apply `will-change: transform` ONLY on elements that are actively animating, and remove it after the animation completes.
323
+ - Use `gsap.quickTo()` for high-frequency updates such as mouse followers and cursor tracking:
324
+
325
+ ```typescript
326
+ 'use client';
327
+ import { useRef } from 'react';
328
+ import { useGSAP } from '@gsap/react';
329
+ import gsap from 'gsap';
330
+
331
+ function CursorFollower() {
332
+ const cursorRef = useRef<HTMLDivElement>(null);
333
+
334
+ useGSAP(() => {
335
+ const xTo = gsap.quickTo(cursorRef.current, 'x', { duration: 0.3, ease: 'power3' });
336
+ const yTo = gsap.quickTo(cursorRef.current, 'y', { duration: 0.3, ease: 'power3' });
337
+
338
+ const handleMouseMove = (e: MouseEvent) => {
339
+ xTo(e.clientX);
340
+ yTo(e.clientY);
341
+ };
342
+
343
+ window.addEventListener('mousemove', handleMouseMove);
344
+ return () => window.removeEventListener('mousemove', handleMouseMove);
345
+ });
346
+
347
+ return <div ref={cursorRef} className="cursor-dot" />;
348
+ }
349
+ ```
350
+
351
+ - Use the `stagger` property instead of creating individual tweens for each element.
352
+ - Batch DOM reads before writes to prevent layout thrashing.
353
+ - Kill off-screen animations and debounce `ScrollTrigger.refresh()` on resize.
354
+
355
+ ---
356
+
357
+ ## Section 8: Accessibility
358
+
359
+ **MANDATORY:** Every animated component must respect `prefers-reduced-motion`.
360
+
361
+ ```typescript
362
+ 'use client';
363
+ import { useRef } from 'react';
364
+ import { useGSAP } from '@gsap/react';
365
+ import gsap from 'gsap';
366
+
367
+ // Option A: gsap.matchMedia (recommended)
368
+ function ScrollHero() {
369
+ const containerRef = useRef<HTMLDivElement>(null);
370
+
371
+ useGSAP(() => {
372
+ gsap.matchMedia().add('(prefers-reduced-motion: no-preference)', () => {
373
+ // Animations here are automatically reverted when media query stops matching
374
+ gsap.to('.hero', { y: -50, scrollTrigger: { scrub: true } });
375
+ });
376
+ }, { scope: containerRef });
377
+
378
+ return (
379
+ <div ref={containerRef}>
380
+ <div className="hero">Content</div>
381
+ </div>
382
+ );
383
+ }
384
+
385
+ // Option B: manual check
386
+ function ManualCheckExample() {
387
+ const containerRef = useRef<HTMLDivElement>(null);
388
+
389
+ useGSAP(() => {
390
+ const prefersReducedMotion = window.matchMedia(
391
+ '(prefers-reduced-motion: reduce)'
392
+ ).matches;
393
+
394
+ if (prefersReducedMotion) {
395
+ gsap.set('.hero', { opacity: 1 }); // skip to final state
396
+ return;
397
+ }
398
+
399
+ gsap.from('.hero', { y: 40, autoAlpha: 0, duration: 0.6 });
400
+ }, { scope: containerRef });
401
+
402
+ return (
403
+ <div ref={containerRef}>
404
+ <div className="hero">Content</div>
405
+ </div>
406
+ );
407
+ }
408
+ ```
409
+
410
+ When reduced motion is active:
411
+ - Skip all transform animations (`x`, `y`, `scale`, `rotation`).
412
+ - Keep opacity-only fades — they do not cause vestibular issues.
413
+ - Use `gsap.set()` to jump to the final visual state so content is still visible.
414
+
415
+ ---
416
+
417
+ ## Section 9: Design Token Bridge
418
+
419
+ Import from the same `@/lib/design-tokens` module that Framer Motion uses to maintain consistency across animation libraries:
420
+
421
+ ```typescript
422
+ 'use client';
423
+ import gsap from 'gsap';
424
+ import { durations, easings } from '@/lib/design-tokens';
425
+
426
+ gsap.to('.element', {
427
+ duration: durations.base, // 0.3
428
+ ease: `cubic-bezier(${easings.standard.join(',')})`,
429
+ });
430
+ ```
431
+
432
+ Alternatively, use GSAP's built-in easing strings when the design token bridge is not needed:
433
+
434
+ | GSAP Ease | Behavior |
435
+ |---|---|
436
+ | `"power2.out"` | Standard deceleration |
437
+ | `"power2.inOut"` | Smooth start and end |
438
+ | `"back.out(1.7)"` | Slight overshoot |
439
+ | `"elastic.out(1, 0.3)"` | Spring-like bounce |
440
+ | `"none"` | Linear (no easing) |
441
+
442
+ > **Rule:** Never hardcode duration numbers. Import from `@/lib/design-tokens`.
443
+
444
+ ---
445
+
446
+ ## Section 10: Anti-patterns
447
+
448
+ | Anti-pattern | Correct approach |
449
+ |---|---|
450
+ | Using useEffect instead of useGSAP | Always use `useGSAP()` from `@gsap/react` — handles cleanup automatically |
451
+ | Forgetting scope ref | Always pass `{ scope: containerRef }` to useGSAP — prevents targeting elements in other components |
452
+ | No cleanup | useGSAP handles this; for manual `gsap.context()`, call `ctx.revert()` in cleanup |
453
+ | Animating width/height/top/left | Use `x`, `y`, `scale`, `rotation` (GPU-composited) |
454
+ | No prefers-reduced-motion check | Wrap animations in `gsap.matchMedia()` or check manually |
455
+ | Mixing GSAP + Framer Motion on same element | Choose one per element — they fight for inline styles |
456
+ | Registering plugins inside components | Register once at app init (`layout.tsx` or `providers.tsx`) |
457
+ | Using GSAP for simple enter/exit | Use Framer Motion — it is declarative and handles mount/unmount |
458
+ | Hardcoded durations/easings | Import from `@/lib/design-tokens` |
459
+ | Creating animations before DOM exists | useGSAP runs after mount — never animate in render body |
460
+
461
+ ---
462
+
463
+ *MORPH-SPEC by Polymorphism Tech*