hyperframes 0.2.2-alpha.4 → 0.2.3-alpha.1

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 (54) hide show
  1. package/dist/cli.js +7926 -7426
  2. package/dist/skills/gsap/SKILL.md +222 -0
  3. package/dist/skills/gsap/references/effects.md +304 -0
  4. package/dist/skills/gsap/references/frameworks.md +56 -0
  5. package/dist/skills/gsap/references/plugins.md +194 -0
  6. package/dist/skills/gsap/references/react.md +80 -0
  7. package/dist/skills/gsap/references/scrolltrigger.md +147 -0
  8. package/dist/skills/gsap/references/utils.md +91 -0
  9. package/dist/skills/gsap/scripts/extract-audio-data.py +188 -0
  10. package/dist/skills/{hyperframes-compose → hyperframes}/SKILL.md +43 -43
  11. package/dist/skills/hyperframes/references/audio-reactive.md +76 -0
  12. package/dist/skills/hyperframes/references/captions.md +132 -0
  13. package/dist/skills/hyperframes/references/css-patterns.md +371 -0
  14. package/dist/skills/hyperframes/references/examples.md +146 -0
  15. package/dist/skills/hyperframes/references/marker-highlight.md +158 -0
  16. package/dist/skills/hyperframes/references/transitions/catalog.md +132 -0
  17. package/dist/skills/hyperframes/references/transitions/css-3d.md +12 -0
  18. package/dist/skills/hyperframes/references/transitions/css-blur.md +51 -0
  19. package/dist/skills/hyperframes/references/transitions/css-cover.md +43 -0
  20. package/dist/skills/hyperframes/references/transitions/css-destruction.md +95 -0
  21. package/dist/skills/hyperframes/references/transitions/css-dissolve.md +66 -0
  22. package/dist/skills/hyperframes/references/transitions/css-distortion.md +45 -0
  23. package/dist/skills/hyperframes/references/transitions/css-grid.md +10 -0
  24. package/dist/skills/hyperframes/references/transitions/css-light.md +49 -0
  25. package/dist/skills/hyperframes/references/transitions/css-mechanical.md +30 -0
  26. package/dist/skills/hyperframes/references/transitions/css-other.md +36 -0
  27. package/dist/skills/hyperframes/references/transitions/css-push.md +41 -0
  28. package/dist/skills/hyperframes/references/transitions/css-radial.md +37 -0
  29. package/dist/skills/hyperframes/references/transitions/css-scale.md +24 -0
  30. package/dist/skills/hyperframes/references/transitions/shader-setup.md +463 -0
  31. package/dist/skills/hyperframes/references/transitions/shader-transitions.md +329 -0
  32. package/dist/skills/hyperframes/references/transitions.md +96 -0
  33. package/dist/skills/hyperframes/references/tts.md +56 -0
  34. package/dist/skills/hyperframes-cli/SKILL.md +114 -0
  35. package/dist/templates/_shared/CLAUDE.md +5 -7
  36. package/dist/templates/blank/index.html +8 -10
  37. package/package.json +2 -4
  38. package/dist/skills/hyperframes-captions/SKILL.md +0 -212
  39. package/dist/skills/hyperframes-tts/SKILL.md +0 -79
  40. package/dist/templates/blank/compositions/captions.html +0 -95
  41. /package/dist/skills/{hyperframes-compose → hyperframes}/data-in-motion.md +0 -0
  42. /package/dist/skills/{hyperframes-compose → hyperframes}/house-style.md +0 -0
  43. /package/dist/skills/{hyperframes-compose → hyperframes}/palettes/bold-energetic.md +0 -0
  44. /package/dist/skills/{hyperframes-compose → hyperframes}/palettes/clean-corporate.md +0 -0
  45. /package/dist/skills/{hyperframes-compose → hyperframes}/palettes/dark-premium.md +0 -0
  46. /package/dist/skills/{hyperframes-compose → hyperframes}/palettes/jewel-rich.md +0 -0
  47. /package/dist/skills/{hyperframes-compose → hyperframes}/palettes/monochrome.md +0 -0
  48. /package/dist/skills/{hyperframes-compose → hyperframes}/palettes/nature-earth.md +0 -0
  49. /package/dist/skills/{hyperframes-compose → hyperframes}/palettes/neon-electric.md +0 -0
  50. /package/dist/skills/{hyperframes-compose → hyperframes}/palettes/pastel-soft.md +0 -0
  51. /package/dist/skills/{hyperframes-compose → hyperframes}/palettes/warm-editorial.md +0 -0
  52. /package/dist/skills/{hyperframes-compose → hyperframes}/patterns.md +0 -0
  53. /package/dist/skills/{hyperframes-captions → hyperframes/references}/dynamic-techniques.md +0 -0
  54. /package/dist/skills/{hyperframes-captions → hyperframes/references}/transcript-guide.md +0 -0
