@shogo-ai/voice 1.9.13 → 2.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/README.md +89 -0
  2. package/dist/{chunk-S3S2RNO6.js → chunk-BI6SL35K.js} +1 -184
  3. package/dist/chunk-CLF25CZC.js +987 -0
  4. package/dist/chunk-KMSL5PWK.js +540 -0
  5. package/dist/chunk-ME3SIZZU.js +581 -0
  6. package/dist/chunk-TQOBJMEK.js +17 -0
  7. package/dist/{chunk-T3T4EBWY.js → chunk-UH75UVM2.js} +6 -2
  8. package/dist/chunk-UW7VQ3S6.js +148 -0
  9. package/dist/chunk-XE4LLC7Z.js +1067 -0
  10. package/dist/chunk-ZAW6F3YT.js +172 -0
  11. package/dist/index.cjs +735 -25
  12. package/dist/index.d.cts +373 -3
  13. package/dist/index.d.ts +373 -3
  14. package/dist/index.js +59 -3
  15. package/dist/live/client.cjs +173 -0
  16. package/dist/live/client.d.cts +132 -0
  17. package/dist/live/client.d.ts +132 -0
  18. package/dist/live/client.js +9 -0
  19. package/dist/native/index.d.cts +5 -2
  20. package/dist/native/index.d.ts +5 -2
  21. package/dist/native/index.js +15 -11
  22. package/dist/{organicParticlesShaders-DIva0vBO.d.ts → organicParticlesShaders-seZq7jYX.d.cts} +1 -421
  23. package/dist/{organicParticlesShaders-DIva0vBO.d.cts → organicParticlesShaders-seZq7jYX.d.ts} +1 -421
  24. package/dist/particlesConfig-0YbdPOdY.d.cts +223 -0
  25. package/dist/particlesConfig-0YbdPOdY.d.ts +223 -0
  26. package/dist/react/conversation.cjs +789 -0
  27. package/dist/react/conversation.d.cts +134 -0
  28. package/dist/react/conversation.d.ts +134 -0
  29. package/dist/react/conversation.js +13 -0
  30. package/dist/react/index.cjs +374 -36
  31. package/dist/react/index.d.cts +10 -141
  32. package/dist/react/index.d.ts +10 -141
  33. package/dist/react/index.js +23 -770
  34. package/dist/react/visuals.cjs +1048 -0
  35. package/dist/react/visuals.d.cts +70 -0
  36. package/dist/react/visuals.d.ts +70 -0
  37. package/dist/react/visuals.js +10 -0
  38. package/dist/route/agent.cjs +1038 -85
  39. package/dist/route/agent.js +3 -3
  40. package/dist/route/audio-tags.cjs +1038 -85
  41. package/dist/route/audio-tags.js +3 -3
  42. package/dist/route/index.cjs +1042 -85
  43. package/dist/route/index.d.cts +19 -3
  44. package/dist/route/index.d.ts +19 -3
  45. package/dist/route/index.js +3 -3
  46. package/dist/route/music.cjs +1038 -85
  47. package/dist/route/music.js +3 -3
  48. package/dist/route/op.cjs +2118 -0
  49. package/dist/route/op.d.cts +43 -0
  50. package/dist/route/op.d.ts +43 -0
  51. package/dist/route/op.js +27 -0
  52. package/dist/route/signed-url.cjs +1038 -85
  53. package/dist/route/signed-url.js +3 -3
  54. package/dist/route/tts-preview.cjs +1038 -85
  55. package/dist/route/tts-preview.d.cts +6 -4
  56. package/dist/route/tts-preview.d.ts +6 -4
  57. package/dist/route/tts-preview.js +3 -3
  58. package/dist/server.cjs +1038 -85
  59. package/dist/server.d.cts +40 -8
  60. package/dist/server.d.ts +40 -8
  61. package/dist/server.js +2 -2
  62. package/dist/types-Bfhu-aQH.d.cts +199 -0
  63. package/dist/types-Bfhu-aQH.d.ts +199 -0
  64. package/dist/{types-W9y6eMj3.d.ts → types-CadjTXNH.d.cts} +193 -12
  65. package/dist/{types-W9y6eMj3.d.cts → types-CadjTXNH.d.ts} +193 -12
  66. package/package.json +21 -1
  67. package/dist/chunk-B4JC3DK2.js +0 -529
  68. package/dist/chunk-O362EJQR.js +0 -524
