@omote/babylon 0.2.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 ADDED
@@ -0,0 +1,58 @@
1
+ # @omote/babylon
2
+
3
+ Babylon.js adapter for the [Omote AI Character SDK](https://github.com/omoteai/muse).
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @omote/babylon @omote/core @babylonjs/core @babylonjs/loaders
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```typescript
14
+ import { SceneLoader } from '@babylonjs/loaders';
15
+ import { OmoteAvatar } from '@omote/babylon';
16
+ import { MicLipSync } from '@omote/core';
17
+
18
+ // Load avatar
19
+ const result = await SceneLoader.ImportMeshAsync('', '/models/', 'avatar.glb', scene);
20
+
21
+ // Create avatar
22
+ const avatar = new OmoteAvatar({ target: result.meshes[0], scene });
23
+
24
+ // Wire a pipeline
25
+ const mic = new MicLipSync({ /* config */ });
26
+ avatar.connectFrameSource(mic);
27
+
28
+ // Update loop (or use autoUpdate: true in constructor)
29
+ scene.registerBeforeRender(() => {
30
+ avatar.update(engine.getDeltaTime() / 1000, scene.activeCamera);
31
+ });
32
+ ```
33
+
34
+ ## API
35
+
36
+ ### `OmoteAvatar`
37
+
38
+ Full-featured avatar class with CharacterController (compositor + gaze + life layer).
39
+
40
+ | Method | Description |
41
+ |--------|-------------|
42
+ | `update(delta, camera, avatarRotationY?)` | Call each frame (or use `autoUpdate: true`) |
43
+ | `connectFrameSource(source)` | Wire any pipeline |
44
+ | `disconnectFrameSource()` | Disconnect the current frame source |
45
+ | `setFrame(blendshapes)` | Direct blendshape input |
46
+ | `setEmotion(emotion)` | Set emotion (string preset or weights) |
47
+ | `setSpeaking(speaking)` | Drive mouth animation intensity |
48
+ | `setState(state)` | Set conversational state (idle, listening, thinking, speaking) |
49
+ | `setAudioEnergy(energy)` | Set audio energy level (0-1, drives emphasis) |
50
+ | `setCamera(camera)` | Set camera for gaze tracking (required with `autoUpdate`) |
51
+ | `reset()` | Reset all state (smoothing, life layer, emotions) |
52
+ | `dispose()` | Clean up resources |
53
+
54
+ **Accessors:** `compositor`, `parts`, `hasMorphTargets`, `mappedBlendshapeCount`
55
+
56
+ ## License
57
+
58
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,488 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ BlendshapeController: () => BlendshapeController,
24
+ OmoteA2E: () => OmoteA2E,
25
+ OmoteAvatar: () => OmoteAvatar,
26
+ discoverScene: () => discoverScene,
27
+ writeBlendshapes: () => writeBlendshapes
28
+ });
29
+ module.exports = __toCommonJS(index_exports);
30
+
31
+ // src/OmoteAvatar.ts
32
+ var import_core2 = require("@omote/core");
33
+
34
+ // src/SceneDiscovery.ts
35
+ var import_core = require("@omote/core");
36
+ var logger = (0, import_core.createLogger)("SceneDiscovery");
37
+ function normalizeName(name) {
38
+ return name.replace(/^morph_/i, "").replace(/^blendshape\./i, "");
39
+ }
40
+ var BONE_PATTERNS = {
41
+ head: /^head$/i,
42
+ neck: /^neck$/i,
43
+ leftEye: /^lefteye$/i,
44
+ rightEye: /^righteye$/i
45
+ };
46
+ function discoverScene(root) {
47
+ const meshes = [];
48
+ const morphEntries = [];
49
+ let faceMesh = null;
50
+ let mappedBlendshapeCount = 0;
51
+ const candidates = [root];
52
+ if (root.getChildMeshes) {
53
+ candidates.push(...root.getChildMeshes(false));
54
+ }
55
+ for (const mesh of candidates) {
56
+ const manager = mesh.morphTargetManager;
57
+ if (!manager) continue;
58
+ meshes.push(mesh);
59
+ if (!faceMesh || mesh.name === "Head_Mesh") {
60
+ faceMesh = mesh;
61
+ }
62
+ const morphLookup = /* @__PURE__ */ new Map();
63
+ const numTargets = manager.numTargets;
64
+ for (let t = 0; t < numTargets; t++) {
65
+ const morphTarget = manager.getTarget(t);
66
+ const normalized = normalizeName(morphTarget.name);
67
+ morphLookup.set(normalized, t);
68
+ }
69
+ const indices = new Int16Array(import_core.LAM_BLENDSHAPES.length);
70
+ let meshMapped = 0;
71
+ for (let i = 0; i < import_core.LAM_BLENDSHAPES.length; i++) {
72
+ const morphIdx = morphLookup.get(import_core.LAM_BLENDSHAPES[i]);
73
+ if (morphIdx !== void 0) {
74
+ indices[i] = morphIdx;
75
+ meshMapped++;
76
+ } else {
77
+ indices[i] = -1;
78
+ }
79
+ }
80
+ if (meshMapped > 0) {
81
+ morphEntries.push({ mesh, indices });
82
+ }
83
+ mappedBlendshapeCount = Math.max(mappedBlendshapeCount, meshMapped);
84
+ logger.debug(`Mesh "${mesh.name}": ${meshMapped}/${import_core.LAM_BLENDSHAPES.length} blendshapes mapped`);
85
+ }
86
+ let headBone = null;
87
+ let neckBone = null;
88
+ let leftEyeBone = null;
89
+ let rightEyeBone = null;
90
+ const transformNodes = root.getChildTransformNodes(false);
91
+ for (const node of transformNodes) {
92
+ if (!headBone && BONE_PATTERNS.head.test(node.name)) {
93
+ headBone = node;
94
+ } else if (!neckBone && BONE_PATTERNS.neck.test(node.name)) {
95
+ neckBone = node;
96
+ } else if (!leftEyeBone && BONE_PATTERNS.leftEye.test(node.name)) {
97
+ leftEyeBone = node;
98
+ } else if (!rightEyeBone && BONE_PATTERNS.rightEye.test(node.name)) {
99
+ rightEyeBone = node;
100
+ }
101
+ if (headBone && neckBone && leftEyeBone && rightEyeBone) break;
102
+ }
103
+ if (morphEntries.length === 0) {
104
+ logger.warn("No morph targets found in scene");
105
+ }
106
+ if (!headBone) {
107
+ logger.warn("Head bone not found in scene");
108
+ }
109
+ const boneNames = [
110
+ headBone && "Head",
111
+ neckBone && "Neck",
112
+ leftEyeBone && "LeftEye",
113
+ rightEyeBone && "RightEye"
114
+ ].filter(Boolean);
115
+ logger.info(
116
+ `Discovery complete: ${meshes.length} mesh(es), ${mappedBlendshapeCount} mapped blendshapes, bones: [${boneNames.join(", ")}]`
117
+ );
118
+ return {
119
+ meshes,
120
+ headBone,
121
+ neckBone,
122
+ leftEyeBone,
123
+ rightEyeBone,
124
+ morphEntries,
125
+ faceMesh,
126
+ mappedBlendshapeCount
127
+ };
128
+ }
129
+
130
+ // src/BlendshapeWriter.ts
131
+ function writeBlendshapes(blendshapes, morphEntries) {
132
+ for (let e = 0; e < morphEntries.length; e++) {
133
+ const { mesh, indices } = morphEntries[e];
134
+ const manager = mesh.morphTargetManager;
135
+ if (!manager) continue;
136
+ for (let i = 0; i < 52; i++) {
137
+ const morphIdx = indices[i];
138
+ if (morphIdx >= 0) {
139
+ const target = manager.getTarget(morphIdx);
140
+ if (target) {
141
+ target.influence = blendshapes[i];
142
+ }
143
+ }
144
+ }
145
+ }
146
+ }
147
+
148
+ // src/OmoteAvatar.ts
149
+ var logger2 = (0, import_core2.createLogger)("OmoteAvatar");
150
+ var OmoteAvatar = class {
151
+ constructor(options) {
152
+ // State
153
+ this.currentBlendshapes = null;
154
+ this._emotion = null;
155
+ this._isSpeaking = false;
156
+ this._state = "idle";
157
+ this._audioEnergy = 0;
158
+ this._camera = null;
159
+ // Frame source connection
160
+ this.frameSourceCallback = null;
161
+ this.connectedSource = null;
162
+ // Auto-update
163
+ this.renderCallback = null;
164
+ this.lastTime = 0;
165
+ this.scene = options.scene;
166
+ this.discovery = discoverScene(options.target);
167
+ this.controller = new import_core2.CharacterController({
168
+ compositor: options.compositor,
169
+ gaze: options.gaze
170
+ });
171
+ if (this.discovery.morphEntries.length === 0) {
172
+ logger2.warn("No morph targets found \u2014 blendshape animation will have no effect");
173
+ }
174
+ if (!this.discovery.headBone) {
175
+ logger2.warn("Head bone not found \u2014 gaze tracking will be disabled");
176
+ }
177
+ logger2.info(
178
+ `Initialized: ${this.discovery.meshes.length} mesh(es), ${this.discovery.mappedBlendshapeCount} mapped blendshapes, headBone=${!!this.discovery.headBone}`
179
+ );
180
+ if (options.autoUpdate) {
181
+ this.registerAutoUpdate();
182
+ }
183
+ }
184
+ // ---------------------------------------------------------------------------
185
+ // Frame update
186
+ // ---------------------------------------------------------------------------
187
+ /**
188
+ * Call each frame with delta time and camera.
189
+ *
190
+ * Runs CharacterController (compositor, gaze, procedural life) then writes
191
+ * blendshapes to morph targets and applies head rotation.
192
+ *
193
+ * If using autoUpdate, this is called automatically via scene.registerBeforeRender().
194
+ *
195
+ * @param delta - Time since last frame in seconds
196
+ * @param camera - Active Babylon.js camera (for gaze tracking)
197
+ * @param avatarRotationY - Optional avatar Y rotation in radians for gaze compensation
198
+ */
199
+ update(delta, camera, avatarRotationY) {
200
+ const camPos = camera.globalPosition;
201
+ const cameraWorldPos = { x: camPos.x, y: camPos.y, z: camPos.z };
202
+ let headWorldPos;
203
+ let headWorldQuat;
204
+ if (this.discovery.headBone) {
205
+ const wp = this.discovery.headBone.getAbsolutePosition();
206
+ headWorldPos = { x: wp.x, y: wp.y, z: wp.z };
207
+ const rq = this.discovery.headBone.absoluteRotationQuaternion;
208
+ if (rq) {
209
+ headWorldQuat = { x: rq.x, y: rq.y, z: rq.z, w: rq.w };
210
+ }
211
+ }
212
+ const output = this.controller.update({
213
+ deltaTime: delta,
214
+ baseBlendshapes: this.currentBlendshapes,
215
+ emotion: this._emotion,
216
+ isSpeaking: this._isSpeaking,
217
+ state: this._state,
218
+ audioEnergy: this._audioEnergy,
219
+ cameraWorldPos,
220
+ headWorldPos,
221
+ headWorldQuat,
222
+ avatarRotationY: avatarRotationY ?? 0
223
+ });
224
+ writeBlendshapes(output.blendshapes, this.discovery.morphEntries);
225
+ if (this.discovery.headBone) {
226
+ this.discovery.headBone.rotation.y = output.headDelta.yaw;
227
+ this.discovery.headBone.rotation.x = output.headDelta.pitch;
228
+ }
229
+ }
230
+ // ---------------------------------------------------------------------------
231
+ // Frame source connection
232
+ // ---------------------------------------------------------------------------
233
+ /**
234
+ * Connect a frame source (PlaybackPipeline, MicLipSync, etc.).
235
+ *
236
+ * Automatically listens for 'frame' events and stores the latest blendshapes.
237
+ * Only one source can be connected at a time; calling again disconnects the previous.
238
+ */
239
+ connectFrameSource(source) {
240
+ this.disconnectFrameSource();
241
+ this.frameSourceCallback = (frame) => {
242
+ this.currentBlendshapes = frame.blendshapes;
243
+ };
244
+ source.on("frame", this.frameSourceCallback);
245
+ this.connectedSource = source;
246
+ logger2.debug("Frame source connected");
247
+ }
248
+ /** Disconnect the current frame source (if any). */
249
+ disconnectFrameSource() {
250
+ if (this.connectedSource && this.frameSourceCallback) {
251
+ this.connectedSource.off?.("frame", this.frameSourceCallback);
252
+ logger2.debug("Frame source disconnected");
253
+ }
254
+ this.connectedSource = null;
255
+ this.frameSourceCallback = null;
256
+ }
257
+ // ---------------------------------------------------------------------------
258
+ // State setters
259
+ // ---------------------------------------------------------------------------
260
+ /** Set blendshapes directly (alternative to connectFrameSource). */
261
+ setFrame(blendshapes) {
262
+ this.currentBlendshapes = blendshapes;
263
+ }
264
+ /** Set emotion (string preset like 'happy' or EmotionWeights object). */
265
+ setEmotion(emotion) {
266
+ this._emotion = emotion;
267
+ }
268
+ /** Set whether the avatar is currently speaking (drives mouth emphasis). */
269
+ setSpeaking(speaking) {
270
+ this._isSpeaking = speaking;
271
+ }
272
+ /** Set conversational state (idle, listening, thinking, speaking). */
273
+ setState(state) {
274
+ this._state = state;
275
+ }
276
+ /** Set audio energy level (0-1, drives emphasis/gesture intensity). */
277
+ setAudioEnergy(energy) {
278
+ this._audioEnergy = energy;
279
+ }
280
+ /**
281
+ * Set the active camera for gaze tracking.
282
+ * Required when using autoUpdate. Can also be passed directly to update().
283
+ */
284
+ setCamera(camera) {
285
+ this._camera = camera;
286
+ }
287
+ // ---------------------------------------------------------------------------
288
+ // Accessors
289
+ // ---------------------------------------------------------------------------
290
+ /** Access underlying FaceCompositor for advanced use. */
291
+ get compositor() {
292
+ return this.controller.compositor;
293
+ }
294
+ /** Access SceneDiscoveryResult (meshes, bones, morph entries). */
295
+ get parts() {
296
+ return this.discovery;
297
+ }
298
+ /** Whether the scene has any mapped morph targets. */
299
+ get hasMorphTargets() {
300
+ return this.discovery.morphEntries.length > 0;
301
+ }
302
+ /** Number of successfully mapped ARKit blendshapes. */
303
+ get mappedBlendshapeCount() {
304
+ return this.discovery.mappedBlendshapeCount;
305
+ }
306
+ // ---------------------------------------------------------------------------
307
+ // Lifecycle
308
+ // ---------------------------------------------------------------------------
309
+ /** Reset all state (smoothing, life layer, emotions). */
310
+ reset() {
311
+ this.currentBlendshapes = null;
312
+ this._emotion = null;
313
+ this._isSpeaking = false;
314
+ this._state = "idle";
315
+ this._audioEnergy = 0;
316
+ this.controller.reset();
317
+ }
318
+ /** Clean up all resources: disconnect frame source, unregister render loop, dispose controller. */
319
+ dispose() {
320
+ this.disconnectFrameSource();
321
+ if (this.renderCallback) {
322
+ this.scene.unregisterBeforeRender(this.renderCallback);
323
+ this.renderCallback = null;
324
+ }
325
+ this.controller.dispose();
326
+ logger2.debug("Disposed");
327
+ }
328
+ // ---------------------------------------------------------------------------
329
+ // Internal
330
+ // ---------------------------------------------------------------------------
331
+ registerAutoUpdate() {
332
+ this.lastTime = performance.now();
333
+ this.renderCallback = () => {
334
+ const now = performance.now();
335
+ const delta = (now - this.lastTime) / 1e3;
336
+ this.lastTime = now;
337
+ if (this._camera) {
338
+ this.update(delta, this._camera);
339
+ }
340
+ };
341
+ this.scene.registerBeforeRender(this.renderCallback);
342
+ }
343
+ };
344
+
345
+ // src/BlendshapeController.ts
346
+ var import_core3 = require("@omote/core");
347
+ var BlendshapeController = class {
348
+ constructor(target, scene, options) {
349
+ this._meshes = [];
350
+ this.nameToIndex = [];
351
+ this.currentWeights = [];
352
+ this.renderObserver = null;
353
+ this.pendingWeights = null;
354
+ this.blendshapeNames = options?.names ?? import_core3.LAM_BLENDSHAPES;
355
+ this.smoothing = options?.smoothing ?? 0.7;
356
+ this.scene = scene;
357
+ this.onMeshesFound = options?.onMeshesFound;
358
+ if (options?.autoFind !== false) {
359
+ this.setTarget(target);
360
+ }
361
+ if (options?.autoRegister) {
362
+ this.registerRenderLoop();
363
+ }
364
+ }
365
+ get meshes() {
366
+ return this._meshes;
367
+ }
368
+ /** Normalize Babylon morph target names (strip common prefixes) */
369
+ normalizeName(name) {
370
+ return name.replace(/^morph_/i, "").replace(/^blendshape\./i, "");
371
+ }
372
+ setTarget(target) {
373
+ this._meshes = [];
374
+ this.nameToIndex = [];
375
+ const candidates = [target];
376
+ if (target.getChildMeshes) {
377
+ candidates.push(...target.getChildMeshes(false));
378
+ }
379
+ for (const mesh of candidates) {
380
+ const manager = mesh.morphTargetManager;
381
+ if (!manager) continue;
382
+ this._meshes.push(mesh);
383
+ const morphLookup = /* @__PURE__ */ new Map();
384
+ const numTargets = manager.numTargets;
385
+ for (let t = 0; t < numTargets; t++) {
386
+ const morphTarget = manager.getTarget(t);
387
+ const normalizedName = this.normalizeName(morphTarget.name);
388
+ morphLookup.set(normalizedName, t);
389
+ }
390
+ const map = /* @__PURE__ */ new Map();
391
+ for (let i = 0; i < this.blendshapeNames.length; i++) {
392
+ const name = this.blendshapeNames[i];
393
+ const idx = morphLookup.get(name);
394
+ if (idx !== void 0) {
395
+ map.set(name, idx);
396
+ }
397
+ }
398
+ this.nameToIndex.push(map);
399
+ }
400
+ this.currentWeights = new Array(this.blendshapeNames.length).fill(0);
401
+ if (this._meshes.length > 0 && this.onMeshesFound) {
402
+ this.onMeshesFound(this._meshes);
403
+ }
404
+ }
405
+ update(weights) {
406
+ this.currentWeights = (0, import_core3.lerpBlendshapes)(this.currentWeights, weights, this.smoothing);
407
+ for (let m = 0; m < this._meshes.length; m++) {
408
+ const mesh = this._meshes[m];
409
+ const map = this.nameToIndex[m];
410
+ const manager = mesh.morphTargetManager;
411
+ if (!manager || !map) continue;
412
+ for (let i = 0; i < this.blendshapeNames.length; i++) {
413
+ const name = this.blendshapeNames[i];
414
+ const morphIdx = map.get(name);
415
+ if (morphIdx !== void 0) {
416
+ const target = manager.getTarget(morphIdx);
417
+ if (target) {
418
+ target.influence = this.currentWeights[i];
419
+ }
420
+ }
421
+ }
422
+ }
423
+ }
424
+ /** Buffer weights for the next render loop tick (used with autoRegister) */
425
+ setWeightsForNextFrame(weights) {
426
+ this.pendingWeights = weights;
427
+ }
428
+ registerRenderLoop() {
429
+ if (!this.scene) return;
430
+ const callback = () => {
431
+ if (this.pendingWeights) {
432
+ this.update(this.pendingWeights);
433
+ this.pendingWeights = null;
434
+ }
435
+ };
436
+ this.scene.registerBeforeRender(callback);
437
+ this.renderObserver = () => {
438
+ this.scene?.unregisterBeforeRender(callback);
439
+ };
440
+ }
441
+ dispose() {
442
+ if (this.renderObserver) {
443
+ this.renderObserver();
444
+ this.renderObserver = null;
445
+ }
446
+ this._meshes = [];
447
+ this.nameToIndex = [];
448
+ this.currentWeights = [];
449
+ this.scene = null;
450
+ }
451
+ };
452
+
453
+ // src/OmoteA2E.ts
454
+ var import_core4 = require("@omote/core");
455
+ var OmoteA2E = class {
456
+ constructor(options) {
457
+ const { target, scene, controllerOptions, ...orchestratorConfig } = options;
458
+ this.controller = new BlendshapeController(target, scene, controllerOptions);
459
+ this.orchestrator = new import_core4.A2EOrchestrator(orchestratorConfig);
460
+ }
461
+ async load() {
462
+ return this.orchestrator.load();
463
+ }
464
+ async start() {
465
+ return this.orchestrator.start();
466
+ }
467
+ stop() {
468
+ this.orchestrator.stop();
469
+ }
470
+ update() {
471
+ const w = this.orchestrator.latestWeights;
472
+ if (w) this.controller.update(w);
473
+ }
474
+ async dispose() {
475
+ await this.orchestrator.dispose();
476
+ this.controller.dispose();
477
+ }
478
+ get isReady() {
479
+ return this.orchestrator.isReady;
480
+ }
481
+ get isStreaming() {
482
+ return this.orchestrator.isStreaming;
483
+ }
484
+ get backend() {
485
+ return this.orchestrator.backend;
486
+ }
487
+ };
488
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/OmoteAvatar.ts","../src/SceneDiscovery.ts","../src/BlendshapeWriter.ts","../src/BlendshapeController.ts","../src/OmoteA2E.ts"],"sourcesContent":["// High-level\nexport { OmoteAvatar } from './OmoteAvatar';\nexport type { OmoteAvatarOptions, FrameSource } from './OmoteAvatar';\n\n// Scene utilities\nexport { discoverScene } from './SceneDiscovery';\nexport type { SceneDiscoveryResult, MorphIndexEntry } from './SceneDiscovery';\nexport { writeBlendshapes } from './BlendshapeWriter';\n\n// Low-level escape hatch\nexport { BlendshapeController } from './BlendshapeController';\nexport type { BlendshapeControllerOptions } from './BlendshapeController';\n\n/** @deprecated Use OmoteAvatar instead */\nexport { OmoteA2E } from './OmoteA2E';\nexport type { OmoteA2EOptions } from './OmoteA2E';\n","/**\n * OmoteAvatar — Full-featured Babylon.js avatar controller.\n *\n * Owns CharacterController, SceneDiscovery, and BlendshapeWriter.\n * Mirrors the Three.js OmoteAvatar API for consistency across adapters.\n *\n * Usage:\n * ```typescript\n * import { OmoteAvatar } from '@omote/babylon';\n * import { createA2E, PlaybackPipeline } from '@omote/core';\n *\n * const avatar = new OmoteAvatar({ target: mesh, scene });\n * avatar.setCamera(camera);\n *\n * // Connect a frame source (PlaybackPipeline, MicLipSync, etc.)\n * const pipeline = new PlaybackPipeline({ lam: createA2E() });\n * avatar.connectFrameSource(pipeline);\n *\n * // Option A: manual update in render loop\n * scene.registerBeforeRender(() => avatar.update(engine.getDeltaTime() / 1000, camera));\n *\n * // Option B: autoUpdate (registers scene.registerBeforeRender internally)\n * const avatar = new OmoteAvatar({ target: mesh, scene, autoUpdate: true });\n * avatar.setCamera(camera);\n * ```\n *\n * @category Babylon\n */\n\nimport { CharacterController, createLogger } from '@omote/core';\n\nconst logger = createLogger('OmoteAvatar');\nimport type {\n CharacterControllerConfig,\n EmotionWeights,\n ConversationalState,\n FaceCompositorConfig,\n} from '@omote/core';\nimport type { AbstractMesh, Scene, Camera } from '@babylonjs/core';\n\nimport { discoverScene, type SceneDiscoveryResult } from './SceneDiscovery';\nimport { writeBlendshapes } from './BlendshapeWriter';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** Generic frame source -- any object that emits 'frame' events */\nexport interface FrameSource {\n on(event: 'frame', callback: (frame: { blendshapes: Float32Array }) => void): void;\n off?(event: 'frame', callback: (...args: any[]) => void): void;\n}\n\nexport interface OmoteAvatarOptions {\n /** Root mesh of the avatar (typically loaded via SceneLoader) */\n target: AbstractMesh;\n /** Babylon.js scene */\n scene: Scene;\n /** FaceCompositor configuration */\n compositor?: FaceCompositorConfig;\n /** Gaze tracking configuration */\n gaze?: CharacterControllerConfig['gaze'];\n /**\n * Register scene.registerBeforeRender() for automatic update.\n * Requires setCamera() to be called before the first frame.\n * Default: false\n */\n autoUpdate?: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// OmoteAvatar\n// ---------------------------------------------------------------------------\n\nexport class OmoteAvatar {\n private readonly controller: CharacterController;\n private readonly discovery: SceneDiscoveryResult;\n private readonly scene: Scene;\n\n // State\n private currentBlendshapes: Float32Array | null = null;\n private _emotion: string | EmotionWeights | null = null;\n private _isSpeaking = false;\n private _state: ConversationalState = 'idle';\n private _audioEnergy = 0;\n private _camera: Camera | null = null;\n\n // Frame source connection\n private frameSourceCallback: ((frame: { blendshapes: Float32Array }) => void) | null = null;\n private connectedSource: FrameSource | null = null;\n\n // Auto-update\n private renderCallback: (() => void) | null = null;\n private lastTime = 0;\n\n constructor(options: OmoteAvatarOptions) {\n this.scene = options.scene;\n this.discovery = discoverScene(options.target);\n this.controller = new CharacterController({\n compositor: options.compositor,\n gaze: options.gaze,\n });\n\n if (this.discovery.morphEntries.length === 0) {\n logger.warn('No morph targets found — blendshape animation will have no effect');\n }\n if (!this.discovery.headBone) {\n logger.warn('Head bone not found — gaze tracking will be disabled');\n }\n logger.info(\n `Initialized: ${this.discovery.meshes.length} mesh(es), ${this.discovery.mappedBlendshapeCount} mapped blendshapes, headBone=${!!this.discovery.headBone}`,\n );\n\n if (options.autoUpdate) {\n this.registerAutoUpdate();\n }\n }\n\n // ---------------------------------------------------------------------------\n // Frame update\n // ---------------------------------------------------------------------------\n\n /**\n * Call each frame with delta time and camera.\n *\n * Runs CharacterController (compositor, gaze, procedural life) then writes\n * blendshapes to morph targets and applies head rotation.\n *\n * If using autoUpdate, this is called automatically via scene.registerBeforeRender().\n *\n * @param delta - Time since last frame in seconds\n * @param camera - Active Babylon.js camera (for gaze tracking)\n * @param avatarRotationY - Optional avatar Y rotation in radians for gaze compensation\n */\n update(delta: number, camera: Camera, avatarRotationY?: number): void {\n // Get camera world position (globalPosition handles parented cameras)\n const camPos = camera.globalPosition;\n const cameraWorldPos = { x: camPos.x, y: camPos.y, z: camPos.z };\n\n // Get head bone world position + quaternion (if available)\n let headWorldPos: { x: number; y: number; z: number } | undefined;\n let headWorldQuat: { x: number; y: number; z: number; w: number } | undefined;\n if (this.discovery.headBone) {\n const wp = this.discovery.headBone.getAbsolutePosition();\n headWorldPos = { x: wp.x, y: wp.y, z: wp.z };\n const rq = this.discovery.headBone.absoluteRotationQuaternion;\n if (rq) {\n headWorldQuat = { x: rq.x, y: rq.y, z: rq.z, w: rq.w };\n }\n }\n\n // Run CharacterController (compositor + gaze + life layer)\n const output = this.controller.update({\n deltaTime: delta,\n baseBlendshapes: this.currentBlendshapes,\n emotion: this._emotion,\n isSpeaking: this._isSpeaking,\n state: this._state,\n audioEnergy: this._audioEnergy,\n cameraWorldPos,\n headWorldPos,\n headWorldQuat,\n avatarRotationY: avatarRotationY ?? 0,\n });\n\n // Write blendshapes to morph targets\n writeBlendshapes(output.blendshapes, this.discovery.morphEntries);\n\n // Apply head rotation delta\n if (this.discovery.headBone) {\n this.discovery.headBone.rotation.y = output.headDelta.yaw;\n this.discovery.headBone.rotation.x = output.headDelta.pitch;\n }\n }\n\n // ---------------------------------------------------------------------------\n // Frame source connection\n // ---------------------------------------------------------------------------\n\n /**\n * Connect a frame source (PlaybackPipeline, MicLipSync, etc.).\n *\n * Automatically listens for 'frame' events and stores the latest blendshapes.\n * Only one source can be connected at a time; calling again disconnects the previous.\n */\n connectFrameSource(source: FrameSource): void {\n this.disconnectFrameSource();\n this.frameSourceCallback = (frame) => {\n this.currentBlendshapes = frame.blendshapes;\n };\n source.on('frame', this.frameSourceCallback);\n this.connectedSource = source;\n logger.debug('Frame source connected');\n }\n\n /** Disconnect the current frame source (if any). */\n disconnectFrameSource(): void {\n if (this.connectedSource && this.frameSourceCallback) {\n this.connectedSource.off?.('frame', this.frameSourceCallback);\n logger.debug('Frame source disconnected');\n }\n this.connectedSource = null;\n this.frameSourceCallback = null;\n }\n\n // ---------------------------------------------------------------------------\n // State setters\n // ---------------------------------------------------------------------------\n\n /** Set blendshapes directly (alternative to connectFrameSource). */\n setFrame(blendshapes: Float32Array): void {\n this.currentBlendshapes = blendshapes;\n }\n\n /** Set emotion (string preset like 'happy' or EmotionWeights object). */\n setEmotion(emotion: string | EmotionWeights): void {\n this._emotion = emotion;\n }\n\n /** Set whether the avatar is currently speaking (drives mouth emphasis). */\n setSpeaking(speaking: boolean): void {\n this._isSpeaking = speaking;\n }\n\n /** Set conversational state (idle, listening, thinking, speaking). */\n setState(state: ConversationalState): void {\n this._state = state;\n }\n\n /** Set audio energy level (0-1, drives emphasis/gesture intensity). */\n setAudioEnergy(energy: number): void {\n this._audioEnergy = energy;\n }\n\n /**\n * Set the active camera for gaze tracking.\n * Required when using autoUpdate. Can also be passed directly to update().\n */\n setCamera(camera: Camera): void {\n this._camera = camera;\n }\n\n // ---------------------------------------------------------------------------\n // Accessors\n // ---------------------------------------------------------------------------\n\n /** Access underlying FaceCompositor for advanced use. */\n get compositor() {\n return this.controller.compositor;\n }\n\n /** Access SceneDiscoveryResult (meshes, bones, morph entries). */\n get parts(): SceneDiscoveryResult {\n return this.discovery;\n }\n\n /** Whether the scene has any mapped morph targets. */\n get hasMorphTargets(): boolean {\n return this.discovery.morphEntries.length > 0;\n }\n\n /** Number of successfully mapped ARKit blendshapes. */\n get mappedBlendshapeCount(): number {\n return this.discovery.mappedBlendshapeCount;\n }\n\n // ---------------------------------------------------------------------------\n // Lifecycle\n // ---------------------------------------------------------------------------\n\n /** Reset all state (smoothing, life layer, emotions). */\n reset(): void {\n this.currentBlendshapes = null;\n this._emotion = null;\n this._isSpeaking = false;\n this._state = 'idle';\n this._audioEnergy = 0;\n this.controller.reset();\n }\n\n /** Clean up all resources: disconnect frame source, unregister render loop, dispose controller. */\n dispose(): void {\n this.disconnectFrameSource();\n if (this.renderCallback) {\n this.scene.unregisterBeforeRender(this.renderCallback);\n this.renderCallback = null;\n }\n this.controller.dispose();\n logger.debug('Disposed');\n }\n\n // ---------------------------------------------------------------------------\n // Internal\n // ---------------------------------------------------------------------------\n\n private registerAutoUpdate(): void {\n this.lastTime = performance.now();\n this.renderCallback = () => {\n const now = performance.now();\n const delta = (now - this.lastTime) / 1000;\n this.lastTime = now;\n if (this._camera) {\n this.update(delta, this._camera);\n }\n };\n this.scene.registerBeforeRender(this.renderCallback);\n }\n}\n","/**\n * SceneDiscovery — Discover avatar structure from a Babylon.js scene graph.\n *\n * Finds morph targets, head/neck/eye bones, and pre-computes a fast index\n * mapping from LAM_BLENDSHAPES order to per-mesh morph target indices.\n *\n * @category Babylon\n */\n\nimport { LAM_BLENDSHAPES, createLogger } from '@omote/core';\n\nconst logger = createLogger('SceneDiscovery');\nimport type { AbstractMesh, TransformNode } from '@babylonjs/core';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface MorphIndexEntry {\n mesh: AbstractMesh;\n /** indices[lamIndex] = morphTargetIndex (or -1 if not found) */\n indices: Int16Array;\n}\n\nexport interface SceneDiscoveryResult {\n /** All meshes under the root that have a MorphTargetManager */\n meshes: AbstractMesh[];\n /** Head bone (TransformNode named 'Head') or null */\n headBone: TransformNode | null;\n /** Neck bone (TransformNode named 'Neck') or null */\n neckBone: TransformNode | null;\n /** Left eye bone (TransformNode named 'LeftEye') or null */\n leftEyeBone: TransformNode | null;\n /** Right eye bone (TransformNode named 'RightEye') or null */\n rightEyeBone: TransformNode | null;\n /** Pre-computed morph index mapping per mesh */\n morphEntries: MorphIndexEntry[];\n /** Primary face mesh (prefers 'Head_Mesh', falls back to first with morph targets) */\n faceMesh: AbstractMesh | null;\n /** Total number of ARKit blendshapes successfully mapped across all meshes */\n mappedBlendshapeCount: number;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/** Normalize morph target name by stripping common prefixes */\nfunction normalizeName(name: string): string {\n return name.replace(/^morph_/i, '').replace(/^blendshape\\./i, '');\n}\n\n/** Case-insensitive bone name matching */\nconst BONE_PATTERNS: Record<string, RegExp> = {\n head: /^head$/i,\n neck: /^neck$/i,\n leftEye: /^lefteye$/i,\n rightEye: /^righteye$/i,\n};\n\n// ---------------------------------------------------------------------------\n// Main API\n// ---------------------------------------------------------------------------\n\n/**\n * Discover avatar structure from a Babylon.js root node.\n *\n * Traverses the scene graph under `root` to find:\n * - Meshes with MorphTargetManagers\n * - Head, neck, and eye bones\n * - Pre-computed LAM_BLENDSHAPES -> morph target index mapping\n *\n * @param root - The root AbstractMesh (typically loaded via SceneLoader)\n * @returns SceneDiscoveryResult with all discovered components\n */\nexport function discoverScene(root: AbstractMesh): SceneDiscoveryResult {\n const meshes: AbstractMesh[] = [];\n const morphEntries: MorphIndexEntry[] = [];\n let faceMesh: AbstractMesh | null = null;\n let mappedBlendshapeCount = 0;\n\n // ---- Morph target discovery ----\n\n // Collect all candidate meshes (root + children)\n const candidates: AbstractMesh[] = [root];\n if (root.getChildMeshes) {\n candidates.push(...root.getChildMeshes(false));\n }\n\n for (const mesh of candidates) {\n const manager = mesh.morphTargetManager;\n if (!manager) continue;\n\n meshes.push(mesh);\n\n // Prefer mesh named 'Head_Mesh' as the face mesh\n if (!faceMesh || mesh.name === 'Head_Mesh') {\n faceMesh = mesh;\n }\n\n // Build normalized name -> morph target index lookup for this mesh\n const morphLookup = new Map<string, number>();\n const numTargets = manager.numTargets;\n for (let t = 0; t < numTargets; t++) {\n const morphTarget = manager.getTarget(t);\n const normalized = normalizeName(morphTarget.name);\n morphLookup.set(normalized, t);\n }\n\n // Pre-compute Int16Array mapping: lamIndex -> morphTargetIndex (or -1)\n const indices = new Int16Array(LAM_BLENDSHAPES.length);\n let meshMapped = 0;\n for (let i = 0; i < LAM_BLENDSHAPES.length; i++) {\n const morphIdx = morphLookup.get(LAM_BLENDSHAPES[i]);\n if (morphIdx !== undefined) {\n indices[i] = morphIdx;\n meshMapped++;\n } else {\n indices[i] = -1;\n }\n }\n\n if (meshMapped > 0) {\n morphEntries.push({ mesh, indices });\n }\n mappedBlendshapeCount = Math.max(mappedBlendshapeCount, meshMapped);\n\n logger.debug(`Mesh \"${mesh.name}\": ${meshMapped}/${LAM_BLENDSHAPES.length} blendshapes mapped`);\n }\n\n // ---- Bone discovery ----\n\n let headBone: TransformNode | null = null;\n let neckBone: TransformNode | null = null;\n let leftEyeBone: TransformNode | null = null;\n let rightEyeBone: TransformNode | null = null;\n\n // getChildTransformNodes is on TransformNode (AbstractMesh extends TransformNode)\n const transformNodes = root.getChildTransformNodes(false);\n\n for (const node of transformNodes) {\n if (!headBone && BONE_PATTERNS.head.test(node.name)) {\n headBone = node;\n } else if (!neckBone && BONE_PATTERNS.neck.test(node.name)) {\n neckBone = node;\n } else if (!leftEyeBone && BONE_PATTERNS.leftEye.test(node.name)) {\n leftEyeBone = node;\n } else if (!rightEyeBone && BONE_PATTERNS.rightEye.test(node.name)) {\n rightEyeBone = node;\n }\n\n // Early exit if all bones found\n if (headBone && neckBone && leftEyeBone && rightEyeBone) break;\n }\n\n if (morphEntries.length === 0) {\n logger.warn('No morph targets found in scene');\n }\n if (!headBone) {\n logger.warn('Head bone not found in scene');\n }\n\n const boneNames = [\n headBone && 'Head',\n neckBone && 'Neck',\n leftEyeBone && 'LeftEye',\n rightEyeBone && 'RightEye',\n ].filter(Boolean);\n\n logger.info(\n `Discovery complete: ${meshes.length} mesh(es), ${mappedBlendshapeCount} mapped blendshapes, bones: [${boneNames.join(', ')}]`,\n );\n\n return {\n meshes,\n headBone,\n neckBone,\n leftEyeBone,\n rightEyeBone,\n morphEntries,\n faceMesh,\n mappedBlendshapeCount,\n };\n}\n","/**\n * BlendshapeWriter — Zero-lookup hot-path blendshape application.\n *\n * Uses pre-computed Int16Array indices from SceneDiscovery for O(1) lookups\n * per blendshape per mesh. No Map.get(), no string comparison on the hot path.\n *\n * @category Babylon\n */\n\nimport type { MorphIndexEntry } from './SceneDiscovery';\n\n/**\n * Write 52 ARKit blendshapes to Babylon.js morph targets.\n *\n * Uses pre-computed indices for zero-lookup hot path.\n * Call this every frame after CharacterController.update().\n *\n * @param blendshapes - 52-element Float32Array in LAM_BLENDSHAPES order\n * @param morphEntries - Pre-computed index mappings from discoverScene()\n */\nexport function writeBlendshapes(\n blendshapes: Float32Array,\n morphEntries: MorphIndexEntry[],\n): void {\n for (let e = 0; e < morphEntries.length; e++) {\n const { mesh, indices } = morphEntries[e];\n const manager = mesh.morphTargetManager;\n if (!manager) continue;\n\n for (let i = 0; i < 52; i++) {\n const morphIdx = indices[i];\n if (morphIdx >= 0) {\n const target = manager.getTarget(morphIdx);\n if (target) {\n target.influence = blendshapes[i];\n }\n }\n }\n }\n}\n","import { LAM_BLENDSHAPES, lerpBlendshapes } from '@omote/core';\nimport type { AbstractMesh, Scene } from '@babylonjs/core';\n\nexport interface BlendshapeControllerOptions {\n /** Blendshape names in order (default: LAM_BLENDSHAPES, 52 ARKit) */\n names?: readonly string[];\n /** Smoothing factor 0-1 (0 = no change, 1 = snap to target). Default: 0.7 */\n smoothing?: number;\n /** Traverse target for child meshes with MorphTargetManager automatically. Default: true */\n autoFind?: boolean;\n /** Register scene.registerBeforeRender() callback automatically. Default: false */\n autoRegister?: boolean;\n /** Called when meshes with morph targets are found */\n onMeshesFound?: (meshes: AbstractMesh[]) => void;\n}\n\nexport class BlendshapeController {\n private _meshes: AbstractMesh[] = [];\n private nameToIndex: Map<string, number>[] = [];\n private currentWeights: number[] = [];\n private blendshapeNames: readonly string[];\n private smoothing: number;\n private scene: Scene | null;\n private renderObserver: (() => void) | null = null;\n private pendingWeights: Float32Array | number[] | null = null;\n private onMeshesFound?: (meshes: AbstractMesh[]) => void;\n\n constructor(target: AbstractMesh, scene: Scene, options?: BlendshapeControllerOptions) {\n this.blendshapeNames = options?.names ?? LAM_BLENDSHAPES;\n this.smoothing = options?.smoothing ?? 0.7;\n this.scene = scene;\n this.onMeshesFound = options?.onMeshesFound;\n\n if (options?.autoFind !== false) {\n this.setTarget(target);\n }\n\n if (options?.autoRegister) {\n this.registerRenderLoop();\n }\n }\n\n get meshes(): AbstractMesh[] {\n return this._meshes;\n }\n\n /** Normalize Babylon morph target names (strip common prefixes) */\n private normalizeName(name: string): string {\n return name.replace(/^morph_/i, '').replace(/^blendshape\\./i, '');\n }\n\n setTarget(target: AbstractMesh): void {\n this._meshes = [];\n this.nameToIndex = [];\n\n // Collect meshes with MorphTargetManager\n const candidates: AbstractMesh[] = [target];\n if (target.getChildMeshes) {\n candidates.push(...target.getChildMeshes(false));\n }\n\n for (const mesh of candidates) {\n const manager = mesh.morphTargetManager;\n if (!manager) continue;\n\n this._meshes.push(mesh);\n\n // Build normalized name -> morph target index lookup\n const morphLookup = new Map<string, number>();\n const numTargets = manager.numTargets;\n for (let t = 0; t < numTargets; t++) {\n const morphTarget = manager.getTarget(t);\n const normalizedName = this.normalizeName(morphTarget.name);\n morphLookup.set(normalizedName, t);\n }\n\n // Map blendshape names to morph target indices\n const map = new Map<string, number>();\n for (let i = 0; i < this.blendshapeNames.length; i++) {\n const name = this.blendshapeNames[i];\n const idx = morphLookup.get(name);\n if (idx !== undefined) {\n map.set(name, idx);\n }\n }\n\n this.nameToIndex.push(map);\n }\n\n this.currentWeights = new Array(this.blendshapeNames.length).fill(0);\n\n if (this._meshes.length > 0 && this.onMeshesFound) {\n this.onMeshesFound(this._meshes);\n }\n }\n\n update(weights: Float32Array | number[]): void {\n this.currentWeights = lerpBlendshapes(this.currentWeights, weights, this.smoothing);\n\n for (let m = 0; m < this._meshes.length; m++) {\n const mesh = this._meshes[m];\n const map = this.nameToIndex[m];\n const manager = mesh.morphTargetManager;\n if (!manager || !map) continue;\n\n for (let i = 0; i < this.blendshapeNames.length; i++) {\n const name = this.blendshapeNames[i];\n const morphIdx = map.get(name);\n if (morphIdx !== undefined) {\n const target = manager.getTarget(morphIdx);\n if (target) {\n target.influence = this.currentWeights[i];\n }\n }\n }\n }\n }\n\n /** Buffer weights for the next render loop tick (used with autoRegister) */\n setWeightsForNextFrame(weights: Float32Array | number[]): void {\n this.pendingWeights = weights;\n }\n\n private registerRenderLoop(): void {\n if (!this.scene) return;\n const callback = () => {\n if (this.pendingWeights) {\n this.update(this.pendingWeights);\n this.pendingWeights = null;\n }\n };\n this.scene.registerBeforeRender(callback);\n this.renderObserver = () => {\n this.scene?.unregisterBeforeRender(callback);\n };\n }\n\n dispose(): void {\n if (this.renderObserver) {\n this.renderObserver();\n this.renderObserver = null;\n }\n this._meshes = [];\n this.nameToIndex = [];\n this.currentWeights = [];\n this.scene = null;\n }\n}\n","import { A2EOrchestrator } from '@omote/core';\nimport type { A2EOrchestratorConfig } from '@omote/core';\nimport type { AbstractMesh, Scene } from '@babylonjs/core';\nimport { BlendshapeController } from './BlendshapeController';\nimport type { BlendshapeControllerOptions } from './BlendshapeController';\n\nexport interface OmoteA2EOptions extends A2EOrchestratorConfig {\n target: AbstractMesh;\n scene: Scene;\n controllerOptions?: BlendshapeControllerOptions;\n}\n\n/** @deprecated Use {@link OmoteAvatar} instead. OmoteA2E will be removed in v0.8.0. */\nexport class OmoteA2E {\n private orchestrator: A2EOrchestrator;\n private controller: BlendshapeController;\n\n constructor(options: OmoteA2EOptions) {\n const { target, scene, controllerOptions, ...orchestratorConfig } = options;\n this.controller = new BlendshapeController(target, scene, controllerOptions);\n this.orchestrator = new A2EOrchestrator(orchestratorConfig);\n }\n\n async load(): Promise<void> { return this.orchestrator.load(); }\n async start(): Promise<void> { return this.orchestrator.start(); }\n stop(): void { this.orchestrator.stop(); }\n\n update(): void {\n const w = this.orchestrator.latestWeights;\n if (w) this.controller.update(w);\n }\n\n async dispose(): Promise<void> {\n await this.orchestrator.dispose();\n this.controller.dispose();\n }\n\n get isReady(): boolean { return this.orchestrator.isReady; }\n get isStreaming(): boolean { return this.orchestrator.isStreaming; }\n get backend(): string | null { return this.orchestrator.backend; }\n}\n"],"mappings":"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","names":["import_core","logger","import_core","import_core"]}