@shogo-ai/voice 1.10.0 → 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.
- package/README.md +89 -0
- package/dist/{chunk-S3S2RNO6.js → chunk-BI6SL35K.js} +1 -184
- package/dist/chunk-CLF25CZC.js +987 -0
- package/dist/chunk-KMSL5PWK.js +540 -0
- package/dist/chunk-ME3SIZZU.js +581 -0
- package/dist/chunk-TQOBJMEK.js +17 -0
- package/dist/{chunk-T3T4EBWY.js → chunk-UH75UVM2.js} +6 -2
- package/dist/chunk-UW7VQ3S6.js +148 -0
- package/dist/chunk-XE4LLC7Z.js +1067 -0
- package/dist/chunk-ZAW6F3YT.js +172 -0
- package/dist/index.cjs +735 -25
- package/dist/index.d.cts +373 -3
- package/dist/index.d.ts +373 -3
- package/dist/index.js +59 -3
- package/dist/live/client.cjs +173 -0
- package/dist/live/client.d.cts +132 -0
- package/dist/live/client.d.ts +132 -0
- package/dist/live/client.js +9 -0
- package/dist/native/index.d.cts +5 -2
- package/dist/native/index.d.ts +5 -2
- package/dist/native/index.js +15 -11
- package/dist/{organicParticlesShaders-DIva0vBO.d.ts → organicParticlesShaders-seZq7jYX.d.cts} +1 -421
- package/dist/{organicParticlesShaders-DIva0vBO.d.cts → organicParticlesShaders-seZq7jYX.d.ts} +1 -421
- package/dist/particlesConfig-0YbdPOdY.d.cts +223 -0
- package/dist/particlesConfig-0YbdPOdY.d.ts +223 -0
- package/dist/react/conversation.cjs +789 -0
- package/dist/react/conversation.d.cts +134 -0
- package/dist/react/conversation.d.ts +134 -0
- package/dist/react/conversation.js +13 -0
- package/dist/react/index.cjs +374 -36
- package/dist/react/index.d.cts +10 -141
- package/dist/react/index.d.ts +10 -141
- package/dist/react/index.js +23 -770
- package/dist/react/visuals.cjs +1048 -0
- package/dist/react/visuals.d.cts +70 -0
- package/dist/react/visuals.d.ts +70 -0
- package/dist/react/visuals.js +10 -0
- package/dist/route/agent.cjs +1038 -85
- package/dist/route/agent.js +3 -3
- package/dist/route/audio-tags.cjs +1038 -85
- package/dist/route/audio-tags.js +3 -3
- package/dist/route/index.cjs +1042 -85
- package/dist/route/index.d.cts +19 -3
- package/dist/route/index.d.ts +19 -3
- package/dist/route/index.js +3 -3
- package/dist/route/music.cjs +1038 -85
- package/dist/route/music.js +3 -3
- package/dist/route/op.cjs +2118 -0
- package/dist/route/op.d.cts +43 -0
- package/dist/route/op.d.ts +43 -0
- package/dist/route/op.js +27 -0
- package/dist/route/signed-url.cjs +1038 -85
- package/dist/route/signed-url.js +3 -3
- package/dist/route/tts-preview.cjs +1038 -85
- package/dist/route/tts-preview.d.cts +6 -4
- package/dist/route/tts-preview.d.ts +6 -4
- package/dist/route/tts-preview.js +3 -3
- package/dist/server.cjs +1038 -85
- package/dist/server.d.cts +40 -8
- package/dist/server.d.ts +40 -8
- package/dist/server.js +2 -2
- package/dist/types-Bfhu-aQH.d.cts +199 -0
- package/dist/types-Bfhu-aQH.d.ts +199 -0
- package/dist/{types-W9y6eMj3.d.ts → types-CadjTXNH.d.cts} +193 -12
- package/dist/{types-W9y6eMj3.d.cts → types-CadjTXNH.d.ts} +193 -12
- package/package.json +21 -1
- package/dist/chunk-B4JC3DK2.js +0 -529
- package/dist/chunk-O362EJQR.js +0 -524
package/dist/react/index.js
CHANGED
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
import {
|
|
2
|
+
appendChatQuery
|
|
3
|
+
} from "../chunk-TQOBJMEK.js";
|
|
4
|
+
import {
|
|
5
|
+
ShogoVoiceProvider,
|
|
6
|
+
useLiveVoiceConversation,
|
|
7
|
+
useVoiceConversation
|
|
8
|
+
} from "../chunk-ME3SIZZU.js";
|
|
9
|
+
import "../chunk-ZAW6F3YT.js";
|
|
10
|
+
import {
|
|
11
|
+
OrganicParticles,
|
|
12
|
+
OrganicSphere
|
|
13
|
+
} from "../chunk-KMSL5PWK.js";
|
|
1
14
|
import {
|
|
2
15
|
DEFAULT_ORGANIC_PARTICLES_CONFIG,
|
|
3
16
|
DEFAULT_ORGANIC_SPHERE_CONFIG,
|
|
@@ -6,239 +19,11 @@ import {
|
|
|
6
19
|
ORGANIC_SPHERE_FRAGMENT_SHADER,
|
|
7
20
|
ORGANIC_SPHERE_VERTEX_SHADER,
|
|
8
21
|
PERLIN_4D,
|
|
9
|
-
appendChatQuery,
|
|
10
|
-
appendTranscriptLine,
|
|
11
|
-
buildSessionPayload,
|
|
12
|
-
createMemoryAddTool,
|
|
13
|
-
createMemoryContextInjector,
|
|
14
|
-
createPostJson,
|
|
15
|
-
createTranscriptDisconnectHandler,
|
|
16
|
-
fetchSignedUrl,
|
|
17
22
|
resolveOrganicParticlesConfig,
|
|
18
|
-
resolveOrganicSphereConfig
|
|
19
|
-
|
|
20
|
-
} from "../chunk-S3S2RNO6.js";
|
|
23
|
+
resolveOrganicSphereConfig
|
|
24
|
+
} from "../chunk-BI6SL35K.js";
|
|
21
25
|
import "../chunk-Q3TJAJ54.js";
|
|
22
26
|
|
|
23
|
-
// src/react/useVoiceConversation.ts
|
|
24
|
-
import { useCallback, useEffect, useRef, useState } from "react";
|
|
25
|
-
import { useConversation } from "@elevenlabs/react";
|
|
26
|
-
function useVoiceConversation(options) {
|
|
27
|
-
const {
|
|
28
|
-
characterName,
|
|
29
|
-
signedUrlPath = "/api/voice/signed-url",
|
|
30
|
-
memoryAddPath = "/api/memory/add",
|
|
31
|
-
memoryRetrievePath = "/api/memory/retrieve",
|
|
32
|
-
transcriptIngestPath = "/api/memory/ingest",
|
|
33
|
-
autoInjectMemory = true,
|
|
34
|
-
includeMemoryTool = true,
|
|
35
|
-
clientTools = {},
|
|
36
|
-
onTranscript,
|
|
37
|
-
shogoApiKey,
|
|
38
|
-
projectId,
|
|
39
|
-
agentName,
|
|
40
|
-
fetchCredentials = shogoApiKey ? "omit" : "same-origin",
|
|
41
|
-
onError,
|
|
42
|
-
onMessage,
|
|
43
|
-
conversationId: optionConversationId,
|
|
44
|
-
dynamicVariables
|
|
45
|
-
} = options;
|
|
46
|
-
const authHeaders = useCallback(() => {
|
|
47
|
-
return shogoApiKey ? { authorization: `Bearer ${shogoApiKey}` } : {};
|
|
48
|
-
}, [shogoApiKey]);
|
|
49
|
-
const resolvedSignedUrlPath = withProjectQuery(signedUrlPath, { projectId, agentName });
|
|
50
|
-
const transcriptRef = useRef([]);
|
|
51
|
-
const lastInjectedRef = useRef("");
|
|
52
|
-
const weStartedSessionRef = useRef(false);
|
|
53
|
-
const [convaiConversationId, setConvaiConversationId] = useState(null);
|
|
54
|
-
const isRestartingRef = useRef(false);
|
|
55
|
-
const conversationRef = useRef(null);
|
|
56
|
-
const postJson = useCallback(
|
|
57
|
-
createPostJson({ authHeaders, fetchCredentials }),
|
|
58
|
-
[fetchCredentials, authHeaders]
|
|
59
|
-
);
|
|
60
|
-
const injectMemoryContext = useCallback(
|
|
61
|
-
createMemoryContextInjector({
|
|
62
|
-
postJson,
|
|
63
|
-
memoryRetrievePath,
|
|
64
|
-
conversationRef,
|
|
65
|
-
enabled: autoInjectMemory,
|
|
66
|
-
lastInjectedRef
|
|
67
|
-
}),
|
|
68
|
-
[autoInjectMemory, memoryRetrievePath, postJson]
|
|
69
|
-
);
|
|
70
|
-
const handleTranscriptOnDisconnect = useCallback(
|
|
71
|
-
createTranscriptDisconnectHandler({
|
|
72
|
-
isRestartingRef,
|
|
73
|
-
weStartedSessionRef,
|
|
74
|
-
transcriptRef,
|
|
75
|
-
onTranscript,
|
|
76
|
-
transcriptIngestPath,
|
|
77
|
-
postJson
|
|
78
|
-
}),
|
|
79
|
-
[onTranscript, postJson, transcriptIngestPath]
|
|
80
|
-
);
|
|
81
|
-
const builtInTools = includeMemoryTool ? { add_memory: createMemoryAddTool({ postJson, memoryAddPath }) } : {};
|
|
82
|
-
const mergedClientTools = { ...builtInTools, ...clientTools };
|
|
83
|
-
const conversation = useConversation({
|
|
84
|
-
clientTools: mergedClientTools,
|
|
85
|
-
onConnect: (info) => {
|
|
86
|
-
const id = info?.conversationId;
|
|
87
|
-
if (typeof id === "string" && id.length > 0) {
|
|
88
|
-
setConvaiConversationId(id);
|
|
89
|
-
}
|
|
90
|
-
if (!isRestartingRef.current) {
|
|
91
|
-
transcriptRef.current = [];
|
|
92
|
-
lastInjectedRef.current = "";
|
|
93
|
-
}
|
|
94
|
-
},
|
|
95
|
-
onDisconnect: () => {
|
|
96
|
-
handleTranscriptOnDisconnect();
|
|
97
|
-
if (!isRestartingRef.current) {
|
|
98
|
-
setConvaiConversationId(null);
|
|
99
|
-
}
|
|
100
|
-
},
|
|
101
|
-
onError: (e) => {
|
|
102
|
-
onError?.(e);
|
|
103
|
-
},
|
|
104
|
-
onMessage: (m) => {
|
|
105
|
-
const msg = m;
|
|
106
|
-
if (!msg?.message || !msg?.source) return;
|
|
107
|
-
appendTranscriptLine(msg, { transcriptRef, weStartedSessionRef });
|
|
108
|
-
onMessage?.({ source: msg.source, message: msg.message });
|
|
109
|
-
if (autoInjectMemory && msg.source === "user" && msg.message.trim().length >= 3 && weStartedSessionRef.current) {
|
|
110
|
-
void injectMemoryContext(msg.message);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
});
|
|
114
|
-
const { status, isSpeaking, isListening, isMuted, setMuted, startSession, endSession } = conversation;
|
|
115
|
-
conversationRef.current = conversation;
|
|
116
|
-
useEffect(() => {
|
|
117
|
-
const onHide = () => {
|
|
118
|
-
if (!weStartedSessionRef.current || transcriptRef.current.length === 0) return;
|
|
119
|
-
const transcript = transcriptRef.current.join("\n").trim();
|
|
120
|
-
transcriptRef.current = [];
|
|
121
|
-
if (transcript.length < 20) return;
|
|
122
|
-
try {
|
|
123
|
-
const blob = new Blob([JSON.stringify({ transcript })], { type: "application/json" });
|
|
124
|
-
navigator.sendBeacon(transcriptIngestPath, blob);
|
|
125
|
-
} catch {
|
|
126
|
-
}
|
|
127
|
-
};
|
|
128
|
-
window.addEventListener("pagehide", onHide);
|
|
129
|
-
return () => window.removeEventListener("pagehide", onHide);
|
|
130
|
-
}, [transcriptIngestPath]);
|
|
131
|
-
const startInternal = useCallback(
|
|
132
|
-
async (opts) => {
|
|
133
|
-
if (status === "connected" || status === "connecting") {
|
|
134
|
-
try {
|
|
135
|
-
endSession();
|
|
136
|
-
await new Promise((r) => setTimeout(r, 120));
|
|
137
|
-
} catch {
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
141
|
-
const data = await fetchSignedUrl({
|
|
142
|
-
path: resolvedSignedUrlPath,
|
|
143
|
-
fetchCredentials,
|
|
144
|
-
authHeaders
|
|
145
|
-
});
|
|
146
|
-
const ctx = data.userContext || "No prior memories yet.";
|
|
147
|
-
weStartedSessionRef.current = true;
|
|
148
|
-
const sessionPayload = buildSessionPayload({
|
|
149
|
-
signedUrl: data.signedUrl,
|
|
150
|
-
characterName,
|
|
151
|
-
userContext: ctx,
|
|
152
|
-
agentPromptOverride: data.agentPromptOverride,
|
|
153
|
-
suppressFirstMessage: opts?.suppressFirstMessage,
|
|
154
|
-
conversationId: optionConversationId,
|
|
155
|
-
dynamicVariables
|
|
156
|
-
});
|
|
157
|
-
await startSession(sessionPayload);
|
|
158
|
-
},
|
|
159
|
-
[
|
|
160
|
-
status,
|
|
161
|
-
endSession,
|
|
162
|
-
resolvedSignedUrlPath,
|
|
163
|
-
fetchCredentials,
|
|
164
|
-
dynamicVariables,
|
|
165
|
-
startSession,
|
|
166
|
-
characterName,
|
|
167
|
-
authHeaders,
|
|
168
|
-
optionConversationId
|
|
169
|
-
]
|
|
170
|
-
);
|
|
171
|
-
const start = useCallback(
|
|
172
|
-
async (options2) => {
|
|
173
|
-
await startInternal(options2);
|
|
174
|
-
},
|
|
175
|
-
[startInternal]
|
|
176
|
-
);
|
|
177
|
-
const end = useCallback(() => {
|
|
178
|
-
endSession();
|
|
179
|
-
}, [endSession]);
|
|
180
|
-
const restart = useCallback(
|
|
181
|
-
async (options2) => {
|
|
182
|
-
const suppress = options2?.suppressFirstMessage ?? true;
|
|
183
|
-
isRestartingRef.current = true;
|
|
184
|
-
try {
|
|
185
|
-
try {
|
|
186
|
-
endSession();
|
|
187
|
-
} catch {
|
|
188
|
-
}
|
|
189
|
-
await new Promise((r) => setTimeout(r, 120));
|
|
190
|
-
await startInternal({ suppressFirstMessage: suppress });
|
|
191
|
-
} finally {
|
|
192
|
-
isRestartingRef.current = false;
|
|
193
|
-
}
|
|
194
|
-
},
|
|
195
|
-
[endSession, startInternal]
|
|
196
|
-
);
|
|
197
|
-
const sendContextualUpdate = useCallback((text) => {
|
|
198
|
-
conversationRef.current?.sendContextualUpdate(text);
|
|
199
|
-
}, []);
|
|
200
|
-
const sendUserMessage = useCallback((text) => {
|
|
201
|
-
const ref = conversationRef.current;
|
|
202
|
-
if (!ref) return;
|
|
203
|
-
if (typeof ref.sendUserMessage === "function") {
|
|
204
|
-
ref.sendUserMessage(text);
|
|
205
|
-
return;
|
|
206
|
-
}
|
|
207
|
-
ref.sendContextualUpdate(text);
|
|
208
|
-
try {
|
|
209
|
-
ref.sendUserActivity?.();
|
|
210
|
-
} catch {
|
|
211
|
-
}
|
|
212
|
-
}, []);
|
|
213
|
-
const sendUserActivity = useCallback(() => {
|
|
214
|
-
conversationRef.current?.sendUserActivity?.();
|
|
215
|
-
}, []);
|
|
216
|
-
const getOutputByteFrequencyData = useCallback(() => {
|
|
217
|
-
try {
|
|
218
|
-
const fn = conversation.getOutputByteFrequencyData;
|
|
219
|
-
return fn ? fn() : null;
|
|
220
|
-
} catch {
|
|
221
|
-
return null;
|
|
222
|
-
}
|
|
223
|
-
}, [conversation]);
|
|
224
|
-
return {
|
|
225
|
-
start,
|
|
226
|
-
end,
|
|
227
|
-
restart,
|
|
228
|
-
status,
|
|
229
|
-
isSpeaking,
|
|
230
|
-
isListening,
|
|
231
|
-
isMuted,
|
|
232
|
-
setMuted,
|
|
233
|
-
getOutputByteFrequencyData,
|
|
234
|
-
sendContextualUpdate,
|
|
235
|
-
sendUserMessage,
|
|
236
|
-
sendUserActivity,
|
|
237
|
-
conversationId: optionConversationId ?? convaiConversationId,
|
|
238
|
-
convaiConversationId
|
|
239
|
-
};
|
|
240
|
-
}
|
|
241
|
-
|
|
242
27
|
// src/react/useShogoVoice.ts
|
|
243
28
|
function useShogoVoice(opts = {}) {
|
|
244
29
|
return useVoiceConversation({
|
|
@@ -250,7 +35,7 @@ function useShogoVoice(opts = {}) {
|
|
|
250
35
|
}
|
|
251
36
|
|
|
252
37
|
// src/react/useChatConversation.ts
|
|
253
|
-
import { useCallback
|
|
38
|
+
import { useCallback, useMemo, useRef } from "react";
|
|
254
39
|
import { useChat } from "@ai-sdk/react";
|
|
255
40
|
import { DefaultChatTransport } from "ai";
|
|
256
41
|
var DEFAULT_API_PATH = "/api/chat/turn";
|
|
@@ -302,9 +87,9 @@ function useChatConversation(options = {}) {
|
|
|
302
87
|
}),
|
|
303
88
|
[resolvedApi, fetchCredentials, headers, body]
|
|
304
89
|
);
|
|
305
|
-
const toolsRef =
|
|
90
|
+
const toolsRef = useRef(clientTools);
|
|
306
91
|
toolsRef.current = clientTools;
|
|
307
|
-
const chatRef =
|
|
92
|
+
const chatRef = useRef(null);
|
|
308
93
|
const resolvedId = id ?? (conversationId ? `shogo-chat:${conversationId}` : DEFAULT_CHAT_ID);
|
|
309
94
|
const chat = useChat({
|
|
310
95
|
id: resolvedId,
|
|
@@ -346,17 +131,17 @@ function useChatConversation(options = {}) {
|
|
|
346
131
|
}
|
|
347
132
|
});
|
|
348
133
|
chatRef.current = chat;
|
|
349
|
-
const sendMessage =
|
|
134
|
+
const sendMessage = useCallback(
|
|
350
135
|
async (text) => {
|
|
351
136
|
if (!text.trim()) return;
|
|
352
137
|
await chatRef.current?.sendMessage({ text });
|
|
353
138
|
},
|
|
354
139
|
[]
|
|
355
140
|
);
|
|
356
|
-
const setMessages =
|
|
141
|
+
const setMessages = useCallback((messages) => {
|
|
357
142
|
chatRef.current?.setMessages?.(messages);
|
|
358
143
|
}, []);
|
|
359
|
-
const appendAssistantMessage =
|
|
144
|
+
const appendAssistantMessage = useCallback((text) => {
|
|
360
145
|
const next = {
|
|
361
146
|
id: syntheticId("synthetic-assistant"),
|
|
362
147
|
role: "assistant",
|
|
@@ -367,7 +152,7 @@ function useChatConversation(options = {}) {
|
|
|
367
152
|
const nextList = [...current.messages, next];
|
|
368
153
|
current.setMessages?.(nextList);
|
|
369
154
|
}, []);
|
|
370
|
-
const appendUserMessage =
|
|
155
|
+
const appendUserMessage = useCallback((text) => {
|
|
371
156
|
const next = {
|
|
372
157
|
id: syntheticId("synthetic-user"),
|
|
373
158
|
role: "user",
|
|
@@ -398,539 +183,6 @@ function useShogoChat(opts = {}) {
|
|
|
398
183
|
...opts
|
|
399
184
|
});
|
|
400
185
|
}
|
|
401
|
-
|
|
402
|
-
// src/react/ShogoVoiceProvider.tsx
|
|
403
|
-
import { ConversationProvider as ElevenLabsConversationProvider } from "@elevenlabs/react";
|
|
404
|
-
import { jsx } from "react/jsx-runtime";
|
|
405
|
-
function ShogoVoiceProvider(props) {
|
|
406
|
-
return /* @__PURE__ */ jsx(ElevenLabsConversationProvider, { children: props.children });
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
// src/react/OrganicSphere.tsx
|
|
410
|
-
import { useEffect as useEffect2, useMemo as useMemo2, useRef as useRef3 } from "react";
|
|
411
|
-
import * as THREE from "three";
|
|
412
|
-
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
413
|
-
function seededUnit(seed, salt) {
|
|
414
|
-
const s = Math.sin((seed + salt * 7919) * 12.9898 + salt * 78.233) * 43758.5453;
|
|
415
|
-
return s - Math.floor(s);
|
|
416
|
-
}
|
|
417
|
-
function OrganicSphere({
|
|
418
|
-
getFrequencyData,
|
|
419
|
-
active = true,
|
|
420
|
-
config: configProp,
|
|
421
|
-
lightAColor,
|
|
422
|
-
lightBColor,
|
|
423
|
-
rimColor,
|
|
424
|
-
rimThreshold,
|
|
425
|
-
rimPower,
|
|
426
|
-
backgroundColor,
|
|
427
|
-
subdivisions,
|
|
428
|
-
maxPixelRatio,
|
|
429
|
-
className,
|
|
430
|
-
style
|
|
431
|
-
}) {
|
|
432
|
-
const containerRef = useRef3(null);
|
|
433
|
-
const resolvedConfig = useMemo2(() => {
|
|
434
|
-
const base = resolveOrganicSphereConfig(configProp);
|
|
435
|
-
const overrides = {};
|
|
436
|
-
if (lightAColor !== void 0) overrides.lightAColor = lightAColor;
|
|
437
|
-
if (lightBColor !== void 0) overrides.lightBColor = lightBColor;
|
|
438
|
-
if (rimColor !== void 0) overrides.rimColor = rimColor;
|
|
439
|
-
if (rimThreshold !== void 0) overrides.rimThreshold = rimThreshold;
|
|
440
|
-
if (rimPower !== void 0) overrides.rimPower = rimPower;
|
|
441
|
-
if (backgroundColor !== void 0) overrides.backgroundColor = backgroundColor;
|
|
442
|
-
if (subdivisions !== void 0) overrides.subdivisions = subdivisions;
|
|
443
|
-
if (maxPixelRatio !== void 0) overrides.maxPixelRatio = maxPixelRatio;
|
|
444
|
-
return { ...base, ...overrides };
|
|
445
|
-
}, [
|
|
446
|
-
configProp,
|
|
447
|
-
lightAColor,
|
|
448
|
-
lightBColor,
|
|
449
|
-
rimColor,
|
|
450
|
-
rimThreshold,
|
|
451
|
-
rimPower,
|
|
452
|
-
backgroundColor,
|
|
453
|
-
subdivisions,
|
|
454
|
-
maxPixelRatio
|
|
455
|
-
]);
|
|
456
|
-
const configRef = useRef3(resolvedConfig);
|
|
457
|
-
useEffect2(() => {
|
|
458
|
-
configRef.current = resolvedConfig;
|
|
459
|
-
}, [resolvedConfig]);
|
|
460
|
-
const getFrequencyDataRef = useRef3(getFrequencyData);
|
|
461
|
-
const activeRef = useRef3(active);
|
|
462
|
-
useEffect2(() => {
|
|
463
|
-
getFrequencyDataRef.current = getFrequencyData;
|
|
464
|
-
}, [getFrequencyData]);
|
|
465
|
-
useEffect2(() => {
|
|
466
|
-
activeRef.current = active;
|
|
467
|
-
}, [active]);
|
|
468
|
-
const initSubdivisions = resolvedConfig.subdivisions;
|
|
469
|
-
const initMaxPixelRatio = resolvedConfig.maxPixelRatio;
|
|
470
|
-
const initBackgroundColor = resolvedConfig.backgroundColor;
|
|
471
|
-
useEffect2(() => {
|
|
472
|
-
const container = containerRef.current;
|
|
473
|
-
if (!container) return;
|
|
474
|
-
const cfg0 = configRef.current;
|
|
475
|
-
const width = container.clientWidth || 1;
|
|
476
|
-
const height = container.clientHeight || 1;
|
|
477
|
-
const pixelRatio = Math.min(
|
|
478
|
-
initMaxPixelRatio ?? (typeof window !== "undefined" ? window.devicePixelRatio : 1),
|
|
479
|
-
2
|
|
480
|
-
);
|
|
481
|
-
const scene = new THREE.Scene();
|
|
482
|
-
if (initBackgroundColor) scene.background = new THREE.Color(initBackgroundColor);
|
|
483
|
-
const camera = new THREE.PerspectiveCamera(cfg0.fov, width / height, 0.1, 100);
|
|
484
|
-
camera.position.set(0, 0, cfg0.cameraZ);
|
|
485
|
-
scene.add(camera);
|
|
486
|
-
const renderer = new THREE.WebGLRenderer({
|
|
487
|
-
antialias: true,
|
|
488
|
-
alpha: initBackgroundColor === null,
|
|
489
|
-
powerPreference: "high-performance"
|
|
490
|
-
});
|
|
491
|
-
renderer.setSize(width, height, false);
|
|
492
|
-
renderer.setPixelRatio(pixelRatio);
|
|
493
|
-
renderer.setClearColor(0, initBackgroundColor === null ? 0 : 1);
|
|
494
|
-
container.appendChild(renderer.domElement);
|
|
495
|
-
renderer.domElement.style.display = "block";
|
|
496
|
-
renderer.domElement.style.width = "100%";
|
|
497
|
-
renderer.domElement.style.height = "100%";
|
|
498
|
-
const geometry = new THREE.SphereGeometry(1, initSubdivisions, initSubdivisions);
|
|
499
|
-
geometry.computeTangents();
|
|
500
|
-
const lightAPos = new THREE.Vector3().setFromSpherical(
|
|
501
|
-
new THREE.Spherical(1, 0.615, 2.049)
|
|
502
|
-
);
|
|
503
|
-
const lightBPos = new THREE.Vector3().setFromSpherical(
|
|
504
|
-
new THREE.Spherical(1, 2.561, -1.844)
|
|
505
|
-
);
|
|
506
|
-
const lightAColorObj = new THREE.Color(cfg0.lightAColor);
|
|
507
|
-
const lightBColorObj = new THREE.Color(cfg0.lightBColor);
|
|
508
|
-
const rimColorObj = new THREE.Color(cfg0.rimColor ?? cfg0.lightBColor);
|
|
509
|
-
const material = new THREE.ShaderMaterial({
|
|
510
|
-
uniforms: {
|
|
511
|
-
uLightAColor: { value: lightAColorObj },
|
|
512
|
-
uLightAPosition: { value: lightAPos },
|
|
513
|
-
uLightAIntensity: { value: cfg0.lightAIntensity },
|
|
514
|
-
uLightBColor: { value: lightBColorObj },
|
|
515
|
-
uLightBPosition: { value: lightBPos },
|
|
516
|
-
uLightBIntensity: { value: cfg0.lightBIntensity },
|
|
517
|
-
uSubdivision: {
|
|
518
|
-
value: new THREE.Vector2(initSubdivisions, initSubdivisions)
|
|
519
|
-
},
|
|
520
|
-
uOffset: { value: new THREE.Vector3() },
|
|
521
|
-
uDistortionFrequency: { value: cfg0.distortionFrequency },
|
|
522
|
-
uDistortionStrength: { value: cfg0.high.idle },
|
|
523
|
-
uDisplacementFrequency: { value: cfg0.displacementFrequency },
|
|
524
|
-
uDisplacementStrength: { value: cfg0.volume.idle },
|
|
525
|
-
uFresnelOffset: { value: cfg0.fresnelOffset },
|
|
526
|
-
uFresnelMultiplier: { value: cfg0.medium.idle },
|
|
527
|
-
uFresnelPower: { value: cfg0.fresnelPower },
|
|
528
|
-
uRimColor: { value: rimColorObj },
|
|
529
|
-
uRimThreshold: { value: cfg0.rimThreshold },
|
|
530
|
-
uRimPower: { value: cfg0.rimPower },
|
|
531
|
-
uTime: { value: 0 }
|
|
532
|
-
},
|
|
533
|
-
defines: { USE_TANGENT: "" },
|
|
534
|
-
vertexShader: ORGANIC_SPHERE_VERTEX_SHADER,
|
|
535
|
-
fragmentShader: ORGANIC_SPHERE_FRAGMENT_SHADER
|
|
536
|
-
});
|
|
537
|
-
const mesh = new THREE.Mesh(geometry, material);
|
|
538
|
-
scene.add(mesh);
|
|
539
|
-
const seedInitialPhase = (seed) => ({
|
|
540
|
-
phi: seededUnit(seed, 1) * Math.PI,
|
|
541
|
-
theta: seededUnit(seed, 2) * Math.PI * 2
|
|
542
|
-
});
|
|
543
|
-
const initialPhase = seedInitialPhase(cfg0.seed);
|
|
544
|
-
const offsetSpherical = new THREE.Spherical(1, initialPhase.phi, initialPhase.theta);
|
|
545
|
-
const offsetDirection = new THREE.Vector3().setFromSpherical(offsetSpherical);
|
|
546
|
-
const variations = {
|
|
547
|
-
volume: { target: 0, current: cfg0.volume.idle },
|
|
548
|
-
medium: { target: 0, current: cfg0.medium.idle },
|
|
549
|
-
high: { target: 0, current: cfg0.high.idle },
|
|
550
|
-
low: { target: 0, current: cfg0.low.idle }
|
|
551
|
-
};
|
|
552
|
-
const resetAnimationState = (cfg) => {
|
|
553
|
-
material.uniforms.uTime.value = 0;
|
|
554
|
-
material.uniforms.uOffset.value.set(0, 0, 0);
|
|
555
|
-
const phase = seedInitialPhase(cfg.seed);
|
|
556
|
-
offsetSpherical.radius = 1;
|
|
557
|
-
offsetSpherical.phi = phase.phi;
|
|
558
|
-
offsetSpherical.theta = phase.theta;
|
|
559
|
-
variations.volume.current = cfg.volume.idle;
|
|
560
|
-
variations.medium.current = cfg.medium.idle;
|
|
561
|
-
variations.high.current = cfg.high.idle;
|
|
562
|
-
variations.low.current = cfg.low.idle;
|
|
563
|
-
variations.volume.target = cfg.volume.idle;
|
|
564
|
-
variations.medium.target = cfg.medium.idle;
|
|
565
|
-
variations.high.target = cfg.high.idle;
|
|
566
|
-
variations.low.target = cfg.low.idle;
|
|
567
|
-
};
|
|
568
|
-
const LEVEL_COUNT = 8;
|
|
569
|
-
function computeLevels(buf) {
|
|
570
|
-
const bins = Math.floor(buf.length / LEVEL_COUNT);
|
|
571
|
-
const levels = new Array(LEVEL_COUNT).fill(0);
|
|
572
|
-
if (bins <= 0) return levels;
|
|
573
|
-
for (let i = 0; i < LEVEL_COUNT; i++) {
|
|
574
|
-
let sum = 0;
|
|
575
|
-
for (let j = 0; j < bins; j++) sum += buf[i * bins + j];
|
|
576
|
-
levels[i] = sum / bins / 256;
|
|
577
|
-
}
|
|
578
|
-
return levels;
|
|
579
|
-
}
|
|
580
|
-
function bandTarget(reactivity, levels, sourceLevel) {
|
|
581
|
-
if (!levels) return reactivity.idle;
|
|
582
|
-
return Math.max(reactivity.floor, reactivity.floor + sourceLevel * reactivity.gain);
|
|
583
|
-
}
|
|
584
|
-
let rafId = 0;
|
|
585
|
-
let lastTs = performance.now();
|
|
586
|
-
let disposed = false;
|
|
587
|
-
let wasActive = activeRef.current;
|
|
588
|
-
let lastSeed = cfg0.seed;
|
|
589
|
-
const render = () => {
|
|
590
|
-
if (disposed) return;
|
|
591
|
-
const now = performance.now();
|
|
592
|
-
const delta = Math.min(now - lastTs, 100);
|
|
593
|
-
lastTs = now;
|
|
594
|
-
const cfg = configRef.current;
|
|
595
|
-
lightAColorObj.set(cfg.lightAColor);
|
|
596
|
-
lightBColorObj.set(cfg.lightBColor);
|
|
597
|
-
rimColorObj.set(cfg.rimColor ?? cfg.lightBColor);
|
|
598
|
-
material.uniforms.uLightAIntensity.value = cfg.lightAIntensity;
|
|
599
|
-
material.uniforms.uLightBIntensity.value = cfg.lightBIntensity;
|
|
600
|
-
material.uniforms.uDistortionFrequency.value = cfg.distortionFrequency;
|
|
601
|
-
material.uniforms.uDisplacementFrequency.value = cfg.displacementFrequency;
|
|
602
|
-
material.uniforms.uFresnelOffset.value = cfg.fresnelOffset;
|
|
603
|
-
material.uniforms.uFresnelPower.value = cfg.fresnelPower;
|
|
604
|
-
material.uniforms.uRimThreshold.value = cfg.rimThreshold;
|
|
605
|
-
material.uniforms.uRimPower.value = cfg.rimPower;
|
|
606
|
-
if (camera.position.z !== cfg.cameraZ) camera.position.z = cfg.cameraZ;
|
|
607
|
-
if (camera.fov !== cfg.fov) {
|
|
608
|
-
camera.fov = cfg.fov;
|
|
609
|
-
camera.updateProjectionMatrix();
|
|
610
|
-
}
|
|
611
|
-
const isActive = activeRef.current;
|
|
612
|
-
if (isActive && !wasActive || cfg.seed !== lastSeed) {
|
|
613
|
-
resetAnimationState(cfg);
|
|
614
|
-
lastSeed = cfg.seed;
|
|
615
|
-
}
|
|
616
|
-
wasActive = isActive;
|
|
617
|
-
if (isActive) {
|
|
618
|
-
let levels = null;
|
|
619
|
-
if (getFrequencyDataRef.current) {
|
|
620
|
-
try {
|
|
621
|
-
const buf = getFrequencyDataRef.current();
|
|
622
|
-
if (buf && buf.length > 0) levels = computeLevels(buf);
|
|
623
|
-
} catch {
|
|
624
|
-
levels = null;
|
|
625
|
-
}
|
|
626
|
-
}
|
|
627
|
-
const l0 = levels ? levels[0] || 0 : 0;
|
|
628
|
-
const l1 = levels ? levels[1] || 0 : 0;
|
|
629
|
-
const l2 = levels ? levels[2] || 0 : 0;
|
|
630
|
-
const loudest = Math.max(l0, l1, l2);
|
|
631
|
-
const update = (variation, reactivity, sourceLevel) => {
|
|
632
|
-
variation.target = bandTarget(reactivity, levels, sourceLevel);
|
|
633
|
-
const easing = variation.target > variation.current ? reactivity.attack : reactivity.decay;
|
|
634
|
-
variation.current += (variation.target - variation.current) * easing * delta;
|
|
635
|
-
};
|
|
636
|
-
update(variations.volume, cfg.volume, loudest);
|
|
637
|
-
update(variations.medium, cfg.medium, l1);
|
|
638
|
-
update(variations.high, cfg.high, l2);
|
|
639
|
-
update(variations.low, cfg.low, l0);
|
|
640
|
-
const timeFrequency = variations.low.current;
|
|
641
|
-
const elapsed = delta * timeFrequency;
|
|
642
|
-
material.uniforms.uDisplacementStrength.value = variations.volume.current;
|
|
643
|
-
material.uniforms.uDistortionStrength.value = variations.high.current;
|
|
644
|
-
material.uniforms.uFresnelMultiplier.value = variations.medium.current;
|
|
645
|
-
const offsetTime = (material.uniforms.uTime.value + elapsed) * 0.3;
|
|
646
|
-
offsetSpherical.phi = (Math.sin(offsetTime * 1e-3) * Math.sin(offsetTime * 321e-5) * 0.5 + 0.5) * Math.PI;
|
|
647
|
-
offsetSpherical.theta = (Math.sin(offsetTime * 1e-4) * Math.sin(offsetTime * 321e-6) * 0.5 + 0.5) * Math.PI * 2;
|
|
648
|
-
offsetDirection.setFromSpherical(offsetSpherical);
|
|
649
|
-
offsetDirection.multiplyScalar(timeFrequency * 2);
|
|
650
|
-
material.uniforms.uOffset.value.add(offsetDirection);
|
|
651
|
-
material.uniforms.uTime.value += elapsed;
|
|
652
|
-
}
|
|
653
|
-
renderer.render(scene, camera);
|
|
654
|
-
rafId = requestAnimationFrame(render);
|
|
655
|
-
};
|
|
656
|
-
rafId = requestAnimationFrame(render);
|
|
657
|
-
const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
658
|
-
const w = container.clientWidth || 1;
|
|
659
|
-
const h = container.clientHeight || 1;
|
|
660
|
-
camera.aspect = w / h;
|
|
661
|
-
camera.updateProjectionMatrix();
|
|
662
|
-
renderer.setSize(w, h, false);
|
|
663
|
-
}) : null;
|
|
664
|
-
resizeObserver?.observe(container);
|
|
665
|
-
return () => {
|
|
666
|
-
disposed = true;
|
|
667
|
-
cancelAnimationFrame(rafId);
|
|
668
|
-
resizeObserver?.disconnect();
|
|
669
|
-
geometry.dispose();
|
|
670
|
-
material.dispose();
|
|
671
|
-
renderer.dispose();
|
|
672
|
-
if (renderer.domElement.parentNode === container) {
|
|
673
|
-
container.removeChild(renderer.domElement);
|
|
674
|
-
}
|
|
675
|
-
};
|
|
676
|
-
}, [initSubdivisions, initMaxPixelRatio, initBackgroundColor]);
|
|
677
|
-
return /* @__PURE__ */ jsx2("div", { ref: containerRef, className, style });
|
|
678
|
-
}
|
|
679
|
-
|
|
680
|
-
// src/react/OrganicParticles.tsx
|
|
681
|
-
import { useEffect as useEffect3, useMemo as useMemo3, useRef as useRef4 } from "react";
|
|
682
|
-
import * as THREE2 from "three";
|
|
683
|
-
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
684
|
-
function seededUnit2(seed, salt) {
|
|
685
|
-
const s = Math.sin((seed + salt * 7919) * 12.9898 + salt * 78.233) * 43758.5453;
|
|
686
|
-
return s - Math.floor(s);
|
|
687
|
-
}
|
|
688
|
-
function buildParticleAttributes(count, innerRadius, outerRadius, seed) {
|
|
689
|
-
const positions = new Float32Array(count * 3);
|
|
690
|
-
const seeds = new Float32Array(count);
|
|
691
|
-
for (let i = 0; i < count; i++) {
|
|
692
|
-
const u = seededUnit2(seed, i * 4 + 1);
|
|
693
|
-
const v = seededUnit2(seed, i * 4 + 2);
|
|
694
|
-
const w = seededUnit2(seed, i * 4 + 3);
|
|
695
|
-
const s = seededUnit2(seed, i * 4 + 4);
|
|
696
|
-
const theta = v * Math.PI * 2;
|
|
697
|
-
const phi = Math.acos(2 * w - 1);
|
|
698
|
-
const r = innerRadius + u * Math.max(0, outerRadius - innerRadius);
|
|
699
|
-
const sinPhi = Math.sin(phi);
|
|
700
|
-
positions[i * 3 + 0] = r * sinPhi * Math.cos(theta);
|
|
701
|
-
positions[i * 3 + 1] = r * sinPhi * Math.sin(theta);
|
|
702
|
-
positions[i * 3 + 2] = r * Math.cos(phi);
|
|
703
|
-
seeds[i] = s;
|
|
704
|
-
}
|
|
705
|
-
return { positions, seeds };
|
|
706
|
-
}
|
|
707
|
-
function OrganicParticles({
|
|
708
|
-
getFrequencyData,
|
|
709
|
-
active = true,
|
|
710
|
-
config: configProp,
|
|
711
|
-
className,
|
|
712
|
-
style
|
|
713
|
-
}) {
|
|
714
|
-
const containerRef = useRef4(null);
|
|
715
|
-
const resolvedConfig = useMemo3(
|
|
716
|
-
() => resolveOrganicParticlesConfig(configProp),
|
|
717
|
-
[configProp]
|
|
718
|
-
);
|
|
719
|
-
const configRef = useRef4(resolvedConfig);
|
|
720
|
-
useEffect3(() => {
|
|
721
|
-
configRef.current = resolvedConfig;
|
|
722
|
-
}, [resolvedConfig]);
|
|
723
|
-
const getFrequencyDataRef = useRef4(getFrequencyData);
|
|
724
|
-
const activeRef = useRef4(active);
|
|
725
|
-
useEffect3(() => {
|
|
726
|
-
getFrequencyDataRef.current = getFrequencyData;
|
|
727
|
-
}, [getFrequencyData]);
|
|
728
|
-
useEffect3(() => {
|
|
729
|
-
activeRef.current = active;
|
|
730
|
-
}, [active]);
|
|
731
|
-
const initCount = resolvedConfig.count;
|
|
732
|
-
const initInnerRadius = resolvedConfig.innerRadius;
|
|
733
|
-
const initOuterRadius = resolvedConfig.outerRadius;
|
|
734
|
-
const initSeed = resolvedConfig.seed;
|
|
735
|
-
const initMaxPixelRatio = resolvedConfig.maxPixelRatio;
|
|
736
|
-
const initBackgroundColor = resolvedConfig.backgroundColor;
|
|
737
|
-
useEffect3(() => {
|
|
738
|
-
const container = containerRef.current;
|
|
739
|
-
if (!container) return;
|
|
740
|
-
const cfg0 = configRef.current;
|
|
741
|
-
const width = container.clientWidth || 1;
|
|
742
|
-
const height = container.clientHeight || 1;
|
|
743
|
-
const pixelRatio = Math.min(
|
|
744
|
-
initMaxPixelRatio ?? (typeof window !== "undefined" ? window.devicePixelRatio : 1),
|
|
745
|
-
2
|
|
746
|
-
);
|
|
747
|
-
const scene = new THREE2.Scene();
|
|
748
|
-
if (initBackgroundColor) scene.background = new THREE2.Color(initBackgroundColor);
|
|
749
|
-
const camera = new THREE2.PerspectiveCamera(cfg0.fov, width / height, 0.1, 100);
|
|
750
|
-
camera.position.set(0, 0, cfg0.cameraZ);
|
|
751
|
-
scene.add(camera);
|
|
752
|
-
const renderer = new THREE2.WebGLRenderer({
|
|
753
|
-
antialias: true,
|
|
754
|
-
alpha: initBackgroundColor === null,
|
|
755
|
-
powerPreference: "high-performance"
|
|
756
|
-
});
|
|
757
|
-
renderer.setSize(width, height, false);
|
|
758
|
-
renderer.setPixelRatio(pixelRatio);
|
|
759
|
-
renderer.setClearColor(0, initBackgroundColor === null ? 0 : 1);
|
|
760
|
-
container.appendChild(renderer.domElement);
|
|
761
|
-
renderer.domElement.style.display = "block";
|
|
762
|
-
renderer.domElement.style.width = "100%";
|
|
763
|
-
renderer.domElement.style.height = "100%";
|
|
764
|
-
const { positions, seeds } = buildParticleAttributes(
|
|
765
|
-
initCount,
|
|
766
|
-
initInnerRadius,
|
|
767
|
-
initOuterRadius,
|
|
768
|
-
initSeed
|
|
769
|
-
);
|
|
770
|
-
const geometry = new THREE2.BufferGeometry();
|
|
771
|
-
geometry.setAttribute("aBasePosition", new THREE2.BufferAttribute(positions, 3));
|
|
772
|
-
geometry.setAttribute("aSeed", new THREE2.BufferAttribute(seeds, 1));
|
|
773
|
-
geometry.setAttribute("position", new THREE2.BufferAttribute(positions, 3));
|
|
774
|
-
const colorCoolObj = new THREE2.Color(cfg0.colorCool);
|
|
775
|
-
const colorHotObj = new THREE2.Color(cfg0.colorHot);
|
|
776
|
-
const material = new THREE2.ShaderMaterial({
|
|
777
|
-
uniforms: {
|
|
778
|
-
uTime: { value: 0 },
|
|
779
|
-
uNoiseFrequency: { value: cfg0.noiseFrequency },
|
|
780
|
-
uNoiseStrength: { value: cfg0.noiseStrength },
|
|
781
|
-
uDisplacement: { value: cfg0.volume.idle },
|
|
782
|
-
uSwirl: { value: cfg0.high.idle },
|
|
783
|
-
uSwirlTimeRate: { value: cfg0.swirlTimeRate },
|
|
784
|
-
uSizeBase: { value: cfg0.sizeBase },
|
|
785
|
-
uSizeAudio: { value: cfg0.medium.idle },
|
|
786
|
-
uPixelRatio: { value: pixelRatio },
|
|
787
|
-
uColorCool: { value: colorCoolObj },
|
|
788
|
-
uColorHot: { value: colorHotObj },
|
|
789
|
-
uOpacity: { value: cfg0.opacity },
|
|
790
|
-
uSoftness: { value: cfg0.softness }
|
|
791
|
-
},
|
|
792
|
-
vertexShader: ORGANIC_PARTICLES_VERTEX_SHADER,
|
|
793
|
-
fragmentShader: ORGANIC_PARTICLES_FRAGMENT_SHADER,
|
|
794
|
-
transparent: true,
|
|
795
|
-
depthWrite: false,
|
|
796
|
-
blending: THREE2.AdditiveBlending
|
|
797
|
-
});
|
|
798
|
-
const points = new THREE2.Points(geometry, material);
|
|
799
|
-
scene.add(points);
|
|
800
|
-
const variations = {
|
|
801
|
-
volume: { target: 0, current: cfg0.volume.idle },
|
|
802
|
-
medium: { target: 0, current: cfg0.medium.idle },
|
|
803
|
-
high: { target: 0, current: cfg0.high.idle },
|
|
804
|
-
low: { target: 0, current: cfg0.low.idle }
|
|
805
|
-
};
|
|
806
|
-
const LEVEL_COUNT = 8;
|
|
807
|
-
function computeLevels(buf) {
|
|
808
|
-
const bins = Math.floor(buf.length / LEVEL_COUNT);
|
|
809
|
-
const levels = new Array(LEVEL_COUNT).fill(0);
|
|
810
|
-
if (bins <= 0) return levels;
|
|
811
|
-
for (let i = 0; i < LEVEL_COUNT; i++) {
|
|
812
|
-
let sum = 0;
|
|
813
|
-
for (let j = 0; j < bins; j++) sum += buf[i * bins + j];
|
|
814
|
-
levels[i] = sum / bins / 256;
|
|
815
|
-
}
|
|
816
|
-
return levels;
|
|
817
|
-
}
|
|
818
|
-
function bandTarget(reactivity, levels, sourceLevel) {
|
|
819
|
-
if (!levels) return reactivity.idle;
|
|
820
|
-
return Math.max(
|
|
821
|
-
reactivity.floor,
|
|
822
|
-
reactivity.floor + sourceLevel * reactivity.gain
|
|
823
|
-
);
|
|
824
|
-
}
|
|
825
|
-
const rotationState = { y: 0 };
|
|
826
|
-
const resetAnimationState = (cfg) => {
|
|
827
|
-
material.uniforms.uTime.value = 0;
|
|
828
|
-
rotationState.y = 0;
|
|
829
|
-
points.rotation.set(0, 0, 0);
|
|
830
|
-
variations.volume.current = cfg.volume.idle;
|
|
831
|
-
variations.medium.current = cfg.medium.idle;
|
|
832
|
-
variations.high.current = cfg.high.idle;
|
|
833
|
-
variations.low.current = cfg.low.idle;
|
|
834
|
-
variations.volume.target = cfg.volume.idle;
|
|
835
|
-
variations.medium.target = cfg.medium.idle;
|
|
836
|
-
variations.high.target = cfg.high.idle;
|
|
837
|
-
variations.low.target = cfg.low.idle;
|
|
838
|
-
};
|
|
839
|
-
let rafId = 0;
|
|
840
|
-
let lastTs = performance.now();
|
|
841
|
-
let disposed = false;
|
|
842
|
-
let wasActive = activeRef.current;
|
|
843
|
-
const render = () => {
|
|
844
|
-
if (disposed) return;
|
|
845
|
-
const now = performance.now();
|
|
846
|
-
const delta = Math.min(now - lastTs, 100);
|
|
847
|
-
lastTs = now;
|
|
848
|
-
const cfg = configRef.current;
|
|
849
|
-
colorCoolObj.set(cfg.colorCool);
|
|
850
|
-
colorHotObj.set(cfg.colorHot);
|
|
851
|
-
material.uniforms.uNoiseFrequency.value = cfg.noiseFrequency;
|
|
852
|
-
material.uniforms.uNoiseStrength.value = cfg.noiseStrength;
|
|
853
|
-
material.uniforms.uSwirlTimeRate.value = cfg.swirlTimeRate;
|
|
854
|
-
material.uniforms.uSizeBase.value = cfg.sizeBase;
|
|
855
|
-
material.uniforms.uOpacity.value = cfg.opacity;
|
|
856
|
-
material.uniforms.uSoftness.value = cfg.softness;
|
|
857
|
-
if (camera.position.z !== cfg.cameraZ) camera.position.z = cfg.cameraZ;
|
|
858
|
-
if (camera.fov !== cfg.fov) {
|
|
859
|
-
camera.fov = cfg.fov;
|
|
860
|
-
camera.updateProjectionMatrix();
|
|
861
|
-
}
|
|
862
|
-
const isActive = activeRef.current;
|
|
863
|
-
if (isActive && !wasActive) {
|
|
864
|
-
resetAnimationState(cfg);
|
|
865
|
-
}
|
|
866
|
-
wasActive = isActive;
|
|
867
|
-
if (isActive) {
|
|
868
|
-
let levels = null;
|
|
869
|
-
if (getFrequencyDataRef.current) {
|
|
870
|
-
try {
|
|
871
|
-
const buf = getFrequencyDataRef.current();
|
|
872
|
-
if (buf && buf.length > 0) levels = computeLevels(buf);
|
|
873
|
-
} catch {
|
|
874
|
-
levels = null;
|
|
875
|
-
}
|
|
876
|
-
}
|
|
877
|
-
const l0 = levels ? levels[0] || 0 : 0;
|
|
878
|
-
const l1 = levels ? levels[1] || 0 : 0;
|
|
879
|
-
const l2 = levels ? levels[2] || 0 : 0;
|
|
880
|
-
const loudest = Math.max(l0, l1, l2);
|
|
881
|
-
const update = (variation, reactivity, sourceLevel) => {
|
|
882
|
-
variation.target = bandTarget(reactivity, levels, sourceLevel);
|
|
883
|
-
const easing = variation.target > variation.current ? reactivity.attack : reactivity.decay;
|
|
884
|
-
variation.current += (variation.target - variation.current) * easing * delta;
|
|
885
|
-
};
|
|
886
|
-
update(variations.volume, cfg.volume, loudest);
|
|
887
|
-
update(variations.medium, cfg.medium, l1);
|
|
888
|
-
update(variations.high, cfg.high, l2);
|
|
889
|
-
update(variations.low, cfg.low, l0);
|
|
890
|
-
const timeFrequency = variations.low.current;
|
|
891
|
-
const elapsed = delta * timeFrequency;
|
|
892
|
-
material.uniforms.uDisplacement.value = variations.volume.current;
|
|
893
|
-
material.uniforms.uSizeAudio.value = variations.medium.current;
|
|
894
|
-
material.uniforms.uSwirl.value = variations.high.current;
|
|
895
|
-
material.uniforms.uTime.value += elapsed;
|
|
896
|
-
rotationState.y += delta * cfg.rotationBias + variations.high.current * delta * 8e-4;
|
|
897
|
-
points.rotation.y = rotationState.y;
|
|
898
|
-
} else {
|
|
899
|
-
material.uniforms.uTime.value += delta * cfg.idleNoiseRate;
|
|
900
|
-
}
|
|
901
|
-
renderer.render(scene, camera);
|
|
902
|
-
rafId = requestAnimationFrame(render);
|
|
903
|
-
};
|
|
904
|
-
rafId = requestAnimationFrame(render);
|
|
905
|
-
const resizeObserver = typeof ResizeObserver !== "undefined" ? new ResizeObserver(() => {
|
|
906
|
-
const w = container.clientWidth || 1;
|
|
907
|
-
const h = container.clientHeight || 1;
|
|
908
|
-
camera.aspect = w / h;
|
|
909
|
-
camera.updateProjectionMatrix();
|
|
910
|
-
renderer.setSize(w, h, false);
|
|
911
|
-
}) : null;
|
|
912
|
-
resizeObserver?.observe(container);
|
|
913
|
-
return () => {
|
|
914
|
-
disposed = true;
|
|
915
|
-
cancelAnimationFrame(rafId);
|
|
916
|
-
resizeObserver?.disconnect();
|
|
917
|
-
geometry.dispose();
|
|
918
|
-
material.dispose();
|
|
919
|
-
renderer.dispose();
|
|
920
|
-
if (renderer.domElement.parentNode === container) {
|
|
921
|
-
container.removeChild(renderer.domElement);
|
|
922
|
-
}
|
|
923
|
-
};
|
|
924
|
-
}, [
|
|
925
|
-
initCount,
|
|
926
|
-
initInnerRadius,
|
|
927
|
-
initOuterRadius,
|
|
928
|
-
initSeed,
|
|
929
|
-
initMaxPixelRatio,
|
|
930
|
-
initBackgroundColor
|
|
931
|
-
]);
|
|
932
|
-
return /* @__PURE__ */ jsx3("div", { ref: containerRef, className, style });
|
|
933
|
-
}
|
|
934
186
|
export {
|
|
935
187
|
DEFAULT_ORGANIC_PARTICLES_CONFIG,
|
|
936
188
|
DEFAULT_ORGANIC_SPHERE_CONFIG,
|
|
@@ -945,6 +197,7 @@ export {
|
|
|
945
197
|
resolveOrganicParticlesConfig,
|
|
946
198
|
resolveOrganicSphereConfig,
|
|
947
199
|
useChatConversation,
|
|
200
|
+
useLiveVoiceConversation,
|
|
948
201
|
useShogoChat,
|
|
949
202
|
useShogoVoice,
|
|
950
203
|
useVoiceConversation
|