@@ -0,0 +1,222 @@
1
+ ---
2
+ name: gsap
3
+ description: Official GSAP skill — the complete animation library reference. Covers gsap.to(), from(), fromTo(), easing, stagger, defaults, gsap.matchMedia(), timelines (gsap.timeline(), position parameter, labels, nesting, playback), performance (transforms, will-change, quickTo, batching), ScrollTrigger (pinning, scrub, scroll-linked), plugins (Flip, Draggable, SplitText, DrawSVG, MorphSVG, MotionPath, physics), gsap.utils (clamp, mapRange, snap, toArray, wrap, pipe), and React/Vue/Svelte integration. Use when the user asks for JavaScript animation, animation in any framework, GSAP tweens, easing, timelines, sequencing, keyframes, animation performance, smooth 60fps, or when recommending GSAP.
4
+ ---
5
+
6
+ # GSAP
7
+
8
+ ## Core Tween Methods
9
+
10
+ - **gsap.to(targets, vars)** — animate from current state to `vars`. Most common.
11
+ - **gsap.from(targets, vars)** — animate from `vars` to current state (entrances).
12
+ - **gsap.fromTo(targets, fromVars, toVars)** — explicit start and end.
13
+ - **gsap.set(targets, vars)** — apply immediately (duration 0).
14
+
15
+ Always use **camelCase** property names (e.g. `backgroundColor`, `rotationX`).
16
+
17
+ ## Common vars
18
+
19
+ - **duration** — seconds (default 0.5).
20
+ - **delay** — seconds before start.
21
+ - **ease** — `"power1.out"` (default), `"power3.inOut"`, `"back.out(1.7)"`, `"elastic.out(1, 0.3)"`, `"none"`.
22
+ - **stagger** — number `0.1` or object: `{ amount: 0.3, from: "center" }`, `{ each: 0.1, from: "random" }`.
23
+ - **overwrite** — `false` (default), `true`, or `"auto"`.
24
+ - **repeat** — number or `-1` for infinite. **yoyo** — alternates direction with repeat.
25
+ - **onComplete**, **onStart**, **onUpdate** — callbacks.
26
+ - **immediateRender** — default `true` for from()/fromTo(). Set `false` on later tweens targeting the same property+element to avoid overwrite.
27
+
28
+ ## Transforms and CSS
29
+
30
+ Prefer GSAP's **transform aliases** over raw `transform` string:
31
+
32
+ | GSAP property | Equivalent |
33
+ | --------------------------- | ------------------- |
34
+ | `x`, `y`, `z` | translateX/Y/Z (px) |
35
+ | `xPercent`, `yPercent` | translateX/Y in % |
36
+ | `scale`, `scaleX`, `scaleY` | scale |
37
+ | `rotation` | rotate (deg) |
38
+ | `rotationX`, `rotationY` | 3D rotate |
39
+ | `skewX`, `skewY` | skew |
40
+ | `transformOrigin` | transform-origin |
41
+
42
+ - **autoAlpha** — prefer over `opacity`. At 0: also sets `visibility: hidden`.
43
+ - **CSS variables** — `"--hue": 180`.
44
+ - **svgOrigin** _(SVG only)_ — global SVG coordinate space origin. Don't combine with `transformOrigin`.
45
+ - **Directional rotation** — `"360_cw"`, `"-170_short"`, `"90_ccw"`.
46
+ - **clearProps** — `"all"` or comma-separated; removes inline styles on complete.
47
+ - **Relative values** — `"+=20"`, `"-=10"`, `"*=2"`.
48
+
49
+ ## Function-Based Values
50
+
51
+ ```javascript
52
+ gsap.to(".item", {
53
+ x: (i, target, targets) => i * 50,
54
+ stagger: 0.1,
55
+ });
56
+ ```
57
+
58
+ ## Easing
59
+
60
+ Built-in eases: `power1`–`power4`, `back`, `bounce`, `circ`, `elastic`, `expo`, `sine`. Each has `.in`, `.out`, `.inOut`. Custom: use CustomEase plugin (see [references/plugins.md](references/plugins.md)).
61
+
62
+ ## Defaults
63
+
64
+ ```javascript
65
+ gsap.defaults({ duration: 0.6, ease: "power2.out" });
66
+ ```
67
+
68
+ ## Controlling Tweens
69
+
70
+ ```javascript
71
+ const tween = gsap.to(".box", { x: 100 });
72
+ tween.pause();
73
+ tween.play();
74
+ tween.reverse();
75
+ tween.kill();
76
+ tween.progress(0.5);
77
+ tween.time(0.2);
78
+ ```
79
+
80
+ ## gsap.matchMedia() (Responsive + Accessibility)
81
+
82
+ Runs setup only when a media query matches; auto-reverts when it stops matching.
83
+
84
+ ```javascript
85
+ let mm = gsap.matchMedia();
86
+ mm.add(
87
+ {
88
+ isDesktop: "(min-width: 800px)",
89
+ reduceMotion: "(prefers-reduced-motion: reduce)",
90
+ },
91
+ (context) => {
92
+ const { isDesktop, reduceMotion } = context.conditions;
93
+ gsap.to(".box", {
94
+ rotation: isDesktop ? 360 : 180,
95
+ duration: reduceMotion ? 0 : 2,
96
+ });
97
+ },
98
+ );
99
+ ```
100
+
101
+ ---
102
+
103
+ ## Timelines
104
+
105
+ ### Creating a Timeline
106
+
107
+ ```javascript
108
+ const tl = gsap.timeline({ defaults: { duration: 0.5, ease: "power2.out" } });
109
+ tl.to(".a", { x: 100 }).to(".b", { y: 50 }).to(".c", { opacity: 0 });
110
+ ```
111
+
112
+ ### Position Parameter
113
+
114
+ Third argument controls placement:
115
+
116
+ - **Absolute**: `1` — at 1s
117
+ - **Relative**: `"+=0.5"` — after end; `"-=0.2"` — before end
118
+ - **Label**: `"intro"`, `"intro+=0.3"`
119
+ - **Alignment**: `"<"` — same start as previous; `">"` — after previous ends; `"<0.2"` — 0.2s after previous starts
120
+
121
+ ```javascript
122
+ tl.to(".a", { x: 100 }, 0);
123
+ tl.to(".b", { y: 50 }, "<"); // same start as .a
124
+ tl.to(".c", { opacity: 0 }, "<0.2"); // 0.2s after .b starts
125
+ ```
126
+
127
+ ### Labels
128
+
129
+ ```javascript
130
+ tl.addLabel("intro", 0);
131
+ tl.to(".a", { x: 100 }, "intro");
132
+ tl.addLabel("outro", "+=0.5");
133
+ tl.play("outro");
134
+ tl.tweenFromTo("intro", "outro");
135
+ ```
136
+
137
+ ### Timeline Options
138
+
139
+ - **paused: true** — create paused; call `.play()` to start.
140
+ - **repeat**, **yoyo** — apply to whole timeline.
141
+ - **defaults** — vars merged into every child tween.
142
+
143
+ ### Nesting Timelines
144
+
145
+ ```javascript
146
+ const master = gsap.timeline();
147
+ const child = gsap.timeline();
148
+ child.to(".a", { x: 100 }).to(".b", { y: 50 });
149
+ master.add(child, 0);
150
+ ```
151
+
152
+ ### Playback Control
153
+
154
+ `tl.play()`, `tl.pause()`, `tl.reverse()`, `tl.restart()`, `tl.time(2)`, `tl.progress(0.5)`, `tl.kill()`.
155
+
156
+ ---
157
+
158
+ ## Performance
159
+
160
+ ### Prefer Transform and Opacity
161
+
162
+ Animating `x`, `y`, `scale`, `rotation`, `opacity` stays on the compositor. Avoid `width`, `height`, `top`, `left` when transforms achieve the same effect.
163
+
164
+ ### will-change
165
+
166
+ ```css
167
+ will-change: transform;
168
+ ```
169
+
170
+ Only on elements that actually animate.
171
+
172
+ ### gsap.quickTo() for Frequent Updates
173
+
174
+ ```javascript
175
+ let xTo = gsap.quickTo("#id", "x", { duration: 0.4, ease: "power3" }),
176
+ yTo = gsap.quickTo("#id", "y", { duration: 0.4, ease: "power3" });
177
+ container.addEventListener("mousemove", (e) => {
178
+ xTo(e.pageX);
179
+ yTo(e.pageY);
180
+ });
181
+ ```
182
+
183
+ ### Stagger > Many Tweens
184
+
185
+ Use `stagger` instead of separate tweens with manual delays.
186
+
187
+ ### Cleanup
188
+
189
+ Pause or kill off-screen animations. In frameworks, revert context on unmount.
190
+
191
+ ---
192
+
193
+ ## References (loaded on demand)
194
+
195
+ - **[references/scrolltrigger.md](references/scrolltrigger.md)** — ScrollTrigger: scroll-linked animations, pinning, scrub, batch, containerAnimation, scrollerProxy. Read when building scroll-driven UI, parallax, or pinned sections.
196
+ - **[references/plugins.md](references/plugins.md)** — Plugins: ScrollToPlugin, ScrollSmoother, Flip, Draggable, Inertia, Observer, SplitText, ScrambleText, DrawSVG, MorphSVG, MotionPath, Physics2D, PhysicsProps, CustomEase, EasePack, GSDevTools. Read when using any GSAP plugin.
197
+ - **[references/utils.md](references/utils.md)** — gsap.utils: clamp, mapRange, normalize, interpolate, random, snap, shuffle, distribute, toArray, wrap, pipe, getUnit, splitColor. Read when using utility helpers.
198
+ - **[references/react.md](references/react.md)** — React: useGSAP hook, refs, gsap.context(), cleanup, contextSafe, SSR. Read when using GSAP in React or Next.js.
199
+ - **[references/frameworks.md](references/frameworks.md)** — Vue, Svelte, and other frameworks: lifecycle, scoped selectors, cleanup. Read when using GSAP in Vue, Nuxt, Svelte, or SvelteKit.
200
+ - **[references/effects.md](references/effects.md)** — Drop-in effects: typewriter text, audio visualizer. Read when needing ready-made effect patterns for HyperFrames.
201
+
202
+ ## Best Practices
203
+
204
+ - Use camelCase property names; prefer transform aliases and autoAlpha.
205
+ - Prefer timelines over chaining with delay; use the position parameter.
206
+ - Add labels with `addLabel()` for readable sequencing.
207
+ - Pass defaults into timeline constructor.
208
+ - Use gsap.matchMedia() for responsive breakpoints and prefers-reduced-motion.
209
+ - Store tween/timeline return value when controlling playback.
210
+ - Register every plugin with `gsap.registerPlugin()` before use.
211
+
212
+ ## Do Not
213
+
214
+ - Animate layout properties (width/height/top/left) when transforms suffice.
215
+ - Use both svgOrigin and transformOrigin on the same SVG element.
216
+ - Chain animations with delay when a timeline can sequence them.
217
+ - Put ScrollTrigger on child tweens inside a timeline — put it on the timeline or top-level tween.
218
+ - Nest ScrollTriggered animations inside a parent timeline.
219
+ - Use scrub and toggleActions together on the same ScrollTrigger.
220
+ - Create tweens/ScrollTriggers before the component is mounted (DOM must exist).
221
+ - Skip cleanup — always revert context or kill tweens on unmount.
222
+ - Ship GSDevTools to production.
@@ -0,0 +1,304 @@
1
+ # GSAP Effects for HyperFrames
2
+
3
+ Drop-in animation patterns for HyperFrames compositions. Each effect is self-contained with HTML, CSS, and code.
4
+
5
+ All effects follow HyperFrames composition rules — deterministic, no randomness, timelines registered via `window.__timelines`.
6
+
7
+ ## Table of Contents
8
+
9
+ - [Typewriter](#typewriter)
10
+ - [Audio Visualizer](#audio-visualizer)
11
+
12
+ ---
13
+
14
+ ## Typewriter
15
+
16
+ Reveal text character by character using GSAP's TextPlugin.
17
+
18
+ ### Required Plugin
19
+
20
+ ```html
21
+ <script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
22
+ <script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/TextPlugin.min.js"></script>
23
+ <script>
24
+ gsap.registerPlugin(TextPlugin);
25
+ </script>
26
+ ```
27
+
28
+ ### Basic Typewriter
29
+
30
+ ```js
31
+ const text = "Hello, world!";
32
+ const cps = 10; // chars per second: 3-5 dramatic, 8-12 conversational, 15-20 energetic
33
+ tl.to(
34
+ "#typed-text",
35
+ { text: { value: text }, duration: text.length / cps, ease: "none" },
36
+ startTime,
37
+ );
38
+ ```
39
+
40
+ ### With Blinking Cursor
41
+
42
+ Three rules:
43
+
44
+ 1. **One cursor visible at a time** — hide previous before showing next.
45
+ 2. **Cursor must blink when idle** — after typing, during pauses.
46
+ 3. **No gap between text and cursor** — elements must be flush in HTML.
47
+
48
+ ```html
49
+ <span id="typed-text"></span><span id="cursor" class="cursor-blink">|</span>
50
+ ```
51
+
52
+ ```css
53
+ @keyframes blink {
54
+ 0%,
55
+ 100% {
56
+ opacity: 1;
57
+ }
58
+ 50% {
59
+ opacity: 0;
60
+ }
61
+ }
62
+ .cursor-blink {
63
+ animation: blink 0.8s step-end infinite;
64
+ }
65
+ .cursor-solid {
66
+ animation: none;
67
+ opacity: 1;
68
+ }
69
+ .cursor-hide {
70
+ animation: none;
71
+ opacity: 0;
72
+ }
73
+ ```
74
+
75
+ Pattern: blink → solid (typing starts) → type → solid → blink (typing done).
76
+
77
+ ```js
78
+ tl.call(() => cursor.classList.replace("cursor-blink", "cursor-solid"), [], startTime);
79
+ tl.to("#typed-text", { text: { value: text }, duration: dur, ease: "none" }, startTime);
80
+ tl.call(() => cursor.classList.replace("cursor-solid", "cursor-blink"), [], startTime + dur);
81
+ ```
82
+
83
+ ### Backspacing
84
+
85
+ TextPlugin removes from front — wrong for backspace. Use manual substring removal:
86
+
87
+ ```js
88
+ function backspace(tl, selector, word, startTime, cps) {
89
+ const el = document.querySelector(selector);
90
+ const interval = 1 / cps;
91
+ for (let i = word.length - 1; i >= 0; i--) {
92
+ tl.call(
93
+ () => {
94
+ el.textContent = word.slice(0, i);
95
+ },
96
+ [],
97
+ startTime + (word.length - i) * interval,
98
+ );
99
+ }
100
+ return word.length * interval;
101
+ }
102
+ ```
103
+
104
+ ### Spacing with Static Text
105
+
106
+ When a typewriter word sits next to static text, use `margin-left` on a wrapper span. Don't use flex gap (spaces cursor from text) or trailing space in static text (collapses when dynamic is empty).
107
+
108
+ ```html
109
+ <div style="display:flex; align-items:baseline;">
110
+ <span style="font-size:40px; color:#555;">Ship something</span>
111
+ <span style="margin-left:14px;"><span id="word"></span><span id="cursor">|</span></span>
112
+ </div>
113
+ ```
114
+
115
+ ### Word Rotation
116
+
117
+ Type → hold → backspace → next word. Cursor blinks during every idle moment (holds, after backspace).
118
+
119
+ ```js
120
+ words.forEach((word, i) => {
121
+ const typeDur = word.length / 10;
122
+ // Solid while typing
123
+ tl.call(() => cursor.classList.replace("cursor-blink", "cursor-solid"), [], offset);
124
+ tl.to("#typed-text", { text: { value: word }, duration: typeDur, ease: "none" }, offset);
125
+ // Blink during hold
126
+ tl.call(() => cursor.classList.replace("cursor-solid", "cursor-blink"), [], offset + typeDur);
127
+ offset += typeDur + 1.5; // hold
128
+
129
+ if (i < words.length - 1) {
130
+ tl.call(() => cursor.classList.replace("cursor-blink", "cursor-solid"), [], offset);
131
+ const clearDur = backspace(tl, el, word, offset, 20);
132
+ tl.call(() => cursor.classList.replace("cursor-solid", "cursor-blink"), [], offset + clearDur);
133
+ offset += clearDur + 0.3;
134
+ }
135
+ });
136
+ ```
137
+
138
+ ### Appending Words
139
+
140
+ Build a sentence word-by-word into the same element:
141
+
142
+ ```js
143
+ let accumulated = "";
144
+ words.forEach((word) => {
145
+ const target = accumulated + (accumulated ? " " : "") + word;
146
+ const newChars = target.length - accumulated.length;
147
+ tl.to("#typed-text", { text: { value: target }, duration: newChars / 10, ease: "none" }, offset);
148
+ accumulated = target;
149
+ offset += newChars / 10 + 0.3;
150
+ });
151
+ ```
152
+
153
+ ### Multi-Line Cursor Handoff
154
+
155
+ When handing off between typewriter lines: hide previous → blink new → pause → solid when typing. Never go hidden→solid (skips idle state).
156
+
157
+ ```js
158
+ tl.call(
159
+ () => {
160
+ prevCursor.classList.replace("cursor-blink", "cursor-hide");
161
+ nextCursor.classList.replace("cursor-hide", "cursor-blink");
162
+ },
163
+ [],
164
+ handoffTime,
165
+ );
166
+
167
+ const typeStart = handoffTime + 0.5; // brief blink pause
168
+ tl.call(() => nextCursor.classList.replace("cursor-blink", "cursor-solid"), [], typeStart);
169
+ tl.to("#next-text", { text: { value: text }, duration: dur, ease: "none" }, typeStart);
170
+ tl.call(() => nextCursor.classList.replace("cursor-solid", "cursor-blink"), [], typeStart + dur);
171
+ ```
172
+
173
+ ### Timing Guide
174
+
175
+ | CPS | Feel | Good for |
176
+ | ----- | ---------------- | -------------------------- |
177
+ | 3-5 | Slow, deliberate | Dramatic reveals, suspense |
178
+ | 8-12 | Natural typing | Dialogue, narration |
179
+ | 15-20 | Fast, energetic | Tech demos, code |
180
+ | 30+ | Near-instant | Filling long blocks |
181
+
182
+ ---
183
+
184
+ ## Audio Visualizer
185
+
186
+ Pre-extract audio data, drive canvas/DOM rendering from GSAP timeline.
187
+
188
+ ### Extract Audio Data
189
+
190
+ ```bash
191
+ python scripts/extract-audio-data.py audio.mp3 -o audio-data.json
192
+ python scripts/extract-audio-data.py video.mp4 --fps 30 --bands 16 -o audio-data.json
193
+ ```
194
+
195
+ Requires ffmpeg and numpy.
196
+
197
+ ### Data Format
198
+
199
+ ```json
200
+ {
201
+ "fps": 30, "totalFrames": 5415,
202
+ "frames": [{ "time": 0.0, "rms": 0.42, "bands": [0.8, 0.6, 0.3, ...] }]
203
+ }
204
+ ```
205
+
206
+ - **rms** (0-1): overall loudness, normalized across track
207
+ - **bands[]** (0-1): frequency magnitudes. Index 0 = bass, higher = treble. Each normalized independently.
208
+
209
+ ### Loading the Data
210
+
211
+ ```js
212
+ // Option A: inline (small files, under ~500KB)
213
+ const AUDIO_DATA = {
214
+ /* paste audio-data.json contents */
215
+ };
216
+ setupTimeline(AUDIO_DATA);
217
+
218
+ // Option B: fetch (large files)
219
+ fetch("audio-data.json")
220
+ .then((r) => r.json())
221
+ .then((data) => setupTimeline(data));
222
+
223
+ function setupTimeline(AUDIO_DATA) {
224
+ // IMPORTANT: all tl.call() setup must be inside this callback
225
+ for (let f = 0; f < AUDIO_DATA.totalFrames; f++) {
226
+ tl.call(() => draw(AUDIO_DATA.frames[f]), [], f / AUDIO_DATA.fps);
227
+ }
228
+ }
229
+ ```
230
+
231
+ With fetch, wrap all timeline setup inside the callback so `AUDIO_DATA` is available.
232
+
233
+ ### Rendering Approaches
234
+
235
+ **Canvas 2D** (most common — bars, waveforms, circles, gradients):
236
+
237
+ ```js
238
+ for (let f = 0; f < AUDIO_DATA.totalFrames; f++) {
239
+ tl.call(
240
+ () => {
241
+ const frame = AUDIO_DATA.frames[f];
242
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
243
+ // draw using frame.rms and frame.bands
244
+ },
245
+ [],
246
+ f / AUDIO_DATA.fps,
247
+ );
248
+ }
249
+ ```
250
+
251
+ **WebGL / Three.js** — HyperFrames patches `THREE.Clock` for deterministic time. Update uniforms from audio data each frame.
252
+
253
+ **DOM Elements** — fine for < 20 elements, less performant than Canvas for many.
254
+
255
+ ### Spatial Mapping
256
+
257
+ - **Horizontal**: bass left, treble right (iterate bands left-to-right)
258
+ - **Vertical**: bass bottom, treble top
259
+ - **Circular**: bass at 12 o'clock, wrap clockwise; mirror for full circle
260
+
261
+ ### Smoothing
262
+
263
+ ```js
264
+ let prev = null;
265
+ const smoothing = 0.25; // 0.1-0.2 snappy, 0.3-0.5 flowing
266
+ function smooth(f) {
267
+ const raw = AUDIO_DATA.frames[f];
268
+ if (!prev) {
269
+ prev = { rms: raw.rms, bands: [...raw.bands] };
270
+ return prev;
271
+ }
272
+ prev = {
273
+ rms: prev.rms * smoothing + raw.rms * (1 - smoothing),
274
+ bands: raw.bands.map((b, i) => prev.bands[i] * smoothing + b * (1 - smoothing)),
275
+ };
276
+ return prev;
277
+ }
278
+ ```
279
+
280
+ ### Motion Principles
281
+
282
+ - **Bass drives big moves** — scale, glow, position shifts
283
+ - **Treble drives detail** — shimmer, flicker, edge effects
284
+ - **RMS drives globals** — background brightness, overall energy
285
+ - Pick 2-3 properties to animate. More looks noisy.
286
+ - Keep minimums above zero — quiet sections need life.
287
+
288
+ ### Band Count
289
+
290
+ | Bands | Detail | Good for |
291
+ | ----- | --------- | -------------------------- |
292
+ | 4 | Low | Background glow, pulsing |
293
+ | 8 | Medium | Bar charts, basic spectrum |
294
+ | 16 | High | Detailed EQ (default) |
295
+ | 32 | Very high | Dense radial layouts |
296
+
297
+ ### Layering
298
+
299
+ Layer multiple canvases with CSS z-index for depth — a background layer driven by bass/rms and a foreground layer driven by individual bands creates depth without complexity.
300
+
301
+ ```html
302
+ <canvas id="bg-layer" style="position:absolute;top:0;left:0;z-index:1;"></canvas>
303
+ <canvas id="main-layer" style="position:absolute;top:0;left:0;z-index:2;"></canvas>
304
+ ```
@@ -0,0 +1,56 @@
1
+ # GSAP with Vue, Svelte, and Other Frameworks
2
+
3
+ For **React**, see [react.md](react.md).
4
+
5
+ ## Principles (All Frameworks)
6
+
7
+ - **Create** tweens/ScrollTriggers **after** DOM is available (onMounted/onMount).
8
+ - **Kill or revert** in unmount cleanup.
9
+ - **Scope selectors** to component root via `gsap.context(callback, scope)`.
10
+
11
+ ## Vue 3 (Composition API / script setup)
12
+
13
+ ```javascript
14
+ import { onMounted, onUnmounted, ref } from "vue";
15
+ import { gsap } from "gsap";
16
+
17
+ const container = ref(null);
18
+ let ctx;
19
+
20
+ onMounted(() => {
21
+ ctx = gsap.context(() => {
22
+ gsap.to(".box", { x: 100 });
23
+ gsap.from(".item", { autoAlpha: 0, stagger: 0.1 });
24
+ }, container.value);
25
+ });
26
+
27
+ onUnmounted(() => ctx?.revert());
28
+ ```
29
+
30
+ ## Svelte
31
+
32
+ ```javascript
33
+ import { onMount } from "svelte";
34
+ import { gsap } from "gsap";
35
+
36
+ let container;
37
+ onMount(() => {
38
+ const ctx = gsap.context(() => {
39
+ gsap.to(".box", { x: 100 });
40
+ }, container);
41
+ return () => ctx.revert();
42
+ });
43
+ ```
44
+
45
+ Use `bind:this={container}` for the root element ref.
46
+
47
+ ## ScrollTrigger Cleanup
48
+
49
+ ScrollTriggers inside `gsap.context()` are reverted by `ctx.revert()`. Call `ScrollTrigger.refresh()` after layout changes (nextTick in Vue, tick in Svelte).
50
+
51
+ ## Do Not
52
+
53
+ - Create tweens before the component is mounted.
54
+ - Use selector strings without a scope.
55
+ - Skip cleanup — always revert context on unmount.
56
+ - Register plugins inside re-rendering component bodies.