hyperframes 0.6.97 → 0.6.98
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/dist/beat-analyzer.global.js +326 -0
- package/dist/cli.js +2479 -1961
- package/dist/commands/layout-audit.browser.js +86 -0
- package/dist/hyperframe-runtime.js +22 -22
- package/dist/hyperframe.manifest.json +1 -1
- package/dist/hyperframe.runtime.iife.js +22 -22
- package/dist/skills/hyperframes-cli/SKILL.md +67 -103
- package/dist/skills/hyperframes-cli/references/doctor-browser.md +45 -0
- package/dist/skills/hyperframes-cli/references/init-and-scaffold.md +51 -0
- package/dist/skills/hyperframes-cli/references/lambda.md +132 -0
- package/dist/skills/hyperframes-cli/references/lint-validate-inspect.md +93 -0
- package/dist/skills/hyperframes-cli/references/preview-render.md +107 -0
- package/dist/skills/hyperframes-cli/references/upgrade-info-misc.md +75 -0
- package/dist/studio/assets/hyperframes-player-DgsMQSvV.js +418 -0
- package/dist/studio/assets/index-B62bDCQv.css +1 -0
- package/dist/studio/assets/index-Ce3pBm_I.js +252 -0
- package/dist/studio/assets/{index-HveJ0MuV.js → index-D-ET9M0b.js} +1 -1
- package/dist/studio/assets/index-D-bS9Dxx.js +1 -0
- package/dist/studio/index.html +2 -2
- package/dist/templates/_shared/AGENTS.md +46 -21
- package/dist/templates/_shared/CLAUDE.md +16 -14
- package/package.json +3 -2
- package/dist/pngDecodeBlitWorker.js +0 -239
- package/dist/skills/gsap/SKILL.md +0 -240
- package/dist/skills/gsap/references/effects.md +0 -297
- package/dist/skills/gsap/scripts/extract-audio-data.py +0 -188
- package/dist/skills/hyperframes/SKILL.md +0 -491
- package/dist/skills/hyperframes/data-in-motion.md +0 -19
- package/dist/skills/hyperframes/house-style.md +0 -73
- package/dist/skills/hyperframes/palettes/bold-energetic.md +0 -14
- package/dist/skills/hyperframes/palettes/clean-corporate.md +0 -14
- package/dist/skills/hyperframes/palettes/dark-premium.md +0 -14
- package/dist/skills/hyperframes/palettes/jewel-rich.md +0 -14
- package/dist/skills/hyperframes/palettes/monochrome.md +0 -14
- package/dist/skills/hyperframes/palettes/nature-earth.md +0 -14
- package/dist/skills/hyperframes/palettes/neon-electric.md +0 -14
- package/dist/skills/hyperframes/palettes/pastel-soft.md +0 -14
- package/dist/skills/hyperframes/palettes/warm-editorial.md +0 -14
- package/dist/skills/hyperframes/patterns.md +0 -191
- package/dist/skills/hyperframes/references/audio-reactive.md +0 -76
- package/dist/skills/hyperframes/references/beat-direction.md +0 -171
- package/dist/skills/hyperframes/references/captions.md +0 -163
- package/dist/skills/hyperframes/references/css-patterns.md +0 -373
- package/dist/skills/hyperframes/references/design-picker.md +0 -117
- package/dist/skills/hyperframes/references/dynamic-techniques.md +0 -102
- package/dist/skills/hyperframes/references/html-in-canvas-patterns.md +0 -507
- package/dist/skills/hyperframes/references/motion-principles.md +0 -150
- package/dist/skills/hyperframes/references/narration.md +0 -92
- package/dist/skills/hyperframes/references/prompt-expansion.md +0 -68
- package/dist/skills/hyperframes/references/techniques.md +0 -525
- package/dist/skills/hyperframes/references/text-effects.md +0 -64
- package/dist/skills/hyperframes/references/transcript-guide.md +0 -107
- package/dist/skills/hyperframes/references/transitions/catalog.md +0 -117
- package/dist/skills/hyperframes/references/transitions/css-3d.md +0 -12
- package/dist/skills/hyperframes/references/transitions/css-blur.md +0 -51
- package/dist/skills/hyperframes/references/transitions/css-cover.md +0 -43
- package/dist/skills/hyperframes/references/transitions/css-destruction.md +0 -95
- package/dist/skills/hyperframes/references/transitions/css-dissolve.md +0 -66
- package/dist/skills/hyperframes/references/transitions/css-distortion.md +0 -45
- package/dist/skills/hyperframes/references/transitions/css-grid.md +0 -10
- package/dist/skills/hyperframes/references/transitions/css-light.md +0 -49
- package/dist/skills/hyperframes/references/transitions/css-mechanical.md +0 -30
- package/dist/skills/hyperframes/references/transitions/css-other.md +0 -25
- package/dist/skills/hyperframes/references/transitions/css-push.md +0 -41
- package/dist/skills/hyperframes/references/transitions/css-radial.md +0 -37
- package/dist/skills/hyperframes/references/transitions/css-scale.md +0 -24
- package/dist/skills/hyperframes/references/transitions.md +0 -138
- package/dist/skills/hyperframes/references/typography.md +0 -175
- package/dist/skills/hyperframes/references/video-composition.md +0 -62
- package/dist/skills/hyperframes/scripts/animation-map.mjs +0 -601
- package/dist/skills/hyperframes/scripts/contrast-report.mjs +0 -348
- package/dist/skills/hyperframes/scripts/package-loader.mjs +0 -269
- package/dist/skills/hyperframes/templates/design-picker.html +0 -1432
- package/dist/skills/hyperframes/visual-styles.md +0 -443
- package/dist/studio/assets/hyperframes-player-Daj5djxa.js +0 -418
- package/dist/studio/assets/index-B0twsRu0.css +0 -1
- package/dist/studio/assets/index-Cfye9xzo.js +0 -251
|
@@ -1,240 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: gsap
|
|
3
|
-
description: GSAP animation reference for HyperFrames. Covers gsap.to(), from(), fromTo(), easing, stagger, defaults, timelines (gsap.timeline(), position parameter, labels, nesting, playback), and performance (transforms, will-change, quickTo). Use when writing GSAP animations in HyperFrames compositions.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# GSAP
|
|
7
|
-
|
|
8
|
-
## HyperFrames Contract
|
|
9
|
-
|
|
10
|
-
HyperFrames controls GSAP through its `gsap` runtime adapter. Create a paused timeline synchronously, register it on `window.__timelines` with the exact `data-composition-id`, and let HyperFrames seek it.
|
|
11
|
-
|
|
12
|
-
```html
|
|
13
|
-
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
|
|
14
|
-
<script>
|
|
15
|
-
window.__timelines = window.__timelines || {};
|
|
16
|
-
const tl = gsap.timeline({ paused: true });
|
|
17
|
-
|
|
18
|
-
tl.from(".title", { y: 48, opacity: 0, duration: 0.6, ease: "power3.out" }, 0);
|
|
19
|
-
tl.to(".accent", { scaleX: 1, duration: 0.5, ease: "power2.out" }, 0.25);
|
|
20
|
-
|
|
21
|
-
window.__timelines["main"] = tl; // key must equal data-composition-id on the composition root
|
|
22
|
-
</script>
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
- The registry key must match the composition root's `data-composition-id`.
|
|
26
|
-
- Do not call `tl.play()` for render-critical motion.
|
|
27
|
-
- Do not build timelines inside async code, timers, or event handlers.
|
|
28
|
-
- Keep loops finite. HyperFrames renders finite video durations.
|
|
29
|
-
|
|
30
|
-
## Core Tween Methods
|
|
31
|
-
|
|
32
|
-
- **gsap.to(targets, vars)** — animate from current state to `vars`. Most common.
|
|
33
|
-
- **gsap.from(targets, vars)** — animate from `vars` to current state (entrances).
|
|
34
|
-
- **gsap.fromTo(targets, fromVars, toVars)** — explicit start and end.
|
|
35
|
-
- **gsap.set(targets, vars)** — apply immediately (duration 0).
|
|
36
|
-
|
|
37
|
-
Always use **camelCase** property names (e.g. `backgroundColor`, `rotationX`).
|
|
38
|
-
|
|
39
|
-
## Common vars
|
|
40
|
-
|
|
41
|
-
- **duration** — seconds (default 0.5).
|
|
42
|
-
- **delay** — seconds before start.
|
|
43
|
-
- **ease** — `"power1.out"` (default), `"power3.inOut"`, `"back.out(1.7)"`, `"elastic.out(1, 0.3)"`, `"none"`.
|
|
44
|
-
- **stagger** — number `0.1` or object: `{ amount: 0.3, from: "center" }`, `{ each: 0.1, from: "random" }`.
|
|
45
|
-
- **overwrite** — `false` (default), `true`, or `"auto"`.
|
|
46
|
-
- **repeat** — finite number; never `-1` in HyperFrames. Compute repeats from the visible duration. **yoyo** — alternates direction with repeat.
|
|
47
|
-
- **onComplete**, **onStart**, **onUpdate** — callbacks.
|
|
48
|
-
- **immediateRender** — default `true` for from()/fromTo(). Set `false` on later tweens targeting the same property+element to avoid overwrite.
|
|
49
|
-
|
|
50
|
-
## Transforms and CSS
|
|
51
|
-
|
|
52
|
-
Prefer GSAP's **transform aliases** over raw `transform` string:
|
|
53
|
-
|
|
54
|
-
| GSAP property | Equivalent |
|
|
55
|
-
| --------------------------- | ------------------- |
|
|
56
|
-
| `x`, `y`, `z` | translateX/Y/Z (px) |
|
|
57
|
-
| `xPercent`, `yPercent` | translateX/Y in % |
|
|
58
|
-
| `scale`, `scaleX`, `scaleY` | scale |
|
|
59
|
-
| `rotation` | rotate (deg) |
|
|
60
|
-
| `rotationX`, `rotationY` | 3D rotate |
|
|
61
|
-
| `skewX`, `skewY` | skew |
|
|
62
|
-
| `transformOrigin` | transform-origin |
|
|
63
|
-
|
|
64
|
-
- **autoAlpha** — prefer over `opacity`. At 0: also sets `visibility: hidden`.
|
|
65
|
-
- **CSS variables** — `"--hue": 180`.
|
|
66
|
-
- **svgOrigin** _(SVG only)_ — global SVG coordinate space origin. Don't combine with `transformOrigin`.
|
|
67
|
-
- **Directional rotation** — `"360_cw"`, `"-170_short"`, `"90_ccw"`.
|
|
68
|
-
- **clearProps** — `"all"` or comma-separated; removes inline styles on complete.
|
|
69
|
-
- **Relative values** — `"+=20"`, `"-=10"`, `"*=2"`.
|
|
70
|
-
|
|
71
|
-
## Function-Based Values
|
|
72
|
-
|
|
73
|
-
```javascript
|
|
74
|
-
gsap.to(".item", {
|
|
75
|
-
x: (i, target, targets) => i * 50,
|
|
76
|
-
stagger: 0.1,
|
|
77
|
-
});
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
## Easing
|
|
81
|
-
|
|
82
|
-
Built-in eases: `power1`–`power4`, `back`, `bounce`, `circ`, `elastic`, `expo`, `sine`. Each has `.in`, `.out`, `.inOut`.
|
|
83
|
-
|
|
84
|
-
## Defaults
|
|
85
|
-
|
|
86
|
-
```javascript
|
|
87
|
-
gsap.defaults({ duration: 0.6, ease: "power2.out" });
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
## Controlling Tweens
|
|
91
|
-
|
|
92
|
-
```javascript
|
|
93
|
-
const tween = gsap.to(".box", { x: 100 });
|
|
94
|
-
tween.pause();
|
|
95
|
-
tween.play();
|
|
96
|
-
tween.reverse();
|
|
97
|
-
tween.kill();
|
|
98
|
-
tween.progress(0.5);
|
|
99
|
-
tween.time(0.2);
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
## gsap.matchMedia() (Responsive + Accessibility)
|
|
103
|
-
|
|
104
|
-
Runs setup only when a media query matches; auto-reverts when it stops matching.
|
|
105
|
-
|
|
106
|
-
```javascript
|
|
107
|
-
let mm = gsap.matchMedia();
|
|
108
|
-
mm.add(
|
|
109
|
-
{
|
|
110
|
-
isDesktop: "(min-width: 800px)",
|
|
111
|
-
reduceMotion: "(prefers-reduced-motion: reduce)",
|
|
112
|
-
},
|
|
113
|
-
(context) => {
|
|
114
|
-
const { isDesktop, reduceMotion } = context.conditions;
|
|
115
|
-
gsap.to(".box", {
|
|
116
|
-
rotation: isDesktop ? 360 : 180,
|
|
117
|
-
duration: reduceMotion ? 0 : 2,
|
|
118
|
-
});
|
|
119
|
-
},
|
|
120
|
-
);
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
---
|
|
124
|
-
|
|
125
|
-
## Timelines
|
|
126
|
-
|
|
127
|
-
### Creating a Timeline
|
|
128
|
-
|
|
129
|
-
```javascript
|
|
130
|
-
const tl = gsap.timeline({ defaults: { duration: 0.5, ease: "power2.out" } });
|
|
131
|
-
tl.to(".a", { x: 100 }).to(".b", { y: 50 }).to(".c", { opacity: 0 });
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
### Position Parameter
|
|
135
|
-
|
|
136
|
-
Third argument controls placement:
|
|
137
|
-
|
|
138
|
-
- **Absolute**: `1` — at 1s
|
|
139
|
-
- **Relative**: `"+=0.5"` — after end; `"-=0.2"` — before end
|
|
140
|
-
- **Label**: `"intro"`, `"intro+=0.3"`
|
|
141
|
-
- **Alignment**: `"<"` — same start as previous; `">"` — after previous ends; `"<0.2"` — 0.2s after previous starts
|
|
142
|
-
|
|
143
|
-
```javascript
|
|
144
|
-
tl.to(".a", { x: 100 }, 0);
|
|
145
|
-
tl.to(".b", { y: 50 }, "<"); // same start as .a
|
|
146
|
-
tl.to(".c", { opacity: 0 }, "<0.2"); // 0.2s after .b starts
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
### Labels
|
|
150
|
-
|
|
151
|
-
```javascript
|
|
152
|
-
tl.addLabel("intro", 0);
|
|
153
|
-
tl.to(".a", { x: 100 }, "intro");
|
|
154
|
-
tl.addLabel("outro", "+=0.5");
|
|
155
|
-
tl.play("outro");
|
|
156
|
-
tl.tweenFromTo("intro", "outro");
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
### Timeline Options
|
|
160
|
-
|
|
161
|
-
- **paused: true** — create paused; call `.play()` to start.
|
|
162
|
-
- **repeat**, **yoyo** — apply to whole timeline.
|
|
163
|
-
- **defaults** — vars merged into every child tween.
|
|
164
|
-
|
|
165
|
-
### Nesting Timelines
|
|
166
|
-
|
|
167
|
-
```javascript
|
|
168
|
-
const master = gsap.timeline();
|
|
169
|
-
const child = gsap.timeline();
|
|
170
|
-
child.to(".a", { x: 100 }).to(".b", { y: 50 });
|
|
171
|
-
master.add(child, 0);
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
### Playback Control
|
|
175
|
-
|
|
176
|
-
`tl.play()`, `tl.pause()`, `tl.reverse()`, `tl.restart()`, `tl.time(2)`, `tl.progress(0.5)`, `tl.kill()`.
|
|
177
|
-
|
|
178
|
-
---
|
|
179
|
-
|
|
180
|
-
## Performance
|
|
181
|
-
|
|
182
|
-
### Prefer Transform and Opacity
|
|
183
|
-
|
|
184
|
-
Animating `x`, `y`, `scale`, `rotation`, `opacity` stays on the compositor. Avoid `width`, `height`, `top`, `left` when transforms achieve the same effect.
|
|
185
|
-
|
|
186
|
-
### will-change
|
|
187
|
-
|
|
188
|
-
```css
|
|
189
|
-
will-change: transform;
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
Only on elements that actually animate.
|
|
193
|
-
|
|
194
|
-
### gsap.quickTo() for Frequent Updates
|
|
195
|
-
|
|
196
|
-
```javascript
|
|
197
|
-
let xTo = gsap.quickTo("#id", "x", { duration: 0.4, ease: "power3" }),
|
|
198
|
-
yTo = gsap.quickTo("#id", "y", { duration: 0.4, ease: "power3" });
|
|
199
|
-
container.addEventListener("mousemove", (e) => {
|
|
200
|
-
xTo(e.pageX);
|
|
201
|
-
yTo(e.pageY);
|
|
202
|
-
});
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
### Stagger > Many Tweens
|
|
206
|
-
|
|
207
|
-
Use `stagger` instead of separate tweens with manual delays.
|
|
208
|
-
|
|
209
|
-
### Cleanup
|
|
210
|
-
|
|
211
|
-
Pause or kill off-screen animations.
|
|
212
|
-
|
|
213
|
-
---
|
|
214
|
-
|
|
215
|
-
## References (loaded on demand)
|
|
216
|
-
|
|
217
|
-
- **[references/effects.md](references/effects.md)** — Drop-in effects: typewriter text, audio visualizer. Read when needing ready-made effect patterns for HyperFrames.
|
|
218
|
-
|
|
219
|
-
## Best Practices
|
|
220
|
-
|
|
221
|
-
- Use camelCase property names; prefer transform aliases and autoAlpha.
|
|
222
|
-
- Prefer timelines over chaining with delay; use the position parameter.
|
|
223
|
-
- Add labels with `addLabel()` for readable sequencing.
|
|
224
|
-
- Pass defaults into timeline constructor.
|
|
225
|
-
- Store tween/timeline return value when controlling playback.
|
|
226
|
-
|
|
227
|
-
## Do Not
|
|
228
|
-
|
|
229
|
-
- Animate layout properties (width/height/top/left) when transforms suffice.
|
|
230
|
-
- Use both svgOrigin and transformOrigin on the same SVG element.
|
|
231
|
-
- Chain animations with delay when a timeline can sequence them.
|
|
232
|
-
- Create tweens before the DOM exists.
|
|
233
|
-
- Skip cleanup — always kill tweens when no longer needed.
|
|
234
|
-
- Use infinite repeat values in HyperFrames compositions. Use finite repeat counts computed from the visible duration.
|
|
235
|
-
|
|
236
|
-
## Credits And References
|
|
237
|
-
|
|
238
|
-
- HyperFrames adapter source: `packages/core/src/runtime/adapters/gsap.ts`.
|
|
239
|
-
- GSAP documentation: https://gsap.com/docs/v3/
|
|
240
|
-
- GSAP timeline pause and seek behavior: https://gsap.com/docs/v3/GSAP/Timeline/pause%28%29/
|
|
@@ -1,297 +0,0 @@
|
|
|
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
|
-
var AUDIO_DATA = {
|
|
214
|
-
/* paste audio-data.json contents */
|
|
215
|
-
};
|
|
216
|
-
|
|
217
|
-
// Option B: sync XHR (large files — must be synchronous for deterministic timeline construction)
|
|
218
|
-
var xhr = new XMLHttpRequest();
|
|
219
|
-
xhr.open("GET", "audio-data.json", false);
|
|
220
|
-
xhr.send();
|
|
221
|
-
var AUDIO_DATA = JSON.parse(xhr.responseText);
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
**Do NOT use async `fetch()` to load audio data.** HyperFrames requires synchronous timeline construction — the capture engine reads `window.__timelines` synchronously after page load. Building timelines inside `.then()` callbacks means the timeline isn't ready when capture starts.
|
|
225
|
-
|
|
226
|
-
### Rendering Approaches
|
|
227
|
-
|
|
228
|
-
**Canvas 2D** (most common — bars, waveforms, circles, gradients):
|
|
229
|
-
|
|
230
|
-
```js
|
|
231
|
-
for (let f = 0; f < AUDIO_DATA.totalFrames; f++) {
|
|
232
|
-
tl.call(
|
|
233
|
-
() => {
|
|
234
|
-
const frame = AUDIO_DATA.frames[f];
|
|
235
|
-
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
236
|
-
// draw using frame.rms and frame.bands
|
|
237
|
-
},
|
|
238
|
-
[],
|
|
239
|
-
f / AUDIO_DATA.fps,
|
|
240
|
-
);
|
|
241
|
-
}
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
**WebGL / Three.js** — HyperFrames patches `THREE.Clock` for deterministic time. Update uniforms from audio data each frame.
|
|
245
|
-
|
|
246
|
-
**DOM Elements** — fine for < 20 elements, less performant than Canvas for many.
|
|
247
|
-
|
|
248
|
-
### Spatial Mapping
|
|
249
|
-
|
|
250
|
-
- **Horizontal**: bass left, treble right (iterate bands left-to-right)
|
|
251
|
-
- **Vertical**: bass bottom, treble top
|
|
252
|
-
- **Circular**: bass at 12 o'clock, wrap clockwise; mirror for full circle
|
|
253
|
-
|
|
254
|
-
### Smoothing
|
|
255
|
-
|
|
256
|
-
```js
|
|
257
|
-
let prev = null;
|
|
258
|
-
const smoothing = 0.25; // 0.1-0.2 snappy, 0.3-0.5 flowing
|
|
259
|
-
function smooth(f) {
|
|
260
|
-
const raw = AUDIO_DATA.frames[f];
|
|
261
|
-
if (!prev) {
|
|
262
|
-
prev = { rms: raw.rms, bands: [...raw.bands] };
|
|
263
|
-
return prev;
|
|
264
|
-
}
|
|
265
|
-
prev = {
|
|
266
|
-
rms: prev.rms * smoothing + raw.rms * (1 - smoothing),
|
|
267
|
-
bands: raw.bands.map((b, i) => prev.bands[i] * smoothing + b * (1 - smoothing)),
|
|
268
|
-
};
|
|
269
|
-
return prev;
|
|
270
|
-
}
|
|
271
|
-
```
|
|
272
|
-
|
|
273
|
-
### Motion Principles
|
|
274
|
-
|
|
275
|
-
- **Bass drives big moves** — scale, glow, position shifts
|
|
276
|
-
- **Treble drives detail** — shimmer, flicker, edge effects
|
|
277
|
-
- **RMS drives globals** — background brightness, overall energy
|
|
278
|
-
- Pick 2-3 properties to animate. More looks noisy.
|
|
279
|
-
- Keep minimums above zero — quiet sections need life.
|
|
280
|
-
|
|
281
|
-
### Band Count
|
|
282
|
-
|
|
283
|
-
| Bands | Detail | Good for |
|
|
284
|
-
| ----- | --------- | -------------------------- |
|
|
285
|
-
| 4 | Low | Background glow, pulsing |
|
|
286
|
-
| 8 | Medium | Bar charts, basic spectrum |
|
|
287
|
-
| 16 | High | Detailed EQ (default) |
|
|
288
|
-
| 32 | Very high | Dense radial layouts |
|
|
289
|
-
|
|
290
|
-
### Layering
|
|
291
|
-
|
|
292
|
-
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.
|
|
293
|
-
|
|
294
|
-
```html
|
|
295
|
-
<canvas id="bg-layer" style="position:absolute;top:0;left:0;z-index:1;"></canvas>
|
|
296
|
-
<canvas id="main-layer" style="position:absolute;top:0;left:0;z-index:2;"></canvas>
|
|
297
|
-
```
|