hanc-webrtc-widgets 2.0.1 → 2.1.0

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,463 +1,166 @@
1
- # Hanc-webrtc-widgets
1
+ # Hanc WebRTC Widgets
2
2
 
3
- **Hanc-webrtc-widgets** is a Web Components library for easily integrating **Hanc AI call widgets** into your website or web application.
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.
4
4
 
5
- It provides ready-to-use, customizable, and lightweight UI widgets for initiating AI-driven voice calls, without the need for any frontend frameworks.
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
6
11
 
7
- You can use it in **plain HTML**, or integrate it with **React**, **Next.js**, or any other modern frontend stack.
8
-
9
- ## Quick Start
10
-
11
- ### HTML Example
12
+ ## Quick Start (Web Component)
12
13
 
13
14
  ```html
14
- <!DOCTYPE html>
15
- <html lang="en">
16
- <head>
17
- <meta charset="UTF-8" />
18
- <script
19
- src="https://unpkg.com/hanc-webrtc-widgets"
20
- async
21
- type="text/javascript"
22
- ></script>
23
- </head>
24
- <body>
25
- <!-- Inline Call Widget -->
26
- <hanc-ai-inline-call agent-id="YOUR_AGENT_ID"></hanc-ai-inline-call>
27
-
28
- <!-- Floating Call Widget -->
29
- <hanc-ai-floating-call agent-id="YOUR_AGENT_ID"></hanc-ai-floating-call>
30
- </body>
31
- </html>
32
- ```
33
-
34
- ### React Example
35
-
36
- 1. Installation lit/react & hanc-webrtc-widgets
37
-
38
- ```bash
39
- npm i @lit/react hanc-webrtc-widgets
40
- ```
41
-
42
- 2. Creating a React wrapper and using
43
-
44
- ```tsx
45
- import React from 'react';
46
- import { createComponent } from '@lit/react';
47
- import { InlineCall, FloatingCall } from 'hanc-webrtc-widgets';
48
-
49
- export const HancAiInlineCall = createComponent({
50
- tagName: 'hanc-ai-inline-call',
51
- elementClass: InlineCall,
52
- react: React,
53
- events: {
54
- onCallStart: 'call-start',
55
- onCallEnd: 'call-end',
56
- },
57
- });
58
-
59
- export const HancAiFloatingCall = createComponent({
60
- tagName: 'hanc-ai-floating-call',
61
- elementClass: FloatingCall,
62
- react: React,
63
- events: {
64
- onCallStart: 'call-start',
65
- onCallEnd: 'call-end',
66
- },
67
- });
68
-
69
- // An example of a component where both widgets are used
70
- export default function Example() {
71
- return (
72
- <>
73
- <HancAiInlineCall agentId="YOUR_AGENT_ID" />
74
- <HancAiFloatingCall agentId="YOUR_AGENT_ID" />
75
- </>
76
- );
77
- }
78
- ```
79
-
80
- ### Next.js Example
15
+ <script type="module" src="https://unpkg.com/hanc-webrtc-widgets"></script>
81
16
 
