hanc-webrtc-widgets 2.1.6 → 2.1.8
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 +790 -114
- package/dist/hanc-webrtc-widgets.es.js +35614 -36104
- package/dist/hanc-webrtc-widgets.umd.js +773 -423
- package/dist/src/components/floating-call/floating-call.d.ts +48 -4
- package/dist/src/components/index.d.ts +6 -2
- package/dist/src/components/inline-call/inline-call.d.ts +47 -5
- package/dist/src/components/pill-call/index.d.ts +1 -1
- package/dist/src/components/pill-call/pill-call.d.ts +48 -3
- package/dist/src/core/orb/AudioAnalyzer.d.ts +78 -0
- package/dist/src/core/orb/OrbRenderer.d.ts +86 -0
- package/dist/src/core/orb/SoundManager.d.ts +55 -0
- package/dist/src/core/orb/colorPresets.d.ts +22 -0
- package/dist/src/core/orb/glow.glsl.d.ts +4 -0
- package/dist/src/core/orb/index.d.ts +12 -0
- package/dist/src/core/orb/orb.frag.glsl.d.ts +1 -0
- package/dist/src/core/orb/orb.vert.glsl.d.ts +1 -0
- package/dist/src/core/orb/themes.d.ts +53 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,166 +1,842 @@
|
|
|
1
1
|
# Hanc WebRTC Widgets
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Hanc WebRTC Widgets** is a Web Components library for easily integrating **Hanc AI voice call widgets** with stunning 3D audio-reactive orb visualizations into your website or web application.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
- Three.js + GLSL orb with real audio reactivity (agent voice, mic, or simulated)
|
|
7
|
-
- LiveKit calling flow with start/end sounds and clear state handling
|
|
8
|
-
- 3 display modes: inline (hero), float (docked), pill (compact CTA)
|
|
9
|
-
- Theme-aware color presets, custom palettes, and advanced orb tuning via JSON
|
|
10
|
-
- Web Components plus direct `HancAiWidget` class for low-level control
|
|
5
|
+
It provides ready-to-use, customizable, and lightweight UI widgets for initiating AI-driven voice calls, with beautiful WebGL-powered visual feedback that responds to both AI and user voice in real-time.
|
|
11
6
|
|
|
12
|
-
|
|
7
|
+
You can use it in **plain HTML**, or integrate it with **React**, **Next.js**, **Vue**, or any other modern frontend stack.
|
|
8
|
+
|
|
9
|
+
## ✨ Features
|
|
10
|
+
|
|
11
|
+
- 🎨 **Three Widget Types**: Inline, Floating, and Pill layouts
|
|
12
|
+
- 🌈 **Audio-Reactive 3D Orb**: WebGL-powered visualization responding to voice
|
|
13
|
+
- 🎭 **Color Presets**: Dark and light theme color palettes
|
|
14
|
+
- 🔧 **Highly Customizable**: Full control over colors, glow, animations, and behavior
|
|
15
|
+
- 🚀 **Zero Dependencies**: Works standalone or with any framework
|
|
16
|
+
- 📦 **Tiny Bundle**: Optimized for performance
|
|
17
|
+
- ♿ **Accessible**: Built with Web Components standards
|
|
18
|
+
- 🎯 **CLS Optimized**: No layout shifts
|
|
19
|
+
|
|
20
|
+
## Quick Start
|
|
21
|
+
|
|
22
|
+
### HTML (CDN)
|
|
13
23
|
|
|
14
24
|
```html
|
|
15
|
-
|
|
25
|
+
<!DOCTYPE html>
|
|
26
|
+
<html lang="en">
|
|
27
|
+
<head>
|
|
28
|
+
<meta charset="UTF-8" />
|
|
29
|
+
<script
|
|
30
|
+
src="https://unpkg.com/hanc-webrtc-widgets"
|
|
31
|
+
async
|
|
32
|
+
type="text/javascript"
|
|
33
|
+
></script>
|
|
34
|
+
</head>
|
|
35
|
+
<body>
|
|
36
|
+
<!-- Inline Call Widget -->
|
|
37
|
+
<hanc-ai-inline-call
|
|
38
|
+
agent-id="YOUR_AGENT_ID"
|
|
39
|
+
size="300"
|
|
40
|
+
></hanc-ai-inline-call>
|
|
41
|
+
|
|
42
|
+
<!-- Floating Call Widget (bottom-right corner) -->
|
|
43
|
+
<hanc-ai-floating-call
|
|
44
|
+
agent-id="YOUR_AGENT_ID"
|
|
45
|
+
position="bottom-right"
|
|
46
|
+
size="120"
|
|
47
|
+
></hanc-ai-floating-call>
|
|
48
|
+
|
|
49
|
+
<!-- Pill Widget (horizontal button) -->
|
|
50
|
+
<hanc-ai-pill-call
|
|
51
|
+
agent-id="YOUR_AGENT_ID"
|
|
52
|
+
button-start-text="Talk to AI Agent"
|
|
53
|
+
orb-size="48"
|
|
54
|
+
></hanc-ai-pill-call>
|
|
55
|
+
</body>
|
|
56
|
+
</html>
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### NPM Installation
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
npm install hanc-webrtc-widgets
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### React Example
|
|
66
|
+
|
|
67
|
+
1. Install dependencies:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
npm install @lit/react hanc-webrtc-widgets
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
2. Create React wrappers:
|
|
74
|
+
|
|
75
|
+
```tsx
|
|
76
|
+
import React from 'react';
|
|
77
|
+
import { createComponent } from '@lit/react';
|
|
78
|
+
import { InlineCall, FloatingCall, PillCall } from 'hanc-webrtc-widgets';
|
|
79
|
+
|
|
80
|
+
export const HancAiInlineCall = createComponent({
|
|
81
|
+
tagName: 'hanc-ai-inline-call',
|
|
82
|
+
elementClass: InlineCall,
|
|
83
|
+
react: React,
|
|
84
|
+
events: {
|
|
85
|
+
onCallStart: 'call-start',
|
|
86
|
+
onCallEnd: 'call-end',
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
export const HancAiFloatingCall = createComponent({
|
|
91
|
+
tagName: 'hanc-ai-floating-call',
|
|
92
|
+
elementClass: FloatingCall,
|
|
93
|
+
react: React,
|
|
94
|
+
events: {
|
|
95
|
+
onCallStart: 'call-start',
|
|
96
|
+
onCallEnd: 'call-end',
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
export const HancAiPillCall = createComponent({
|
|
101
|
+
tagName: 'hanc-ai-pill-call',
|
|
102
|
+
elementClass: PillCall,
|
|
103
|
+
react: React,
|
|
104
|
+
events: {
|
|
105
|
+
onCallStart: 'call-start',
|
|
106
|
+
onCallEnd: 'call-end',
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
3. Use in your components:
|
|
112
|
+
|
|
113
|
+
```tsx
|
|
114
|
+
import { darkPresets, lightPresets } from 'hanc-webrtc-widgets';
|
|
115
|
+
|
|
116
|
+
export default function Example() {
|
|
117
|
+
return (
|
|
118
|
+
<>
|
|
119
|
+
{/* Inline widget with custom colors */}
|
|
120
|
+
<HancAiInlineCall
|
|
121
|
+
agentId="YOUR_AGENT_ID"
|
|
122
|
+
size={300}
|
|
123
|
+
orbColors={darkPresets.emerald}
|
|
124
|
+
glowIntensity={1.2}
|
|
125
|
+
/>
|
|
126
|
+
|
|
127
|
+
{/* Floating widget in top-left */}
|
|
128
|
+
<HancAiFloatingCall
|
|
129
|
+
agentId="YOUR_AGENT_ID"
|
|
130
|
+
position="top-left"
|
|
131
|
+
orbColors={darkPresets.rose}
|
|
132
|
+
/>
|
|
133
|
+
|
|
134
|
+
{/* Pill button */}
|
|
135
|
+
<HancAiPillCall
|
|
136
|
+
agentId="YOUR_AGENT_ID"
|
|
137
|
+
buttonStartText="Talk to AI"
|
|
138
|
+
orbColors={lightPresets.indigo}
|
|
139
|
+
/>
|
|
140
|
+
</>
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Next.js Example
|
|
146
|
+
|
|
147
|
+
1. Install dependencies:
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
npm install @lit/react hanc-webrtc-widgets
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
2. Create a wrapper component with dynamic import:
|
|
154
|
+
|
|
155
|
+
```tsx
|
|
156
|
+
'use client';
|
|
157
|
+
|
|
158
|
+
import React from 'react';
|
|
159
|
+
import dynamic from 'next/dynamic';
|
|
160
|
+
import { createComponent } from '@lit/react';
|
|
161
|
+
|
|
162
|
+
export const HancAiInlineCall = dynamic(
|
|
163
|
+
async () => {
|
|
164
|
+
const { InlineCall } = await import('hanc-webrtc-widgets');
|
|
165
|
+
|
|
166
|
+
return createComponent({
|
|
167
|
+
tagName: 'hanc-ai-inline-call',
|
|
168
|
+
elementClass: InlineCall,
|
|
169
|
+
react: React,
|
|
170
|
+
events: {
|
|
171
|
+
onCallStart: 'call-start',
|
|
172
|
+
onCallEnd: 'call-end',
|
|
173
|
+
},
|
|
174
|
+
});
|
|
175
|
+
},
|
|
176
|
+
{ ssr: false }
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
export const HancAiFloatingCall = dynamic(
|
|
180
|
+
async () => {
|
|
181
|
+
const { FloatingCall } = await import('hanc-webrtc-widgets');
|
|
182
|
+
|
|
183
|
+
return createComponent({
|
|
184
|
+
tagName: 'hanc-ai-floating-call',
|
|
185
|
+
elementClass: FloatingCall,
|
|
186
|
+
react: React,
|
|
187
|
+
events: {
|
|
188
|
+
onCallStart: 'call-start',
|
|
189
|
+
onCallEnd: 'call-end',
|
|
190
|
+
},
|
|
191
|
+
});
|
|
192
|
+
},
|
|
193
|
+
{ ssr: false }
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
export const HancAiPillCall = dynamic(
|
|
197
|
+
async () => {
|
|
198
|
+
const { PillCall } = await import('hanc-webrtc-widgets');
|
|
199
|
+
|
|
200
|
+
return createComponent({
|
|
201
|
+
tagName: 'hanc-ai-pill-call',
|
|
202
|
+
elementClass: PillCall,
|
|
203
|
+
react: React,
|
|
204
|
+
events: {
|
|
205
|
+
onCallStart: 'call-start',
|
|
206
|
+
onCallEnd: 'call-end',
|
|
207
|
+
},
|
|
208
|
+
});
|
|
209
|
+
},
|
|
210
|
+
{ ssr: false }
|
|
211
|
+
);
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
3. Use in your pages:
|
|
215
|
+
|
|
216
|
+
```tsx
|
|
217
|
+
'use client';
|
|
218
|
+
|
|
219
|
+
import { HancAiInlineCall, HancAiFloatingCall, HancAiPillCall } from '@/components/hanc-widgets';
|
|
220
|
+
import { darkPresets } from 'hanc-webrtc-widgets';
|
|
221
|
+
|
|
222
|
+
export default function Home() {
|
|
223
|
+
return (
|
|
224
|
+
<main>
|
|
225
|
+
<HancAiInlineCall
|
|
226
|
+
agentId="YOUR_AGENT_ID"
|
|
227
|
+
orbColors={darkPresets.purple}
|
|
228
|
+
/>
|
|
229
|
+
|
|
230
|
+
<HancAiFloatingCall
|
|
231
|
+
agentId="YOUR_AGENT_ID"
|
|
232
|
+
position="bottom-right"
|
|
233
|
+
/>
|
|
234
|
+
</main>
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Vue Example
|
|
16
240
|
|
|
241
|
+
```vue
|
|
242
|
+
<script setup>
|
|
243
|
+
import { ref, onMounted } from 'vue';
|
|
244
|
+
import { darkPresets } from 'hanc-webrtc-widgets';
|
|
245
|
+
|
|
246
|
+
// Import components for side-effects (registers web components)
|
|
247
|
+
onMounted(async () => {
|
|
248
|
+
await import('hanc-webrtc-widgets');
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
const handleCallStart = () => {
|
|
252
|
+
console.log('Call started');
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
const handleCallEnd = () => {
|
|
256
|
+
console.log('Call ended');
|
|
257
|
+
};
|
|
258
|
+
</script>
|
|
259
|
+
|
|
260
|
+
<template>
|
|
261
|
+
<div>
|
|
262
|
+
<!-- Inline widget -->
|
|
263
|
+
<hanc-ai-inline-call
|
|
264
|
+
agent-id="YOUR_AGENT_ID"
|
|
265
|
+
:size="300"
|
|
266
|
+
@call-start="handleCallStart"
|
|
267
|
+
@call-end="handleCallEnd"
|
|
268
|
+
/>
|
|
269
|
+
|
|
270
|
+
<!-- Floating widget -->
|
|
271
|
+
<hanc-ai-floating-call
|
|
272
|
+
agent-id="YOUR_AGENT_ID"
|
|
273
|
+
position="bottom-right"
|
|
274
|
+
/>
|
|
275
|
+
|
|
276
|
+
<!-- Pill widget -->
|
|
277
|
+
<hanc-ai-pill-call
|
|
278
|
+
agent-id="YOUR_AGENT_ID"
|
|
279
|
+
button-start-text="Chat with AI"
|
|
280
|
+
/>
|
|
281
|
+
</div>
|
|
282
|
+
</template>
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
## Components
|
|
286
|
+
|
|
287
|
+
### `<hanc-ai-inline-call>`
|
|
288
|
+
|
|
289
|
+
An inline widget that embeds directly in your page content. Features a large, prominent orb visualization with button overlay.
|
|
290
|
+
|
|
291
|
+
#### Quick Start Attributes
|
|
292
|
+
|
|
293
|
+
The essentials to get started:
|
|
294
|
+
|
|
295
|
+
| Attribute | Type | Default | Description |
|
|
296
|
+
|-----------|------|---------|-------------|
|
|
297
|
+
| `agent-id` **(required)** | string | - | Your Hanc AI agent ID |
|
|
298
|
+
| `theme` | string | `"default"` | Theme name: `"default"`, `"emerald"`, `"rose"`, `"amber"`, `"cyan"`, `"purple"`, `"blue"` |
|
|
299
|
+
| `theme-mode` | string | `"auto"` | `"auto"` (system), `"dark"`, or `"light"` |
|
|
300
|
+
| `size` | number | `370` | Container size in pixels (responsive - scales down on smaller screens) |
|
|
301
|
+
| `container-padding` | number | `45` | Padding around orb (orb size = size - padding * 2) |
|
|
302
|
+
| `button-start-text` | string | `"Start Call"` | Button text |
|
|
303
|
+
|
|
304
|
+
#### All Attributes
|
|
305
|
+
|
|
306
|
+
| Attribute | Type | Default | Description |
|
|
307
|
+
|-----------|------|---------|-------------|
|
|
308
|
+
| `agent-id` **(required)** | string | - | Hanc AI agent ID |
|
|
309
|
+
| `voice-service-url` | string | - | Optional custom voice service URL |
|
|
310
|
+
| `button-start-text` | string | `"Start Call"` | Button text in idle state |
|
|
311
|
+
| `button-connecting-text` | string | `"Connecting..."` | Button text when connecting |
|
|
312
|
+
| `size` | number | `370` | Container size in pixels (responsive on small screens) |
|
|
313
|
+
| `container-padding` | number | `45` | Padding around orb (orb size = size - padding * 2) |
|
|
314
|
+
| `theme` | string | `"default"` | Theme name (e.g., "emerald", "rose") - see Themes section |
|
|
315
|
+
| `theme-mode` | string | `"auto"` | Theme mode: `"auto"`, `"dark"`, or `"light"` |
|
|
316
|
+
| `orb-colors` | object | Default preset | Color configuration object (see Color Presets) |
|
|
317
|
+
| `glow-intensity` | number | `0.8` | Glow effect strength (0-2) |
|
|
318
|
+
| `idle-glow-multiplier` | number | `0.4` | Glow multiplier in idle state |
|
|
319
|
+
| `morph-strength` | number | `1.0` | Audio-driven deformation strength |
|
|
320
|
+
| `noise-scale` | number | `1.5` | Noise pattern scale |
|
|
321
|
+
| `noise-speed` | number | `0.3` | Noise animation speed |
|
|
322
|
+
| `fresnel-power` | number | `2.5` | Edge glow (Fresnel) effect power |
|
|
323
|
+
| `rotation-speed` | number | `0.1` | Orb rotation speed |
|
|
324
|
+
| `audio-reactivity` | number | `3.0` | Audio response multiplier |
|
|
325
|
+
| `audio-smoothing` | number | `0.9` | Audio smoothing (0.1 = slow, 1.0 = instant) |
|
|
326
|
+
| `idle-morph-multiplier` | number | `0.25` | Morph strength in idle state |
|
|
327
|
+
| `color-contrast` | number | `1.5` | Color pattern sharpness |
|
|
328
|
+
|
|
329
|
+
#### Events
|
|
330
|
+
|
|
331
|
+
| Event | Description |
|
|
332
|
+
|-------|-------------|
|
|
333
|
+
| `call-start` | Fired when call successfully connects |
|
|
334
|
+
| `call-end` | Fired when call ends |
|
|
335
|
+
|
|
336
|
+
#### CSS Parts
|
|
337
|
+
|
|
338
|
+
| Part | Description |
|
|
339
|
+
|------|-------------|
|
|
340
|
+
| `container` | Outer container |
|
|
341
|
+
| `orb-container` | Orb canvas container |
|
|
342
|
+
| `button` | Call button |
|
|
343
|
+
|
|
344
|
+
#### Example
|
|
345
|
+
|
|
346
|
+
```html
|
|
17
347
|
<hanc-ai-inline-call
|
|
18
348
|
agent-id="YOUR_AGENT_ID"
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
349
|
+
size="300"
|
|
350
|
+
button-start-text="Talk to AI"
|
|
351
|
+
glow-intensity="1.2"
|
|
352
|
+
audio-reactivity="4.0"
|
|
23
353
|
></hanc-ai-inline-call>
|
|
354
|
+
|
|
355
|
+
<script type="module">
|
|
356
|
+
import { darkPresets } from 'https://unpkg.com/hanc-webrtc-widgets';
|
|
357
|
+
|
|
358
|
+
const widget = document.querySelector('hanc-ai-inline-call');
|
|
359
|
+
widget.orbColors = darkPresets.emerald;
|
|
360
|
+
|
|
361
|
+
widget.addEventListener('call-start', () => {
|
|
362
|
+
console.log('Call started!');
|
|
363
|
+
});
|
|
364
|
+
</script>
|
|
24
365
|
```
|
|
25
366
|
|
|
26
|
-
|
|
367
|
+
---
|
|
368
|
+
|
|
369
|
+
### `<hanc-ai-floating-call>`
|
|
370
|
+
|
|
371
|
+
A floating widget that stays fixed in a corner of the viewport. Perfect for persistent AI assistant access.
|
|
372
|
+
|
|
373
|
+
#### Quick Start Attributes
|
|
374
|
+
|
|
375
|
+
The essentials to get started:
|
|
376
|
+
|
|
377
|
+
| Attribute | Type | Default | Description |
|
|
378
|
+
|-----------|------|---------|-------------|
|
|
379
|
+
| `agent-id` **(required)** | string | - | Your Hanc AI agent ID |
|
|
380
|
+
| `position` | string | `"bottom-right"` | Corner position: `"bottom-right"`, `"bottom-left"`, `"top-right"`, `"top-left"` |
|
|
381
|
+
| `theme` | string | `"default"` | Theme name: `"default"`, `"emerald"`, `"rose"`, `"amber"`, `"cyan"`, `"purple"`, `"blue"` |
|
|
382
|
+
| `theme-mode` | string | `"auto"` | `"auto"` (system), `"dark"`, or `"light"` |
|
|
383
|
+
| `size` | number | `120` | Widget size in pixels |
|
|
384
|
+
|
|
385
|
+
#### All Attributes
|
|
386
|
+
|
|
387
|
+
All attributes from `<hanc-ai-inline-call>`, plus:
|
|
388
|
+
|
|
389
|
+
| Attribute | Type | Default | Description |
|
|
390
|
+
|-----------|------|---------|-------------|
|
|
391
|
+
| `position` | string | `"bottom-right"` | Corner position: `"bottom-right"`, `"bottom-left"`, `"top-right"`, `"top-left"`, or `"static"` |
|
|
392
|
+
| `button-start-text` | string | `"Call"` | Shorter default text for compact layout |
|
|
393
|
+
| `size` | number | `120` | Widget size in pixels (smaller default) |
|
|
394
|
+
| `theme` | string | `"default"` | Theme name - see Themes section |
|
|
395
|
+
| `theme-mode` | string | `"auto"` | Theme mode: `"auto"`, `"dark"`, or `"light"` |
|
|
396
|
+
|
|
397
|
+
#### Example
|
|
27
398
|
|
|
28
399
|
```html
|
|
29
|
-
<!--
|
|
400
|
+
<!-- Bottom-right corner (default) -->
|
|
401
|
+
<hanc-ai-floating-call
|
|
402
|
+
agent-id="YOUR_AGENT_ID"
|
|
403
|
+
position="bottom-right"
|
|
404
|
+
></hanc-ai-floating-call>
|
|
405
|
+
|
|
406
|
+
<!-- Top-left corner with custom size -->
|
|
30
407
|
<hanc-ai-floating-call
|
|
31
408
|
agent-id="YOUR_AGENT_ID"
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
theme="auto"
|
|
409
|
+
position="top-left"
|
|
410
|
+
size="150"
|
|
35
411
|
></hanc-ai-floating-call>
|
|
36
412
|
|
|
37
|
-
<!--
|
|
413
|
+
<!-- Static positioning (for custom layouts) -->
|
|
414
|
+
<hanc-ai-floating-call
|
|
415
|
+
agent-id="YOUR_AGENT_ID"
|
|
416
|
+
position="static"
|
|
417
|
+
></hanc-ai-floating-call>
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
---
|
|
421
|
+
|
|
422
|
+
### `<hanc-ai-pill-call>`
|
|
423
|
+
|
|
424
|
+
A horizontal pill-shaped button with orb on the left side. Ideal for minimal interfaces and inline CTAs.
|
|
425
|
+
|
|
426
|
+
#### Quick Start Attributes
|
|
427
|
+
|
|
428
|
+
The essentials to get started:
|
|
429
|
+
|
|
430
|
+
| Attribute | Type | Default | Description |
|
|
431
|
+
|-----------|------|---------|-------------|
|
|
432
|
+
| `agent-id` **(required)** | string | - | Your Hanc AI agent ID |
|
|
433
|
+
| `theme` | string | `"default"` | Theme name: `"default"`, `"emerald"`, `"rose"`, `"amber"`, `"cyan"`, `"purple"`, `"blue"` |
|
|
434
|
+
| `theme-mode` | string | `"auto"` | `"auto"` (system), `"dark"`, or `"light"` |
|
|
435
|
+
| `button-start-text` | string | `"Talk to AI Agent"` | Button text when idle |
|
|
436
|
+
| `orb-size` | number | `48` | Orb diameter in pixels |
|
|
437
|
+
|
|
438
|
+
#### All Attributes
|
|
439
|
+
|
|
440
|
+
Same attributes as `<hanc-ai-inline-call>`, plus:
|
|
441
|
+
|
|
442
|
+
| Attribute | Type | Default | Description |
|
|
443
|
+
|-----------|------|---------|-------------|
|
|
444
|
+
| `button-start-text` | string | `"Talk to AI Agent"` | Button text in idle state |
|
|
445
|
+
| `button-end-text` | string | `"End call"` | Button text when connected |
|
|
446
|
+
| `orb-size` | number | `48` | Orb diameter in pixels |
|
|
447
|
+
| `theme` | string | `"default"` | Theme name - see Themes section |
|
|
448
|
+
| `theme-mode` | string | `"auto"` | Theme mode: `"auto"`, `"dark"`, or `"light"` |
|
|
449
|
+
|
|
450
|
+
#### Example
|
|
451
|
+
|
|
452
|
+
```html
|
|
38
453
|
<hanc-ai-pill-call
|
|
39
454
|
agent-id="YOUR_AGENT_ID"
|
|
40
|
-
|
|
41
|
-
button-text="
|
|
42
|
-
|
|
43
|
-
color-preset="rose"
|
|
455
|
+
button-start-text="Chat with Support"
|
|
456
|
+
button-end-text="End Chat"
|
|
457
|
+
orb-size="48"
|
|
44
458
|
></hanc-ai-pill-call>
|
|
459
|
+
|
|
460
|
+
<script type="module">
|
|
461
|
+
import { lightPresets } from 'https://unpkg.com/hanc-webrtc-widgets';
|
|
462
|
+
|
|
463
|
+
const pill = document.querySelector('hanc-ai-pill-call');
|
|
464
|
+
pill.orbColors = lightPresets.violet;
|
|
465
|
+
pill.glowIntensity = 1.5;
|
|
466
|
+
pill.idleGlowMultiplier = 1.0; // Brighter for light backgrounds
|
|
467
|
+
</script>
|
|
45
468
|
```
|
|
46
469
|
|
|
47
|
-
|
|
48
|
-
- `agent-id` *(string, required for real calls)*
|
|
49
|
-
- `voice-service-url` *(string, required for real calls)*
|
|
50
|
-
- `size` *(number, default 280 — not used in pill mode)*
|
|
51
|
-
- `mode` *(inline \| float \| pill — only on `<hanc-ai-orb>`)*
|
|
52
|
-
- `position` *(center \| bottom-right \| bottom-left \| top-right \| top-left — used in float mode)*
|
|
53
|
-
- `button-text` / `active-button-text` / `connecting-text` *(strings)*
|
|
54
|
-
- `color-preset` *(indigo | cyan | emerald | rose | amber — uses dark/light versions automatically when `theme="auto"`)*
|
|
55
|
-
- `colors` *(JSON string `{"primary":"#...","secondary":"#..."}` to override the preset)*
|
|
56
|
-
- `orb-config` *(JSON string for advanced control: `morphStrength`, `glowIntensity`, `audioReactivity`, `idleGlowMultiplier`, etc.)*
|
|
57
|
-
- `theme` *(`auto` | `dark` | `light`, default `auto` — adjusts palette and glow)*
|
|
58
|
-
- `enable-sounds` *(boolean, default true)*
|
|
59
|
-
- `sound-volume` *(number 0.0–1.0, default 0.3)*
|
|
60
|
-
- Legacy aliases are still accepted: `button-start-text`, `button-end-text`, `button-connecting-text`.
|
|
61
|
-
|
|
62
|
-
### Events
|
|
63
|
-
- `call-start` — `{ agentId, timestamp }`
|
|
64
|
-
- `call-end` — `{ agentId, duration, reason, timestamp }`
|
|
65
|
-
- `state-change` — `{ state: 'idle' | 'connecting' | 'active' | 'ending' | 'error', previousState }`
|
|
66
|
-
- `error` — `{ error }`
|
|
67
|
-
|
|
68
|
-
```js
|
|
69
|
-
const orb = document.querySelector('hanc-ai-inline-call');
|
|
70
|
-
|
|
71
|
-
orb.addEventListener('state-change', e => {
|
|
72
|
-
console.log('state', e.detail.state);
|
|
73
|
-
});
|
|
470
|
+
---
|
|
74
471
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
472
|
+
## Color Presets
|
|
473
|
+
|
|
474
|
+
The library includes professional color presets optimized for dark and light backgrounds.
|
|
475
|
+
|
|
476
|
+
### Using Presets
|
|
477
|
+
|
|
478
|
+
```javascript
|
|
479
|
+
import { darkPresets, lightPresets, getColorPreset } from 'hanc-webrtc-widgets';
|
|
480
|
+
|
|
481
|
+
// Apply a preset
|
|
482
|
+
const widget = document.querySelector('hanc-ai-inline-call');
|
|
483
|
+
widget.orbColors = darkPresets.emerald;
|
|
484
|
+
|
|
485
|
+
// Or use the helper function
|
|
486
|
+
widget.orbColors = getColorPreset('rose', 'dark');
|
|
78
487
|
```
|
|
79
488
|
|
|
80
|
-
|
|
489
|
+
### Dark Theme Presets
|
|
81
490
|
|
|
82
|
-
|
|
491
|
+
Optimized for dark backgrounds (default for floating/inline widgets):
|
|
83
492
|
|
|
84
|
-
|
|
85
|
-
|
|
493
|
+
- `default` - Indigo/Purple/Cyan
|
|
494
|
+
- `emerald` - Emerald green tones
|
|
495
|
+
- `rose` - Rose/Pink tones
|
|
496
|
+
- `amber` - Warm amber/orange
|
|
497
|
+
- `cyan` - Cool cyan/turquoise
|
|
498
|
+
- `purple` - Deep purple/violet
|
|
499
|
+
- `blue` - Classic blue
|
|
86
500
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
501
|
+
### Light Theme Presets
|
|
502
|
+
|
|
503
|
+
Optimized for light backgrounds (default for pill widget):
|
|
504
|
+
|
|
505
|
+
- `indigo` - Deep indigo
|
|
506
|
+
- `violet` - Rich violet
|
|
507
|
+
- `teal` - Ocean teal
|
|
508
|
+
- `orange` - Warm orange
|
|
509
|
+
- `blue` - Vibrant blue
|
|
510
|
+
- `pink` - Hot pink
|
|
511
|
+
|
|
512
|
+
### Custom Colors
|
|
513
|
+
|
|
514
|
+
```javascript
|
|
515
|
+
const widget = document.querySelector('hanc-ai-inline-call');
|
|
516
|
+
|
|
517
|
+
widget.orbColors = {
|
|
518
|
+
primary: '#6366f1', // Main orb color
|
|
519
|
+
secondary: '#8b5cf6', // Secondary color for patterns
|
|
520
|
+
accent: '#06b6d4', // Accent highlights
|
|
521
|
+
glow: '#818cf8', // Outer glow color
|
|
522
|
+
atmosphere: '#c4b5fd', // Atmospheric haze
|
|
523
|
+
depth: '#312e81', // Deep shadow color
|
|
524
|
+
highlight: '#e0e7ff' // Bright highlight color
|
|
525
|
+
};
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
### Glow Settings for Different Backgrounds
|
|
529
|
+
|
|
530
|
+
```javascript
|
|
531
|
+
// For dark backgrounds
|
|
532
|
+
widget.glowIntensity = 0.8;
|
|
533
|
+
widget.idleGlowMultiplier = 0.4;
|
|
534
|
+
|
|
535
|
+
// For light backgrounds (more visible)
|
|
536
|
+
widget.glowIntensity = 1.5;
|
|
537
|
+
widget.idleGlowMultiplier = 1.0;
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
---
|
|
541
|
+
|
|
542
|
+
## Themes
|
|
543
|
+
|
|
544
|
+
Themes combine colors and glow settings into ready-to-use configurations. Each theme includes both dark and light variants that **automatically detect and match your system's color scheme** by default.
|
|
101
545
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
546
|
+
### Using Themes with Attributes
|
|
547
|
+
|
|
548
|
+
The simplest way - just set the `theme` attribute:
|
|
549
|
+
|
|
550
|
+
```html
|
|
551
|
+
<!-- Auto theme (default) - automatically switches between dark/light based on system -->
|
|
552
|
+
<hanc-ai-inline-call
|
|
553
|
+
agent-id="YOUR_AGENT_ID"
|
|
554
|
+
theme="emerald"
|
|
555
|
+
theme-mode="auto"
|
|
556
|
+
></hanc-ai-inline-call>
|
|
557
|
+
|
|
558
|
+
<!-- Or force a specific mode -->
|
|
559
|
+
<hanc-ai-pill-call
|
|
560
|
+
agent-id="YOUR_AGENT_ID"
|
|
561
|
+
theme="rose"
|
|
562
|
+
theme-mode="dark"
|
|
563
|
+
></hanc-ai-pill-call>
|
|
564
|
+
|
|
565
|
+
<!-- theme-mode="auto" is the default, so you can omit it -->
|
|
566
|
+
<hanc-ai-floating-call
|
|
567
|
+
agent-id="YOUR_AGENT_ID"
|
|
568
|
+
theme="cyan"
|
|
569
|
+
></hanc-ai-floating-call>
|
|
108
570
|
```
|
|
109
571
|
|
|
110
|
-
###
|
|
111
|
-
- `connectAudioStream(stream: MediaStream)` — drive the orb from any audio stream
|
|
112
|
-
- `connectMicrophone()` / `disconnectMicrophone()` — mic-driven visuals (demo mode)
|
|
113
|
-
- `isConnected()` / `getState()` — quick state checks
|
|
572
|
+
### Using Themes with JavaScript
|
|
114
573
|
|
|
115
|
-
|
|
574
|
+
```javascript
|
|
575
|
+
import { themes, getTheme, applyTheme, detectSystemTheme, watchSystemTheme } from 'hanc-webrtc-widgets';
|
|
116
576
|
|
|
117
|
-
|
|
577
|
+
// Get a complete theme configuration (auto-detects system by default)
|
|
578
|
+
const theme = getTheme('emerald', 'auto');
|
|
579
|
+
console.log(theme);
|
|
580
|
+
// {
|
|
581
|
+
// colors: { primary: '#10b981', secondary: '#34d399', ... },
|
|
582
|
+
// glowIntensity: 1.2,
|
|
583
|
+
// idleGlowMultiplier: 0.6
|
|
584
|
+
// }
|
|
118
585
|
|
|
586
|
+
// Detect system theme
|
|
587
|
+
const systemTheme = detectSystemTheme(); // Returns 'dark' or 'light'
|
|
588
|
+
|
|
589
|
+
// Apply theme to a widget
|
|
590
|
+
const widget = document.querySelector('hanc-ai-inline-call');
|
|
591
|
+
applyTheme(widget, 'rose', 'auto');
|
|
592
|
+
|
|
593
|
+
// Watch for system theme changes and update automatically
|
|
594
|
+
const stopWatching = watchSystemTheme(widget, 'emerald');
|
|
595
|
+
// Call stopWatching() to cleanup when done
|
|
596
|
+
|
|
597
|
+
// Or access theme structure directly
|
|
598
|
+
const emeraldTheme = themes.emerald;
|
|
599
|
+
widget.orbColors = emeraldTheme.dark.colors;
|
|
600
|
+
widget.glowIntensity = emeraldTheme.dark.glowIntensity;
|
|
119
601
|
```
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
602
|
+
|
|
603
|
+
### Available Themes
|
|
604
|
+
|
|
605
|
+
All themes include both dark and light variants that automatically switch based on system preference:
|
|
606
|
+
|
|
607
|
+
- `default` - Indigo/Purple/Cyan (subtle in dark, vibrant in light)
|
|
608
|
+
- `emerald` - Fresh emerald green tones
|
|
609
|
+
- `rose` - Elegant rose/pink palette
|
|
610
|
+
- `amber` - Warm amber/orange hues
|
|
611
|
+
- `cyan` - Cool cyan/turquoise shades
|
|
612
|
+
- `purple` - Deep purple/violet colors
|
|
613
|
+
- `blue` - Classic blue spectrum
|
|
614
|
+
|
|
615
|
+
**Dark variants** are optimized for dark backgrounds with subtle glow.
|
|
616
|
+
**Light variants** are optimized for light backgrounds with stronger, more visible glow.
|
|
617
|
+
|
|
618
|
+
### Automatic System Theme Detection
|
|
619
|
+
|
|
620
|
+
The widgets automatically detect and respond to your system's color scheme preference:
|
|
621
|
+
|
|
622
|
+
```javascript
|
|
623
|
+
import { detectSystemTheme, watchSystemTheme } from 'hanc-webrtc-widgets';
|
|
624
|
+
|
|
625
|
+
// Check current system preference
|
|
626
|
+
const isDark = detectSystemTheme() === 'dark';
|
|
627
|
+
|
|
628
|
+
// Automatically update widget when system theme changes
|
|
629
|
+
const widget = document.querySelector('hanc-ai-inline-call');
|
|
630
|
+
const cleanup = watchSystemTheme(widget, 'emerald');
|
|
631
|
+
|
|
632
|
+
// The widget will now automatically switch between
|
|
633
|
+
// emerald.dark and emerald.light based on system preference
|
|
634
|
+
|
|
635
|
+
// Cleanup when component unmounts
|
|
636
|
+
cleanup();
|
|
123
637
|
```
|
|
124
638
|
|
|
125
|
-
|
|
639
|
+
### Theme vs Manual Configuration
|
|
126
640
|
|
|
127
|
-
|
|
641
|
+
**Use Themes when:**
|
|
642
|
+
- You want quick, professional-looking results
|
|
643
|
+
- You need consistent styling across light/dark backgrounds
|
|
644
|
+
- You want the recommended glow settings
|
|
128
645
|
|
|
129
|
-
|
|
646
|
+
**Use Manual Configuration when:**
|
|
647
|
+
- You need precise control over individual colors
|
|
648
|
+
- You want custom brand colors
|
|
649
|
+
- You're fine-tuning for specific design requirements
|
|
130
650
|
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
651
|
+
```html
|
|
652
|
+
<!-- Using theme (quick and easy) - auto-detects system preference -->
|
|
653
|
+
<hanc-ai-inline-call
|
|
654
|
+
agent-id="YOUR_AGENT_ID"
|
|
655
|
+
theme="emerald"
|
|
656
|
+
></hanc-ai-inline-call>
|
|
135
657
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
658
|
+
<!-- Using theme with forced mode -->
|
|
659
|
+
<hanc-ai-inline-call
|
|
660
|
+
agent-id="YOUR_AGENT_ID"
|
|
661
|
+
theme="rose"
|
|
662
|
+
theme-mode="dark"
|
|
663
|
+
></hanc-ai-inline-call>
|
|
142
664
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
665
|
+
<!-- Manual configuration (full control) -->
|
|
666
|
+
<hanc-ai-inline-call
|
|
667
|
+
agent-id="YOUR_AGENT_ID"
|
|
668
|
+
glow-intensity="1.2"
|
|
669
|
+
idle-glow-multiplier="0.6"
|
|
670
|
+
></hanc-ai-inline-call>
|
|
671
|
+
|
|
672
|
+
<script type="module">
|
|
673
|
+
const widget = document.querySelector('hanc-ai-inline-call:last-of-type');
|
|
674
|
+
widget.orbColors = {
|
|
675
|
+
primary: '#custom',
|
|
676
|
+
secondary: '#colors',
|
|
677
|
+
// ...
|
|
678
|
+
};
|
|
679
|
+
</script>
|
|
680
|
+
```
|
|
681
|
+
|
|
682
|
+
---
|
|
683
|
+
|
|
684
|
+
## Advanced Configuration
|
|
685
|
+
|
|
686
|
+
### Audio Reactivity Tuning
|
|
687
|
+
|
|
688
|
+
```html
|
|
689
|
+
<hanc-ai-inline-call
|
|
690
|
+
agent-id="YOUR_AGENT_ID"
|
|
691
|
+
audio-reactivity="4.0"
|
|
692
|
+
audio-smoothing="0.85"
|
|
693
|
+
morph-strength="1.2"
|
|
694
|
+
></hanc-ai-inline-call>
|
|
695
|
+
```
|
|
696
|
+
|
|
697
|
+
- **`audio-reactivity`**: Higher values = stronger visual response (1.0 - 5.0)
|
|
698
|
+
- **`audio-smoothing`**: Lower = smoother, Higher = snappier (0.1 - 1.0)
|
|
699
|
+
- **`morph-strength`**: Audio-driven deformation intensity (0.5 - 2.0)
|
|
700
|
+
|
|
701
|
+
### Visual Effects
|
|
702
|
+
|
|
703
|
+
```html
|
|
704
|
+
<hanc-ai-inline-call
|
|
705
|
+
agent-id="YOUR_AGENT_ID"
|
|
706
|
+
glow-intensity="1.5"
|
|
707
|
+
fresnel-power="3.0"
|
|
708
|
+
color-contrast="2.0"
|
|
709
|
+
noise-scale="2.0"
|
|
710
|
+
></hanc-ai-inline-call>
|
|
711
|
+
```
|
|
712
|
+
|
|
713
|
+
- **`glow-intensity`**: Outer glow strength (0.5 - 2.0)
|
|
714
|
+
- **`fresnel-power`**: Edge highlight intensity (1.0 - 5.0)
|
|
715
|
+
- **`color-contrast`**: Color pattern sharpness (1.0 - 3.0)
|
|
716
|
+
- **`noise-scale`**: Pattern detail level (1.0 - 3.0)
|
|
717
|
+
|
|
718
|
+
### Idle Animation
|
|
719
|
+
|
|
720
|
+
```html
|
|
721
|
+
<hanc-ai-inline-call
|
|
722
|
+
agent-id="YOUR_AGENT_ID"
|
|
723
|
+
idle-morph-multiplier="0.5"
|
|
724
|
+
idle-glow-multiplier="0.6"
|
|
725
|
+
rotation-speed="0.2"
|
|
726
|
+
noise-speed="0.5"
|
|
727
|
+
></hanc-ai-inline-call>
|
|
728
|
+
```
|
|
729
|
+
|
|
730
|
+
- **`idle-morph-multiplier`**: Movement in idle state (0 - 1.0)
|
|
731
|
+
- **`idle-glow-multiplier`**: Glow visibility when idle (0 - 1.0)
|
|
732
|
+
- **`rotation-speed`**: Rotation animation speed (0 - 1.0)
|
|
733
|
+
- **`noise-speed`**: Pattern animation speed (0 - 1.0)
|
|
734
|
+
|
|
735
|
+
---
|
|
736
|
+
|
|
737
|
+
## Styling with CSS
|
|
738
|
+
|
|
739
|
+
All widgets support CSS parts for custom styling:
|
|
740
|
+
|
|
741
|
+
```css
|
|
742
|
+
/* Style the button */
|
|
743
|
+
hanc-ai-inline-call::part(button) {
|
|
744
|
+
font-family: 'Inter', sans-serif;
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
/* Change container background */
|
|
748
|
+
hanc-ai-floating-call::part(container) {
|
|
749
|
+
background: rgba(0, 0, 0, 0.1);
|
|
750
|
+
backdrop-filter: blur(10px);
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
/* Style the pill button */
|
|
754
|
+
hanc-ai-pill-call::part(pill-button) {
|
|
755
|
+
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
|
|
756
|
+
}
|
|
757
|
+
```
|
|
758
|
+
|
|
759
|
+
---
|
|
760
|
+
|
|
761
|
+
## Events
|
|
762
|
+
|
|
763
|
+
All widgets emit the same events:
|
|
764
|
+
|
|
765
|
+
### `call-start`
|
|
766
|
+
|
|
767
|
+
Fired when the AI call successfully connects.
|
|
768
|
+
|
|
769
|
+
```javascript
|
|
770
|
+
widget.addEventListener('call-start', () => {
|
|
771
|
+
console.log('Call started');
|
|
772
|
+
// Update UI, start timer, etc.
|
|
148
773
|
});
|
|
774
|
+
```
|
|
149
775
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
776
|
+
### `call-end`
|
|
777
|
+
|
|
778
|
+
Fired when the call ends (user hangup or error).
|
|
779
|
+
|
|
780
|
+
```javascript
|
|
781
|
+
widget.addEventListener('call-end', () => {
|
|
782
|
+
console.log('Call ended');
|
|
783
|
+
// Clean up, show feedback form, etc.
|
|
155
784
|
});
|
|
156
785
|
```
|
|
157
786
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
-
|
|
787
|
+
---
|
|
788
|
+
|
|
789
|
+
## Browser Support
|
|
790
|
+
|
|
791
|
+
- ✅ Chrome/Edge 90+
|
|
792
|
+
- ✅ Firefox 88+
|
|
793
|
+
- ✅ Safari 15.4+
|
|
794
|
+
- ✅ Opera 76+
|
|
795
|
+
|
|
796
|
+
Requires support for:
|
|
797
|
+
- Web Components (Custom Elements v1)
|
|
798
|
+
- Shadow DOM v1
|
|
799
|
+
- WebGL 2.0
|
|
800
|
+
- Web Audio API
|
|
801
|
+
- WebRTC
|
|
802
|
+
|
|
803
|
+
---
|
|
804
|
+
|
|
805
|
+
## Performance
|
|
806
|
+
|
|
807
|
+
- **Bundle Size**: ~320KB gzipped (includes Three.js for WebGL rendering)
|
|
808
|
+
- **Performance**: 60 FPS on modern hardware
|
|
809
|
+
- **CLS Optimized**: Fixed dimensions prevent layout shifts
|
|
810
|
+
- **Lazy Loading**: Load widgets on demand with dynamic imports
|
|
811
|
+
|
|
812
|
+
---
|
|
813
|
+
|
|
814
|
+
## TypeScript
|
|
815
|
+
|
|
816
|
+
Full TypeScript support with exported types:
|
|
817
|
+
|
|
818
|
+
```typescript
|
|
819
|
+
import type { OrbColors } from 'hanc-webrtc-widgets';
|
|
820
|
+
|
|
821
|
+
const customColors: OrbColors = {
|
|
822
|
+
primary: '#6366f1',
|
|
823
|
+
secondary: '#8b5cf6',
|
|
824
|
+
accent: '#06b6d4',
|
|
825
|
+
glow: '#818cf8',
|
|
826
|
+
atmosphere: '#c4b5fd',
|
|
827
|
+
depth: '#312e81',
|
|
828
|
+
highlight: '#e0e7ff'
|
|
829
|
+
};
|
|
830
|
+
```
|
|
831
|
+
|
|
832
|
+
---
|
|
163
833
|
|
|
164
834
|
## License
|
|
165
835
|
|
|
166
836
|
MIT
|
|
837
|
+
|
|
838
|
+
---
|
|
839
|
+
|
|
840
|
+
## Support
|
|
841
|
+
|
|
842
|
+
For issues, questions, or feature requests, please visit our [GitHub repository](https://github.com/hanc-ai/hanc-webrtc-widget).
|