loomlarge 0.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 +714 -0
- package/dist/index.cjs +1176 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +631 -0
- package/dist/index.d.ts +631 -0
- package/dist/index.js +1166 -0
- package/dist/index.js.map +1 -0
- package/package.json +51 -0
package/README.md
ADDED
|
@@ -0,0 +1,714 @@
|
|
|
1
|
+

|
|
2
|
+
|
|
3
|
+
# LoomLarge (Latticework Animation Platform)
|
|
4
|
+
|
|
5
|
+
**LoomLarge** is a next-generation interactive 3D character animation platform built on **Latticework**, featuring reactive state management with XState, facial animation control via ARKit FACS (Facial Action Coding System), and modular agency-based architecture for lip-sync, eye/head tracking, prosodic expression, and conversational AI.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Table of Contents
|
|
10
|
+
1. [Quick Start](#quick-start)
|
|
11
|
+
2. [Core Concepts](#core-concepts)
|
|
12
|
+
- [Latticework Architecture](#latticework-architecture)
|
|
13
|
+
- [Composite Rotation System](#composite-rotation-system)
|
|
14
|
+
- [XState & Reactive Services](#xstate--reactive-services)
|
|
15
|
+
3. [Installation](#installation)
|
|
16
|
+
4. [Project Structure](#project-structure)
|
|
17
|
+
5. [How It Works](#how-it-works)
|
|
18
|
+
- [Animation Service](#animation-service)
|
|
19
|
+
- [Eye & Head Tracking](#eye--head-tracking)
|
|
20
|
+
- [Lip-Sync Agency](#lip-sync-agency)
|
|
21
|
+
- [Prosodic Expression](#prosodic-expression)
|
|
22
|
+
6. [Modules](#modules)
|
|
23
|
+
7. [Development](#development)
|
|
24
|
+
8. [Deployment](#deployment)
|
|
25
|
+
9. [License & Acknowledgments](#license--acknowledgments)
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Quick Start
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
# Clone the repository
|
|
33
|
+
git clone https://github.com/meekmachine/LoomLarge.git
|
|
34
|
+
cd LoomLarge
|
|
35
|
+
|
|
36
|
+
# Install dependencies
|
|
37
|
+
yarn install
|
|
38
|
+
|
|
39
|
+
# Start development server (Vite)
|
|
40
|
+
yarn dev
|
|
41
|
+
|
|
42
|
+
# Build for production
|
|
43
|
+
yarn build
|
|
44
|
+
|
|
45
|
+
# Deploy to GitHub Pages
|
|
46
|
+
yarn deploy
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The development server will start at `http://localhost:5173` with hot module replacement enabled.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Core Concepts
|
|
54
|
+
|
|
55
|
+
### Latticework Architecture
|
|
56
|
+
|
|
57
|
+
- **Agency-Based Design**: Independent services (agencies) handle specialized tasks:
|
|
58
|
+
- **Animation Agency**: Core snippet scheduling and playback
|
|
59
|
+
- **Lip-Sync Agency**: Phoneme prediction and viseme animation
|
|
60
|
+
- **Prosodic Expression Agency**: Emotional head gestures and speech timing
|
|
61
|
+
- **Eye/Head Tracking Agency**: Gaze control with mouse, webcam, or manual modes
|
|
62
|
+
- **Conversation Agency**: Multi-modal conversational AI orchestration
|
|
63
|
+
|
|
64
|
+
- **Immutable State**: Reactive state management ensures predictable updates and time-travel debugging
|
|
65
|
+
- **XState Machines**: Declarative state machines replace callback hell and ad-hoc timers
|
|
66
|
+
|
|
67
|
+
### Composite Rotation System
|
|
68
|
+
|
|
69
|
+
The **Composite Rotation System** in EngineThree allows smooth blending of blendshapes (morphs) and bone rotations:
|
|
70
|
+
|
|
71
|
+
- **Continuum Values** (-1 to +1): Single value controls paired AUs (e.g., Head Left ↔ Right)
|
|
72
|
+
- **Mix Weights** (0 to 1): Blend between 100% morph (0) and 100% bone (1)
|
|
73
|
+
- **Unified Rotation State**: Prevents axis conflicts when multiple systems control the same bones
|
|
74
|
+
|
|
75
|
+
Example:
|
|
76
|
+
```typescript
|
|
77
|
+
// Eyes: -1 (look left) to +1 (look right)
|
|
78
|
+
engine.applyEyeComposite(yaw, pitch);
|
|
79
|
+
|
|
80
|
+
// Head: yaw/pitch/roll with mix control
|
|
81
|
+
engine.applyHeadComposite(yaw, pitch, roll);
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### XState & Reactive Services
|
|
85
|
+
|
|
86
|
+
- **XState 5.x**: Modern state machines with TypeScript support
|
|
87
|
+
- **Service Pattern**: Each agency exposes a service with start/stop/update lifecycle
|
|
88
|
+
- **Global Context**: Services registered in `ModulesContext` for cross-component access
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Installation
|
|
93
|
+
|
|
94
|
+
### Prerequisites
|
|
95
|
+
|
|
96
|
+
- **Node.js** 18+ (LTS recommended)
|
|
97
|
+
- **Yarn** 1.22+ or npm 8+
|
|
98
|
+
- Modern browser with WebGL 2.0 support
|
|
99
|
+
|
|
100
|
+
### Setup Steps
|
|
101
|
+
|
|
102
|
+
1. **Clone and install**:
|
|
103
|
+
```bash
|
|
104
|
+
git clone https://github.com/meekmachine/LoomLarge.git
|
|
105
|
+
cd LoomLarge
|
|
106
|
+
yarn install
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
2. **Add your 3D model**:
|
|
110
|
+
- Place GLB file in `public/characters/`
|
|
111
|
+
- Update model path in `src/App.tsx`:
|
|
112
|
+
```typescript
|
|
113
|
+
const glbSrc = import.meta.env.BASE_URL + "characters/your-model.glb";
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
3. **Configure API keys** (optional, for AI modules):
|
|
117
|
+
- Create `.env.local`:
|
|
118
|
+
```
|
|
119
|
+
VITE_ANTHROPIC_API_KEY=sk-ant-...
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
4. **Start development**:
|
|
123
|
+
```bash
|
|
124
|
+
yarn dev
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Project Structure
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
LoomLarge/
|
|
133
|
+
├── README.md # ← This file
|
|
134
|
+
├── package.json
|
|
135
|
+
├── vite.config.ts # Vite bundler config
|
|
136
|
+
├── public/
|
|
137
|
+
│ ├── characters/ # GLB 3D models
|
|
138
|
+
│ ├── animations/ # Pre-baked animation JSON
|
|
139
|
+
│ ├── models/ # ML models (face-api.js)
|
|
140
|
+
│ └── skyboxes/ # Environment maps
|
|
141
|
+
├── src/
|
|
142
|
+
│ ├── App.tsx # Main React app entry
|
|
143
|
+
│ ├── main.tsx # Vite entry point
|
|
144
|
+
│ ├── engine/
|
|
145
|
+
│ │ ├── EngineThree.ts # Three.js engine (AU/morph control)
|
|
146
|
+
│ │ ├── EngineWind.ts # Wind physics for hair/cloth
|
|
147
|
+
│ │ └── arkit/
|
|
148
|
+
│ │ └── shapeDict.ts # ARKit FACS AU → morph mappings
|
|
149
|
+
│ ├── latticework/ # Core agencies
|
|
150
|
+
│ │ ├── animation/ # Animation scheduler (XState)
|
|
151
|
+
│ │ ├── lipsync/ # Lip-sync phoneme predictor
|
|
152
|
+
│ │ ├── prosodic/ # Prosodic expression (head gestures)
|
|
153
|
+
│ │ ├── eyeHeadTracking/ # Eye/head tracking service
|
|
154
|
+
│ │ ├── conversation/ # Conversational AI orchestration
|
|
155
|
+
│ │ └── transcription/ # Speech-to-text services
|
|
156
|
+
│ ├── components/
|
|
157
|
+
│ │ ├── au/ # AU control UI components
|
|
158
|
+
│ │ │ ├── AUSection.tsx # AU sliders
|
|
159
|
+
│ │ │ ├── VisemeSection.tsx # Viseme controls
|
|
160
|
+
│ │ │ ├── EyeHeadTrackingSection.tsx # Eye/head tracking UI
|
|
161
|
+
│ │ │ └── ContinuumSlider.tsx # Bidirectional AU slider
|
|
162
|
+
│ │ ├── SliderDrawer.tsx # Main dockable UI drawer
|
|
163
|
+
│ │ ├── PlaybackControls.tsx # Animation playback controls
|
|
164
|
+
│ │ ├── CurveEditor.tsx # Visual curve editor
|
|
165
|
+
│ │ └── ModulesMenu.tsx # Module activation UI
|
|
166
|
+
│ ├── modules/ # Pluggable modules
|
|
167
|
+
│ │ ├── aiChat/ # AI chat module (Anthropic)
|
|
168
|
+
│ │ ├── frenchQuiz/ # French quiz demo module
|
|
169
|
+
│ │ └── config.ts # Module registry
|
|
170
|
+
│ ├── context/
|
|
171
|
+
│ │ ├── threeContext.tsx # Global engine/animation context
|
|
172
|
+
│ │ └── ModulesContext.tsx # Module state management
|
|
173
|
+
│ ├── hooks/
|
|
174
|
+
│ │ └── useWebcamEyeTracking.ts # Webcam face tracking hook
|
|
175
|
+
│ ├── scenes/
|
|
176
|
+
│ │ └── CharacterGLBScene.tsx # Three.js React scene
|
|
177
|
+
│ └── utils/
|
|
178
|
+
│ └── animationLoader.ts # Load animation JSON files
|
|
179
|
+
└── docs/ # Documentation
|
|
180
|
+
├── QUICK_START.md
|
|
181
|
+
├── LIPSYNC_COMPLETE_GUIDE.md
|
|
182
|
+
├── BACKEND_INTEGRATION.md
|
|
183
|
+
└── DEPLOYMENT.md
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## How It Works
|
|
189
|
+
|
|
190
|
+
### Animation Service
|
|
191
|
+
|
|
192
|
+
The **Animation Service** (`latticework/animation/animationService.ts`) is the core scheduler:
|
|
193
|
+
|
|
194
|
+
1. **Load Snippets**: JSON files defining AU/morph keyframe curves
|
|
195
|
+
```typescript
|
|
196
|
+
const anim = createAnimationService(host);
|
|
197
|
+
anim.loadSnippet('smile', smileSnippetJSON);
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
2. **Schedule Playback**: Queue snippets with priority and duration
|
|
201
|
+
```typescript
|
|
202
|
+
anim.schedule('smile', {
|
|
203
|
+
duration: 1000,
|
|
204
|
+
priority: 10,
|
|
205
|
+
loop: false
|
|
206
|
+
});
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
3. **XState Machine**: Manages snippet lifecycle (`idle` → `playing` → `paused`)
|
|
210
|
+
- Driven by central frame loop (`threeContext.tsx`)
|
|
211
|
+
- Handles overlapping snippets with priority-based blending
|
|
212
|
+
|
|
213
|
+
4. **Host Interface**: Abstraction layer for AU/morph application
|
|
214
|
+
```typescript
|
|
215
|
+
const host = {
|
|
216
|
+
applyAU: (id, value) => engine.setAU(id, value),
|
|
217
|
+
setMorph: (key, value) => engine.setMorph(key, value),
|
|
218
|
+
transitionAU: (id, value, duration) => engine.transitionAU(id, value, duration)
|
|
219
|
+
};
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Eye & Head Tracking
|
|
223
|
+
|
|
224
|
+
The **Eye/Head Tracking Service** (`latticework/eyeHeadTracking/eyeHeadTrackingService.ts`) provides three tracking modes:
|
|
225
|
+
|
|
226
|
+
1. **Manual Mode**: Direct slider control of gaze direction
|
|
227
|
+
2. **Mouse Mode**: Character follows cursor with mirror behavior
|
|
228
|
+
- Mouse left → Character looks right (at user)
|
|
229
|
+
- Negative x coordinate for natural gaze
|
|
230
|
+
3. **Webcam Mode**: Face tracking using BlazeFace model
|
|
231
|
+
- Real-time eye position detection
|
|
232
|
+
- Normalized coordinates (-1 to 1)
|
|
233
|
+
|
|
234
|
+
**Key Features**:
|
|
235
|
+
- **Composite Methods**: Uses `applyEyeComposite(yaw, pitch)` and `applyHeadComposite(yaw, pitch, roll)`
|
|
236
|
+
- **Intensity Control**: Separate sliders for eye and head movement intensity
|
|
237
|
+
- **Head Follow Eyes**: Optional delayed head movement matching eye gaze
|
|
238
|
+
- **Global Service**: Created in App.tsx and shared via ModulesContext
|
|
239
|
+
|
|
240
|
+
**Usage**:
|
|
241
|
+
```typescript
|
|
242
|
+
// Initialize service with engine reference
|
|
243
|
+
const service = createEyeHeadTrackingService({
|
|
244
|
+
eyeTrackingEnabled: true,
|
|
245
|
+
headTrackingEnabled: true,
|
|
246
|
+
headFollowEyes: true,
|
|
247
|
+
eyeIntensity: 1.0,
|
|
248
|
+
headIntensity: 0.5,
|
|
249
|
+
engine: engine
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
service.start();
|
|
253
|
+
service.setMode('mouse'); // or 'webcam' or 'manual'
|
|
254
|
+
|
|
255
|
+
// Set gaze target manually
|
|
256
|
+
service.setGazeTarget({ x: 0.5, y: -0.2, z: 0 });
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### Lip-Sync Agency
|
|
260
|
+
|
|
261
|
+
The **Lip-Sync Agency** (`latticework/lipsync/`) generates viseme animations from text:
|
|
262
|
+
|
|
263
|
+
1. **Phoneme Prediction**: Enhanced predictor with coarticulation model
|
|
264
|
+
```typescript
|
|
265
|
+
const predictor = new EnhancedPhonemePredictor();
|
|
266
|
+
const phonemes = predictor.predict('Hello world');
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
2. **Viseme Mapping**: Phonemes → ARKit visemes (AA, CH_J, DD, etc.)
|
|
270
|
+
- Timing based on phoneme duration and speech rate
|
|
271
|
+
- Coarticulation smoothing between adjacent phonemes
|
|
272
|
+
|
|
273
|
+
3. **Animation Snippet Generation**: Creates JSON snippets for animation service
|
|
274
|
+
```typescript
|
|
275
|
+
const snippet = generateLipsyncSnippet(text, {
|
|
276
|
+
speechRate: 1.0,
|
|
277
|
+
intensity: 0.8,
|
|
278
|
+
style: 'relaxed' // or 'precise', 'theatrical', etc.
|
|
279
|
+
});
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
4. **Integration**: Scheduled via animation service with high priority (30)
|
|
283
|
+
|
|
284
|
+
### Prosodic Expression
|
|
285
|
+
|
|
286
|
+
The **Prosodic Expression Agency** (`latticework/prosodic/prosodicService.ts`) adds emotional head movements:
|
|
287
|
+
|
|
288
|
+
1. **XState Machine**: Models prosodic states (idle → analyzing → expressing)
|
|
289
|
+
2. **Gesture Library**: Pre-defined head nods, tilts, and shakes
|
|
290
|
+
- Nod: Positive affirmation (head pitch down)
|
|
291
|
+
- Shake: Negation (head yaw side-to-side)
|
|
292
|
+
- Tilt: Curiosity/emphasis (head roll)
|
|
293
|
+
|
|
294
|
+
3. **Emotion Mapping**: Text analysis triggers appropriate gestures
|
|
295
|
+
```typescript
|
|
296
|
+
// Question → slight head tilt
|
|
297
|
+
// Exclamation → head nod emphasis
|
|
298
|
+
// Negation words → head shake
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
4. **Scheduling**: Prosodic snippets scheduled with medium priority (20)
|
|
302
|
+
|
|
303
|
+
---
|
|
304
|
+
|
|
305
|
+
## Modules
|
|
306
|
+
|
|
307
|
+
LoomLarge supports pluggable modules for extended functionality:
|
|
308
|
+
|
|
309
|
+
### AI Chat Module
|
|
310
|
+
- **Description**: Real-time conversational AI using Anthropic Claude
|
|
311
|
+
- **Location**: `src/modules/aiChat/`
|
|
312
|
+
- **Features**:
|
|
313
|
+
- Streaming text-to-speech synthesis
|
|
314
|
+
- Lip-sync integration with prosodic expression
|
|
315
|
+
- Eye/head tracking during conversation
|
|
316
|
+
- WebSocket or LiveKit audio streaming
|
|
317
|
+
|
|
318
|
+
**Activation**:
|
|
319
|
+
```typescript
|
|
320
|
+
// Via ModulesMenu UI or programmatically:
|
|
321
|
+
import { AIChatApp } from './modules/aiChat';
|
|
322
|
+
<AIChatApp animationManager={anim} />
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
### French Quiz Module
|
|
326
|
+
- **Description**: Interactive language learning demo
|
|
327
|
+
- **Location**: `src/modules/frenchQuiz/`
|
|
328
|
+
- **Features**:
|
|
329
|
+
- Survey-style question flow
|
|
330
|
+
- Facial expressions tied to correct/incorrect answers
|
|
331
|
+
- Modal-based UI with progress tracking
|
|
332
|
+
|
|
333
|
+
### Custom Modules
|
|
334
|
+
|
|
335
|
+
Create your own modules by following this pattern:
|
|
336
|
+
|
|
337
|
+
1. **Define module config** (`src/modules/config.ts`):
|
|
338
|
+
```typescript
|
|
339
|
+
export default {
|
|
340
|
+
modules: [
|
|
341
|
+
{
|
|
342
|
+
name: 'My Module',
|
|
343
|
+
description: 'Custom module description',
|
|
344
|
+
component: './modules/myModule/index.tsx'
|
|
345
|
+
}
|
|
346
|
+
]
|
|
347
|
+
};
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
2. **Create module component**:
|
|
351
|
+
```typescript
|
|
352
|
+
// src/modules/myModule/index.tsx
|
|
353
|
+
import React from 'react';
|
|
354
|
+
import { useModulesContext } from '../../context/ModulesContext';
|
|
355
|
+
|
|
356
|
+
export default function MyModule({ animationManager }: any) {
|
|
357
|
+
const { eyeHeadTrackingService } = useModulesContext();
|
|
358
|
+
|
|
359
|
+
// Your module logic here
|
|
360
|
+
return <div>My Module UI</div>;
|
|
361
|
+
}
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
---
|
|
365
|
+
|
|
366
|
+
## Development
|
|
367
|
+
|
|
368
|
+
### Running the Dev Server
|
|
369
|
+
|
|
370
|
+
```bash
|
|
371
|
+
yarn dev
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
Access at `http://localhost:5173` with:
|
|
375
|
+
- Hot module replacement (HMR)
|
|
376
|
+
- Source maps for debugging
|
|
377
|
+
- Console logging for all services
|
|
378
|
+
|
|
379
|
+
### Testing Animation Snippets
|
|
380
|
+
|
|
381
|
+
Load test animations in the browser console:
|
|
382
|
+
|
|
383
|
+
```javascript
|
|
384
|
+
// Global handles (auto-exposed in dev mode)
|
|
385
|
+
window.engine // EngineThree instance
|
|
386
|
+
window.anim // Animation service
|
|
387
|
+
|
|
388
|
+
// Load and play a snippet
|
|
389
|
+
anim.loadSnippet('test', {
|
|
390
|
+
duration: 2000,
|
|
391
|
+
keyframes: {
|
|
392
|
+
'AU_12': [[0, 0], [1000, 1], [2000, 0]], // Smile curve
|
|
393
|
+
'AU_6': [[0, 0], [1000, 0.8], [2000, 0]] // Cheek raise
|
|
394
|
+
}
|
|
395
|
+
});
|
|
396
|
+
anim.schedule('test', { priority: 10 });
|
|
397
|
+
anim.play();
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
### Debugging Eye/Head Tracking
|
|
401
|
+
|
|
402
|
+
The service includes comprehensive diagnostic logging:
|
|
403
|
+
|
|
404
|
+
```javascript
|
|
405
|
+
// Check current mode
|
|
406
|
+
window.eyeHeadTrackingService?.getMode(); // 'manual' | 'mouse' | 'webcam'
|
|
407
|
+
|
|
408
|
+
// Set gaze manually
|
|
409
|
+
window.eyeHeadTrackingService?.setGazeTarget({ x: 0.5, y: -0.3, z: 0 });
|
|
410
|
+
|
|
411
|
+
// Update configuration
|
|
412
|
+
window.eyeHeadTrackingService?.updateConfig({
|
|
413
|
+
eyeIntensity: 1.0,
|
|
414
|
+
headIntensity: 0.7,
|
|
415
|
+
headFollowEyes: true
|
|
416
|
+
});
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
### TypeScript Type Checking
|
|
420
|
+
|
|
421
|
+
```bash
|
|
422
|
+
yarn typecheck
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
Runs `tsc --noEmit` to validate types without building.
|
|
426
|
+
|
|
427
|
+
---
|
|
428
|
+
|
|
429
|
+
## Deployment
|
|
430
|
+
|
|
431
|
+
### GitHub Pages Deployment
|
|
432
|
+
|
|
433
|
+
The project is configured for automatic GitHub Pages deployment:
|
|
434
|
+
|
|
435
|
+
```bash
|
|
436
|
+
yarn deploy
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
This script:
|
|
440
|
+
1. Builds production bundle (`yarn build`)
|
|
441
|
+
2. Deploys to `gh-pages` branch
|
|
442
|
+
3. Publishes to `https://meekmachine.github.io/LoomLarge`
|
|
443
|
+
|
|
444
|
+
**Configuration** (`vite.config.ts`):
|
|
445
|
+
```typescript
|
|
446
|
+
export default defineConfig({
|
|
447
|
+
base: '/LoomLarge/', // GitHub repo name
|
|
448
|
+
build: {
|
|
449
|
+
outDir: 'dist',
|
|
450
|
+
assetsDir: 'assets'
|
|
451
|
+
}
|
|
452
|
+
});
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
### Custom Domain
|
|
456
|
+
|
|
457
|
+
To use a custom domain:
|
|
458
|
+
|
|
459
|
+
1. Add `CNAME` file to `public/`:
|
|
460
|
+
```
|
|
461
|
+
your-domain.com
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
2. Configure DNS:
|
|
465
|
+
```
|
|
466
|
+
A 185.199.108.153
|
|
467
|
+
A 185.199.109.153
|
|
468
|
+
A 185.199.110.153
|
|
469
|
+
A 185.199.111.153
|
|
470
|
+
CNAME www your-username.github.io
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
3. Deploy:
|
|
474
|
+
```bash
|
|
475
|
+
yarn deploy
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
---
|
|
479
|
+
|
|
480
|
+
## API Reference
|
|
481
|
+
|
|
482
|
+
### Animation Service API
|
|
483
|
+
|
|
484
|
+
```typescript
|
|
485
|
+
interface AnimationService {
|
|
486
|
+
loadSnippet(name: string, snippet: AnimationSnippet): void;
|
|
487
|
+
schedule(name: string, options?: ScheduleOptions): void;
|
|
488
|
+
play(): void;
|
|
489
|
+
pause(): void;
|
|
490
|
+
stop(): void;
|
|
491
|
+
setLoop(loop: boolean): void;
|
|
492
|
+
scrub(time: number): void;
|
|
493
|
+
step(deltaSeconds: number): void;
|
|
494
|
+
dispose(): void;
|
|
495
|
+
}
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
### Eye/Head Tracking Service API
|
|
499
|
+
|
|
500
|
+
```typescript
|
|
501
|
+
interface EyeHeadTrackingService {
|
|
502
|
+
start(): void;
|
|
503
|
+
stop(): void;
|
|
504
|
+
setGazeTarget(target: GazeTarget): void;
|
|
505
|
+
setMode(mode: 'manual' | 'mouse' | 'webcam'): void;
|
|
506
|
+
getMode(): 'manual' | 'mouse' | 'webcam';
|
|
507
|
+
updateConfig(config: Partial<EyeHeadTrackingConfig>): void;
|
|
508
|
+
setSpeaking(isSpeaking: boolean): void;
|
|
509
|
+
setListening(isListening: boolean): void;
|
|
510
|
+
blink(): void;
|
|
511
|
+
dispose(): void;
|
|
512
|
+
}
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
### EngineThree Composite Methods
|
|
516
|
+
|
|
517
|
+
```typescript
|
|
518
|
+
class EngineThree {
|
|
519
|
+
// Eye composite rotation (yaw/pitch)
|
|
520
|
+
applyEyeComposite(yaw: number, pitch: number): void;
|
|
521
|
+
|
|
522
|
+
// Head composite rotation (yaw/pitch/roll)
|
|
523
|
+
applyHeadComposite(yaw: number, pitch: number, roll?: number): void;
|
|
524
|
+
|
|
525
|
+
// Get/Set AU mix weight (morph ↔ bone blend)
|
|
526
|
+
getAUMixWeight(auId: number): number | undefined;
|
|
527
|
+
setAUMixWeight(auId: number, mix: number): void;
|
|
528
|
+
|
|
529
|
+
// Direct AU control
|
|
530
|
+
setAU(id: number | string, value: number): void;
|
|
531
|
+
setMorph(key: string, value: number): void;
|
|
532
|
+
|
|
533
|
+
// Smooth transitions
|
|
534
|
+
transitionAU(id: number | string, target: number, duration?: number): void;
|
|
535
|
+
transitionMorph(key: string, target: number, duration?: number): void;
|
|
536
|
+
}
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
---
|
|
540
|
+
|
|
541
|
+
## Troubleshooting
|
|
542
|
+
|
|
543
|
+
### Character Not Moving
|
|
544
|
+
|
|
545
|
+
1. **Check engine initialization**:
|
|
546
|
+
```javascript
|
|
547
|
+
console.log(window.engine); // Should show EngineThree instance
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
2. **Verify service startup**:
|
|
551
|
+
```javascript
|
|
552
|
+
console.log(window.anim?.getSnapshot?.().value); // Should show 'playing' or 'idle'
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
3. **Check eye/head tracking**:
|
|
556
|
+
```javascript
|
|
557
|
+
window.eyeHeadTrackingService?.getState(); // Should show current gaze/status
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
### Eye Tracking Direction Issues
|
|
561
|
+
|
|
562
|
+
- **Eyes looking wrong way**: Check coordinate negation in `eyeHeadTrackingService.ts:283`
|
|
563
|
+
- **Head not following**: Verify `headFollowEyes` is enabled in config
|
|
564
|
+
- **Intensity too low**: Increase `eyeIntensity` and `headIntensity` sliders
|
|
565
|
+
|
|
566
|
+
### Animation Not Loading
|
|
567
|
+
|
|
568
|
+
1. **Check JSON format**:
|
|
569
|
+
- Must have `duration` and `keyframes` fields
|
|
570
|
+
- AU keys must match ARKit spec (e.g., 'AU_12', not '12')
|
|
571
|
+
|
|
572
|
+
2. **Verify snippet name**:
|
|
573
|
+
```javascript
|
|
574
|
+
anim.listSnippets(); // Show all loaded snippets
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
3. **Check console for errors**:
|
|
578
|
+
- Look for `[Animation]` prefixed logs
|
|
579
|
+
- Validate keyframe curve format: `[[time, value], ...]`
|
|
580
|
+
|
|
581
|
+
### TensorFlow.js Bundling Errors
|
|
582
|
+
|
|
583
|
+
If you encounter errors related to TensorFlow.js modules (e.g., `@tensorflow/tfjs-core/dist/ops/ops_for_converter`), this is a **known issue** with TensorFlow.js 4.x and Vite.
|
|
584
|
+
|
|
585
|
+
**The Problem:**
|
|
586
|
+
- TensorFlow.js references internal module paths that don't actually exist in the npm package
|
|
587
|
+
- Vite's esbuild optimizer cannot resolve these phantom paths
|
|
588
|
+
- Results in 100+ bundling errors about missing exports and modules
|
|
589
|
+
|
|
590
|
+
**Solution (Already Implemented):**
|
|
591
|
+
LoomLarge loads TensorFlow.js and BlazeFace from **CDN** instead of npm packages:
|
|
592
|
+
|
|
593
|
+
```html
|
|
594
|
+
<!-- index.html -->
|
|
595
|
+
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@4.22.0/dist/tf.min.js"></script>
|
|
596
|
+
<script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/blazeface@0.0.7/dist/blazeface.js"></script>
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
The code uses global `blazeface` object with TypeScript declarations:
|
|
600
|
+
```typescript
|
|
601
|
+
// useWebcamEyeTracking.ts
|
|
602
|
+
declare const blazeface: any;
|
|
603
|
+
const model = await blazeface.load();
|
|
604
|
+
```
|
|
605
|
+
|
|
606
|
+
Vite config excludes TensorFlow packages from optimization:
|
|
607
|
+
```typescript
|
|
608
|
+
// vite.config.ts
|
|
609
|
+
optimizeDeps: {
|
|
610
|
+
exclude: [
|
|
611
|
+
'@tensorflow/tfjs',
|
|
612
|
+
'@tensorflow/tfjs-core',
|
|
613
|
+
'@tensorflow/tfjs-converter',
|
|
614
|
+
'@tensorflow/tfjs-backend-cpu',
|
|
615
|
+
'@tensorflow/tfjs-backend-webgl',
|
|
616
|
+
'@tensorflow-models/blazeface',
|
|
617
|
+
],
|
|
618
|
+
}
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
**If you still see errors:**
|
|
622
|
+
1. Ensure TensorFlow packages are NOT in `package.json` dependencies
|
|
623
|
+
2. Clear Vite cache: `rm -rf node_modules/.vite`
|
|
624
|
+
3. Restart dev server: `yarn dev`
|
|
625
|
+
|
|
626
|
+
See [src/hooks/README_useWebcamEyeTracking.md](src/hooks/README_useWebcamEyeTracking.md) for full documentation.
|
|
627
|
+
|
|
628
|
+
### Build Errors
|
|
629
|
+
|
|
630
|
+
```bash
|
|
631
|
+
# Clear cache and rebuild
|
|
632
|
+
rm -rf node_modules dist .vite
|
|
633
|
+
yarn install
|
|
634
|
+
yarn build
|
|
635
|
+
```
|
|
636
|
+
|
|
637
|
+
---
|
|
638
|
+
|
|
639
|
+
## Performance Optimization
|
|
640
|
+
|
|
641
|
+
### Animation Loop
|
|
642
|
+
|
|
643
|
+
- Central frame loop runs at 60 FPS (`threeContext.tsx`)
|
|
644
|
+
- Animation scheduler ticks every frame via `step(deltaTime)`
|
|
645
|
+
- Morph/bone updates batched per frame
|
|
646
|
+
|
|
647
|
+
### Composite Rotation Caching
|
|
648
|
+
|
|
649
|
+
- Rotation state cached in `compositeRotationState` map
|
|
650
|
+
- Only recalculates when values change
|
|
651
|
+
- Avoids redundant Three.js object updates
|
|
652
|
+
|
|
653
|
+
### Snippet Scheduling
|
|
654
|
+
|
|
655
|
+
- Priority-based scheduler prevents conflicts
|
|
656
|
+
- Lower priority snippets paused when higher priority plays
|
|
657
|
+
- Automatic cleanup of completed snippets
|
|
658
|
+
|
|
659
|
+
---
|
|
660
|
+
|
|
661
|
+
## Contributing
|
|
662
|
+
|
|
663
|
+
We welcome contributions! Please follow these guidelines:
|
|
664
|
+
|
|
665
|
+
1. **Fork and clone** the repository
|
|
666
|
+
2. **Create a feature branch**: `git checkout -b feature/my-feature`
|
|
667
|
+
3. **Follow code style**:
|
|
668
|
+
- TypeScript strict mode
|
|
669
|
+
- ESLint/Prettier for formatting
|
|
670
|
+
- Descriptive variable names
|
|
671
|
+
4. **Test thoroughly**:
|
|
672
|
+
- Manual testing in dev mode
|
|
673
|
+
- TypeScript type checking (`yarn typecheck`)
|
|
674
|
+
5. **Commit with descriptive messages**:
|
|
675
|
+
```
|
|
676
|
+
feat: Add webcam eye tracking support
|
|
677
|
+
fix: Correct head yaw direction in mouse mode
|
|
678
|
+
docs: Update README with API reference
|
|
679
|
+
```
|
|
680
|
+
6. **Push and create PR** to `main` branch
|
|
681
|
+
|
|
682
|
+
---
|
|
683
|
+
|
|
684
|
+
## License & Acknowledgments
|
|
685
|
+
|
|
686
|
+
**© 2025 Jonathan Sutton Fields, Lovelace LOL**
|
|
687
|
+
Licensed under the **Loom Large, Latticework copyleft license**
|
|
688
|
+
|
|
689
|
+
### Acknowledgments
|
|
690
|
+
|
|
691
|
+
- **Three.js** – 3D rendering engine
|
|
692
|
+
- **XState** – State machine library
|
|
693
|
+
- **React** – UI framework
|
|
694
|
+
- **Vite** – Lightning-fast bundler
|
|
695
|
+
- **ARKit** – Facial Action Coding System specification
|
|
696
|
+
- **BlazeFace** – Webcam face detection model
|
|
697
|
+
|
|
698
|
+
### Related Projects
|
|
699
|
+
|
|
700
|
+
- **VISOS** – Predecessor architecture (object-oriented)
|
|
701
|
+
- **eEVA Workbench** – Original survey/conversation platform
|
|
702
|
+
- **Latticework** – Core agency framework
|
|
703
|
+
|
|
704
|
+
---
|
|
705
|
+
|
|
706
|
+
## Support
|
|
707
|
+
|
|
708
|
+
- **Issues**: [GitHub Issues](https://github.com/meekmachine/LoomLarge/issues)
|
|
709
|
+
- **Discussions**: [GitHub Discussions](https://github.com/meekmachine/LoomLarge/discussions)
|
|
710
|
+
- **Email**: jonathan@lovelacelol.com
|
|
711
|
+
|
|
712
|
+
---
|
|
713
|
+
|
|
714
|
+
**Built with ❤️ by the Latticework team**
|