82
- 1. Installation lit/react & hanc-webrtc-widgets
83
-
84
- ```bash
85
- npm i @lit/react hanc-webrtc-widgets
86
- ```
87
-
88
- 2. Creating a Next.js wrapper and using
89
-
90
- ```tsx
91
- 'use client';
92
-
93
- import React from 'react';
94
- import dynamic from 'next/dynamic';
95
- import { createComponent } from '@lit/react';
96
-
97
- export const HancAiInlineCall = dynamic(
98
- async () => {
99
- const { InlineCall } = await import('hanc-webrtc-widgets');
100
-
101
- return createComponent({
102
- tagName: 'hanc-ai-inline-call',
103
- elementClass: InlineCall,
104
- react: React,
105
- events: {
106
- onCallStart: 'call-start',
107
- onCallEnd: 'call-end',
108
- },
109
- });
110
- },
111
- { ssr: false },
112
- );
113
-
114
- export const HancAiFloatingCall = dynamic(
115
- async () => {
116
- const { FloatingCall } = await import('hanc-webrtc-widgets');
117
-
118
- return createComponent({
119
- tagName: 'hanc-ai-floating-call',
120
- elementClass: FloatingCall,
121
- react: React,
122
- events: {
123
- onCallStart: 'call-start',
124
- onCallEnd: 'call-end',
125
- },
126
- });
127
- },
128
- { ssr: false },
129
- );
130
-
131
- // An example of a component where both widgets are used
132
- export default function Example() {
133
- return (
134
- <>
135
- <HancAiInlineCall agentId="YOUR_AGENT_ID" />
136
- <HancAiFloatingCall agentId="YOUR_AGENT_ID" />
137
- </>
138
- );
139
- }
140
- ```
141
-
142
- ## Components props & styles
143
-
144
- ### `<hanc-ai-inline-call>`
145
-
146
- **Description:**
147
- An “inline” widget that you embed directly in page content (often as a hero CTA). “Bubble” hints at the round, branded graphic.
148
-
149
- #### Available Attributes:
150
-
151
- | Attribute | Type | Description |
152
- | ------------------------ | ------ | -------------------------------------------------------- |
153
- | `agent-id` (required) | string | Agent ID for Twilio calls |
154
- | `button-start-text` | string | Custom start button text (default: `Start Call with ai`) |
155
- | `button-connecting-text` | string | Custom connecting button text (default: `Connecting...`) |
156
- | `button-end-text` | string | End button text (default: `End call`) |
157
- | `hide-button` | bool | Hide the button (orb click still toggles the call) |
158
- | `button-position` | string | Button placement: `top` or `bottom` |
159
- | `orb-color` | string | Base orb color in idle state |
160
- | `active-orb-color` | string | Orb color applied when the call becomes active |
161
- | `button-color` | string | Base button color (also used to derive hover/active) |
162
- | `button-hover-color` | string | Button hover color override |
163
- | `button-active-color` | string | Button active color override |
164
- | `button-text-color` | string | Button text color |
165
-
166
- #### Available Events:
167
-
168
- | Event Name | Description |
169
- | ------------ | ------------------------------------------------------------ |
170
- | `call-start` | Fired when a call is successfully connected and starts. |
171
- | `call-end` | Fired when a call ends, either by hangup or due to an error. |
172
-
173
- #### Available CSS Parts for Styling:
174
-
175
- | Part Name | Description |
176
- | ----------------- | --------------------------------- |
177
- | `wrapper` | Outer wrapper container |
178
- | `filter-light` | Light background filter |
179
- | `filter-gradient` | Gradient overlay |
180
- | `filter-overlay` | Active call overlay (state-based) |
181
- | `video` | The avatar video element |
182
- | `content-wrapper` | Button and content wrapper |
183
- | `button` | The main call button |
184
- | `icon-button` | The call icon inside the button |
185
- | `call-off-icon` | The "end call" icon |
186
- | `button-text` | Text inside the button |
187
-
188
- #### Example:
189
-
190
- ```html
191
17
  <hanc-ai-inline-call
192
- agent-id="67c34fa38ef2105d28bb287c"
193
- button-start-text="Call Agent"
18
+ agent-id="YOUR_AGENT_ID"
19
+ voice-service-url="https://voice.hanc.ai"
20
+ size="320"
21
+ color-preset="indigo"
22
+ theme="auto"
194
23
  ></hanc-ai-inline-call>
195
-
196
- <style>
197
- hanc-ai-inline-call::part(button) {
198
- /* your styles here */
199
- }
200
-
201
- hanc-ai-inline-call::part(button-text) {
202
- /* your styles here */
203
- }
204
-
205
- hanc-ai-inline-call::part(filter-overlay)[data-calling='true'] {
206
- /* your styles here */
207
- }
208
- </style>
209
24
  ```
210
25
 
