@streamoji/aitwin 0.1.5 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -53,7 +53,7 @@ Provide **`id`** (cloud twin) **or** **`assets`** (fixed URLs). One is required.
53
53
  | `id` | Twin id for `getAiTwin` (e.g. `olivia`) |
54
54
  | `assets` | `{ twinBase, binBase, encrypted }` — skip `getAiTwin` (lab / custom CDN) |
55
55
  | `authToken` | Bearer for TTS + encrypted assets; omitted → dev `getAuthToken` |
56
- | `ttsEngineId` | TTS engine when using `assets` (default Google) |
56
+ | `ttsEngineId` | TTS engine when using `assets` (default Cartesia) |
57
57
  | `voiceId` | Override TTS voice |
58
58
  | `speakingRate` | Default `0.85` |
59
59
  | `showErrorOverlay` | Canvas error overlay (default `true`) |
package/dist/aitwin.cjs CHANGED
@@ -1,3 +1,3 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const Oe=require("react/jsx-runtime"),p=require("react");var Pe=typeof document<"u"?document.currentScript:null;const xt="https://pub-607ad1fc22e2400eb57d17240aab857c.r2.dev",lt={publicBase:xt},Ct="0.1.5",Mt={version:Ct},Ft={},Ae="https://ai.streamoji.com",Ot=`${lt.publicBase}/custom-faces`,Pt=`${lt.publicBase}/aitwin-workers/v${Mt.version}/visemeDiffPreview.worker.js`;function Lt(e){if(e)return e;const t=typeof{url:typeof document>"u"?require("url").pathToFileURL(__filename).href:Pe&&Pe.tagName.toUpperCase()==="SCRIPT"&&Pe.src||new URL("aitwin.cjs",document.baseURI).href}<"u"?Ft?.VITE_AITWIN_WORKER_URL:void 0;return t?.trim()?t.trim():Pt}const Ut="https://us-central1-streamoji-265f4.cloudfunctions.net/getAiTwin",re="eng_a7f2b9c1",we="eng_d4e8f3a2",ge="eng_c9b1e6d4",Ke=we,Nt=new Set([we,ge]),ft={[re]:"oculus_direct",[ge]:"oculus_direct",[we]:"inworld_word"},Je={google:re,inworld:we,cartesia:ge};function Bt(e){return ft[e]}function Vt(e){return e===ge}function $t(e){if(e.ttsEngineId&&e.ttsEngineId in ft)return e.ttsEngineId;const t=e.tts?.toLowerCase();return t&&t in Je?Je[t]:Ke}class ve extends Error{constructor(t="AI twin not found"){super(t),this.name="AiTwinNotFoundError"}}async function dt(e,t=Ut){const n=new URL(t);n.searchParams.set("id",e);const r=await fetch(n.toString());if(r.status===404)throw new ve;if(!r.ok)throw new Error(`getAiTwin failed (${r.status})`);const s=await r.json();if(!s.success)throw new ve(s.error??"AI twin not found");const{tts:i,...a}=s.data;return{...a,ttsEngineId:$t(s.data)}}const Ht="https://us-central1-streamoji-265f4.cloudfunctions.net/getAuthToken",qt="client_6TNvp3SCs4Og0a1ijm9TommXLql1",Wt="kk8Fq8EmexzP10jMIEwY3R44M5RKUEm1",Kt="6TNvp3SCs4Og0a1ijm9TommXLql1",Gt="Swaraj Mali";async function Ue(){const e=await fetch(Ht,{method:"POST",headers:{"Content-Type":"application/json","Client-Id":qt,"Client-Secret":Wt},body:JSON.stringify({userId:Kt,userName:Gt})});if(!e.ok)throw new Error(`getAuthToken failed (${e.status})`);const t=await e.json(),n=t.authToken??t.token??"";if(!n.trim())throw new Error("getAuthToken returned no token");return n}async function jt(e,t=Ae){const n=await fetch(`${t.replace(/\/$/,"")}/api/session-value`,{headers:{Authorization:`Bearer ${e}`}});if(!n.ok)throw new Error(`/api/session-value failed (${n.status})`);const r=await n.json();if(!r.value)throw new Error("Session value response missing value");return r}function zt(e){const t=e.trim();if(t.length%2!==0)throw new Error("Invalid hex key");const n=new Uint8Array(t.length/2);for(let r=0;r<t.length;r+=2)n[r/2]=Number.parseInt(t.slice(r,r+2),16);return n}function Se(e){return Uint8Array.from(e)}function Qt(e,t){const n=new Uint8Array(e.length+t.length);return n.set(e,0),n.set(t,e.length),n}async function Jt(e,t){if(!t)throw new Error("Asset key is required for encrypted assets");if(e.byteLength<28)throw new Error("Encrypted payload too small");const n=new Uint8Array(e),r=Se(n.subarray(0,12)),s=Se(n.subarray(12,28)),i=Se(n.subarray(28)),a=Se(Qt(i,s)),c=await crypto.subtle.importKey("raw",zt(t),{name:"AES-GCM"},!1,["decrypt"]);return crypto.subtle.decrypt({name:"AES-GCM",iv:r,tagLength:128},c,a)}let Ne=null;const Be=new Set;function Yt(e,t=Ot){const n=`${t.replace(/\/$/,"")}/${e}`;return{twinBase:n,binBase:n,encrypted:!0}}function Xt(e){Ne=e;for(const t of Be)t()}function Zt(e,t){const n=typeof globalThis.location<"u"?globalThis.location.href:void 0;if(!n)return e;const r=s=>{try{return new URL(s,n).href.replace(/\/$/,"")}catch{return s}};return{twinBase:r(e.twinBase),binBase:r(e.binBase),encrypted:e.encrypted}}function se(){if(!Ne)throw new Error("Twin assets not configured; call setActiveTwinAssets first");return Ne}function en(e){return Be.add(e),()=>Be.delete(e)}function tn(){return`${se().twinBase}/sil.png`}function nn(){return`${se().twinBase}/idle.mp4`}function rn(){const{encrypted:e,binBase:t,twinBase:n}=se();return e?t:n}function ht(){return se().encrypted}function sn(){const{binBase:e,twinBase:t,encrypted:n}=se();return n?`${e}/atlas.bin`:`${t}/atlas.json`}function on(){const{binBase:e,twinBase:t,encrypted:n}=se();return n?`${e}/expression_atlas.bin`:`${t}/expression_atlas.json`}function an(e){const t=e.split(/\r?\n/);let n="",r="";for(const i of t)i.startsWith("event:")?n=i.slice(6).trim():i.startsWith("data:")&&(r=i.slice(5).trim());if(!n)return null;let s={};if(r)try{s=JSON.parse(r)}catch{s={raw:r}}return{event:n,data:s}}const _t=["aa","CH","DD","E","FF","I","O","PP","RR","SS","TH","U","kk","nn","sil"],cn=new Map(_t.map(e=>[e.toLowerCase(),e]));function mt(e){const t=(e??"").trim();return t?cn.get(t.toLowerCase())??"sil":"sil"}const un={aei:["aa","E","I"],o:["O","U"],ee:["I"],bmp:["PP"],fv:["FF"],l:["nn"],r:["RR"],th:["TH"],qw:["U","O"],cdgknstxyz:["DD","SS","kk","CH"]};function ln(e){if(!e)return["sil"];const t=e.toLowerCase();return un[t]??["sil"]}function fn(e,t){const n=e.word.length;if(n<=0)return 0;const r=e.wduration;if(r<=0)return 0;const s=Math.max(0,Math.min(1,(t-e.wtime)/r));return Math.min(n-1,Math.floor(s*n))}function be(e,t){const n=Math.max(0,Math.min(e.length-1,t));return e[n]??""}function dn(e,t){const n=e.toLowerCase(),r=be(n,t),s=n.slice(Math.max(0,t-1),t+2);return r==="i"||r==="y"?"I":s.includes("ee")||r==="e"||n.includes("ea")?"E":"aa"}function hn(e,t){const n=e.toLowerCase(),r=n.slice(Math.max(0,t-1),Math.min(n.length,t+3));if(/oo|ou|uw/.test(r))return"U";const s=be(n,t);return s==="u"||s==="w"?"U":"O"}function _n(e,t){const n=e.toLowerCase(),r=n.slice(Math.max(0,t-2),t+1);if(/qu/.test(r))return"U";const s=n.slice(Math.max(0,t-1),Math.min(n.length,t+3));return/wo|wh/.test(s)||be(n,t)==="o"?"O":"U"}const Te={d:"DD",t:"DD",n:"DD",s:"SS",z:"SS",k:"kk",g:"kk",c:"CH",x:"CH",j:"CH"};function mn(e,t){const n=e.toLowerCase(),r=be(n,t);if(Te[r])return Te[r];for(let s=0;s<n.length;s++){const i=n[s];if(Te[i])return Te[i]}return"DD"}function wn(e,t,n){const r=ln(e);if(r.length===1)return r[0];const s=t.trim();if(!s)return r[0];const i=(e??"").toLowerCase(),a=Math.max(0,n);switch(i){case"aei":return dn(s,a);case"o":return hn(s,a);case"qw":return _n(s,a);case"cdgknstxyz":return mn(s,a);default:return r[0]}}function gn(e){let t=e.trim();const n=t.indexOf(",");t.startsWith("data:")&&n>=0&&(t=t.slice(n+1)),t=t.replace(/\s+/g,"").replace(/-/g,"+").replace(/_/g,"/");const r=t.length%4;return r!==0&&(t+="=".repeat(4-r)),t}const yn=24e3;function pn(e){return e.length>=4&&e[0]===82&&e[1]===73&&e[2]===70&&e[3]===70}function Ye(e,t,n=yn){const r=t.byteOffset%2===0?t:t.slice(),s=new Int16Array(r.buffer,r.byteOffset,r.byteLength/2),i=new Float32Array(s.length);for(let c=0;c<s.length;c++)i[c]=s[c]>=32768?-(65536-s[c])/32768:s[c]/32767;const a=e.createBuffer(1,i.length,n);return a.copyToChannel(i,0),a}function En(e){const t=gn(e),n=window.atob(t),r=new Uint8Array(n.length);for(let s=0;s<n.length;s++)r[s]=n.charCodeAt(s);return r}async function Sn(e,t){const n=En(t);if(pn(n)){const r=n.buffer.slice(n.byteOffset,n.byteOffset+n.byteLength);return e.decodeAudioData(r)}if(n.length>=2&&n.length%2===0)return Ye(e,n);try{const r=n.buffer.slice(n.byteOffset,n.byteOffset+n.byteLength);return await e.decodeAudioData(r)}catch{return Ye(e,n)}}function wt(e,t){let n=null;for(const r of e)t<r.vtime||t>=r.vtime+r.vduration||(!n||r.vtime>=n.vtime)&&(n=r);return n?n.viseme:"sil"}function gt(e,t){for(const n of e)if(t>=n.wtime&&t<n.wtime+n.wduration)return n;return null}function Xe(e){let t=0;for(const n of e)t=Math.max(t,n.vtime+n.vduration);return t}const yt=.5,pt=1.5,Ge="Olivia",Et="f786b574-daa5-4673-aa0c-cbe3e8534c02",je=.85;function St(e,t=Ae){const n=`${t.replace(/\/$/,"")}/avatar_ttsWithPoses`,r=[],s=[],i=[];let a="neutral";const c=[],l=[];let d=null,m=!1,_=!1,I=!1,o=!1,x=0,w=0,u=0,g=0,E=null,R=1,$="",y=re,S=re,C=!1;const D=new Set,q=()=>{for(const h of l)h.playbackRate.value=R},W=()=>D.forEach(h=>h()),ae=()=>{E!=null&&(clearTimeout(E),E=null)},ye=()=>{for(const h of l)try{h.stop()}catch{}l.length=0},X=()=>{C=!0,ae(),ye(),c.length=0,m=!1,_=!1,I=!1,o=!1,r.length=0,s.length=0,i.length=0,a="neutral",u=0,g=0,w=0,e("idle"),W()},K=()=>{!o||m||l.length>0||c.length>0||(_=!1,ae(),e("done"),W())},pe=()=>{const h=Xe(r);if(h<=0){e("done"),W();return}_=!0,x=performance.now(),e("speaking"),W(),ae();const M=R>0?h/R:h;E=setTimeout(()=>{C||(_=!1,E=null,e("done"),W())},M)},xe=(h,M,B)=>{h.length!==0&&(B&&(u=M),h.forEach(P=>{const U=String(P.word??"").trim();if(!U)return;const Q=Math.round((P.start??0)*1e3),V=Math.round((P.duration??0)*1e3);s.push({word:U,wtime:u+Q,wduration:V,queueIndex:s.length})}))},ce=(h,M,B,P)=>{h.length!==0&&(B&&(u=M),h.forEach(k=>{const U=String(k.symbol??"").trim();if(!U)return;const Q=Math.round((k.start??0)*1e3),V=Math.max(1,Math.round((k.duration??0)*1e3)),L=u+Q;let F;if(Bt(P)==="oculus_direct")F=mt(U);else{const O=gt(s,L),J=O?fn(O,L):0;F=wn(U,O?.word??"",J)}r.push({viseme:F,weight:1,vtime:L,vduration:V})}),W())},ie=(h,M,B,P,k)=>{xe(M,B,P),ce(h,B,P,k)},Ee=async(h,M,B,P)=>{if(C||!h?.trim()){(M.length>0||B.length>0)&&!I&&ie(M,B,u,P,S);return}if(m){c.push({audio:h,visemes:M,words:B,isNewSegment:P});return}m=!0;try{const k=window.AudioContext||window.webkitAudioContext,U=d??new k;U.state==="suspended"&&await U.resume(),d=U;const Q=await Sn(U,h);I=!0;const V=U.currentTime;let L=g;const F=!_;L<V&&(L=V+.1),g=L+Q.duration;const O=U.createBufferSource();if(O.buffer=Q,O.playbackRate.value=R,O.connect(U.destination),l.push(O),C){l.pop();return}if(F){_=!0,e("speaking"),w=L,u=0,r.length=0,s.length=0;const H=(L-V)*1e3;x=performance.now()+H}O.onended=()=>{const H=l.indexOf(O);H>=0&&l.splice(H,1),K(),W()},O.start(L);const J=(L-w)*1e3;ie(M,B,J,P,S)}catch(k){console.error("[avatarTtsLipsync] audio chunk failed:",k)}finally{m=!1;const k=c.shift();k?await Ee(k.audio,k.visemes,k.words,k.isNewSegment):K()}},Z=()=>{if(o=!0,!I&&r.length>0){pe();return}K()};return{setDeveloperToken:h=>{$=h},setTtsEngineId:h=>{y=h},getTtsEngineId:()=>y,speak:async(h,M)=>{X(),C=!1,e("loading");const B=$.trim();if(!B)throw new Error("Developer token required for avatar_ttsWithPoses");const P=M?.ttsEngineId??y??Ke;S=P;const k=M?.voiceId??Ge,U=M?.speakingRate??je,Q=Math.max(yt,Math.min(pt,U)),V={user_query:h,ttsEngineId:P,speakingRate:Q};Nt.has(P)&&(V.voice_id=k);try{const L=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${B}`},body:JSON.stringify(V)});if(!L.ok)throw new Error(`avatar_ttsWithPoses failed (${L.status})`);const F=L.body;if(!F)throw new Error("No response body");const O=F.getReader(),J=new TextDecoder;let H="";const le=async fe=>{const f=an(fe);if(f){if(f.event==="audio"){const T=f.data.chunk,A=f.data.visemes??[],v=f.data.words??[],b=f.data.is_new_segment??!1;if(T)await Ee(T,A,v,b);else if(A.length>0||v.length>0){const G=b&&r.length>0?Xe(r):u;ie(A,v,G,b,P)}}else if(f.event==="metadata"){const T=f.data.mood;typeof T=="string"&&T.trim()&&(a=T.trim());const A=f.data.sentence_emotions;if(Array.isArray(A)){i.length=0;for(const v of A){if(!v||typeof v!="object")continue;const b=v;i.push({sentence_index:Number(b.sentence_index??0),text:String(b.text??""),sentiment:typeof b.sentiment=="string"?b.sentiment:void 0,emotion:String(b.emotion??a),start_word:Number(b.start_word??0),end_word:Number(b.end_word??0)})}}W()}else if(f.event==="error")throw new Error(String(f.data.message??"avatar_ttsWithPoses stream error"))}};for(;;){const{done:fe,value:f}=await O.read();f&&(H+=J.decode(f,{stream:!0}));const T=H.split(`
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const Pe=require("react/jsx-runtime"),p=require("react");var Le=typeof document<"u"?document.currentScript:null;const Ct="https://pub-607ad1fc22e2400eb57d17240aab857c.r2.dev",ht={publicBase:Ct},Mt="0.1.7",Ft={version:Mt},Ot={},ve="https://ai.streamoji.com",Pt=`${ht.publicBase}/custom-faces`,Lt=`${ht.publicBase}/aitwin-workers/v${Ft.version}/visemeDiffPreview.worker.js`;function Ut(e){if(e)return e;const t=typeof{url:typeof document>"u"?require("url").pathToFileURL(__filename).href:Le&&Le.tagName.toUpperCase()==="SCRIPT"&&Le.src||new URL("aitwin.cjs",document.baseURI).href}<"u"?Ot?.VITE_AITWIN_WORKER_URL:void 0;return t?.trim()?t.trim():Lt}const Nt="https://us-central1-streamoji-265f4.cloudfunctions.net/getAiTwin",Ge="eng_a7f2b9c1",be="eng_d4e8f3a2",ae="eng_c9b1e6d4",re=ae,Bt=new Set([be,ae]),_t={[Ge]:"oculus_direct",[ae]:"oculus_direct",[be]:"inworld_word"},Xe={google:Ge,inworld:be,cartesia:ae};function Vt(e){return _t[e]}function $t(e){return e===ae}function Ht(e){if(e.ttsEngineId&&e.ttsEngineId in _t)return e.ttsEngineId;const t=e.tts?.toLowerCase();return t&&t in Xe?Xe[t]:re}class Ae extends Error{constructor(t="AI twin not found"){super(t),this.name="AiTwinNotFoundError"}}async function mt(e,t=Nt){const n=new URL(t);n.searchParams.set("id",e);const r=await fetch(n.toString());if(r.status===404)throw new Ae;if(!r.ok)throw new Error(`getAiTwin failed (${r.status})`);const s=await r.json();if(!s.success)throw new Ae(s.error??"AI twin not found");const{tts:i,...c}=s.data;return{...c,ttsEngineId:Ht(s.data)}}const Wt="https://us-central1-streamoji-265f4.cloudfunctions.net/getAuthToken",qt="client_6TNvp3SCs4Og0a1ijm9TommXLql1",Kt="kk8Fq8EmexzP10jMIEwY3R44M5RKUEm1",Gt="6TNvp3SCs4Og0a1ijm9TommXLql1",jt="Swaraj Mali";async function Ne(){const e=await fetch(Wt,{method:"POST",headers:{"Content-Type":"application/json","Client-Id":qt,"Client-Secret":Kt},body:JSON.stringify({userId:Gt,userName:jt})});if(!e.ok)throw new Error(`getAuthToken failed (${e.status})`);const t=await e.json(),n=t.authToken??t.token??"";if(!n.trim())throw new Error("getAuthToken returned no token");return n}async function zt(e,t=ve){const n=await fetch(`${t.replace(/\/$/,"")}/api/session-value`,{headers:{Authorization:`Bearer ${e}`}});if(!n.ok)throw new Error(`/api/session-value failed (${n.status})`);const r=await n.json();if(!r.value)throw new Error("Session value response missing value");return r}function Qt(e){const t=e.trim();if(t.length%2!==0)throw new Error("Invalid hex key");const n=new Uint8Array(t.length/2);for(let r=0;r<t.length;r+=2)n[r/2]=Number.parseInt(t.slice(r,r+2),16);return n}function Se(e){return Uint8Array.from(e)}function Jt(e,t){const n=new Uint8Array(e.length+t.length);return n.set(e,0),n.set(t,e.length),n}async function Yt(e,t){if(!t)throw new Error("Asset key is required for encrypted assets");if(e.byteLength<28)throw new Error("Encrypted payload too small");const n=new Uint8Array(e),r=Se(n.subarray(0,12)),s=Se(n.subarray(12,28)),i=Se(n.subarray(28)),c=Se(Jt(i,s)),a=await crypto.subtle.importKey("raw",Qt(t),{name:"AES-GCM"},!1,["decrypt"]);return crypto.subtle.decrypt({name:"AES-GCM",iv:r,tagLength:128},a,c)}let Be=null;const Ve=new Set;function Xt(e,t=Pt){const n=`${t.replace(/\/$/,"")}/${e}`;return{twinBase:n,binBase:n,encrypted:!0}}function Zt(e){Be=e;for(const t of Ve)t()}function en(e,t){const n=typeof globalThis.location<"u"?globalThis.location.href:void 0;if(!n)return e;const r=s=>{try{return new URL(s,n).href.replace(/\/$/,"")}catch{return s}};return{twinBase:r(e.twinBase),binBase:r(e.binBase),encrypted:e.encrypted}}function se(){if(!Be)throw new Error("Twin assets not configured; call setActiveTwinAssets first");return Be}function tn(e){return Ve.add(e),()=>Ve.delete(e)}function Ze(){const{binBase:e,twinBase:t,encrypted:n}=se();return n?`${e}/sil.bin`:`${t}/sil.png`}function nn(){const{binBase:e,twinBase:t,encrypted:n}=se();return n?`${e}/idle.bin`:`${t}/idle.mp4`}function rn(){const{encrypted:e,binBase:t,twinBase:n}=se();return e?t:n}function je(){return se().encrypted}function sn(){const{binBase:e,twinBase:t,encrypted:n}=se();return n?`${e}/atlas.bin`:`${t}/atlas.json`}function on(){const{binBase:e,twinBase:t,encrypted:n}=se();return n?`${e}/expression_atlas.bin`:`${t}/expression_atlas.json`}function an(e){const t=e.split(/\r?\n/);let n="",r="";for(const i of t)i.startsWith("event:")?n=i.slice(6).trim():i.startsWith("data:")&&(r=i.slice(5).trim());if(!n)return null;let s={};if(r)try{s=JSON.parse(r)}catch{s={raw:r}}return{event:n,data:s}}const wt=["aa","CH","DD","E","FF","I","O","PP","RR","SS","TH","U","kk","nn","sil"],cn=new Map(wt.map(e=>[e.toLowerCase(),e]));function gt(e){const t=(e??"").trim();return t?cn.get(t.toLowerCase())??"sil":"sil"}const un={aei:["aa","E","I"],o:["O","U"],ee:["I"],bmp:["PP"],fv:["FF"],l:["nn"],r:["RR"],th:["TH"],qw:["U","O"],cdgknstxyz:["DD","SS","kk","CH"]};function ln(e){if(!e)return["sil"];const t=e.toLowerCase();return un[t]??["sil"]}function fn(e,t){const n=e.word.length;if(n<=0)return 0;const r=e.wduration;if(r<=0)return 0;const s=Math.max(0,Math.min(1,(t-e.wtime)/r));return Math.min(n-1,Math.floor(s*n))}function De(e,t){const n=Math.max(0,Math.min(e.length-1,t));return e[n]??""}function dn(e,t){const n=e.toLowerCase(),r=De(n,t),s=n.slice(Math.max(0,t-1),t+2);return r==="i"||r==="y"?"I":s.includes("ee")||r==="e"||n.includes("ea")?"E":"aa"}function hn(e,t){const n=e.toLowerCase(),r=n.slice(Math.max(0,t-1),Math.min(n.length,t+3));if(/oo|ou|uw/.test(r))return"U";const s=De(n,t);return s==="u"||s==="w"?"U":"O"}function _n(e,t){const n=e.toLowerCase(),r=n.slice(Math.max(0,t-2),t+1);if(/qu/.test(r))return"U";const s=n.slice(Math.max(0,t-1),Math.min(n.length,t+3));return/wo|wh/.test(s)||De(n,t)==="o"?"O":"U"}const Te={d:"DD",t:"DD",n:"DD",s:"SS",z:"SS",k:"kk",g:"kk",c:"CH",x:"CH",j:"CH"};function mn(e,t){const n=e.toLowerCase(),r=De(n,t);if(Te[r])return Te[r];for(let s=0;s<n.length;s++){const i=n[s];if(Te[i])return Te[i]}return"DD"}function wn(e,t,n){const r=ln(e);if(r.length===1)return r[0];const s=t.trim();if(!s)return r[0];const i=(e??"").toLowerCase(),c=Math.max(0,n);switch(i){case"aei":return dn(s,c);case"o":return hn(s,c);case"qw":return _n(s,c);case"cdgknstxyz":return mn(s,c);default:return r[0]}}function gn(e){let t=e.trim();const n=t.indexOf(",");t.startsWith("data:")&&n>=0&&(t=t.slice(n+1)),t=t.replace(/\s+/g,"").replace(/-/g,"+").replace(/_/g,"/");const r=t.length%4;return r!==0&&(t+="=".repeat(4-r)),t}const yn=24e3;function pn(e){return e.length>=4&&e[0]===82&&e[1]===73&&e[2]===70&&e[3]===70}function et(e,t,n=yn){const r=t.byteOffset%2===0?t:t.slice(),s=new Int16Array(r.buffer,r.byteOffset,r.byteLength/2),i=new Float32Array(s.length);for(let a=0;a<s.length;a++)i[a]=s[a]>=32768?-(65536-s[a])/32768:s[a]/32767;const c=e.createBuffer(1,i.length,n);return c.copyToChannel(i,0),c}function En(e){const t=gn(e),n=window.atob(t),r=new Uint8Array(n.length);for(let s=0;s<n.length;s++)r[s]=n.charCodeAt(s);return r}async function Sn(e,t){const n=En(t);if(pn(n)){const r=n.buffer.slice(n.byteOffset,n.byteOffset+n.byteLength);return e.decodeAudioData(r)}if(n.length>=2&&n.length%2===0)return et(e,n);try{const r=n.buffer.slice(n.byteOffset,n.byteOffset+n.byteLength);return await e.decodeAudioData(r)}catch{return et(e,n)}}function yt(e,t){let n=null;for(const r of e)t<r.vtime||t>=r.vtime+r.vduration||(!n||r.vtime>=n.vtime)&&(n=r);return n?n.viseme:"sil"}function pt(e,t){for(const n of e)if(t>=n.wtime&&t<n.wtime+n.wduration)return n;return null}function tt(e){let t=0;for(const n of e)t=Math.max(t,n.vtime+n.vduration);return t}const Et=.5,St=1.5,ze="Olivia",Tt="f786b574-daa5-4673-aa0c-cbe3e8534c02",Qe=.85;function kt(e,t=ve){const n=`${t.replace(/\/$/,"")}/avatar_ttsWithPoses`,r=[],s=[],i=[];let c="neutral";const a=[],l=[];let d=null,m=!1,_=!1,k=!1,o=!1,x=0,w=0,u=0,g=0,E=null,R=1,$="",y=re,S=re,C=!1;const D=new Set,W=()=>{for(const h of l)h.playbackRate.value=R},q=()=>D.forEach(h=>h()),ce=()=>{E!=null&&(clearTimeout(E),E=null)},ge=()=>{for(const h of l)try{h.stop()}catch{}l.length=0},Z=()=>{C=!0,ce(),ge(),a.length=0,m=!1,_=!1,k=!1,o=!1,r.length=0,s.length=0,i.length=0,c="neutral",u=0,g=0,w=0,e("idle"),q()},K=()=>{!o||m||l.length>0||a.length>0||(_=!1,ce(),e("done"),q())},ye=()=>{const h=tt(r);if(h<=0){e("done"),q();return}_=!0,x=performance.now(),e("speaking"),q(),ce();const M=R>0?h/R:h;E=setTimeout(()=>{C||(_=!1,E=null,e("done"),q())},M)},Me=(h,M,B)=>{h.length!==0&&(B&&(u=M),h.forEach(P=>{const U=String(P.word??"").trim();if(!U)return;const Q=Math.round((P.start??0)*1e3),V=Math.round((P.duration??0)*1e3);s.push({word:U,wtime:u+Q,wduration:V,queueIndex:s.length})}))},ue=(h,M,B,P)=>{h.length!==0&&(B&&(u=M),h.forEach(I=>{const U=String(I.symbol??"").trim();if(!U)return;const Q=Math.round((I.start??0)*1e3),V=Math.max(1,Math.round((I.duration??0)*1e3)),L=u+Q;let F;if(Vt(P)==="oculus_direct")F=gt(U);else{const O=pt(s,L),J=O?fn(O,L):0;F=wn(U,O?.word??"",J)}r.push({viseme:F,weight:1,vtime:L,vduration:V})}),q())},ie=(h,M,B,P,I)=>{Me(M,B,P),ue(h,B,P,I)},pe=async(h,M,B,P)=>{if(C||!h?.trim()){(M.length>0||B.length>0)&&!k&&ie(M,B,u,P,S);return}if(m){a.push({audio:h,visemes:M,words:B,isNewSegment:P});return}m=!0;try{const I=window.AudioContext||window.webkitAudioContext,U=d??new I;U.state==="suspended"&&await U.resume(),d=U;const Q=await Sn(U,h);k=!0;const V=U.currentTime;let L=g;const F=!_;L<V&&(L=V+.1),g=L+Q.duration;const O=U.createBufferSource();if(O.buffer=Q,O.playbackRate.value=R,O.connect(U.destination),l.push(O),C){l.pop();return}if(F){_=!0,e("speaking"),w=L,u=0,r.length=0,s.length=0;const H=(L-V)*1e3;x=performance.now()+H}O.onended=()=>{const H=l.indexOf(O);H>=0&&l.splice(H,1),K(),q()},O.start(L);const J=(L-w)*1e3;ie(M,B,J,P,S)}catch(I){console.error("[avatarTtsLipsync] audio chunk failed:",I)}finally{m=!1;const I=a.shift();I?await pe(I.audio,I.visemes,I.words,I.isNewSegment):K()}},ee=()=>{if(o=!0,!k&&r.length>0){ye();return}K()};return{setDeveloperToken:h=>{$=h},setTtsEngineId:h=>{y=h},getTtsEngineId:()=>y,speak:async(h,M)=>{Z(),C=!1,e("loading");const B=$.trim();if(!B)throw new Error("Developer token required for avatar_ttsWithPoses");const P=M?.ttsEngineId??y??re;S=P;const I=M?.voiceId??ze,U=M?.speakingRate??Qe,Q=Math.max(Et,Math.min(St,U)),V={user_query:h,ttsEngineId:P,speakingRate:Q};Bt.has(P)&&(V.voice_id=I);try{const L=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${B}`},body:JSON.stringify(V)});if(!L.ok)throw new Error(`avatar_ttsWithPoses failed (${L.status})`);const F=L.body;if(!F)throw new Error("No response body");const O=F.getReader(),J=new TextDecoder;let H="";const fe=async de=>{const f=an(de);if(f){if(f.event==="audio"){const T=f.data.chunk,v=f.data.visemes??[],A=f.data.words??[],b=f.data.is_new_segment??!1;if(T)await pe(T,v,A,b);else if(v.length>0||A.length>0){const G=b&&r.length>0?tt(r):u;ie(v,A,G,b,P)}}else if(f.event==="metadata"){const T=f.data.mood;typeof T=="string"&&T.trim()&&(c=T.trim());const v=f.data.sentence_emotions;if(Array.isArray(v)){i.length=0;for(const A of v){if(!A||typeof A!="object")continue;const b=A;i.push({sentence_index:Number(b.sentence_index??0),text:String(b.text??""),sentiment:typeof b.sentiment=="string"?b.sentiment:void 0,emotion:String(b.emotion??c),start_word:Number(b.start_word??0),end_word:Number(b.end_word??0)})}}q()}else if(f.event==="error")throw new Error(String(f.data.message??"avatar_ttsWithPoses stream error"))}};for(;;){const{done:de,value:f}=await O.read();f&&(H+=J.decode(f,{stream:!0}));const T=H.split(`
2
2
 
3
- `);H=T.pop()??"";for(const A of T)await le(A);if(fe){H.trim()&&await le(H.trim()),C||Z();break}}}catch(L){throw console.error("[avatarTtsLipsync]",L),X(),e("error"),L}},stop:X,getVisemeQueue:()=>r,getWordQueue:()=>s,getSentenceEmotions:()=>i,getStreamMood:()=>a,getPlaybackElapsedMs:()=>_?I&&d&&w>0?Math.max(0,(d.currentTime-w)*1e3):Math.max(0,(performance.now()-x)*R):0,isSpeaking:()=>_,setPlaybackSpeed:h=>{R=Math.max(.1,Math.min(1,h)),q()},getPlaybackSpeed:()=>R,subscribe:h=>(D.add(h),()=>D.delete(h))}}function Tn(e,t,n){return{width:e.crop?.source_width??t,height:e.crop?.source_height??n}}function In(e,t){const n=e.crop;return{x:t?.source_x??n?.x??0,y:t?.source_y??n?.y??0,width:t?.source_w??n?.width??e.frame_width??0,height:t?.source_h??n?.height??e.frame_height??0}}function kn(e){return e?(e.w??0)>0&&(e.h??0)>0:!1}async function Tt(e,t){const n=await fetch(e);if(!n.ok)throw new Error(`Failed to load encrypted asset: ${e}`);const r=await n.arrayBuffer();return Jt(r,t)}async function An(e,t){if(!t)throw new Error("Missing asset key for encrypted JSON");const n=await Tt(e,t),r=new TextDecoder().decode(n);return JSON.parse(r)}async function vn(e){const t=new Blob([e],{type:"image/webp"}),n=URL.createObjectURL(t);return new Promise((r,s)=>{const i=new Image;i.decoding="async",i.onload=()=>{URL.revokeObjectURL(n),r(i)},i.onerror=()=>{URL.revokeObjectURL(n),s(new Error("Failed to decode decrypted image"))},i.src=n})}function It(e,t){return`${e}/${t}_minus_sil.png`}const ze=15,Rn=["aa","E","I","O","U","PP","FF","DD","SS","TH","CH","RR","kk","nn"],Ve=["t01_0.17","t02_0.33","t03_0.50","t04_0.67","t05_0.83"],bn=Ve.length,Ze=new Set(["aa__kk","aa__nn","aa__sil","CH__aa","CH__DD","CH__E","CH__FF","CH__I","CH__kk","CH__nn","CH__O","CH__PP","CH__RR","CH__sil","CH__SS","CH__TH","CH__U","DD__aa","DD__E","DD__FF","DD__I","DD__kk","DD__nn","DD__O","DD__PP","DD__RR","DD__sil","DD__SS","DD__TH","DD__U","E__aa","E__FF","E__I","E__kk","E__nn","E__O","E__PP","E__RR","E__sil","E__SS","E__TH","E__U","FF__aa","FF__I","FF__kk","FF__nn","FF__O","FF__PP","FF__RR","FF__sil","FF__SS","FF__TH","FF__U","I__aa","I__kk","I__nn","I__O","I__PP","I__RR","I__sil","I__SS","I__TH","I__U","kk__nn","kk__sil","nn__sil","O__aa","O__kk","O__nn","O__PP","O__RR","O__sil","O__SS","O__TH","O__U","PP__aa","PP__kk","PP__nn","PP__RR","PP__sil","PP__SS","PP__TH","PP__U","RR__aa","RR__kk","RR__nn","RR__sil","RR__SS","RR__TH","RR__U","SS__aa","SS__kk","SS__nn","SS__sil","SS__TH","SS__U","TH__aa","TH__kk","TH__nn","TH__sil","TH__U","U__aa","U__kk","U__nn","U__sil"]);function et(e,t){return`${e}__${t}`}function tt(e,t){return`pairs/${e}/${t}_minus_sil.png`}function $e(e){return`${e}_minus_sil.png`}function Dn(e,t){if(e===t)return[];const n=[],r=et(e,t);if(Ze.has(r)){for(const i of Ve)n.push(tt(r,i));return n}const s=et(t,e);if(Ze.has(s)){for(let i=bn-1;i>=0;i--)n.push(tt(s,Ve[i]));return n}return[]}function xn(e){return e<16?[]:e<35?[2]:e<51?[0,4]:e<67?[0,2,4]:e<83?[0,1,2,3]:[0,1,2,3,4]}function Cn(e,t){return xn(t).map(r=>e[r]).filter(r=>r!=null)}function Mn(e,t,n,r){if(r<=0)return 0;const i=Math.max(1,n-t)/r,a=e-t,c=Math.floor(a/i);return Math.min(r-1,Math.max(0,c))}function Fn(e,t,n){if(!n)return`${e}/${t}`;const r=t.split("/").pop()??t,s=r.includes(".")?r.slice(0,r.lastIndexOf(".")):r;return`${e}/${s}.bin`}const On=[.32,.24,.16,.08,0],De=On.map(e=>`eyes_${e.toFixed(2)}`),Pn=["eyes_0.32","eyes_0.16","eyes_0.00"],Ln=["eyes_0.32","eyes_0.16","eyes_0.08","eyes_0.00"],Un={fear:"fear",afraid:"fear",anxiety:"fear",anger:"anger",angry:"anger",mad:"anger",sad:"sad",sadness:"sad",sorrow:"sad",neutral:"neutral",calm:"neutral",love:"love",loving:"love",affection:"love",happy:"happy",happiness:"happy",joy:"happy",joyful:"happy",excited:"happy",disgust:"disgust",disgusted:"disgust"};function oe(e,t="neutral"){const n=String(e??"").trim().toLowerCase();return n?Un[n]??t:t}function z(e){return e==="neutral"?null:It(e,"eyes_standard")}function He(e,t){return!t||t==="eyes_standard"?z(e):e==="neutral"&&t==="eyes_standard"?null:It(e,t)}function Nn(e){if(!e)return"open";const t=e.match(/\/(eyes_[^/]+)_minus_sil\.png$/);if(!t?.[1])return"open";const n=t[1];return De.includes(n)?n:"open"}function Bn(e){return e==="open"?-1:De.indexOf(e)}function Vn(e,t){const n=[];for(const r of t)n.push(He(e,r));for(let r=t.length-2;r>=0;r--)n.push(He(e,t[r]));return n.push(z(e)),n}function $n(e,t){if(t==="open")return[z(e)];const n=Bn(t);if(n<0)return[z(e)];const r=[];for(let s=n;s>=0;s--)r.push(He(e,De[s]));return r.push(z(e)),r}const Hn=["t01_0.20","t02_0.40","t03_0.60","t04_0.80"];function qn(e,t){return`${e}__${t}`}function Wn(e,t,n){return`pairs/${qn(e,t)}/${n}_minus_sil.png`}function Kn(e,t){return Hn.map(n=>Wn(e,t,n))}function he(e,t){return e+Math.random()*(t-e)}function Ie(){return he(14,32)}function Gn(e={}){const{initialDelayMs:t=800+Math.random()*1200,intervalMinMs:n=2200,intervalMaxMs:r=5800,doubleBlinkChance:s=.18,doubleBlinkGapMinMs:i=120,doubleBlinkGapMaxMs:a=220,fullBlinkChance:c=.75,postEmotionChangeDelayMs:l=380,minDwellMs:d=550}=e;let m="neutral",_="neutral",I=0,o={kind:"idle",nextBlinkAt:performance.now()+t},x=null,w="__eyes_open__|neutral";function u(y,S){x=y,w=`${y??"__eyes_open__"}|${S}`}function g(y,S){o={kind:"idle",nextBlinkAt:y+he(n,r)},_=S,u(z(S),S)}function E(y,S,C){const D=C?Pn:Math.random()<c?De:Ln;o={kind:"playing",paths:Vn(S,D),index:0,holdUntil:y+Ie(),after:"idle",blinkEmotion:S},_=S,u(o.paths[0]??null,S)}function R(y,S,C){const D=Nn(x),q=[];if(D!=="open"){const W=$n(S,D);q.push(...W.slice(0,-1))}q.push(...Kn(S,C)),q.push(z(C)),o={kind:"emotionBlend",paths:q,index:0,holdUntil:y+Ie(),thenEmotion:C},u(q[0]??null,S)}function $(y){if(o.kind==="emotionBlend"){for(;y>=o.holdUntil&&o.index<o.paths.length-1;)o.index+=1,o.holdUntil=y+Ie();const S=o.paths[o.index]??null;u(S,o.thenEmotion),y>=o.holdUntil&&o.index>=o.paths.length-1&&(m=o.thenEmotion,_=o.thenEmotion,u(z(o.thenEmotion),o.thenEmotion),o={kind:"idle",nextBlinkAt:y+l});return}if(o.kind==="idle"){u(z(_),_),y>=o.nextBlinkAt&&E(y,_,!1);return}if(o.kind==="doublePause"){u(z(o.blinkEmotion),o.blinkEmotion),y>=o.resumeAt&&E(y,o.blinkEmotion,!0);return}if(o.kind==="playing"){for(;y>=o.holdUntil&&o.index<o.paths.length-1;)o.index+=1,o.holdUntil=y+Ie();if(u(o.paths[o.index]??null,o.blinkEmotion),y>=o.holdUntil&&o.index>=o.paths.length-1){if(o.after==="resumeIdle"){g(y+l,m);return}if(o.after==="doublePause"){o={kind:"doublePause",resumeAt:y+he(i,a),blinkEmotion:o.blinkEmotion},u(z(o.blinkEmotion),o.blinkEmotion);return}if(o.after==="idle"&&Math.random()<s){o={kind:"doublePause",resumeAt:y+he(i,a),blinkEmotion:o.blinkEmotion},u(z(o.blinkEmotion),o.blinkEmotion);return}g(y,o.blinkEmotion)}}}return{advance:$,setTargetEmotion(y){const S=oe(y,m);if(S===m&&o.kind!=="emotionBlend")return;const C=performance.now();if(d>0&&S!==m&&o.kind!=="emotionBlend"&&!(m==="neutral"&&S!=="neutral")&&C-I<d)return;const D=m;if(m=S,I=C,o.kind==="playing"){R(C,_,S);return}if(o.kind==="emotionBlend"){o={...o,thenEmotion:S};return}R(C,D,S)},getTargetEmotion:()=>m,getExpressionPath:()=>x,getDrawKey:()=>w,reset(){m="neutral",_="neutral",I=0,g(performance.now()+he(n,r),"neutral")}}}function jn(e){const t=document.createElement("video");t.muted=!0,t.playsInline=!0,t.preload="auto",t.setAttribute("playsinline",""),t.loop=!0;let n=!1;return{async load(){n||await new Promise((r,s)=>{const i=()=>{const a=t.duration;if(!Number.isFinite(a)||a<=0){s(new Error(`Idle video has invalid duration: ${e}`));return}n=!0,t.currentTime=0,r()};t.addEventListener("loadeddata",i,{once:!0}),t.addEventListener("error",()=>s(new Error(`Failed to load idle video: ${e}`)),{once:!0}),t.src=e,t.load()})},isReady(){return n},getVideo(){return t},setActive(r){n&&(r?t.paused&&t.play().catch(()=>{}):t.paused||t.pause())},restart(){n&&(t.currentTime=0)}}}const zn=50,kt=400;function Qn(e,t,n){return e.filter(r=>{const s=r.queueIndex??-1;return s>=t&&s<=n})}function Jn(e,t){const n=[];for(const r of e){const s=Qn(t,r.start_word,r.end_word);if(s.length===0)continue;const i=s[0],a=s[s.length-1];n.push({sentence:r,startMs:Math.max(0,i.wtime-zn),endMs:a.wtime+a.wduration+kt})}return n.sort((r,s)=>r.startMs-s.startMs)}function Yn(e,t,n,r="neutral"){const s=oe(r);if(t.length===0)return s;if(n.length===0||e<n[0].wtime)return oe(t[0]?.emotion,s);const i=Jn(t,n);let a=null;for(const d of i)e>=d.startMs&&e<=d.endMs&&(a=d);if(a)return oe(a.sentence.emotion,s);const c=n[n.length-1],l=c.wtime+c.wduration;return e>l+kt?oe(t[t.length-1]?.emotion,s):s}function At(e,t,n,r,s=ze){const i=new OffscreenCanvas(n,r),a=i.getContext("2d",{willReadFrequently:!0});a.drawImage(e,0,0,n,r);const c=a.getImageData(0,0,n,r),l=a.createImageData(n,r);l.data.set(c.data);const m=new OffscreenCanvas(n,r).getContext("2d",{willReadFrequently:!0});for(const _ of t){m.clearRect(0,0,n,r),m.drawImage(_,0,0,n,r);const I=m.getImageData(0,0,n,r);for(let o=0;o<l.data.length;o+=4){const x=I.data[o],w=I.data[o+1],u=I.data[o+2];Math.max(x,w,u)>s&&(l.data[o]=x,l.data[o+1]=w,l.data[o+2]=u,l.data[o+3]=255)}}return a.putImageData(l,0,0),i}let ne=null,_e=null;const Re=new Map;function Xn(){ne=null,_e=null,Re.clear()}en(Xn);function Zn(e){return e??_e??void 0}function Qe(e){return new Promise((t,n)=>{const r=new Image;r.decoding="async",r.onload=()=>t(r),r.onerror=()=>n(new Error(`Failed to load image: ${e}`)),r.src=e})}async function nt(e,t,n,r){const s=n?await An(e,r):await fetch(e).then(d=>{if(!d.ok)throw new Error(`Failed to load ${e}`);return d.json()}),i=s.sheets?.[0];if(!i?.path)throw new Error(`${e} has no sheets[0].path`);const a=n?await vn(await Tt(Fn(t,i.path,n),r??"")):await Qe(`${t}/${i.path}`),c=new Map;for(const d of s.cells??[])d.path&&c.set(d.path,d);const l=new Map;for(const d of s.sheets??[])l.set(d.index,d);return{atlas:a,atlasMeta:s,cellByPath:c,sheetByIndex:l,diffBase:t}}async function qe(e){const t=Zn(e),n=ht();if(n&&!t)throw new Error("Encrypted assets enabled but no key provided");if(ne&&(!n||_e===(t??null))){const i=await ne;return me(i)}_e=t??null,Re.clear();const r=rn();ne=(async()=>{const i=await Qe(tn()),a=await nt(sn(),r,n,t);let c=null;try{c=await nt(on(),r,n,t)}catch{c=null}return{sil:i,viseme:a,expression:c}})();const s=await ne;return me(s)}async function vt(e){if(await qe(e),!ne)throw new Error("Assets not loaded");return ne}function me(e){return Tn(e.viseme.atlasMeta,e.sil.naturalWidth,e.sil.naturalHeight)}function er(e,t){const n=document.createElement("canvas");return n.width=t.w,n.height=t.h,n.getContext("2d",{willReadFrequently:!0}).drawImage(e.atlas,t.x,t.y,t.w,t.h,0,0,t.w,t.h),n}async function rt(e,t,n){const r=`${t.diffBase}::${n}`,s=Re.get(r);if(s)return s;const i=(async()=>{const a=t.cellByPath.get(n);if(!a)throw new Error(`No atlas cell for path: ${n}`);const c=In(t.atlasMeta,a),l=me(e);if(kn(a)){const _=er(t,a),I=document.createElement("canvas");I.width=l.width,I.height=l.height;const o=I.getContext("2d");return o.fillStyle="#000",o.fillRect(0,0,l.width,l.height),o.drawImage(_,c.x,c.y),I}const d=`${t.diffBase}/${n}`,m=await Qe(d);if(m.naturalWidth===l.width&&m.naturalHeight===l.height)return m;throw new Error(`Diff PNG wrong size for ${n}`)})();return Re.set(r,i),i}async function st(e,t,n,r=ze,s,i){if(s){const{width:I,height:o}=s;if(i&&!i()||t.readyState<HTMLMediaElement.HAVE_CURRENT_DATA)return;const x=document.createElement("canvas");x.width=I,x.height=o;const w=x.getContext("2d");if(w.clearRect(0,0,I,o),w.drawImage(t,0,0,I,o),i&&!i())return;(e.width!==I||e.height!==o)&&(e.width=I,e.height=o);const u=e.getContext("2d");u.clearRect(0,0,I,o),u.drawImage(x,0,0);return}const a=await vt(),{width:c,height:l}=me(a);(e.width!==c||e.height!==l)&&(e.width=c,e.height=l);const d=[],m=e.getContext("2d");if(m.clearRect(0,0,c,l),t.readyState<HTMLMediaElement.HAVE_CURRENT_DATA){const I=a.sil;m.drawImage(I,0,0,c,l);return}if(d.length===0){m.drawImage(t,0,0,c,l);return}const _=At(t,d,c,l,r);m.drawImage(_,0,0)}async function We(e,t,n=ze){const r=await vt(_e??void 0),{width:s,height:i}=me(r);(e.width!==s||e.height!==i)&&(e.width=s,e.height=i);const a=[];t.mouthPath&&a.push(await rt(r,r.viseme,t.mouthPath)),t.expressionPath&&r.expression&&a.push(await rt(r,r.expression,t.expressionPath));const c=e.getContext("2d");if(c.clearRect(0,0,s,i),a.length===0){c.drawImage(r.sil,0,0,s,i);return}const l=At(r.sil,a,s,i,n);c.drawImage(l,0,0)}async function tr(e){await We(e,{mouthPath:null,expressionPath:null})}function nr(e){const t=new Map;for(const n of e)t.has(n.vtime)||t.set(n.vtime,n);return[...t.values()].sort((n,r)=>n.vtime-r.vtime)}function rr(e){const t=nr(e),n=[];for(let r=0;r<t.length-1;r++){const s=t[r].viseme,i=t[r+1].viseme,a=t[r].vtime,c=t[r+1].vtime;s===i||c<=a||n.push({from:s,to:i,fromVtime:a,toVtime:c})}return n}function sr(e,t){let n=null;for(const r of e)t>=r.fromVtime&&t<r.toVtime&&(n=r);return n}function ir(e,t){return{gapMs:Math.max(0,t-e),holdEnd:e,transStart:e}}const or=500,ar="__sil__";function cr(){return{lastDrawnKey:""}}function de(e){e.lastDrawnKey=""}function it(e){return e??ar}function ur(e,t){if(e.length===0)return{diffPath:null,label:"sil"};const n=rr(e),r=sr(n,t);if(r){const i=r.toVtime-r.fromVtime,a=ir(r.fromVtime,r.toVtime);if(t>=a.transStart&&t<r.toVtime){const c=Dn(r.from,r.to),l=Cn(c,i);if(l.length>0){const d=Mn(t,a.transStart,r.toVtime,l.length);return{diffPath:l[d]??l[l.length-1],label:`${r.from}→${r.to}`}}return{diffPath:$e(r.to),label:r.to}}}const s=wt(e,t);return s==="sil"?{diffPath:null,label:"sil"}:{diffPath:$e(s),label:s}}function Rt(e,t){const n=t??it(e.expressionPath);return`${it(e.mouthPath)}|${n}`}function lr(e,t,n,r,s,i,a,c){const l=ur(t,n),d={mouthPath:l.diffPath,expressionPath:r},m=Rt(d,s);m!==i.lastDrawnKey&&(c(l.label),a(e,d,m,_=>{_===m&&(i.lastDrawnKey=m)}))}function ot(e,t,n,r,s,i,a=null){const c={mouthPath:null,expressionPath:t},l=a!=null?`|idle@${Math.round(a*1e3)}`:"",d=Rt(c,n)+l;!(a!=null)&&d===r.lastDrawnKey||(i(a!=null?"idle":"sil"),s(e,c,d,_=>{_===d&&(r.lastDrawnKey=d)}))}function bt(e){let t=0,n=null,r=!1,s=!1;const i=async()=>{if(!r){r=!0;try{for(;n;){const c=n;n=null;const l=++t,d=await e(c.diffs,l,c);n||d&&l===t&&c.onDisplayed?.(c.drawKey)}}finally{r=!1,n&&i()}}},a=()=>{s||(s=!0,queueMicrotask(()=>{s=!1,i()}))};return{enqueue(c,l,d){n={diffs:c,drawKey:l,onDisplayed:d},a()},reset(){t+=1,n=null},isLatestSeq(c){return c===t},getLatestSeq(){return t}}}const at=-1,ct=new Map;async function fr(e){let t=ct.get(e);if(!t){const n=await fetch(e);if(!n.ok)throw new Error(`Failed to fetch worker script (${n.status}): ${e}`);const r=await n.blob();t=URL.createObjectURL(r),ct.set(e,t)}return new Worker(t,{name:"visemeDiffPreview"})}function dr(){return typeof Worker<"u"&&typeof OffscreenCanvas<"u"}function hr(e,t){(e.width!==t.width||e.height!==t.height)&&(e.width=t.width,e.height=t.height);const n=e.getContext("2d");n&&n.drawImage(t,0,0)}function ut(e,t){let n=0;const r=bt(async(s,i)=>(await qe(),await We(e,s),r.isLatestSeq(i)));return{usesWorker:!1,async loadAssets(s){return await qe(s)},async renderSilOnly(){n+=1,r.reset(),await tr(e)},drawLiveFrame(s,i,a,c){r.enqueue(i,a,c)},async renderViseme(s,i){n+=1;const a=n;t.onStatus?.(i),await We(s,{mouthPath:$e(i),expressionPath:null})},dispose(){n+=1,r.reset()}}}function _r(e,t,n){let r=null,s=1,i=0,a=!1,c=!1;const l=new Map,d=bt(async(w,u,g)=>(l.set(u,{drawKey:g.drawKey,onDisplayed:g.onDisplayed}),await o({type:"drawFrame",diffPath:w.mouthPath,expressionDiffPath:w.expressionPath,liveSeq:u},void 0,!0),!1)),m=w=>{if(w===at){let E=-1,R;for(const[$,y]of l)$>=E&&(E=$,R=y);E>=0&&l.delete(E),R?.onDisplayed?.(R.drawKey);return}const u=-w,g=l.get(u);l.delete(u),g?.onDisplayed?.(g.drawKey)},_=new Map,I=(w,u)=>{c||!r||r.postMessage(w,[])},o=(w,u,g=!1)=>{if(c)return Promise.resolve();const E=s++;return new Promise((R,$)=>{_.set(E,{resolve:y=>R(y),reject:$,generation:typeof w.generation=="number"?w.generation:void 0,expectRenderDone:g}),I({...w,requestId:E})})},x=(async()=>{r=await fr(n),r.onmessage=w=>{if(c)return;const u=w.data;if(u.type==="status"){t.onStatus?.(u.label);return}if(u.type==="frame"){const E=u.generation<0;if(!E&&u.generation!==i){u.bitmap.close();return}if(E&&!(u.generation===at)){const $=-u.generation;if(!d.isLatestSeq($)){u.bitmap.close();return}}if(E&&t.shouldAcceptLiveFrame&&!t.shouldAcceptLiveFrame()){u.bitmap.close();return}hr(e,u.bitmap),u.bitmap.close(),E&&m(u.generation);return}const g=_.get(u.requestId);if(g)switch(u.type){case"ready":_.delete(u.requestId),g.resolve();break;case"loadAssetsDone":_.delete(u.requestId),g.resolve({width:u.width,height:u.height});break;case"renderDone":if(g.expectRenderDone&&g.generation!=null&&u.generation!==g.generation)return;_.delete(u.requestId),g.resolve();break;case"renderAborted":_.delete(u.requestId),g.resolve();break;case"error":_.delete(u.requestId),t.onError?.(u.message),g.reject(new Error(u.message));break}},r.onerror=w=>{if(c)return;const u=w.message||"Worker error";t.onError?.(u);for(const[,g]of _)g.reject(new Error(u));_.clear()},await o({type:"init"}),a=!0})();return{usesWorker:!0,async loadAssets(w){if(c)return{width:842,height:1264};if(await x,c)return{width:842,height:1264};if(!a)throw new Error("Worker init failed");return await o({type:"loadAssets",keyHex:w,urls:Zt(se())})??{width:842,height:1264}},async renderSilOnly(){if(c||(await x,c))return;i+=1,d.reset(),l.clear();const w=i;await o({type:"renderSil",generation:w},void 0,!0)},drawLiveFrame(w,u,g,E){c||x.then(()=>{c||d.enqueue(u,g,E)})},async renderViseme(w,u,g={}){if(c||(await x,c))return;i+=1;const E=i;try{await o({type:"renderViseme",generation:E,to:u,from:g.from,transitionDurationMs:g.transitionDurationMs,gapMs:g.gapMs,threshold:g.threshold},void 0,!0)}catch(R){if(R?.name==="AbortError")return;throw R}},dispose(){if(!c){c=!0,i+=1,d.reset(),l.clear();for(const[,w]of _)w.resolve();_.clear(),r?.terminate(),r=null}}}}function mr(e,t={}){if(!dr())return ut(e,t);const n=Lt(t.workerScriptUrl);try{return _r(e,t,n)}catch{return ut(e,t)}}class wr extends Error{constructor(t,n){super(`${t} timed out after ${Math.round(n/1e3)}s`),this.name="LoadTimeoutError"}}function Le(e,t,n){return new Promise((r,s)=>{const i=globalThis.setTimeout(()=>{s(new wr(n,t))},t);e.then(a=>{globalThis.clearTimeout(i),r(a)},a=>{globalThis.clearTimeout(i),s(a)})})}const gr={position:"relative",display:"inline-block",lineHeight:0},yr={display:"block",maxWidth:"100%",height:"auto"},pr={position:"absolute",inset:0,display:"flex",alignItems:"center",justifyContent:"center",padding:"1rem",background:"rgba(0,0,0,0.55)",color:"#fff",fontSize:"0.875rem",textAlign:"center"};function ke(e){return Vt(e)?Et:Ge}const Er=p.forwardRef(function({id:t,assets:n,authToken:r,ttsEngineId:s=re,voiceId:i,speakingRate:a=je,className:c,style:l,canvasStyle:d,onStatusChange:m,onDisplayStatus:_,onError:I,onReady:o,showErrorOverlay:x=!0},w){const u=p.useRef(null),g=p.useRef(null),E=p.useRef(cr()),R=p.useRef(Gn()),$=p.useRef(0),y=p.useRef(0),S=p.useRef(null),C=p.useRef(!1),D=p.useRef(null),q=p.useRef(!1),[W,ae]=p.useState("idle"),[ye,X]=p.useState(null),[K,pe]=p.useState(!1),[xe,ce]=p.useState(!1),[ie,Ee]=p.useState({width:842,height:1264}),Z=p.useRef(r??null),ue=p.useRef(null),h=p.useRef(null),M=p.useRef(!1),B=p.useRef({width:842,height:1264}),P=p.useRef(o),k=p.useRef(_),U=p.useRef(I);P.current=o,k.current=_,U.current=I;const Q=p.useCallback(f=>{const T=f?.ttsEngineId??s??h.current?.ttsEngineId??re,A=f?.voiceId??i??h.current?.voiceId??ke(T);return{ttsEngineId:T,voiceId:A}},[s,i]),V=p.useCallback(f=>{X(f),U.current?.(f)},[]),L=p.useCallback(f=>{ae(f),m?.(f)},[m]),F=p.useRef(St(L,Ae)),O=p.useCallback(()=>{S.current!=null&&(clearTimeout(S.current),S.current=null)},[]),J=p.useCallback(async()=>{const f=y.current,T=g.current;!T||!K||F.current.isSpeaking()||(de(E.current),await T.renderSilOnly(),f===y.current&&(F.current.isSpeaking()||(k.current?.("sil"),q.current&&D.current&&(D.current.restart(),D.current.setActive(!0)))))},[K]),H=p.useCallback(()=>{O();const f=y.current;J(),S.current=setTimeout(()=>{S.current=null,f===y.current&&J()},or)},[O,J]),le=p.useCallback(async()=>{const f=Math.floor(Date.now()/1e3);if(ue.current&&f<ue.current.expiresAt-60)return ue.current.key;const T=Z.current??await Ue();Z.current=T,F.current.setDeveloperToken(T);const A=await jt(T,Ae);return ue.current={key:A.value,expiresAt:A.expiresAt},A.value},[]);p.useEffect(()=>{r&&(Z.current=r,F.current.setDeveloperToken(r))},[r]),p.useEffect(()=>{F.current.setTtsEngineId(s),h.current&&(h.current.ttsEngineId=s)},[s]),p.useEffect(()=>{const f=i??ke(s);h.current&&(h.current.voiceId=f)},[i,s]);const fe=p.useMemo(()=>n?JSON.stringify(n):`id:${t??""}`,[n,t]);return p.useEffect(()=>{if(!t&&!n){V("AiTwin requires either `id` or `assets`");return}let f=!1;M.current=!1,pe(!1),ce(!1),X(null),h.current=null,D.current=null,q.current=!1;const T=u.current;if(!T)return;let A=null;return(async()=>{try{let v,b,G;if(n)v=n,b=s,G=i??ke(b);else{k.current?.("getAiTwin");const N=await Le(dt(t),3e4,"getAiTwin");if(f)return;if(!N.faceId?.trim())throw new Error("getAiTwin returned no faceId");b=N.ttsEngineId,G=i??N.voiceId??ke(b),v=Yt(N.faceId)}h.current={ttsEngineId:b,voiceId:G},Xt(v),D.current=jn(nn()),A=mr(T,{onStatus:N=>{f||k.current?.(N)},onError:N=>{f||V(N)},shouldAcceptLiveFrame:()=>F.current.isSpeaking()}),g.current=A,k.current?.("auth");const Y=Z.current??r??await Le(Ue(),3e4,"getAuthToken");if(f)return;Z.current=Y,F.current.setDeveloperToken(Y),F.current.setTtsEngineId(b);const Ce=ht()?await le():void 0;if(f)return;k.current?.("loadAssets");const j=await Le(A.loadAssets(Ce),18e4,"load face assets");if(!f&&j.width>0&&j.height>0&&(B.current=j,Ee(j)),f)return;M.current=!0,pe(!0),P.current?.(),A.renderSilOnly().then(()=>{f||k.current?.("sil")}),(async()=>{try{if(await D.current.load(),f)return;q.current=!0,ce(!0),de(E.current),D.current.setActive(!0);const N=D.current.getVideo();await st(T,N,null,void 0,B.current),f||k.current?.("idle")}catch(N){if(f)return;q.current=!1,ce(!1),console.warn("[AiTwin] Idle video unavailable:",N)}})()}catch(v){if(f)return;if(v instanceof ve){V(v.message);return}V(v instanceof Error?v.message:"Failed to load AI twin")}})(),()=>{f=!0,A?.dispose(),g.current=null}},[fe,n,s,i,r,le,V]),p.useEffect(()=>{W==="done"&&K&&!F.current.isSpeaking()&&H()},[W,K,H]),p.useEffect(()=>{const f=F.current,T={current:!1},A=()=>{const v=u.current,b=g.current;if(!v||!b||!K){$.current=requestAnimationFrame(A);return}const G=f.isSpeaking(),Y=f.getPlaybackElapsedMs(),Ce=G?Yn(Y,f.getSentenceEmotions(),f.getWordQueue(),f.getStreamMood()):f.getStreamMood();if(G){if(q.current&&D.current?.setActive(!1),f.getVisemeQueue().length===0){$.current=requestAnimationFrame(A);return}R.current.setTargetEmotion(Ce),R.current.advance(performance.now());const N=R.current.getExpressionPath(),ee=R.current.getDrawKey();lr(v,f.getVisemeQueue(),Y,N,ee,E.current,(te,Me,Fe,Dt)=>b.drawLiveFrame(te,Me,Fe,Dt),te=>k.current?.(te))}else if(q.current&&D.current){const j=D.current,N=j.getVideo();N.readyState>=HTMLMediaElement.HAVE_CURRENT_DATA?(j.setActive(!0),T.current||(T.current=!0,st(v,N,null,void 0,B.current,()=>!f.isSpeaking()).then(()=>k.current?.("idle")).finally(()=>{T.current=!1}))):ot(v,null,"__sil__",E.current,(ee,te,Me,Fe)=>b.drawLiveFrame(ee,te,Me,Fe),ee=>k.current?.(ee))}else ot(v,null,"__sil__",E.current,(j,N,ee,te)=>b.drawLiveFrame(j,N,ee,te),j=>k.current?.(j));C.current&&!G&&(R.current.reset(),D.current?.setActive(!1),H()),C.current=G,$.current=requestAnimationFrame(A)};return $.current=requestAnimationFrame(A),()=>{cancelAnimationFrame($.current),O(),f.stop()}},[K,xe,H,O]),p.useImperativeHandle(w,()=>({speakText:async(f,T)=>{const A=f.trim();if(!A)return;const v=g.current;if(!v||!M.current&&!K)throw new Error("AI twin is not ready");const{ttsEngineId:b,voiceId:G}=Q(T);X(null),y.current+=1,O(),de(E.current),R.current.reset(),C.current=!1;try{q.current?(D.current?.setActive(!1),D.current?.restart(),de(E.current)):await v.renderSilOnly(),await F.current.speak(A,{voiceId:G,speakingRate:T?.speakingRate??a,ttsEngineId:b})}catch(Y){throw V(Y instanceof Error?Y.message:"TTS failed"),Y}},stop:()=>{y.current+=1,O(),F.current.stop(),de(E.current),C.current=!1,H()},setTtsEngineId:f=>{F.current.setTtsEngineId(f),h.current&&(h.current.ttsEngineId=f)},renderViseme:async(f,T)=>{const A=g.current,v=u.current;if(!A||!v||!M.current)throw new Error("AI twin is not ready");await A.renderViseme(v,f,{from:T?.from,transitionDurationMs:T?.transitionDurationMs,gapMs:T?.gapMs,onStatus:b=>k.current?.(b)})},isReady:()=>M.current,getStatus:()=>W}),[K,a,O,H,V,Q,W]),Oe.jsxs("div",{className:c,style:{...gr,...l},children:[Oe.jsx("canvas",{ref:u,width:ie.width,height:ie.height,style:{...yr,...d},"aria-label":t?`AI twin ${t}`:"AI twin face"}),x&&ye?Oe.jsx("div",{style:pr,children:ye}):null]})});exports.AiTwin=Er;exports.AiTwinNotFoundError=ve;exports.DEFAULT_TTS_ENGINE_ID=Ke;exports.OCULUS_VISEME_IDS=_t;exports.SPEAKING_RATE_MAX=pt;exports.SPEAKING_RATE_MIN=yt;exports.TTS_ENGINE_CARTESIA=ge;exports.TTS_ENGINE_GOOGLE=re;exports.TTS_ENGINE_INWORLD=we;exports.VISEME_IDS=Rn;exports.VISEME_TEST_CARTESIA_VOICE_ID=Et;exports.VISEME_TEST_SPEAKING_RATE=je;exports.VISEME_TEST_VOICE_ID=Ge;exports.createAvatarTtsLipsyncController=St;exports.fetchAiTwin=dt;exports.fetchDevAuthToken=Ue;exports.normalizeOculusViseme=mt;exports.resolveVisemeAtTime=wt;exports.resolveWordAtTime=gt;
3
+ `);H=T.pop()??"";for(const v of T)await fe(v);if(de){H.trim()&&await fe(H.trim()),C||ee();break}}}catch(L){throw console.error("[avatarTtsLipsync]",L),Z(),e("error"),L}},stop:Z,getVisemeQueue:()=>r,getWordQueue:()=>s,getSentenceEmotions:()=>i,getStreamMood:()=>c,getPlaybackElapsedMs:()=>_?k&&d&&w>0?Math.max(0,(d.currentTime-w)*1e3):Math.max(0,(performance.now()-x)*R):0,isSpeaking:()=>_,setPlaybackSpeed:h=>{R=Math.max(.1,Math.min(1,h)),W()},getPlaybackSpeed:()=>R,subscribe:h=>(D.add(h),()=>D.delete(h))}}function Tn(e,t,n){return{width:e.crop?.source_width??t,height:e.crop?.source_height??n}}function kn(e,t){const n=e.crop;return{x:t?.source_x??n?.x??0,y:t?.source_y??n?.y??0,width:t?.source_w??n?.width??e.frame_width??0,height:t?.source_h??n?.height??e.frame_height??0}}function In(e){return e?(e.w??0)>0&&(e.h??0)>0:!1}async function xe(e,t){const n=await fetch(e);if(!n.ok)throw new Error(`Failed to load encrypted asset: ${e}`);const r=await n.arrayBuffer();return Yt(r,t)}async function vn(e,t){if(!t)throw new Error("Missing asset key for encrypted JSON");const n=await xe(e,t),r=new TextDecoder().decode(n);return JSON.parse(r)}async function An(e){const t=new Blob([e],{type:"image/webp"}),n=URL.createObjectURL(t);return new Promise((r,s)=>{const i=new Image;i.decoding="async",i.onload=()=>{URL.revokeObjectURL(n),r(i)},i.onerror=()=>{URL.revokeObjectURL(n),s(new Error("Failed to decode decrypted image"))},i.src=n})}async function Rn(e){const t=new Blob([e],{type:"image/png"}),n=URL.createObjectURL(t);return new Promise((r,s)=>{const i=new Image;i.decoding="async",i.onload=()=>{URL.revokeObjectURL(n),r(i)},i.onerror=()=>{URL.revokeObjectURL(n),s(new Error("Failed to decode decrypted PNG"))},i.src=n})}async function bn(e){const t=nn();if(!je())return t;if(!e)throw new Error("Missing asset key for encrypted idle video");const n=await xe(t,e);return URL.createObjectURL(new Blob([n],{type:"video/mp4"}))}function It(e,t){return`${e}/${t}_minus_sil.png`}const Je=15,Dn=["aa","E","I","O","U","PP","FF","DD","SS","TH","CH","RR","kk","nn"],$e=["t01_0.17","t02_0.33","t03_0.50","t04_0.67","t05_0.83"],xn=$e.length,nt=new Set(["aa__kk","aa__nn","aa__sil","CH__aa","CH__DD","CH__E","CH__FF","CH__I","CH__kk","CH__nn","CH__O","CH__PP","CH__RR","CH__sil","CH__SS","CH__TH","CH__U","DD__aa","DD__E","DD__FF","DD__I","DD__kk","DD__nn","DD__O","DD__PP","DD__RR","DD__sil","DD__SS","DD__TH","DD__U","E__aa","E__FF","E__I","E__kk","E__nn","E__O","E__PP","E__RR","E__sil","E__SS","E__TH","E__U","FF__aa","FF__I","FF__kk","FF__nn","FF__O","FF__PP","FF__RR","FF__sil","FF__SS","FF__TH","FF__U","I__aa","I__kk","I__nn","I__O","I__PP","I__RR","I__sil","I__SS","I__TH","I__U","kk__nn","kk__sil","nn__sil","O__aa","O__kk","O__nn","O__PP","O__RR","O__sil","O__SS","O__TH","O__U","PP__aa","PP__kk","PP__nn","PP__RR","PP__sil","PP__SS","PP__TH","PP__U","RR__aa","RR__kk","RR__nn","RR__sil","RR__SS","RR__TH","RR__U","SS__aa","SS__kk","SS__nn","SS__sil","SS__TH","SS__U","TH__aa","TH__kk","TH__nn","TH__sil","TH__U","U__aa","U__kk","U__nn","U__sil"]);function rt(e,t){return`${e}__${t}`}function st(e,t){return`pairs/${e}/${t}_minus_sil.png`}function He(e){return`${e}_minus_sil.png`}function Cn(e,t){if(e===t)return[];const n=[],r=rt(e,t);if(nt.has(r)){for(const i of $e)n.push(st(r,i));return n}const s=rt(t,e);if(nt.has(s)){for(let i=xn-1;i>=0;i--)n.push(st(s,$e[i]));return n}return[]}function Mn(e){return e<16?[]:e<35?[2]:e<51?[0,4]:e<67?[0,2,4]:e<83?[0,1,2,3]:[0,1,2,3,4]}function Fn(e,t){return Mn(t).map(r=>e[r]).filter(r=>r!=null)}function On(e,t,n,r){if(r<=0)return 0;const i=Math.max(1,n-t)/r,c=e-t,a=Math.floor(c/i);return Math.min(r-1,Math.max(0,a))}function Pn(e,t,n){if(!n)return`${e}/${t}`;const r=t.split("/").pop()??t,s=r.includes(".")?r.slice(0,r.lastIndexOf(".")):r;return`${e}/${s}.bin`}const Ln=[.32,.24,.16,.08,0],Ce=Ln.map(e=>`eyes_${e.toFixed(2)}`),Un=["eyes_0.32","eyes_0.16","eyes_0.00"],Nn=["eyes_0.32","eyes_0.16","eyes_0.08","eyes_0.00"],Bn={fear:"fear",afraid:"fear",anxiety:"fear",anger:"anger",angry:"anger",mad:"anger",sad:"sad",sadness:"sad",sorrow:"sad",neutral:"neutral",calm:"neutral",love:"love",loving:"love",affection:"love",happy:"happy",happiness:"happy",joy:"happy",joyful:"happy",excited:"happy",disgust:"disgust",disgusted:"disgust"};function oe(e,t="neutral"){const n=String(e??"").trim().toLowerCase();return n?Bn[n]??t:t}function z(e){return e==="neutral"?null:It(e,"eyes_standard")}function We(e,t){return!t||t==="eyes_standard"?z(e):e==="neutral"&&t==="eyes_standard"?null:It(e,t)}function Vn(e){if(!e)return"open";const t=e.match(/\/(eyes_[^/]+)_minus_sil\.png$/);if(!t?.[1])return"open";const n=t[1];return Ce.includes(n)?n:"open"}function $n(e){return e==="open"?-1:Ce.indexOf(e)}function Hn(e,t){const n=[];for(const r of t)n.push(We(e,r));for(let r=t.length-2;r>=0;r--)n.push(We(e,t[r]));return n.push(z(e)),n}function Wn(e,t){if(t==="open")return[z(e)];const n=$n(t);if(n<0)return[z(e)];const r=[];for(let s=n;s>=0;s--)r.push(We(e,Ce[s]));return r.push(z(e)),r}const qn=["t01_0.20","t02_0.40","t03_0.60","t04_0.80"];function Kn(e,t){return`${e}__${t}`}function Gn(e,t,n){return`pairs/${Kn(e,t)}/${n}_minus_sil.png`}function jn(e,t){return qn.map(n=>Gn(e,t,n))}function _e(e,t){return e+Math.random()*(t-e)}function ke(){return _e(14,32)}function zn(e={}){const{initialDelayMs:t=800+Math.random()*1200,intervalMinMs:n=2200,intervalMaxMs:r=5800,doubleBlinkChance:s=.18,doubleBlinkGapMinMs:i=120,doubleBlinkGapMaxMs:c=220,fullBlinkChance:a=.75,postEmotionChangeDelayMs:l=380,minDwellMs:d=550}=e;let m="neutral",_="neutral",k=0,o={kind:"idle",nextBlinkAt:performance.now()+t},x=null,w="__eyes_open__|neutral";function u(y,S){x=y,w=`${y??"__eyes_open__"}|${S}`}function g(y,S){o={kind:"idle",nextBlinkAt:y+_e(n,r)},_=S,u(z(S),S)}function E(y,S,C){const D=C?Un:Math.random()<a?Ce:Nn;o={kind:"playing",paths:Hn(S,D),index:0,holdUntil:y+ke(),after:"idle",blinkEmotion:S},_=S,u(o.paths[0]??null,S)}function R(y,S,C){const D=Vn(x),W=[];if(D!=="open"){const q=Wn(S,D);W.push(...q.slice(0,-1))}W.push(...jn(S,C)),W.push(z(C)),o={kind:"emotionBlend",paths:W,index:0,holdUntil:y+ke(),thenEmotion:C},u(W[0]??null,S)}function $(y){if(o.kind==="emotionBlend"){for(;y>=o.holdUntil&&o.index<o.paths.length-1;)o.index+=1,o.holdUntil=y+ke();const S=o.paths[o.index]??null;u(S,o.thenEmotion),y>=o.holdUntil&&o.index>=o.paths.length-1&&(m=o.thenEmotion,_=o.thenEmotion,u(z(o.thenEmotion),o.thenEmotion),o={kind:"idle",nextBlinkAt:y+l});return}if(o.kind==="idle"){u(z(_),_),y>=o.nextBlinkAt&&E(y,_,!1);return}if(o.kind==="doublePause"){u(z(o.blinkEmotion),o.blinkEmotion),y>=o.resumeAt&&E(y,o.blinkEmotion,!0);return}if(o.kind==="playing"){for(;y>=o.holdUntil&&o.index<o.paths.length-1;)o.index+=1,o.holdUntil=y+ke();if(u(o.paths[o.index]??null,o.blinkEmotion),y>=o.holdUntil&&o.index>=o.paths.length-1){if(o.after==="resumeIdle"){g(y+l,m);return}if(o.after==="doublePause"){o={kind:"doublePause",resumeAt:y+_e(i,c),blinkEmotion:o.blinkEmotion},u(z(o.blinkEmotion),o.blinkEmotion);return}if(o.after==="idle"&&Math.random()<s){o={kind:"doublePause",resumeAt:y+_e(i,c),blinkEmotion:o.blinkEmotion},u(z(o.blinkEmotion),o.blinkEmotion);return}g(y,o.blinkEmotion)}}}return{advance:$,setTargetEmotion(y){const S=oe(y,m);if(S===m&&o.kind!=="emotionBlend")return;const C=performance.now();if(d>0&&S!==m&&o.kind!=="emotionBlend"&&!(m==="neutral"&&S!=="neutral")&&C-k<d)return;const D=m;if(m=S,k=C,o.kind==="playing"){R(C,_,S);return}if(o.kind==="emotionBlend"){o={...o,thenEmotion:S};return}R(C,D,S)},getTargetEmotion:()=>m,getExpressionPath:()=>x,getDrawKey:()=>w,reset(){m="neutral",_="neutral",k=0,g(performance.now()+_e(n,r),"neutral")}}}function Qn(){const e=document.createElement("video");e.muted=!0,e.playsInline=!0,e.preload="auto",e.setAttribute("playsinline",""),e.loop=!0;let t=!1,n=null,r="";const s=()=>{n&&(URL.revokeObjectURL(n),n=null)};return{async load(i){t&&r===i||(s(),t=!1,r=i,i.startsWith("blob:")&&(n=i),await new Promise((c,a)=>{const l=()=>{const d=e.duration;if(!Number.isFinite(d)||d<=0){a(new Error(`Idle video has invalid duration: ${i}`));return}t=!0,e.currentTime=0,c()};e.addEventListener("loadeddata",l,{once:!0}),e.addEventListener("error",()=>a(new Error(`Failed to load idle video: ${i}`)),{once:!0}),e.src=i,e.load()}))},isReady(){return t},getVideo(){return e},setActive(i){t&&(i?e.paused&&e.play().catch(()=>{}):e.paused||e.pause())},restart(){t&&(e.currentTime=0)},dispose(){e.pause(),e.removeAttribute("src"),e.load(),s(),t=!1,r=""}}}const Jn=50,vt=400;function Yn(e,t,n){return e.filter(r=>{const s=r.queueIndex??-1;return s>=t&&s<=n})}function Xn(e,t){const n=[];for(const r of e){const s=Yn(t,r.start_word,r.end_word);if(s.length===0)continue;const i=s[0],c=s[s.length-1];n.push({sentence:r,startMs:Math.max(0,i.wtime-Jn),endMs:c.wtime+c.wduration+vt})}return n.sort((r,s)=>r.startMs-s.startMs)}function Zn(e,t,n,r="neutral"){const s=oe(r);if(t.length===0)return s;if(n.length===0||e<n[0].wtime)return oe(t[0]?.emotion,s);const i=Xn(t,n);let c=null;for(const d of i)e>=d.startMs&&e<=d.endMs&&(c=d);if(c)return oe(c.sentence.emotion,s);const a=n[n.length-1],l=a.wtime+a.wduration;return e>l+vt?oe(t[t.length-1]?.emotion,s):s}function At(e,t,n,r,s=Je){const i=new OffscreenCanvas(n,r),c=i.getContext("2d",{willReadFrequently:!0});c.drawImage(e,0,0,n,r);const a=c.getImageData(0,0,n,r),l=c.createImageData(n,r);l.data.set(a.data);const m=new OffscreenCanvas(n,r).getContext("2d",{willReadFrequently:!0});for(const _ of t){m.clearRect(0,0,n,r),m.drawImage(_,0,0,n,r);const k=m.getImageData(0,0,n,r);for(let o=0;o<l.data.length;o+=4){const x=k.data[o],w=k.data[o+1],u=k.data[o+2];Math.max(x,w,u)>s&&(l.data[o]=x,l.data[o+1]=w,l.data[o+2]=u,l.data[o+3]=255)}}return c.putImageData(l,0,0),i}let ne=null,me=null;const Re=new Map;function er(){ne=null,me=null,Re.clear()}tn(er);function tr(e){return e??me??void 0}function Ye(e){return new Promise((t,n)=>{const r=new Image;r.decoding="async",r.onload=()=>t(r),r.onerror=()=>n(new Error(`Failed to load image: ${e}`)),r.src=e})}async function it(e,t,n,r){const s=n?await vn(e,r):await fetch(e).then(d=>{if(!d.ok)throw new Error(`Failed to load ${e}`);return d.json()}),i=s.sheets?.[0];if(!i?.path)throw new Error(`${e} has no sheets[0].path`);const c=n?await An(await xe(Pn(t,i.path,n),r??"")):await Ye(`${t}/${i.path}`),a=new Map;for(const d of s.cells??[])d.path&&a.set(d.path,d);const l=new Map;for(const d of s.sheets??[])l.set(d.index,d);return{atlas:c,atlasMeta:s,cellByPath:a,sheetByIndex:l,diffBase:t}}async function qe(e){const t=tr(e),n=je();if(n&&!t)throw new Error("Encrypted assets enabled but no key provided");if(ne&&(!n||me===(t??null))){const i=await ne;return we(i)}me=t??null,Re.clear();const r=rn();ne=(async()=>{const i=n?await Rn(await xe(Ze(),t??"")):await Ye(Ze()),c=await it(sn(),r,n,t);let a=null;try{a=await it(on(),r,n,t)}catch{a=null}return{sil:i,viseme:c,expression:a}})();const s=await ne;return we(s)}async function Rt(e){if(await qe(e),!ne)throw new Error("Assets not loaded");return ne}function we(e){return Tn(e.viseme.atlasMeta,e.sil.naturalWidth,e.sil.naturalHeight)}function nr(e,t){const n=document.createElement("canvas");return n.width=t.w,n.height=t.h,n.getContext("2d",{willReadFrequently:!0}).drawImage(e.atlas,t.x,t.y,t.w,t.h,0,0,t.w,t.h),n}async function ot(e,t,n){const r=`${t.diffBase}::${n}`,s=Re.get(r);if(s)return s;const i=(async()=>{const c=t.cellByPath.get(n);if(!c)throw new Error(`No atlas cell for path: ${n}`);const a=kn(t.atlasMeta,c),l=we(e);if(In(c)){const _=nr(t,c),k=document.createElement("canvas");k.width=l.width,k.height=l.height;const o=k.getContext("2d");return o.fillStyle="#000",o.fillRect(0,0,l.width,l.height),o.drawImage(_,a.x,a.y),k}const d=`${t.diffBase}/${n}`,m=await Ye(d);if(m.naturalWidth===l.width&&m.naturalHeight===l.height)return m;throw new Error(`Diff PNG wrong size for ${n}`)})();return Re.set(r,i),i}async function at(e,t,n,r=Je,s,i){if(s){const{width:k,height:o}=s;if(i&&!i()||t.readyState<HTMLMediaElement.HAVE_CURRENT_DATA)return;const x=document.createElement("canvas");x.width=k,x.height=o;const w=x.getContext("2d");if(w.clearRect(0,0,k,o),w.drawImage(t,0,0,k,o),i&&!i())return;(e.width!==k||e.height!==o)&&(e.width=k,e.height=o);const u=e.getContext("2d");u.clearRect(0,0,k,o),u.drawImage(x,0,0);return}const c=await Rt(),{width:a,height:l}=we(c);(e.width!==a||e.height!==l)&&(e.width=a,e.height=l);const d=[],m=e.getContext("2d");if(m.clearRect(0,0,a,l),t.readyState<HTMLMediaElement.HAVE_CURRENT_DATA){const k=c.sil;m.drawImage(k,0,0,a,l);return}if(d.length===0){m.drawImage(t,0,0,a,l);return}const _=At(t,d,a,l,r);m.drawImage(_,0,0)}async function Ke(e,t,n=Je){const r=await Rt(me??void 0),{width:s,height:i}=we(r);(e.width!==s||e.height!==i)&&(e.width=s,e.height=i);const c=[];t.mouthPath&&c.push(await ot(r,r.viseme,t.mouthPath)),t.expressionPath&&r.expression&&c.push(await ot(r,r.expression,t.expressionPath));const a=e.getContext("2d");if(a.clearRect(0,0,s,i),c.length===0){a.drawImage(r.sil,0,0,s,i);return}const l=At(r.sil,c,s,i,n);a.drawImage(l,0,0)}async function rr(e){await Ke(e,{mouthPath:null,expressionPath:null})}function sr(e){const t=new Map;for(const n of e)t.has(n.vtime)||t.set(n.vtime,n);return[...t.values()].sort((n,r)=>n.vtime-r.vtime)}function ir(e){const t=sr(e),n=[];for(let r=0;r<t.length-1;r++){const s=t[r].viseme,i=t[r+1].viseme,c=t[r].vtime,a=t[r+1].vtime;s===i||a<=c||n.push({from:s,to:i,fromVtime:c,toVtime:a})}return n}function or(e,t){let n=null;for(const r of e)t>=r.fromVtime&&t<r.toVtime&&(n=r);return n}function ar(e,t){return{gapMs:Math.max(0,t-e),holdEnd:e,transStart:e}}const cr=500,ur="__sil__";function lr(){return{lastDrawnKey:""}}function he(e){e.lastDrawnKey=""}function ct(e){return e??ur}function fr(e,t){if(e.length===0)return{diffPath:null,label:"sil"};const n=ir(e),r=or(n,t);if(r){const i=r.toVtime-r.fromVtime,c=ar(r.fromVtime,r.toVtime);if(t>=c.transStart&&t<r.toVtime){const a=Cn(r.from,r.to),l=Fn(a,i);if(l.length>0){const d=On(t,c.transStart,r.toVtime,l.length);return{diffPath:l[d]??l[l.length-1],label:`${r.from}→${r.to}`}}return{diffPath:He(r.to),label:r.to}}}const s=yt(e,t);return s==="sil"?{diffPath:null,label:"sil"}:{diffPath:He(s),label:s}}function bt(e,t){const n=t??ct(e.expressionPath);return`${ct(e.mouthPath)}|${n}`}function dr(e,t,n,r,s,i,c,a){const l=fr(t,n),d={mouthPath:l.diffPath,expressionPath:r},m=bt(d,s);m!==i.lastDrawnKey&&(a(l.label),c(e,d,m,_=>{_===m&&(i.lastDrawnKey=m)}))}function ut(e,t,n,r,s,i,c=null){const a={mouthPath:null,expressionPath:t},l=c!=null?`|idle@${Math.round(c*1e3)}`:"",d=bt(a,n)+l;!(c!=null)&&d===r.lastDrawnKey||(i(c!=null?"idle":"sil"),s(e,a,d,_=>{_===d&&(r.lastDrawnKey=d)}))}function Dt(e){let t=0,n=null,r=!1,s=!1;const i=async()=>{if(!r){r=!0;try{for(;n;){const a=n;n=null;const l=++t,d=await e(a.diffs,l,a);n||d&&l===t&&a.onDisplayed?.(a.drawKey)}}finally{r=!1,n&&i()}}},c=()=>{s||(s=!0,queueMicrotask(()=>{s=!1,i()}))};return{enqueue(a,l,d){n={diffs:a,drawKey:l,onDisplayed:d},c()},reset(){t+=1,n=null},isLatestSeq(a){return a===t},getLatestSeq(){return t}}}const lt=-1,ft=new Map;async function hr(e){let t=ft.get(e);if(!t){const n=await fetch(e);if(!n.ok)throw new Error(`Failed to fetch worker script (${n.status}): ${e}`);const r=await n.blob();t=URL.createObjectURL(r),ft.set(e,t)}return new Worker(t,{name:"visemeDiffPreview"})}function _r(){return typeof Worker<"u"&&typeof OffscreenCanvas<"u"}function mr(e,t){(e.width!==t.width||e.height!==t.height)&&(e.width=t.width,e.height=t.height);const n=e.getContext("2d");n&&n.drawImage(t,0,0)}function dt(e,t){let n=0;const r=Dt(async(s,i)=>(await qe(),await Ke(e,s),r.isLatestSeq(i)));return{usesWorker:!1,async loadAssets(s){return await qe(s)},async renderSilOnly(){n+=1,r.reset(),await rr(e)},drawLiveFrame(s,i,c,a){r.enqueue(i,c,a)},async renderViseme(s,i){n+=1;const c=n;t.onStatus?.(i),await Ke(s,{mouthPath:He(i),expressionPath:null})},dispose(){n+=1,r.reset()}}}function wr(e,t,n){let r=null,s=1,i=0,c=!1,a=!1;const l=new Map,d=Dt(async(w,u,g)=>(l.set(u,{drawKey:g.drawKey,onDisplayed:g.onDisplayed}),await o({type:"drawFrame",diffPath:w.mouthPath,expressionDiffPath:w.expressionPath,liveSeq:u},void 0,!0),!1)),m=w=>{if(w===lt){let E=-1,R;for(const[$,y]of l)$>=E&&(E=$,R=y);E>=0&&l.delete(E),R?.onDisplayed?.(R.drawKey);return}const u=-w,g=l.get(u);l.delete(u),g?.onDisplayed?.(g.drawKey)},_=new Map,k=(w,u)=>{a||!r||r.postMessage(w,[])},o=(w,u,g=!1)=>{if(a)return Promise.resolve();const E=s++;return new Promise((R,$)=>{_.set(E,{resolve:y=>R(y),reject:$,generation:typeof w.generation=="number"?w.generation:void 0,expectRenderDone:g}),k({...w,requestId:E})})},x=(async()=>{r=await hr(n),r.onmessage=w=>{if(a)return;const u=w.data;if(u.type==="status"){t.onStatus?.(u.label);return}if(u.type==="frame"){const E=u.generation<0;if(!E&&u.generation!==i){u.bitmap.close();return}if(E&&!(u.generation===lt)){const $=-u.generation;if(!d.isLatestSeq($)){u.bitmap.close();return}}if(E&&t.shouldAcceptLiveFrame&&!t.shouldAcceptLiveFrame()){u.bitmap.close();return}mr(e,u.bitmap),u.bitmap.close(),E&&m(u.generation);return}const g=_.get(u.requestId);if(g)switch(u.type){case"ready":_.delete(u.requestId),g.resolve();break;case"loadAssetsDone":_.delete(u.requestId),g.resolve({width:u.width,height:u.height});break;case"renderDone":if(g.expectRenderDone&&g.generation!=null&&u.generation!==g.generation)return;_.delete(u.requestId),g.resolve();break;case"renderAborted":_.delete(u.requestId),g.resolve();break;case"error":_.delete(u.requestId),t.onError?.(u.message),g.reject(new Error(u.message));break}},r.onerror=w=>{if(a)return;const u=w.message||"Worker error";t.onError?.(u);for(const[,g]of _)g.reject(new Error(u));_.clear()},await o({type:"init"}),c=!0})();return{usesWorker:!0,async loadAssets(w){if(a)return{width:842,height:1264};if(await x,a)return{width:842,height:1264};if(!c)throw new Error("Worker init failed");return await o({type:"loadAssets",keyHex:w,urls:en(se())})??{width:842,height:1264}},async renderSilOnly(){if(a||(await x,a))return;i+=1,d.reset(),l.clear();const w=i;await o({type:"renderSil",generation:w},void 0,!0)},drawLiveFrame(w,u,g,E){a||x.then(()=>{a||d.enqueue(u,g,E)})},async renderViseme(w,u,g={}){if(a||(await x,a))return;i+=1;const E=i;try{await o({type:"renderViseme",generation:E,to:u,from:g.from,transitionDurationMs:g.transitionDurationMs,gapMs:g.gapMs,threshold:g.threshold},void 0,!0)}catch(R){if(R?.name==="AbortError")return;throw R}},dispose(){if(!a){a=!0,i+=1,d.reset(),l.clear();for(const[,w]of _)w.resolve();_.clear(),r?.terminate(),r=null}}}}function gr(e,t={}){if(!_r())return dt(e,t);const n=Ut(t.workerScriptUrl);try{return wr(e,t,n)}catch{return dt(e,t)}}class yr extends Error{constructor(t,n){super(`${t} timed out after ${Math.round(n/1e3)}s`),this.name="LoadTimeoutError"}}function Ue(e,t,n){return new Promise((r,s)=>{const i=globalThis.setTimeout(()=>{s(new yr(n,t))},t);e.then(c=>{globalThis.clearTimeout(i),r(c)},c=>{globalThis.clearTimeout(i),s(c)})})}const pr={position:"relative",display:"inline-block",lineHeight:0},Er={display:"block",maxWidth:"100%",height:"auto"},Sr={position:"absolute",inset:0,display:"flex",alignItems:"center",justifyContent:"center",padding:"1rem",background:"rgba(0,0,0,0.55)",color:"#fff",fontSize:"0.875rem",textAlign:"center"};function Ie(e){return $t(e)?Tt:ze}const Tr=p.forwardRef(function({id:t,assets:n,authToken:r,ttsEngineId:s=re,voiceId:i,speakingRate:c=Qe,className:a,style:l,canvasStyle:d,onStatusChange:m,onDisplayStatus:_,onError:k,onReady:o,showErrorOverlay:x=!0},w){const u=p.useRef(null),g=p.useRef(null),E=p.useRef(lr()),R=p.useRef(zn()),$=p.useRef(0),y=p.useRef(0),S=p.useRef(null),C=p.useRef(!1),D=p.useRef(null),W=p.useRef(!1),[q,ce]=p.useState("idle"),[ge,Z]=p.useState(null),[K,ye]=p.useState(!1),[Me,ue]=p.useState(!1),[ie,pe]=p.useState({width:842,height:1264}),ee=p.useRef(r??null),le=p.useRef(null),h=p.useRef(null),M=p.useRef(!1),B=p.useRef({width:842,height:1264}),P=p.useRef(o),I=p.useRef(_),U=p.useRef(k);P.current=o,I.current=_,U.current=k;const Q=p.useCallback(f=>{const T=f?.ttsEngineId??s??h.current?.ttsEngineId??re,v=f?.voiceId??i??h.current?.voiceId??Ie(T);return{ttsEngineId:T,voiceId:v}},[s,i]),V=p.useCallback(f=>{Z(f),U.current?.(f)},[]),L=p.useCallback(f=>{ce(f),m?.(f)},[m]),F=p.useRef(kt(L,ve)),O=p.useCallback(()=>{S.current!=null&&(clearTimeout(S.current),S.current=null)},[]),J=p.useCallback(async()=>{const f=y.current,T=g.current;!T||!K||F.current.isSpeaking()||(he(E.current),await T.renderSilOnly(),f===y.current&&(F.current.isSpeaking()||(I.current?.("sil"),W.current&&D.current&&(D.current.restart(),D.current.setActive(!0)))))},[K]),H=p.useCallback(()=>{O();const f=y.current;J(),S.current=setTimeout(()=>{S.current=null,f===y.current&&J()},cr)},[O,J]),fe=p.useCallback(async()=>{const f=Math.floor(Date.now()/1e3);if(le.current&&f<le.current.expiresAt-60)return le.current.key;const T=ee.current??await Ne();ee.current=T,F.current.setDeveloperToken(T);const v=await zt(T,ve);return le.current={key:v.value,expiresAt:v.expiresAt},v.value},[]);p.useEffect(()=>{r&&(ee.current=r,F.current.setDeveloperToken(r))},[r]),p.useEffect(()=>{F.current.setTtsEngineId(s),h.current&&(h.current.ttsEngineId=s)},[s]),p.useEffect(()=>{const f=i??Ie(s);h.current&&(h.current.voiceId=f)},[i,s]);const de=p.useMemo(()=>n?JSON.stringify(n):`id:${t??""}`,[n,t]);return p.useEffect(()=>{if(!t&&!n){V("AiTwin requires either `id` or `assets`");return}let f=!1;M.current=!1,ye(!1),ue(!1),Z(null),h.current=null,D.current=null,W.current=!1;const T=u.current;if(!T)return;let v=null;return(async()=>{try{let A,b,G;if(n)A=n,b=s,G=i??Ie(b);else{I.current?.("getAiTwin");const N=await Ue(mt(t),3e4,"getAiTwin");if(f)return;if(!N.faceId?.trim())throw new Error("getAiTwin returned no faceId");b=N.ttsEngineId,G=i??N.voiceId??Ie(b),A=Xt(N.faceId)}h.current={ttsEngineId:b,voiceId:G},Zt(A),D.current=Qn(),v=gr(T,{onStatus:N=>{f||I.current?.(N)},onError:N=>{f||V(N)},shouldAcceptLiveFrame:()=>F.current.isSpeaking()}),g.current=v,I.current?.("auth");const Y=ee.current??r??await Ue(Ne(),3e4,"getAuthToken");if(f)return;ee.current=Y,F.current.setDeveloperToken(Y),F.current.setTtsEngineId(b);const Ee=je()?await fe():void 0;if(f)return;I.current?.("loadAssets");const j=await Ue(v.loadAssets(Ee),18e4,"load face assets");if(!f&&j.width>0&&j.height>0&&(B.current=j,pe(j)),f)return;M.current=!0,ye(!0),P.current?.(),v.renderSilOnly().then(()=>{f||I.current?.("sil")}),(async()=>{try{const N=await bn(Ee);if(await D.current.load(N),f)return;W.current=!0,ue(!0),he(E.current),D.current.setActive(!0);const X=D.current.getVideo();await at(T,X,null,void 0,B.current),f||I.current?.("idle")}catch(N){if(f)return;W.current=!1,ue(!1),console.warn("[AiTwin] Idle video unavailable:",N)}})()}catch(A){if(f)return;if(A instanceof Ae){V(A.message);return}V(A instanceof Error?A.message:"Failed to load AI twin")}})(),()=>{f=!0,D.current?.dispose(),v?.dispose(),g.current=null}},[de,n,s,i,r,fe,V]),p.useEffect(()=>{q==="done"&&K&&!F.current.isSpeaking()&&H()},[q,K,H]),p.useEffect(()=>{const f=F.current,T={current:!1},v=()=>{const A=u.current,b=g.current;if(!A||!b||!K){$.current=requestAnimationFrame(v);return}const G=f.isSpeaking(),Y=f.getPlaybackElapsedMs(),Ee=G?Zn(Y,f.getSentenceEmotions(),f.getWordQueue(),f.getStreamMood()):f.getStreamMood();if(G){if(W.current&&D.current?.setActive(!1),f.getVisemeQueue().length===0){$.current=requestAnimationFrame(v);return}R.current.setTargetEmotion(Ee),R.current.advance(performance.now());const N=R.current.getExpressionPath(),X=R.current.getDrawKey();dr(A,f.getVisemeQueue(),Y,N,X,E.current,(te,Fe,Oe,xt)=>b.drawLiveFrame(te,Fe,Oe,xt),te=>I.current?.(te))}else if(W.current&&D.current){const j=D.current,N=j.getVideo();N.readyState>=HTMLMediaElement.HAVE_CURRENT_DATA?(j.setActive(!0),T.current||(T.current=!0,at(A,N,null,void 0,B.current,()=>!f.isSpeaking()).then(()=>I.current?.("idle")).finally(()=>{T.current=!1}))):ut(A,null,"__sil__",E.current,(X,te,Fe,Oe)=>b.drawLiveFrame(X,te,Fe,Oe),X=>I.current?.(X))}else ut(A,null,"__sil__",E.current,(j,N,X,te)=>b.drawLiveFrame(j,N,X,te),j=>I.current?.(j));C.current&&!G&&(R.current.reset(),D.current?.setActive(!1),H()),C.current=G,$.current=requestAnimationFrame(v)};return $.current=requestAnimationFrame(v),()=>{cancelAnimationFrame($.current),O(),f.stop()}},[K,Me,H,O]),p.useImperativeHandle(w,()=>({speakText:async(f,T)=>{const v=f.trim();if(!v)return;const A=g.current;if(!A||!M.current&&!K)throw new Error("AI twin is not ready");const{ttsEngineId:b,voiceId:G}=Q(T);Z(null),y.current+=1,O(),he(E.current),R.current.reset(),C.current=!1;try{W.current?(D.current?.setActive(!1),D.current?.restart(),he(E.current)):await A.renderSilOnly(),await F.current.speak(v,{voiceId:G,speakingRate:T?.speakingRate??c,ttsEngineId:b})}catch(Y){throw V(Y instanceof Error?Y.message:"TTS failed"),Y}},stop:()=>{y.current+=1,O(),F.current.stop(),he(E.current),C.current=!1,H()},setTtsEngineId:f=>{F.current.setTtsEngineId(f),h.current&&(h.current.ttsEngineId=f)},renderViseme:async(f,T)=>{const v=g.current,A=u.current;if(!v||!A||!M.current)throw new Error("AI twin is not ready");await v.renderViseme(A,f,{from:T?.from,transitionDurationMs:T?.transitionDurationMs,gapMs:T?.gapMs,onStatus:b=>I.current?.(b)})},isReady:()=>M.current,getStatus:()=>q}),[K,c,O,H,V,Q,q]),Pe.jsxs("div",{className:a,style:{...pr,...l},children:[Pe.jsx("canvas",{ref:u,width:ie.width,height:ie.height,style:{...Er,...d},"aria-label":t?`AI twin ${t}`:"AI twin face"}),x&&ge?Pe.jsx("div",{style:Sr,children:ge}):null]})});exports.AiTwin=Tr;exports.AiTwinNotFoundError=Ae;exports.DEFAULT_TTS_ENGINE_ID=re;exports.OCULUS_VISEME_IDS=wt;exports.SPEAKING_RATE_MAX=St;exports.SPEAKING_RATE_MIN=Et;exports.TTS_ENGINE_CARTESIA=ae;exports.TTS_ENGINE_GOOGLE=Ge;exports.TTS_ENGINE_INWORLD=be;exports.VISEME_IDS=Dn;exports.VISEME_TEST_CARTESIA_VOICE_ID=Tt;exports.VISEME_TEST_SPEAKING_RATE=Qe;exports.VISEME_TEST_VOICE_ID=ze;exports.createAvatarTtsLipsyncController=kt;exports.fetchAiTwin=mt;exports.fetchDevAuthToken=Ne;exports.normalizeOculusViseme=gt;exports.resolveVisemeAtTime=yt;exports.resolveWordAtTime=pt;