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.
@@ -1,6 +1,32 @@
1
- import type { ReactElement } from 'react';
2
- type AbstractAnimatedBackgroundProps = {
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({ className, }: AbstractAnimatedBackgroundProps): ReactElement;
6
- export {};
32
+ export declare function AbstractAnimatedBackground(props: AbstractAnimatedBackgroundProps): ReactElement;
@@ -1,437 +1,214 @@
1
1
  'use client';
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { Canvas, useFrame } from '@react-three/fiber';
4
- import { Suspense, useRef } from 'react';
5
- import { DoubleSide, ShaderMaterial, Vector2 } from 'three';
6
- const BUBBLE_SPECS = [
7
- {
8
- size: 32,
9
- left: '12%',
10
- top: '18%',
11
- delay: '0s',
12
- duration: '8s',
13
- opacity: 0.55
14
- },
15
- {
16
- size: 20,
17
- left: '28%',
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 MARBLE_FRAGMENT_SHADER = /* glsl */ `
80
- precision highp float;
81
-
82
- varying vec2 vUv;
83
-
84
- uniform float uTime;
85
- uniform vec2 uPointer;
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
- color += vec3(0.82, 0.86, 1.0) * uFlashIntensity * 0.15;
160
-
161
- gl_FragColor = vec4(color, 0.95 + uFlashIntensity * 0.012);
162
- }
163
- `;
164
- function combineClassNames(baseClassName, extraClassName) {
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
- function useMarbleMaterial() {
171
- const materialRef = useRef(null);
172
- const uniforms = {
173
- uTime: {
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
- function MarblePlane({ lightningValue }) {
227
- const materialRef = useMarbleMaterial();
228
- const meshRef = useRef(null);
229
- function handleFrame(state, delta) {
230
- if (!meshRef.current) {
231
- return;
232
- }
233
- if (materialRef.current?.uniforms.uFlashIntensity) {
234
- materialRef.current.uniforms.uFlashIntensity.value = lightningValue.current;
235
- }
236
- meshRef.current.rotation.z += delta * 0.02;
237
- meshRef.current.position.x = state.pointer.x * 0.08;
238
- meshRef.current.position.y = state.pointer.y * 0.04;
239
- const scalePulse = 1.04 + Math.sin(state.clock.elapsedTime * 0.45) * 0.02;
240
- meshRef.current.scale.set(scalePulse, scalePulse, scalePulse);
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
- useFrame(handleFrame);
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 FlowHalo({ lightningValue }) {
267
- const materialRef = useRef(null);
268
- const meshRef = useRef(null);
269
- if (materialRef.current === null) {
270
- const radialShader = new ShaderMaterial({
271
- vertexShader: MARBLE_VERTEX_SHADER,
272
- fragmentShader: /* glsl */ `
273
- precision mediump float;
274
- varying vec2 vUv;
275
- uniform float uTime;
276
- uniform float uFlash;
277
- void main() {
278
- vec2 uv = vUv - 0.5;
279
- float radius = length(uv);
280
- float angle = atan(uv.y, uv.x);
281
- float glow = smoothstep(0.45, 0.05, radius);
282
- float ripple = sin(angle * 6.0 + uTime * 1.5) * 0.12;
283
- float highlight = smoothstep(0.25 + ripple, 0.12, radius);
284
- vec3 inner = vec3(0.32, 0.45, 0.98);
285
- vec3 outer = vec3(0.93, 0.48, 0.78);
286
- vec3 color = mix(outer, inner, glow);
287
- color += highlight * 0.28 + vec3(0.82, 0.88, 1.0) * uFlash * 0.22;
288
- gl_FragColor = vec4(color, glow * (0.48 + uFlash * 0.12));
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
- uniforms: {
292
- uTime: {
293
- value: 0
294
- },
295
- uFlash: {
296
- value: 0
297
- }
298
- },
299
- transparent: true,
300
- depthWrite: false
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
- materialRef.current = radialShader;
303
- }
304
- function handleFrame(state, delta) {
305
- if (!materialRef.current || !meshRef.current) {
306
- return;
307
- }
308
- if (materialRef.current.uniforms.uTime) {
309
- materialRef.current.uniforms.uTime.value += delta;
310
- }
311
- if (materialRef.current.uniforms.uFlash) {
312
- materialRef.current.uniforms.uFlash.value = lightningValue.current;
313
- }
314
- meshRef.current.rotation.z += delta * 0.08;
315
- meshRef.current.position.x = state.pointer.x * 0.05;
316
- meshRef.current.position.y = state.pointer.y * 0.03;
317
- }
318
- useFrame(handleFrame);
319
- return /*#__PURE__*/ _jsxs("mesh", {
320
- ref: meshRef,
321
- position: [
322
- 0,
323
- 0,
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
- backgroundColor: 'transparent'
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
- /*#__PURE__*/ _jsx("div", {
384
- className: "marble-base-gradient"
385
- }),
386
- /*#__PURE__*/ _jsx("div", {
387
- className: "marble-secondary-gradient"
388
- }),
389
- /*#__PURE__*/ _jsx("div", {
390
- className: "marble-overlay-gradient"
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
  }