211
- ## Additional customization options (append-only)
212
-
213
- Below are the new properties and examples you can add to the widgets.
214
-
215
- ### Theme and visual style
216
-
217
- Themes: `liquid-purple` , `liquid-cyan`, `liquid-pink`, `neural-green`,
218
- `neural-blue`(default), `orbit-blue`, `synaptic-purple`, `minimal-dark`, `minimal-light`, `custom`.
219
-
220
- Visual styles: `liquid-glass` , `liquid-glass-premium`, `neural-liquid`,
221
- `neural-orbit`, `neural-network`(default), `synaptic-core`, `organic-sphere`, `morphing-blob`.
26
+ ### Other layouts
222
27
 
223
28
  ```html
224
- <hanc-ai-inline-call
29
+ <!-- Floating orb -->
30
+ <hanc-ai-floating-call
225
31
  agent-id="YOUR_AGENT_ID"
226
- theme="liquid-cyan"
227
- visual-style="neural-liquid"
228
- orb-size="200"
229
- ></hanc-ai-inline-call>
230
- ```
231
-
232
- ### Inline widget new attributes
233
-
234
- - `voice-service-url`
235
- - `theme`
236
- - `visual-style`
237
- - `orb-size`
238
- - `button-end-text`
239
- - `hide-button`
240
- - `button-position`
241
- - `orb-color`
242
- - `active-orb-color`
243
- - `button-color`
244
- - `button-hover-color`
245
- - `button-active-color`
246
- - `button-text-color`
32
+ voice-service-url="https://voice.hanc.ai"
33
+ color-preset="cyan"
34
+ theme="auto"
35
+ ></hanc-ai-floating-call>
247
36
 
248
- ```html
249
- <hanc-ai-inline-call
37
+ <!-- Pill CTA -->
38
+ <hanc-ai-pill-call
250
39
  agent-id="YOUR_AGENT_ID"
251
- voice-service-url="https://voice.example.com"
252
- theme="minimal-light"
253
- visual-style="morphing-blob"
254
- orb-size="220"
255
- button-end-text="Stop"
256
- ></hanc-ai-inline-call>
40
+ voice-service-url="https://voice.hanc.ai"
41
+ button-text="Talk to AI"
42
+ active-button-text="End call"
43
+ color-preset="rose"
44
+ ></hanc-ai-pill-call>
257
45
  ```
258
46
 
259
- ### Floating widget new attributes
260
-
261
- - `voice-service-url`
262
- - `theme`
263
- - `visual-style`
264
- - `position`
265
- - `offset-x`
266
- - `offset-y`
267
- - `orb-size`
268
- - `hide-button`
269
- - `button-position`
270
- - `orb-color`
271
- - `active-orb-color`
272
- - `button-color`
273
- - `button-hover-color`
274
- - `button-active-color`
275
- - `button-text-color`
276
- - `minimized`
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
+ });
277
74
 
278
- ```html
279
- <hanc-ai-floating-call
280
- agent-id="YOUR_AGENT_ID"
281
- voice-service-url="https://voice.example.com"
282
- theme="neural-green"
283
- visual-style="neural-network"
284
- position="top-left"
285
- offset-x="32"
286
- offset-y="32"
287
- orb-size="140"
288
- minimized
289
- ></hanc-ai-floating-call>
75
+ orb.addEventListener('call-start', e => {
76
+ console.log('connected to', e.detail.agentId);
77
+ });
290
78
  ```
291
79
 
