use-scroll-animate 6.1.1 → 6.3.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/CHANGELOG.md +33 -0
- package/dist/chunks/{base-Yno7N2eC.js → base-DchG4q_S.js} +2 -2
- package/dist/chunks/{base-Yno7N2eC.js.map → base-DchG4q_S.js.map} +1 -1
- package/dist/chunks/{core-BIOaYdgN.js → core-D2vF8kZb.js} +2 -2
- package/dist/chunks/{core-BIOaYdgN.js.map → core-D2vF8kZb.js.map} +1 -1
- package/dist/chunks/{core-CUGCsMsJ.js → core-DVyTlo9Q.js} +2 -2
- package/dist/chunks/{core-CUGCsMsJ.js.map → core-DVyTlo9Q.js.map} +1 -1
- package/dist/chunks/{fx-BqDeFywO.js → fx-DUMVKSvg.js} +2 -2
- package/dist/chunks/{fx-BqDeFywO.js.map → fx-DUMVKSvg.js.map} +1 -1
- package/dist/chunks/generative-BHIj-NU0.cjs +295 -0
- package/dist/chunks/generative-BHIj-NU0.cjs.map +1 -0
- package/dist/chunks/generative-BRUZaIsX.js +290 -0
- package/dist/chunks/generative-BRUZaIsX.js.map +1 -0
- package/dist/chunks/gpu-BBRLgEzM.cjs +388 -0
- package/dist/chunks/gpu-BBRLgEzM.cjs.map +1 -0
- package/dist/chunks/gpu-XHWzeNb5.js +381 -0
- package/dist/chunks/gpu-XHWzeNb5.js.map +1 -0
- package/dist/chunks/registry-Bu5NrAyA.js +121 -0
- package/dist/chunks/registry-Bu5NrAyA.js.map +1 -0
- package/dist/chunks/registry-DehBVRDV.cjs +131 -0
- package/dist/chunks/registry-DehBVRDV.cjs.map +1 -0
- package/dist/chunks/shared-eweTlzxv.js +50 -0
- package/dist/chunks/shared-eweTlzxv.js.map +1 -0
- package/dist/chunks/shared-jkgRH-Hx.cjs +58 -0
- package/dist/chunks/shared-jkgRH-Hx.cjs.map +1 -0
- package/dist/chunks/{spring-DfQO5USi.js → spring-BhoT09Qb.js} +2 -2
- package/dist/chunks/{spring-DfQO5USi.js.map → spring-BhoT09Qb.js.map} +1 -1
- package/dist/chunks/{variants-VNscPeTD.js → variants-C_hv_s23.js} +2 -2
- package/dist/chunks/{variants-VNscPeTD.js.map → variants-C_hv_s23.js.map} +1 -1
- package/dist/components/a11y.js +2 -2
- package/dist/components/angular.cjs +1 -0
- package/dist/components/angular.cjs.map +1 -1
- package/dist/components/angular.js +7 -6
- package/dist/components/angular.js.map +1 -1
- package/dist/components/background.js +2 -2
- package/dist/components/bridge.js +1 -1
- package/dist/components/cards.js +2 -2
- package/dist/components/click.js +3 -3
- package/dist/components/depth.js +3 -3
- package/dist/components/effects.cjs +72 -403
- package/dist/components/effects.cjs.map +1 -1
- package/dist/components/effects.js +9 -339
- package/dist/components/effects.js.map +1 -1
- package/dist/components/feedback.js +1 -1
- package/dist/components/fx-gpu.cjs +13 -0
- package/dist/components/fx-gpu.cjs.map +1 -0
- package/dist/components/fx-gpu.d.cts +63 -0
- package/dist/components/fx-gpu.d.ts +63 -0
- package/dist/components/fx-gpu.js +6 -0
- package/dist/components/fx-gpu.js.map +1 -0
- package/dist/components/fx-text.cjs +267 -0
- package/dist/components/fx-text.cjs.map +1 -0
- package/dist/components/fx-text.d.cts +70 -0
- package/dist/components/fx-text.d.ts +70 -0
- package/dist/components/fx-text.js +263 -0
- package/dist/components/fx-text.js.map +1 -0
- package/dist/components/fx.cjs +13 -133
- package/dist/components/fx.cjs.map +1 -1
- package/dist/components/fx.js +6 -125
- package/dist/components/fx.js.map +1 -1
- package/dist/components/fx2.cjs +32 -0
- package/dist/components/fx2.cjs.map +1 -0
- package/dist/components/fx2.d.cts +162 -0
- package/dist/components/fx2.d.ts +162 -0
- package/dist/components/fx2.js +22 -0
- package/dist/components/fx2.js.map +1 -0
- package/dist/components/gesture.js +4 -4
- package/dist/components/interaction.js +1 -1
- package/dist/components/layout.js +1 -1
- package/dist/components/lite.cjs +5 -9
- package/dist/components/lite.cjs.map +1 -1
- package/dist/components/lite.js +5 -9
- package/dist/components/lite.js.map +1 -1
- package/dist/components/packs.js +1 -1
- package/dist/components/page.js +3 -3
- package/dist/components/perf.js +2 -2
- package/dist/components/physics.js +3 -3
- package/dist/components/reveal.js +1 -1
- package/dist/components/solid.cjs +1 -0
- package/dist/components/solid.cjs.map +1 -1
- package/dist/components/solid.js +7 -6
- package/dist/components/solid.js.map +1 -1
- package/dist/components/svelte.cjs +1 -0
- package/dist/components/svelte.cjs.map +1 -1
- package/dist/components/svelte.js +7 -6
- package/dist/components/svelte.js.map +1 -1
- package/dist/components/svg.js +1 -1
- package/dist/components/text.js +2 -2
- package/dist/components/timeline.js +3 -3
- package/dist/components/transitions.js +1 -1
- package/dist/components/ui.js +4 -4
- package/dist/components/vue.cjs +1 -0
- package/dist/components/vue.cjs.map +1 -1
- package/dist/components/vue.js +7 -6
- package/dist/components/vue.js.map +1 -1
- package/dist/components/webgl.js +1 -1
- package/dist/components/widgets.cjs +1174 -0
- package/dist/components/widgets.cjs.map +1 -0
- package/dist/components/widgets.d.cts +206 -0
- package/dist/components/widgets.d.ts +206 -0
- package/dist/components/widgets.js +1155 -0
- package/dist/components/widgets.js.map +1 -0
- package/dist/components.cjs +10 -9
- package/dist/components.cjs.map +1 -1
- package/dist/components.js +10 -9
- package/dist/components.js.map +1 -1
- package/dist/components.umd.js +2 -2
- package/dist/components.umd.js.map +1 -1
- package/dist/index.js +2 -2
- package/dist/widgets.umd.js +2 -0
- package/dist/widgets.umd.js.map +1 -0
- package/docs/ROADMAP.md +10 -11
- package/docs/components.md +61 -0
- package/package.json +41 -1
|
@@ -1,59 +1,14 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var components_fx = require('./fx.cjs');
|
|
4
|
+
var shared = require('../chunks/shared-jkgRH-Hx.cjs');
|
|
4
5
|
var base = require('../chunks/base-BaQV-2ha.cjs');
|
|
6
|
+
var generative = require('../chunks/generative-BHIj-NU0.cjs');
|
|
7
|
+
var registry = require('../chunks/registry-DehBVRDV.cjs');
|
|
5
8
|
var components_tokens = require('./tokens.cjs');
|
|
6
9
|
var core = require('../chunks/core-BGAyaY6L.cjs');
|
|
7
10
|
require('../chunks/fx-lBGVtQO1.cjs');
|
|
8
11
|
|
|
9
|
-
let layer = null;
|
|
10
|
-
/** A fixed, pointer-transparent, aria-hidden layer for transient particles. */
|
|
11
|
-
function fxLayer() {
|
|
12
|
-
if (layer?.isConnected)
|
|
13
|
-
return layer;
|
|
14
|
-
layer = document.createElement('div');
|
|
15
|
-
layer.setAttribute('aria-hidden', 'true');
|
|
16
|
-
layer.setAttribute('data-usa-fx-layer', '');
|
|
17
|
-
layer.style.cssText = 'position:fixed;inset:0;pointer-events:none;overflow:hidden;z-index:2147483000;contain:strict';
|
|
18
|
-
document.body.appendChild(layer);
|
|
19
|
-
return layer;
|
|
20
|
-
}
|
|
21
|
-
/** Client point of the triggering pointer event, or the element's center. */
|
|
22
|
-
function origin(el, ctx) {
|
|
23
|
-
const e = ctx.event;
|
|
24
|
-
const r = el.getBoundingClientRect();
|
|
25
|
-
return e && typeof e.clientX === 'number' && (e.clientX || e.clientY) ? { x: e.clientX, y: e.clientY } : { x: r.left + r.width / 2, y: r.top + r.height / 2 };
|
|
26
|
-
}
|
|
27
|
-
/** Spawn an absolutely positioned node in the fx layer at (x, y); removed when its animation ends. */
|
|
28
|
-
function spawn(x, y, css, ctx, frames, opts, text = '') {
|
|
29
|
-
const n = document.createElement('span');
|
|
30
|
-
n.style.cssText = `position:absolute;left:${x}px;top:${y}px;${css}`;
|
|
31
|
-
if (text)
|
|
32
|
-
n.textContent = text;
|
|
33
|
-
fxLayer().appendChild(n);
|
|
34
|
-
const a = ctx.animate(n, frames, { fill: 'forwards', ...opts });
|
|
35
|
-
const rm = () => n.remove();
|
|
36
|
-
if (a)
|
|
37
|
-
a.finished.then(rm, rm);
|
|
38
|
-
else
|
|
39
|
-
rm();
|
|
40
|
-
return a;
|
|
41
|
-
}
|
|
42
|
-
/** An overlay child covering `el` (makes `el` a positioning context). Returns it and a remover. */
|
|
43
|
-
function overlay(el, css) {
|
|
44
|
-
const o = document.createElement('span');
|
|
45
|
-
o.setAttribute('aria-hidden', 'true');
|
|
46
|
-
o.style.cssText = `position:absolute;inset:0;pointer-events:none;border-radius:inherit;${css}`;
|
|
47
|
-
if (getComputedStyle(el).position === 'static')
|
|
48
|
-
el.style.position = 'relative';
|
|
49
|
-
el.appendChild(o);
|
|
50
|
-
return [o, () => o.remove()];
|
|
51
|
-
}
|
|
52
|
-
const PALETTE = ['#7c5cff', '#ff5c8a', '#22d3ee', '#facc15', '#34d399'];
|
|
53
|
-
const rand = (a, b) => a + Math.random() * (b - a);
|
|
54
|
-
/** Wait for all animations (ignoring nulls). */
|
|
55
|
-
const all = (anims) => Promise.all(anims.filter(Boolean).map((a) => a.finished.catch(() => undefined)));
|
|
56
|
-
|
|
57
12
|
const CARD_FX = [
|
|
58
13
|
{
|
|
59
14
|
name: 'holo',
|
|
@@ -62,7 +17,7 @@ const CARD_FX = [
|
|
|
62
17
|
reduced: 'run',
|
|
63
18
|
defaults: { strength: 0.55 },
|
|
64
19
|
run: (el, o, ctx) => {
|
|
65
|
-
const [layer, remove] = overlay(el, `mix-blend-mode:color-dodge;opacity:${o.strength};background:linear-gradient(115deg,transparent 20%,#ff8bd855 35%,#8bf3ff55 45%,#fff58b55 55%,transparent 70%),repeating-linear-gradient(55deg,#ffffff10 0 2px,transparent 2px 6px);background-size:250% 250%,100% 100%;background-position:50% 50%;transition:background-position .2s ease-out`);
|
|
20
|
+
const [layer, remove] = shared.overlay(el, `mix-blend-mode:color-dodge;opacity:${o.strength};background:linear-gradient(115deg,transparent 20%,#ff8bd855 35%,#8bf3ff55 45%,#fff58b55 55%,transparent 70%),repeating-linear-gradient(55deg,#ffffff10 0 2px,transparent 2px 6px);background-size:250% 250%,100% 100%;background-position:50% 50%;transition:background-position .2s ease-out`);
|
|
66
21
|
if (ctx.reduced)
|
|
67
22
|
return remove;
|
|
68
23
|
const move = (e) => {
|
|
@@ -94,7 +49,7 @@ const CARD_FX = [
|
|
|
94
49
|
run: (el, o, ctx) => {
|
|
95
50
|
if (ctx.reduced)
|
|
96
51
|
return;
|
|
97
|
-
const [g, remove] = overlay(el, `overflow:hidden;background:linear-gradient(105deg,transparent 35%,${o.color} 50%,transparent 65%);background-size:250% 100%`);
|
|
52
|
+
const [g, remove] = shared.overlay(el, `overflow:hidden;background:linear-gradient(105deg,transparent 35%,${o.color} 50%,transparent 65%);background-size:250% 100%`);
|
|
98
53
|
const a = ctx.animate(g, [{ backgroundPosition: '150% 0' }, { backgroundPosition: '-50% 0' }], { duration: o.duration, easing: 'ease-in-out' });
|
|
99
54
|
if (a)
|
|
100
55
|
a.finished.then(remove, remove);
|
|
@@ -121,7 +76,7 @@ const CARD_FX = [
|
|
|
121
76
|
run: (el, o, ctx) => {
|
|
122
77
|
const kids = Array.from(el.children);
|
|
123
78
|
const mid = (kids.length - 1) / 2;
|
|
124
|
-
return all(kids.map((k, i) => ctx.animate(k, [{ transform: 'none' }, { transform: `translateX(${(i - mid) * o.spread}px) rotate(${(i - mid) * (o.spread / 2)}deg)`, offset: 0.5 }, { transform: 'none' }], { duration: o.duration, easing: 'cubic-bezier(0.34, 1.56, 0.64, 1)' })));
|
|
79
|
+
return shared.all(kids.map((k, i) => ctx.animate(k, [{ transform: 'none' }, { transform: `translateX(${(i - mid) * o.spread}px) rotate(${(i - mid) * (o.spread / 2)}deg)`, offset: 0.5 }, { transform: 'none' }], { duration: o.duration, easing: 'cubic-bezier(0.34, 1.56, 0.64, 1)' })));
|
|
125
80
|
},
|
|
126
81
|
},
|
|
127
82
|
{
|
|
@@ -154,24 +109,24 @@ const CLICK_FX = [
|
|
|
154
109
|
run: (el, o, ctx) => {
|
|
155
110
|
if (ctx.reduced)
|
|
156
111
|
return;
|
|
157
|
-
const { x, y } = origin(el, ctx);
|
|
158
|
-
return all([0, 120].map((delay) => spawn(x, y, `width:${o.size}px;height:${o.size}px;margin:${-o.size / 2}px 0 0 ${-o.size / 2}px;border:3px solid ${o.color};border-radius:50%`, ctx, [{ transform: 'scale(0)', opacity: 0.9 }, { transform: 'scale(1)', opacity: 0 }], { duration: o.duration, delay, easing: 'cubic-bezier(0.22, 1, 0.36, 1)' })));
|
|
112
|
+
const { x, y } = shared.origin(el, ctx);
|
|
113
|
+
return shared.all([0, 120].map((delay) => shared.spawn(x, y, `width:${o.size}px;height:${o.size}px;margin:${-o.size / 2}px 0 0 ${-o.size / 2}px;border:3px solid ${o.color};border-radius:50%`, ctx, [{ transform: 'scale(0)', opacity: 0.9 }, { transform: 'scale(1)', opacity: 0 }], { duration: o.duration, delay, easing: 'cubic-bezier(0.22, 1, 0.36, 1)' })));
|
|
159
114
|
},
|
|
160
115
|
},
|
|
161
116
|
{
|
|
162
117
|
name: 'ink-splash',
|
|
163
118
|
kind: 'click',
|
|
164
119
|
description: 'Ink blobs splatter from the click point and fade.',
|
|
165
|
-
defaults: { count: 9, colors: PALETTE, duration: 800 },
|
|
120
|
+
defaults: { count: 9, colors: shared.PALETTE, duration: 800 },
|
|
166
121
|
run: (el, o, ctx) => {
|
|
167
122
|
if (ctx.reduced)
|
|
168
123
|
return;
|
|
169
|
-
const { x, y } = origin(el, ctx);
|
|
170
|
-
return all(Array.from({ length: o.count }, (_, i) => {
|
|
171
|
-
const s = rand(6, 22);
|
|
172
|
-
const ang = rand(0, Math.PI * 2);
|
|
173
|
-
const d = rand(20, 70);
|
|
174
|
-
return spawn(x, y, `width:${s}px;height:${s}px;margin:${-s / 2}px 0 0 ${-s / 2}px;background:${o.colors[i % o.colors.length]};border-radius:${rand(40, 50)}% ${rand(50, 60)}% ${rand(40, 60)}% ${rand(45, 55)}%`, ctx, [{ transform: 'translate(0,0) scale(.3)', opacity: 1 }, { transform: `translate(${Math.cos(ang) * d}px,${Math.sin(ang) * d}px) scale(1)`, opacity: 0.9, offset: 0.5 }, { transform: `translate(${Math.cos(ang) * d}px,${Math.sin(ang) * d + 8}px) scale(1.1)`, opacity: 0 }], { duration: o.duration, easing: 'cubic-bezier(0.22, 1, 0.36, 1)' });
|
|
124
|
+
const { x, y } = shared.origin(el, ctx);
|
|
125
|
+
return shared.all(Array.from({ length: o.count }, (_, i) => {
|
|
126
|
+
const s = shared.rand(6, 22);
|
|
127
|
+
const ang = shared.rand(0, Math.PI * 2);
|
|
128
|
+
const d = shared.rand(20, 70);
|
|
129
|
+
return shared.spawn(x, y, `width:${s}px;height:${s}px;margin:${-s / 2}px 0 0 ${-s / 2}px;background:${o.colors[i % o.colors.length]};border-radius:${shared.rand(40, 50)}% ${shared.rand(50, 60)}% ${shared.rand(40, 60)}% ${shared.rand(45, 55)}%`, ctx, [{ transform: 'translate(0,0) scale(.3)', opacity: 1 }, { transform: `translate(${Math.cos(ang) * d}px,${Math.sin(ang) * d}px) scale(1)`, opacity: 0.9, offset: 0.5 }, { transform: `translate(${Math.cos(ang) * d}px,${Math.sin(ang) * d + 8}px) scale(1.1)`, opacity: 0 }], { duration: o.duration, easing: 'cubic-bezier(0.22, 1, 0.36, 1)' });
|
|
175
130
|
}));
|
|
176
131
|
},
|
|
177
132
|
},
|
|
@@ -183,12 +138,12 @@ const CLICK_FX = [
|
|
|
183
138
|
run: (el, o, ctx) => {
|
|
184
139
|
if (ctx.reduced)
|
|
185
140
|
return;
|
|
186
|
-
const { x, y } = origin(el, ctx);
|
|
187
|
-
return all(Array.from({ length: o.count }, (_, i) => {
|
|
141
|
+
const { x, y } = shared.origin(el, ctx);
|
|
142
|
+
return shared.all(Array.from({ length: o.count }, (_, i) => {
|
|
188
143
|
const ang = (i / o.count) * Math.PI * 2;
|
|
189
|
-
const d = rand(40, 80);
|
|
190
|
-
const s = rand(12, 22);
|
|
191
|
-
return spawn(x, y, `font-size:${s}px;line-height:1;margin:${-s / 2}px 0 0 ${-s / 2}px;color:${o.colors[i % o.colors.length]}`, ctx, [{ transform: 'translate(0,0) rotate(0) scale(.2)', opacity: 1 }, { transform: `translate(${Math.cos(ang) * d}px,${Math.sin(ang) * d}px) rotate(${rand(180, 360)}deg) scale(1)`, opacity: 0 }], { duration: o.duration, easing: 'cubic-bezier(0.22, 1, 0.36, 1)' }, '★');
|
|
144
|
+
const d = shared.rand(40, 80);
|
|
145
|
+
const s = shared.rand(12, 22);
|
|
146
|
+
return shared.spawn(x, y, `font-size:${s}px;line-height:1;margin:${-s / 2}px 0 0 ${-s / 2}px;color:${o.colors[i % o.colors.length]}`, ctx, [{ transform: 'translate(0,0) rotate(0) scale(.2)', opacity: 1 }, { transform: `translate(${Math.cos(ang) * d}px,${Math.sin(ang) * d}px) rotate(${shared.rand(180, 360)}deg) scale(1)`, opacity: 0 }], { duration: o.duration, easing: 'cubic-bezier(0.22, 1, 0.36, 1)' }, '★');
|
|
192
147
|
}));
|
|
193
148
|
},
|
|
194
149
|
},
|
|
@@ -207,8 +162,8 @@ const CLICK_FX = [
|
|
|
207
162
|
run: (el, o, ctx) => {
|
|
208
163
|
if (ctx.reduced)
|
|
209
164
|
return;
|
|
210
|
-
const { x, y } = origin(el, ctx);
|
|
211
|
-
return all(Array.from({ length: o.rings }, (_, i) => spawn(x, y, `width:${o.size}px;height:${o.size}px;margin:${-o.size / 2}px 0 0 ${-o.size / 2}px;border:2px solid ${o.color};border-radius:50%`, ctx, [{ transform: 'scale(.1)', opacity: 0.8 }, { transform: 'scale(1)', opacity: 0 }], { duration: o.duration, delay: i * 160, easing: 'ease-out' })));
|
|
165
|
+
const { x, y } = shared.origin(el, ctx);
|
|
166
|
+
return shared.all(Array.from({ length: o.rings }, (_, i) => shared.spawn(x, y, `width:${o.size}px;height:${o.size}px;margin:${-o.size / 2}px 0 0 ${-o.size / 2}px;border:2px solid ${o.color};border-radius:50%`, ctx, [{ transform: 'scale(.1)', opacity: 0.8 }, { transform: 'scale(1)', opacity: 0 }], { duration: o.duration, delay: i * 160, easing: 'ease-out' })));
|
|
212
167
|
},
|
|
213
168
|
},
|
|
214
169
|
{
|
|
@@ -219,11 +174,11 @@ const CLICK_FX = [
|
|
|
219
174
|
run: (el, o, ctx) => {
|
|
220
175
|
if (ctx.reduced)
|
|
221
176
|
return;
|
|
222
|
-
const { x, y } = origin(el, ctx);
|
|
177
|
+
const { x, y } = shared.origin(el, ctx);
|
|
223
178
|
const chars = Array.from(String(o.emoji));
|
|
224
|
-
return all(Array.from({ length: o.count }, (_, i) => {
|
|
225
|
-
const dx = rand(-90, 90);
|
|
226
|
-
return spawn(x, y, `font-size:${rand(16, 28)}px;line-height:1`, ctx, [{ transform: 'translate(0,0) scale(.4)', opacity: 0 }, { transform: `translate(${dx * 0.6}px,${rand(-90, -50)}px) scale(1)`, opacity: 1, offset: 0.35 }, { transform: `translate(${dx}px,${rand(40, 90)}px) rotate(${rand(-60, 60)}deg) scale(.9)`, opacity: 0 }], { duration: o.duration, delay: i * 25, easing: 'cubic-bezier(0.33, 0, 0.67, 1)' }, chars[i % chars.length]);
|
|
179
|
+
return shared.all(Array.from({ length: o.count }, (_, i) => {
|
|
180
|
+
const dx = shared.rand(-90, 90);
|
|
181
|
+
return shared.spawn(x, y, `font-size:${shared.rand(16, 28)}px;line-height:1`, ctx, [{ transform: 'translate(0,0) scale(.4)', opacity: 0 }, { transform: `translate(${dx * 0.6}px,${shared.rand(-90, -50)}px) scale(1)`, opacity: 1, offset: 0.35 }, { transform: `translate(${dx}px,${shared.rand(40, 90)}px) rotate(${shared.rand(-60, 60)}deg) scale(.9)`, opacity: 0 }], { duration: o.duration, delay: i * 25, easing: 'cubic-bezier(0.33, 0, 0.67, 1)' }, chars[i % chars.length]);
|
|
227
182
|
}));
|
|
228
183
|
},
|
|
229
184
|
},
|
|
@@ -370,7 +325,7 @@ const PHYSICS_FX = [
|
|
|
370
325
|
el.dataset.usaSplit = '1';
|
|
371
326
|
}
|
|
372
327
|
const hs = bounceKeyframes(o.bounce, 32);
|
|
373
|
-
return all(Array.from(el.children).map((s, i) => ctx.animate(s, hs.map((h) => ({ transform: `translateY(${(-h * o.height).toFixed(1)}px)` })), { duration: o.duration, delay: i * o.stagger, easing: 'linear', fill: 'backwards' })));
|
|
328
|
+
return shared.all(Array.from(el.children).map((s, i) => ctx.animate(s, hs.map((h) => ({ transform: `translateY(${(-h * o.height).toFixed(1)}px)` })), { duration: o.duration, delay: i * o.stagger, easing: 'linear', fill: 'backwards' })));
|
|
374
329
|
},
|
|
375
330
|
},
|
|
376
331
|
{
|
|
@@ -504,7 +459,7 @@ const PAGE_FX = [
|
|
|
504
459
|
reduced: 'run',
|
|
505
460
|
defaults: TRANSITION_DEFAULTS,
|
|
506
461
|
run: transition((s, o, ctx, el) => {
|
|
507
|
-
const { x, y } = origin(el, ctx);
|
|
462
|
+
const { x, y } = shared.origin(el, ctx);
|
|
508
463
|
const r = Math.hypot(Math.max(x, innerWidth - x), Math.max(y, innerHeight - y)) + 2;
|
|
509
464
|
// a huge box-shadow ring around a hole: the hole shrinks to 0 to cover
|
|
510
465
|
const p = part(s, `left:${x}px;top:${y}px;width:0;height:0;border-radius:50%;box-shadow:0 0 0 ${Math.ceil(r)}px ${o.color}`);
|
|
@@ -829,292 +784,6 @@ function defineStory(tag = 'usa-story') {
|
|
|
829
784
|
}, { id: 'usa-story', text: CSS });
|
|
830
785
|
}
|
|
831
786
|
|
|
832
|
-
/** Deterministic smooth pseudo-noise in [-1, 1] (sum of sines — cheap, no tables). */
|
|
833
|
-
function noise2(x, y, t = 0) {
|
|
834
|
-
return (Math.sin(x * 1.7 + t) * Math.cos(y * 1.3 - t * 0.7) + Math.sin((x + y) * 0.9 + t * 0.5) * 0.5 + Math.cos(x * 0.6 - y * 1.1 - t * 0.3) * 0.5) / 2;
|
|
835
|
-
}
|
|
836
|
-
/** Hex `#rrggbb` → [r, g, b]. */
|
|
837
|
-
function hexRgb(hex) {
|
|
838
|
-
const m = /^#?([\da-f]{2})([\da-f]{2})([\da-f]{2})$/i.exec(hex.trim());
|
|
839
|
-
return m ? [parseInt(m[1], 16), parseInt(m[2], 16), parseInt(m[3], 16)] : [124, 92, 255];
|
|
840
|
-
}
|
|
841
|
-
/**
|
|
842
|
-
* Mount a generative canvas behind `el` and run `spec` on it. Returns the
|
|
843
|
-
* cleanup. Exposed for custom generative effects.
|
|
844
|
-
*/
|
|
845
|
-
function canvasBackground(el, fx, spec, o) {
|
|
846
|
-
const canvas = document.createElement('canvas');
|
|
847
|
-
canvas.setAttribute('aria-hidden', 'true');
|
|
848
|
-
canvas.setAttribute('data-usa-fx-canvas', '');
|
|
849
|
-
canvas.style.cssText = 'position:absolute;inset:0;width:100%;height:100%;pointer-events:none;z-index:-1;border-radius:inherit';
|
|
850
|
-
const restore = [];
|
|
851
|
-
const set = (k, v) => {
|
|
852
|
-
restore.push([k, el.style[k]]);
|
|
853
|
-
el.style[k] = v;
|
|
854
|
-
};
|
|
855
|
-
if (getComputedStyle(el).position === 'static')
|
|
856
|
-
set('position', 'relative');
|
|
857
|
-
set('isolation', 'isolate');
|
|
858
|
-
el.prepend(canvas);
|
|
859
|
-
const ctx = canvas.getContext('2d');
|
|
860
|
-
let raf = 0;
|
|
861
|
-
let visible = true;
|
|
862
|
-
let quality = Math.min(1, Math.max(0.35, Number(o.quality) || 1));
|
|
863
|
-
let w = 0;
|
|
864
|
-
let h = 0;
|
|
865
|
-
let state = null;
|
|
866
|
-
const t0 = performance.now();
|
|
867
|
-
let last = t0;
|
|
868
|
-
let slow = 0;
|
|
869
|
-
let fast = 0;
|
|
870
|
-
const resize = () => {
|
|
871
|
-
const r = el.getBoundingClientRect();
|
|
872
|
-
w = Math.max(1, Math.round(r.width));
|
|
873
|
-
h = Math.max(1, Math.round(r.height));
|
|
874
|
-
const dpr = Math.min(2, (typeof devicePixelRatio === 'number' ? devicePixelRatio : 1) || 1) * quality;
|
|
875
|
-
canvas.width = Math.max(1, Math.round(w * dpr));
|
|
876
|
-
canvas.height = Math.max(1, Math.round(h * dpr));
|
|
877
|
-
if (ctx)
|
|
878
|
-
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
|
879
|
-
state = spec.init ? spec.init(w, h, o) : {};
|
|
880
|
-
};
|
|
881
|
-
const frame = (now) => {
|
|
882
|
-
raf = 0;
|
|
883
|
-
if (!ctx)
|
|
884
|
-
return;
|
|
885
|
-
const dt = now - last;
|
|
886
|
-
last = now;
|
|
887
|
-
// adaptive quality: sustained slow frames lower the render scale, fast ones raise it
|
|
888
|
-
if (dt > 28)
|
|
889
|
-
slow++;
|
|
890
|
-
else if (dt < 18)
|
|
891
|
-
fast++;
|
|
892
|
-
if (slow > 20 && quality > 0.35) {
|
|
893
|
-
quality = Math.max(0.35, quality - 0.15);
|
|
894
|
-
slow = fast = 0;
|
|
895
|
-
resize();
|
|
896
|
-
}
|
|
897
|
-
else if (fast > 240 && quality < 1) {
|
|
898
|
-
quality = Math.min(1, quality + 0.15);
|
|
899
|
-
slow = fast = 0;
|
|
900
|
-
resize();
|
|
901
|
-
}
|
|
902
|
-
spec.draw({ ctx, w, h, t: (now - t0) / 1000, quality, state, o });
|
|
903
|
-
if (visible && !document.hidden)
|
|
904
|
-
raf = requestAnimationFrame(frame);
|
|
905
|
-
};
|
|
906
|
-
const start = () => {
|
|
907
|
-
if (!raf && ctx && !fx.reduced) {
|
|
908
|
-
last = performance.now();
|
|
909
|
-
raf = requestAnimationFrame(frame);
|
|
910
|
-
}
|
|
911
|
-
};
|
|
912
|
-
resize();
|
|
913
|
-
if (ctx)
|
|
914
|
-
spec.draw({ ctx, w, h, t: 0, quality, state, o }); // first / static frame
|
|
915
|
-
const io = typeof IntersectionObserver === 'function' ? new IntersectionObserver((es) => {
|
|
916
|
-
visible = es.some((e) => e.isIntersecting);
|
|
917
|
-
if (visible)
|
|
918
|
-
start();
|
|
919
|
-
}) : null;
|
|
920
|
-
io?.observe(el);
|
|
921
|
-
const ro = typeof ResizeObserver === 'function' ? new ResizeObserver(() => {
|
|
922
|
-
resize();
|
|
923
|
-
if (ctx && fx.reduced)
|
|
924
|
-
spec.draw({ ctx, w, h, t: 0, quality, state, o });
|
|
925
|
-
}) : null;
|
|
926
|
-
ro?.observe(el);
|
|
927
|
-
const vis = () => !document.hidden && visible && start();
|
|
928
|
-
document.addEventListener('visibilitychange', vis);
|
|
929
|
-
start();
|
|
930
|
-
return () => {
|
|
931
|
-
cancelAnimationFrame(raf);
|
|
932
|
-
raf = 0;
|
|
933
|
-
io?.disconnect();
|
|
934
|
-
ro?.disconnect();
|
|
935
|
-
document.removeEventListener('visibilitychange', vis);
|
|
936
|
-
canvas.remove();
|
|
937
|
-
for (const [k, v] of restore)
|
|
938
|
-
el.style[k] = v;
|
|
939
|
-
};
|
|
940
|
-
}
|
|
941
|
-
const gen = (name, description, defaults, spec) => ({
|
|
942
|
-
name,
|
|
943
|
-
kind: 'background',
|
|
944
|
-
description,
|
|
945
|
-
reduced: 'run',
|
|
946
|
-
defaults: { colors: PALETTE, background: '#0b0d12', speed: 1, quality: 1, ...defaults },
|
|
947
|
-
run: (el, o, ctx) => canvasBackground(el, ctx, spec, o),
|
|
948
|
-
});
|
|
949
|
-
/** Low-resolution scalar field → ImageData, drawn scaled up (used by voronoi / metaballs / contours). */
|
|
950
|
-
function field(f, cell, px) {
|
|
951
|
-
const step = Math.max(2, Math.round(cell / f.quality));
|
|
952
|
-
const cw = Math.max(1, Math.ceil(f.w / step));
|
|
953
|
-
const ch = Math.max(1, Math.ceil(f.h / step));
|
|
954
|
-
const st = f.state;
|
|
955
|
-
if (!st.buf || st.buf.width !== cw || st.buf.height !== ch) {
|
|
956
|
-
st.buf = document.createElement('canvas');
|
|
957
|
-
st.buf.width = cw;
|
|
958
|
-
st.buf.height = ch;
|
|
959
|
-
st.bctx = st.buf.getContext('2d');
|
|
960
|
-
st.img = st.bctx?.createImageData(cw, ch);
|
|
961
|
-
}
|
|
962
|
-
if (!st.bctx || !st.img)
|
|
963
|
-
return;
|
|
964
|
-
const d = st.img.data;
|
|
965
|
-
for (let y = 0; y < ch; y++)
|
|
966
|
-
for (let x = 0; x < cw; x++)
|
|
967
|
-
px(x * step, y * step, d, (y * cw + x) * 4);
|
|
968
|
-
st.bctx.putImageData(st.img, 0, 0);
|
|
969
|
-
f.ctx.imageSmoothingEnabled = true;
|
|
970
|
-
f.ctx.drawImage(st.buf, 0, 0, f.w, f.h);
|
|
971
|
-
}
|
|
972
|
-
const GENERATIVE_FX = [
|
|
973
|
-
gen('flow-field', 'Particles drift along a slowly changing flow field, leaving silky trails.', { count: 600, fade: 0.06 }, {
|
|
974
|
-
init: (w, h, o) => ({ p: Array.from({ length: o.count }, () => [Math.random() * w, Math.random() * h]) }),
|
|
975
|
-
draw: ({ ctx, w, h, t, state, o, quality }) => {
|
|
976
|
-
ctx.fillStyle = o.background;
|
|
977
|
-
ctx.globalAlpha = t === 0 ? 1 : o.fade;
|
|
978
|
-
ctx.fillRect(0, 0, w, h);
|
|
979
|
-
ctx.globalAlpha = 0.8;
|
|
980
|
-
const n = Math.round(state.p.length * quality);
|
|
981
|
-
const steps = t === 0 ? 40 : 1;
|
|
982
|
-
for (let i = 0; i < n; i++) {
|
|
983
|
-
const q = state.p[i];
|
|
984
|
-
ctx.fillStyle = o.colors[i % o.colors.length];
|
|
985
|
-
for (let s = 0; s < steps; s++) {
|
|
986
|
-
const a = noise2(q[0] * 0.004, q[1] * 0.004, t * 0.15 * o.speed) * Math.PI * 2;
|
|
987
|
-
q[0] += Math.cos(a) * 1.2 * o.speed;
|
|
988
|
-
q[1] += Math.sin(a) * 1.2 * o.speed;
|
|
989
|
-
if (q[0] < 0 || q[0] > w || q[1] < 0 || q[1] > h)
|
|
990
|
-
(q[0] = Math.random() * w), (q[1] = Math.random() * h);
|
|
991
|
-
ctx.fillRect(q[0], q[1], 1.4, 1.4);
|
|
992
|
-
}
|
|
993
|
-
}
|
|
994
|
-
ctx.globalAlpha = 1;
|
|
995
|
-
},
|
|
996
|
-
}),
|
|
997
|
-
gen('voronoi', 'Drifting Voronoi cells in the palette, with darker borders.', { seeds: 14, cell: 6 }, {
|
|
998
|
-
init: (w, h, o) => ({ s: Array.from({ length: o.seeds }, (_, i) => ({ x: Math.random() * w, y: Math.random() * h, vx: Math.random() - 0.5, vy: Math.random() - 0.5, c: hexRgb(o.colors[i % o.colors.length]) })) }),
|
|
999
|
-
draw: (f) => {
|
|
1000
|
-
const { w, h, state, o } = f;
|
|
1001
|
-
for (const s of state.s) {
|
|
1002
|
-
s.x += s.vx * o.speed;
|
|
1003
|
-
s.y += s.vy * o.speed;
|
|
1004
|
-
if (s.x < 0 || s.x > w)
|
|
1005
|
-
s.vx *= -1;
|
|
1006
|
-
if (s.y < 0 || s.y > h)
|
|
1007
|
-
s.vy *= -1;
|
|
1008
|
-
}
|
|
1009
|
-
field(f, o.cell, (x, y, d, i) => {
|
|
1010
|
-
let b = Infinity;
|
|
1011
|
-
let b2 = Infinity;
|
|
1012
|
-
let c = state.s[0].c;
|
|
1013
|
-
for (const s of state.s) {
|
|
1014
|
-
const dd = (s.x - x) ** 2 + (s.y - y) ** 2;
|
|
1015
|
-
if (dd < b)
|
|
1016
|
-
(b2 = b), (b = dd), (c = s.c);
|
|
1017
|
-
else if (dd < b2)
|
|
1018
|
-
b2 = dd;
|
|
1019
|
-
}
|
|
1020
|
-
const edge = Math.sqrt(b2) - Math.sqrt(b) < 6 ? 0.55 : 1;
|
|
1021
|
-
d[i] = c[0] * edge;
|
|
1022
|
-
d[i + 1] = c[1] * edge;
|
|
1023
|
-
d[i + 2] = c[2] * edge;
|
|
1024
|
-
d[i + 3] = 255;
|
|
1025
|
-
});
|
|
1026
|
-
},
|
|
1027
|
-
}),
|
|
1028
|
-
gen('mesh-gradient', 'Soft blobs of colour orbit and blend into a living mesh gradient.', { blobs: 4, blur: 0.65 }, {
|
|
1029
|
-
draw: ({ ctx, w, h, t, o }) => {
|
|
1030
|
-
ctx.fillStyle = o.background;
|
|
1031
|
-
ctx.fillRect(0, 0, w, h);
|
|
1032
|
-
const r = Math.max(w, h) * o.blur;
|
|
1033
|
-
for (let i = 0; i < o.blobs; i++) {
|
|
1034
|
-
const a = t * 0.25 * o.speed + (i * Math.PI * 2) / o.blobs;
|
|
1035
|
-
const x = w / 2 + Math.cos(a * (1 + i * 0.13)) * w * 0.32;
|
|
1036
|
-
const y = h / 2 + Math.sin(a * (0.8 + i * 0.11)) * h * 0.32;
|
|
1037
|
-
const [cr, cg, cb] = hexRgb(o.colors[i % o.colors.length]);
|
|
1038
|
-
const g = ctx.createRadialGradient(x, y, 0, x, y, r);
|
|
1039
|
-
g.addColorStop(0, `rgba(${cr},${cg},${cb},0.7)`);
|
|
1040
|
-
g.addColorStop(1, `rgba(${cr},${cg},${cb},0)`);
|
|
1041
|
-
ctx.fillStyle = g;
|
|
1042
|
-
ctx.fillRect(0, 0, w, h);
|
|
1043
|
-
}
|
|
1044
|
-
},
|
|
1045
|
-
}),
|
|
1046
|
-
gen('starfield', 'Stars stream toward the viewer (warp speed with `speed: 4`).', { stars: 400, color: '#ffffff' }, {
|
|
1047
|
-
init: (_w, _h, o) => ({ s: Array.from({ length: o.stars }, () => [Math.random() * 2 - 1, Math.random() * 2 - 1, Math.random()]) }),
|
|
1048
|
-
draw: ({ ctx, w, h, t, state, o, quality }) => {
|
|
1049
|
-
ctx.fillStyle = o.background;
|
|
1050
|
-
ctx.fillRect(0, 0, w, h);
|
|
1051
|
-
ctx.fillStyle = o.color;
|
|
1052
|
-
const n = Math.round(state.s.length * quality);
|
|
1053
|
-
for (let i = 0; i < n; i++) {
|
|
1054
|
-
const s = state.s[i];
|
|
1055
|
-
if (t > 0)
|
|
1056
|
-
s[2] -= 0.004 * o.speed;
|
|
1057
|
-
if (s[2] <= 0.01)
|
|
1058
|
-
(s[0] = Math.random() * 2 - 1), (s[1] = Math.random() * 2 - 1), (s[2] = 1);
|
|
1059
|
-
const x = w / 2 + (s[0] / s[2]) * w * 0.5;
|
|
1060
|
-
const y = h / 2 + (s[1] / s[2]) * h * 0.5;
|
|
1061
|
-
if (x < 0 || x > w || y < 0 || y > h)
|
|
1062
|
-
continue;
|
|
1063
|
-
const size = (1 - s[2]) * 2.6;
|
|
1064
|
-
ctx.globalAlpha = Math.min(1, (1 - s[2]) * 1.6);
|
|
1065
|
-
ctx.fillRect(x, y, size, size);
|
|
1066
|
-
}
|
|
1067
|
-
ctx.globalAlpha = 1;
|
|
1068
|
-
},
|
|
1069
|
-
}),
|
|
1070
|
-
gen('metaballs', 'Gooey blobs that merge and split (low-resolution field, scaled up).', { balls: 6, cell: 5, threshold: 1 }, {
|
|
1071
|
-
init: (w, h, o) => ({ b: Array.from({ length: o.balls }, () => ({ x: Math.random() * w, y: Math.random() * h, vx: (Math.random() - 0.5) * 1.6, vy: (Math.random() - 0.5) * 1.6, r: Math.min(w, h) * (0.08 + Math.random() * 0.08) })) }),
|
|
1072
|
-
draw: (f) => {
|
|
1073
|
-
const { w, h, state, o } = f;
|
|
1074
|
-
for (const b of state.b) {
|
|
1075
|
-
b.x += b.vx * o.speed;
|
|
1076
|
-
b.y += b.vy * o.speed;
|
|
1077
|
-
if (b.x < 0 || b.x > w)
|
|
1078
|
-
b.vx *= -1;
|
|
1079
|
-
if (b.y < 0 || b.y > h)
|
|
1080
|
-
b.vy *= -1;
|
|
1081
|
-
}
|
|
1082
|
-
const [ar, ag, ab] = hexRgb(o.colors[0]);
|
|
1083
|
-
const [br, bg, bb] = hexRgb(o.colors[1] || o.colors[0]);
|
|
1084
|
-
const [kr, kg, kb] = hexRgb(o.background);
|
|
1085
|
-
field(f, o.cell, (x, y, d, i) => {
|
|
1086
|
-
let v = 0;
|
|
1087
|
-
for (const b of state.b)
|
|
1088
|
-
v += (b.r * b.r) / ((b.x - x) ** 2 + (b.y - y) ** 2 + 1);
|
|
1089
|
-
const inside = v >= o.threshold;
|
|
1090
|
-
const k = Math.min(1, (v - o.threshold) * 0.8);
|
|
1091
|
-
d[i] = inside ? ar + (br - ar) * k : kr;
|
|
1092
|
-
d[i + 1] = inside ? ag + (bg - ag) * k : kg;
|
|
1093
|
-
d[i + 2] = inside ? ab + (bb - ab) * k : kb;
|
|
1094
|
-
d[i + 3] = 255;
|
|
1095
|
-
});
|
|
1096
|
-
},
|
|
1097
|
-
}),
|
|
1098
|
-
gen('contours', 'Topographic contour lines over a slowly shifting height field.', { levels: 9, cell: 4, color: '#7c5cff' }, {
|
|
1099
|
-
draw: (f) => {
|
|
1100
|
-
const { t, o } = f;
|
|
1101
|
-
const [lr, lg, lb] = hexRgb(o.color);
|
|
1102
|
-
const [kr, kg, kb] = hexRgb(o.background);
|
|
1103
|
-
const z = (x, y) => (noise2(x * 0.006, y * 0.006, t * 0.2 * o.speed) + 1) / 2;
|
|
1104
|
-
const step = Math.max(2, Math.round(o.cell / f.quality));
|
|
1105
|
-
field(f, o.cell, (x, y, d, i) => {
|
|
1106
|
-
const a = Math.floor(z(x, y) * o.levels);
|
|
1107
|
-
const line = a !== Math.floor(z(x + step, y) * o.levels) || a !== Math.floor(z(x, y + step) * o.levels);
|
|
1108
|
-
const shade = 0.12 + (a / o.levels) * 0.18;
|
|
1109
|
-
d[i] = line ? lr : kr + (lr - kr) * shade;
|
|
1110
|
-
d[i + 1] = line ? lg : kg + (lg - kg) * shade;
|
|
1111
|
-
d[i + 2] = line ? lb : kb + (lb - kb) * shade;
|
|
1112
|
-
d[i + 3] = 255;
|
|
1113
|
-
});
|
|
1114
|
-
},
|
|
1115
|
-
}),
|
|
1116
|
-
];
|
|
1117
|
-
|
|
1118
787
|
let actx = null;
|
|
1119
788
|
let current = null;
|
|
1120
789
|
const mediaSources = new WeakMap();
|
|
@@ -1279,7 +948,7 @@ function bindBeat(el, name, options = {}) {
|
|
|
1279
948
|
const { threshold, cooldown, history, floor, ...fx } = options;
|
|
1280
949
|
return onBeat(() => {
|
|
1281
950
|
if (!base.prefersReducedMotion())
|
|
1282
|
-
|
|
951
|
+
registry.playEffect(el, name, fx).catch(() => undefined);
|
|
1283
952
|
}, { threshold, cooldown, history, floor });
|
|
1284
953
|
}
|
|
1285
954
|
// --- visual effects ----------------------------------------------------------
|
|
@@ -1300,8 +969,8 @@ const audioFx = (name, description, defaults, spec) => ({
|
|
|
1300
969
|
kind: 'background',
|
|
1301
970
|
description,
|
|
1302
971
|
reduced: 'skip',
|
|
1303
|
-
defaults: { colors: PALETTE, background: '#0b0d12', speed: 1, quality: 1, ...defaults },
|
|
1304
|
-
run: (el, o, ctx) => canvasBackground(el, ctx, spec, o),
|
|
972
|
+
defaults: { colors: shared.PALETTE, background: '#0b0d12', speed: 1, quality: 1, ...defaults },
|
|
973
|
+
run: (el, o, ctx) => generative.canvasBackground(el, ctx, spec, o),
|
|
1305
974
|
});
|
|
1306
975
|
const AUDIO_FX = [
|
|
1307
976
|
audioFx('spectrum-bars', 'Frequency bars dance to the audio (mirror them with `mirror: true`).', { bars: 48, gap: 2, mirror: false }, {
|
|
@@ -1326,7 +995,7 @@ const AUDIO_FX = [
|
|
|
1326
995
|
ctx.fillStyle = o.background;
|
|
1327
996
|
ctx.fillRect(0, 0, w, h);
|
|
1328
997
|
const s = read(t, 32);
|
|
1329
|
-
const [r, g, b] = hexRgb(o.color);
|
|
998
|
+
const [r, g, b] = generative.hexRgb(o.color);
|
|
1330
999
|
const base = Math.min(w, h) * 0.18;
|
|
1331
1000
|
for (let i = 0; i < o.rings; i++) {
|
|
1332
1001
|
const rad = base * (1 + i * 0.55) * (1 + s.bass * 0.6);
|
|
@@ -1414,7 +1083,7 @@ function defineAudio(tag = 'usa-audio') {
|
|
|
1414
1083
|
catch {
|
|
1415
1084
|
/* ignore bad JSON */
|
|
1416
1085
|
}
|
|
1417
|
-
|
|
1086
|
+
registry.playEffect(el, el.dataset.usaBeat || 'pulse', opts).catch(() => undefined);
|
|
1418
1087
|
});
|
|
1419
1088
|
}, { threshold: this.num('threshold', 1.35), cooldown: this.num('cooldown', 250) });
|
|
1420
1089
|
}
|
|
@@ -1446,7 +1115,7 @@ const touchOk = (e, o) => o.touch || e.pointerType !== 'touch';
|
|
|
1446
1115
|
function overlayCanvas(draw) {
|
|
1447
1116
|
const c = document.createElement('canvas');
|
|
1448
1117
|
c.style.cssText = 'position:absolute;inset:0;width:100%;height:100%';
|
|
1449
|
-
fxLayer().appendChild(c);
|
|
1118
|
+
shared.fxLayer().appendChild(c);
|
|
1450
1119
|
const g = c.getContext('2d');
|
|
1451
1120
|
let raf = 0;
|
|
1452
1121
|
const frame = (now) => {
|
|
@@ -1508,7 +1177,7 @@ const CURSOR_FX = [
|
|
|
1508
1177
|
description: 'A glowing comet tail follows the pointer over the element (persistent; `color`, `width`, `life`).',
|
|
1509
1178
|
defaults: { color: '#7c5cff', width: 10, life: 320, touch: false },
|
|
1510
1179
|
run: (el, o) => trail(el, o, (g, pts, now) => {
|
|
1511
|
-
const [r, gg, b] = hexRgb(o.color);
|
|
1180
|
+
const [r, gg, b] = generative.hexRgb(o.color);
|
|
1512
1181
|
g.lineCap = 'round';
|
|
1513
1182
|
for (let i = 1; i < pts.length; i++) {
|
|
1514
1183
|
const k = 1 - (now - pts[i].t) / o.life;
|
|
@@ -1546,7 +1215,7 @@ const CURSOR_FX = [
|
|
|
1546
1215
|
name: 'sparkle-trail',
|
|
1547
1216
|
kind: 'cursor',
|
|
1548
1217
|
description: 'Little stars twinkle off the pointer as it moves (persistent; `colors`, `spacing` px between stars).',
|
|
1549
|
-
defaults: { colors: PALETTE, spacing: 14, size: 14, touch: false },
|
|
1218
|
+
defaults: { colors: shared.PALETTE, spacing: 14, size: 14, touch: false },
|
|
1550
1219
|
run: (el, o, ctx) => {
|
|
1551
1220
|
let lx = -1e4;
|
|
1552
1221
|
let ly = -1e4;
|
|
@@ -1555,8 +1224,8 @@ const CURSOR_FX = [
|
|
|
1555
1224
|
return;
|
|
1556
1225
|
lx = e.clientX;
|
|
1557
1226
|
ly = e.clientY;
|
|
1558
|
-
const s = o.size * rand(0.6, 1.2);
|
|
1559
|
-
spawn(e.clientX - s / 2, e.clientY - s / 2, `font-size:${s}px;line-height:1;color:${o.colors[Math.floor(rand(0, o.colors.length))]}`, ctx, [{ transform: 'translate(0,0) scale(0) rotate(0deg)', opacity: 1 }, { transform: `translate(${rand(-14, 14)}px,${rand(4, 26)}px) scale(1) rotate(${rand(-90, 90)}deg)`, opacity: 0 }], { duration: rand(500, 800), easing: 'ease-out' }, '✦');
|
|
1227
|
+
const s = o.size * shared.rand(0.6, 1.2);
|
|
1228
|
+
shared.spawn(e.clientX - s / 2, e.clientY - s / 2, `font-size:${s}px;line-height:1;color:${o.colors[Math.floor(shared.rand(0, o.colors.length))]}`, ctx, [{ transform: 'translate(0,0) scale(0) rotate(0deg)', opacity: 1 }, { transform: `translate(${shared.rand(-14, 14)}px,${shared.rand(4, 26)}px) scale(1) rotate(${shared.rand(-90, 90)}deg)`, opacity: 0 }], { duration: shared.rand(500, 800), easing: 'ease-out' }, '✦');
|
|
1560
1229
|
};
|
|
1561
1230
|
el.addEventListener('pointermove', move, { passive: true });
|
|
1562
1231
|
return () => el.removeEventListener('pointermove', move);
|
|
@@ -1580,7 +1249,7 @@ const CURSOR_FX = [
|
|
|
1580
1249
|
const leave = () => ((p.x = -1e4), (p.y = -1e4));
|
|
1581
1250
|
el.addEventListener('pointermove', move, { passive: true });
|
|
1582
1251
|
el.addEventListener('pointerleave', leave);
|
|
1583
|
-
const off = canvasBackground(el, ctx, {
|
|
1252
|
+
const off = generative.canvasBackground(el, ctx, {
|
|
1584
1253
|
draw: ({ ctx: g, w, h }) => {
|
|
1585
1254
|
g.clearRect(0, 0, w, h);
|
|
1586
1255
|
if (o.background !== 'transparent') {
|
|
@@ -1614,7 +1283,7 @@ const CURSOR_FX = [
|
|
|
1614
1283
|
description: 'A soft light follows the pointer across the element, easing behind it (persistent; `color`, `size`).',
|
|
1615
1284
|
defaults: { color: '#ffffff', size: 260, ease: 0.18, touch: false },
|
|
1616
1285
|
run: (el, o) => {
|
|
1617
|
-
const [r, g, b] = hexRgb(o.color);
|
|
1286
|
+
const [r, g, b] = generative.hexRgb(o.color);
|
|
1618
1287
|
const s = document.createElement('span');
|
|
1619
1288
|
s.setAttribute('aria-hidden', 'true');
|
|
1620
1289
|
s.style.cssText = `position:absolute;inset:0;pointer-events:none;border-radius:inherit;opacity:0;transition:opacity .25s;mix-blend-mode:soft-light;background:radial-gradient(circle ${o.size / 2}px at var(--sx,50%) var(--sy,50%),rgba(${r},${g},${b},.75),transparent)`;
|
|
@@ -1700,7 +1369,7 @@ function bindGesture(el, gesture, effect, o = {}) {
|
|
|
1700
1369
|
if (typeof effect === 'function')
|
|
1701
1370
|
effect(d, e);
|
|
1702
1371
|
else
|
|
1703
|
-
|
|
1372
|
+
registry.playEffect(el, effect, effectOptions, e).catch(() => undefined);
|
|
1704
1373
|
};
|
|
1705
1374
|
const twistAngle = () => {
|
|
1706
1375
|
const [a, b] = [...pts.values()];
|
|
@@ -1814,7 +1483,7 @@ function defineGestureFx(tag = 'usa-gesture-fx') {
|
|
|
1814
1483
|
}
|
|
1815
1484
|
const target = this.flag('self') ? this : this.firstElementChild || this;
|
|
1816
1485
|
const effect = this.str('effect', 'pulse');
|
|
1817
|
-
this.onCleanup(bindGesture(this, this.gesture, (_d, e) => void
|
|
1486
|
+
this.onCleanup(bindGesture(this, this.gesture, (_d, e) => void registry.playEffect(target, effect, effectOptions, e).catch(() => undefined), {
|
|
1818
1487
|
velocity: this.num('velocity', 0.8),
|
|
1819
1488
|
angle: this.num('angle', 30),
|
|
1820
1489
|
duration: this.num('duration', 650),
|
|
@@ -1855,11 +1524,11 @@ function bumpCount(el, delta, ctx) {
|
|
|
1855
1524
|
const pop = (el, ctx, s = 1.25, d = 380) => ctx.animate(el, [{ transform: 'scale(1)' }, { transform: `scale(${s})`, offset: 0.4 }, { transform: 'scale(1)' }], { duration: d, easing: 'cubic-bezier(.2,1.4,.4,1)' });
|
|
1856
1525
|
/** A few glyphs flying out of the pointer / centre. */
|
|
1857
1526
|
function burst(el, ctx, glyph, color, n = 6, rise = false) {
|
|
1858
|
-
const { x, y } = origin(el, ctx);
|
|
1859
|
-
return all(Array.from({ length: n }, (_, i) => {
|
|
1860
|
-
const a = rise ? -Math.PI / 2 + rand(-0.6, 0.6) : (i / n) * Math.PI * 2;
|
|
1861
|
-
const d = rand(28, 56);
|
|
1862
|
-
return spawn(x - 7, y - 7, `font-size:14px;line-height:1;color:${color}`, ctx, [{ transform: 'translate(0,0) scale(.4)', opacity: 1 }, { transform: `translate(${Math.cos(a) * d}px,${Math.sin(a) * d}px) scale(1)`, opacity: 0 }], { duration: rand(500, 750), easing: 'cubic-bezier(.2,.8,.3,1)' }, glyph);
|
|
1527
|
+
const { x, y } = shared.origin(el, ctx);
|
|
1528
|
+
return shared.all(Array.from({ length: n }, (_, i) => {
|
|
1529
|
+
const a = rise ? -Math.PI / 2 + shared.rand(-0.6, 0.6) : (i / n) * Math.PI * 2;
|
|
1530
|
+
const d = shared.rand(28, 56);
|
|
1531
|
+
return shared.spawn(x - 7, y - 7, `font-size:14px;line-height:1;color:${color}`, ctx, [{ transform: 'translate(0,0) scale(.4)', opacity: 1 }, { transform: `translate(${Math.cos(a) * d}px,${Math.sin(a) * d}px) scale(1)`, opacity: 0 }], { duration: shared.rand(500, 750), easing: 'cubic-bezier(.2,.8,.3,1)' }, glyph);
|
|
1863
1532
|
}));
|
|
1864
1533
|
}
|
|
1865
1534
|
const click = (name, description, defaults, run) => ({ name, kind: 'click', description, defaults, run });
|
|
@@ -1902,7 +1571,7 @@ const MICRO_FX = [
|
|
|
1902
1571
|
if (el.getAttribute('aria-busy') === 'true')
|
|
1903
1572
|
return;
|
|
1904
1573
|
el.setAttribute('aria-busy', 'true');
|
|
1905
|
-
const [bar, remove] = overlay(el, `background:${o.color}55;transform-origin:left;transform:scaleX(0)`);
|
|
1574
|
+
const [bar, remove] = shared.overlay(el, `background:${o.color}55;transform-origin:left;transform:scaleX(0)`);
|
|
1906
1575
|
const a = ctx.animate(bar, [{ transform: 'scaleX(0)' }, { transform: 'scaleX(1)' }], { duration: o.duration, easing: 'linear', fill: 'forwards' });
|
|
1907
1576
|
const done = a ? a.finished.catch(() => undefined) : Promise.resolve();
|
|
1908
1577
|
return done.then(() => {
|
|
@@ -1928,12 +1597,12 @@ const MICRO_FX = [
|
|
|
1928
1597
|
click('send-plane', 'A paper plane ✈ takes off from the button.', { color: '#22d3ee' }, (el, o, ctx) => {
|
|
1929
1598
|
const r = el.getBoundingClientRect();
|
|
1930
1599
|
pop(el, ctx, 0.92, 200);
|
|
1931
|
-
return spawn(r.left + r.width / 2 - 8, r.top + r.height / 2 - 8, `font-size:16px;color:${o.color}`, ctx, [{ transform: 'translate(0,0) rotate(0)', opacity: 1 }, { transform: 'translate(40px,-10px) rotate(-10deg)', opacity: 1, offset: 0.4 }, { transform: 'translate(160px,-90px) rotate(-25deg)', opacity: 0 }], { duration: 800, easing: 'ease-in' }, '✈')?.finished;
|
|
1600
|
+
return shared.spawn(r.left + r.width / 2 - 8, r.top + r.height / 2 - 8, `font-size:16px;color:${o.color}`, ctx, [{ transform: 'translate(0,0) rotate(0)', opacity: 1 }, { transform: 'translate(40px,-10px) rotate(-10deg)', opacity: 1, offset: 0.4 }, { transform: 'translate(160px,-90px) rotate(-25deg)', opacity: 0 }], { duration: 800, easing: 'ease-in' }, '✈')?.finished;
|
|
1932
1601
|
}),
|
|
1933
1602
|
click('add-to-cart', 'Bumps `[data-count]` by one and floats a "+1" (`text`).', { text: '+1', color: '#34d399' }, (el, o, ctx) => {
|
|
1934
1603
|
bumpCount(el, 1, ctx);
|
|
1935
|
-
const { x, y } = origin(el, ctx);
|
|
1936
|
-
return spawn(x - 10, y - 10, `font:700 14px system-ui;color:${o.color}`, ctx, [{ transform: 'translateY(0)', opacity: 1 }, { transform: 'translateY(-40px)', opacity: 0 }], { duration: 700, easing: 'ease-out' }, o.text)?.finished;
|
|
1604
|
+
const { x, y } = shared.origin(el, ctx);
|
|
1605
|
+
return shared.spawn(x - 10, y - 10, `font:700 14px system-ui;color:${o.color}`, ctx, [{ transform: 'translateY(0)', opacity: 1 }, { transform: 'translateY(-40px)', opacity: 0 }], { duration: 700, easing: 'ease-out' }, o.text)?.finished;
|
|
1937
1606
|
}),
|
|
1938
1607
|
click('counter-bump', 'Adds `step` to `[data-count]` with a rolling number.', { step: 1 }, (el, o, ctx) => void bumpCount(el, Number(o.step) || 1, ctx)),
|
|
1939
1608
|
click('upvote', 'Toggles an upvote: the arrow nudges up and `[data-count]` ±1.', {}, (el, _o, ctx) => {
|
|
@@ -1967,7 +1636,7 @@ const MICRO_FX = [
|
|
|
1967
1636
|
}),
|
|
1968
1637
|
attn('error-flash', 'Flashes the element red once (no more than one flash per call).', { color: '#ff5c8a' }, (el, o, ctx) => ctx.animate(el, [{ boxShadow: `0 0 0 0 ${o.color}00` }, { boxShadow: `0 0 0 4px ${o.color}`, offset: 0.3 }, { boxShadow: `0 0 0 0 ${o.color}00` }], { duration: 700 })),
|
|
1969
1638
|
attn('success-check', 'A green ✓ badge pops over the element and fades.', { color: '#34d399' }, (el, o, ctx) => {
|
|
1970
|
-
const [b, remove] = overlay(el, `display:grid;place-items:center;font:700 22px system-ui;color:#fff;background:${o.color}d0`);
|
|
1639
|
+
const [b, remove] = shared.overlay(el, `display:grid;place-items:center;font:700 22px system-ui;color:#fff;background:${o.color}d0`);
|
|
1971
1640
|
b.textContent = '✓';
|
|
1972
1641
|
const a = ctx.animate(b, [{ opacity: 0, transform: 'scale(.6)' }, { opacity: 1, transform: 'scale(1)', offset: 0.3 }, { opacity: 1, offset: 0.75 }, { opacity: 0 }], { duration: 1100, easing: 'ease-out' });
|
|
1973
1642
|
return a ? a.finished.then(remove, remove) : void setTimeout(remove, 900);
|
|
@@ -2082,7 +1751,7 @@ function themePreset(t, role) {
|
|
|
2082
1751
|
function playThemeEffect(el, role, theme) {
|
|
2083
1752
|
const name = theme || el.closest('[data-usa-theme]')?.getAttribute('data-usa-theme') || 'neon';
|
|
2084
1753
|
const pr = themePreset(name, role);
|
|
2085
|
-
return
|
|
1754
|
+
return registry.playEffect(el, pr.effect, pr.options);
|
|
2086
1755
|
}
|
|
2087
1756
|
const THEME_FX = [
|
|
2088
1757
|
{
|
|
@@ -2105,7 +1774,7 @@ const THEME_FX = [
|
|
|
2105
1774
|
description: 'A bright diagonal shine sweeps across frosted glass.',
|
|
2106
1775
|
defaults: { duration: 700 },
|
|
2107
1776
|
run: (el, o, ctx) => {
|
|
2108
|
-
const [s, remove] = overlay(el, 'overflow:hidden;background:linear-gradient(105deg,transparent 35%,#ffffff8c 50%,transparent 65%);background-size:250% 100%;background-position:120% 0');
|
|
1777
|
+
const [s, remove] = shared.overlay(el, 'overflow:hidden;background:linear-gradient(105deg,transparent 35%,#ffffff8c 50%,transparent 65%);background-size:250% 100%;background-position:120% 0');
|
|
2109
1778
|
const a = ctx.animate(s, [{ backgroundPosition: '120% 0' }, { backgroundPosition: '-20% 0' }], { duration: o.duration, easing: 'ease-in-out' });
|
|
2110
1779
|
return a ? a.finished.then(remove, remove) : void remove();
|
|
2111
1780
|
},
|
|
@@ -2117,7 +1786,7 @@ const THEME_FX = [
|
|
|
2117
1786
|
reduced: 'run',
|
|
2118
1787
|
defaults: { opacity: 0.18 },
|
|
2119
1788
|
run: (el, o, ctx) => {
|
|
2120
|
-
const [s, remove] = overlay(el, `opacity:${o.opacity};background:repeating-linear-gradient(0deg,#000 0 1px,transparent 1px 3px);mix-blend-mode:multiply`);
|
|
1789
|
+
const [s, remove] = shared.overlay(el, `opacity:${o.opacity};background:repeating-linear-gradient(0deg,#000 0 1px,transparent 1px 3px);mix-blend-mode:multiply`);
|
|
2121
1790
|
const a = ctx.reduced ? null : ctx.animate(s, [{ backgroundPosition: '0 0' }, { backgroundPosition: '0 30px' }], { duration: 2400, iterations: Infinity, easing: 'linear' });
|
|
2122
1791
|
return () => {
|
|
2123
1792
|
a?.cancel();
|
|
@@ -2152,7 +1821,7 @@ function defineTheme(tag = 'usa-theme') {
|
|
|
2152
1821
|
const pr = themePreset(this.theme, role);
|
|
2153
1822
|
const trigger = role === 'attention' ? 'click' : role === 'background' ? 'load' : role;
|
|
2154
1823
|
try {
|
|
2155
|
-
this.onCleanup(
|
|
1824
|
+
this.onCleanup(registry.bindEffect(el, pr.effect, { ...(pr.options || {}), trigger }));
|
|
2156
1825
|
}
|
|
2157
1826
|
catch {
|
|
2158
1827
|
/* effect not registered: call registerAllEffects() */
|
|
@@ -2271,7 +1940,7 @@ function createPlayer(root, animation, o = {}) {
|
|
|
2271
1940
|
if (!e.fired && time >= e.t.start) {
|
|
2272
1941
|
e.fired = true;
|
|
2273
1942
|
for (const el of e.els)
|
|
2274
|
-
|
|
1943
|
+
registry.playEffect(el, e.t.effect, e.t.options || {}).catch(() => undefined);
|
|
2275
1944
|
}
|
|
2276
1945
|
};
|
|
2277
1946
|
const done = () => {
|
|
@@ -2479,7 +2148,7 @@ const EFFECT_PACKS = {
|
|
|
2479
2148
|
'cards-click': [...CARD_FX, ...CLICK_FX],
|
|
2480
2149
|
physics: PHYSICS_FX,
|
|
2481
2150
|
page: PAGE_FX,
|
|
2482
|
-
generative: GENERATIVE_FX,
|
|
2151
|
+
generative: generative.GENERATIVE_FX,
|
|
2483
2152
|
audio: AUDIO_FX,
|
|
2484
2153
|
cursor: CURSOR_FX,
|
|
2485
2154
|
micro: MICRO_FX,
|
|
@@ -2487,32 +2156,32 @@ const EFFECT_PACKS = {
|
|
|
2487
2156
|
};
|
|
2488
2157
|
/** 5.1: card & click effects 2.0. */
|
|
2489
2158
|
function registerCardClickEffects() {
|
|
2490
|
-
|
|
2159
|
+
registry.registerEffects(EFFECT_PACKS['cards-click']);
|
|
2491
2160
|
}
|
|
2492
2161
|
/** 5.2: bounce & physics micro-interactions. */
|
|
2493
2162
|
function registerPhysicsEffects() {
|
|
2494
|
-
|
|
2163
|
+
registry.registerEffects(EFFECT_PACKS.physics);
|
|
2495
2164
|
}
|
|
2496
2165
|
/** 5.3: page-wide transitions and effects. */
|
|
2497
2166
|
function registerPageEffects() {
|
|
2498
|
-
|
|
2167
|
+
registry.registerEffects(EFFECT_PACKS.page);
|
|
2499
2168
|
}
|
|
2500
2169
|
/** 5.5: generative Canvas 2D backgrounds. */
|
|
2501
2170
|
function registerGenerativeEffects() {
|
|
2502
|
-
|
|
2171
|
+
registry.registerEffects(EFFECT_PACKS.generative);
|
|
2503
2172
|
}
|
|
2504
2173
|
/** 5.6: sound-reactive (Web Audio) backgrounds. */
|
|
2505
2174
|
function registerAudioEffects() {
|
|
2506
|
-
|
|
2175
|
+
registry.registerEffects(EFFECT_PACKS.audio);
|
|
2507
2176
|
}
|
|
2508
2177
|
/** 5.7: cursor trails, magnetic dots, spotlight cursor. */
|
|
2509
2178
|
function registerCursorEffects() {
|
|
2510
|
-
|
|
2179
|
+
registry.registerEffects(EFFECT_PACKS.cursor);
|
|
2511
2180
|
}
|
|
2512
2181
|
/** 5.8: micro-interactions + theme-pack effects. */
|
|
2513
2182
|
function registerMicroEffects() {
|
|
2514
|
-
|
|
2515
|
-
|
|
2183
|
+
registry.registerEffects(EFFECT_PACKS.micro);
|
|
2184
|
+
registry.registerEffects(EFFECT_PACKS.themes);
|
|
2516
2185
|
}
|
|
2517
2186
|
/** Define the 5.x elements of this entry (`<usa-story>`, …) under their default tags. */
|
|
2518
2187
|
function defineEffectElements() {
|
|
@@ -2526,16 +2195,20 @@ function defineEffectElements() {
|
|
|
2526
2195
|
function registerAllEffects() {
|
|
2527
2196
|
components_fx.registerBuiltinEffects();
|
|
2528
2197
|
for (const defs of Object.values(EFFECT_PACKS))
|
|
2529
|
-
|
|
2198
|
+
registry.registerEffects(defs);
|
|
2530
2199
|
}
|
|
2531
2200
|
|
|
2201
|
+
exports.fxLayer = shared.fxLayer;
|
|
2202
|
+
exports.GENERATIVE_FX = generative.GENERATIVE_FX;
|
|
2203
|
+
exports.canvasBackground = generative.canvasBackground;
|
|
2204
|
+
exports.hexRgb = generative.hexRgb;
|
|
2205
|
+
exports.noise2 = generative.noise2;
|
|
2532
2206
|
exports.ANIMATION_FORMAT = ANIMATION_FORMAT;
|
|
2533
2207
|
exports.AUDIO_FX = AUDIO_FX;
|
|
2534
2208
|
exports.CARD_FX = CARD_FX;
|
|
2535
2209
|
exports.CLICK_FX = CLICK_FX;
|
|
2536
2210
|
exports.CURSOR_FX = CURSOR_FX;
|
|
2537
2211
|
exports.EFFECT_PACKS = EFFECT_PACKS;
|
|
2538
|
-
exports.GENERATIVE_FX = GENERATIVE_FX;
|
|
2539
2212
|
exports.GESTURES = GESTURES;
|
|
2540
2213
|
exports.MICRO_FX = MICRO_FX;
|
|
2541
2214
|
exports.PAGE_FX = PAGE_FX;
|
|
@@ -2551,7 +2224,6 @@ exports.bindBeat = bindBeat;
|
|
|
2551
2224
|
exports.bindGesture = bindGesture;
|
|
2552
2225
|
exports.bounceKeyframes = bounceKeyframes;
|
|
2553
2226
|
exports.bumpCount = bumpCount;
|
|
2554
|
-
exports.canvasBackground = canvasBackground;
|
|
2555
2227
|
exports.createBeatDetector = createBeatDetector;
|
|
2556
2228
|
exports.createPlayer = createPlayer;
|
|
2557
2229
|
exports.defineAudio = defineAudio;
|
|
@@ -2564,10 +2236,7 @@ exports.disableAudio = disableAudio;
|
|
|
2564
2236
|
exports.enableAudio = enableAudio;
|
|
2565
2237
|
exports.flingVelocity = flingVelocity;
|
|
2566
2238
|
exports.formatCount = formatCount;
|
|
2567
|
-
exports.fxLayer = fxLayer;
|
|
2568
2239
|
exports.getAudio = getAudio;
|
|
2569
|
-
exports.hexRgb = hexRgb;
|
|
2570
|
-
exports.noise2 = noise2;
|
|
2571
2240
|
exports.normalizeAnimation = normalizeAnimation;
|
|
2572
2241
|
exports.onBeat = onBeat;
|
|
2573
2242
|
exports.playThemeEffect = playThemeEffect;
|