@@ -0,0 +1,1048 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/react/visuals.ts
31
+ var visuals_exports = {};
32
+ __export(visuals_exports, {
33
+ OrganicParticles: () => OrganicParticles,
34
+ OrganicSphere: () => OrganicSphere
35
+ });
36
+ module.exports = __toCommonJS(visuals_exports);
37
+
38
+ // src/react/OrganicSphere.tsx
39
+ var import_react = require("react");
40
+ var THREE = __toESM(require("three"), 1);
41
+
42
+ // src/react/shaders/organicSphereShaders.ts
43
+ var PERLIN_4D = (
44
+ /* glsl */
45
+ `
46
+ vec4 permute(vec4 x){return mod(((x*34.0)+1.0)*x, 289.0);}
47
+ vec4 taylorInvSqrt(vec4 r){return 1.79284291400159 - 0.85373472095314 * r;}
48
+ vec4 fade(vec4 t) {return t*t*t*(t*(t*6.0-15.0)+10.0);}
49
+
50
+ float perlin4d(vec4 P){
51
+ vec4 Pi0 = floor(P);
52
+ vec4 Pi1 = Pi0 + 1.0;
53
+ Pi0 = mod(Pi0, 289.0);
54
+ Pi1 = mod(Pi1, 289.0);
55
+ vec4 Pf0 = fract(P);
56
+ vec4 Pf1 = Pf0 - 1.0;
57
+ vec4 ix = vec4(Pi0.x, Pi1.x, Pi0.x, Pi1.x);
58
+ vec4 iy = vec4(Pi0.yy, Pi1.yy);
59
+ vec4 iz0 = vec4(Pi0.zzzz);
60
+ vec4 iz1 = vec4(Pi1.zzzz);
61
+ vec4 iw0 = vec4(Pi0.wwww);
62
+ vec4 iw1 = vec4(Pi1.wwww);
63
+
64
+ vec4 ixy = permute(permute(ix) + iy);
65
+ vec4 ixy0 = permute(ixy + iz0);
66
+ vec4 ixy1 = permute(ixy + iz1);
67
+ vec4 ixy00 = permute(ixy0 + iw0);
68
+ vec4 ixy01 = permute(ixy0 + iw1);
69
+ vec4 ixy10 = permute(ixy1 + iw0);
70
+ vec4 ixy11 = permute(ixy1 + iw1);
71
+
72
+ vec4 gx00 = ixy00 / 7.0;
73
+ vec4 gy00 = floor(gx00) / 7.0;
74
+ vec4 gz00 = floor(gy00) / 6.0;
75
+ gx00 = fract(gx00) - 0.5;
76
+ gy00 = fract(gy00) - 0.5;
77
+ gz00 = fract(gz00) - 0.5;
78
+ vec4 gw00 = vec4(0.75) - abs(gx00) - abs(gy00) - abs(gz00);
79
+ vec4 sw00 = step(gw00, vec4(0.0));
80
+ gx00 -= sw00 * (step(0.0, gx00) - 0.5);
81
+ gy00 -= sw00 * (step(0.0, gy00) - 0.5);
82
+
83
+ vec4 gx01 = ixy01 / 7.0;
84
+ vec4 gy01 = floor(gx01) / 7.0;
85
+ vec4 gz01 = floor(gy01) / 6.0;
86
+ gx01 = fract(gx01) - 0.5;
87
+ gy01 = fract(gy01) - 0.5;
88
+ gz01 = fract(gz01) - 0.5;
89
+ vec4 gw01 = vec4(0.75) - abs(gx01) - abs(gy01) - abs(gz01);
90
+ vec4 sw01 = step(gw01, vec4(0.0));
91
+ gx01 -= sw01 * (step(0.0, gx01) - 0.5);
92
+ gy01 -= sw01 * (step(0.0, gy01) - 0.5);
93
+
94
+ vec4 gx10 = ixy10 / 7.0;
95
+ vec4 gy10 = floor(gx10) / 7.0;
96
+ vec4 gz10 = floor(gy10) / 6.0;
97
+ gx10 = fract(gx10) - 0.5;
98
+ gy10 = fract(gy10) - 0.5;
99
+ gz10 = fract(gz10) - 0.5;
100
+ vec4 gw10 = vec4(0.75) - abs(gx10) - abs(gy10) - abs(gz10);
101
+ vec4 sw10 = step(gw10, vec4(0.0));
102
+ gx10 -= sw10 * (step(0.0, gx10) - 0.5);
103
+ gy10 -= sw10 * (step(0.0, gy10) - 0.5);
104
+
105
+ vec4 gx11 = ixy11 / 7.0;
106
+ vec4 gy11 = floor(gx11) / 7.0;
107
+ vec4 gz11 = floor(gy11) / 6.0;
108
+ gx11 = fract(gx11) - 0.5;
109
+ gy11 = fract(gy11) - 0.5;
110
+ gz11 = fract(gz11) - 0.5;
111
+ vec4 gw11 = vec4(0.75) - abs(gx11) - abs(gy11) - abs(gz11);
112
+ vec4 sw11 = step(gw11, vec4(0.0));
113
+ gx11 -= sw11 * (step(0.0, gx11) - 0.5);
114
+ gy11 -= sw11 * (step(0.0, gy11) - 0.5);
115
+
116
+ vec4 g0000 = vec4(gx00.x,gy00.x,gz00.x,gw00.x);
117
+ vec4 g1000 = vec4(gx00.y,gy00.y,gz00.y,gw00.y);
118
+ vec4 g0100 = vec4(gx00.z,gy00.z,gz00.z,gw00.z);
119
+ vec4 g1100 = vec4(gx00.w,gy00.w,gz00.w,gw00.w);
120
+ vec4 g0010 = vec4(gx10.x,gy10.x,gz10.x,gw10.x);
121
+ vec4 g1010 = vec4(gx10.y,gy10.y,gz10.y,gw10.y);
122
+ vec4 g0110 = vec4(gx10.z,gy10.z,gz10.z,gw10.z);
123
+ vec4 g1110 = vec4(gx10.w,gy10.w,gz10.w,gw10.w);
124
+ vec4 g0001 = vec4(gx01.x,gy01.x,gz01.x,gw01.x);
125
+ vec4 g1001 = vec4(gx01.y,gy01.y,gz01.y,gw01.y);
126
+ vec4 g0101 = vec4(gx01.z,gy01.z,gz01.z,gw01.z);
127
+ vec4 g1101 = vec4(gx01.w,gy01.w,gz01.w,gw01.w);
128
+ vec4 g0011 = vec4(gx11.x,gy11.x,gz11.x,gw11.x);
129
+ vec4 g1011 = vec4(gx11.y,gy11.y,gz11.y,gw11.y);
130
+ vec4 g0111 = vec4(gx11.z,gy11.z,gz11.z,gw11.z);
131
+ vec4 g1111 = vec4(gx11.w,gy11.w,gz11.w,gw11.w);
132
+
133
+ vec4 norm00 = taylorInvSqrt(vec4(dot(g0000, g0000), dot(g0100, g0100), dot(g1000, g1000), dot(g1100, g1100)));
134
+ g0000 *= norm00.x; g0100 *= norm00.y; g1000 *= norm00.z; g1100 *= norm00.w;
135
+
136
+ vec4 norm01 = taylorInvSqrt(vec4(dot(g0001, g0001), dot(g0101, g0101), dot(g1001, g1001), dot(g1101, g1101)));
137
+ g0001 *= norm01.x; g0101 *= norm01.y; g1001 *= norm01.z; g1101 *= norm01.w;
138
+
139
+ vec4 norm10 = taylorInvSqrt(vec4(dot(g0010, g0010), dot(g0110, g0110), dot(g1010, g1010), dot(g1110, g1110)));
140
+ g0010 *= norm10.x; g0110 *= norm10.y; g1010 *= norm10.z; g1110 *= norm10.w;
141
+
142
+ vec4 norm11 = taylorInvSqrt(vec4(dot(g0011, g0011), dot(g0111, g0111), dot(g1011, g1011), dot(g1111, g1111)));
143
+ g0011 *= norm11.x; g0111 *= norm11.y; g1011 *= norm11.z; g1111 *= norm11.w;
144
+
145
+ float n0000 = dot(g0000, Pf0);
146
+ float n1000 = dot(g1000, vec4(Pf1.x, Pf0.yzw));
147
+ float n0100 = dot(g0100, vec4(Pf0.x, Pf1.y, Pf0.zw));
148
+ float n1100 = dot(g1100, vec4(Pf1.xy, Pf0.zw));
149
+ float n0010 = dot(g0010, vec4(Pf0.xy, Pf1.z, Pf0.w));
150
+ float n1010 = dot(g1010, vec4(Pf1.x, Pf0.y, Pf1.z, Pf0.w));
151
+ float n0110 = dot(g0110, vec4(Pf0.x, Pf1.yz, Pf0.w));
152
+ float n1110 = dot(g1110, vec4(Pf1.xyz, Pf0.w));
153
+ float n0001 = dot(g0001, vec4(Pf0.xyz, Pf1.w));
154
+ float n1001 = dot(g1001, vec4(Pf1.x, Pf0.yz, Pf1.w));
155
+ float n0101 = dot(g0101, vec4(Pf0.x, Pf1.y, Pf0.z, Pf1.w));
156
+ float n1101 = dot(g1101, vec4(Pf1.xy, Pf0.z, Pf1.w));
157
+ float n0011 = dot(g0011, vec4(Pf0.xy, Pf1.zw));
158
+ float n1011 = dot(g1011, vec4(Pf1.x, Pf0.y, Pf1.zw));
159
+ float n0111 = dot(g0111, vec4(Pf0.x, Pf1.yzw));
160
+ float n1111 = dot(g1111, Pf1);
161
+
162
+ vec4 fade_xyzw = fade(Pf0);
163
+ vec4 n_0w = mix(vec4(n0000, n1000, n0100, n1100), vec4(n0001, n1001, n0101, n1101), fade_xyzw.w);
164
+ vec4 n_1w = mix(vec4(n0010, n1010, n0110, n1110), vec4(n0011, n1011, n0111, n1111), fade_xyzw.w);
165
+ vec4 n_zw = mix(n_0w, n_1w, fade_xyzw.z);
166
+ vec2 n_yzw = mix(n_zw.xy, n_zw.zw, fade_xyzw.y);
167
+ float n_xyzw = mix(n_yzw.x, n_yzw.y, fade_xyzw.x);
168
+ return 2.2 * n_xyzw;
169
+ }
170
+ `
171
+ );
172
+ var ORGANIC_SPHERE_VERTEX_SHADER = (
173
+ /* glsl */
174
+ `
175
+ #define M_PI 3.1415926535897932384626433832795
176
+
177
+ uniform vec3 uLightAColor;
178
+ uniform vec3 uLightAPosition;
179
+ uniform float uLightAIntensity;
180
+ uniform vec3 uLightBColor;
181
+ uniform vec3 uLightBPosition;
182
+ uniform float uLightBIntensity;
183
+
184
+ uniform vec2 uSubdivision;
185
+
186
+ uniform vec3 uOffset;
187
+
188
+ uniform float uDistortionFrequency;
189
+ uniform float uDistortionStrength;
190
+ uniform float uDisplacementFrequency;
191
+ uniform float uDisplacementStrength;
192
+
193
+ uniform float uFresnelOffset;
194
+ uniform float uFresnelMultiplier;
195
+ uniform float uFresnelPower;
196
+
197
+ uniform vec3 uRimColor;
198
+ uniform float uRimThreshold;
199
+ uniform float uRimPower;
200
+
201
+ uniform float uTime;
202
+
203
+ varying vec3 vColor;
204
+
205
+ ${PERLIN_4D}
206
+
207
+ vec3 getDisplacedPosition(vec3 _position)
208
+ {
209
+ vec3 distoredPosition = _position;
210
+ distoredPosition += perlin4d(vec4(distoredPosition * uDistortionFrequency + uOffset, uTime)) * uDistortionStrength;
211
+
212
+ float perlinStrength = perlin4d(vec4(distoredPosition * uDisplacementFrequency + uOffset, uTime));
213
+
214
+ vec3 displacedPosition = _position;
215
+ displacedPosition += normalize(_position) * perlinStrength * uDisplacementStrength;
216
+
217
+ return displacedPosition;
218
+ }
219
+
220
+ void main()
221
+ {
222
+ vec3 displacedPosition = getDisplacedPosition(position);
223
+ vec4 viewPosition = viewMatrix * vec4(displacedPosition, 1.0);
224
+ gl_Position = projectionMatrix * viewPosition;
225
+
226
+ float distanceA = (M_PI * 2.0) / uSubdivision.x;
227
+ float distanceB = M_PI / uSubdivision.x;
228
+
229
+ vec3 biTangent = cross(normal, tangent.xyz);
230
+
231
+ vec3 positionA = position + tangent.xyz * distanceA;
232
+ vec3 displacedPositionA = getDisplacedPosition(positionA);
233
+
234
+ vec3 positionB = position + biTangent.xyz * distanceB;
235
+ vec3 displacedPositionB = getDisplacedPosition(positionB);
236
+
237
+ vec3 computedNormal = cross(displacedPositionA - displacedPosition.xyz, displacedPositionB - displacedPosition.xyz);
238
+ computedNormal = normalize(computedNormal);
239
+
240
+ vec3 viewDirection = normalize(displacedPosition.xyz - cameraPosition);
241
+ float fresnel = uFresnelOffset + (1.0 + dot(viewDirection, computedNormal)) * uFresnelMultiplier;
242
+ fresnel = pow(max(0.0, fresnel), uFresnelPower);
243
+
244
+ float lightAIntensity = max(0.0, - dot(computedNormal.xyz, normalize(- uLightAPosition))) * uLightAIntensity;
245
+ float lightBIntensity = max(0.0, - dot(computedNormal.xyz, normalize(- uLightBPosition))) * uLightBIntensity;
246
+
247
+ // Clamp mix factors to [0, 1] so a high lightIntensity*fresnel (common on
248
+ // displacement peaks and loud audio) cannot extrapolate past the orange
249
+ // light color and saturate R, producing yellow-white hotspots.
250
+ vec3 color = vec3(0.0);
251
+ color = mix(color, uLightAColor, clamp(lightAIntensity * fresnel, 0.0, 1.0));
252
+ color = mix(color, uLightBColor, clamp(lightBIntensity * fresnel, 0.0, 1.0));
253
+ color = mix(color, uRimColor, clamp(pow(max(0.0, fresnel - uRimThreshold), uRimPower), 0.0, 1.0));
254
+
255
+ vColor = color;
256
+ }
257
+ `
258
+ );
259
+ var ORGANIC_SPHERE_FRAGMENT_SHADER = (
260
+ /* glsl */
261
+ `
262
+ varying vec3 vColor;
263
+
264
+ void main()
265
+ {
266
+ gl_FragColor = vec4(vColor, 1.0);
267
+ }
268
+ `
269
+ );
270
+
271
+ // src/react/sphereConfig.ts
272
+ var DEFAULT_ORGANIC_SPHERE_CONFIG = {
273
+ // Lighting & rim
274
+ lightAColor: "#c2410c",
275
+ lightBColor: "#fb923c",
276
+ lightAIntensity: 2.13,
277
+ lightBIntensity: 1.61,
278
+ rimColor: null,
279
+ rimThreshold: 0.92,
280
+ rimPower: 5,
281
+ // Static shape
282
+ distortionFrequency: 1.5,
283
+ displacementFrequency: 2.12,
284
+ fresnelOffset: -1.609,
285
+ fresnelPower: 1.793,
286
+ // Audio reactivity
287
+ volume: {
288
+ idle: 0.152,
289
+ gain: 0.3,
290
+ floor: 0,
291
+ attack: 0.03,
292
+ decay: 2e-3
293
+ },
294
+ medium: {
295
+ idle: 3.587,
296
+ gain: 2,
297
+ floor: 3.587,
298
+ attack: 8e-3,
299
+ decay: 4e-3
300
+ },
301
+ high: {
302
+ idle: 0.65,
303
+ gain: 5,
304
+ floor: 0.5,
305
+ attack: 0.02,
306
+ decay: 1e-3
307
+ },
308
+ low: {
309
+ idle: 3e-4,
310
+ gain: 3e-3,
311
+ floor: 1e-4,
312
+ attack: 5e-3,
313
+ decay: 2e-3
314
+ },
315
+ // Camera
316
+ cameraZ: 3.84,
317
+ fov: 35,
318
+ // Determinism
319
+ seed: 0,
320
+ // Init-only
321
+ subdivisions: 512,
322
+ maxPixelRatio: null,
323
+ backgroundColor: null
324
+ };
325
+ function resolveOrganicSphereConfig(partial) {
326
+ const base = DEFAULT_ORGANIC_SPHERE_CONFIG;
327
+ if (!partial) return { ...base, volume: { ...base.volume }, medium: { ...base.medium }, high: { ...base.high }, low: { ...base.low } };
328
+ return {
329
+ ...base,
330
+ ...partial,
331
+ volume: { ...base.volume, ...partial.volume ?? {} },
332
+ medium: { ...base.medium, ...partial.medium ?? {} },
333
+ high: { ...base.high, ...partial.high ?? {} },
334
+ low: { ...base.low, ...partial.low ?? {} }
335
+ };
336
+ }
337
+
338
+ // src/react/OrganicSphere.tsx
339
+ var import_jsx_runtime = require("react/jsx-runtime");
340
+ function seededUnit(seed, salt) {
341
+ const s = Math.sin((seed + salt * 7919) * 12.9898 + salt * 78.233) * 43758.5453;
342
+ return s - Math.floor(s);
343
+ }
344
+ function OrganicSphere({
345
+ getFrequencyData,
346
+ active = true,
347
+ config: configProp,
348
+ lightAColor,
349
+ lightBColor,
350
+ rimColor,
351
+ rimThreshold,
352
+ rimPower,
353
+ backgroundColor,
354
+ subdivisions,
355
+ maxPixelRatio,
356
+ className,
357
+ style
358
+ }) {
359
+ const containerRef = (0, import_react.useRef)(null);
360
+ const resolvedConfig = (0, import_react.useMemo)(() => {
361
+ const base = resolveOrganicSphereConfig(configProp);
362
+ const overrides = {};
363
+ if (lightAColor !== void 0) overrides.lightAColor = lightAColor;
364
+ if (lightBColor !== void 0) overrides.lightBColor = lightBColor;
365
+ if (rimColor !== void 0) overrides.rimColor = rimColor;
366
+ if (rimThreshold !== void 0) overrides.rimThreshold = rimThreshold;
367
+ if (rimPower !== void 0) overrides.rimPower = rimPower;
368
+ if (backgroundColor !== void 0) overrides.backgroundColor = backgroundColor;
369
+ if (subdivisions !== void 0) overrides.subdivisions = subdivisions;
370
+ if (maxPixelRatio !== void 0) overrides.maxPixelRatio = maxPixelRatio;
371
+ return { ...base, ...overrides };
372
+ }, [
373
+ configProp,
374
+ lightAColor,
375
+ lightBColor,
376
+ rimColor,
377
+ rimThreshold,
378
+ rimPower,
379
+ backgroundColor,
380
+ subdivisions,
381
+ maxPixelRatio
382
+ ]);
383
+ const configRef = (0, import_react.useRef)(resolvedConfig);
384
+ (0, import_react.useEffect)(() => {
385
+ configRef.current = resolvedConfig;
386
+ }, [resolvedConfig]);
387
+ const getFrequencyDataRef = (0, import_react.useRef)(getFrequencyData);
388
+ const activeRef = (0, import_react.useRef)(active);
389
+ (0, import_react.useEffect)(() => {
390
+ getFrequencyDataRef.current = getFrequencyData;
391
+ }, [getFrequencyData]);
392
+ (0, import_react.useEffect)(() => {
393
+ activeRef.current = active;
394
+ }, [active]);
395
+ const initSubdivisions = resolvedConfig.subdivisions;
396
+ const initMaxPixelRatio = resolvedConfig.maxPixelRatio;
397
+ const initBackgroundColor = resolvedConfig.backgroundColor;
398
+ (0, import_react.useEffect)(() => {
399
+ const container = containerRef.current;
400
+ if (!container) return;
401
+ const cfg0 = configRef.current;
402
+ const width = container.clientWidth || 1;
403
+ const height = container.clientHeight || 1;
404
+ const pixelRatio = Math.min(
405
+ initMaxPixelRatio ?? (typeof window !== "undefined" ? window.devicePixelRatio : 1),
406
+ 2
407
+ );
408
+ const scene = new THREE.Scene();
409
+ if (initBackgroundColor) scene.background = new THREE.Color(initBackgroundColor);
410
+ const camera = new THREE.PerspectiveCamera(cfg0.fov, width / height, 0.1, 100);
411
+ camera.position.set(0, 0, cfg0.cameraZ);
412
+ scene.add(camera);
413
+ const renderer = new THREE.WebGLRenderer({
414
+ antialias: true,
415
+ alpha: initBackgroundColor === null,
416
+ powerPreference: "high-performance"
417
+ });
418
+ renderer.setSize(width, height, false);
419
+ renderer.setPixelRatio(pixelRatio);
420
+ renderer.setClearColor(0, initBackgroundColor === null ? 0 : 1);
421
+ container.appendChild(renderer.domElement);
422
+ renderer.domElement.style.display = "block";
423
+ renderer.domElement.style.width = "100%";
424
+ renderer.domElement.style.height = "100%";
425
+ const geometry = new THREE.SphereGeometry(1, initSubdivisions, initSubdivisions);
426
+ geometry.computeTangents();
427
+ const lightAPos = new THREE.Vector3().setFromSpherical(
428
+ new THREE.Spherical(1, 0.615, 2.049)
429
+ );
430
+ const lightBPos = new THREE.Vector3().setFromSpherical(
431
+ new THREE.Spherical(1, 2.561, -1.844)
432
+ );
433
+ const lightAColorObj = new THREE.Color(cfg0.lightAColor);
434
+ const lightBColorObj = new THREE.Color(cfg0.lightBColor);
435
+ const rimColorObj = new THREE.Color(cfg0.rimColor ?? cfg0.lightBColor);
436
+ const material = new THREE.ShaderMaterial({
437
+ uniforms: {
438
+ uLightAColor: { value: lightAColorObj },
439
+ uLightAPosition: { value: lightAPos },
440
+ uLightAIntensity: { value: cfg0.lightAIntensity },
441
+ uLightBColor: { value: lightBColorObj },
442
+ uLightBPosition: { value: lightBPos },
443
+ uLightBIntensity: { value: cfg0.lightBIntensity },
444
+ uSubdivision: {
445
+ value: new THREE.Vector2(initSubdivisions, initSubdivisions)
446
+ },
447
+ uOffset: { value: new THREE.Vector3() },
448
+ uDistortionFrequency: { value: cfg0.distortionFrequency },
449
+ uDistortionStrength: { value: cfg0.high.idle },
450
+ uDisplacementFrequency: { value: cfg0.displacementFrequency },
451
+ uDisplacementStrength: { value: cfg0.volume.idle },
452
+ uFresnelOffset: { value: cfg0.fresnelOffset },
453
+ uFresnelMultiplier: { value: cfg0.medium.idle },
454
+ uFresnelPower: { value: cfg0.fresnelPower },
455
+ uRimColor: { value: rimColorObj },
456
+ uRimThreshold: { value: cfg0.rimThreshold },
457
+ uRimPower: { value: cfg0.rimPower },
458
+ uTime: { value: 0 }
459
+ },
460
+ defines: { USE_TANGENT: "" },
461
+ vertexShader: ORGANIC_SPHERE_VERTEX_SHADER,
462
+ fragmentShader: ORGANIC_SPHERE_FRAGMENT_SHADER
463
+ });
464
+ const mesh = new THREE.Mesh(geometry, material);
465
+ scene.add(mesh);
466
+ const seedInitialPhase = (seed) => ({
467
+ phi: seededUnit(seed, 1) * Math.PI,
468
+ theta: seededUnit(seed, 2) * Math.PI * 2
469
+ });
470
+ const initialPhase = seedInitialPhase(cfg0.seed);
471
+ const offsetSpherical = new THREE.Spherical(1, initialPhase.phi, initialPhase.theta);
472
+ const offsetDirection = new THREE.Vector3().setFromSpherical(offsetSpherical);
473
+ const variations = {
474
+ volume: { target: 0, current: cfg0.volume.idle },
475
+ medium: { target: 0, current: cfg0.medium.idle },
476
+ high: { target: 0, current: cfg0.high.idle },
477
+ low: { target: 0, current: cfg0.low.idle }
478
+ };
479
+ const resetAnimationState = (cfg) => {
480
+ material.uniforms.uTime.value = 0;
481
+ material.uniforms.uOffset.value.set(0, 0, 0);
482
+ const phase = seedInitialPhase(cfg.seed);
483
+ offsetSpherical.radius = 1;
484
+ offsetSpherical.phi = phase.phi;
485
+ offsetSpherical.theta = phase.theta;
486
+ variations.volume.current = cfg.volume.idle;
487
+ variations.medium.current = cfg.medium.idle;
488
+ variations.high.current = cfg.high.idle;
489
+ variations.low.current = cfg.low.idle;
490
+ variations.volume.target = cfg.volume.idle;
491
+ variations.medium.target = cfg.medium.idle;
492
+ variations.high.target = cfg.high.idle;
493
+ variations.low.target = cfg.low.idle;
494
+ };
495
+ const LEVEL_COUNT = 8;
496
+ function computeLevels(buf) {
497
+ const bins = Math.floor(buf.length / LEVEL_COUNT);
498
+ const levels = new Array(LEVEL_COUNT).fill(0);
499
+ if (bins <= 0) return levels;
500
+ for (let i = 0; i < LEVEL_COUNT; i++) {
501
+ let sum = 0;
502
+ for (let j = 0; j < bins; j++) sum += buf[i * bins + j];
503
+ levels[i] = sum / bins / 256;
504
+ }
505
+ return levels;
506
+ }
507
+ function bandTarget(reactivity, levels, sourceLevel) {
508
+ if (!levels) return reactivity.idle;
509
+ return Math.max(reactivity.floor, reactivity.floor + sourceLevel * reactivity.gain);
510
+ }
511
+ let rafId = 0;
512
+ let lastTs = performance.now();
513
+ let disposed = false;
514
+ let wasActive = activeRef.current;
515
+ let lastSeed = cfg0.seed;
516
+ const render = () => {
517
+ if (disposed) return;
518
+ const now = performance.now();
519
+ const delta = Math.min(now - lastTs, 100);
520
+ lastTs = now;
521
+ const cfg = configRef.current;
522
+ lightAColorObj.set(cfg.lightAColor);
523
+ lightBColorObj.set(cfg.lightBColor);
524
+ rimColorObj.set(cfg.rimColor ?? cfg.lightBColor);
525
+ material.uniforms.uLightAIntensity.value = cfg.lightAIntensity;
526
+ material.uniforms.uLightBIntensity.value = cfg.lightBIntensity;
527
+ material.uniforms.uDistortionFrequency.value = cfg.distortionFrequency;
528
+ material.uniforms.uDisplacementFrequency.value = cfg.displacementFrequency;
529
+ material.uniforms.uFresnelOffset.value = cfg.fresnelOffset;
530
+ material.uniforms.uFresnelPower.value = cfg.fresnelPower;
531
+ material.uniforms.uRimThreshold.value = cfg.rimThreshold;
532
+ material.uniforms.uRimPower.value = cfg.rimPower;
533
+ if (camera.position.z !== cfg.cameraZ) camera.position.z = cfg.cameraZ;
534
+ if (camera.fov !== cfg.fov) {
535
+ camera.fov = cfg.fov;
536
+ camera.updateProjectionMatrix();
537
+ }
538
+ const isActive = activeRef.current;
539
+ if (isActive && !wasActive || cfg.seed !== lastSeed) {
540
+ resetAnimationState(cfg);
541
+ lastSeed = cfg.seed;
542
+ }
543
+ wasActive = isActive;
544
+ if (isActive) {
545
+ let levels = null;
546
+ if (getFrequencyDataRef.current) {
547
+ try {
548
+ const buf = getFrequencyDataRef.current();
549
+ if (buf && buf.length > 0) levels = computeLevels(buf);
550
+ } catch {
551
+ levels = null;
552
+ }
553
+ }
554
+ const l0 = levels ? levels[0] || 0 : 0;
555
+ const l1 = levels ? levels[1] || 0 : 0;
556
+ const l2 = levels ? levels[2] || 0 : 0;
557
+ const loudest = Math.max(l0, l1, l2);
558
+ const update = (variation, reactivity, sourceLevel) => {
559
+ variation.target = bandTarget(reactivity, levels, sourceLevel);
560
+ const easing = variation.target > variation.current ? reactivity.attack : reactivity.decay;
561
+ variation.current += (variation.target - variation.current) * easing * delta;
562
+ };
563
+ update(variations.volume, cfg.volume, loudest);
564
+ update(variations.medium, cfg.medium, l1);
565
+ update(variations.high, cfg.high, l2);
566
+ update(variations.low, cfg.low, l0);
567
+ const timeFrequency = variations.low.current;
568
+ const elapsed = delta * timeFrequency;
569
+ material.uniforms.uDisplacementStrength.value = variations.volume.current;
570
+ material.uniforms.uDistortionStrength.value = variations.high.current;
571
+ material.uniforms.uFresnelMultiplier.value = variations.medium.current;
572
+ const offsetTime = (material.uniforms.uTime.value + elapsed) * 0.3;
573
+ offsetSpherical.phi = (Math.sin(offsetTime * 1e-3) * Math.sin(offsetTime * 321e-5) * 0.5 + 0.5) * Math.PI;
574
+ offsetSpherical.theta = (Math.sin(offsetTime * 1e-4) * Math.sin(offsetTime * 321e-6) * 0.5 + 0.5) * Math.PI * 2;
575
+ offsetDirection.setFromSpherical(offsetSpherical);
576
+ offsetDirection.multiplyScalar(timeFrequency * 2);
577
+ material.uniforms.uOffset.value.add(offsetDirection);
578
+ material.uniforms.uTime.value += elapsed;
579
+ }
580
+ renderer.render(scene, camera);
581
+ rafId = requestAnimationFrame(render);
582
+ };
583
+ rafId = requestAnimationFrame(render);
584
+ const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
585
+ const w = container.clientWidth || 1;
586
+ const h = container.clientHeight || 1;
587
+ camera.aspect = w / h;
588
+ camera.updateProjectionMatrix();
589
+ renderer.setSize(w, h, false);
590
+ }) : null;
591
+ resizeObserver?.observe(container);
592
+ return () => {
593
+ disposed = true;
594
+ cancelAnimationFrame(rafId);
595
+ resizeObserver?.disconnect();
596
+ geometry.dispose();
597
+ material.dispose();
598
+ renderer.dispose();
599
+ if (renderer.domElement.parentNode === container) {
600
+ container.removeChild(renderer.domElement);
601
+ }
602
+ };
603
+ }, [initSubdivisions, initMaxPixelRatio, initBackgroundColor]);
604
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ref: containerRef, className, style });
605
+ }
606
+
607
+ // src/react/OrganicParticles.tsx
608
+ var import_react2 = require("react");
609
+ var THREE2 = __toESM(require("three"), 1);
610
+
611
+ // src/react/shaders/organicParticlesShaders.ts
612
+ var ORGANIC_PARTICLES_VERTEX_SHADER = (
613
+ /* glsl */
614
+ `
615
+ ${PERLIN_4D}
616
+
617
+ attribute vec3 aBasePosition;
618
+ attribute float aSeed;
619
+
620
+ uniform float uTime;
621
+ uniform float uNoiseFrequency;
622
+ uniform float uNoiseStrength;
623
+ uniform float uDisplacement;
624
+ uniform float uSwirl;
625
+ uniform float uSwirlTimeRate;
626
+ uniform float uSizeBase;
627
+ uniform float uSizeAudio;
628
+ uniform float uPixelRatio;
629
+
630
+ varying float vHeat;
631
+ varying float vSeed;
632
+
633
+ void main() {
634
+ vec3 pos = aBasePosition;
635
+
636
+ // 4D Perlin sampled in particle space. The 4th axis is time so the
637
+ // cloud evolves over time without tiling.
638
+ float n = perlin4d(vec4(pos * uNoiseFrequency, uTime));
639
+
640
+ // Per-particle phase so the cloud doesn't breathe in lockstep.
641
+ float phaseShift = (aSeed - 0.5) * 0.5;
642
+ float breath = sin(uTime * 0.0008 + aSeed * 6.2831) * 0.5 + 0.5;
643
+
644
+ // Outward push: noise + audio-driven displacement, scaled by seed so
645
+ // some particles dart further than others on the same beat.
646
+ vec3 radial = normalize(pos);
647
+ float push = n * uNoiseStrength + uDisplacement * (0.6 + aSeed * 0.8) + breath * 0.05;
648
+ pos += radial * push;
649
+
650
+ // Twist around Y. Amount scales with height so the cloud spirals
651
+ // rather than rigid-rotating. uSwirlTimeRate is 0 by default so the
652
+ // swirl is driven by audio (uSwirl) alone; crank it for a constant
653
+ // drift.
654
+ float swirlAngle = pos.y * uSwirl + uTime * uSwirlTimeRate + phaseShift;
655
+ float c = cos(swirlAngle);
656
+ float s = sin(swirlAngle);
657
+ pos.xz = mat2(c, -s, s, c) * pos.xz;
658
+
659
+ vec4 mvPos = modelViewMatrix * vec4(pos, 1.0);
660
+ gl_Position = projectionMatrix * mvPos;
661
+
662
+ // Point size: base + audio boost, gently perspective-attenuated. At
663
+ // the default camera (z ~= 3.84) a uSizeBase of 1 renders roughly one
664
+ // device pixel \u2014 intentionally tiny so 40k+ additively-blended points
665
+ // read as fine dust rather than a solid blob.
666
+ float size = uSizeBase + uSizeAudio * (0.5 + aSeed);
667
+ gl_PointSize = max(1.0, size * uPixelRatio * (2.0 / max(0.1, -mvPos.z)));
668
+
669
+ // Heat: 0 at core, 1 at fringe. Used by the fragment to lerp color.
670
+ vHeat = clamp((length(pos) - 0.4) / 1.4, 0.0, 1.0);
671
+ vSeed = aSeed;
672
+ }
673
+ `
674
+ );
675
+ var ORGANIC_PARTICLES_FRAGMENT_SHADER = (
676
+ /* glsl */
677
+ `
678
+ precision mediump float;
679
+
680
+ uniform vec3 uColorCool;
681
+ uniform vec3 uColorHot;
682
+ uniform float uOpacity;
683
+ uniform float uSoftness;
684
+
685
+ varying float vHeat;
686
+ varying float vSeed;
687
+
688
+ void main() {
689
+ vec2 centered = gl_PointCoord - vec2(0.5);
690
+ float distSq = dot(centered, centered);
691
+ if (distSq > 0.25) discard;
692
+
693
+ // Soft circular falloff. uSoftness in [0.5, 1] controls how hard the
694
+ // edge is: 0.5 = sharp disc, 1 = feathered blob.
695
+ float innerR = 0.25 * (1.0 - uSoftness);
696
+ float alpha = smoothstep(0.25, innerR, distSq);
697
+
698
+ // Warm/cool gradient, with a tiny seed-based tint wobble so the cloud
699
+ // doesn't look banded.
700
+ float wobble = (vSeed - 0.5) * 0.15;
701
+ vec3 color = mix(uColorCool, uColorHot, clamp(vHeat + wobble, 0.0, 1.0));
702
+
703
+ gl_FragColor = vec4(color, alpha * uOpacity);
704
+ }
705
+ `
706
+ );
707
+
708
+ // src/react/particlesConfig.ts
709
+ var DEFAULT_ORGANIC_PARTICLES_CONFIG = {
710
+ // Cloud shape
711
+ count: 4e4,
712
+ innerRadius: 0.6,
713
+ outerRadius: 1.1,
714
+ // Motion. Constant rotation / swirl drift default to 0 so the cloud
715
+ // only spins in response to audio — but `idleNoiseRate` keeps the
716
+ // Perlin field shimmering slightly so the cloud doesn't look frozen
717
+ // while paused.
718
+ noiseFrequency: 1.4,
719
+ noiseStrength: 0.22,
720
+ rotationBias: 0,
721
+ swirlTimeRate: 0,
722
+ idleNoiseRate: 1e-4,
723
+ // Rendering. Additive blending stacks contributions, so keep opacity
724
+ // low (<0.3) or 40k particles will saturate to white. sizeBase ~1
725
+ // renders as tiny dust; crank it higher for softer plasma look.
726
+ sizeBase: 1,
727
+ softness: 0.55,
728
+ opacity: 0.18,
729
+ // Color
730
+ colorCool: "#c2410c",
731
+ colorHot: "#fb923c",
732
+ // Audio reactivity
733
+ volume: {
734
+ idle: 0.02,
735
+ gain: 0.4,
736
+ floor: 0,
737
+ attack: 0.03,
738
+ decay: 25e-4
739
+ },
740
+ medium: {
741
+ idle: 0,
742
+ gain: 4,
743
+ floor: 0,
744
+ attack: 0.01,
745
+ decay: 4e-3
746
+ },
747
+ high: {
748
+ idle: 0.2,
749
+ gain: 1.2,
750
+ floor: 0.15,
751
+ attack: 0.015,
752
+ decay: 2e-3
753
+ },
754
+ low: {
755
+ idle: 4e-4,
756
+ gain: 4e-3,
757
+ floor: 1e-4,
758
+ attack: 5e-3,
759
+ decay: 2e-3
760
+ },
761
+ // Camera
762
+ cameraZ: 3.84,
763
+ fov: 35,
764
+ // Determinism
765
+ seed: 0,
766
+ // Init-only
767
+ maxPixelRatio: null,
768
+ backgroundColor: null
769
+ };
770
+ function resolveOrganicParticlesConfig(partial) {
771
+ const base = DEFAULT_ORGANIC_PARTICLES_CONFIG;
772
+ if (!partial) {
773
+ return {
774
+ ...base,
775
+ volume: { ...base.volume },
776
+ medium: { ...base.medium },
777
+ high: { ...base.high },
778
+ low: { ...base.low }
779
+ };
780
+ }
781
+ return {
782
+ ...base,
783
+ ...partial,
784
+ volume: { ...base.volume, ...partial.volume ?? {} },
785
+ medium: { ...base.medium, ...partial.medium ?? {} },
786
+ high: { ...base.high, ...partial.high ?? {} },
787
+ low: { ...base.low, ...partial.low ?? {} }
788
+ };
789
+ }
790
+
791
+ // src/react/OrganicParticles.tsx
792
+ var import_jsx_runtime2 = require("react/jsx-runtime");
793
+ function seededUnit2(seed, salt) {
794
+ const s = Math.sin((seed + salt * 7919) * 12.9898 + salt * 78.233) * 43758.5453;
795
+ return s - Math.floor(s);
796
+ }
797
+ function buildParticleAttributes(count, innerRadius, outerRadius, seed) {
798
+ const positions = new Float32Array(count * 3);
799
+ const seeds = new Float32Array(count);
800
+ for (let i = 0; i < count; i++) {
801
+ const u = seededUnit2(seed, i * 4 + 1);
802
+ const v = seededUnit2(seed, i * 4 + 2);
803
+ const w = seededUnit2(seed, i * 4 + 3);
804
+ const s = seededUnit2(seed, i * 4 + 4);
805
+ const theta = v * Math.PI * 2;
806
+ const phi = Math.acos(2 * w - 1);
807
+ const r = innerRadius + u * Math.max(0, outerRadius - innerRadius);
808
+ const sinPhi = Math.sin(phi);
809
+ positions[i * 3 + 0] = r * sinPhi * Math.cos(theta);
810
+ positions[i * 3 + 1] = r * sinPhi * Math.sin(theta);
811
+ positions[i * 3 + 2] = r * Math.cos(phi);
812
+ seeds[i] = s;
813
+ }
814
+ return { positions, seeds };
815
+ }
816
+ function OrganicParticles({
817
+ getFrequencyData,
818
+ active = true,
819
+ config: configProp,
820
+ className,
821
+ style
822
+ }) {
823
+ const containerRef = (0, import_react2.useRef)(null);
824
+ const resolvedConfig = (0, import_react2.useMemo)(
825
+ () => resolveOrganicParticlesConfig(configProp),
826
+ [configProp]
827
+ );
828
+ const configRef = (0, import_react2.useRef)(resolvedConfig);
829
+ (0, import_react2.useEffect)(() => {
830
+ configRef.current = resolvedConfig;
831
+ }, [resolvedConfig]);
832
+ const getFrequencyDataRef = (0, import_react2.useRef)(getFrequencyData);
833
+ const activeRef = (0, import_react2.useRef)(active);
834
+ (0, import_react2.useEffect)(() => {
835
+ getFrequencyDataRef.current = getFrequencyData;
836
+ }, [getFrequencyData]);
837
+ (0, import_react2.useEffect)(() => {
838
+ activeRef.current = active;
839
+ }, [active]);
840
+ const initCount = resolvedConfig.count;
841
+ const initInnerRadius = resolvedConfig.innerRadius;
842
+ const initOuterRadius = resolvedConfig.outerRadius;
843
+ const initSeed = resolvedConfig.seed;
844
+ const initMaxPixelRatio = resolvedConfig.maxPixelRatio;
845
+ const initBackgroundColor = resolvedConfig.backgroundColor;
846
+ (0, import_react2.useEffect)(() => {
847
+ const container = containerRef.current;
848
+ if (!container) return;
849
+ const cfg0 = configRef.current;
850
+ const width = container.clientWidth || 1;
851
+ const height = container.clientHeight || 1;
852
+ const pixelRatio = Math.min(
853
+ initMaxPixelRatio ?? (typeof window !== "undefined" ? window.devicePixelRatio : 1),
854
+ 2
855
+ );
856
+ const scene = new THREE2.Scene();
857
+ if (initBackgroundColor) scene.background = new THREE2.Color(initBackgroundColor);
858
+ const camera = new THREE2.PerspectiveCamera(cfg0.fov, width / height, 0.1, 100);
859
+ camera.position.set(0, 0, cfg0.cameraZ);
860
+ scene.add(camera);
861
+ const renderer = new THREE2.WebGLRenderer({
862
+ antialias: true,
863
+ alpha: initBackgroundColor === null,
864
+ powerPreference: "high-performance"
865
+ });
866
+ renderer.setSize(width, height, false);
867
+ renderer.setPixelRatio(pixelRatio);
868
+ renderer.setClearColor(0, initBackgroundColor === null ? 0 : 1);
869
+ container.appendChild(renderer.domElement);
870
+ renderer.domElement.style.display = "block";
871
+ renderer.domElement.style.width = "100%";
872
+ renderer.domElement.style.height = "100%";
873
+ const { positions, seeds } = buildParticleAttributes(
874
+ initCount,
875
+ initInnerRadius,
876
+ initOuterRadius,
877
+ initSeed
878
+ );
879
+ const geometry = new THREE2.BufferGeometry();
880
+ geometry.setAttribute("aBasePosition", new THREE2.BufferAttribute(positions, 3));
881
+ geometry.setAttribute("aSeed", new THREE2.BufferAttribute(seeds, 1));
882
+ geometry.setAttribute("position", new THREE2.BufferAttribute(positions, 3));
883
+ const colorCoolObj = new THREE2.Color(cfg0.colorCool);
884
+ const colorHotObj = new THREE2.Color(cfg0.colorHot);
885
+ const material = new THREE2.ShaderMaterial({
886
+ uniforms: {
887
+ uTime: { value: 0 },
888
+ uNoiseFrequency: { value: cfg0.noiseFrequency },
889
+ uNoiseStrength: { value: cfg0.noiseStrength },
890
+ uDisplacement: { value: cfg0.volume.idle },
891
+ uSwirl: { value: cfg0.high.idle },
892
+ uSwirlTimeRate: { value: cfg0.swirlTimeRate },
893
+ uSizeBase: { value: cfg0.sizeBase },
894
+ uSizeAudio: { value: cfg0.medium.idle },
895
+ uPixelRatio: { value: pixelRatio },
896
+ uColorCool: { value: colorCoolObj },
897
+ uColorHot: { value: colorHotObj },
898
+ uOpacity: { value: cfg0.opacity },
899
+ uSoftness: { value: cfg0.softness }
900
+ },
901
+ vertexShader: ORGANIC_PARTICLES_VERTEX_SHADER,
902
+ fragmentShader: ORGANIC_PARTICLES_FRAGMENT_SHADER,
903
+ transparent: true,
904
+ depthWrite: false,
905
+ blending: THREE2.AdditiveBlending
906
+ });
907
+ const points = new THREE2.Points(geometry, material);
908
+ scene.add(points);
909
+ const variations = {
910
+ volume: { target: 0, current: cfg0.volume.idle },
911
+ medium: { target: 0, current: cfg0.medium.idle },
912
+ high: { target: 0, current: cfg0.high.idle },
913
+ low: { target: 0, current: cfg0.low.idle }
914
+ };
915
+ const LEVEL_COUNT = 8;
916
+ function computeLevels(buf) {
917
+ const bins = Math.floor(buf.length / LEVEL_COUNT);
918
+ const levels = new Array(LEVEL_COUNT).fill(0);
919
+ if (bins <= 0) return levels;
920
+ for (let i = 0; i < LEVEL_COUNT; i++) {
921
+ let sum = 0;
922
+ for (let j = 0; j < bins; j++) sum += buf[i * bins + j];
923
+ levels[i] = sum / bins / 256;
924
+ }
925
+ return levels;
926
+ }
927
+ function bandTarget(reactivity, levels, sourceLevel) {
928
+ if (!levels) return reactivity.idle;
929
+ return Math.max(
930
+ reactivity.floor,
931
+ reactivity.floor + sourceLevel * reactivity.gain
932
+ );
933
+ }
934
+ const rotationState = { y: 0 };
935
+ const resetAnimationState = (cfg) => {
936
+ material.uniforms.uTime.value = 0;
937
+ rotationState.y = 0;
938
+ points.rotation.set(0, 0, 0);
939
+ variations.volume.current = cfg.volume.idle;
940
+ variations.medium.current = cfg.medium.idle;
941
+ variations.high.current = cfg.high.idle;
942
+ variations.low.current = cfg.low.idle;
943
+ variations.volume.target = cfg.volume.idle;
944
+ variations.medium.target = cfg.medium.idle;
945
+ variations.high.target = cfg.high.idle;
946
+ variations.low.target = cfg.low.idle;
947
+ };
948
+ let rafId = 0;
949
+ let lastTs = performance.now();
950
+ let disposed = false;
951
+ let wasActive = activeRef.current;
952
+ const render = () => {
953
+ if (disposed) return;
954
+ const now = performance.now();
955
+ const delta = Math.min(now - lastTs, 100);
956
+ lastTs = now;
957
+ const cfg = configRef.current;
958
+ colorCoolObj.set(cfg.colorCool);
959
+ colorHotObj.set(cfg.colorHot);
960
+ material.uniforms.uNoiseFrequency.value = cfg.noiseFrequency;
961
+ material.uniforms.uNoiseStrength.value = cfg.noiseStrength;
962
+ material.uniforms.uSwirlTimeRate.value = cfg.swirlTimeRate;
963
+ material.uniforms.uSizeBase.value = cfg.sizeBase;
964
+ material.uniforms.uOpacity.value = cfg.opacity;
965
+ material.uniforms.uSoftness.value = cfg.softness;
966
+ if (camera.position.z !== cfg.cameraZ) camera.position.z = cfg.cameraZ;
967
+ if (camera.fov !== cfg.fov) {
968
+ camera.fov = cfg.fov;
969
+ camera.updateProjectionMatrix();
970
+ }
971
+ const isActive = activeRef.current;
972
+ if (isActive && !wasActive) {
973
+ resetAnimationState(cfg);
974
+ }
975
+ wasActive = isActive;
976
+ if (isActive) {
977
+ let levels = null;
978
+ if (getFrequencyDataRef.current) {
979
+ try {
980
+ const buf = getFrequencyDataRef.current();
981
+ if (buf && buf.length > 0) levels = computeLevels(buf);
982
+ } catch {
983
+ levels = null;
984
+ }
985
+ }
986
+ const l0 = levels ? levels[0] || 0 : 0;
987
+ const l1 = levels ? levels[1] || 0 : 0;
988
+ const l2 = levels ? levels[2] || 0 : 0;
989
+ const loudest = Math.max(l0, l1, l2);
990
+ const update = (variation, reactivity, sourceLevel) => {
991
+ variation.target = bandTarget(reactivity, levels, sourceLevel);
992
+ const easing = variation.target > variation.current ? reactivity.attack : reactivity.decay;
993
+ variation.current += (variation.target - variation.current) * easing * delta;
994
+ };
995
+ update(variations.volume, cfg.volume, loudest);
996
+ update(variations.medium, cfg.medium, l1);
997
+ update(variations.high, cfg.high, l2);
998
+ update(variations.low, cfg.low, l0);
999
+ const timeFrequency = variations.low.current;
1000
+ const elapsed = delta * timeFrequency;
1001
+ material.uniforms.uDisplacement.value = variations.volume.current;
1002
+ material.uniforms.uSizeAudio.value = variations.medium.current;
1003
+ material.uniforms.uSwirl.value = variations.high.current;
1004
+ material.uniforms.uTime.value += elapsed;
1005
+ rotationState.y += delta * cfg.rotationBias + variations.high.current * delta * 8e-4;
1006
+ points.rotation.y = rotationState.y;
1007
+ } else {
1008
+ material.uniforms.uTime.value += delta * cfg.idleNoiseRate;
1009
+ }
1010
+ renderer.render(scene, camera);
1011
+ rafId = requestAnimationFrame(render);
1012
+ };
1013
+ rafId = requestAnimationFrame(render);
1014
+ const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
1015
+ const w = container.clientWidth || 1;
1016
+ const h = container.clientHeight || 1;
1017
+ camera.aspect = w / h;
1018
+ camera.updateProjectionMatrix();
1019
+ renderer.setSize(w, h, false);
1020
+ }) : null;
1021
+ resizeObserver?.observe(container);
1022
+ return () => {
1023
+ disposed = true;
1024
+ cancelAnimationFrame(rafId);
1025
+ resizeObserver?.disconnect();
1026
+ geometry.dispose();
1027
+ material.dispose();
1028
+ renderer.dispose();
1029
+ if (renderer.domElement.parentNode === container) {
1030
+ container.removeChild(renderer.domElement);
1031
+ }
1032
+ };
1033
+ }, [
1034
+ initCount,
1035
+ initInnerRadius,
1036
+ initOuterRadius,
1037
+ initSeed,
1038
+ initMaxPixelRatio,
1039
+ initBackgroundColor
1040
+ ]);
1041
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { ref: containerRef, className, style });
1042
+ }
1043
+ // Annotate the CommonJS export names for ESM import in node:
1044
+ 0 && (module.exports = {
1045
+ OrganicParticles,
1046
+ OrganicSphere
1047
+ });
1048
+ //# sourceMappingURL=visuals.cjs.map