292
- ### CSS variables (when using theme="custom")
293
-
294
- ```css
295
- hanc-ai-inline-call {
296
- --hanc-button: linear-gradient(135deg, #0ea5e9 0%, #22d3ee 100%);
297
- --hanc-button-hover: linear-gradient(135deg, #0284c7 0%, #0ea5e9 100%);
298
- --hanc-button-active: linear-gradient(135deg, #ef4444 0%, #dc2626 100%);
299
- --hanc-button-text: #ffffff;
300
- --hanc-button-radius: 16px;
301
- --hanc-button-shadow: rgba(14, 165, 233, 0.35);
302
- --hanc-button-shadow-hover: rgba(14, 165, 233, 0.45);
303
- --hanc-button-shadow-active: rgba(239, 68, 68, 0.45);
304
- --hanc-orb-active-glow: rgba(14, 165, 233, 0.35);
305
- --hanc-orb-z-index: 10000;
306
- --hanc-widget-z-index: 9999;
307
- }
308
-
309
- hanc-ai-floating-call {
310
- --hanc-background: rgba(10, 10, 20, 0.9);
311
- --hanc-glow-shadow: rgba(14, 165, 233, 0.2);
312
- --hanc-orb-size: 140px;
313
- --hanc-orb-active-glow: rgba(14, 165, 233, 0.35);
314
- --hanc-orb-z-index: 10000;
315
- --hanc-widget-z-index: 9999;
316
- }
80
+ ## Direct API (HancAiWidget)
81
+
82
+ Import the low-level class when you need manual control, external media streams, or custom placement.
83
+
84
+ ```ts
85
+ import { HancAiWidget } from 'hanc-webrtc-widgets';
86
+
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
+ });
101
+
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();
317
108
  ```
318
109
 
319
- #### Custom theme examples
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
320
114
 
321
- Tip: set `theme="custom"` and override only the variables you need. All other values fall back to defaults.
115
+ ## Voice Service Requirements
322
116
 
323
- ```html
324
- <hanc-ai-inline-call
325
- agent-id="YOUR_AGENT_ID"
326
- theme="custom"
327
- visual-style="neural-network"
328
- active-orb-color="#22c55e"
329
- ></hanc-ai-inline-call>
117
+ The widget expects a `/connect` endpoint on your voice service:
330
118
 
