@myned-ai/avatar-chat-widget 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Myned AI
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,305 @@
1
+ # Avatar Chat Widget
2
+
3
+ **Embeddable 3D Avatar Chat Widget** - Real-time Voice & Text Chat with Gaussian Splatting Avatar Animation.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@myned-ai/avatar-chat-widget.svg)](https://www.npmjs.com/package/@myned-ai/avatar-chat-widget)
6
+
7
+ ---
8
+
9
+ ## Installation
10
+
11
+ ### Script Tag (No Build Required)
12
+
13
+ Add directly to any HTML page or website builder:
14
+
15
+ ```html
16
+ <!-- Container for the widget -->
17
+ <div id="avatar-chat"></div>
18
+
19
+ <!-- Load from CDN -->
20
+ <script src="https://cdn.jsdelivr.net/npm/@myned-ai/avatar-chat-widget"></script>
21
+
22
+ <script>
23
+ // Initialize the widget
24
+ AvatarChat.init({
25
+ container: '#avatar-chat',
26
+ serverUrl: 'wss://your-backend-server.com/ws',
27
+ position: 'bottom-right',
28
+ theme: 'light'
29
+ });
30
+ </script>
31
+ ```
32
+
33
+ ### Programmatic Control
34
+
35
+ ```typescript
36
+ const chat = AvatarChat.init({
37
+ container: '#avatar-chat',
38
+ serverUrl: 'wss://your-backend-server.com/ws',
39
+ theme: 'dark',
40
+ onReady: () => console.log('Widget ready!'),
41
+ onMessage: (msg) => console.log('Message:', msg)
42
+ });
43
+
44
+ // Control programmatically
45
+ chat.sendMessage('Hello!');
46
+ chat.collapse(); // Minimize to bubble
47
+ chat.expand(); // Open full widget
48
+ chat.destroy(); // Cleanup
49
+ ```
50
+
51
+ ---
52
+
53
+ ## Configuration Options
54
+
55
+ | Option | Type | Default | Description |
56
+ |--------|------|---------|-------------|
57
+ | `container` | `string \| HTMLElement` | **required** | CSS selector or DOM element |
58
+ | `serverUrl` | `string` | **required** | WebSocket server URL |
59
+ | `position` | `string` | `'bottom-right'` | Position: `bottom-right`, `bottom-left`, `top-right`, `top-left`, `inline` |
60
+ | `theme` | `string` | `'light'` | Theme: `light`, `dark`, `auto` |
61
+ | `startCollapsed` | `boolean` | `true` | Start minimized as bubble |
62
+ | `width` | `number` | `380` | Widget width in pixels |
63
+ | `height` | `number` | `550` | Widget height in pixels |
64
+ | `logLevel` | `string` | `'error'` | Log level: `none`, `error`, `warn`, `info`, `debug` |
65
+ | `customStyles` | `string` | `undefined` | Custom CSS to inject |
66
+ | `authEnabled` | `boolean` | `true` | Enable HMAC token authentication |
67
+
68
+ ### Callbacks
69
+
70
+ | Callback | Type | Description |
71
+ |----------|------|-------------|
72
+ | `onReady` | `() => void` | Called when widget is initialized |
73
+ | `onConnectionChange` | `(connected: boolean) => void` | Connection status changes |
74
+ | `onMessage` | `(msg: {role, text}) => void` | Message received |
75
+ | `onError` | `(error: Error) => void` | Error occurred |
76
+
77
+ ---
78
+
79
+ ## Development
80
+
81
+ ### Local Development
82
+
83
+ ```bash
84
+ # Install dependencies
85
+ npm install
86
+
87
+ # Start development server (SPA mode)
88
+ npm run dev
89
+
90
+ # Build library for distribution
91
+ npm run build:lib
92
+
93
+ # Build both SPA and library
94
+ npm run build:all
95
+ ```
96
+
97
+ ### Test with Sample Backend Server
98
+
99
+ ```bash
100
+ # Clone the avatar chat server
101
+ git clone https://github.com/myned-ai/avatar-chat-server.git
102
+ cd avatar-chat-server
103
+
104
+ # Follow the instructions in the repository to start the Docker container
105
+ docker-compose up
106
+ ```
107
+
108
+ The server will start on `ws://localhost:8765` by default.
109
+
110
+ ---
111
+
112
+ ## Features
113
+
114
+ - **Text & Voice Chat** - Real-time messaging with microphone streaming
115
+ - **3D Avatar** - Gaussian Splatting rendering with 52 ARKit blendshapes
116
+ - **Synchronized Animation** - Audio and facial expressions in perfect sync
117
+ - **Auto-reconnection** - Resilient WebSocket with exponential backoff
118
+ - **Shadow DOM** - CSS isolated, no style conflicts
119
+ - **Accessible** - WCAG 2.1 AA compliant
120
+
121
+ ---
122
+
123
+ ## Avatar Rendering Engine
124
+
125
+ This widget uses [@myned-ai/gsplat-flame-avatar-renderer](https://www.npmjs.com/package/@myned-ai/gsplat-flame-avatar-renderer), a specialized Gaussian Splatting library for rendering animated 3D avatars.
126
+
127
+ ### Animation States
128
+
129
+ | State | Animation Index | Description |
130
+ |-------|-----------------|-------------|
131
+ | **Idle** | 1 | Subtle breathing and micro-movements |
132
+ | **Hello** | 2 | Attentive greeting posture |
133
+ | **Responding** | 6 | Speaking body movements (head sway, gestures) |
134
+
135
+ ### Eye Blink Behavior
136
+
137
+ The widget handles all eye blinking on the frontend for consistent behavior across states. Blink intervals vary by avatar state:
138
+
139
+ | State | Interval | Description |
140
+ |-------|----------|-------------|
141
+ | **Idle** | 2-4 seconds | Relaxed, natural blinking |
142
+ | **Hello** | 1.8-3.5 seconds | Attentive, slightly more frequent |
143
+ | **Responding** | 1.3-3.3 seconds | Natural speaking rate |
144
+
145
+ Each blink uses randomized patterns and intensity (80-100%) for natural variation.
146
+
147
+ ### Avatar Asset Format
148
+
149
+ The widget loads a modified LAM based avatar from ZIP file containing:
150
+
151
+ ```
152
+ avatar.zip
153
+ ├── avatar/
154
+ │ ├── offset.ply # Gaussian splats point cloud
155
+ │ ├── animation.glb # Animation clips
156
+ │ ├── skin.glb # Skinning/skeleton data
157
+ │ ├── vertex_order.json # Vertex ordering
158
+ │ └── iris_occlusion.json # Iris occlusion ranges (optional)
159
+ ```
160
+
161
+ ### Browser Requirements
162
+
163
+ For production deployment, your server must send these headers to enable SharedArrayBuffer (used for high-performance sorting):
164
+
165
+ ```
166
+ Cross-Origin-Embedder-Policy: require-corp
167
+ Cross-Origin-Opener-Policy: same-origin
168
+ ```
169
+
170
+ ---
171
+
172
+ ## Directory Structure
173
+
174
+ | Path | Files | Description |
175
+ |------|-------|-------------|
176
+ | `src/` | 3 | Entry points (`widget.ts`, `main.ts`, `config.ts`) |
177
+ | `src/avatar/` | 3 | Avatar rendering (`GaussianAvatar`, `LazyAvatar`) |
178
+ | `src/constants/` | 2 | ARKit blendshape constants |
179
+ | `src/managers/` | 2 | Chat orchestration (`ChatManager`) |
180
+ | `src/services/` | 8 | Core services (audio, WebSocket, blendshapes) |
181
+ | `src/types/` | 4 | TypeScript type definitions |
182
+ | `src/utils/` | 9 | Shared utilities (logging, buffers, protocols) |
183
+
184
+ ### Key Components
185
+
186
+ | Component | Description |
187
+ |-----------|-------------|
188
+ | `widget.ts` | Main entry point, `AvatarChat.init()` API |
189
+ | `ChatManager` | Orchestrates services, handles state transitions |
190
+ | `GaussianAvatar` | Wrapper for gsplat-flame-avatar-renderer |
191
+ | `SocketService` | WebSocket connection with auto-reconnect |
192
+ | `AudioInput` | Microphone capture (PCM16 for OpenAI Realtime API) |
193
+ | `AudioOutput` | Audio playback with Web Audio API |
194
+ | `SyncPlayback` | Synchronized audio + blendshape playback |
195
+ | `BlendshapeBuffer` | Frame buffer for smooth animation |
196
+ | `AuthService` | HMAC token authentication |
197
+ | `Logger` | Centralized logging with levels |
198
+
199
+ ---
200
+
201
+ ## Architecture
202
+
203
+ ```
204
+ Frontend (This Widget) Backend (Your Server)
205
+ ┌─────────────────────┐ ┌──────────────────────┐
206
+ │ Widget (Shadow) │◄────►│ WebSocket Server │
207
+ │ ├─ Chat UI │ │ ├─ AI/LLM │
208
+ │ ├─ Voice I/O │ │ ├─ TTS │
209
+ │ └─ Avatar │ │ └─ Blendshape Gen │
210
+ └─────────────────────┘ └──────────────────────┘
211
+ ```
212
+
213
+ ---
214
+
215
+ ## WebSocket Protocol
216
+
217
+ **Client to Server:**
218
+ ```json
219
+ { "type": "text", "data": "Hello", "userId": "user_123", "timestamp": 123 }
220
+ { "type": "audio", "data": "<ArrayBuffer>", "format": "audio/webm" }
221
+ ```
222
+
223
+ **Server to Client:**
224
+ ```json
225
+ { "type": "audio_start", "sessionId": "abc", "sampleRate": 24000 }
226
+ { "type": "audio_chunk", "data": "<ArrayBuffer>", "timestamp": 124 }
227
+ { "type": "blendshape", "weights": {...}, "timestamp": 124 }
228
+ { "type": "audio_end", "sessionId": "abc" }
229
+ ```
230
+
231
+ ---
232
+
233
+ ## Authentication
234
+
235
+ The widget uses HMAC token authentication by default for secure WebSocket connections.
236
+
237
+ ### Disabling Authentication (Development)
238
+
239
+ For local development without an auth server:
240
+
241
+ ```typescript
242
+ AvatarChat.init({
243
+ container: '#avatar-chat',
244
+ serverUrl: 'ws://localhost:8080/ws',
245
+ authEnabled: false // Disable for local testing
246
+ });
247
+ ```
248
+
249
+ ### How It Works
250
+
251
+ 1. Widget requests a token from `POST /api/auth/token`
252
+ 2. Server validates origin and returns HMAC-signed token
253
+ 3. Widget connects to WebSocket with token: `ws://server/ws?token=...`
254
+ 4. Server verifies token signature and expiration
255
+
256
+ ### Authentication Flow
257
+
258
+ ```
259
+ Widget Server
260
+ │ │
261
+ │ POST /api/auth/token │
262
+ │ Origin: https://yoursite.com │
263
+ │──────────────────────────────►│
264
+ │ │ Validate origin
265
+ │ {token, ttl, origin} │ Generate HMAC token
266
+ │◄──────────────────────────────│
267
+ │ │
268
+ │ WebSocket /ws?token=... │
269
+ │──────────────────────────────►│
270
+ │ │ Verify token
271
+ │ Connection OK │ Check rate limits
272
+ │◄──────────────────────────────│
273
+ ```
274
+
275
+ ### Security Features
276
+
277
+ - **Origin validation** - Only whitelisted domains can connect
278
+ - **HMAC-SHA256 tokens** - Cryptographically signed, time-limited
279
+ - **Rate limiting** - Per-domain and per-session limits
280
+ - **Auto-refresh** - Tokens refresh automatically before expiry
281
+
282
+ ### Server Requirements
283
+
284
+ The backend must implement:
285
+ - `POST /api/auth/token` - Returns `{token, ttl, origin}`
286
+ - WebSocket token verification via query parameter
287
+
288
+ ---
289
+
290
+ ### Acknowledgement
291
+
292
+ This work is built on many amazing research works and open-source projects:
293
+ - [OpenLRM](https://github.com/3DTopia/OpenLRM)
294
+ - [GAGAvatar](https://github.com/xg-chu/GAGAvatar)
295
+ - [GaussianAvatars](https://github.com/ShenhanQian/GaussianAvatars)
296
+ - [VHAP](https://github.com/ShenhanQian/VHAP)
297
+ - [LAM](https://github.com/aigc3d/LAM)
298
+
299
+ Thanks for their excellent works and great contribution.
300
+
301
+ ---
302
+
303
+ ## License
304
+
305
+ MIT License - see [LICENSE](LICENSE) for details.
@@ -0,0 +1,191 @@
1
+ /**
2
+ * AvatarChat - Public Widget API
3
+ */
4
+ declare const AvatarChat: {
5
+ /** Version */
6
+ version: string;
7
+ /** Active instance */
8
+ _instance: AvatarChatElement | null;
9
+ /**
10
+ * Initialize and mount the widget
11
+ */
12
+ init(config: AvatarChatConfig): AvatarChatInstance;
13
+ /**
14
+ * Destroy current instance
15
+ */
16
+ destroy(): void;
17
+ /**
18
+ * Get current instance
19
+ */
20
+ getInstance(): AvatarChatInstance | null;
21
+ };
22
+ export { AvatarChat }
23
+ export default AvatarChat;
24
+
25
+ /**
26
+ * Avatar Chat Widget - Embeddable Web Component
27
+ *
28
+ * A real-time voice/text chat widget with 3D avatar animation.
29
+ * Uses Shadow DOM for complete CSS isolation from host page.
30
+ *
31
+ * @example Script Tag (Wix, WordPress, HTML)
32
+ * ```html
33
+ * <div id="avatar-chat"></div>
34
+ * <script src="https://cdn.jsdelivr.net/gh/user/repo@v1.0.0/dist/avatar-chat-widget.umd.cjs"></script>
35
+ * <script>
36
+ * AvatarChat.init({
37
+ * container: '#avatar-chat',
38
+ * serverUrl: 'wss://your-server.com/ws'
39
+ * });
40
+ * </script>
41
+ * ```
42
+ *
43
+ * @example NPM Package
44
+ * ```typescript
45
+ * import { AvatarChat } from 'avatar-chat-widget';
46
+ * const widget = AvatarChat.init({ container: '#chat', serverUrl: 'wss://...' });
47
+ * ```
48
+ */
49
+ /**
50
+ * Widget configuration options passed at runtime
51
+ */
52
+ export declare interface AvatarChatConfig {
53
+ /** CSS selector or HTMLElement for the widget container (required) */
54
+ container: string | HTMLElement;
55
+ /** WebSocket server URL (required) */
56
+ serverUrl: string;
57
+ /** Widget position when using floating mode */
58
+ position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left' | 'inline';
59
+ /** UI theme */
60
+ theme?: 'light' | 'dark' | 'auto';
61
+ /** Start in collapsed state (bubble only) */
62
+ startCollapsed?: boolean;
63
+ /** Widget width in pixels (default: 380) */
64
+ width?: number;
65
+ /** Widget height in pixels (default: 550) */
66
+ height?: number;
67
+ /** Enable/disable voice input (default: true) */
68
+ enableVoice?: boolean;
69
+ /** Enable/disable text input (default: true) */
70
+ enableText?: boolean;
71
+ /** Path to avatar model (default: './asset/nyx.zip') */
72
+ avatarUrl?: string;
73
+ /** Enable authentication (default: false) */
74
+ authEnabled?: boolean;
75
+ /** Log level for debugging */
76
+ logLevel?: 'none' | 'error' | 'warn' | 'info' | 'debug';
77
+ /** Custom CSS to inject (optional) */
78
+ customStyles?: string;
79
+ /** Callback when widget is ready */
80
+ onReady?: () => void;
81
+ /** Callback when connection state changes */
82
+ onConnectionChange?: (connected: boolean) => void;
83
+ /** Callback when a message is received */
84
+ onMessage?: (message: {
85
+ role: 'user' | 'assistant';
86
+ text: string;
87
+ }) => void;
88
+ /** Callback on error */
89
+ onError?: (error: Error) => void;
90
+ }
91
+
92
+ declare class AvatarChatElement extends HTMLElement {
93
+ private shadow;
94
+ private config;
95
+ private avatar;
96
+ private chatManager;
97
+ private _isMounted;
98
+ private _isConnected;
99
+ private _isCollapsed;
100
+ constructor();
101
+ /**
102
+ * Configure the widget (call before mount)
103
+ */
104
+ configure(config: AvatarChatConfig): void;
105
+ /**
106
+ * Mount the widget to DOM
107
+ */
108
+ mount(): Promise<void>;
109
+ /**
110
+ * Render the full widget
111
+ */
112
+ private renderWidget;
113
+ /**
114
+ * Render collapsed bubble
115
+ */
116
+ private renderBubble;
117
+ /**
118
+ * Initialize avatar renderer
119
+ */
120
+ private initializeAvatar;
121
+ /**
122
+ * Initialize chat manager
123
+ */
124
+ private initializeChat;
125
+ /**
126
+ * Setup UI event listeners
127
+ */
128
+ private setupUIEvents;
129
+ /**
130
+ * Update connection status UI
131
+ */
132
+ private updateConnectionStatus;
133
+ /**
134
+ * Collapse to bubble
135
+ */
136
+ collapse(): void;
137
+ /**
138
+ * Expand from bubble
139
+ */
140
+ expand(): Promise<void>;
141
+ /**
142
+ * Show widget
143
+ */
144
+ show(): void;
145
+ /**
146
+ * Hide widget
147
+ */
148
+ hide(): void;
149
+ /**
150
+ * Send message programmatically
151
+ */
152
+ sendMessage(text: string): void;
153
+ /**
154
+ * Check if mounted
155
+ */
156
+ isMounted(): boolean;
157
+ /**
158
+ * Check if connected to server
159
+ */
160
+ isServerConnected(): boolean;
161
+ /**
162
+ * Cleanup
163
+ */
164
+ destroy(): void;
165
+ }
166
+
167
+ /**
168
+ * Widget instance returned by init()
169
+ */
170
+ export declare interface AvatarChatInstance {
171
+ /** Send a text message */
172
+ sendMessage(text: string): void;
173
+ /** Mount widget to DOM (called automatically by init) */
174
+ mount(): void;
175
+ /** Destroy and cleanup widget */
176
+ destroy(): void;
177
+ /** Show the widget */
178
+ show(): void;
179
+ /** Hide the widget */
180
+ hide(): void;
181
+ /** Expand from collapsed state */
182
+ expand(): void;
183
+ /** Collapse to bubble */
184
+ collapse(): void;
185
+ /** Check if widget is mounted */
186
+ isMounted(): boolean;
187
+ /** Check if connected to server */
188
+ isConnected(): boolean;
189
+ }
190
+
191
+ export { }