nucleus-core-ts 0.9.751 → 0.9.753
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/fe/components/AbstractAnimatedBackground/index.d.ts +30 -4
- package/dist/fe/components/AbstractAnimatedBackground/index.js +199 -422
- package/dist/index.js +8 -7
- package/dist/src/ElysiaPlugin/index.d.ts +1 -1
- package/dist/src/ElysiaPlugin/routes/chat/types.d.ts +4 -0
- package/dist/src/ElysiaPlugin/routes/storage/cdn.d.ts +16 -1
- package/dist/src/ElysiaPlugin/routes/storage/imageTransform.d.ts +75 -0
- package/dist/src/ElysiaPlugin/routes/storage/imageTransform.test.d.ts +1 -0
- package/dist/src/ElysiaPlugin/routes/storage/index.d.ts +3 -0
- package/dist/src/ElysiaPlugin/routes/storage/mediaPostProcess.d.ts +20 -0
- package/dist/src/ElysiaPlugin/routes/storage/videoTransform.d.ts +39 -0
- package/dist/src/ElysiaPlugin/routes/storage/videoTransform.test.d.ts +1 -0
- package/dist/src/types.d.ts +63 -0
- package/package.json +4 -6
- package/schemas/config.nucleus.json +253 -1
|
@@ -1,6 +1,32 @@
|
|
|
1
|
-
import type
|
|
2
|
-
|
|
1
|
+
import { type ReactElement } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* A GPU-cheap animated FOG background for auth / landing screens — a single full-screen WebGL
|
|
4
|
+
* fragment shader (Vanta-FOG-style domain-warped fractal noise). It replaces the previous
|
|
5
|
+
* three.js / @react-three/fiber "marble" implementation, which paid heavy React-reconciliation +
|
|
6
|
+
* multi-mesh overhead; this version runs one draw call per frame at a capped device-pixel-ratio, so
|
|
7
|
+
* it holds 60fps far more cheaply.
|
|
8
|
+
*
|
|
9
|
+
* Backward compatible: the only previously-supported prop was `className`, and the default colors keep
|
|
10
|
+
* the old indigo→blue→purple→pink feel, so existing `<AbstractAnimatedBackground className="…" />`
|
|
11
|
+
* call-sites render unchanged. Every visual is now customizable via the optional props below.
|
|
12
|
+
*/
|
|
13
|
+
export type AbstractAnimatedBackgroundProps = {
|
|
3
14
|
className?: string;
|
|
15
|
+
/** Darkest fog color (background). Hex, e.g. "#0b1020". */
|
|
16
|
+
baseColor?: string;
|
|
17
|
+
/** Low-midtone fog color. */
|
|
18
|
+
lowlightColor?: string;
|
|
19
|
+
/** Mid fog color. */
|
|
20
|
+
midtoneColor?: string;
|
|
21
|
+
/** Brightest fog wisps. */
|
|
22
|
+
highlightColor?: string;
|
|
23
|
+
/** Animation speed multiplier (0 = frozen). Default 0.7. */
|
|
24
|
+
speed?: number;
|
|
25
|
+
/** Fog scale — larger = more zoomed-in / bigger cloud shapes. Default 1.0. */
|
|
26
|
+
zoom?: number;
|
|
27
|
+
/** Softness of the highlight wisps, 0-1 (higher = softer). Default 0.6. */
|
|
28
|
+
blur?: number;
|
|
29
|
+
/** Cap the render device-pixel-ratio (fog is soft, so 1–1.5 looks identical and is much cheaper). Default 1.5. */
|
|
30
|
+
maxDpr?: number;
|
|
4
31
|
};
|
|
5
|
-
export declare function AbstractAnimatedBackground(
|
|
6
|
-
export {};
|
|
32
|
+
export declare function AbstractAnimatedBackground(props: AbstractAnimatedBackgroundProps): ReactElement;
|
|
@@ -1,437 +1,214 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { jsx as _jsx
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
top: '72%',
|
|
19
|
-
delay: '2s',
|
|
20
|
-
duration: '7s',
|
|
21
|
-
opacity: 0.4
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
size: 26,
|
|
25
|
-
left: '46%',
|
|
26
|
-
top: '36%',
|
|
27
|
-
delay: '1s',
|
|
28
|
-
duration: '6.5s',
|
|
29
|
-
opacity: 0.48
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
size: 18,
|
|
33
|
-
left: '64%',
|
|
34
|
-
top: '58%',
|
|
35
|
-
delay: '3s',
|
|
36
|
-
duration: '7.4s',
|
|
37
|
-
opacity: 0.35
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
size: 24,
|
|
41
|
-
left: '78%',
|
|
42
|
-
top: '28%',
|
|
43
|
-
delay: '1.8s',
|
|
44
|
-
duration: '8.5s',
|
|
45
|
-
opacity: 0.5
|
|
46
|
-
},
|
|
47
|
-
{
|
|
48
|
-
size: 16,
|
|
49
|
-
left: '86%',
|
|
50
|
-
top: '62%',
|
|
51
|
-
delay: '4.1s',
|
|
52
|
-
duration: '6.8s',
|
|
53
|
-
opacity: 0.38
|
|
54
|
-
},
|
|
55
|
-
{
|
|
56
|
-
size: 28,
|
|
57
|
-
left: '32%',
|
|
58
|
-
top: '52%',
|
|
59
|
-
delay: '2.6s',
|
|
60
|
-
duration: '7.2s',
|
|
61
|
-
opacity: 0.44
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
size: 14,
|
|
65
|
-
left: '58%',
|
|
66
|
-
top: '22%',
|
|
67
|
-
delay: '0.8s',
|
|
68
|
-
duration: '6.2s',
|
|
69
|
-
opacity: 0.32
|
|
70
|
-
}
|
|
71
|
-
];
|
|
72
|
-
const MARBLE_VERTEX_SHADER = /* glsl */ `
|
|
73
|
-
varying vec2 vUv;
|
|
74
|
-
void main() {
|
|
75
|
-
vUv = uv;
|
|
76
|
-
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
|
77
|
-
}
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useRef } from 'react';
|
|
4
|
+
const DEFAULTS = {
|
|
5
|
+
baseColor: '#0b1020',
|
|
6
|
+
lowlightColor: '#3b4fd6',
|
|
7
|
+
midtoneColor: '#8b5cf6',
|
|
8
|
+
highlightColor: '#ec4899',
|
|
9
|
+
speed: 0.7,
|
|
10
|
+
zoom: 1.0,
|
|
11
|
+
blur: 0.6,
|
|
12
|
+
maxDpr: 1.5
|
|
13
|
+
};
|
|
14
|
+
const VERTEX_SHADER = /* glsl */ `
|
|
15
|
+
attribute vec2 a_pos;
|
|
16
|
+
varying vec2 vUv;
|
|
17
|
+
void main() { vUv = a_pos * 0.5 + 0.5; gl_Position = vec4(a_pos, 0.0, 1.0); }
|
|
78
18
|
`;
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
uniform float uBaseShift;
|
|
87
|
-
uniform float uAccentShift;
|
|
88
|
-
uniform float uFlashIntensity;
|
|
89
|
-
|
|
90
|
-
float hash(vec2 p) {
|
|
91
|
-
return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
float noise(vec2 p) {
|
|
95
|
-
vec2 i = floor(p);
|
|
96
|
-
vec2 f = fract(p);
|
|
97
|
-
float a = hash(i);
|
|
98
|
-
float b = hash(i + vec2(1.0, 0.0));
|
|
99
|
-
float c = hash(i + vec2(0.0, 1.0));
|
|
100
|
-
float d = hash(i + vec2(1.0, 1.0));
|
|
101
|
-
vec2 u = f * f * (3.0 - 2.0 * f);
|
|
102
|
-
return mix(a, b, u.x) + (c - a) * u.y * (1.0 - u.x) + (d - b) * u.x * u.y;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
float fbm(vec2 p) {
|
|
106
|
-
float total = 0.0;
|
|
107
|
-
float amplitude = 0.5;
|
|
108
|
-
for (int i = 0; i < 5; i++) {
|
|
109
|
-
total += noise(p) * amplitude;
|
|
110
|
-
p *= 2.0;
|
|
111
|
-
amplitude *= 0.5;
|
|
112
|
-
}
|
|
113
|
-
return total;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
vec3 palette(float t, float timeShift) {
|
|
117
|
-
float cycle = sin(timeShift * 0.08) * 0.5 + 0.5;
|
|
118
|
-
|
|
119
|
-
vec3 blue = vec3(0.345, 0.486, 0.968);
|
|
120
|
-
vec3 purple = vec3(0.639, 0.451, 0.937);
|
|
121
|
-
vec3 pink = vec3(0.925, 0.337, 0.745);
|
|
122
|
-
vec3 teal = vec3(0.2, 0.8, 0.7);
|
|
123
|
-
vec3 orange = vec3(0.95, 0.6, 0.25);
|
|
124
|
-
vec3 whiteHighlight = vec3(0.98, 0.96, 0.99);
|
|
125
|
-
|
|
126
|
-
vec3 primaryA = mix(blue, teal, cycle);
|
|
127
|
-
vec3 primaryB = mix(purple, orange, cycle);
|
|
128
|
-
vec3 accentA = mix(pink, vec3(0.4, 0.9, 0.6), cycle);
|
|
129
|
-
vec3 accentB = mix(whiteHighlight, vec3(1.0, 0.9, 0.7), cycle);
|
|
130
|
-
|
|
131
|
-
vec3 base = mix(primaryA, primaryB, smoothstep(0.2, 0.8, t));
|
|
132
|
-
vec3 accent = mix(accentA, accentB, smoothstep(0.5, 1.0, t));
|
|
133
|
-
return mix(base, accent, 0.45 + 0.35 * sin(t * 3.14159));
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
void main() {
|
|
137
|
-
vec2 uv = vUv * 2.6 - 1.3;
|
|
138
|
-
vec2 flowUv = uv;
|
|
139
|
-
flowUv.x += uPointer.x * 0.18;
|
|
140
|
-
flowUv.y += uPointer.y * 0.12;
|
|
141
|
-
|
|
142
|
-
float t = uTime * 0.12;
|
|
143
|
-
float basePattern = fbm(flowUv * 2.6 + t);
|
|
144
|
-
float swirl = fbm(vec2(flowUv.y + basePattern * 0.6 + t * 0.5, flowUv.x + t));
|
|
145
|
-
float marble = sin((flowUv.x + swirl * 1.6) * 6.0 + basePattern * 2.4 + t * 2.4);
|
|
146
|
-
float accent = fbm(flowUv * 4.2 + uBaseShift + t * 1.2);
|
|
147
|
-
float highlight = smoothstep(0.55, 0.9, fbm(flowUv * 6.0 + uAccentShift + t * 0.8));
|
|
148
|
-
|
|
149
|
-
float finalPattern = (marble * 0.35 + basePattern * 0.4 + accent * 0.25);
|
|
150
|
-
finalPattern = 0.5 + 0.5 * finalPattern;
|
|
151
|
-
vec3 color = palette(finalPattern, uTime);
|
|
152
|
-
|
|
153
|
-
float depth = smoothstep(0.0, 0.6, basePattern) * 0.4;
|
|
154
|
-
float sheen = highlight * 0.6;
|
|
155
|
-
|
|
156
|
-
color += vec3(0.08, 0.06, 0.12) * depth;
|
|
157
|
-
color += vec3(0.25, 0.28, 0.35) * sheen;
|
|
19
|
+
const FRAGMENT_SHADER = /* glsl */ `
|
|
20
|
+
precision highp float;
|
|
21
|
+
varying vec2 vUv;
|
|
22
|
+
uniform float u_time;
|
|
23
|
+
uniform vec2 u_res;
|
|
24
|
+
uniform vec3 u_base, u_low, u_mid, u_high;
|
|
25
|
+
uniform float u_speed, u_zoom, u_blur;
|
|
158
26
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
if (!extraClassName) {
|
|
166
|
-
return baseClassName;
|
|
167
|
-
}
|
|
168
|
-
return `${baseClassName} ${extraClassName}`;
|
|
27
|
+
float hash(vec2 p) { return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123); }
|
|
28
|
+
float noise(vec2 p) {
|
|
29
|
+
vec2 i = floor(p), f = fract(p);
|
|
30
|
+
float a = hash(i), b = hash(i + vec2(1.0, 0.0)), c = hash(i + vec2(0.0, 1.0)), d = hash(i + vec2(1.0, 1.0));
|
|
31
|
+
vec2 u = f * f * (3.0 - 2.0 * f);
|
|
32
|
+
return mix(a, b, u.x) + (c - a) * u.y * (1.0 - u.x) + (d - b) * u.x * u.y;
|
|
169
33
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
value: 0
|
|
175
|
-
},
|
|
176
|
-
uPointer: {
|
|
177
|
-
value: new Vector2(0, 0)
|
|
178
|
-
},
|
|
179
|
-
uBaseShift: {
|
|
180
|
-
value: Math.random() * 10
|
|
181
|
-
},
|
|
182
|
-
uAccentShift: {
|
|
183
|
-
value: Math.random() * 20
|
|
184
|
-
},
|
|
185
|
-
uFlashIntensity: {
|
|
186
|
-
value: 0
|
|
187
|
-
}
|
|
188
|
-
};
|
|
189
|
-
function handleFrame(state, delta) {
|
|
190
|
-
if (!materialRef.current) {
|
|
191
|
-
return;
|
|
192
|
-
}
|
|
193
|
-
uniforms.uTime.value += delta;
|
|
194
|
-
uniforms.uPointer.value.set(state.pointer.x, state.pointer.y);
|
|
195
|
-
const { uniforms: activeUniforms } = materialRef.current;
|
|
196
|
-
if (activeUniforms.uTime) {
|
|
197
|
-
activeUniforms.uTime.value = uniforms.uTime.value;
|
|
198
|
-
}
|
|
199
|
-
if (activeUniforms.uPointer) {
|
|
200
|
-
activeUniforms.uPointer.value.copy(uniforms.uPointer.value);
|
|
201
|
-
}
|
|
202
|
-
if (activeUniforms.uFlashIntensity) {
|
|
203
|
-
activeUniforms.uFlashIntensity.value = uniforms.uFlashIntensity.value;
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
useFrame(handleFrame);
|
|
207
|
-
if (materialRef.current === null) {
|
|
208
|
-
materialRef.current = new ShaderMaterial({
|
|
209
|
-
vertexShader: MARBLE_VERTEX_SHADER,
|
|
210
|
-
fragmentShader: MARBLE_FRAGMENT_SHADER,
|
|
211
|
-
transparent: true,
|
|
212
|
-
depthWrite: false,
|
|
213
|
-
side: DoubleSide,
|
|
214
|
-
uniforms: {
|
|
215
|
-
uTime: uniforms.uTime,
|
|
216
|
-
uPointer: uniforms.uPointer,
|
|
217
|
-
uBaseShift: uniforms.uBaseShift,
|
|
218
|
-
uAccentShift: uniforms.uAccentShift,
|
|
219
|
-
uFlashIntensity: uniforms.uFlashIntensity
|
|
220
|
-
}
|
|
221
|
-
});
|
|
222
|
-
materialRef.current.needsUpdate = true;
|
|
223
|
-
}
|
|
224
|
-
return materialRef;
|
|
34
|
+
float fbm(vec2 p) {
|
|
35
|
+
float v = 0.0, a = 0.5;
|
|
36
|
+
for (int i = 0; i < 6; i++) { v += a * noise(p); p = p * 2.0 + vec2(3.1, 1.7); a *= 0.5; }
|
|
37
|
+
return v;
|
|
225
38
|
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
39
|
+
void main() {
|
|
40
|
+
float aspect = u_res.x / max(u_res.y, 1.0);
|
|
41
|
+
vec2 p = (vUv - 0.5); p.x *= aspect; p /= max(u_zoom, 0.05);
|
|
42
|
+
float t = u_time * u_speed;
|
|
43
|
+
vec2 q = vec2(fbm(p + vec2(0.0, t * 0.15)), fbm(p + vec2(5.2, t * 0.13)));
|
|
44
|
+
vec2 r = vec2(fbm(p + 2.0 * q + vec2(1.7, 9.2) + t * 0.10), fbm(p + 2.0 * q + vec2(8.3, 2.8) - t * 0.12));
|
|
45
|
+
float f = clamp(fbm(p + 2.0 * r + t * 0.05) * 1.12, 0.0, 1.0);
|
|
46
|
+
vec3 col = u_base;
|
|
47
|
+
col = mix(col, u_low, smoothstep(0.15, 0.50, f));
|
|
48
|
+
col = mix(col, u_mid, smoothstep(0.40, 0.75, f));
|
|
49
|
+
col = mix(col, u_high, smoothstep(0.70, 0.96, f + length(r) * (1.0 - clamp(u_blur, 0.0, 1.0)) * 0.30));
|
|
50
|
+
gl_FragColor = vec4(col, 1.0);
|
|
51
|
+
}
|
|
52
|
+
`;
|
|
53
|
+
function hexToRgb(hex) {
|
|
54
|
+
const normalized = hex.replace('#', '');
|
|
55
|
+
const value = Number.parseInt(normalized.length === 3 ? normalized.split('').map((c)=>c + c).join('') : normalized, 16);
|
|
56
|
+
if (!Number.isFinite(value)) return [
|
|
57
|
+
0,
|
|
58
|
+
0,
|
|
59
|
+
0
|
|
60
|
+
];
|
|
61
|
+
return [
|
|
62
|
+
(value >> 16 & 255) / 255,
|
|
63
|
+
(value >> 8 & 255) / 255,
|
|
64
|
+
(value & 255) / 255
|
|
65
|
+
];
|
|
66
|
+
}
|
|
67
|
+
function compile(gl, type, src) {
|
|
68
|
+
const shader = gl.createShader(type);
|
|
69
|
+
if (!shader) return null;
|
|
70
|
+
gl.shaderSource(shader, src);
|
|
71
|
+
gl.compileShader(shader);
|
|
72
|
+
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
|
|
73
|
+
gl.deleteShader(shader);
|
|
74
|
+
return null;
|
|
241
75
|
}
|
|
242
|
-
|
|
243
|
-
return /*#__PURE__*/ _jsxs("mesh", {
|
|
244
|
-
ref: meshRef,
|
|
245
|
-
position: [
|
|
246
|
-
0,
|
|
247
|
-
0,
|
|
248
|
-
0
|
|
249
|
-
],
|
|
250
|
-
children: [
|
|
251
|
-
/*#__PURE__*/ _jsx("planeGeometry", {
|
|
252
|
-
args: [
|
|
253
|
-
4.4,
|
|
254
|
-
3.2,
|
|
255
|
-
64,
|
|
256
|
-
64
|
|
257
|
-
]
|
|
258
|
-
}),
|
|
259
|
-
/*#__PURE__*/ _jsx("primitive", {
|
|
260
|
-
object: materialRef.current,
|
|
261
|
-
attach: "material"
|
|
262
|
-
})
|
|
263
|
-
]
|
|
264
|
-
});
|
|
76
|
+
return shader;
|
|
265
77
|
}
|
|
266
|
-
function
|
|
267
|
-
const
|
|
268
|
-
const
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
78
|
+
export function AbstractAnimatedBackground(props) {
|
|
79
|
+
const { className } = props;
|
|
80
|
+
const canvasRef = useRef(null);
|
|
81
|
+
// Resolve config here so the effect deps capture value changes and re-init the uniforms.
|
|
82
|
+
const baseColor = props.baseColor ?? DEFAULTS.baseColor;
|
|
83
|
+
const lowlightColor = props.lowlightColor ?? DEFAULTS.lowlightColor;
|
|
84
|
+
const midtoneColor = props.midtoneColor ?? DEFAULTS.midtoneColor;
|
|
85
|
+
const highlightColor = props.highlightColor ?? DEFAULTS.highlightColor;
|
|
86
|
+
const speed = props.speed ?? DEFAULTS.speed;
|
|
87
|
+
const zoom = props.zoom ?? DEFAULTS.zoom;
|
|
88
|
+
const blur = props.blur ?? DEFAULTS.blur;
|
|
89
|
+
const maxDpr = props.maxDpr ?? DEFAULTS.maxDpr;
|
|
90
|
+
useEffect(()=>{
|
|
91
|
+
const canvas = canvasRef.current;
|
|
92
|
+
if (!canvas) return;
|
|
93
|
+
const gl = canvas.getContext('webgl', {
|
|
94
|
+
antialias: false,
|
|
95
|
+
alpha: true,
|
|
96
|
+
premultipliedAlpha: false
|
|
97
|
+
}) ?? canvas.getContext('experimental-webgl');
|
|
98
|
+
if (!gl) return; // No WebGL → the CSS gradient fallback (rendered below) remains visible.
|
|
99
|
+
const program = gl.createProgram();
|
|
100
|
+
const vs = compile(gl, gl.VERTEX_SHADER, VERTEX_SHADER);
|
|
101
|
+
const fs = compile(gl, gl.FRAGMENT_SHADER, FRAGMENT_SHADER);
|
|
102
|
+
if (!program || !vs || !fs) return;
|
|
103
|
+
gl.attachShader(program, vs);
|
|
104
|
+
gl.attachShader(program, fs);
|
|
105
|
+
gl.linkProgram(program);
|
|
106
|
+
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) return;
|
|
107
|
+
gl.useProgram(program);
|
|
108
|
+
const buffer = gl.createBuffer();
|
|
109
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
|
|
110
|
+
// One oversized triangle covering the clip space — a fullscreen draw with no index buffer.
|
|
111
|
+
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
|
|
112
|
+
-1,
|
|
113
|
+
-1,
|
|
114
|
+
3,
|
|
115
|
+
-1,
|
|
116
|
+
-1,
|
|
117
|
+
3
|
|
118
|
+
]), gl.STATIC_DRAW);
|
|
119
|
+
const posLoc = gl.getAttribLocation(program, 'a_pos');
|
|
120
|
+
gl.enableVertexAttribArray(posLoc);
|
|
121
|
+
gl.vertexAttribPointer(posLoc, 2, gl.FLOAT, false, 0, 0);
|
|
122
|
+
const u = (name)=>gl.getUniformLocation(program, name);
|
|
123
|
+
gl.uniform3fv(u('u_base'), hexToRgb(baseColor));
|
|
124
|
+
gl.uniform3fv(u('u_low'), hexToRgb(lowlightColor));
|
|
125
|
+
gl.uniform3fv(u('u_mid'), hexToRgb(midtoneColor));
|
|
126
|
+
gl.uniform3fv(u('u_high'), hexToRgb(highlightColor));
|
|
127
|
+
gl.uniform1f(u('u_speed'), speed);
|
|
128
|
+
gl.uniform1f(u('u_zoom'), zoom);
|
|
129
|
+
gl.uniform1f(u('u_blur'), blur);
|
|
130
|
+
const timeLoc = u('u_time');
|
|
131
|
+
const resLoc = u('u_res');
|
|
132
|
+
const dpr = Math.min(typeof window !== 'undefined' ? window.devicePixelRatio || 1 : 1, maxDpr);
|
|
133
|
+
const resize = ()=>{
|
|
134
|
+
const w = Math.max(1, Math.floor(canvas.clientWidth * dpr));
|
|
135
|
+
const h = Math.max(1, Math.floor(canvas.clientHeight * dpr));
|
|
136
|
+
if (canvas.width !== w || canvas.height !== h) {
|
|
137
|
+
canvas.width = w;
|
|
138
|
+
canvas.height = h;
|
|
139
|
+
gl.viewport(0, 0, w, h);
|
|
140
|
+
}
|
|
141
|
+
gl.uniform2f(resLoc, canvas.width, canvas.height);
|
|
142
|
+
};
|
|
143
|
+
const resizeObserver = new ResizeObserver(resize);
|
|
144
|
+
resizeObserver.observe(canvas);
|
|
145
|
+
resize();
|
|
146
|
+
const reduceMotion = typeof window !== 'undefined' && window.matchMedia?.('(prefers-reduced-motion: reduce)').matches === true;
|
|
147
|
+
let raf = 0;
|
|
148
|
+
let visible = true;
|
|
149
|
+
const start = performance.now();
|
|
150
|
+
const draw = (now)=>{
|
|
151
|
+
gl.uniform1f(timeLoc, (now - start) / 1000);
|
|
152
|
+
gl.drawArrays(gl.TRIANGLES, 0, 3);
|
|
153
|
+
};
|
|
154
|
+
const loop = (now)=>{
|
|
155
|
+
draw(now);
|
|
156
|
+
raf = requestAnimationFrame(loop);
|
|
157
|
+
};
|
|
158
|
+
if (reduceMotion) {
|
|
159
|
+
// Respect reduced-motion: render one static frame, no animation loop.
|
|
160
|
+
draw(start);
|
|
161
|
+
} else {
|
|
162
|
+
raf = requestAnimationFrame(loop);
|
|
289
163
|
}
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
164
|
+
// Pause the loop while off-screen (scrolled away / tab hidden) to save GPU.
|
|
165
|
+
const io = new IntersectionObserver((entries)=>{
|
|
166
|
+
const nowVisible = entries[0]?.isIntersecting ?? true;
|
|
167
|
+
if (nowVisible === visible) return;
|
|
168
|
+
visible = nowVisible;
|
|
169
|
+
if (reduceMotion) return;
|
|
170
|
+
if (visible && raf === 0) raf = requestAnimationFrame(loop);
|
|
171
|
+
else if (!visible && raf !== 0) {
|
|
172
|
+
cancelAnimationFrame(raf);
|
|
173
|
+
raf = 0;
|
|
174
|
+
}
|
|
301
175
|
});
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
-0.4
|
|
325
|
-
],
|
|
326
|
-
children: [
|
|
327
|
-
/*#__PURE__*/ _jsx("planeGeometry", {
|
|
328
|
-
args: [
|
|
329
|
-
5.4,
|
|
330
|
-
3.8,
|
|
331
|
-
2,
|
|
332
|
-
2
|
|
333
|
-
]
|
|
334
|
-
}),
|
|
335
|
-
/*#__PURE__*/ _jsx("primitive", {
|
|
336
|
-
object: materialRef.current,
|
|
337
|
-
attach: "material"
|
|
338
|
-
})
|
|
339
|
-
]
|
|
340
|
-
});
|
|
341
|
-
}
|
|
342
|
-
function MarbleScene({ lightningValue }) {
|
|
343
|
-
return /*#__PURE__*/ _jsxs("group", {
|
|
344
|
-
children: [
|
|
345
|
-
/*#__PURE__*/ _jsx(MarblePlane, {
|
|
346
|
-
lightningValue: lightningValue
|
|
347
|
-
}),
|
|
348
|
-
/*#__PURE__*/ _jsx(FlowHalo, {
|
|
349
|
-
lightningValue: lightningValue
|
|
350
|
-
})
|
|
351
|
-
]
|
|
352
|
-
});
|
|
353
|
-
}
|
|
354
|
-
function BubbleOverlay() {
|
|
176
|
+
io.observe(canvas);
|
|
177
|
+
return ()=>{
|
|
178
|
+
if (raf !== 0) cancelAnimationFrame(raf);
|
|
179
|
+
resizeObserver.disconnect();
|
|
180
|
+
io.disconnect();
|
|
181
|
+
gl.deleteBuffer(buffer);
|
|
182
|
+
gl.deleteProgram(program);
|
|
183
|
+
gl.deleteShader(vs);
|
|
184
|
+
gl.deleteShader(fs);
|
|
185
|
+
gl.getExtension('WEBGL_lose_context')?.loseContext();
|
|
186
|
+
};
|
|
187
|
+
}, [
|
|
188
|
+
baseColor,
|
|
189
|
+
lowlightColor,
|
|
190
|
+
midtoneColor,
|
|
191
|
+
highlightColor,
|
|
192
|
+
speed,
|
|
193
|
+
zoom,
|
|
194
|
+
blur,
|
|
195
|
+
maxDpr
|
|
196
|
+
]);
|
|
197
|
+
const rootClassName = className ? `absolute inset-0 overflow-hidden ${className}` : 'absolute inset-0 overflow-hidden';
|
|
355
198
|
return /*#__PURE__*/ _jsx("div", {
|
|
356
|
-
className: "absolute inset-0 pointer-events-none",
|
|
357
|
-
children: BUBBLE_SPECS.map(function renderBubble(spec, index) {
|
|
358
|
-
return /*#__PURE__*/ _jsx("span", {
|
|
359
|
-
className: "marble-bubble",
|
|
360
|
-
style: {
|
|
361
|
-
width: `${spec.size}px`,
|
|
362
|
-
height: `${spec.size}px`,
|
|
363
|
-
left: spec.left,
|
|
364
|
-
top: spec.top,
|
|
365
|
-
animationDelay: spec.delay,
|
|
366
|
-
animationDuration: spec.duration,
|
|
367
|
-
opacity: spec.opacity
|
|
368
|
-
}
|
|
369
|
-
}, `bubble-${index}`);
|
|
370
|
-
})
|
|
371
|
-
});
|
|
372
|
-
}
|
|
373
|
-
export function AbstractAnimatedBackground({ className }) {
|
|
374
|
-
const baseClassName = 'absolute inset-0 overflow-hidden';
|
|
375
|
-
const rootClassName = combineClassNames(baseClassName, className);
|
|
376
|
-
const lightningValue = useRef(0);
|
|
377
|
-
return /*#__PURE__*/ _jsxs("div", {
|
|
378
199
|
className: rootClassName,
|
|
379
200
|
style: {
|
|
380
|
-
|
|
201
|
+
// CSS gradient fallback for no-WebGL / SSR-first-paint — the canvas paints over it.
|
|
202
|
+
background: `linear-gradient(135deg, ${baseColor}, ${lowlightColor} 45%, ${midtoneColor} 75%, ${highlightColor})`
|
|
381
203
|
},
|
|
382
|
-
children:
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
}),
|
|
392
|
-
/*#__PURE__*/ _jsx(Suspense, {
|
|
393
|
-
fallback: null,
|
|
394
|
-
children: /*#__PURE__*/ _jsx(Canvas, {
|
|
395
|
-
className: "marble-canvas",
|
|
396
|
-
dpr: [
|
|
397
|
-
1,
|
|
398
|
-
1.5
|
|
399
|
-
],
|
|
400
|
-
gl: {
|
|
401
|
-
antialias: true,
|
|
402
|
-
alpha: true
|
|
403
|
-
},
|
|
404
|
-
camera: {
|
|
405
|
-
position: [
|
|
406
|
-
0,
|
|
407
|
-
0,
|
|
408
|
-
2.5
|
|
409
|
-
],
|
|
410
|
-
fov: 45
|
|
411
|
-
},
|
|
412
|
-
style: {
|
|
413
|
-
position: 'absolute',
|
|
414
|
-
top: '50%',
|
|
415
|
-
left: '50%',
|
|
416
|
-
width: '150%',
|
|
417
|
-
height: '150%',
|
|
418
|
-
transform: 'translate(-50%, -50%)'
|
|
419
|
-
},
|
|
420
|
-
children: /*#__PURE__*/ _jsx(MarbleScene, {
|
|
421
|
-
lightningValue: lightningValue
|
|
422
|
-
})
|
|
423
|
-
})
|
|
424
|
-
}),
|
|
425
|
-
/*#__PURE__*/ _jsx("div", {
|
|
426
|
-
className: "marble-swirl"
|
|
427
|
-
}),
|
|
428
|
-
/*#__PURE__*/ _jsx(BubbleOverlay, {}),
|
|
429
|
-
/*#__PURE__*/ _jsx("div", {
|
|
430
|
-
className: "marble-highlight"
|
|
431
|
-
}),
|
|
432
|
-
/*#__PURE__*/ _jsx("div", {
|
|
433
|
-
className: "marble-glass"
|
|
434
|
-
})
|
|
435
|
-
]
|
|
204
|
+
children: /*#__PURE__*/ _jsx("canvas", {
|
|
205
|
+
ref: canvasRef,
|
|
206
|
+
style: {
|
|
207
|
+
display: 'block',
|
|
208
|
+
width: '100%',
|
|
209
|
+
height: '100%'
|
|
210
|
+
},
|
|
211
|
+
"aria-hidden": "true"
|
|
212
|
+
})
|
|
436
213
|
});
|
|
437
214
|
}
|