@omote/avatar 0.1.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/dist/index.cjs ADDED
@@ -0,0 +1,288 @@
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
+ OmoteAvatarCore: () => OmoteAvatarCore
24
+ });
25
+ module.exports = __toCommonJS(index_exports);
26
+
27
+ // src/OmoteAvatarCore.ts
28
+ var import_core = require("@omote/core");
29
+ var OmoteAvatarCore = class {
30
+ constructor() {
31
+ // Voice primitives
32
+ this.ttsSpeaker = null;
33
+ this.speechListener = null;
34
+ this.voiceOrchestrator = null;
35
+ // Frame source wiring
36
+ this.frameSourceUnsub = null;
37
+ this.stateUnsub = null;
38
+ // Callbacks set by the adapter
39
+ this._onFrame = null;
40
+ this._onStateChange = null;
41
+ // State
42
+ this._isSpeaking = false;
43
+ this._state = "idle";
44
+ }
45
+ get isSpeaking() {
46
+ return this._isSpeaking;
47
+ }
48
+ get state() {
49
+ return this._state;
50
+ }
51
+ get speaker() {
52
+ return this.ttsSpeaker ?? this.voiceOrchestrator?.speaker ?? null;
53
+ }
54
+ get listener() {
55
+ return this.speechListener ?? this.voiceOrchestrator?.listener ?? null;
56
+ }
57
+ /**
58
+ * Set the frame handler. Called by the adapter to receive blendshape frames.
59
+ * The adapter writes these to its renderer (morphTargets, refs, etc.).
60
+ */
61
+ set onFrame(handler) {
62
+ this._onFrame = handler;
63
+ }
64
+ /**
65
+ * Set the state change handler. Called by the adapter to sync conversational state.
66
+ */
67
+ set onStateChange(handler) {
68
+ this._onStateChange = handler;
69
+ }
70
+ // ---------------------------------------------------------------------------
71
+ // Speaker (TTS → lip sync)
72
+ // ---------------------------------------------------------------------------
73
+ /** Warm up AudioContext for iOS/Safari autoplay policy. Call from user gesture. */
74
+ async warmup() {
75
+ if (this.ttsSpeaker) await this.ttsSpeaker.warmup();
76
+ }
77
+ async connectSpeaker(tts, config) {
78
+ await this.disconnectSpeaker();
79
+ const speaker = new import_core.TTSSpeaker();
80
+ await speaker.connect(tts, config);
81
+ this.ttsSpeaker = speaker;
82
+ this.wireSpeakerFrameSource(speaker);
83
+ }
84
+ async disconnectSpeaker() {
85
+ this.frameSourceUnsub?.();
86
+ this.frameSourceUnsub = null;
87
+ if (this.ttsSpeaker) {
88
+ await this.ttsSpeaker.dispose();
89
+ this.ttsSpeaker = null;
90
+ }
91
+ }
92
+ async speak(text, options) {
93
+ if (this.voiceOrchestrator) {
94
+ await this.voiceOrchestrator.speak(text, options);
95
+ return;
96
+ }
97
+ if (!this.ttsSpeaker) throw new Error("No speaker connected. Call connectSpeaker() first.");
98
+ this._isSpeaking = true;
99
+ this.updateState("speaking");
100
+ try {
101
+ await this.ttsSpeaker.speak(text, options);
102
+ } finally {
103
+ this._isSpeaking = false;
104
+ if (this._state === "speaking") this.updateState("idle");
105
+ }
106
+ }
107
+ async streamText(options) {
108
+ if (this.voiceOrchestrator) {
109
+ return this.voiceOrchestrator.streamText(options);
110
+ }
111
+ if (!this.ttsSpeaker) throw new Error("No speaker connected. Call connectSpeaker() first.");
112
+ this._isSpeaking = true;
113
+ this.updateState("speaking");
114
+ const stream = await this.ttsSpeaker.streamText(options ?? {});
115
+ return {
116
+ push: stream.push,
117
+ end: async () => {
118
+ try {
119
+ await stream.end();
120
+ } finally {
121
+ this._isSpeaking = false;
122
+ if (this._state === "speaking") this.updateState("idle");
123
+ }
124
+ }
125
+ };
126
+ }
127
+ stopSpeaking() {
128
+ if (this.voiceOrchestrator) {
129
+ this.voiceOrchestrator.stopSpeaking();
130
+ return;
131
+ }
132
+ this.ttsSpeaker?.stop();
133
+ }
134
+ // ---------------------------------------------------------------------------
135
+ // Listener (mic → VAD → ASR → transcript)
136
+ // ---------------------------------------------------------------------------
137
+ async connectListener(config) {
138
+ if (this.speechListener) {
139
+ await this.speechListener.dispose();
140
+ }
141
+ const listener = new import_core.SpeechListener(config);
142
+ this.speechListener = listener;
143
+ await listener.loadModels();
144
+ }
145
+ async disconnectListener() {
146
+ if (this.speechListener) {
147
+ await this.speechListener.dispose();
148
+ this.speechListener = null;
149
+ }
150
+ }
151
+ async startListening() {
152
+ if (this.voiceOrchestrator) {
153
+ await this.voiceOrchestrator.startListening();
154
+ return;
155
+ }
156
+ if (!this.speechListener) throw new Error("No listener connected. Call connectListener() first.");
157
+ this.updateState("listening");
158
+ await this.speechListener.start();
159
+ }
160
+ stopListening() {
161
+ if (this.voiceOrchestrator) {
162
+ this.voiceOrchestrator.stopListening();
163
+ return;
164
+ }
165
+ this.speechListener?.stop();
166
+ if (this._state === "listening") this.updateState("idle");
167
+ }
168
+ // Event subscriptions (require listener or orchestrator)
169
+ onTranscript(callback) {
170
+ const listener = this.speechListener ?? this.voiceOrchestrator?.listener;
171
+ if (!listener) throw new Error("No listener connected. Call connectListener() or connectVoice() first.");
172
+ listener.on("transcript", callback);
173
+ return () => {
174
+ listener.off?.("transcript", callback);
175
+ };
176
+ }
177
+ onTranscriptEvent(callback) {
178
+ const orch = this.voiceOrchestrator;
179
+ if (!orch) throw new Error("No voice connected. Call connectVoice() first.");
180
+ return orch.on("transcript", callback);
181
+ }
182
+ onVoiceStateChange(callback) {
183
+ const orch = this.voiceOrchestrator;
184
+ if (!orch) throw new Error("No voice connected. Call connectVoice() first.");
185
+ return orch.on("state", callback);
186
+ }
187
+ onLoadingProgress(callback) {
188
+ const orch = this.voiceOrchestrator;
189
+ if (!orch) throw new Error("No voice connected. Call connectVoice() first.");
190
+ return orch.on("loading:progress", callback);
191
+ }
192
+ onError(callback) {
193
+ const orch = this.voiceOrchestrator;
194
+ if (!orch) throw new Error("No voice connected. Call connectVoice() first.");
195
+ return orch.on("error", callback);
196
+ }
197
+ onAudioLevel(callback) {
198
+ const orch = this.voiceOrchestrator;
199
+ if (!orch) throw new Error("No voice connected. Call connectVoice() first.");
200
+ return orch.on("audio:level", callback);
201
+ }
202
+ // ---------------------------------------------------------------------------
203
+ // Voice (combined speaker + listener + interruption)
204
+ // ---------------------------------------------------------------------------
205
+ async connectVoice(config) {
206
+ await this.disconnectVoice();
207
+ const orchestrator = new import_core.VoiceOrchestrator();
208
+ this.voiceOrchestrator = orchestrator;
209
+ await orchestrator.connect(config);
210
+ if (orchestrator.frameSource) {
211
+ this.wireFrameSource(orchestrator.frameSource);
212
+ }
213
+ this.stateUnsub = orchestrator.on("state", (state) => {
214
+ this._state = state;
215
+ this._isSpeaking = state === "speaking";
216
+ this._onStateChange?.(state);
217
+ });
218
+ }
219
+ async disconnectVoice() {
220
+ if (this.voiceOrchestrator) {
221
+ this.frameSourceUnsub?.();
222
+ this.frameSourceUnsub = null;
223
+ this.stateUnsub?.();
224
+ this.stateUnsub = null;
225
+ await this.voiceOrchestrator.disconnect();
226
+ this.voiceOrchestrator = null;
227
+ }
228
+ }
229
+ // ---------------------------------------------------------------------------
230
+ // Frame source
231
+ // ---------------------------------------------------------------------------
232
+ connectFrameSource(source) {
233
+ this.disconnectFrameSource();
234
+ this.wireFrameSource(source);
235
+ }
236
+ disconnectFrameSource() {
237
+ this.frameSourceUnsub?.();
238
+ this.frameSourceUnsub = null;
239
+ }
240
+ // ---------------------------------------------------------------------------
241
+ // State helpers
242
+ // ---------------------------------------------------------------------------
243
+ setState(state) {
244
+ this._state = state;
245
+ this._onStateChange?.(state);
246
+ }
247
+ setSpeaking(speaking) {
248
+ this._isSpeaking = speaking;
249
+ }
250
+ reset() {
251
+ this._isSpeaking = false;
252
+ this._state = "idle";
253
+ this._onStateChange?.("idle");
254
+ }
255
+ // ---------------------------------------------------------------------------
256
+ // Cleanup
257
+ // ---------------------------------------------------------------------------
258
+ async dispose() {
259
+ await this.disconnectVoice();
260
+ await this.disconnectSpeaker();
261
+ await this.disconnectListener();
262
+ this._onFrame = null;
263
+ this._onStateChange = null;
264
+ }
265
+ // ---------------------------------------------------------------------------
266
+ // Internal
267
+ // ---------------------------------------------------------------------------
268
+ wireFrameSource(source) {
269
+ const handler = (frame) => {
270
+ this._onFrame?.(frame);
271
+ };
272
+ source.on("frame", handler);
273
+ this.frameSourceUnsub = () => {
274
+ source.off?.("frame", handler);
275
+ };
276
+ }
277
+ wireSpeakerFrameSource(speaker) {
278
+ const source = speaker.frameSource;
279
+ if (source) {
280
+ this.wireFrameSource(source);
281
+ }
282
+ }
283
+ updateState(state) {
284
+ this._state = state;
285
+ this._onStateChange?.(state);
286
+ }
287
+ };
288
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/OmoteAvatarCore.ts"],"sourcesContent":["export { OmoteAvatarCore } from './OmoteAvatarCore';\nexport type { SpeakOptions, StreamTextSink, FrameHandler, StateChangeHandler } from './types';\n","/**\n * OmoteAvatarCore — Renderer-agnostic voice composition for OmoteAvatar adapters.\n *\n * Holds all voice state (TTSSpeaker, SpeechListener, VoiceOrchestrator) and\n * the imperative voice API. Adapters instantiate this and delegate voice\n * methods, keeping only renderer-specific code (animation, blendshape writes).\n *\n * Eliminates ~150 lines of identical voice wiring duplicated across\n * Three.js, Babylon.js, and R3F adapters.\n *\n * @category Avatar\n */\n\nimport {\n TTSSpeaker,\n SpeechListener,\n VoiceOrchestrator,\n} from '@omote/core';\nimport type {\n TTSBackend,\n TTSSpeakerConfig,\n SpeechListenerConfig,\n TranscriptResult,\n LoadingProgress,\n ConversationalState,\n FrameSource,\n VoiceOrchestratorConfig,\n} from '@omote/core';\nimport type { SpeakOptions, StreamTextSink, FrameHandler, StateChangeHandler } from './types';\n\n/**\n * Renderer-agnostic voice composition class.\n *\n * Owns: TTSSpeaker, SpeechListener, VoiceOrchestrator, frame source wiring.\n * Does NOT own: CharacterController, animation, scene graph, morph targets.\n */\nexport class OmoteAvatarCore {\n // Voice primitives\n private ttsSpeaker: TTSSpeaker | null = null;\n private speechListener: SpeechListener | null = null;\n private voiceOrchestrator: VoiceOrchestrator | null = null;\n\n // Frame source wiring\n private frameSourceUnsub: (() => void) | null = null;\n private stateUnsub: (() => void) | null = null;\n\n // Callbacks set by the adapter\n private _onFrame: FrameHandler | null = null;\n private _onStateChange: StateChangeHandler | null = null;\n\n // State\n private _isSpeaking = false;\n private _state: ConversationalState = 'idle';\n\n get isSpeaking(): boolean { return this._isSpeaking; }\n get state(): ConversationalState { return this._state; }\n get speaker(): TTSSpeaker | null { return this.ttsSpeaker ?? this.voiceOrchestrator?.speaker ?? null; }\n get listener(): SpeechListener | null { return this.speechListener ?? this.voiceOrchestrator?.listener ?? null; }\n\n /**\n * Set the frame handler. Called by the adapter to receive blendshape frames.\n * The adapter writes these to its renderer (morphTargets, refs, etc.).\n */\n set onFrame(handler: FrameHandler | null) { this._onFrame = handler; }\n\n /**\n * Set the state change handler. Called by the adapter to sync conversational state.\n */\n set onStateChange(handler: StateChangeHandler | null) { this._onStateChange = handler; }\n\n // ---------------------------------------------------------------------------\n // Speaker (TTS → lip sync)\n // ---------------------------------------------------------------------------\n\n /** Warm up AudioContext for iOS/Safari autoplay policy. Call from user gesture. */\n async warmup(): Promise<void> {\n if (this.ttsSpeaker) await this.ttsSpeaker.warmup();\n }\n\n async connectSpeaker(tts: TTSBackend, config?: TTSSpeakerConfig): Promise<void> {\n await this.disconnectSpeaker();\n const speaker = new TTSSpeaker();\n await speaker.connect(tts, config);\n this.ttsSpeaker = speaker;\n this.wireSpeakerFrameSource(speaker);\n }\n\n async disconnectSpeaker(): Promise<void> {\n this.frameSourceUnsub?.();\n this.frameSourceUnsub = null;\n if (this.ttsSpeaker) {\n await this.ttsSpeaker.dispose();\n this.ttsSpeaker = null;\n }\n }\n\n async speak(text: string, options?: SpeakOptions): Promise<void> {\n if (this.voiceOrchestrator) {\n await this.voiceOrchestrator.speak(text, options);\n return;\n }\n if (!this.ttsSpeaker) throw new Error('No speaker connected. Call connectSpeaker() first.');\n this._isSpeaking = true;\n this.updateState('speaking');\n try {\n await this.ttsSpeaker.speak(text, options);\n } finally {\n this._isSpeaking = false;\n if (this._state === 'speaking') this.updateState('idle');\n }\n }\n\n async streamText(options?: SpeakOptions): Promise<StreamTextSink> {\n if (this.voiceOrchestrator) {\n return this.voiceOrchestrator.streamText(options);\n }\n if (!this.ttsSpeaker) throw new Error('No speaker connected. Call connectSpeaker() first.');\n this._isSpeaking = true;\n this.updateState('speaking');\n const stream = await this.ttsSpeaker.streamText(options ?? {});\n return {\n push: stream.push,\n end: async () => {\n try { await stream.end(); }\n finally {\n this._isSpeaking = false;\n if (this._state === 'speaking') this.updateState('idle');\n }\n },\n };\n }\n\n stopSpeaking(): void {\n if (this.voiceOrchestrator) {\n this.voiceOrchestrator.stopSpeaking();\n return;\n }\n this.ttsSpeaker?.stop();\n }\n\n // ---------------------------------------------------------------------------\n // Listener (mic → VAD → ASR → transcript)\n // ---------------------------------------------------------------------------\n\n async connectListener(config?: SpeechListenerConfig): Promise<void> {\n if (this.speechListener) {\n await this.speechListener.dispose();\n }\n const listener = new SpeechListener(config);\n this.speechListener = listener;\n await listener.loadModels();\n }\n\n async disconnectListener(): Promise<void> {\n if (this.speechListener) {\n await this.speechListener.dispose();\n this.speechListener = null;\n }\n }\n\n async startListening(): Promise<void> {\n if (this.voiceOrchestrator) {\n await this.voiceOrchestrator.startListening();\n return;\n }\n if (!this.speechListener) throw new Error('No listener connected. Call connectListener() first.');\n this.updateState('listening');\n await this.speechListener.start();\n }\n\n stopListening(): void {\n if (this.voiceOrchestrator) {\n this.voiceOrchestrator.stopListening();\n return;\n }\n this.speechListener?.stop();\n if (this._state === 'listening') this.updateState('idle');\n }\n\n // Event subscriptions (require listener or orchestrator)\n onTranscript(callback: (result: TranscriptResult) => void): () => void {\n const listener = this.speechListener ?? this.voiceOrchestrator?.listener;\n if (!listener) throw new Error('No listener connected. Call connectListener() or connectVoice() first.');\n listener.on('transcript', callback);\n return () => { listener.off?.('transcript', callback); };\n }\n\n onTranscriptEvent(callback: (result: TranscriptResult) => void): () => void {\n const orch = this.voiceOrchestrator;\n if (!orch) throw new Error('No voice connected. Call connectVoice() first.');\n return orch.on('transcript', callback);\n }\n\n onVoiceStateChange(callback: (state: ConversationalState) => void): () => void {\n const orch = this.voiceOrchestrator;\n if (!orch) throw new Error('No voice connected. Call connectVoice() first.');\n return orch.on('state', callback);\n }\n\n onLoadingProgress(callback: (progress: LoadingProgress) => void): () => void {\n const orch = this.voiceOrchestrator;\n if (!orch) throw new Error('No voice connected. Call connectVoice() first.');\n return orch.on('loading:progress', callback);\n }\n\n onError(callback: (error: Error) => void): () => void {\n const orch = this.voiceOrchestrator;\n if (!orch) throw new Error('No voice connected. Call connectVoice() first.');\n return orch.on('error', callback);\n }\n\n onAudioLevel(callback: (level: { rms: number; peak: number }) => void): () => void {\n const orch = this.voiceOrchestrator;\n if (!orch) throw new Error('No voice connected. Call connectVoice() first.');\n return orch.on('audio:level', callback);\n }\n\n // ---------------------------------------------------------------------------\n // Voice (combined speaker + listener + interruption)\n // ---------------------------------------------------------------------------\n\n async connectVoice(config: VoiceOrchestratorConfig): Promise<void> {\n await this.disconnectVoice();\n const orchestrator = new VoiceOrchestrator();\n this.voiceOrchestrator = orchestrator;\n await orchestrator.connect(config);\n\n // Wire frame source from orchestrator\n if (orchestrator.frameSource) {\n this.wireFrameSource(orchestrator.frameSource);\n }\n\n // Sync state from orchestrator\n this.stateUnsub = orchestrator.on('state', (state) => {\n this._state = state;\n this._isSpeaking = state === 'speaking';\n this._onStateChange?.(state);\n });\n }\n\n async disconnectVoice(): Promise<void> {\n if (this.voiceOrchestrator) {\n this.frameSourceUnsub?.();\n this.frameSourceUnsub = null;\n this.stateUnsub?.();\n this.stateUnsub = null;\n await this.voiceOrchestrator.disconnect();\n this.voiceOrchestrator = null;\n }\n }\n\n // ---------------------------------------------------------------------------\n // Frame source\n // ---------------------------------------------------------------------------\n\n connectFrameSource(source: FrameSource): void {\n this.disconnectFrameSource();\n this.wireFrameSource(source);\n }\n\n disconnectFrameSource(): void {\n this.frameSourceUnsub?.();\n this.frameSourceUnsub = null;\n }\n\n // ---------------------------------------------------------------------------\n // State helpers\n // ---------------------------------------------------------------------------\n\n setState(state: ConversationalState): void {\n this._state = state;\n this._onStateChange?.(state);\n }\n\n setSpeaking(speaking: boolean): void {\n this._isSpeaking = speaking;\n }\n\n reset(): void {\n this._isSpeaking = false;\n this._state = 'idle';\n this._onStateChange?.('idle');\n }\n\n // ---------------------------------------------------------------------------\n // Cleanup\n // ---------------------------------------------------------------------------\n\n async dispose(): Promise<void> {\n await this.disconnectVoice();\n await this.disconnectSpeaker();\n await this.disconnectListener();\n this._onFrame = null;\n this._onStateChange = null;\n }\n\n // ---------------------------------------------------------------------------\n // Internal\n // ---------------------------------------------------------------------------\n\n private wireFrameSource(source: FrameSource): void {\n const handler = (frame: { blendshapes: Float32Array; emotion?: string }) => {\n this._onFrame?.(frame);\n };\n source.on('frame', handler);\n this.frameSourceUnsub = () => { source.off?.('frame', handler); };\n }\n\n private wireSpeakerFrameSource(speaker: TTSSpeaker): void {\n const source = speaker.frameSource;\n if (source) {\n this.wireFrameSource(source);\n }\n }\n\n private updateState(state: ConversationalState): void {\n this._state = state;\n this._onStateChange?.(state);\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,104 @@
1
+ import { ConversationalState, TTSSpeaker, SpeechListener, TTSBackend, TTSSpeakerConfig, SpeechListenerConfig, TranscriptResult, LoadingProgress, VoiceOrchestratorConfig, FrameSource } from '@omote/core';
2
+
3
+ /**
4
+ * Types for @omote/avatar — renderer-agnostic voice composition.
5
+ *
6
+ * @category Avatar
7
+ */
8
+
9
+ /** Options passed to `speak()` and `streamText()`. */
10
+ interface SpeakOptions {
11
+ signal?: AbortSignal;
12
+ voice?: string;
13
+ speed?: number;
14
+ language?: string;
15
+ }
16
+ /** Sink returned by `streamText()` for token-by-token streaming TTS. */
17
+ interface StreamTextSink {
18
+ push: (token: string) => void;
19
+ end: () => Promise<void>;
20
+ }
21
+ /** Callback receiving blendshape frames from a FrameSource. */
22
+ type FrameHandler = (frame: {
23
+ blendshapes: Float32Array;
24
+ emotion?: string;
25
+ }) => void;
26
+ /** Callback receiving conversational state changes. */
27
+ type StateChangeHandler = (state: ConversationalState) => void;
28
+
29
+ /**
30
+ * OmoteAvatarCore — Renderer-agnostic voice composition for OmoteAvatar adapters.
31
+ *
32
+ * Holds all voice state (TTSSpeaker, SpeechListener, VoiceOrchestrator) and
33
+ * the imperative voice API. Adapters instantiate this and delegate voice
34
+ * methods, keeping only renderer-specific code (animation, blendshape writes).
35
+ *
36
+ * Eliminates ~150 lines of identical voice wiring duplicated across
37
+ * Three.js, Babylon.js, and R3F adapters.
38
+ *
39
+ * @category Avatar
40
+ */
41
+
42
+ /**
43
+ * Renderer-agnostic voice composition class.
44
+ *
45
+ * Owns: TTSSpeaker, SpeechListener, VoiceOrchestrator, frame source wiring.
46
+ * Does NOT own: CharacterController, animation, scene graph, morph targets.
47
+ */
48
+ declare class OmoteAvatarCore {
49
+ private ttsSpeaker;
50
+ private speechListener;
51
+ private voiceOrchestrator;
52
+ private frameSourceUnsub;
53
+ private stateUnsub;
54
+ private _onFrame;
55
+ private _onStateChange;
56
+ private _isSpeaking;
57
+ private _state;
58
+ get isSpeaking(): boolean;
59
+ get state(): ConversationalState;
60
+ get speaker(): TTSSpeaker | null;
61
+ get listener(): SpeechListener | null;
62
+ /**
63
+ * Set the frame handler. Called by the adapter to receive blendshape frames.
64
+ * The adapter writes these to its renderer (morphTargets, refs, etc.).
65
+ */
66
+ set onFrame(handler: FrameHandler | null);
67
+ /**
68
+ * Set the state change handler. Called by the adapter to sync conversational state.
69
+ */
70
+ set onStateChange(handler: StateChangeHandler | null);
71
+ /** Warm up AudioContext for iOS/Safari autoplay policy. Call from user gesture. */
72
+ warmup(): Promise<void>;
73
+ connectSpeaker(tts: TTSBackend, config?: TTSSpeakerConfig): Promise<void>;
74
+ disconnectSpeaker(): Promise<void>;
75
+ speak(text: string, options?: SpeakOptions): Promise<void>;
76
+ streamText(options?: SpeakOptions): Promise<StreamTextSink>;
77
+ stopSpeaking(): void;
78
+ connectListener(config?: SpeechListenerConfig): Promise<void>;
79
+ disconnectListener(): Promise<void>;
80
+ startListening(): Promise<void>;
81
+ stopListening(): void;
82
+ onTranscript(callback: (result: TranscriptResult) => void): () => void;
83
+ onTranscriptEvent(callback: (result: TranscriptResult) => void): () => void;
84
+ onVoiceStateChange(callback: (state: ConversationalState) => void): () => void;
85
+ onLoadingProgress(callback: (progress: LoadingProgress) => void): () => void;
86
+ onError(callback: (error: Error) => void): () => void;
87
+ onAudioLevel(callback: (level: {
88
+ rms: number;
89
+ peak: number;
90
+ }) => void): () => void;
91
+ connectVoice(config: VoiceOrchestratorConfig): Promise<void>;
92
+ disconnectVoice(): Promise<void>;
93
+ connectFrameSource(source: FrameSource): void;
94
+ disconnectFrameSource(): void;
95
+ setState(state: ConversationalState): void;
96
+ setSpeaking(speaking: boolean): void;
97
+ reset(): void;
98
+ dispose(): Promise<void>;
99
+ private wireFrameSource;
100
+ private wireSpeakerFrameSource;
101
+ private updateState;
102
+ }
103
+
104
+ export { type FrameHandler, OmoteAvatarCore, type SpeakOptions, type StateChangeHandler, type StreamTextSink };
@@ -0,0 +1,104 @@
1
+ import { ConversationalState, TTSSpeaker, SpeechListener, TTSBackend, TTSSpeakerConfig, SpeechListenerConfig, TranscriptResult, LoadingProgress, VoiceOrchestratorConfig, FrameSource } from '@omote/core';
2
+
3
+ /**
4
+ * Types for @omote/avatar — renderer-agnostic voice composition.
5
+ *
6
+ * @category Avatar
7
+ */
8
+
9
+ /** Options passed to `speak()` and `streamText()`. */
10
+ interface SpeakOptions {
11
+ signal?: AbortSignal;
12
+ voice?: string;
13
+ speed?: number;
14
+ language?: string;
15
+ }
16
+ /** Sink returned by `streamText()` for token-by-token streaming TTS. */
17
+ interface StreamTextSink {
18
+ push: (token: string) => void;
19
+ end: () => Promise<void>;
20
+ }
21
+ /** Callback receiving blendshape frames from a FrameSource. */
22
+ type FrameHandler = (frame: {
23
+ blendshapes: Float32Array;
24
+ emotion?: string;
25
+ }) => void;
26
+ /** Callback receiving conversational state changes. */
27
+ type StateChangeHandler = (state: ConversationalState) => void;
28
+
29
+ /**
30
+ * OmoteAvatarCore — Renderer-agnostic voice composition for OmoteAvatar adapters.
31
+ *
32
+ * Holds all voice state (TTSSpeaker, SpeechListener, VoiceOrchestrator) and
33
+ * the imperative voice API. Adapters instantiate this and delegate voice
34
+ * methods, keeping only renderer-specific code (animation, blendshape writes).
35
+ *
36
+ * Eliminates ~150 lines of identical voice wiring duplicated across
37
+ * Three.js, Babylon.js, and R3F adapters.
38
+ *
39
+ * @category Avatar
40
+ */
41
+
42
+ /**
43
+ * Renderer-agnostic voice composition class.
44
+ *
45
+ * Owns: TTSSpeaker, SpeechListener, VoiceOrchestrator, frame source wiring.
46
+ * Does NOT own: CharacterController, animation, scene graph, morph targets.
47
+ */
48
+ declare class OmoteAvatarCore {
49
+ private ttsSpeaker;
50
+ private speechListener;
51
+ private voiceOrchestrator;
52
+ private frameSourceUnsub;
53
+ private stateUnsub;
54
+ private _onFrame;
55
+ private _onStateChange;
56
+ private _isSpeaking;
57
+ private _state;
58
+ get isSpeaking(): boolean;
59
+ get state(): ConversationalState;
60
+ get speaker(): TTSSpeaker | null;
61
+ get listener(): SpeechListener | null;
62
+ /**
63
+ * Set the frame handler. Called by the adapter to receive blendshape frames.
64
+ * The adapter writes these to its renderer (morphTargets, refs, etc.).
65
+ */
66
+ set onFrame(handler: FrameHandler | null);
67
+ /**
68
+ * Set the state change handler. Called by the adapter to sync conversational state.
69
+ */
70
+ set onStateChange(handler: StateChangeHandler | null);
71
+ /** Warm up AudioContext for iOS/Safari autoplay policy. Call from user gesture. */
72
+ warmup(): Promise<void>;
73
+ connectSpeaker(tts: TTSBackend, config?: TTSSpeakerConfig): Promise<void>;
74
+ disconnectSpeaker(): Promise<void>;
75
+ speak(text: string, options?: SpeakOptions): Promise<void>;
76
+ streamText(options?: SpeakOptions): Promise<StreamTextSink>;
77
+ stopSpeaking(): void;
78
+ connectListener(config?: SpeechListenerConfig): Promise<void>;
79
+ disconnectListener(): Promise<void>;
80
+ startListening(): Promise<void>;
81
+ stopListening(): void;
82
+ onTranscript(callback: (result: TranscriptResult) => void): () => void;
83
+ onTranscriptEvent(callback: (result: TranscriptResult) => void): () => void;
84
+ onVoiceStateChange(callback: (state: ConversationalState) => void): () => void;
85
+ onLoadingProgress(callback: (progress: LoadingProgress) => void): () => void;
86
+ onError(callback: (error: Error) => void): () => void;
87
+ onAudioLevel(callback: (level: {
88
+ rms: number;
89
+ peak: number;
90
+ }) => void): () => void;
91
+ connectVoice(config: VoiceOrchestratorConfig): Promise<void>;
92
+ disconnectVoice(): Promise<void>;
93
+ connectFrameSource(source: FrameSource): void;
94
+ disconnectFrameSource(): void;
95
+ setState(state: ConversationalState): void;
96
+ setSpeaking(speaking: boolean): void;
97
+ reset(): void;
98
+ dispose(): Promise<void>;
99
+ private wireFrameSource;
100
+ private wireSpeakerFrameSource;
101
+ private updateState;
102
+ }
103
+
104
+ export { type FrameHandler, OmoteAvatarCore, type SpeakOptions, type StateChangeHandler, type StreamTextSink };
package/dist/index.js ADDED
@@ -0,0 +1,269 @@
1
+ // src/OmoteAvatarCore.ts
2
+ import {
3
+ TTSSpeaker,
4
+ SpeechListener,
5
+ VoiceOrchestrator
6
+ } from "@omote/core";
7
+ var OmoteAvatarCore = class {
8
+ constructor() {
9
+ // Voice primitives
10
+ this.ttsSpeaker = null;
11
+ this.speechListener = null;
12
+ this.voiceOrchestrator = null;
13
+ // Frame source wiring
14
+ this.frameSourceUnsub = null;
15
+ this.stateUnsub = null;
16
+ // Callbacks set by the adapter
17
+ this._onFrame = null;
18
+ this._onStateChange = null;
19
+ // State
20
+ this._isSpeaking = false;
21
+ this._state = "idle";
22
+ }
23
+ get isSpeaking() {
24
+ return this._isSpeaking;
25
+ }
26
+ get state() {
27
+ return this._state;
28
+ }
29
+ get speaker() {
30
+ return this.ttsSpeaker ?? this.voiceOrchestrator?.speaker ?? null;
31
+ }
32
+ get listener() {
33
+ return this.speechListener ?? this.voiceOrchestrator?.listener ?? null;
34
+ }
35
+ /**
36
+ * Set the frame handler. Called by the adapter to receive blendshape frames.
37
+ * The adapter writes these to its renderer (morphTargets, refs, etc.).
38
+ */
39
+ set onFrame(handler) {
40
+ this._onFrame = handler;
41
+ }
42
+ /**
43
+ * Set the state change handler. Called by the adapter to sync conversational state.
44
+ */
45
+ set onStateChange(handler) {
46
+ this._onStateChange = handler;
47
+ }
48
+ // ---------------------------------------------------------------------------
49
+ // Speaker (TTS → lip sync)
50
+ // ---------------------------------------------------------------------------
51
+ /** Warm up AudioContext for iOS/Safari autoplay policy. Call from user gesture. */
52
+ async warmup() {
53
+ if (this.ttsSpeaker) await this.ttsSpeaker.warmup();
54
+ }
55
+ async connectSpeaker(tts, config) {
56
+ await this.disconnectSpeaker();
57
+ const speaker = new TTSSpeaker();
58
+ await speaker.connect(tts, config);
59
+ this.ttsSpeaker = speaker;
60
+ this.wireSpeakerFrameSource(speaker);
61
+ }
62
+ async disconnectSpeaker() {
63
+ this.frameSourceUnsub?.();
64
+ this.frameSourceUnsub = null;
65
+ if (this.ttsSpeaker) {
66
+ await this.ttsSpeaker.dispose();
67
+ this.ttsSpeaker = null;
68
+ }
69
+ }
70
+ async speak(text, options) {
71
+ if (this.voiceOrchestrator) {
72
+ await this.voiceOrchestrator.speak(text, options);
73
+ return;
74
+ }
75
+ if (!this.ttsSpeaker) throw new Error("No speaker connected. Call connectSpeaker() first.");
76
+ this._isSpeaking = true;
77
+ this.updateState("speaking");
78
+ try {
79
+ await this.ttsSpeaker.speak(text, options);
80
+ } finally {
81
+ this._isSpeaking = false;
82
+ if (this._state === "speaking") this.updateState("idle");
83
+ }
84
+ }
85
+ async streamText(options) {
86
+ if (this.voiceOrchestrator) {
87
+ return this.voiceOrchestrator.streamText(options);
88
+ }
89
+ if (!this.ttsSpeaker) throw new Error("No speaker connected. Call connectSpeaker() first.");
90
+ this._isSpeaking = true;
91
+ this.updateState("speaking");
92
+ const stream = await this.ttsSpeaker.streamText(options ?? {});
93
+ return {
94
+ push: stream.push,
95
+ end: async () => {
96
+ try {
97
+ await stream.end();
98
+ } finally {
99
+ this._isSpeaking = false;
100
+ if (this._state === "speaking") this.updateState("idle");
101
+ }
102
+ }
103
+ };
104
+ }
105
+ stopSpeaking() {
106
+ if (this.voiceOrchestrator) {
107
+ this.voiceOrchestrator.stopSpeaking();
108
+ return;
109
+ }
110
+ this.ttsSpeaker?.stop();
111
+ }
112
+ // ---------------------------------------------------------------------------
113
+ // Listener (mic → VAD → ASR → transcript)
114
+ // ---------------------------------------------------------------------------
115
+ async connectListener(config) {
116
+ if (this.speechListener) {
117
+ await this.speechListener.dispose();
118
+ }
119
+ const listener = new SpeechListener(config);
120
+ this.speechListener = listener;
121
+ await listener.loadModels();
122
+ }
123
+ async disconnectListener() {
124
+ if (this.speechListener) {
125
+ await this.speechListener.dispose();
126
+ this.speechListener = null;
127
+ }
128
+ }
129
+ async startListening() {
130
+ if (this.voiceOrchestrator) {
131
+ await this.voiceOrchestrator.startListening();
132
+ return;
133
+ }
134
+ if (!this.speechListener) throw new Error("No listener connected. Call connectListener() first.");
135
+ this.updateState("listening");
136
+ await this.speechListener.start();
137
+ }
138
+ stopListening() {
139
+ if (this.voiceOrchestrator) {
140
+ this.voiceOrchestrator.stopListening();
141
+ return;
142
+ }
143
+ this.speechListener?.stop();
144
+ if (this._state === "listening") this.updateState("idle");
145
+ }
146
+ // Event subscriptions (require listener or orchestrator)
147
+ onTranscript(callback) {
148
+ const listener = this.speechListener ?? this.voiceOrchestrator?.listener;
149
+ if (!listener) throw new Error("No listener connected. Call connectListener() or connectVoice() first.");
150
+ listener.on("transcript", callback);
151
+ return () => {
152
+ listener.off?.("transcript", callback);
153
+ };
154
+ }
155
+ onTranscriptEvent(callback) {
156
+ const orch = this.voiceOrchestrator;
157
+ if (!orch) throw new Error("No voice connected. Call connectVoice() first.");
158
+ return orch.on("transcript", callback);
159
+ }
160
+ onVoiceStateChange(callback) {
161
+ const orch = this.voiceOrchestrator;
162
+ if (!orch) throw new Error("No voice connected. Call connectVoice() first.");
163
+ return orch.on("state", callback);
164
+ }
165
+ onLoadingProgress(callback) {
166
+ const orch = this.voiceOrchestrator;
167
+ if (!orch) throw new Error("No voice connected. Call connectVoice() first.");
168
+ return orch.on("loading:progress", callback);
169
+ }
170
+ onError(callback) {
171
+ const orch = this.voiceOrchestrator;
172
+ if (!orch) throw new Error("No voice connected. Call connectVoice() first.");
173
+ return orch.on("error", callback);
174
+ }
175
+ onAudioLevel(callback) {
176
+ const orch = this.voiceOrchestrator;
177
+ if (!orch) throw new Error("No voice connected. Call connectVoice() first.");
178
+ return orch.on("audio:level", callback);
179
+ }
180
+ // ---------------------------------------------------------------------------
181
+ // Voice (combined speaker + listener + interruption)
182
+ // ---------------------------------------------------------------------------
183
+ async connectVoice(config) {
184
+ await this.disconnectVoice();
185
+ const orchestrator = new VoiceOrchestrator();
186
+ this.voiceOrchestrator = orchestrator;
187
+ await orchestrator.connect(config);
188
+ if (orchestrator.frameSource) {
189
+ this.wireFrameSource(orchestrator.frameSource);
190
+ }
191
+ this.stateUnsub = orchestrator.on("state", (state) => {
192
+ this._state = state;
193
+ this._isSpeaking = state === "speaking";
194
+ this._onStateChange?.(state);
195
+ });
196
+ }
197
+ async disconnectVoice() {
198
+ if (this.voiceOrchestrator) {
199
+ this.frameSourceUnsub?.();
200
+ this.frameSourceUnsub = null;
201
+ this.stateUnsub?.();
202
+ this.stateUnsub = null;
203
+ await this.voiceOrchestrator.disconnect();
204
+ this.voiceOrchestrator = null;
205
+ }
206
+ }
207
+ // ---------------------------------------------------------------------------
208
+ // Frame source
209
+ // ---------------------------------------------------------------------------
210
+ connectFrameSource(source) {
211
+ this.disconnectFrameSource();
212
+ this.wireFrameSource(source);
213
+ }
214
+ disconnectFrameSource() {
215
+ this.frameSourceUnsub?.();
216
+ this.frameSourceUnsub = null;
217
+ }
218
+ // ---------------------------------------------------------------------------
219
+ // State helpers
220
+ // ---------------------------------------------------------------------------
221
+ setState(state) {
222
+ this._state = state;
223
+ this._onStateChange?.(state);
224
+ }
225
+ setSpeaking(speaking) {
226
+ this._isSpeaking = speaking;
227
+ }
228
+ reset() {
229
+ this._isSpeaking = false;
230
+ this._state = "idle";
231
+ this._onStateChange?.("idle");
232
+ }
233
+ // ---------------------------------------------------------------------------
234
+ // Cleanup
235
+ // ---------------------------------------------------------------------------
236
+ async dispose() {
237
+ await this.disconnectVoice();
238
+ await this.disconnectSpeaker();
239
+ await this.disconnectListener();
240
+ this._onFrame = null;
241
+ this._onStateChange = null;
242
+ }
243
+ // ---------------------------------------------------------------------------
244
+ // Internal
245
+ // ---------------------------------------------------------------------------
246
+ wireFrameSource(source) {
247
+ const handler = (frame) => {
248
+ this._onFrame?.(frame);
249
+ };
250
+ source.on("frame", handler);
251
+ this.frameSourceUnsub = () => {
252
+ source.off?.("frame", handler);
253
+ };
254
+ }
255
+ wireSpeakerFrameSource(speaker) {
256
+ const source = speaker.frameSource;
257
+ if (source) {
258
+ this.wireFrameSource(source);
259
+ }
260
+ }
261
+ updateState(state) {
262
+ this._state = state;
263
+ this._onStateChange?.(state);
264
+ }
265
+ };
266
+ export {
267
+ OmoteAvatarCore
268
+ };
269
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/OmoteAvatarCore.ts"],"sourcesContent":["/**\n * OmoteAvatarCore — Renderer-agnostic voice composition for OmoteAvatar adapters.\n *\n * Holds all voice state (TTSSpeaker, SpeechListener, VoiceOrchestrator) and\n * the imperative voice API. Adapters instantiate this and delegate voice\n * methods, keeping only renderer-specific code (animation, blendshape writes).\n *\n * Eliminates ~150 lines of identical voice wiring duplicated across\n * Three.js, Babylon.js, and R3F adapters.\n *\n * @category Avatar\n */\n\nimport {\n TTSSpeaker,\n SpeechListener,\n VoiceOrchestrator,\n} from '@omote/core';\nimport type {\n TTSBackend,\n TTSSpeakerConfig,\n SpeechListenerConfig,\n TranscriptResult,\n LoadingProgress,\n ConversationalState,\n FrameSource,\n VoiceOrchestratorConfig,\n} from '@omote/core';\nimport type { SpeakOptions, StreamTextSink, FrameHandler, StateChangeHandler } from './types';\n\n/**\n * Renderer-agnostic voice composition class.\n *\n * Owns: TTSSpeaker, SpeechListener, VoiceOrchestrator, frame source wiring.\n * Does NOT own: CharacterController, animation, scene graph, morph targets.\n */\nexport class OmoteAvatarCore {\n // Voice primitives\n private ttsSpeaker: TTSSpeaker | null = null;\n private speechListener: SpeechListener | null = null;\n private voiceOrchestrator: VoiceOrchestrator | null = null;\n\n // Frame source wiring\n private frameSourceUnsub: (() => void) | null = null;\n private stateUnsub: (() => void) | null = null;\n\n // Callbacks set by the adapter\n private _onFrame: FrameHandler | null = null;\n private _onStateChange: StateChangeHandler | null = null;\n\n // State\n private _isSpeaking = false;\n private _state: ConversationalState = 'idle';\n\n get isSpeaking(): boolean { return this._isSpeaking; }\n get state(): ConversationalState { return this._state; }\n get speaker(): TTSSpeaker | null { return this.ttsSpeaker ?? this.voiceOrchestrator?.speaker ?? null; }\n get listener(): SpeechListener | null { return this.speechListener ?? this.voiceOrchestrator?.listener ?? null; }\n\n /**\n * Set the frame handler. Called by the adapter to receive blendshape frames.\n * The adapter writes these to its renderer (morphTargets, refs, etc.).\n */\n set onFrame(handler: FrameHandler | null) { this._onFrame = handler; }\n\n /**\n * Set the state change handler. Called by the adapter to sync conversational state.\n */\n set onStateChange(handler: StateChangeHandler | null) { this._onStateChange = handler; }\n\n // ---------------------------------------------------------------------------\n // Speaker (TTS → lip sync)\n // ---------------------------------------------------------------------------\n\n /** Warm up AudioContext for iOS/Safari autoplay policy. Call from user gesture. */\n async warmup(): Promise<void> {\n if (this.ttsSpeaker) await this.ttsSpeaker.warmup();\n }\n\n async connectSpeaker(tts: TTSBackend, config?: TTSSpeakerConfig): Promise<void> {\n await this.disconnectSpeaker();\n const speaker = new TTSSpeaker();\n await speaker.connect(tts, config);\n this.ttsSpeaker = speaker;\n this.wireSpeakerFrameSource(speaker);\n }\n\n async disconnectSpeaker(): Promise<void> {\n this.frameSourceUnsub?.();\n this.frameSourceUnsub = null;\n if (this.ttsSpeaker) {\n await this.ttsSpeaker.dispose();\n this.ttsSpeaker = null;\n }\n }\n\n async speak(text: string, options?: SpeakOptions): Promise<void> {\n if (this.voiceOrchestrator) {\n await this.voiceOrchestrator.speak(text, options);\n return;\n }\n if (!this.ttsSpeaker) throw new Error('No speaker connected. Call connectSpeaker() first.');\n this._isSpeaking = true;\n this.updateState('speaking');\n try {\n await this.ttsSpeaker.speak(text, options);\n } finally {\n this._isSpeaking = false;\n if (this._state === 'speaking') this.updateState('idle');\n }\n }\n\n async streamText(options?: SpeakOptions): Promise<StreamTextSink> {\n if (this.voiceOrchestrator) {\n return this.voiceOrchestrator.streamText(options);\n }\n if (!this.ttsSpeaker) throw new Error('No speaker connected. Call connectSpeaker() first.');\n this._isSpeaking = true;\n this.updateState('speaking');\n const stream = await this.ttsSpeaker.streamText(options ?? {});\n return {\n push: stream.push,\n end: async () => {\n try { await stream.end(); }\n finally {\n this._isSpeaking = false;\n if (this._state === 'speaking') this.updateState('idle');\n }\n },\n };\n }\n\n stopSpeaking(): void {\n if (this.voiceOrchestrator) {\n this.voiceOrchestrator.stopSpeaking();\n return;\n }\n this.ttsSpeaker?.stop();\n }\n\n // ---------------------------------------------------------------------------\n // Listener (mic → VAD → ASR → transcript)\n // ---------------------------------------------------------------------------\n\n async connectListener(config?: SpeechListenerConfig): Promise<void> {\n if (this.speechListener) {\n await this.speechListener.dispose();\n }\n const listener = new SpeechListener(config);\n this.speechListener = listener;\n await listener.loadModels();\n }\n\n async disconnectListener(): Promise<void> {\n if (this.speechListener) {\n await this.speechListener.dispose();\n this.speechListener = null;\n }\n }\n\n async startListening(): Promise<void> {\n if (this.voiceOrchestrator) {\n await this.voiceOrchestrator.startListening();\n return;\n }\n if (!this.speechListener) throw new Error('No listener connected. Call connectListener() first.');\n this.updateState('listening');\n await this.speechListener.start();\n }\n\n stopListening(): void {\n if (this.voiceOrchestrator) {\n this.voiceOrchestrator.stopListening();\n return;\n }\n this.speechListener?.stop();\n if (this._state === 'listening') this.updateState('idle');\n }\n\n // Event subscriptions (require listener or orchestrator)\n onTranscript(callback: (result: TranscriptResult) => void): () => void {\n const listener = this.speechListener ?? this.voiceOrchestrator?.listener;\n if (!listener) throw new Error('No listener connected. Call connectListener() or connectVoice() first.');\n listener.on('transcript', callback);\n return () => { listener.off?.('transcript', callback); };\n }\n\n onTranscriptEvent(callback: (result: TranscriptResult) => void): () => void {\n const orch = this.voiceOrchestrator;\n if (!orch) throw new Error('No voice connected. Call connectVoice() first.');\n return orch.on('transcript', callback);\n }\n\n onVoiceStateChange(callback: (state: ConversationalState) => void): () => void {\n const orch = this.voiceOrchestrator;\n if (!orch) throw new Error('No voice connected. Call connectVoice() first.');\n return orch.on('state', callback);\n }\n\n onLoadingProgress(callback: (progress: LoadingProgress) => void): () => void {\n const orch = this.voiceOrchestrator;\n if (!orch) throw new Error('No voice connected. Call connectVoice() first.');\n return orch.on('loading:progress', callback);\n }\n\n onError(callback: (error: Error) => void): () => void {\n const orch = this.voiceOrchestrator;\n if (!orch) throw new Error('No voice connected. Call connectVoice() first.');\n return orch.on('error', callback);\n }\n\n onAudioLevel(callback: (level: { rms: number; peak: number }) => void): () => void {\n const orch = this.voiceOrchestrator;\n if (!orch) throw new Error('No voice connected. Call connectVoice() first.');\n return orch.on('audio:level', callback);\n }\n\n // ---------------------------------------------------------------------------\n // Voice (combined speaker + listener + interruption)\n // ---------------------------------------------------------------------------\n\n async connectVoice(config: VoiceOrchestratorConfig): Promise<void> {\n await this.disconnectVoice();\n const orchestrator = new VoiceOrchestrator();\n this.voiceOrchestrator = orchestrator;\n await orchestrator.connect(config);\n\n // Wire frame source from orchestrator\n if (orchestrator.frameSource) {\n this.wireFrameSource(orchestrator.frameSource);\n }\n\n // Sync state from orchestrator\n this.stateUnsub = orchestrator.on('state', (state) => {\n this._state = state;\n this._isSpeaking = state === 'speaking';\n this._onStateChange?.(state);\n });\n }\n\n async disconnectVoice(): Promise<void> {\n if (this.voiceOrchestrator) {\n this.frameSourceUnsub?.();\n this.frameSourceUnsub = null;\n this.stateUnsub?.();\n this.stateUnsub = null;\n await this.voiceOrchestrator.disconnect();\n this.voiceOrchestrator = null;\n }\n }\n\n // ---------------------------------------------------------------------------\n // Frame source\n // ---------------------------------------------------------------------------\n\n connectFrameSource(source: FrameSource): void {\n this.disconnectFrameSource();\n this.wireFrameSource(source);\n }\n\n disconnectFrameSource(): void {\n this.frameSourceUnsub?.();\n this.frameSourceUnsub = null;\n }\n\n // ---------------------------------------------------------------------------\n // State helpers\n // ---------------------------------------------------------------------------\n\n setState(state: ConversationalState): void {\n this._state = state;\n this._onStateChange?.(state);\n }\n\n setSpeaking(speaking: boolean): void {\n this._isSpeaking = speaking;\n }\n\n reset(): void {\n this._isSpeaking = false;\n this._state = 'idle';\n this._onStateChange?.('idle');\n }\n\n // ---------------------------------------------------------------------------\n // Cleanup\n // ---------------------------------------------------------------------------\n\n async dispose(): Promise<void> {\n await this.disconnectVoice();\n await this.disconnectSpeaker();\n await this.disconnectListener();\n this._onFrame = null;\n this._onStateChange = null;\n }\n\n // ---------------------------------------------------------------------------\n // Internal\n // ---------------------------------------------------------------------------\n\n private wireFrameSource(source: FrameSource): void {\n const handler = (frame: { blendshapes: Float32Array; emotion?: string }) => {\n this._onFrame?.(frame);\n };\n source.on('frame', handler);\n this.frameSourceUnsub = () => { source.off?.('frame', handler); };\n }\n\n private wireSpeakerFrameSource(speaker: TTSSpeaker): void {\n const source = speaker.frameSource;\n if (source) {\n this.wireFrameSource(source);\n }\n }\n\n private updateState(state: ConversationalState): void {\n this._state = state;\n this._onStateChange?.(state);\n }\n}\n"],"mappings":";AAaA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAmBA,IAAM,kBAAN,MAAsB;AAAA,EAAtB;AAEL;AAAA,SAAQ,aAAgC;AACxC,SAAQ,iBAAwC;AAChD,SAAQ,oBAA8C;AAGtD;AAAA,SAAQ,mBAAwC;AAChD,SAAQ,aAAkC;AAG1C;AAAA,SAAQ,WAAgC;AACxC,SAAQ,iBAA4C;AAGpD;AAAA,SAAQ,cAAc;AACtB,SAAQ,SAA8B;AAAA;AAAA,EAEtC,IAAI,aAAsB;AAAE,WAAO,KAAK;AAAA,EAAa;AAAA,EACrD,IAAI,QAA6B;AAAE,WAAO,KAAK;AAAA,EAAQ;AAAA,EACvD,IAAI,UAA6B;AAAE,WAAO,KAAK,cAAc,KAAK,mBAAmB,WAAW;AAAA,EAAM;AAAA,EACtG,IAAI,WAAkC;AAAE,WAAO,KAAK,kBAAkB,KAAK,mBAAmB,YAAY;AAAA,EAAM;AAAA;AAAA;AAAA;AAAA;AAAA,EAMhH,IAAI,QAAQ,SAA8B;AAAE,SAAK,WAAW;AAAA,EAAS;AAAA;AAAA;AAAA;AAAA,EAKrE,IAAI,cAAc,SAAoC;AAAE,SAAK,iBAAiB;AAAA,EAAS;AAAA;AAAA;AAAA;AAAA;AAAA,EAOvF,MAAM,SAAwB;AAC5B,QAAI,KAAK,WAAY,OAAM,KAAK,WAAW,OAAO;AAAA,EACpD;AAAA,EAEA,MAAM,eAAe,KAAiB,QAA0C;AAC9E,UAAM,KAAK,kBAAkB;AAC7B,UAAM,UAAU,IAAI,WAAW;AAC/B,UAAM,QAAQ,QAAQ,KAAK,MAAM;AACjC,SAAK,aAAa;AAClB,SAAK,uBAAuB,OAAO;AAAA,EACrC;AAAA,EAEA,MAAM,oBAAmC;AACvC,SAAK,mBAAmB;AACxB,SAAK,mBAAmB;AACxB,QAAI,KAAK,YAAY;AACnB,YAAM,KAAK,WAAW,QAAQ;AAC9B,WAAK,aAAa;AAAA,IACpB;AAAA,EACF;AAAA,EAEA,MAAM,MAAM,MAAc,SAAuC;AAC/D,QAAI,KAAK,mBAAmB;AAC1B,YAAM,KAAK,kBAAkB,MAAM,MAAM,OAAO;AAChD;AAAA,IACF;AACA,QAAI,CAAC,KAAK,WAAY,OAAM,IAAI,MAAM,oDAAoD;AAC1F,SAAK,cAAc;AACnB,SAAK,YAAY,UAAU;AAC3B,QAAI;AACF,YAAM,KAAK,WAAW,MAAM,MAAM,OAAO;AAAA,IAC3C,UAAE;AACA,WAAK,cAAc;AACnB,UAAI,KAAK,WAAW,WAAY,MAAK,YAAY,MAAM;AAAA,IACzD;AAAA,EACF;AAAA,EAEA,MAAM,WAAW,SAAiD;AAChE,QAAI,KAAK,mBAAmB;AAC1B,aAAO,KAAK,kBAAkB,WAAW,OAAO;AAAA,IAClD;AACA,QAAI,CAAC,KAAK,WAAY,OAAM,IAAI,MAAM,oDAAoD;AAC1F,SAAK,cAAc;AACnB,SAAK,YAAY,UAAU;AAC3B,UAAM,SAAS,MAAM,KAAK,WAAW,WAAW,WAAW,CAAC,CAAC;AAC7D,WAAO;AAAA,MACL,MAAM,OAAO;AAAA,MACb,KAAK,YAAY;AACf,YAAI;AAAE,gBAAM,OAAO,IAAI;AAAA,QAAG,UAC1B;AACE,eAAK,cAAc;AACnB,cAAI,KAAK,WAAW,WAAY,MAAK,YAAY,MAAM;AAAA,QACzD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,eAAqB;AACnB,QAAI,KAAK,mBAAmB;AAC1B,WAAK,kBAAkB,aAAa;AACpC;AAAA,IACF;AACA,SAAK,YAAY,KAAK;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,gBAAgB,QAA8C;AAClE,QAAI,KAAK,gBAAgB;AACvB,YAAM,KAAK,eAAe,QAAQ;AAAA,IACpC;AACA,UAAM,WAAW,IAAI,eAAe,MAAM;AAC1C,SAAK,iBAAiB;AACtB,UAAM,SAAS,WAAW;AAAA,EAC5B;AAAA,EAEA,MAAM,qBAAoC;AACxC,QAAI,KAAK,gBAAgB;AACvB,YAAM,KAAK,eAAe,QAAQ;AAClC,WAAK,iBAAiB;AAAA,IACxB;AAAA,EACF;AAAA,EAEA,MAAM,iBAAgC;AACpC,QAAI,KAAK,mBAAmB;AAC1B,YAAM,KAAK,kBAAkB,eAAe;AAC5C;AAAA,IACF;AACA,QAAI,CAAC,KAAK,eAAgB,OAAM,IAAI,MAAM,sDAAsD;AAChG,SAAK,YAAY,WAAW;AAC5B,UAAM,KAAK,eAAe,MAAM;AAAA,EAClC;AAAA,EAEA,gBAAsB;AACpB,QAAI,KAAK,mBAAmB;AAC1B,WAAK,kBAAkB,cAAc;AACrC;AAAA,IACF;AACA,SAAK,gBAAgB,KAAK;AAC1B,QAAI,KAAK,WAAW,YAAa,MAAK,YAAY,MAAM;AAAA,EAC1D;AAAA;AAAA,EAGA,aAAa,UAA0D;AACrE,UAAM,WAAW,KAAK,kBAAkB,KAAK,mBAAmB;AAChE,QAAI,CAAC,SAAU,OAAM,IAAI,MAAM,wEAAwE;AACvG,aAAS,GAAG,cAAc,QAAQ;AAClC,WAAO,MAAM;AAAE,eAAS,MAAM,cAAc,QAAQ;AAAA,IAAG;AAAA,EACzD;AAAA,EAEA,kBAAkB,UAA0D;AAC1E,UAAM,OAAO,KAAK;AAClB,QAAI,CAAC,KAAM,OAAM,IAAI,MAAM,gDAAgD;AAC3E,WAAO,KAAK,GAAG,cAAc,QAAQ;AAAA,EACvC;AAAA,EAEA,mBAAmB,UAA4D;AAC7E,UAAM,OAAO,KAAK;AAClB,QAAI,CAAC,KAAM,OAAM,IAAI,MAAM,gDAAgD;AAC3E,WAAO,KAAK,GAAG,SAAS,QAAQ;AAAA,EAClC;AAAA,EAEA,kBAAkB,UAA2D;AAC3E,UAAM,OAAO,KAAK;AAClB,QAAI,CAAC,KAAM,OAAM,IAAI,MAAM,gDAAgD;AAC3E,WAAO,KAAK,GAAG,oBAAoB,QAAQ;AAAA,EAC7C;AAAA,EAEA,QAAQ,UAA8C;AACpD,UAAM,OAAO,KAAK;AAClB,QAAI,CAAC,KAAM,OAAM,IAAI,MAAM,gDAAgD;AAC3E,WAAO,KAAK,GAAG,SAAS,QAAQ;AAAA,EAClC;AAAA,EAEA,aAAa,UAAsE;AACjF,UAAM,OAAO,KAAK;AAClB,QAAI,CAAC,KAAM,OAAM,IAAI,MAAM,gDAAgD;AAC3E,WAAO,KAAK,GAAG,eAAe,QAAQ;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,aAAa,QAAgD;AACjE,UAAM,KAAK,gBAAgB;AAC3B,UAAM,eAAe,IAAI,kBAAkB;AAC3C,SAAK,oBAAoB;AACzB,UAAM,aAAa,QAAQ,MAAM;AAGjC,QAAI,aAAa,aAAa;AAC5B,WAAK,gBAAgB,aAAa,WAAW;AAAA,IAC/C;AAGA,SAAK,aAAa,aAAa,GAAG,SAAS,CAAC,UAAU;AACpD,WAAK,SAAS;AACd,WAAK,cAAc,UAAU;AAC7B,WAAK,iBAAiB,KAAK;AAAA,IAC7B,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,kBAAiC;AACrC,QAAI,KAAK,mBAAmB;AAC1B,WAAK,mBAAmB;AACxB,WAAK,mBAAmB;AACxB,WAAK,aAAa;AAClB,WAAK,aAAa;AAClB,YAAM,KAAK,kBAAkB,WAAW;AACxC,WAAK,oBAAoB;AAAA,IAC3B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMA,mBAAmB,QAA2B;AAC5C,SAAK,sBAAsB;AAC3B,SAAK,gBAAgB,MAAM;AAAA,EAC7B;AAAA,EAEA,wBAA8B;AAC5B,SAAK,mBAAmB;AACxB,SAAK,mBAAmB;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAMA,SAAS,OAAkC;AACzC,SAAK,SAAS;AACd,SAAK,iBAAiB,KAAK;AAAA,EAC7B;AAAA,EAEA,YAAY,UAAyB;AACnC,SAAK,cAAc;AAAA,EACrB;AAAA,EAEA,QAAc;AACZ,SAAK,cAAc;AACnB,SAAK,SAAS;AACd,SAAK,iBAAiB,MAAM;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,UAAyB;AAC7B,UAAM,KAAK,gBAAgB;AAC3B,UAAM,KAAK,kBAAkB;AAC7B,UAAM,KAAK,mBAAmB;AAC9B,SAAK,WAAW;AAChB,SAAK,iBAAiB;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA,EAMQ,gBAAgB,QAA2B;AACjD,UAAM,UAAU,CAAC,UAA2D;AAC1E,WAAK,WAAW,KAAK;AAAA,IACvB;AACA,WAAO,GAAG,SAAS,OAAO;AAC1B,SAAK,mBAAmB,MAAM;AAAE,aAAO,MAAM,SAAS,OAAO;AAAA,IAAG;AAAA,EAClE;AAAA,EAEQ,uBAAuB,SAA2B;AACxD,UAAM,SAAS,QAAQ;AACvB,QAAI,QAAQ;AACV,WAAK,gBAAgB,MAAM;AAAA,IAC7B;AAAA,EACF;AAAA,EAEQ,YAAY,OAAkC;AACpD,SAAK,SAAS;AACd,SAAK,iBAAiB,KAAK;AAAA,EAC7B;AACF;","names":[]}
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@omote/avatar",
3
+ "version": "0.1.1",
4
+ "description": "Renderer-agnostic avatar voice composition for Omote SDK",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "require": "./dist/index.cjs"
14
+ }
15
+ },
16
+ "scripts": {
17
+ "build": "tsup",
18
+ "typecheck": "tsc --noEmit"
19
+ },
20
+ "peerDependencies": {
21
+ "@omote/core": ">=0.10.0"
22
+ },
23
+ "devDependencies": {
24
+ "@omote/core": "file:../core",
25
+ "tsup": "^8.0.0",
26
+ "typescript": "^5.3.0"
27
+ },
28
+ "publishConfig": {
29
+ "access": "public"
30
+ },
31
+ "files": [
32
+ "dist"
33
+ ],
34
+ "license": "MIT",
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "https://github.com/omoteai/omote.git",
38
+ "directory": "packages/avatar"
39
+ }
40
+ }