331
- <style>
332
- hanc-ai-inline-call {
333
- --hanc-background: rgba(10, 15, 20, 0.8);
334
- --hanc-orb-size: 220px;
335
- --hanc-button: linear-gradient(135deg, #0ea5e9 0%, #22c55e 100%);
336
- --hanc-button-hover: linear-gradient(135deg, #0284c7 0%, #16a34a 100%);
337
- --hanc-button-active: linear-gradient(135deg, #ef4444 0%, #dc2626 100%);
338
- --hanc-button-text: #ffffff;
339
- --hanc-orb-active-glow: rgba(34, 197, 94, 0.4);
340
- }
341
- </style>
119
+ ```
120
+ POST /connect
121
+ Body: { "agentId": "<your-agent-id>" }
122
+ Response: { "token": "<livekit-token>", "url": "<wss://...>" }
342
123
  ```
343
124
 
344
- ```html
345
- <hanc-ai-inline-call
346
- agent-id="YOUR_AGENT_ID"
347
- theme="custom"
348
- visual-style="neural-orbit"
349
- button-position="top"
350
- ></hanc-ai-inline-call>
125
+ Set `voice-service-url` (or `VITE_VOICE_SERVICE_URL`) to point at this service.
351
126
 
352
- <style>
353
- hanc-ai-inline-call {
354
- --hanc-orb-size: 260px;
355
- --hanc-button-radius: 999px;
356
- --hanc-button: linear-gradient(135deg, #111827 0%, #374151 100%);
357
- --hanc-button-hover: linear-gradient(135deg, #1f2937 0%, #111827 100%);
358
- --hanc-button-active: linear-gradient(135deg, #ef4444 0%, #b91c1c 100%);
359
- --hanc-button-text: #f9fafb;
360
- --hanc-orb-active-glow: rgba(59, 130, 246, 0.35);
361
- }
362
- </style>
363
- ```
127
+ ## Framework Usage
364
128
 
365
- ```html
366
- <hanc-ai-floating-call
367
- agent-id="YOUR_AGENT_ID"
368
- theme="custom"
369
- position="top-right"
370
- button-position="top"
371
- active-orb-color="#f97316"
372
- ></hanc-ai-floating-call>
129
+ Register the custom elements once and use them anywhere. Example for React with `@lit/react`:
373
130
 
374
- <style>
375
- hanc-ai-floating-call {
376
- --hanc-background: rgba(255, 255, 255, 0.92);
377
- --hanc-text: rgba(24, 24, 27, 0.8);
378
- --hanc-glow-shadow: rgba(249, 115, 22, 0.2);
379
- --hanc-orb-size: 120px;
380
- --hanc-button: linear-gradient(135deg, #f97316 0%, #f59e0b 100%);
381
- --hanc-button-hover: linear-gradient(135deg, #ea580c 0%, #f97316 100%);
382
- --hanc-button-active: linear-gradient(135deg, #b91c1c 0%, #991b1b 100%);
383
- --hanc-button-text: #ffffff;
384
- }
385
- </style>
386
- ```
131
+ ```ts
132
+ import React from 'react';
133
+ import { createComponent } from '@lit/react';
134
+ import { InlineCall, FloatingCall, PillCall } from 'hanc-webrtc-widgets';
387
135
 
388
- ---
389
-
390
- ### `<hanc-ai-floating-call>`
391
-
392
- **Description:**
393
- A persistent, docked widget that floats in the corner and launches the same voice-call flow from anywhere on the page.
394
-
395
- #### Available Attributes:
396
-
397
- | Attribute | Type | Description |
398
- | ------------------------ | ------ | -------------------------------------------------------- |
399
- | `agent-id` (required) | string | Agent ID for Twilio calls |
400
- | `label-text` | string | Label above the button (default: `Need a help?`) |
401
- | `button-start-text` | string | Start button text (default: `Start Call with ai`) |
402
- | `button-connecting-text` | string | Custom connecting button text (default: `Connecting...`) |
403
- | `button-end-text` | string | End button text (default: `End call`) |
404
- | `hide-button` | bool | Hide the button (orb click still toggles the call) |
405
- | `button-position` | string | Button placement: `top` or `bottom` |
406
- | `orb-color` | string | Base orb color in idle state |
407
- | `active-orb-color` | string | Orb color applied when the call becomes active |
408
- | `button-color` | string | Base button color (also used to derive hover/active) |
409
- | `button-hover-color` | string | Button hover color override |
410
- | `button-active-color` | string | Button active color override |
411
- | `button-text-color` | string | Button text color |
412
-
413
- #### Available Events:
414
-
415
- | Event Name | Description |
416
- | ------------ | ------------------------------------------------------------ |
417
- | `call-start` | Fired when a call is successfully connected and starts. |
418
- | `call-end` | Fired when a call ends, either by hangup or due to an error. |
419
-
420
- #### Available CSS Parts for Styling:
421
-
422
- | Part Name | Description |
423
- | ----------------- | --------------------------------- |
424
- | `root` | Outer container |
425
- | `avatar-wrapper` | Wrapper for avatar/video |
426
- | `filter-light` | Light background filter |
427
- | `filter-gradient` | Gradient overlay |
428
- | `filter-overlay` | Active call overlay (state-based) |
429
- | `avatar-video` | The avatar video element |
430
- | `content` | Container for label and button |
431
- | `title` | The label/title text |
432
- | `button` | The main call button |
433
- | `icon-button` | The call icon inside the button |
434
- | `button-text` | Text inside the button |
435
-
436
- #### Example:
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
+ });
437
142
 
438
- ```html
439
- <hanc-ai-floating-call
440
- agent-id="67c34fa38ef2105d28bb287c"
441
- label-text="Need Assistance?"
442
- button-start-text="Start Call"
443
- button-end-text="End Call"
444
- ></hanc-ai-floating-call>
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' },
148
+ });
445
149
 
446
- <style>
447
- hanc-ai-floating-call::part(root) {
448
- /* your styles here */
449
- }
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' },
155
+ });
156
+ ```
450
157
 
451
- hanc-ai-floating-call::part(title) {
452
- /* your styles here */
453
- }
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}'`.
454
163
 
455
- hanc-ai-floating-call::part(button) {
456
- /* your styles here */
457
- }
164
+ ## License
458
165
 
459
- hanc-ai-floating-call::part(filter-overlay)[data-calling='true'] {
460
- /* your styles here */
461
- }
462
- </style>
463
- ```
166
+ MIT