@mehshekari/gsap-motion 3.1.1 → 3.2.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/README.md +1 -1
- package/bin/gsap-motion.mjs +17 -0
- package/package.json +1 -1
- package/skill/SKILL.md +14 -10
- package/skill/adapter/astro.md +111 -0
- package/skill/adapter/next.md +99 -0
- package/skill/adapter/r3f.md +128 -0
- package/skill/adapter/react.md +133 -0
- package/skill/adapter/svelte.md +105 -0
- package/skill/adapter/three.md +141 -0
- package/skill/adapter/vanilla.md +115 -0
- package/skill/adapter/vue.md +120 -0
- package/skill/example/svg-loader.md +1 -1
- package/skill/reference/core-gsap.md +1 -1
- package/skill/reference/interaction.md +183 -183
- package/skill/reference/routing.md +119 -119
- package/skill/reference/scrolltrigger.md +1 -1
- package/skill/reference/svg.md +1 -1
- package/skill/reference/timeline.md +1 -1
- package/skill/scripts/lib/ast.mjs +7 -1
- package/skill/scripts/lib/rules.mjs +97 -3
- package/skill/scripts/lib/source.mjs +51 -3
- package/skill/reference/frameworks.md +0 -153
- package/skill/reference/react-nextjs.md +0 -234
- package/skill/reference/three-r3f.md +0 -161
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
# Three.js and React Three Fiber
|
|
2
|
-
|
|
3
|
-
GSAP is the **orchestration layer**, not the renderer. Three owns the scene,
|
|
4
|
-
the camera, and the draw loop. GSAP owns *when* values change and *how* they
|
|
5
|
-
ease between states.
|
|
6
|
-
|
|
7
|
-
Neither library comes with GSAP, and most projects have neither. Check
|
|
8
|
-
`package.json` before writing code against them, and say so if they are not
|
|
9
|
-
there.
|
|
10
|
-
|
|
11
|
-
## The division
|
|
12
|
-
|
|
13
|
-
| GSAP | Three / R3F |
|
|
14
|
-
|---|---|
|
|
15
|
-
| timing, easing, sequencing | geometry, materials, lights |
|
|
16
|
-
| camera moves between positions | camera projection, the render loop |
|
|
17
|
-
| object transforms over time | the transforms themselves |
|
|
18
|
-
| material property transitions | shaders |
|
|
19
|
-
| tying it all to scroll | rendering the result |
|
|
20
|
-
|
|
21
|
-
Do not rebuild a physics engine or a particle system in GSAP. Do not hand-write
|
|
22
|
-
easing in `useFrame` when a tween would say it in one line.
|
|
23
|
-
|
|
24
|
-
## The core pattern
|
|
25
|
-
|
|
26
|
-
Three objects are plain JS objects, so GSAP tweens them directly. The only thing
|
|
27
|
-
to remember is that nested properties are their own targets:
|
|
28
|
-
|
|
29
|
-
```ts
|
|
30
|
-
gsap.to(mesh.position, { x: 2, y: 1, duration: 1.2, ease: "power3.inOut" });
|
|
31
|
-
gsap.to(mesh.rotation, { y: Math.PI * 2, duration: 3, ease: "none", repeat: -1 });
|
|
32
|
-
gsap.to(mesh.material, { opacity: 0, duration: 0.6 });
|
|
33
|
-
gsap.to(mesh.scale, { x: 1.4, y: 1.4, z: 1.4, duration: 0.5 });
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
`gsap.to(mesh, { position: { x: 2 } })` does not work. Target `mesh.position`.
|
|
37
|
-
|
|
38
|
-
For a material property to animate opacity, `transparent` must already be true —
|
|
39
|
-
setting it mid-tween causes a shader recompile.
|
|
40
|
-
|
|
41
|
-
## Uniforms
|
|
42
|
-
|
|
43
|
-
Shader uniforms are `{ value }` objects, which tween cleanly:
|
|
44
|
-
|
|
45
|
-
```ts
|
|
46
|
-
gsap.to(material.uniforms.uProgress, { value: 1, duration: 1.5, ease: "power2.inOut" });
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
This is the usual bridge between a GSAP timeline and a custom shader effect —
|
|
50
|
-
one uniform, driven by the timeline, interpreted by the shader.
|
|
51
|
-
|
|
52
|
-
## R3F
|
|
53
|
-
|
|
54
|
-
The renderer runs its own loop, so nothing needs invalidating on demand unless
|
|
55
|
-
the canvas is set to `frameloop="demand"` — in which case call `invalidate()`
|
|
56
|
-
from `onUpdate`.
|
|
57
|
-
|
|
58
|
-
```tsx
|
|
59
|
-
"use client";
|
|
60
|
-
|
|
61
|
-
import { useGSAP } from "@gsap/react";
|
|
62
|
-
import { useFrame, useThree } from "@react-three/fiber";
|
|
63
|
-
import gsap from "gsap";
|
|
64
|
-
import { useRef } from "react";
|
|
65
|
-
import type { Mesh } from "three";
|
|
66
|
-
|
|
67
|
-
export function Box() {
|
|
68
|
-
const mesh = useRef<Mesh>(null);
|
|
69
|
-
|
|
70
|
-
useGSAP(() => {
|
|
71
|
-
if (!mesh.current) return;
|
|
72
|
-
gsap.to(mesh.current.rotation, {
|
|
73
|
-
y: Math.PI * 2,
|
|
74
|
-
duration: 6,
|
|
75
|
-
ease: "none",
|
|
76
|
-
repeat: -1,
|
|
77
|
-
});
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
return (
|
|
81
|
-
<mesh ref={mesh}>
|
|
82
|
-
<boxGeometry />
|
|
83
|
-
<meshStandardMaterial />
|
|
84
|
-
</mesh>
|
|
85
|
-
);
|
|
86
|
-
}
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
**Never drive a 3D transform through React state.** `useState` per frame
|
|
90
|
-
re-renders the React tree for a value Three reads directly. Refs and GSAP only.
|
|
91
|
-
|
|
92
|
-
`useFrame` and GSAP are complementary, not competing: `useFrame` for continuous
|
|
93
|
-
per-frame logic that depends on the clock, GSAP for transitions between states.
|
|
94
|
-
|
|
95
|
-
## Camera
|
|
96
|
-
|
|
97
|
-
Camera moves are where GSAP earns its place — easing a camera by hand is how
|
|
98
|
-
scroll-driven 3D ends up feeling mechanical.
|
|
99
|
-
|
|
100
|
-
```ts
|
|
101
|
-
const { camera } = useThree();
|
|
102
|
-
|
|
103
|
-
gsap.timeline({ defaults: { ease: "power2.inOut", duration: 2 } })
|
|
104
|
-
.to(camera.position, { x: 0, y: 1.5, z: 4 })
|
|
105
|
-
.to(camera.rotation, { x: -0.2 }, "<");
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
If the camera uses `lookAt`, tween a proxy target and call `lookAt` in
|
|
109
|
-
`onUpdate` — otherwise the rotation you tween is overwritten every frame:
|
|
110
|
-
|
|
111
|
-
```ts
|
|
112
|
-
const look = { x: 0, y: 0, z: 0 };
|
|
113
|
-
gsap.to(look, {
|
|
114
|
-
x: 2,
|
|
115
|
-
duration: 2,
|
|
116
|
-
onUpdate: () => camera.lookAt(look.x, look.y, look.z),
|
|
117
|
-
});
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
## Scroll-driven 3D
|
|
121
|
-
|
|
122
|
-
Scrub a timeline, do not compute from `scrollY` in `useFrame`:
|
|
123
|
-
|
|
124
|
-
```ts
|
|
125
|
-
gsap.timeline({
|
|
126
|
-
scrollTrigger: { trigger: section, start: "top top", end: "+=2000",
|
|
127
|
-
pin: true, scrub: 1 },
|
|
128
|
-
})
|
|
129
|
-
.to(camera.position, { z: 3, ease: "none" })
|
|
130
|
-
.to(material.uniforms.uProgress, { value: 1, ease: "none" }, "<");
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
`ease: "none"` on every child, as with any scrub. See
|
|
134
|
-
[scrolltrigger.md](scrolltrigger.md).
|
|
135
|
-
|
|
136
|
-
## Cost and accessibility
|
|
137
|
-
|
|
138
|
-
3D is the most expensive thing on a page, and the constraints are harder than
|
|
139
|
-
for DOM animation:
|
|
140
|
-
|
|
141
|
-
- A WebGL canvas runs the GPU continuously. On a phone that is battery and heat.
|
|
142
|
-
- Give the canvas a real fallback — a static image — for low-power devices and
|
|
143
|
-
for `prefers-reduced-motion`. Do not merely stop the animation and leave a
|
|
144
|
-
running canvas.
|
|
145
|
-
- Dynamically import the 3D component so Three is not in the initial bundle.
|
|
146
|
-
- `frameloop="demand"` when the scene is static between interactions.
|
|
147
|
-
- Dispose geometries, materials and textures on unmount; GSAP's cleanup does not
|
|
148
|
-
do that.
|
|
149
|
-
- Nothing essential — text, navigation, product information — should exist only
|
|
150
|
-
inside the canvas.
|
|
151
|
-
|
|
152
|
-
## Cleanup
|
|
153
|
-
|
|
154
|
-
```ts
|
|
155
|
-
useGSAP(() => {
|
|
156
|
-
const tl = gsap.timeline({ scrollTrigger: { ... } });
|
|
157
|
-
return () => { tl.scrollTrigger?.kill(); };
|
|
158
|
-
});
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
Plus Three's own disposal, which is separate and yours to do.
|