@navai/voice-frontend 0.1.1 → 0.1.3
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.en.md +320 -0
- package/README.es.md +320 -0
- package/README.md +320 -126
- package/dist/Orb-B4OSC3XR.js +6 -0
- package/dist/chunk-KBBRQQLK.js +531 -0
- package/dist/index.cjs +966 -2
- package/dist/index.d.cts +104 -1
- package/dist/index.d.ts +104 -1
- package/dist/index.js +417 -2
- package/package.json +5 -2
package/dist/index.cjs
CHANGED
|
@@ -3,6 +3,9 @@ var __defProp = Object.defineProperty;
|
|
|
3
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __esm = (fn, res) => function __init() {
|
|
7
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
8
|
+
};
|
|
6
9
|
var __export = (target, all) => {
|
|
7
10
|
for (var name in all)
|
|
8
11
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -17,15 +20,561 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
17
20
|
};
|
|
18
21
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
22
|
|
|
23
|
+
// src/orb/styles.ts
|
|
24
|
+
function ensureNavaiVoiceOrbStyles() {
|
|
25
|
+
if (typeof document === "undefined") {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
if (document.getElementById(NAVAI_VOICE_ORB_STYLE_ID)) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const style = document.createElement("style");
|
|
32
|
+
style.id = NAVAI_VOICE_ORB_STYLE_ID;
|
|
33
|
+
style.textContent = NAVAI_VOICE_ORB_CSS;
|
|
34
|
+
document.head.appendChild(style);
|
|
35
|
+
}
|
|
36
|
+
function useNavaiVoiceOrbStyles() {
|
|
37
|
+
(0, import_react2.useEffect)(() => {
|
|
38
|
+
ensureNavaiVoiceOrbStyles();
|
|
39
|
+
}, []);
|
|
40
|
+
}
|
|
41
|
+
var import_react2, NAVAI_VOICE_ORB_STYLE_ID, NAVAI_VOICE_ORB_CSS;
|
|
42
|
+
var init_styles = __esm({
|
|
43
|
+
"src/orb/styles.ts"() {
|
|
44
|
+
"use strict";
|
|
45
|
+
import_react2 = require("react");
|
|
46
|
+
NAVAI_VOICE_ORB_STYLE_ID = "navai-voice-orb-styles";
|
|
47
|
+
NAVAI_VOICE_ORB_CSS = `
|
|
48
|
+
.navai-orb-container { position: relative; z-index: 0; width: 100%; height: 100%; }
|
|
49
|
+
.navai-voice-orb-dock { display: grid; justify-items: center; gap: 0.6rem; }
|
|
50
|
+
.navai-voice-orb-dock.is-bottom-right,
|
|
51
|
+
.navai-voice-orb-dock.is-bottom-left { position: fixed; bottom: calc(1rem + env(safe-area-inset-bottom)); z-index: 70; }
|
|
52
|
+
.navai-voice-orb-dock.is-bottom-right { right: calc(1rem + env(safe-area-inset-right)); }
|
|
53
|
+
.navai-voice-orb-dock.is-bottom-left { left: calc(1rem + env(safe-area-inset-left)); }
|
|
54
|
+
.navai-voice-orb-wrap { position: relative; width: clamp(4.2rem, 8vw, 5.5rem); aspect-ratio: 1 / 1; display: grid; place-items: center; }
|
|
55
|
+
.navai-voice-orb-surface { position: absolute; inset: 0; border-radius: 999px; overflow: hidden; transition: transform 180ms ease, filter 180ms ease, opacity 180ms ease; }
|
|
56
|
+
.navai-voice-orb-surface::after { content: ""; position: absolute; inset: 10%; border-radius: inherit; background: radial-gradient(circle at 50% 50%, rgba(255,255,255,0.1), rgba(6,9,20,0)); pointer-events: none; }
|
|
57
|
+
.navai-voice-orb-surface.is-highlighted { transform: scale(1.03); filter: saturate(1.08); }
|
|
58
|
+
.navai-voice-orb-surface .navai-orb-container { border-radius: inherit; overflow: hidden; }
|
|
59
|
+
.navai-voice-orb-surface .navai-orb-container canvas { display: block; width: 100% !important; height: 100% !important; transform: scale(1.08); transform-origin: center; }
|
|
60
|
+
.navai-voice-orb-button-shell { position: relative; z-index: 1; display: grid; place-items: center; width: clamp(2.7rem, 5vw, 3.15rem); height: clamp(2.7rem, 5vw, 3.15rem); border-radius: 999px; border: 1px solid rgba(156,182,255,0.4); background: rgba(10,14,36,0.72); box-shadow: inset 0 0 24px rgba(8,12,31,0.28), 0 10px 22px rgba(4,8,24,0.42); backdrop-filter: blur(8px); }
|
|
61
|
+
.navai-voice-orb-button-shell.is-active { border-color: rgba(255,156,192,0.92); box-shadow: 0 0 0 2px rgba(255,112,160,0.18), inset 0 0 28px rgba(61,14,40,0.3), 0 12px 26px rgba(85,16,49,0.42); }
|
|
62
|
+
.navai-voice-orb-button { display: grid; place-items: center; width: clamp(2.05rem, 4vw, 2.4rem); height: clamp(2.05rem, 4vw, 2.4rem); border-radius: 999px; border: 1px solid rgba(162,193,255,0.58); background: linear-gradient(145deg, rgba(245,249,255,0.98), rgba(223,233,255,0.94)); color: #2154d9; box-shadow: 0 8px 18px rgba(14,26,61,0.34); cursor: pointer; transition: transform 160ms ease, box-shadow 160ms ease, opacity 160ms ease, border-color 160ms ease; }
|
|
63
|
+
.navai-voice-orb-button:hover:not(:disabled) { transform: translateY(-1px) scale(1.02); }
|
|
64
|
+
.navai-voice-orb-button:focus-visible { outline: 2px solid rgba(191,219,254,0.92); outline-offset: 3px; }
|
|
65
|
+
.navai-voice-orb-button.is-active { background: rgba(255,92,132,0.96); color: rgba(255,255,255,0.98); border-color: rgba(255,164,190,0.98); box-shadow: 0 0 0 3px rgba(255,108,154,0.24), 0 10px 24px rgba(96,14,39,0.42); }
|
|
66
|
+
.navai-voice-orb-button.is-connecting { background: linear-gradient(145deg, rgba(255,246,214,0.98), rgba(252,220,128,0.94)); color: #7c4300; border-color: rgba(251,191,36,0.9); }
|
|
67
|
+
.navai-voice-orb-button:disabled { opacity: 0.74; cursor: not-allowed; }
|
|
68
|
+
.navai-voice-orb-status { margin: 0; max-width: min(18rem, 80vw); padding: 0.45rem 0.6rem; border-radius: 0.7rem; border: 1px solid rgba(244,114,182,0.24); background: rgba(6,12,28,0.84); color: rgba(230,240,255,0.96); font-size: 0.74rem; line-height: 1.35; text-align: center; box-shadow: 0 10px 20px rgba(4,8,24,0.24); }
|
|
69
|
+
.navai-voice-orb-status.is-error { border-color: rgba(248,113,113,0.46); background: rgba(69,10,10,0.84); color: rgba(254,202,202,0.98); }
|
|
70
|
+
.navai-voice-orb-live { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }
|
|
71
|
+
.navai-voice-orb-hero { width: min(32rem, 100%); aspect-ratio: 1 / 1; }
|
|
72
|
+
.navai-voice-orb-icon { display: block; }
|
|
73
|
+
.navai-voice-orb-icon.is-pulsing { animation: navai-voice-orb-pulse 1.05s ease-in-out infinite; }
|
|
74
|
+
.navai-voice-orb-spinner { display: block; box-sizing: border-box; border-radius: 999px; border: 2px solid currentColor; border-right-color: transparent; animation: navai-voice-orb-spin 0.72s linear infinite; }
|
|
75
|
+
.navai-voice-orb-dock.is-light .navai-voice-orb-button-shell,
|
|
76
|
+
.navai-voice-orb-hero.is-light { color: #10245e; }
|
|
77
|
+
.navai-voice-orb-dock.is-light .navai-voice-orb-button-shell { border-color: rgba(121,146,220,0.34); background: rgba(244,249,255,0.88); box-shadow: inset 0 0 20px rgba(111,134,183,0.14), 0 10px 22px rgba(86,104,149,0.22); }
|
|
78
|
+
.navai-voice-orb-dock.is-light .navai-voice-orb-button-shell.is-active { border-color: rgba(255,142,188,0.82); box-shadow: 0 0 0 2px rgba(255,130,183,0.18), inset 0 0 24px rgba(255,141,191,0.2), 0 10px 24px rgba(141,81,110,0.24); }
|
|
79
|
+
.navai-voice-orb-dock.is-light .navai-voice-orb-button { border-color: rgba(70,136,246,0.42); background: linear-gradient(145deg, rgba(255,255,255,0.98), rgba(228,238,255,0.95)); color: #1d3d9a; box-shadow: 0 8px 18px rgba(71,85,105,0.18); }
|
|
80
|
+
.navai-voice-orb-dock.is-light .navai-voice-orb-button.is-connecting { background: linear-gradient(145deg, rgba(255,246,214,0.98), rgba(252,220,128,0.94)); color: #7c4300; border-color: rgba(251,191,36,0.9); }
|
|
81
|
+
.navai-voice-orb-dock.is-light .navai-voice-orb-button.is-active { background: rgba(255,92,132,0.96); color: rgba(255,255,255,0.98); border-color: rgba(255,164,190,0.98); box-shadow: 0 0 0 3px rgba(255,108,154,0.24), 0 10px 24px rgba(96,14,39,0.28); }
|
|
82
|
+
.navai-voice-orb-dock.is-light .navai-voice-orb-status { border-color: rgba(59,130,246,0.18); background: rgba(255,255,255,0.92); color: #1f2937; box-shadow: 0 10px 20px rgba(148,163,184,0.18); }
|
|
83
|
+
.navai-voice-orb-dock.is-light .navai-voice-orb-status.is-error { border-color: rgba(248,113,113,0.34); background: rgba(255,241,242,0.96); color: #9f1239; }
|
|
84
|
+
@keyframes navai-voice-orb-pulse { 0% { transform: scale(1); opacity: 1; } 50% { transform: scale(1.08); opacity: 0.78; } 100% { transform: scale(1); opacity: 1; } }
|
|
85
|
+
@keyframes navai-voice-orb-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
|
|
86
|
+
@media (max-width: 640px) {
|
|
87
|
+
.navai-voice-orb-dock.is-bottom-right, .navai-voice-orb-dock.is-bottom-left { bottom: calc(0.8rem + env(safe-area-inset-bottom)); }
|
|
88
|
+
.navai-voice-orb-dock.is-bottom-right { right: calc(0.8rem + env(safe-area-inset-right)); }
|
|
89
|
+
.navai-voice-orb-dock.is-bottom-left { left: calc(0.8rem + env(safe-area-inset-left)); }
|
|
90
|
+
.navai-voice-orb-wrap { width: clamp(3.8rem, 22vw, 4.4rem); }
|
|
91
|
+
.navai-voice-orb-button-shell { width: clamp(2.45rem, 13vw, 2.82rem); height: clamp(2.45rem, 13vw, 2.82rem); }
|
|
92
|
+
.navai-voice-orb-button { width: clamp(1.85rem, 10vw, 2.18rem); height: clamp(1.85rem, 10vw, 2.18rem); }
|
|
93
|
+
}
|
|
94
|
+
`;
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// src/orb/Orb.tsx
|
|
99
|
+
var Orb_exports = {};
|
|
100
|
+
__export(Orb_exports, {
|
|
101
|
+
default: () => Orb
|
|
102
|
+
});
|
|
103
|
+
function Orb({
|
|
104
|
+
hue = 0,
|
|
105
|
+
autoHueShift = true,
|
|
106
|
+
hueShiftMin = 0,
|
|
107
|
+
hueShiftMax = 360,
|
|
108
|
+
hueShiftHalfCycleSeconds = 30,
|
|
109
|
+
hoverIntensity = 0.2,
|
|
110
|
+
rotateOnHover = true,
|
|
111
|
+
forceHoverState = false,
|
|
112
|
+
enablePointerHover = true,
|
|
113
|
+
backgroundColor = "#000000",
|
|
114
|
+
animate = true
|
|
115
|
+
}) {
|
|
116
|
+
useNavaiVoiceOrbStyles();
|
|
117
|
+
const containerRef = (0, import_react3.useRef)(null);
|
|
118
|
+
const hueRef = (0, import_react3.useRef)(hue);
|
|
119
|
+
const autoHueShiftRef = (0, import_react3.useRef)(autoHueShift);
|
|
120
|
+
const hueShiftMinRef = (0, import_react3.useRef)(hueShiftMin);
|
|
121
|
+
const hueShiftMaxRef = (0, import_react3.useRef)(hueShiftMax);
|
|
122
|
+
const hueShiftHalfCycleSecondsRef = (0, import_react3.useRef)(hueShiftHalfCycleSeconds);
|
|
123
|
+
const hoverIntensityRef = (0, import_react3.useRef)(hoverIntensity);
|
|
124
|
+
const rotateOnHoverRef = (0, import_react3.useRef)(rotateOnHover);
|
|
125
|
+
const forceHoverStateRef = (0, import_react3.useRef)(forceHoverState);
|
|
126
|
+
const enablePointerHoverRef = (0, import_react3.useRef)(enablePointerHover);
|
|
127
|
+
const backgroundColorVecRef = (0, import_react3.useRef)(hexToVec3(backgroundColor));
|
|
128
|
+
const animateRef = (0, import_react3.useRef)(animate);
|
|
129
|
+
(0, import_react3.useEffect)(() => {
|
|
130
|
+
hueRef.current = hue;
|
|
131
|
+
}, [hue]);
|
|
132
|
+
(0, import_react3.useEffect)(() => {
|
|
133
|
+
autoHueShiftRef.current = autoHueShift;
|
|
134
|
+
}, [autoHueShift]);
|
|
135
|
+
(0, import_react3.useEffect)(() => {
|
|
136
|
+
hueShiftMinRef.current = hueShiftMin;
|
|
137
|
+
}, [hueShiftMin]);
|
|
138
|
+
(0, import_react3.useEffect)(() => {
|
|
139
|
+
hueShiftMaxRef.current = hueShiftMax;
|
|
140
|
+
}, [hueShiftMax]);
|
|
141
|
+
(0, import_react3.useEffect)(() => {
|
|
142
|
+
hueShiftHalfCycleSecondsRef.current = hueShiftHalfCycleSeconds;
|
|
143
|
+
}, [hueShiftHalfCycleSeconds]);
|
|
144
|
+
(0, import_react3.useEffect)(() => {
|
|
145
|
+
hoverIntensityRef.current = hoverIntensity;
|
|
146
|
+
}, [hoverIntensity]);
|
|
147
|
+
(0, import_react3.useEffect)(() => {
|
|
148
|
+
rotateOnHoverRef.current = rotateOnHover;
|
|
149
|
+
}, [rotateOnHover]);
|
|
150
|
+
(0, import_react3.useEffect)(() => {
|
|
151
|
+
forceHoverStateRef.current = forceHoverState;
|
|
152
|
+
}, [forceHoverState]);
|
|
153
|
+
(0, import_react3.useEffect)(() => {
|
|
154
|
+
enablePointerHoverRef.current = enablePointerHover;
|
|
155
|
+
}, [enablePointerHover]);
|
|
156
|
+
(0, import_react3.useEffect)(() => {
|
|
157
|
+
backgroundColorVecRef.current = hexToVec3(backgroundColor);
|
|
158
|
+
}, [backgroundColor]);
|
|
159
|
+
(0, import_react3.useEffect)(() => {
|
|
160
|
+
animateRef.current = animate;
|
|
161
|
+
}, [animate]);
|
|
162
|
+
(0, import_react3.useEffect)(() => {
|
|
163
|
+
const container = containerRef.current;
|
|
164
|
+
if (!container) {
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
const renderer = new import_ogl.Renderer({ alpha: true, premultipliedAlpha: false });
|
|
168
|
+
const gl = renderer.gl;
|
|
169
|
+
gl.clearColor(0, 0, 0, 0);
|
|
170
|
+
container.appendChild(gl.canvas);
|
|
171
|
+
const geometry = new import_ogl.Triangle(gl);
|
|
172
|
+
const program = new import_ogl.Program(gl, {
|
|
173
|
+
vertex: VERTEX_SHADER,
|
|
174
|
+
fragment: FRAGMENT_SHADER,
|
|
175
|
+
uniforms: {
|
|
176
|
+
iTime: { value: 0 },
|
|
177
|
+
iResolution: {
|
|
178
|
+
value: new import_ogl.Vec3(gl.canvas.width, gl.canvas.height, gl.canvas.width / Math.max(gl.canvas.height, 1))
|
|
179
|
+
},
|
|
180
|
+
hue: { value: hueRef.current },
|
|
181
|
+
hover: { value: 0 },
|
|
182
|
+
rot: { value: 0 },
|
|
183
|
+
hoverIntensity: { value: hoverIntensityRef.current },
|
|
184
|
+
backgroundColor: { value: backgroundColorVecRef.current }
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
const mesh = new import_ogl.Mesh(gl, { geometry, program });
|
|
188
|
+
const resize = () => {
|
|
189
|
+
const dpr = window.devicePixelRatio || 1;
|
|
190
|
+
const width = Math.max(container.clientWidth, 1);
|
|
191
|
+
const height = Math.max(container.clientHeight, 1);
|
|
192
|
+
renderer.setSize(width * dpr, height * dpr);
|
|
193
|
+
gl.canvas.style.width = `${width}px`;
|
|
194
|
+
gl.canvas.style.height = `${height}px`;
|
|
195
|
+
program.uniforms.iResolution.value.set(gl.canvas.width, gl.canvas.height, gl.canvas.width / gl.canvas.height);
|
|
196
|
+
};
|
|
197
|
+
window.addEventListener("resize", resize);
|
|
198
|
+
resize();
|
|
199
|
+
let targetHover = 0;
|
|
200
|
+
let lastTime = 0;
|
|
201
|
+
let currentRotation = 0;
|
|
202
|
+
const rotationSpeed = 0.3;
|
|
203
|
+
const handlePointerMove = (event) => {
|
|
204
|
+
if (!enablePointerHoverRef.current) {
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
const rect = container.getBoundingClientRect();
|
|
208
|
+
const x = event.clientX - rect.left;
|
|
209
|
+
const y = event.clientY - rect.top;
|
|
210
|
+
const size = Math.min(rect.width, rect.height);
|
|
211
|
+
const centerX = rect.width / 2;
|
|
212
|
+
const centerY = rect.height / 2;
|
|
213
|
+
const uvX = (x - centerX) / size * 2;
|
|
214
|
+
const uvY = (y - centerY) / size * 2;
|
|
215
|
+
targetHover = Math.sqrt(uvX * uvX + uvY * uvY) < 0.8 ? 1 : 0;
|
|
216
|
+
};
|
|
217
|
+
const handlePointerLeave = () => {
|
|
218
|
+
if (!enablePointerHoverRef.current) {
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
targetHover = 0;
|
|
222
|
+
};
|
|
223
|
+
container.addEventListener("mousemove", handlePointerMove);
|
|
224
|
+
container.addEventListener("mouseleave", handlePointerLeave);
|
|
225
|
+
let animationFrameId = 0;
|
|
226
|
+
let idleTimerId = 0;
|
|
227
|
+
let lastRenderTime = 0;
|
|
228
|
+
let hasRenderedStaticFrame = false;
|
|
229
|
+
const frameIntervalMs = 1e3 / 24;
|
|
230
|
+
const idleCheckIntervalMs = 750;
|
|
231
|
+
const getAnimatedHueValue = (timeMs = 0) => {
|
|
232
|
+
if (!autoHueShiftRef.current) {
|
|
233
|
+
return hueRef.current;
|
|
234
|
+
}
|
|
235
|
+
const minHue = hueShiftMinRef.current;
|
|
236
|
+
const maxHue = hueShiftMaxRef.current;
|
|
237
|
+
const halfCycleSeconds = hueShiftHalfCycleSecondsRef.current;
|
|
238
|
+
const hueRange = maxHue - minHue;
|
|
239
|
+
if (halfCycleSeconds <= 0 || hueRange <= 0) {
|
|
240
|
+
return minHue;
|
|
241
|
+
}
|
|
242
|
+
const fullCycleSeconds = halfCycleSeconds * 2;
|
|
243
|
+
const elapsedSeconds = timeMs * 1e-3;
|
|
244
|
+
const cycleSeconds = (elapsedSeconds % fullCycleSeconds + fullCycleSeconds) % fullCycleSeconds;
|
|
245
|
+
const halfCycleProgress = cycleSeconds / halfCycleSeconds;
|
|
246
|
+
const wave = halfCycleProgress <= 1 ? halfCycleProgress : 2 - halfCycleProgress;
|
|
247
|
+
return minHue + wave * hueRange;
|
|
248
|
+
};
|
|
249
|
+
const renderStaticFrame = (timeMs = 0) => {
|
|
250
|
+
program.uniforms.iTime.value = 0;
|
|
251
|
+
program.uniforms.hue.value = getAnimatedHueValue(timeMs);
|
|
252
|
+
program.uniforms.hoverIntensity.value = hoverIntensityRef.current;
|
|
253
|
+
program.uniforms.backgroundColor.value = backgroundColorVecRef.current;
|
|
254
|
+
program.uniforms.hover.value = 0;
|
|
255
|
+
program.uniforms.rot.value = currentRotation;
|
|
256
|
+
renderer.render({ scene: mesh });
|
|
257
|
+
};
|
|
258
|
+
const scheduleNextFrame = () => {
|
|
259
|
+
if (animateRef.current && !document.hidden) {
|
|
260
|
+
animationFrameId = window.requestAnimationFrame(update);
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
idleTimerId = window.setTimeout(() => {
|
|
264
|
+
animationFrameId = window.requestAnimationFrame(update);
|
|
265
|
+
}, idleCheckIntervalMs);
|
|
266
|
+
};
|
|
267
|
+
const update = (timeMs) => {
|
|
268
|
+
if (document.hidden) {
|
|
269
|
+
scheduleNextFrame();
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
if (!animateRef.current) {
|
|
273
|
+
if (!hasRenderedStaticFrame) {
|
|
274
|
+
renderStaticFrame(timeMs);
|
|
275
|
+
hasRenderedStaticFrame = true;
|
|
276
|
+
}
|
|
277
|
+
scheduleNextFrame();
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
hasRenderedStaticFrame = false;
|
|
281
|
+
if (timeMs - lastRenderTime < frameIntervalMs) {
|
|
282
|
+
scheduleNextFrame();
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
lastRenderTime = timeMs;
|
|
286
|
+
const deltaSeconds = (timeMs - lastTime) * 1e-3;
|
|
287
|
+
lastTime = timeMs;
|
|
288
|
+
program.uniforms.iTime.value = timeMs * 1e-3;
|
|
289
|
+
program.uniforms.hue.value = getAnimatedHueValue(timeMs);
|
|
290
|
+
program.uniforms.hoverIntensity.value = hoverIntensityRef.current;
|
|
291
|
+
program.uniforms.backgroundColor.value = backgroundColorVecRef.current;
|
|
292
|
+
const effectiveHover = forceHoverStateRef.current ? 1 : enablePointerHoverRef.current ? targetHover : 0;
|
|
293
|
+
program.uniforms.hover.value += (effectiveHover - program.uniforms.hover.value) * 0.1;
|
|
294
|
+
if (rotateOnHoverRef.current && effectiveHover > 0.5) {
|
|
295
|
+
currentRotation += deltaSeconds * rotationSpeed;
|
|
296
|
+
}
|
|
297
|
+
program.uniforms.rot.value = currentRotation;
|
|
298
|
+
renderer.render({ scene: mesh });
|
|
299
|
+
scheduleNextFrame();
|
|
300
|
+
};
|
|
301
|
+
scheduleNextFrame();
|
|
302
|
+
return () => {
|
|
303
|
+
window.cancelAnimationFrame(animationFrameId);
|
|
304
|
+
window.clearTimeout(idleTimerId);
|
|
305
|
+
window.removeEventListener("resize", resize);
|
|
306
|
+
container.removeEventListener("mousemove", handlePointerMove);
|
|
307
|
+
container.removeEventListener("mouseleave", handlePointerLeave);
|
|
308
|
+
if (gl.canvas.parentElement === container) {
|
|
309
|
+
container.removeChild(gl.canvas);
|
|
310
|
+
}
|
|
311
|
+
gl.getExtension("WEBGL_lose_context")?.loseContext();
|
|
312
|
+
};
|
|
313
|
+
}, []);
|
|
314
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ref: containerRef, className: "navai-orb-container" });
|
|
315
|
+
}
|
|
316
|
+
function hslToRgb(hue, saturation, lightness) {
|
|
317
|
+
if (saturation === 0) {
|
|
318
|
+
return new import_ogl.Vec3(lightness, lightness, lightness);
|
|
319
|
+
}
|
|
320
|
+
const hueToRgb = (p2, q2, t) => {
|
|
321
|
+
let normalizedT = t;
|
|
322
|
+
if (normalizedT < 0) {
|
|
323
|
+
normalizedT += 1;
|
|
324
|
+
}
|
|
325
|
+
if (normalizedT > 1) {
|
|
326
|
+
normalizedT -= 1;
|
|
327
|
+
}
|
|
328
|
+
if (normalizedT < 1 / 6) {
|
|
329
|
+
return p2 + (q2 - p2) * 6 * normalizedT;
|
|
330
|
+
}
|
|
331
|
+
if (normalizedT < 1 / 2) {
|
|
332
|
+
return q2;
|
|
333
|
+
}
|
|
334
|
+
if (normalizedT < 2 / 3) {
|
|
335
|
+
return p2 + (q2 - p2) * (2 / 3 - normalizedT) * 6;
|
|
336
|
+
}
|
|
337
|
+
return p2;
|
|
338
|
+
};
|
|
339
|
+
const q = lightness < 0.5 ? lightness * (1 + saturation) : lightness + saturation - lightness * saturation;
|
|
340
|
+
const p = 2 * lightness - q;
|
|
341
|
+
return new import_ogl.Vec3(hueToRgb(p, q, hue + 1 / 3), hueToRgb(p, q, hue), hueToRgb(p, q, hue - 1 / 3));
|
|
342
|
+
}
|
|
343
|
+
function hexToVec3(color) {
|
|
344
|
+
if (color.startsWith("#")) {
|
|
345
|
+
const hex = color.slice(1);
|
|
346
|
+
if (hex.length === 3) {
|
|
347
|
+
return new import_ogl.Vec3(
|
|
348
|
+
Number.parseInt(`${hex[0]}${hex[0]}`, 16) / 255,
|
|
349
|
+
Number.parseInt(`${hex[1]}${hex[1]}`, 16) / 255,
|
|
350
|
+
Number.parseInt(`${hex[2]}${hex[2]}`, 16) / 255
|
|
351
|
+
);
|
|
352
|
+
}
|
|
353
|
+
if (hex.length >= 6) {
|
|
354
|
+
return new import_ogl.Vec3(
|
|
355
|
+
Number.parseInt(hex.slice(0, 2), 16) / 255,
|
|
356
|
+
Number.parseInt(hex.slice(2, 4), 16) / 255,
|
|
357
|
+
Number.parseInt(hex.slice(4, 6), 16) / 255
|
|
358
|
+
);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
const rgbMatch = color.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);
|
|
362
|
+
if (rgbMatch) {
|
|
363
|
+
const [, red, green, blue] = rgbMatch;
|
|
364
|
+
return new import_ogl.Vec3(
|
|
365
|
+
Number.parseInt(red ?? "0", 10) / 255,
|
|
366
|
+
Number.parseInt(green ?? "0", 10) / 255,
|
|
367
|
+
Number.parseInt(blue ?? "0", 10) / 255
|
|
368
|
+
);
|
|
369
|
+
}
|
|
370
|
+
const hslMatch = color.match(/hsla?\((\d+),\s*(\d+)%,\s*(\d+)%/);
|
|
371
|
+
if (hslMatch) {
|
|
372
|
+
const [, hue, saturation, lightness] = hslMatch;
|
|
373
|
+
return hslToRgb(
|
|
374
|
+
Number.parseInt(hue ?? "0", 10) / 360,
|
|
375
|
+
Number.parseInt(saturation ?? "0", 10) / 100,
|
|
376
|
+
Number.parseInt(lightness ?? "0", 10) / 100
|
|
377
|
+
);
|
|
378
|
+
}
|
|
379
|
+
return new import_ogl.Vec3(0, 0, 0);
|
|
380
|
+
}
|
|
381
|
+
var import_ogl, import_react3, import_jsx_runtime, VERTEX_SHADER, FRAGMENT_SHADER;
|
|
382
|
+
var init_Orb = __esm({
|
|
383
|
+
"src/orb/Orb.tsx"() {
|
|
384
|
+
"use strict";
|
|
385
|
+
import_ogl = require("ogl");
|
|
386
|
+
import_react3 = require("react");
|
|
387
|
+
init_styles();
|
|
388
|
+
import_jsx_runtime = require("react/jsx-runtime");
|
|
389
|
+
VERTEX_SHADER = /* glsl */
|
|
390
|
+
`
|
|
391
|
+
precision highp float;
|
|
392
|
+
attribute vec2 position;
|
|
393
|
+
attribute vec2 uv;
|
|
394
|
+
varying vec2 vUv;
|
|
395
|
+
|
|
396
|
+
void main() {
|
|
397
|
+
vUv = uv;
|
|
398
|
+
gl_Position = vec4(position, 0.0, 1.0);
|
|
399
|
+
}
|
|
400
|
+
`;
|
|
401
|
+
FRAGMENT_SHADER = /* glsl */
|
|
402
|
+
`
|
|
403
|
+
precision highp float;
|
|
404
|
+
|
|
405
|
+
uniform float iTime;
|
|
406
|
+
uniform vec3 iResolution;
|
|
407
|
+
uniform float hue;
|
|
408
|
+
uniform float hover;
|
|
409
|
+
uniform float rot;
|
|
410
|
+
uniform float hoverIntensity;
|
|
411
|
+
uniform vec3 backgroundColor;
|
|
412
|
+
varying vec2 vUv;
|
|
413
|
+
|
|
414
|
+
vec3 rgb2yiq(vec3 c) {
|
|
415
|
+
float y = dot(c, vec3(0.299, 0.587, 0.114));
|
|
416
|
+
float i = dot(c, vec3(0.596, -0.274, -0.322));
|
|
417
|
+
float q = dot(c, vec3(0.211, -0.523, 0.312));
|
|
418
|
+
return vec3(y, i, q);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
vec3 yiq2rgb(vec3 c) {
|
|
422
|
+
float r = c.x + 0.956 * c.y + 0.621 * c.z;
|
|
423
|
+
float g = c.x - 0.272 * c.y - 0.647 * c.z;
|
|
424
|
+
float b = c.x - 1.106 * c.y + 1.703 * c.z;
|
|
425
|
+
return vec3(r, g, b);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
vec3 adjustHue(vec3 color, float hueDeg) {
|
|
429
|
+
float hueRad = hueDeg * 3.14159265 / 180.0;
|
|
430
|
+
vec3 yiq = rgb2yiq(color);
|
|
431
|
+
float cosA = cos(hueRad);
|
|
432
|
+
float sinA = sin(hueRad);
|
|
433
|
+
float i = yiq.y * cosA - yiq.z * sinA;
|
|
434
|
+
float q = yiq.y * sinA + yiq.z * cosA;
|
|
435
|
+
yiq.y = i;
|
|
436
|
+
yiq.z = q;
|
|
437
|
+
return yiq2rgb(yiq);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
vec3 hash33(vec3 p3) {
|
|
441
|
+
p3 = fract(p3 * vec3(0.1031, 0.11369, 0.13787));
|
|
442
|
+
p3 += dot(p3, p3.yxz + 19.19);
|
|
443
|
+
return -1.0 + 2.0 * fract(vec3(
|
|
444
|
+
p3.x + p3.y,
|
|
445
|
+
p3.x + p3.z,
|
|
446
|
+
p3.y + p3.z
|
|
447
|
+
) * p3.zyx);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
float snoise3(vec3 p) {
|
|
451
|
+
const float K1 = 0.333333333;
|
|
452
|
+
const float K2 = 0.166666667;
|
|
453
|
+
vec3 i = floor(p + (p.x + p.y + p.z) * K1);
|
|
454
|
+
vec3 d0 = p - (i - (i.x + i.y + i.z) * K2);
|
|
455
|
+
vec3 e = step(vec3(0.0), d0 - d0.yzx);
|
|
456
|
+
vec3 i1 = e * (1.0 - e.zxy);
|
|
457
|
+
vec3 i2 = 1.0 - e.zxy * (1.0 - e);
|
|
458
|
+
vec3 d1 = d0 - (i1 - K2);
|
|
459
|
+
vec3 d2 = d0 - (i2 - K1);
|
|
460
|
+
vec3 d3 = d0 - 0.5;
|
|
461
|
+
vec4 h = max(0.6 - vec4(
|
|
462
|
+
dot(d0, d0),
|
|
463
|
+
dot(d1, d1),
|
|
464
|
+
dot(d2, d2),
|
|
465
|
+
dot(d3, d3)
|
|
466
|
+
), 0.0);
|
|
467
|
+
vec4 n = h * h * h * h * vec4(
|
|
468
|
+
dot(d0, hash33(i)),
|
|
469
|
+
dot(d1, hash33(i + i1)),
|
|
470
|
+
dot(d2, hash33(i + i2)),
|
|
471
|
+
dot(d3, hash33(i + 1.0))
|
|
472
|
+
);
|
|
473
|
+
return dot(vec4(31.316), n);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
vec4 extractAlpha(vec3 colorIn) {
|
|
477
|
+
float a = max(max(colorIn.r, colorIn.g), colorIn.b);
|
|
478
|
+
return vec4(colorIn.rgb / (a + 1e-5), a);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
const vec3 baseColor1 = vec3(0.611765, 0.262745, 0.996078);
|
|
482
|
+
const vec3 baseColor2 = vec3(0.298039, 0.760784, 0.913725);
|
|
483
|
+
const vec3 baseColor3 = vec3(0.062745, 0.078431, 0.600000);
|
|
484
|
+
const float innerRadius = 0.6;
|
|
485
|
+
const float noiseScale = 0.65;
|
|
486
|
+
|
|
487
|
+
float light1(float intensity, float attenuation, float dist) {
|
|
488
|
+
return intensity / (1.0 + dist * attenuation);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
float light2(float intensity, float attenuation, float dist) {
|
|
492
|
+
return intensity / (1.0 + dist * dist * attenuation);
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
vec4 draw(vec2 uv) {
|
|
496
|
+
vec3 color1 = adjustHue(baseColor1, hue);
|
|
497
|
+
vec3 color2 = adjustHue(baseColor2, hue);
|
|
498
|
+
vec3 color3 = adjustHue(baseColor3, hue);
|
|
499
|
+
|
|
500
|
+
float ang = atan(uv.y, uv.x);
|
|
501
|
+
float len = length(uv);
|
|
502
|
+
float invLen = len > 0.0 ? 1.0 / len : 0.0;
|
|
503
|
+
float bgLuminance = dot(backgroundColor, vec3(0.299, 0.587, 0.114));
|
|
504
|
+
|
|
505
|
+
float n0 = snoise3(vec3(uv * noiseScale, iTime * 0.5)) * 0.5 + 0.5;
|
|
506
|
+
float r0 = mix(mix(innerRadius, 1.0, 0.4), mix(innerRadius, 1.0, 0.6), n0);
|
|
507
|
+
float d0 = distance(uv, (r0 * invLen) * uv);
|
|
508
|
+
float v0 = light1(1.0, 10.0, d0);
|
|
509
|
+
|
|
510
|
+
v0 *= smoothstep(r0 * 1.05, r0, len);
|
|
511
|
+
float innerFade = smoothstep(r0 * 0.8, r0 * 0.95, len);
|
|
512
|
+
v0 *= mix(innerFade, 1.0, bgLuminance * 0.7);
|
|
513
|
+
float cl = cos(ang + iTime * 2.0) * 0.5 + 0.5;
|
|
514
|
+
|
|
515
|
+
float a = iTime * -1.0;
|
|
516
|
+
vec2 pos = vec2(cos(a), sin(a)) * r0;
|
|
517
|
+
float d = distance(uv, pos);
|
|
518
|
+
float v1 = light2(1.5, 5.0, d);
|
|
519
|
+
v1 *= light1(1.0, 50.0, d0);
|
|
520
|
+
|
|
521
|
+
float v2 = smoothstep(1.0, mix(innerRadius, 1.0, n0 * 0.5), len);
|
|
522
|
+
float v3 = smoothstep(innerRadius, mix(innerRadius, 1.0, 0.5), len);
|
|
523
|
+
|
|
524
|
+
vec3 colBase = mix(color1, color2, cl);
|
|
525
|
+
float fadeAmount = mix(1.0, 0.1, bgLuminance);
|
|
526
|
+
vec3 darkCol = mix(color3, colBase, v0);
|
|
527
|
+
darkCol = (darkCol + v1) * v2 * v3;
|
|
528
|
+
darkCol = clamp(darkCol, 0.0, 1.0);
|
|
529
|
+
|
|
530
|
+
vec3 lightCol = (colBase + v1) * mix(1.0, v2 * v3, fadeAmount);
|
|
531
|
+
lightCol = mix(backgroundColor, lightCol, v0);
|
|
532
|
+
lightCol = clamp(lightCol, 0.0, 1.0);
|
|
533
|
+
|
|
534
|
+
return extractAlpha(mix(darkCol, lightCol, bgLuminance));
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
vec4 mainImage(vec2 fragCoord) {
|
|
538
|
+
vec2 center = iResolution.xy * 0.5;
|
|
539
|
+
float size = min(iResolution.x, iResolution.y);
|
|
540
|
+
vec2 uv = (fragCoord - center) / size * 2.0;
|
|
541
|
+
|
|
542
|
+
float angle = rot;
|
|
543
|
+
float s = sin(angle);
|
|
544
|
+
float c = cos(angle);
|
|
545
|
+
uv = vec2(c * uv.x - s * uv.y, s * uv.x + c * uv.y);
|
|
546
|
+
uv.x += hover * hoverIntensity * 0.1 * sin(uv.y * 10.0 + iTime);
|
|
547
|
+
uv.y += hover * hoverIntensity * 0.1 * sin(uv.x * 10.0 + iTime);
|
|
548
|
+
|
|
549
|
+
return draw(uv);
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
void main() {
|
|
553
|
+
vec2 fragCoord = vUv * iResolution.xy;
|
|
554
|
+
vec4 col = mainImage(fragCoord);
|
|
555
|
+
gl_FragColor = vec4(col.rgb * col.a, col.a);
|
|
556
|
+
}
|
|
557
|
+
`;
|
|
558
|
+
}
|
|
559
|
+
});
|
|
560
|
+
|
|
20
561
|
// src/index.ts
|
|
21
562
|
var index_exports = {};
|
|
22
563
|
__export(index_exports, {
|
|
564
|
+
NavaiHeroOrb: () => NavaiHeroOrb,
|
|
565
|
+
NavaiMiniOrbDock: () => NavaiMiniOrbDock,
|
|
566
|
+
NavaiVoiceHeroOrb: () => NavaiVoiceHeroOrb,
|
|
567
|
+
NavaiVoiceOrbDock: () => NavaiVoiceOrbDock,
|
|
568
|
+
NavaiVoiceOrbDockMicIcon: () => NavaiVoiceOrbDockMicIcon,
|
|
569
|
+
Orb: () => Orb,
|
|
23
570
|
buildNavaiAgent: () => buildNavaiAgent,
|
|
571
|
+
clampNavaiOrbDelayMs: () => clampNavaiOrbDelayMs,
|
|
24
572
|
createNavaiBackendClient: () => createNavaiBackendClient,
|
|
25
573
|
getNavaiRoutePromptLines: () => getNavaiRoutePromptLines,
|
|
26
574
|
loadNavaiFunctions: () => loadNavaiFunctions,
|
|
27
575
|
resolveNavaiFrontendRuntimeConfig: () => resolveNavaiFrontendRuntimeConfig,
|
|
28
576
|
resolveNavaiRoute: () => resolveNavaiRoute,
|
|
577
|
+
resolveNavaiVoiceOrbRuntimeSnapshot: () => resolveNavaiVoiceOrbRuntimeSnapshot,
|
|
29
578
|
useWebVoiceAgent: () => useWebVoiceAgent
|
|
30
579
|
});
|
|
31
580
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -760,6 +1309,7 @@ function emitWarnings(warnings) {
|
|
|
760
1309
|
}
|
|
761
1310
|
function useWebVoiceAgent(options) {
|
|
762
1311
|
const sessionRef = (0, import_react.useRef)(null);
|
|
1312
|
+
const attachedRealtimeSessionRef = (0, import_react.useRef)(null);
|
|
763
1313
|
const runtimeConfigPromise = (0, import_react.useMemo)(
|
|
764
1314
|
() => resolveNavaiFrontendRuntimeConfig({
|
|
765
1315
|
moduleLoaders: options.moduleLoaders,
|
|
@@ -790,15 +1340,61 @@ function useWebVoiceAgent(options) {
|
|
|
790
1340
|
[options.apiBaseUrl, options.env]
|
|
791
1341
|
);
|
|
792
1342
|
const [status, setStatus] = (0, import_react.useState)("idle");
|
|
1343
|
+
const [agentVoiceState, setAgentVoiceState] = (0, import_react.useState)("idle");
|
|
793
1344
|
const [error, setError] = (0, import_react.useState)(null);
|
|
1345
|
+
const setAgentVoiceStateIfChanged = (0, import_react.useCallback)((next) => {
|
|
1346
|
+
setAgentVoiceState((current) => current === next ? current : next);
|
|
1347
|
+
}, []);
|
|
1348
|
+
const handleSessionAudioStart = (0, import_react.useCallback)(() => {
|
|
1349
|
+
setAgentVoiceStateIfChanged("speaking");
|
|
1350
|
+
}, [setAgentVoiceStateIfChanged]);
|
|
1351
|
+
const handleSessionAudioStopped = (0, import_react.useCallback)(() => {
|
|
1352
|
+
setAgentVoiceStateIfChanged("idle");
|
|
1353
|
+
}, [setAgentVoiceStateIfChanged]);
|
|
1354
|
+
const handleSessionAudioInterrupted = (0, import_react.useCallback)(() => {
|
|
1355
|
+
setAgentVoiceStateIfChanged("idle");
|
|
1356
|
+
}, [setAgentVoiceStateIfChanged]);
|
|
1357
|
+
const handleSessionError = (0, import_react.useCallback)(() => {
|
|
1358
|
+
setAgentVoiceStateIfChanged("idle");
|
|
1359
|
+
}, [setAgentVoiceStateIfChanged]);
|
|
1360
|
+
const detachSessionAudioListeners = (0, import_react.useCallback)(() => {
|
|
1361
|
+
const attachedSession = attachedRealtimeSessionRef.current;
|
|
1362
|
+
if (!attachedSession) {
|
|
1363
|
+
return;
|
|
1364
|
+
}
|
|
1365
|
+
attachedSession.off("audio_start", handleSessionAudioStart);
|
|
1366
|
+
attachedSession.off("audio_stopped", handleSessionAudioStopped);
|
|
1367
|
+
attachedSession.off("audio_interrupted", handleSessionAudioInterrupted);
|
|
1368
|
+
attachedSession.off("error", handleSessionError);
|
|
1369
|
+
attachedRealtimeSessionRef.current = null;
|
|
1370
|
+
}, [handleSessionAudioInterrupted, handleSessionAudioStart, handleSessionAudioStopped, handleSessionError]);
|
|
1371
|
+
const attachSessionAudioListeners = (0, import_react.useCallback)(
|
|
1372
|
+
(session) => {
|
|
1373
|
+
detachSessionAudioListeners();
|
|
1374
|
+
session.on("audio_start", handleSessionAudioStart);
|
|
1375
|
+
session.on("audio_stopped", handleSessionAudioStopped);
|
|
1376
|
+
session.on("audio_interrupted", handleSessionAudioInterrupted);
|
|
1377
|
+
session.on("error", handleSessionError);
|
|
1378
|
+
attachedRealtimeSessionRef.current = session;
|
|
1379
|
+
},
|
|
1380
|
+
[
|
|
1381
|
+
detachSessionAudioListeners,
|
|
1382
|
+
handleSessionAudioInterrupted,
|
|
1383
|
+
handleSessionAudioStart,
|
|
1384
|
+
handleSessionAudioStopped,
|
|
1385
|
+
handleSessionError
|
|
1386
|
+
]
|
|
1387
|
+
);
|
|
794
1388
|
const stop = (0, import_react.useCallback)(() => {
|
|
1389
|
+
detachSessionAudioListeners();
|
|
795
1390
|
try {
|
|
796
1391
|
sessionRef.current?.close();
|
|
797
1392
|
} finally {
|
|
798
1393
|
sessionRef.current = null;
|
|
799
1394
|
setStatus("idle");
|
|
1395
|
+
setAgentVoiceStateIfChanged("idle");
|
|
800
1396
|
}
|
|
801
|
-
}, []);
|
|
1397
|
+
}, [detachSessionAudioListeners, setAgentVoiceStateIfChanged]);
|
|
802
1398
|
(0, import_react.useEffect)(() => {
|
|
803
1399
|
return () => {
|
|
804
1400
|
stop();
|
|
@@ -810,6 +1406,7 @@ function useWebVoiceAgent(options) {
|
|
|
810
1406
|
}
|
|
811
1407
|
setError(null);
|
|
812
1408
|
setStatus("connecting");
|
|
1409
|
+
setAgentVoiceStateIfChanged("idle");
|
|
813
1410
|
try {
|
|
814
1411
|
const runtimeConfig = await runtimeConfigPromise;
|
|
815
1412
|
const requestPayload = runtimeConfig.modelOverride ? { model: runtimeConfig.modelOverride } : {};
|
|
@@ -824,6 +1421,7 @@ function useWebVoiceAgent(options) {
|
|
|
824
1421
|
});
|
|
825
1422
|
emitWarnings([...runtimeConfig.warnings, ...backendFunctionsResult.warnings, ...warnings]);
|
|
826
1423
|
const session = new import_realtime2.RealtimeSession(agent);
|
|
1424
|
+
attachSessionAudioListeners(session);
|
|
827
1425
|
if (runtimeConfig.modelOverride) {
|
|
828
1426
|
await session.connect({ apiKey: secretPayload.value, model: runtimeConfig.modelOverride });
|
|
829
1427
|
} else {
|
|
@@ -835,29 +1433,395 @@ function useWebVoiceAgent(options) {
|
|
|
835
1433
|
const message = formatError(startError);
|
|
836
1434
|
setError(message);
|
|
837
1435
|
setStatus("error");
|
|
1436
|
+
setAgentVoiceStateIfChanged("idle");
|
|
1437
|
+
detachSessionAudioListeners();
|
|
838
1438
|
try {
|
|
839
1439
|
sessionRef.current?.close();
|
|
840
1440
|
} catch {
|
|
841
1441
|
}
|
|
842
1442
|
sessionRef.current = null;
|
|
843
1443
|
}
|
|
844
|
-
}, [
|
|
1444
|
+
}, [
|
|
1445
|
+
attachSessionAudioListeners,
|
|
1446
|
+
backendClient,
|
|
1447
|
+
detachSessionAudioListeners,
|
|
1448
|
+
options.navigate,
|
|
1449
|
+
runtimeConfigPromise,
|
|
1450
|
+
setAgentVoiceStateIfChanged,
|
|
1451
|
+
status
|
|
1452
|
+
]);
|
|
845
1453
|
return {
|
|
846
1454
|
status,
|
|
1455
|
+
agentVoiceState,
|
|
847
1456
|
error,
|
|
848
1457
|
isConnecting: status === "connecting",
|
|
849
1458
|
isConnected: status === "connected",
|
|
1459
|
+
isAgentSpeaking: agentVoiceState === "speaking",
|
|
850
1460
|
start,
|
|
851
1461
|
stop
|
|
852
1462
|
};
|
|
853
1463
|
}
|
|
1464
|
+
|
|
1465
|
+
// src/orb/index.ts
|
|
1466
|
+
init_Orb();
|
|
1467
|
+
|
|
1468
|
+
// src/orb/NavaiHeroOrb.tsx
|
|
1469
|
+
var import_react5 = require("react");
|
|
1470
|
+
|
|
1471
|
+
// src/orb/dynamic.tsx
|
|
1472
|
+
var import_react4 = require("react");
|
|
1473
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
1474
|
+
function dynamic(loader, options = {}) {
|
|
1475
|
+
const { ssr = true, loading: LoadingComponent } = options;
|
|
1476
|
+
const LazyComponent = (0, import_react4.lazy)(async () => {
|
|
1477
|
+
const loaded = await loader();
|
|
1478
|
+
if (typeof loaded === "function") {
|
|
1479
|
+
return { default: loaded };
|
|
1480
|
+
}
|
|
1481
|
+
return loaded;
|
|
1482
|
+
});
|
|
1483
|
+
function DynamicComponent(props) {
|
|
1484
|
+
const [isClientReady, setIsClientReady] = (0, import_react4.useState)(ssr);
|
|
1485
|
+
(0, import_react4.useEffect)(() => {
|
|
1486
|
+
if (!ssr) {
|
|
1487
|
+
setIsClientReady(true);
|
|
1488
|
+
}
|
|
1489
|
+
}, [ssr]);
|
|
1490
|
+
if (!isClientReady) {
|
|
1491
|
+
return null;
|
|
1492
|
+
}
|
|
1493
|
+
const fallback = LoadingComponent ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(LoadingComponent, {}) : null;
|
|
1494
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react4.Suspense, { fallback, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(LazyComponent, { ...props }) });
|
|
1495
|
+
}
|
|
1496
|
+
DynamicComponent.displayName = "DynamicComponent";
|
|
1497
|
+
return DynamicComponent;
|
|
1498
|
+
}
|
|
1499
|
+
|
|
1500
|
+
// src/orb/NavaiHeroOrb.tsx
|
|
1501
|
+
init_styles();
|
|
1502
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
1503
|
+
var Orb2 = dynamic(() => Promise.resolve().then(() => (init_Orb(), Orb_exports)), {
|
|
1504
|
+
ssr: false
|
|
1505
|
+
});
|
|
1506
|
+
var ORB_DELAY_MS_MIN = 0;
|
|
1507
|
+
var ORB_DELAY_MS_MAX = 6e4;
|
|
1508
|
+
var DEFAULT_AUTOPLAY_DELAY_MS = 9e3;
|
|
1509
|
+
var DEFAULT_REVEAL_DELAY_MS = 5200;
|
|
1510
|
+
function clampNavaiOrbDelayMs(value, fallback) {
|
|
1511
|
+
const numericValue = Number.isFinite(value) ? value : fallback;
|
|
1512
|
+
return Math.min(ORB_DELAY_MS_MAX, Math.max(ORB_DELAY_MS_MIN, numericValue));
|
|
1513
|
+
}
|
|
1514
|
+
function NavaiHeroOrb({
|
|
1515
|
+
className = "",
|
|
1516
|
+
backgroundColor = "#000000",
|
|
1517
|
+
isAgentSpeaking = false,
|
|
1518
|
+
hoverIntensitySpeaking = 0.66,
|
|
1519
|
+
hoverIntensityIdle = 0.08,
|
|
1520
|
+
revealDelayMs = DEFAULT_REVEAL_DELAY_MS,
|
|
1521
|
+
autoplayDelayMs = DEFAULT_AUTOPLAY_DELAY_MS
|
|
1522
|
+
}) {
|
|
1523
|
+
useNavaiVoiceOrbStyles();
|
|
1524
|
+
const resolvedRevealDelayMs = clampNavaiOrbDelayMs(revealDelayMs, DEFAULT_REVEAL_DELAY_MS);
|
|
1525
|
+
const resolvedAutoplayDelayMs = clampNavaiOrbDelayMs(autoplayDelayMs, DEFAULT_AUTOPLAY_DELAY_MS);
|
|
1526
|
+
const [isOrbReady, setIsOrbReady] = (0, import_react5.useState)(resolvedRevealDelayMs === 0);
|
|
1527
|
+
const [isOrbAutoAnimating, setIsOrbAutoAnimating] = (0, import_react5.useState)(resolvedAutoplayDelayMs === 0);
|
|
1528
|
+
(0, import_react5.useEffect)(() => {
|
|
1529
|
+
if (typeof window === "undefined" || resolvedRevealDelayMs === 0) {
|
|
1530
|
+
return;
|
|
1531
|
+
}
|
|
1532
|
+
const revealOrb = () => setIsOrbReady(true);
|
|
1533
|
+
window.addEventListener("pointerdown", revealOrb, { passive: true, once: true });
|
|
1534
|
+
window.addEventListener("touchstart", revealOrb, { passive: true, once: true });
|
|
1535
|
+
window.addEventListener("keydown", revealOrb, { once: true });
|
|
1536
|
+
const timeoutId = window.setTimeout(revealOrb, resolvedRevealDelayMs);
|
|
1537
|
+
return () => {
|
|
1538
|
+
window.removeEventListener("pointerdown", revealOrb);
|
|
1539
|
+
window.removeEventListener("touchstart", revealOrb);
|
|
1540
|
+
window.removeEventListener("keydown", revealOrb);
|
|
1541
|
+
window.clearTimeout(timeoutId);
|
|
1542
|
+
};
|
|
1543
|
+
}, [resolvedRevealDelayMs]);
|
|
1544
|
+
(0, import_react5.useEffect)(() => {
|
|
1545
|
+
if (typeof window === "undefined" || resolvedAutoplayDelayMs === 0) {
|
|
1546
|
+
return;
|
|
1547
|
+
}
|
|
1548
|
+
let started = false;
|
|
1549
|
+
const startOrbAnimation = () => {
|
|
1550
|
+
if (started) {
|
|
1551
|
+
return;
|
|
1552
|
+
}
|
|
1553
|
+
started = true;
|
|
1554
|
+
setIsOrbAutoAnimating(true);
|
|
1555
|
+
};
|
|
1556
|
+
if (navigator.userActivation?.hasBeenActive) {
|
|
1557
|
+
startOrbAnimation();
|
|
1558
|
+
}
|
|
1559
|
+
window.addEventListener("pointerdown", startOrbAnimation, { passive: true, once: true });
|
|
1560
|
+
window.addEventListener("touchstart", startOrbAnimation, { passive: true, once: true });
|
|
1561
|
+
window.addEventListener("keydown", startOrbAnimation, { once: true });
|
|
1562
|
+
const timeoutId = window.setTimeout(startOrbAnimation, resolvedAutoplayDelayMs);
|
|
1563
|
+
return () => {
|
|
1564
|
+
window.removeEventListener("pointerdown", startOrbAnimation);
|
|
1565
|
+
window.removeEventListener("touchstart", startOrbAnimation);
|
|
1566
|
+
window.removeEventListener("keydown", startOrbAnimation);
|
|
1567
|
+
window.clearTimeout(timeoutId);
|
|
1568
|
+
};
|
|
1569
|
+
}, [resolvedAutoplayDelayMs]);
|
|
1570
|
+
const orbHoverIntensity = (0, import_react5.useMemo)(() => {
|
|
1571
|
+
return isAgentSpeaking ? hoverIntensitySpeaking : hoverIntensityIdle;
|
|
1572
|
+
}, [hoverIntensityIdle, hoverIntensitySpeaking, isAgentSpeaking]);
|
|
1573
|
+
if (!isOrbReady) {
|
|
1574
|
+
return null;
|
|
1575
|
+
}
|
|
1576
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: ["navai-voice-orb-hero", className].filter(Boolean).join(" "), children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1577
|
+
Orb2,
|
|
1578
|
+
{
|
|
1579
|
+
hoverIntensity: orbHoverIntensity,
|
|
1580
|
+
rotateOnHover: true,
|
|
1581
|
+
forceHoverState: isAgentSpeaking,
|
|
1582
|
+
enablePointerHover: false,
|
|
1583
|
+
animate: isAgentSpeaking || isOrbAutoAnimating,
|
|
1584
|
+
backgroundColor
|
|
1585
|
+
}
|
|
1586
|
+
) });
|
|
1587
|
+
}
|
|
1588
|
+
|
|
1589
|
+
// src/orb/NavaiMiniOrbDock.tsx
|
|
1590
|
+
init_styles();
|
|
1591
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
1592
|
+
var Orb3 = dynamic(() => Promise.resolve().then(() => (init_Orb(), Orb_exports)), {
|
|
1593
|
+
ssr: false
|
|
1594
|
+
});
|
|
1595
|
+
function NavaiMiniOrbDock({
|
|
1596
|
+
className = "",
|
|
1597
|
+
style,
|
|
1598
|
+
themeMode = "dark",
|
|
1599
|
+
placement = "bottom-right",
|
|
1600
|
+
isActive = false,
|
|
1601
|
+
isConnected = false,
|
|
1602
|
+
isDisabled = false,
|
|
1603
|
+
isAgentSpeaking = false,
|
|
1604
|
+
animateOrb = true,
|
|
1605
|
+
backgroundColor = "#060914",
|
|
1606
|
+
buttonAriaLabel,
|
|
1607
|
+
buttonIcon,
|
|
1608
|
+
buttonType = "button",
|
|
1609
|
+
onButtonClick,
|
|
1610
|
+
statusMessage = "",
|
|
1611
|
+
isError = false,
|
|
1612
|
+
ariaMessage = ""
|
|
1613
|
+
}) {
|
|
1614
|
+
useNavaiVoiceOrbStyles();
|
|
1615
|
+
const dockClassName = ["navai-voice-orb-dock", `is-${placement}`, themeMode === "light" ? "is-light" : "", className].filter(Boolean).join(" ");
|
|
1616
|
+
const shouldHighlightOrb = isAgentSpeaking || isActive;
|
|
1617
|
+
const orbHoverIntensity = isAgentSpeaking ? 0.66 : 0.08;
|
|
1618
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("aside", { className: dockClassName, style, children: [
|
|
1619
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "navai-voice-orb-wrap", children: [
|
|
1620
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: ["navai-voice-orb-surface", shouldHighlightOrb ? "is-highlighted" : ""].filter(Boolean).join(" "), children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1621
|
+
Orb3,
|
|
1622
|
+
{
|
|
1623
|
+
hoverIntensity: orbHoverIntensity,
|
|
1624
|
+
rotateOnHover: true,
|
|
1625
|
+
forceHoverState: isAgentSpeaking,
|
|
1626
|
+
enablePointerHover: false,
|
|
1627
|
+
animate: animateOrb,
|
|
1628
|
+
backgroundColor
|
|
1629
|
+
}
|
|
1630
|
+
) }),
|
|
1631
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: ["navai-voice-orb-button-shell", isConnected ? "is-active" : ""].filter(Boolean).join(" "), children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1632
|
+
"button",
|
|
1633
|
+
{
|
|
1634
|
+
type: buttonType,
|
|
1635
|
+
className: [
|
|
1636
|
+
"navai-voice-orb-button",
|
|
1637
|
+
isConnected ? "is-active" : "",
|
|
1638
|
+
isActive && !isConnected ? "is-connecting" : ""
|
|
1639
|
+
].filter(Boolean).join(" "),
|
|
1640
|
+
onClick: onButtonClick,
|
|
1641
|
+
disabled: isDisabled,
|
|
1642
|
+
"aria-label": buttonAriaLabel,
|
|
1643
|
+
children: buttonIcon
|
|
1644
|
+
}
|
|
1645
|
+
) })
|
|
1646
|
+
] }),
|
|
1647
|
+
statusMessage ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: ["navai-voice-orb-status", isError ? "is-error" : ""].filter(Boolean).join(" "), role: "status", children: statusMessage }) : null,
|
|
1648
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "navai-voice-orb-live", "aria-live": "polite", children: ariaMessage })
|
|
1649
|
+
] });
|
|
1650
|
+
}
|
|
1651
|
+
|
|
1652
|
+
// src/orb/NavaiVoiceHeroOrb.tsx
|
|
1653
|
+
var import_react7 = require("react");
|
|
1654
|
+
|
|
1655
|
+
// src/orb/NavaiVoiceOrbDock.tsx
|
|
1656
|
+
var import_react6 = require("react");
|
|
1657
|
+
|
|
1658
|
+
// src/orb/NavaiVoiceOrbDockMicIcon.tsx
|
|
1659
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
1660
|
+
function NavaiVoiceOrbDockMicIcon({
|
|
1661
|
+
isActive = false,
|
|
1662
|
+
size = 20
|
|
1663
|
+
}) {
|
|
1664
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1665
|
+
"svg",
|
|
1666
|
+
{
|
|
1667
|
+
width: size,
|
|
1668
|
+
height: size,
|
|
1669
|
+
viewBox: "0 0 24 24",
|
|
1670
|
+
fill: "none",
|
|
1671
|
+
stroke: "currentColor",
|
|
1672
|
+
strokeWidth: "2",
|
|
1673
|
+
strokeLinecap: "round",
|
|
1674
|
+
strokeLinejoin: "round",
|
|
1675
|
+
"aria-hidden": "true",
|
|
1676
|
+
className: ["navai-voice-orb-icon", isActive ? "is-pulsing" : ""].filter(Boolean).join(" "),
|
|
1677
|
+
children: [
|
|
1678
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M12 3a3 3 0 0 0-3 3v6a3 3 0 1 0 6 0V6a3 3 0 0 0-3-3Z" }),
|
|
1679
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M19 10v2a7 7 0 1 1-14 0v-2" }),
|
|
1680
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M12 19v3" })
|
|
1681
|
+
]
|
|
1682
|
+
}
|
|
1683
|
+
);
|
|
1684
|
+
}
|
|
1685
|
+
|
|
1686
|
+
// src/orb/NavaiVoiceOrbDockSpinnerIcon.tsx
|
|
1687
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
1688
|
+
function NavaiVoiceOrbDockSpinnerIcon({
|
|
1689
|
+
size = 20
|
|
1690
|
+
}) {
|
|
1691
|
+
const style = {
|
|
1692
|
+
width: size,
|
|
1693
|
+
height: size
|
|
1694
|
+
};
|
|
1695
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { "aria-hidden": "true", className: "navai-voice-orb-spinner", style });
|
|
1696
|
+
}
|
|
1697
|
+
|
|
1698
|
+
// src/orb/NavaiVoiceOrbDock.tsx
|
|
1699
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
1700
|
+
var DEFAULT_MESSAGES = {
|
|
1701
|
+
ariaStart: "Activate NAVAI voice",
|
|
1702
|
+
ariaStop: "Deactivate NAVAI voice",
|
|
1703
|
+
idle: "NAVAI ready to start.",
|
|
1704
|
+
connecting: "Connecting NAVAI voice...",
|
|
1705
|
+
listening: "NAVAI is listening.",
|
|
1706
|
+
speaking: "NAVAI is speaking.",
|
|
1707
|
+
errorPrefix: "NAVAI error"
|
|
1708
|
+
};
|
|
1709
|
+
function resolveNavaiVoiceOrbRuntimeSnapshot(agent) {
|
|
1710
|
+
return {
|
|
1711
|
+
status: agent.status,
|
|
1712
|
+
agentVoiceState: agent.agentVoiceState,
|
|
1713
|
+
isAgentSpeaking: agent.isAgentSpeaking,
|
|
1714
|
+
error: agent.error
|
|
1715
|
+
};
|
|
1716
|
+
}
|
|
1717
|
+
function resolveStatusMessage(runtimeSnapshot, messages) {
|
|
1718
|
+
if (runtimeSnapshot.error) {
|
|
1719
|
+
return `${messages.errorPrefix}: ${runtimeSnapshot.error}`;
|
|
1720
|
+
}
|
|
1721
|
+
if (runtimeSnapshot.isAgentSpeaking) {
|
|
1722
|
+
return messages.speaking;
|
|
1723
|
+
}
|
|
1724
|
+
if (runtimeSnapshot.status === "connecting") {
|
|
1725
|
+
return messages.connecting;
|
|
1726
|
+
}
|
|
1727
|
+
if (runtimeSnapshot.status === "connected") {
|
|
1728
|
+
return messages.listening;
|
|
1729
|
+
}
|
|
1730
|
+
return messages.idle;
|
|
1731
|
+
}
|
|
1732
|
+
function NavaiVoiceOrbDock({
|
|
1733
|
+
agent,
|
|
1734
|
+
className,
|
|
1735
|
+
style,
|
|
1736
|
+
themeMode = "dark",
|
|
1737
|
+
placement = "bottom-right",
|
|
1738
|
+
backgroundColorLight = "#f4f6fb",
|
|
1739
|
+
backgroundColorDark = "#060914",
|
|
1740
|
+
showStatus = true,
|
|
1741
|
+
messages
|
|
1742
|
+
}) {
|
|
1743
|
+
const resolvedMessages = (0, import_react6.useMemo)(() => ({ ...DEFAULT_MESSAGES, ...messages }), [messages]);
|
|
1744
|
+
const runtimeSnapshot = (0, import_react6.useMemo)(() => resolveNavaiVoiceOrbRuntimeSnapshot(agent), [agent]);
|
|
1745
|
+
const statusMessage = showStatus ? resolveStatusMessage(runtimeSnapshot, resolvedMessages) : "";
|
|
1746
|
+
const isError = runtimeSnapshot.status === "error" || Boolean(runtimeSnapshot.error);
|
|
1747
|
+
const isConnecting = runtimeSnapshot.status === "connecting";
|
|
1748
|
+
const isActive = runtimeSnapshot.status === "connecting" || runtimeSnapshot.status === "connected";
|
|
1749
|
+
const isDisabled = agent.isConnecting;
|
|
1750
|
+
const shouldAnimateOrb = runtimeSnapshot.status !== "error";
|
|
1751
|
+
const handleToggle = (0, import_react6.useCallback)(() => {
|
|
1752
|
+
if (agent.isConnecting) {
|
|
1753
|
+
return;
|
|
1754
|
+
}
|
|
1755
|
+
if (agent.isConnected) {
|
|
1756
|
+
agent.stop();
|
|
1757
|
+
return;
|
|
1758
|
+
}
|
|
1759
|
+
void agent.start();
|
|
1760
|
+
}, [agent]);
|
|
1761
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1762
|
+
NavaiMiniOrbDock,
|
|
1763
|
+
{
|
|
1764
|
+
className,
|
|
1765
|
+
style,
|
|
1766
|
+
themeMode,
|
|
1767
|
+
placement,
|
|
1768
|
+
isActive,
|
|
1769
|
+
isConnected: agent.isConnected,
|
|
1770
|
+
isDisabled,
|
|
1771
|
+
isAgentSpeaking: agent.isAgentSpeaking,
|
|
1772
|
+
animateOrb: shouldAnimateOrb,
|
|
1773
|
+
backgroundColor: themeMode === "light" ? backgroundColorLight : backgroundColorDark,
|
|
1774
|
+
buttonAriaLabel: isConnecting ? resolvedMessages.connecting : agent.isConnected ? resolvedMessages.ariaStop : resolvedMessages.ariaStart,
|
|
1775
|
+
buttonIcon: isConnecting ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(NavaiVoiceOrbDockSpinnerIcon, {}) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(NavaiVoiceOrbDockMicIcon, { isActive: agent.isConnected || agent.isAgentSpeaking }),
|
|
1776
|
+
onButtonClick: handleToggle,
|
|
1777
|
+
statusMessage,
|
|
1778
|
+
isError,
|
|
1779
|
+
ariaMessage: statusMessage
|
|
1780
|
+
}
|
|
1781
|
+
);
|
|
1782
|
+
}
|
|
1783
|
+
|
|
1784
|
+
// src/orb/NavaiVoiceHeroOrb.tsx
|
|
1785
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
1786
|
+
function NavaiVoiceHeroOrb({
|
|
1787
|
+
agent,
|
|
1788
|
+
themeMode = "dark",
|
|
1789
|
+
backgroundColorLight = "#ffffff",
|
|
1790
|
+
backgroundColorDark = "#000000",
|
|
1791
|
+
onRuntimeSnapshotChange,
|
|
1792
|
+
...orbProps
|
|
1793
|
+
}) {
|
|
1794
|
+
const runtimeSnapshot = resolveNavaiVoiceOrbRuntimeSnapshot(agent);
|
|
1795
|
+
(0, import_react7.useEffect)(() => {
|
|
1796
|
+
if (typeof onRuntimeSnapshotChange === "function") {
|
|
1797
|
+
onRuntimeSnapshotChange(runtimeSnapshot);
|
|
1798
|
+
}
|
|
1799
|
+
}, [onRuntimeSnapshotChange, runtimeSnapshot]);
|
|
1800
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1801
|
+
NavaiHeroOrb,
|
|
1802
|
+
{
|
|
1803
|
+
...orbProps,
|
|
1804
|
+
isAgentSpeaking: runtimeSnapshot.isAgentSpeaking,
|
|
1805
|
+
backgroundColor: themeMode === "light" ? backgroundColorLight : backgroundColorDark,
|
|
1806
|
+
className: themeMode === "light" ? "is-light" : ""
|
|
1807
|
+
}
|
|
1808
|
+
);
|
|
1809
|
+
}
|
|
854
1810
|
// Annotate the CommonJS export names for ESM import in node:
|
|
855
1811
|
0 && (module.exports = {
|
|
1812
|
+
NavaiHeroOrb,
|
|
1813
|
+
NavaiMiniOrbDock,
|
|
1814
|
+
NavaiVoiceHeroOrb,
|
|
1815
|
+
NavaiVoiceOrbDock,
|
|
1816
|
+
NavaiVoiceOrbDockMicIcon,
|
|
1817
|
+
Orb,
|
|
856
1818
|
buildNavaiAgent,
|
|
1819
|
+
clampNavaiOrbDelayMs,
|
|
857
1820
|
createNavaiBackendClient,
|
|
858
1821
|
getNavaiRoutePromptLines,
|
|
859
1822
|
loadNavaiFunctions,
|
|
860
1823
|
resolveNavaiFrontendRuntimeConfig,
|
|
861
1824
|
resolveNavaiRoute,
|
|
1825
|
+
resolveNavaiVoiceOrbRuntimeSnapshot,
|
|
862
1826
|
useWebVoiceAgent
|
|
863
1827
|
});
|