hanc-webrtc-widgets 2.1.5 → 2.1.7

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 CHANGED
@@ -1,166 +1,842 @@
1
1
  # Hanc WebRTC Widgets
2
2
 
3
- Audio-reactive AI call widgets powered by the **hanc-ai-orb** renderer and LiveKit voice calls. Ship a glossy, stateful orb that reacts to voice, respects system themes, and exposes a full programmatic API.
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
- ## Highlights
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
- ## Quick Start (Web Component)
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
- <script type="module" src="https://unpkg.com/hanc-webrtc-widgets"></script>
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
- voice-service-url="https://voice.hanc.ai"
20
- size="320"
21
- color-preset="indigo"
22
- theme="auto"
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
- ### Other layouts
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
- <!-- Floating orb -->
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
- voice-service-url="https://voice.hanc.ai"
33
- color-preset="cyan"
34
- theme="auto"
409
+ position="top-left"
410
+ size="150"
35
411
  ></hanc-ai-floating-call>
36
412
 
37
- <!-- Pill CTA -->
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
- voice-service-url="https://voice.hanc.ai"
41
- button-text="Talk to AI"
42
- active-button-text="End call"
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
- ### Attributes (shared across widgets)
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
- orb.addEventListener('call-start', e => {
76
- console.log('connected to', e.detail.agentId);
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
- ## Direct API (HancAiWidget)
489
+ ### Dark Theme Presets
81
490
 
82
- Import the low-level class when you need manual control, external media streams, or custom placement.
491
+ Optimized for dark backgrounds (default for floating/inline widgets):
83
492
 
84
- ```ts
85
- import { HancAiWidget } from 'hanc-webrtc-widgets';
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
- const widget = new HancAiWidget('#container', {
88
- agentId: 'YOUR_AGENT_ID',
89
- voiceServiceUrl: 'https://voice.hanc.ai',
90
- mode: 'float',
91
- position: 'bottom-right',
92
- size: 280,
93
- buttonText: 'Start call',
94
- activeButtonText: 'End call',
95
- colors: { primary: '#38bdf8', accent: '#c084fc' },
96
- orbConfig: { audioReactivity: 3.5, glowIntensity: 0.8 },
97
- onStateChange: (state, prev) => console.log(state, prev),
98
- onCallStart: e => console.log('started', e.agentId),
99
- onCallEnd: e => console.log('ended after', e.duration, 'ms'),
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
- // Control
103
- await widget.startCall();
104
- widget.setColors({ glow: '#c7d2fe' });
105
- widget.setGlowSettings(0.8, 0.4); // e.g. dark theme
106
- await widget.endCall();
107
- widget.destroy();
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
- ### Audio helpers
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
- ## Voice Service Requirements
574
+ ```javascript
575
+ import { themes, getTheme, applyTheme, detectSystemTheme, watchSystemTheme } from 'hanc-webrtc-widgets';
116
576
 
117
- The widget expects a `/connect` endpoint on your voice service:
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
- POST /connect
121
- Body: { "agentId": "<your-agent-id>" }
122
- Response: { "token": "<livekit-token>", "url": "<wss://...>" }
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
- Set `voice-service-url` (or `VITE_VOICE_SERVICE_URL`) to point at this service.
639
+ ### Theme vs Manual Configuration
126
640
 
127
- ## Framework Usage
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
- Register the custom elements once and use them anywhere. Example for React with `@lit/react`:
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
- ```ts
132
- import React from 'react';
133
- import { createComponent } from '@lit/react';
134
- import { InlineCall, FloatingCall, PillCall } from 'hanc-webrtc-widgets';
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
- export const HancInline = createComponent({
137
- tagName: 'hanc-ai-inline-call',
138
- elementClass: InlineCall,
139
- react: React,
140
- events: { onCallStart: 'call-start', onCallEnd: 'call-end' },
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
- export const HancFloating = createComponent({
144
- tagName: 'hanc-ai-floating-call',
145
- elementClass: FloatingCall,
146
- react: React,
147
- events: { onCallStart: 'call-start', onCallEnd: 'call-end' },
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
- export const HancPill = createComponent({
151
- tagName: 'hanc-ai-pill-call',
152
- elementClass: PillCall,
153
- react: React,
154
- events: { onCallStart: 'call-start', onCallEnd: 'call-end' },
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
- ## Theming Tips
159
- - `theme="auto"` listens to `prefers-color-scheme` and switches presets/glow for you.
160
- - Use `color-preset` for quick palettes (`indigo`, `cyan`, `emerald`, `rose`, `amber`).
161
- - Override any color with `colors='{"accent":"#8b5cf6","glow":"#c084fc"}'`.
162
- - For light themes, pair with `orb-config='{"idleGlowMultiplier":0.2,"glowIntensity":0.4}'`.
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).