@streamoji/aitwin 0.1.1 → 0.1.2

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/aitwin.cjs CHANGED
@@ -1,3 +1,3 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const De=require("react/jsx-runtime"),_=require("react"),Re="https://ai.streamoji.com",Ve="https://pub-607ad1fc22e2400eb57d17240aab857c.r2.dev/custom-faces",gt="https://us-central1-streamoji-265f4.cloudfunctions.net/getAiTwin";class Ae extends Error{constructor(e="AI twin not found"){super(e),this.name="AiTwinNotFoundError"}}async function tt(t,e=gt){const n=new URL(e);n.searchParams.set("id",t);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");return s.data}const pt="https://us-central1-streamoji-265f4.cloudfunctions.net/getAuthToken",yt="client_6TNvp3SCs4Og0a1ijm9TommXLql1",Et="kk8Fq8EmexzP10jMIEwY3R44M5RKUEm1",St="6TNvp3SCs4Og0a1ijm9TommXLql1",kt="Swaraj Mali";async function Ce(){const t=await fetch(pt,{method:"POST",headers:{"Content-Type":"application/json","Client-Id":yt,"Client-Secret":Et},body:JSON.stringify({userId:St,userName:kt})});if(!t.ok)throw new Error(`getAuthToken failed (${t.status})`);const e=await t.json(),n=e.authToken??e.token??"";if(!n.trim())throw new Error("getAuthToken returned no token");return n}async function vt(t,e=Re){const n=await fetch(`${e.replace(/\/$/,"")}/api/session-value`,{headers:{Authorization:`Bearer ${t}`}});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 At(t){const e=t.trim();if(e.length%2!==0)throw new Error("Invalid hex key");const n=new Uint8Array(e.length/2);for(let r=0;r<e.length;r+=2)n[r/2]=Number.parseInt(e.slice(r,r+2),16);return n}function Ee(t){return Uint8Array.from(t)}function Tt(t,e){const n=new Uint8Array(t.length+e.length);return n.set(t,0),n.set(e,t.length),n}async function It(t,e){if(!e)throw new Error("Asset key is required for encrypted assets");if(t.byteLength<28)throw new Error("Encrypted payload too small");const n=new Uint8Array(t),r=Ee(n.subarray(0,12)),s=Ee(n.subarray(12,28)),a=Ee(n.subarray(28)),i=Ee(Tt(a,s)),c=await crypto.subtle.importKey("raw",At(e),{name:"AES-GCM"},!1,["decrypt"]);return crypto.subtle.decrypt({name:"AES-GCM",iv:r,tagLength:128},c,i)}let Pe=null;const Me=new Set;function Rt(t,e=Ve){const n=`${e.replace(/\/$/,"")}/${t}`;return{twinBase:n,binBase:n,encrypted:!0}}function bt(t){Pe=t;for(const e of Me)e()}function ne(){if(!Pe)throw new Error("Twin assets not configured; call setActiveTwinAssets first");return Pe}function xt(t){return Me.add(t),()=>Me.delete(t)}function Dt(){return`${ne().twinBase}/sil.png`}function Ct(){return`${ne().twinBase}/idle.mp4`}function Pt(){const{encrypted:t,binBase:e,twinBase:n}=ne();return t?e:n}function te(){return ne().encrypted}function nt(){const{binBase:t,twinBase:e,encrypted:n}=ne();return n?`${t}/atlas.bin`:`${e}/atlas.json`}function Mt(){const{binBase:t,twinBase:e,encrypted:n}=ne();return n?`${t}/expression_atlas.bin`:`${e}/expression_atlas.json`}function Ft(t){const e=t.split(/\r?\n/);let n="",r="";for(const a of e)a.startsWith("event:")?n=a.slice(6).trim():a.startsWith("data:")&&(r=a.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 rt=["aa","CH","DD","E","FF","I","O","PP","RR","SS","TH","U","kk","nn","sil"],Ot=new Map(rt.map(t=>[t.toLowerCase(),t]));function st(t){const e=(t??"").trim();return e?Ot.get(e.toLowerCase())??"sil":"sil"}const Ut={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 Lt(t){if(!t)return["sil"];const e=t.toLowerCase();return Ut[e]??["sil"]}function Vt(t,e){const n=t.word.length;if(n<=0)return 0;const r=t.wduration;if(r<=0)return 0;const s=Math.max(0,Math.min(1,(e-t.wtime)/r));return Math.min(n-1,Math.floor(s*n))}function be(t,e){const n=Math.max(0,Math.min(t.length-1,e));return t[n]??""}function Bt(t,e){const n=t.toLowerCase(),r=be(n,e),s=n.slice(Math.max(0,e-1),e+2);return r==="i"||r==="y"?"I":s.includes("ee")||r==="e"||n.includes("ea")?"E":"aa"}function $t(t,e){const n=t.toLowerCase(),r=n.slice(Math.max(0,e-1),Math.min(n.length,e+3));if(/oo|ou|uw/.test(r))return"U";const s=be(n,e);return s==="u"||s==="w"?"U":"O"}function Nt(t,e){const n=t.toLowerCase(),r=n.slice(Math.max(0,e-2),e+1);if(/qu/.test(r))return"U";const s=n.slice(Math.max(0,e-1),Math.min(n.length,e+3));return/wo|wh/.test(s)||be(n,e)==="o"?"O":"U"}const Se={d:"DD",t:"DD",n:"DD",s:"SS",z:"SS",k:"kk",g:"kk",c:"CH",x:"CH",j:"CH"};function Ht(t,e){const n=t.toLowerCase(),r=be(n,e);if(Se[r])return Se[r];for(let s=0;s<n.length;s++){const a=n[s];if(Se[a])return Se[a]}return"DD"}function Wt(t,e,n){const r=Lt(t);if(r.length===1)return r[0];const s=e.trim();if(!s)return r[0];const a=(t??"").toLowerCase(),i=Math.max(0,n);switch(a){case"aei":return Bt(s,i);case"o":return $t(s,i);case"qw":return Nt(s,i);case"cdgknstxyz":return Ht(s,i);default:return r[0]}}function Kt(t){let e=t.trim();const n=e.indexOf(",");e.startsWith("data:")&&n>=0&&(e=e.slice(n+1)),e=e.replace(/\s+/g,"").replace(/-/g,"+").replace(/_/g,"/");const r=e.length%4;return r!==0&&(e+="=".repeat(4-r)),e}const qt=24e3;function jt(t){return t.length>=4&&t[0]===82&&t[1]===73&&t[2]===70&&t[3]===70}function qe(t,e,n=qt){const r=e.byteOffset%2===0?e:e.slice(),s=new Int16Array(r.buffer,r.byteOffset,r.byteLength/2),a=new Float32Array(s.length);for(let c=0;c<s.length;c++)a[c]=s[c]>=32768?-(65536-s[c])/32768:s[c]/32767;const i=t.createBuffer(1,a.length,n);return i.copyToChannel(a,0),i}function zt(t){const e=Kt(t),n=window.atob(e),r=new Uint8Array(n.length);for(let s=0;s<n.length;s++)r[s]=n.charCodeAt(s);return r}async function Gt(t,e){const n=zt(e);if(jt(n)){const r=n.buffer.slice(n.byteOffset,n.byteOffset+n.byteLength);return t.decodeAudioData(r)}if(n.length>=2&&n.length%2===0)return qe(t,n);try{const r=n.buffer.slice(n.byteOffset,n.byteOffset+n.byteLength);return await t.decodeAudioData(r)}catch{return qe(t,n)}}function it(t,e){let n=null;for(const r of t)e<r.vtime||e>=r.vtime+r.vduration||(!n||r.vtime>=n.vtime)&&(n=r);return n?n.viseme:"sil"}function ot(t,e){for(const n of t)if(e>=n.wtime&&e<n.wtime+n.wduration)return n;return null}function je(t){let e=0;for(const n of t)e=Math.max(e,n.vtime+n.vduration);return e}const at=.5,ct=1.5,Be="Olivia",ut="f786b574-daa5-4673-aa0c-cbe3e8534c02",$e=.85;function lt(t,e=Re){const n=`${e.replace(/\/$/,"")}/avatar_ttsWithPoses`,r=[],s=[],a=[];let i="neutral";const c=[],u=[];let p=null,w=!1,o=!1,f=!1,d=!1,S=0,D=0,F=0,Z=0,N=null,h=1,y="",P="google",O="google",M=!1;const K=new Set,re=()=>{for(const m of u)m.playbackRate.value=h},C=()=>K.forEach(m=>m()),H=()=>{N!=null&&(clearTimeout(N),N=null)},se=()=>{for(const m of u)try{m.stop()}catch{}u.length=0},ue=()=>{M=!0,H(),se(),c.length=0,w=!1,o=!1,f=!1,d=!1,r.length=0,s.length=0,a.length=0,i="neutral",F=0,Z=0,D=0,t("idle"),C()},ie=()=>{!d||w||u.length>0||c.length>0||(o=!1,H(),t("done"),C())},le=()=>{const m=je(r);if(m<=0){t("done"),C();return}o=!0,S=performance.now(),t("speaking"),C(),H();const b=h>0?m/h:m;N=setTimeout(()=>{M||(o=!1,N=null,t("done"),C())},b)},z=(m,b,T)=>{m.length!==0&&(T&&(F=b),m.forEach(I=>{const R=String(I.word??"").trim();if(!R)return;const q=Math.round((I.start??0)*1e3),B=Math.round((I.duration??0)*1e3);s.push({word:R,wtime:F+q,wduration:B,queueIndex:s.length})}))},ge=(m,b,T,I)=>{m.length!==0&&(T&&(F=b),m.forEach(x=>{const R=String(x.symbol??"").trim();if(!R)return;const q=Math.round((x.start??0)*1e3),B=Math.max(1,Math.round((x.duration??0)*1e3)),A=F+q;let G;if(I==="google"||I==="cartesia")G=st(R);else{const v=ot(s,A),$=v?Vt(v,A):0;G=Wt(R,v?.word??"",$)}r.push({viseme:G,weight:1,vtime:A,vduration:B})}),C())},fe=(m,b,T,I,x)=>{z(b,T,I),ge(m,T,I,x)},oe=async(m,b,T,I)=>{if(M||!m?.trim()){(b.length>0||T.length>0)&&!f&&fe(b,T,F,I,O);return}if(w){c.push({audio:m,visemes:b,words:T,isNewSegment:I});return}w=!0;try{const x=window.AudioContext||window.webkitAudioContext,R=p??new x;R.state==="suspended"&&await R.resume(),p=R;const q=await Gt(R,m);f=!0;const B=R.currentTime;let A=Z;const G=!o;A<B&&(A=B+.1),Z=A+q.duration;const v=R.createBufferSource();if(v.buffer=q,v.playbackRate.value=h,v.connect(R.destination),u.push(v),M){u.pop();return}if(G){o=!0,t("speaking"),D=A,F=0,r.length=0,s.length=0;const V=(A-B)*1e3;S=performance.now()+V}v.onended=()=>{const V=u.indexOf(v);V>=0&&u.splice(V,1),ie(),C()},v.start(A);const $=(A-D)*1e3;fe(b,T,$,I,O)}catch(x){console.error("[avatarTtsLipsync] audio chunk failed:",x)}finally{w=!1;const x=c.shift();x?await oe(x.audio,x.visemes,x.words,x.isNewSegment):ie()}},pe=()=>{if(d=!0,!f&&r.length>0){le();return}ie()};return{setDeveloperToken:m=>{y=m},setTtsProvider:m=>{P=m},getTtsProvider:()=>P,speak:async(m,b)=>{ue(),M=!1,t("loading");const T=y.trim();if(!T)throw new Error("Developer token required for avatar_ttsWithPoses");const I=b?.tts??P;O=I;const x=b?.voiceId??Be,R=b?.speakingRate??$e,q=Math.max(at,Math.min(ct,R)),B={user_query:m,tts:I,speakingRate:q};(I==="inworld"||I==="cartesia")&&(B.voice_id=x);try{const A=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${T}`},body:JSON.stringify(B)});if(!A.ok)throw new Error(`avatar_ttsWithPoses failed (${A.status})`);const G=A.body;if(!G)throw new Error("No response body");const v=G.getReader(),$=new TextDecoder;let V="";const J=async ae=>{const U=Ft(ae);if(U){if(U.event==="audio"){const l=U.data.chunk,E=U.data.visemes??[],k=U.data.words??[],g=U.data.is_new_segment??!1;if(l)await oe(l,E,k,g);else if(E.length>0||k.length>0){const L=g&&r.length>0?je(r):F;fe(E,k,L,g,I)}}else if(U.event==="metadata"){const l=U.data.mood;typeof l=="string"&&l.trim()&&(i=l.trim());const E=U.data.sentence_emotions;if(Array.isArray(E)){a.length=0;for(const k of E){if(!k||typeof k!="object")continue;const g=k;a.push({sentence_index:Number(g.sentence_index??0),text:String(g.text??""),sentiment:typeof g.sentiment=="string"?g.sentiment:void 0,emotion:String(g.emotion??i),start_word:Number(g.start_word??0),end_word:Number(g.end_word??0)})}}C()}else if(U.event==="error")throw new Error(String(U.data.message??"avatar_ttsWithPoses stream error"))}};for(;;){const{done:ae,value:U}=await v.read();U&&(V+=$.decode(U,{stream:!0}));const l=V.split(`
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const Fe=require("react/jsx-runtime"),m=require("react"),De="https://ai.streamoji.com",We="https://pub-607ad1fc22e2400eb57d17240aab857c.r2.dev/custom-faces",vt="https://us-central1-streamoji-265f4.cloudfunctions.net/getAiTwin",re="eng_a7f2b9c1",ye="eng_d4e8f3a2",pe="eng_c9b1e6d4",Ke=ye,Rt=new Set([ye,pe]),ct={[re]:"oculus_direct",[pe]:"oculus_direct",[ye]:"inworld_word"},Je={google:re,inworld:ye,cartesia:pe};function bt(e){return ct[e]}function Dt(e){return e===pe}function xt(e){if(e.ttsEngineId&&e.ttsEngineId in ct)return e.ttsEngineId;const t=e.tts?.toLowerCase();return t&&t in Je?Je[t]:Ke}class Re extends Error{constructor(t="AI twin not found"){super(t),this.name="AiTwinNotFoundError"}}async function ut(e,t=vt){const n=new URL(t);n.searchParams.set("id",e);const r=await fetch(n.toString());if(r.status===404)throw new Re;if(!r.ok)throw new Error(`getAiTwin failed (${r.status})`);const s=await r.json();if(!s.success)throw new Re(s.error??"AI twin not found");const{tts:a,...o}=s.data;return{...o,ttsEngineId:xt(s.data)}}const Ct="https://us-central1-streamoji-265f4.cloudfunctions.net/getAuthToken",Mt="client_6TNvp3SCs4Og0a1ijm9TommXLql1",Ft="kk8Fq8EmexzP10jMIEwY3R44M5RKUEm1",Pt="6TNvp3SCs4Og0a1ijm9TommXLql1",Ot="Swaraj Mali";async function Oe(){const e=await fetch(Ct,{method:"POST",headers:{"Content-Type":"application/json","Client-Id":Mt,"Client-Secret":Ft},body:JSON.stringify({userId:Pt,userName:Ot})});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 Lt(e,t=De){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 Nt(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 Ie(e){return Uint8Array.from(e)}function Ut(e,t){const n=new Uint8Array(e.length+t.length);return n.set(e,0),n.set(t,e.length),n}async function Vt(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=Ie(n.subarray(0,12)),s=Ie(n.subarray(12,28)),a=Ie(n.subarray(28)),o=Ie(Ut(a,s)),c=await crypto.subtle.importKey("raw",Nt(t),{name:"AES-GCM"},!1,["decrypt"]);return crypto.subtle.decrypt({name:"AES-GCM",iv:r,tagLength:128},c,o)}let Le=null;const Ne=new Set;function Bt(e,t=We){const n=`${t.replace(/\/$/,"")}/${e}`;return{twinBase:n,binBase:n,encrypted:!0}}function $t(e){Le=e;for(const t of Ne)t()}function se(){if(!Le)throw new Error("Twin assets not configured; call setActiveTwinAssets first");return Le}function Ht(e){return Ne.add(e),()=>Ne.delete(e)}function Wt(){return`${se().twinBase}/sil.png`}function Kt(){return`${se().twinBase}/idle.mp4`}function qt(){const{encrypted:e,binBase:t,twinBase:n}=se();return e?t:n}function lt(){return se().encrypted}function Gt(){const{binBase:e,twinBase:t,encrypted:n}=se();return n?`${e}/atlas.bin`:`${t}/atlas.json`}function jt(){const{binBase:e,twinBase:t,encrypted:n}=se();return n?`${e}/expression_atlas.bin`:`${t}/expression_atlas.json`}function zt(e){const t=e.split(/\r?\n/);let n="",r="";for(const a of t)a.startsWith("event:")?n=a.slice(6).trim():a.startsWith("data:")&&(r=a.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 ft=["aa","CH","DD","E","FF","I","O","PP","RR","SS","TH","U","kk","nn","sil"],Qt=new Map(ft.map(e=>[e.toLowerCase(),e]));function dt(e){const t=(e??"").trim();return t?Qt.get(t.toLowerCase())??"sil":"sil"}const Jt={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 Xt(e){if(!e)return["sil"];const t=e.toLowerCase();return Jt[t]??["sil"]}function Yt(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 xe(e,t){const n=Math.max(0,Math.min(e.length-1,t));return e[n]??""}function Zt(e,t){const n=e.toLowerCase(),r=xe(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 en(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=xe(n,t);return s==="u"||s==="w"?"U":"O"}function tn(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)||xe(n,t)==="o"?"O":"U"}const Ae={d:"DD",t:"DD",n:"DD",s:"SS",z:"SS",k:"kk",g:"kk",c:"CH",x:"CH",j:"CH"};function nn(e,t){const n=e.toLowerCase(),r=xe(n,t);if(Ae[r])return Ae[r];for(let s=0;s<n.length;s++){const a=n[s];if(Ae[a])return Ae[a]}return"DD"}function rn(e,t,n){const r=Xt(e);if(r.length===1)return r[0];const s=t.trim();if(!s)return r[0];const a=(e??"").toLowerCase(),o=Math.max(0,n);switch(a){case"aei":return Zt(s,o);case"o":return en(s,o);case"qw":return tn(s,o);case"cdgknstxyz":return nn(s,o);default:return r[0]}}function sn(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 on=24e3;function an(e){return e.length>=4&&e[0]===82&&e[1]===73&&e[2]===70&&e[3]===70}function Xe(e,t,n=on){const r=t.byteOffset%2===0?t:t.slice(),s=new Int16Array(r.buffer,r.byteOffset,r.byteLength/2),a=new Float32Array(s.length);for(let c=0;c<s.length;c++)a[c]=s[c]>=32768?-(65536-s[c])/32768:s[c]/32767;const o=e.createBuffer(1,a.length,n);return o.copyToChannel(a,0),o}function cn(e){const t=sn(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 un(e,t){const n=cn(t);if(an(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 Xe(e,n);try{const r=n.buffer.slice(n.byteOffset,n.byteOffset+n.byteLength);return await e.decodeAudioData(r)}catch{return Xe(e,n)}}function ht(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 _t(e,t){for(const n of e)if(t>=n.wtime&&t<n.wtime+n.wduration)return n;return null}function Ye(e){let t=0;for(const n of e)t=Math.max(t,n.vtime+n.vduration);return t}const mt=.5,wt=1.5,qe="Olivia",gt="f786b574-daa5-4673-aa0c-cbe3e8534c02",Ge=.85;function Et(e,t=De){const n=`${t.replace(/\/$/,"")}/avatar_ttsWithPoses`,r=[],s=[],a=[];let o="neutral";const c=[],f=[];let h=null,_=!1,d=!1,u=!1,i=!1,T=0,R=0,S=0,Q=0,W=null,N=1,K="",g=re,E=re,k=!1;const V=new Set,q=()=>{for(const w of f)w.playbackRate.value=N},I=()=>V.forEach(w=>w()),J=()=>{W!=null&&(clearTimeout(W),W=null)},ie=()=>{for(const w of f)try{w.stop()}catch{}f.length=0},le=()=>{k=!0,J(),ie(),c.length=0,_=!1,d=!1,u=!1,i=!1,r.length=0,s.length=0,a.length=0,o="neutral",S=0,Q=0,R=0,e("idle"),I()},oe=()=>{!i||_||f.length>0||c.length>0||(d=!1,J(),e("done"),I())},fe=()=>{const w=Ye(r);if(w<=0){e("done"),I();return}d=!0,T=performance.now(),e("speaking"),I(),J();const C=N>0?w/N:w;W=setTimeout(()=>{k||(d=!1,W=null,e("done"),I())},C)},Y=(w,C,A)=>{w.length!==0&&(A&&(S=C),w.forEach(v=>{const F=String(v.word??"").trim();if(!F)return;const D=Math.round((v.start??0)*1e3),G=Math.round((v.duration??0)*1e3);s.push({word:F,wtime:S+D,wduration:G,queueIndex:s.length})}))},Se=(w,C,A,v)=>{w.length!==0&&(A&&(S=C),w.forEach(b=>{const F=String(b.symbol??"").trim();if(!F)return;const D=Math.round((b.start??0)*1e3),G=Math.max(1,Math.round((b.duration??0)*1e3)),M=S+D;let B;if(bt(v)==="oculus_direct")B=dt(F);else{const $=_t(s,M),P=$?Yt($,M):0;B=rn(F,$?.word??"",P)}r.push({viseme:B,weight:1,vtime:M,vduration:G})}),I())},de=(w,C,A,v,b)=>{Y(C,A,v),Se(w,A,v,b)},ae=async(w,C,A,v)=>{if(k||!w?.trim()){(C.length>0||A.length>0)&&!u&&de(C,A,S,v,E);return}if(_){c.push({audio:w,visemes:C,words:A,isNewSegment:v});return}_=!0;try{const b=window.AudioContext||window.webkitAudioContext,F=h??new b;F.state==="suspended"&&await F.resume(),h=F;const D=await un(F,w);u=!0;const G=F.currentTime;let M=Q;const B=!d;M<G&&(M=G+.1),Q=M+D.duration;const $=F.createBufferSource();if($.buffer=D,$.playbackRate.value=N,$.connect(F.destination),f.push($),k){f.pop();return}if(B){d=!0,e("speaking"),R=M,S=0,r.length=0,s.length=0;const L=(M-G)*1e3;T=performance.now()+L}$.onended=()=>{const L=f.indexOf($);L>=0&&f.splice(L,1),oe(),I()},$.start(M);const P=(M-R)*1e3;de(C,A,P,v,E)}catch(b){console.error("[avatarTtsLipsync] audio chunk failed:",b)}finally{_=!1;const b=c.shift();b?await ae(b.audio,b.visemes,b.words,b.isNewSegment):oe()}},Te=()=>{if(i=!0,!u&&r.length>0){fe();return}oe()};return{setDeveloperToken:w=>{K=w},setTtsEngineId:w=>{g=w},getTtsEngineId:()=>g,speak:async(w,C)=>{le(),k=!1,e("loading");const A=K.trim();if(!A)throw new Error("Developer token required for avatar_ttsWithPoses");const v=C?.ttsEngineId??g??Ke;E=v;const b=C?.voiceId??qe,F=C?.speakingRate??Ge,D=Math.max(mt,Math.min(wt,F)),G={user_query:w,ttsEngineId:v,speakingRate:D};Rt.has(v)&&(G.voice_id=b);try{const M=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${A}`},body:JSON.stringify(G)});if(!M.ok)throw new Error(`avatar_ttsWithPoses failed (${M.status})`);const B=M.body;if(!B)throw new Error("No response body");const $=B.getReader(),P=new TextDecoder;let L="";const ce=async Z=>{const U=zt(Z);if(U){if(U.event==="audio"){const X=U.data.chunk,l=U.data.visemes??[],p=U.data.words??[],y=U.data.is_new_segment??!1;if(X)await ae(X,l,p,y);else if(l.length>0||p.length>0){const x=y&&r.length>0?Ye(r):S;de(l,p,x,y,v)}}else if(U.event==="metadata"){const X=U.data.mood;typeof X=="string"&&X.trim()&&(o=X.trim());const l=U.data.sentence_emotions;if(Array.isArray(l)){a.length=0;for(const p of l){if(!p||typeof p!="object")continue;const y=p;a.push({sentence_index:Number(y.sentence_index??0),text:String(y.text??""),sentiment:typeof y.sentiment=="string"?y.sentiment:void 0,emotion:String(y.emotion??o),start_word:Number(y.start_word??0),end_word:Number(y.end_word??0)})}}I()}else if(U.event==="error")throw new Error(String(U.data.message??"avatar_ttsWithPoses stream error"))}};for(;;){const{done:Z,value:U}=await $.read();U&&(L+=P.decode(U,{stream:!0}));const X=L.split(`
2
2
 
3
- `);V=l.pop()??"";for(const E of l)await J(E);if(ae){V.trim()&&await J(V.trim()),M||pe();break}}}catch(A){throw console.error("[avatarTtsLipsync]",A),ue(),t("error"),A}},stop:ue,getVisemeQueue:()=>r,getWordQueue:()=>s,getSentenceEmotions:()=>a,getStreamMood:()=>i,getPlaybackElapsedMs:()=>o?f&&p&&D>0?Math.max(0,(p.currentTime-D)*1e3):Math.max(0,(performance.now()-S)*h):0,isSpeaking:()=>o,setPlaybackSpeed:m=>{h=Math.max(.1,Math.min(1,m)),re()},getPlaybackSpeed:()=>h,subscribe:m=>(K.add(m),()=>K.delete(m))}}function Qt(t,e,n){return{width:t.crop?.source_width??e,height:t.crop?.source_height??n}}function Jt(t,e){const n=t.crop;return{x:e?.source_x??n?.x??0,y:e?.source_y??n?.y??0,width:e?.source_w??n?.width??t.frame_width??0,height:e?.source_h??n?.height??t.frame_height??0}}function Xt(t){return t?(t.w??0)>0&&(t.h??0)>0:!1}async function ft(t,e){const n=await fetch(t);if(!n.ok)throw new Error(`Failed to load encrypted asset: ${t}`);const r=await n.arrayBuffer();return It(r,e)}async function dt(t,e){if(!e)throw new Error("Missing asset key for encrypted JSON");const n=await ft(t,e),r=new TextDecoder().decode(n);return JSON.parse(r)}async function Yt(t){const e=new Blob([t],{type:"image/webp"}),n=URL.createObjectURL(e);return new Promise((r,s)=>{const a=new Image;a.decoding="async",a.onload=()=>{URL.revokeObjectURL(n),r(a)},a.onerror=()=>{URL.revokeObjectURL(n),s(new Error("Failed to decode decrypted image"))},a.src=n})}function ht(t,e){return`${t}/${e}_minus_sil.png`}const Ne=15,Zt=["aa","E","I","O","U","PP","FF","DD","SS","TH","CH","RR","kk","nn"],Fe=["t01_0.17","t02_0.33","t03_0.50","t04_0.67","t05_0.83"],en=Fe.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 Ge(t,e){return`${t}__${e}`}function Qe(t,e){return`pairs/${t}/${e}_minus_sil.png`}function Oe(t){return`${t}_minus_sil.png`}function tn(t,e){if(t===e)return[];const n=[],r=Ge(t,e);if(ze.has(r)){for(const a of Fe)n.push(Qe(r,a));return n}const s=Ge(e,t);if(ze.has(s)){for(let a=en-1;a>=0;a--)n.push(Qe(s,Fe[a]));return n}return[]}function nn(t){return t<16?[]:t<35?[2]:t<51?[0,4]:t<67?[0,2,4]:t<83?[0,1,2,3]:[0,1,2,3,4]}function rn(t,e){return nn(e).map(r=>t[r]).filter(r=>r!=null)}function sn(t,e,n,r){if(r<=0)return 0;const a=Math.max(1,n-e)/r,i=t-e,c=Math.floor(i/a);return Math.min(r-1,Math.max(0,c))}function on(t,e){if(!te())return`${t}/${e}`;const n=e.split("/").pop()??e,r=n.includes(".")?n.slice(0,n.lastIndexOf(".")):n;return`${t}/${r}.bin`}async function an(t){const e=nt(),n=te()?await dt(e,t):await fetch(e).then(r=>{if(!r.ok)throw new Error(`Failed to load ${e}`);return r.json()});return{width:n.crop?.source_width??n.frame_width??842,height:n.crop?.source_height??n.frame_height??1264}}const cn=[.32,.24,.16,.08,0],xe=cn.map(t=>`eyes_${t.toFixed(2)}`),un=["eyes_0.32","eyes_0.16","eyes_0.00"],ln=["eyes_0.32","eyes_0.16","eyes_0.08","eyes_0.00"],fn={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 ee(t,e="neutral"){const n=String(t??"").trim().toLowerCase();return n?fn[n]??e:e}function W(t){return t==="neutral"?null:ht(t,"eyes_standard")}function Ue(t,e){return!e||e==="eyes_standard"?W(t):t==="neutral"&&e==="eyes_standard"?null:ht(t,e)}function dn(t){if(!t)return"open";const e=t.match(/\/(eyes_[^/]+)_minus_sil\.png$/);if(!e?.[1])return"open";const n=e[1];return xe.includes(n)?n:"open"}function hn(t){return t==="open"?-1:xe.indexOf(t)}function _n(t,e){const n=[];for(const r of e)n.push(Ue(t,r));for(let r=e.length-2;r>=0;r--)n.push(Ue(t,e[r]));return n.push(W(t)),n}function mn(t,e){if(e==="open")return[W(t)];const n=hn(e);if(n<0)return[W(t)];const r=[];for(let s=n;s>=0;s--)r.push(Ue(t,xe[s]));return r.push(W(t)),r}const wn=["t01_0.20","t02_0.40","t03_0.60","t04_0.80"];function gn(t,e){return`${t}__${e}`}function pn(t,e,n){return`pairs/${gn(t,e)}/${n}_minus_sil.png`}function yn(t,e){return wn.map(n=>pn(t,e,n))}function _e(t,e){return t+Math.random()*(e-t)}function ke(){return _e(14,32)}function En(t={}){const{initialDelayMs:e=800+Math.random()*1200,intervalMinMs:n=2200,intervalMaxMs:r=5800,doubleBlinkChance:s=.18,doubleBlinkGapMinMs:a=120,doubleBlinkGapMaxMs:i=220,fullBlinkChance:c=.75,postEmotionChangeDelayMs:u=380}=t;let p="neutral",w="neutral",o={kind:"idle",nextBlinkAt:performance.now()+e},f=null,d="__eyes_open__|neutral";function S(h,y){f=h,d=`${h??"__eyes_open__"}|${y}`}function D(h,y){o={kind:"idle",nextBlinkAt:h+_e(n,r)},w=y,S(W(y),y)}function F(h,y,P){const O=P?un:Math.random()<c?xe:ln;o={kind:"playing",paths:_n(y,O),index:0,holdUntil:h+ke(),after:"idle",blinkEmotion:y},w=y,S(o.paths[0]??null,y)}function Z(h,y,P){const O=dn(f),M=[];if(O!=="open"){const K=mn(y,O);M.push(...K.slice(0,-1))}M.push(...yn(y,P)),M.push(W(P)),o={kind:"emotionBlend",paths:M,index:0,holdUntil:h+ke(),thenEmotion:P},S(M[0]??null,y)}function N(h){if(o.kind==="emotionBlend"){for(;h>=o.holdUntil&&o.index<o.paths.length-1;)o.index+=1,o.holdUntil=h+ke();const y=o.paths[o.index]??null;S(y,o.thenEmotion),h>=o.holdUntil&&o.index>=o.paths.length-1&&(p=o.thenEmotion,w=o.thenEmotion,S(W(o.thenEmotion),o.thenEmotion),o={kind:"idle",nextBlinkAt:h+u});return}if(o.kind==="idle"){S(W(w),w),h>=o.nextBlinkAt&&F(h,w,!1);return}if(o.kind==="doublePause"){S(W(o.blinkEmotion),o.blinkEmotion),h>=o.resumeAt&&F(h,o.blinkEmotion,!0);return}if(o.kind==="playing"){for(;h>=o.holdUntil&&o.index<o.paths.length-1;)o.index+=1,o.holdUntil=h+ke();if(S(o.paths[o.index]??null,o.blinkEmotion),h>=o.holdUntil&&o.index>=o.paths.length-1){if(o.after==="resumeIdle"){D(h+u,p);return}if(o.after==="doublePause"){o={kind:"doublePause",resumeAt:h+_e(a,i),blinkEmotion:o.blinkEmotion},S(W(o.blinkEmotion),o.blinkEmotion);return}if(o.after==="idle"&&Math.random()<s){o={kind:"doublePause",resumeAt:h+_e(a,i),blinkEmotion:o.blinkEmotion},S(W(o.blinkEmotion),o.blinkEmotion);return}D(h,o.blinkEmotion)}}}return{advance:N,setTargetEmotion(h){const y=ee(h,p);if(y===p&&o.kind!=="emotionBlend")return;const P=performance.now(),O=p;if(p=y,o.kind==="playing"){Z(P,w,y);return}if(o.kind==="emotionBlend"){o={...o,thenEmotion:y};return}Z(P,O,y)},getTargetEmotion:()=>p,getExpressionPath:()=>f,getDrawKey:()=>d,reset(){p="neutral",w="neutral",D(performance.now()+_e(n,r),"neutral")}}}function Sn(t){const e=document.createElement("video");e.muted=!0,e.playsInline=!0,e.preload="auto",e.setAttribute("playsinline",""),e.loop=!0;let n=!1;return{async load(){n||await new Promise((r,s)=>{const a=()=>{const i=e.duration;if(!Number.isFinite(i)||i<=0){s(new Error(`Idle video has invalid duration: ${t}`));return}n=!0,e.currentTime=0,r()};e.addEventListener("loadeddata",a,{once:!0}),e.addEventListener("error",()=>s(new Error(`Failed to load idle video: ${t}`)),{once:!0}),e.src=t,e.load()})},isReady(){return n},getVideo(){return e},setActive(r){n&&(r?e.paused&&e.play().catch(()=>{}):e.paused||e.pause())},restart(){n&&(e.currentTime=0)}}}function kn(t,e){for(const n of t)if(e>=n.wtime&&e<n.wtime+n.wduration)return n;return null}function vn(t,e,n,r="neutral"){const s=ee(r);if(e.length===0)return s;if(n.length===0)return ee(e[0]?.emotion,s);const a=kn(n,t);let i;if(a)i=a.queueIndex??n.findIndex(c=>c===a),i<0&&(i=0);else{if(t<n[0].wtime)return ee(e[0]?.emotion,s);i=n[n.length-1].queueIndex??n.length-1}for(const c of e)if(i>=c.start_word&&i<=c.end_word)return ee(c.emotion,s);for(const c of e)if(i<c.start_word)return ee(c.emotion,s);return ee(e[e.length-1]?.emotion,s)}function _t(t,e,n,r,s=Ne){const a=new OffscreenCanvas(n,r),i=a.getContext("2d",{willReadFrequently:!0});i.drawImage(t,0,0,n,r);const c=i.getImageData(0,0,n,r),u=i.createImageData(n,r);u.data.set(c.data);const w=new OffscreenCanvas(n,r).getContext("2d",{willReadFrequently:!0});for(const o of e){w.clearRect(0,0,n,r),w.drawImage(o,0,0,n,r);const f=w.getImageData(0,0,n,r);for(let d=0;d<u.data.length;d+=4){const S=f.data[d],D=f.data[d+1],F=f.data[d+2];Math.max(S,D,F)>s&&(u.data[d]=S,u.data[d+1]=D,u.data[d+2]=F,u.data[d+3]=255)}}return i.putImageData(u,0,0),a}let me=null,we=null;const Te=new Map;function An(){me=null,we=null,Te.clear()}xt(An);function Tn(t){return t??we??void 0}function He(t){return new Promise((e,n)=>{const r=new Image;r.decoding="async",r.onload=()=>e(r),r.onerror=()=>n(new Error(`Failed to load image: ${t}`)),r.src=t})}async function Je(t,e,n){const r=te()?await dt(t,n):await fetch(t).then(u=>{if(!u.ok)throw new Error(`Failed to load ${t}`);return u.json()}),s=r.sheets?.[0];if(!s?.path)throw new Error(`${t} has no sheets[0].path`);const a=te()?await Yt(await ft(on(e,s.path),n??"")):await He(`${e}/${s.path}`),i=new Map;for(const u of r.cells??[])u.path&&i.set(u.path,u);const c=new Map;for(const u of r.sheets??[])c.set(u.index,u);return{atlas:a,atlasMeta:r,cellByPath:i,sheetByIndex:c,diffBase:e}}async function Ie(t){const e=Tn(t);if(te()&&!e)throw new Error("Encrypted assets enabled but no key provided");if(me&&(!te()||we===(e??null)))return me;we=e??null,Te.clear();const n=Pt();return me=(async()=>{const r=await He(Dt()),s=await Je(nt(),n,e);let a=null;try{a=await Je(Mt(),n,e)}catch{a=null}return{sil:r,viseme:s,expression:a}})(),me}function We(t){return Qt(t.viseme.atlasMeta,t.sil.naturalWidth,t.sil.naturalHeight)}function In(t,e){const n=document.createElement("canvas");return n.width=e.w,n.height=e.h,n.getContext("2d",{willReadFrequently:!0}).drawImage(t.atlas,e.x,e.y,e.w,e.h,0,0,e.w,e.h),n}async function Xe(t,e,n){const r=`${e.diffBase}::${n}`,s=Te.get(r);if(s)return s;const a=(async()=>{const i=e.cellByPath.get(n);if(!i)throw new Error(`No atlas cell for path: ${n}`);const c=Jt(e.atlasMeta,i),u=We(t);if(Xt(i)){const o=In(e,i),f=document.createElement("canvas");f.width=u.width,f.height=u.height;const d=f.getContext("2d");return d.fillStyle="#000",d.fillRect(0,0,u.width,u.height),d.drawImage(o,c.x,c.y),f}const p=`${e.diffBase}/${n}`,w=await He(p);if(w.naturalWidth===u.width&&w.naturalHeight===u.height)return w;throw new Error(`Diff PNG wrong size for ${n}`)})();return Te.set(r,a),a}async function Ye(t,e,n,r=Ne){const s=await Ie(),{width:a,height:i}=We(s);(t.width!==a||t.height!==i)&&(t.width=a,t.height=i);const c=[],u=t.getContext("2d");if(u.clearRect(0,0,a,i),e.readyState<HTMLMediaElement.HAVE_CURRENT_DATA){const w=s.sil;u.drawImage(w,0,0,a,i);return}if(c.length===0){u.drawImage(e,0,0,a,i);return}const p=_t(e,c,a,i,r);u.drawImage(p,0,0)}async function Le(t,e,n=Ne){const r=await Ie(we??void 0),{width:s,height:a}=We(r);(t.width!==s||t.height!==a)&&(t.width=s,t.height=a);const i=[];e.mouthPath&&i.push(await Xe(r,r.viseme,e.mouthPath)),e.expressionPath&&r.expression&&i.push(await Xe(r,r.expression,e.expressionPath));const c=t.getContext("2d");if(c.clearRect(0,0,s,a),i.length===0){c.drawImage(r.sil,0,0,s,a);return}const u=_t(r.sil,i,s,a,n);c.drawImage(u,0,0)}async function Rn(t){await Le(t,{mouthPath:null,expressionPath:null})}function bn(t){const e=new Map;for(const n of t)e.has(n.vtime)||e.set(n.vtime,n);return[...e.values()].sort((n,r)=>n.vtime-r.vtime)}function xn(t){const e=bn(t),n=[];for(let r=0;r<e.length-1;r++){const s=e[r].viseme,a=e[r+1].viseme,i=e[r].vtime,c=e[r+1].vtime;s===a||c<=i||n.push({from:s,to:a,fromVtime:i,toVtime:c})}return n}function Dn(t,e){let n=null;for(const r of t)e>=r.fromVtime&&e<r.toVtime&&(n=r);return n}function Cn(t,e){return{gapMs:Math.max(0,e-t),holdEnd:t,transStart:t}}const Pn=500,Mn="__sil__";function Fn(){return{lastDrawnKey:""}}function he(t){t.lastDrawnKey=""}function Ze(t){return t??Mn}function On(t,e){if(t.length===0)return{diffPath:null,label:"sil"};const n=xn(t),r=Dn(n,e);if(r){const a=r.toVtime-r.fromVtime,i=Cn(r.fromVtime,r.toVtime);if(e>=i.transStart&&e<r.toVtime){const c=tn(r.from,r.to),u=rn(c,a);if(u.length>0){const p=sn(e,i.transStart,r.toVtime,u.length);return{diffPath:u[p]??u[u.length-1],label:`${r.from}→${r.to}`}}return{diffPath:Oe(r.to),label:r.to}}}const s=it(t,e);return s==="sil"?{diffPath:null,label:"sil"}:{diffPath:Oe(s),label:s}}function mt(t,e){const n=e??Ze(t.expressionPath);return`${Ze(t.mouthPath)}|${n}`}function Un(t,e,n,r,s,a,i,c){const u=On(e,n),p={mouthPath:u.diffPath,expressionPath:r},w=mt(p,s);w!==a.lastDrawnKey&&(a.lastDrawnKey=w,c(u.label),i(t,p))}function Ln(t,e,n,r,s,a,i=null){const c={mouthPath:null,expressionPath:e},u=i!=null?`|idle@${Math.round(i*1e3)}`:"",p=mt(c,n)+u;!(i!=null)&&p===r.lastDrawnKey||(r.lastDrawnKey=p,a(i!=null?"idle":"sil"),s(t,c))}function Vn(t){return new Worker("/assets/visemeDiffPreview.worker-B8Juk7ys.js",{name:t?.name})}function Bn(){return typeof Worker<"u"&&typeof OffscreenCanvas<"u"}function $n(t,e){(t.width!==e.width||t.height!==e.height)&&(t.width=e.width,t.height=e.height);const n=t.getContext("2d");n&&n.drawImage(e,0,0)}function et(t,e){let n=0;return{usesWorker:!1,async loadAssets(r){await Ie(r)},async renderSilOnly(){n+=1,await Rn(t)},async drawLiveFrame(r,s){await Ie(),await Le(r,s)},async renderViseme(r,s){n+=1;const a=n;e.onStatus?.(s),await Le(r,{mouthPath:Oe(s),expressionPath:null})},dispose(){n+=1}}}function Nn(t,e){const n=new Vn;let r=1,s=0,a=!1,i=!1;const c=new Map,u=(o,f)=>{i||n.postMessage(o,[])},p=(o,f,d=!1)=>{if(i)return Promise.resolve();const S=r++;return new Promise((D,F)=>{c.set(S,{resolve:()=>D(),reject:F,generation:typeof o.generation=="number"?o.generation:void 0,expectRenderDone:d}),u({...o,requestId:S})})};n.onmessage=o=>{if(i)return;const f=o.data;if(f.type==="status"){e.onStatus?.(f.label);return}if(f.type==="frame"){const S=f.generation<0;if(!S&&f.generation!==s){f.bitmap.close();return}if(S&&e.shouldAcceptLiveFrame&&!e.shouldAcceptLiveFrame()){f.bitmap.close();return}$n(t,f.bitmap),f.bitmap.close();return}const d=c.get(f.requestId);if(d)switch(f.type){case"ready":case"loadAssetsDone":c.delete(f.requestId),d.resolve();break;case"renderDone":if(d.expectRenderDone&&d.generation!=null&&f.generation!==d.generation)return;c.delete(f.requestId),d.resolve();break;case"renderAborted":c.delete(f.requestId),d.resolve();break;case"error":c.delete(f.requestId),e.onError?.(f.message),d.reject(new Error(f.message));break}},n.onerror=o=>{if(i)return;const f=o.message||"Worker error";e.onError?.(f);for(const[,d]of c)d.reject(new Error(f));c.clear()};const w=(async()=>{await p({type:"init"}),a=!0})();return{usesWorker:!0,async loadAssets(o){if(!i&&(await w,!i)){if(!a)throw new Error("Worker init failed");await p({type:"loadAssets",keyHex:o,urls:ne()})}},async renderSilOnly(){if(i||(await w,i))return;s+=1;const o=s;await p({type:"renderSil",generation:o},void 0,!0)},async drawLiveFrame(o,f){i||(await w,!i&&await p({type:"drawFrame",diffPath:f.mouthPath,expressionDiffPath:f.expressionPath},void 0,!0))},async renderViseme(o,f,d={}){if(i||(await w,i))return;s+=1;const S=s;try{await p({type:"renderViseme",generation:S,to:f,from:d.from,transitionDurationMs:d.transitionDurationMs,gapMs:d.gapMs,threshold:d.threshold},void 0,!0)}catch(D){if(D?.name==="AbortError")return;throw D}},dispose(){if(!i){i=!0,s+=1;for(const[,o]of c)o.resolve();c.clear(),n.terminate()}}}}function Hn(t,e={}){if(!Bn())return et(t,e);try{return Nn(t,e)}catch{return et(t,e)}}const Wn={position:"relative",display:"inline-block",lineHeight:0},Kn={display:"block",maxWidth:"100%",height:"auto"},qn={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 ve(t){return t==="cartesia"?ut:Be}const jn=_.forwardRef(function({id:e,assets:n,authToken:r,apiBase:s=Re,facesCdnBase:a=Ve,tts:i="google",voiceId:c,speakingRate:u=$e,className:p,style:w,canvasStyle:o,onStatusChange:f,onDisplayStatus:d,onError:S,onReady:D,showErrorOverlay:F=!0},Z){const N=_.useRef(null),h=_.useRef(null),y=_.useRef(Fn()),P=_.useRef(En()),O=_.useRef(0),M=_.useRef(0),K=_.useRef(null),re=_.useRef(!1),C=_.useRef(null),H=_.useRef(!1),[se,ue]=_.useState("idle"),[ie,le]=_.useState(null),[z,ge]=_.useState(!1),[fe,oe]=_.useState(!1),[pe,Ke]=_.useState({width:842,height:1264}),m=_.useRef(r??null),b=_.useRef(null),T=_.useRef(null),I=_.useRef(!1),x=_.useRef(D),R=_.useRef(d),q=_.useRef(S);x.current=D,R.current=d,q.current=S;const B=_.useCallback(l=>{const E=l?.tts??i??T.current?.tts??"google",k=l?.voiceId??c??T.current?.voiceId??ve(E);return{tts:E,voiceId:k}},[i,c]),A=_.useCallback(l=>{le(l),q.current?.(l)},[]),G=_.useCallback(l=>{ue(l),f?.(l)},[f]),v=_.useRef(lt(G,s)),$=_.useCallback(()=>{K.current!=null&&(clearTimeout(K.current),K.current=null)},[]),V=_.useCallback(async()=>{const l=M.current,E=h.current;!E||!z||v.current.isSpeaking()||(he(y.current),!H.current&&(await E.renderSilOnly(),l!==M.current||v.current.isSpeaking()))},[z]),J=_.useCallback(()=>{$();const l=M.current;V(),K.current=setTimeout(()=>{K.current=null,l===M.current&&V()},Pn)},[$,V]),ae=_.useCallback(async()=>{const l=Math.floor(Date.now()/1e3);if(b.current&&l<b.current.expiresAt-60)return b.current.key;const E=m.current??await Ce();m.current=E,v.current.setDeveloperToken(E);const k=await vt(E,s);return b.current={key:k.value,expiresAt:k.expiresAt},k.value},[s]);_.useEffect(()=>{r&&(m.current=r,v.current.setDeveloperToken(r))},[r]),_.useEffect(()=>{v.current.setTtsProvider(i),T.current&&(T.current.tts=i)},[i]),_.useEffect(()=>{const l=c??ve(i);T.current&&(T.current.voiceId=l)},[c,i]);const U=_.useMemo(()=>n?JSON.stringify(n):`id:${e??""}:${a}`,[n,e,a]);return _.useEffect(()=>{if(!e&&!n){A("AiTwin requires either `id` or `assets`");return}let l=!1;I.current=!1,ge(!1),oe(!1),le(null),T.current=null,C.current=null,H.current=!1;const E=N.current;if(!E)return;const k=Hn(E,{onStatus:g=>{l||R.current?.(g)},onError:g=>{l||A(g)},shouldAcceptLiveFrame:()=>v.current.isSpeaking()});return h.current=k,(async()=>{try{let g,L,Q;if(n)g=n,L=i,Q=c??ve(L);else{const Y=await tt(e);if(l)return;L=Y.tts,Q=c??Y.voiceId??ve(L),g=Rt(Y.faceId,a)}T.current={tts:L,voiceId:Q},bt(g),C.current=Sn(Ct());const X=m.current??r??await Ce();if(l)return;m.current=X,v.current.setDeveloperToken(X),v.current.setTtsProvider(L);const ye=te()?await ae():void 0;if(l)return;const j=await an(ye);if(!l&&j.width>0&&j.height>0&&Ke(j),await k.loadAssets(ye),l)return;let ce=!1;try{await C.current.load(),ce=!0,H.current=!0,oe(!0)}catch(Y){H.current=!1,oe(!1),console.warn("[AiTwin] Idle video unavailable:",Y)}if(!ce)await k.renderSilOnly(),R.current?.("sil");else{he(y.current);const Y=C.current.getVideo();C.current.setActive(!0);try{await Ye(E,Y,null),R.current?.("idle")}catch(de){console.warn("[AiTwin] Initial idle frame paint failed:",de)}}if(l)return;I.current=!0,ge(!0),x.current?.()}catch(g){if(l)return;if(g instanceof Ae){A(g.message);return}A(g instanceof Error?g.message:"Failed to load AI twin")}})(),()=>{l=!0,k.dispose(),h.current=null}},[U,e,a,r,s,ae,A]),_.useEffect(()=>{se==="done"&&z&&!v.current.isSpeaking()&&J()},[se,z,J]),_.useEffect(()=>{const l=v.current,E={current:!1},k=()=>{const g=N.current,L=h.current;if(!g||!L||!z){O.current=requestAnimationFrame(k);return}const Q=l.isSpeaking(),X=l.getPlaybackElapsedMs(),ye=Q?vn(X,l.getSentenceEmotions(),l.getWordQueue(),l.getStreamMood()):l.getStreamMood();if(Q){if(H.current&&C.current?.setActive(!1),l.getVisemeQueue().length===0){O.current=requestAnimationFrame(k);return}P.current.setTargetEmotion(ye),P.current.advance(performance.now());const ce=P.current.getExpressionPath(),Y=P.current.getDrawKey();Un(g,l.getVisemeQueue(),X,ce,Y,y.current,(de,wt)=>L.drawLiveFrame(de,wt),de=>R.current?.(de))}else if(H.current&&C.current){const j=C.current;j.setActive(!0),E.current||(E.current=!0,Ye(g,j.getVideo()).then(()=>R.current?.("idle")).finally(()=>{E.current=!1}))}else Ln(g,null,"__sil__",y.current,(j,ce)=>L.drawLiveFrame(j,ce),j=>R.current?.(j));re.current&&!Q&&(P.current.reset(),H.current&&C.current?.restart(),J()),re.current=Q,O.current=requestAnimationFrame(k)};return O.current=requestAnimationFrame(k),()=>{cancelAnimationFrame(O.current),$(),l.stop()}},[z,fe,J,$]),_.useImperativeHandle(Z,()=>({speakText:async(l,E)=>{const k=l.trim();if(!k)return;const g=h.current;if(!g||!I.current&&!z)throw new Error("AI twin is not ready");const{tts:L,voiceId:Q}=B(E);le(null),M.current+=1,$(),he(y.current),P.current.reset(),re.current=!1;try{H.current?(C.current?.setActive(!1),C.current?.restart(),he(y.current)):await g.renderSilOnly(),await v.current.speak(k,{voiceId:Q,speakingRate:E?.speakingRate??u,tts:L})}catch(X){throw A(X instanceof Error?X.message:"TTS failed"),X}},stop:()=>{M.current+=1,$(),v.current.stop(),he(y.current),re.current=!1,J()},setTtsProvider:l=>{v.current.setTtsProvider(l),T.current&&(T.current.tts=l)},renderViseme:async(l,E)=>{const k=h.current,g=N.current;if(!k||!g||!I.current)throw new Error("AI twin is not ready");await k.renderViseme(g,l,{from:E?.from,transitionDurationMs:E?.transitionDurationMs,gapMs:E?.gapMs,onStatus:L=>R.current?.(L)})},isReady:()=>I.current,getStatus:()=>se}),[z,u,$,J,A,B,se]),De.jsxs("div",{className:p,style:{...Wn,...w},children:[De.jsx("canvas",{ref:N,width:pe.width,height:pe.height,style:{...Kn,...o},"aria-label":e?`AI twin ${e}`:"AI twin face"}),F&&ie?De.jsx("div",{style:qn,children:ie}):null]})});exports.AiTwin=jn;exports.AiTwinNotFoundError=Ae;exports.DEFAULT_API_BASE=Re;exports.DEFAULT_FACES_CDN_BASE=Ve;exports.OCULUS_VISEME_IDS=rt;exports.SPEAKING_RATE_MAX=ct;exports.SPEAKING_RATE_MIN=at;exports.VISEME_IDS=Zt;exports.VISEME_TEST_CARTESIA_VOICE_ID=ut;exports.VISEME_TEST_SPEAKING_RATE=$e;exports.VISEME_TEST_VOICE_ID=Be;exports.createAvatarTtsLipsyncController=lt;exports.fetchAiTwin=tt;exports.fetchDevAuthToken=Ce;exports.normalizeOculusViseme=st;exports.resolveVisemeAtTime=it;exports.resolveWordAtTime=ot;
3
+ `);L=X.pop()??"";for(const l of X)await ce(l);if(Z){L.trim()&&await ce(L.trim()),k||Te();break}}}catch(M){throw console.error("[avatarTtsLipsync]",M),le(),e("error"),M}},stop:le,getVisemeQueue:()=>r,getWordQueue:()=>s,getSentenceEmotions:()=>a,getStreamMood:()=>o,getPlaybackElapsedMs:()=>d?u&&h&&R>0?Math.max(0,(h.currentTime-R)*1e3):Math.max(0,(performance.now()-T)*N):0,isSpeaking:()=>d,setPlaybackSpeed:w=>{N=Math.max(.1,Math.min(1,w)),q()},getPlaybackSpeed:()=>N,subscribe:w=>(V.add(w),()=>V.delete(w))}}function ln(e,t,n){return{width:e.crop?.source_width??t,height:e.crop?.source_height??n}}function fn(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 dn(e){return e?(e.w??0)>0&&(e.h??0)>0:!1}async function yt(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 Vt(r,t)}async function hn(e,t){if(!t)throw new Error("Missing asset key for encrypted JSON");const n=await yt(e,t),r=new TextDecoder().decode(n);return JSON.parse(r)}async function _n(e){const t=new Blob([e],{type:"image/webp"}),n=URL.createObjectURL(t);return new Promise((r,s)=>{const a=new Image;a.decoding="async",a.onload=()=>{URL.revokeObjectURL(n),r(a)},a.onerror=()=>{URL.revokeObjectURL(n),s(new Error("Failed to decode decrypted image"))},a.src=n})}function pt(e,t){return`${e}/${t}_minus_sil.png`}const je=15,mn=["aa","E","I","O","U","PP","FF","DD","SS","TH","CH","RR","kk","nn"],Ue=["t01_0.17","t02_0.33","t03_0.50","t04_0.67","t05_0.83"],wn=Ue.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 Ve(e){return`${e}_minus_sil.png`}function gn(e,t){if(e===t)return[];const n=[],r=et(e,t);if(Ze.has(r)){for(const a of Ue)n.push(tt(r,a));return n}const s=et(t,e);if(Ze.has(s)){for(let a=wn-1;a>=0;a--)n.push(tt(s,Ue[a]));return n}return[]}function En(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 yn(e,t){return En(t).map(r=>e[r]).filter(r=>r!=null)}function pn(e,t,n,r){if(r<=0)return 0;const a=Math.max(1,n-t)/r,o=e-t,c=Math.floor(o/a);return Math.min(r-1,Math.max(0,c))}function Sn(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 Tn=[.32,.24,.16,.08,0],Ce=Tn.map(e=>`eyes_${e.toFixed(2)}`),In=["eyes_0.32","eyes_0.16","eyes_0.00"],An=["eyes_0.32","eyes_0.16","eyes_0.08","eyes_0.00"],kn={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 ue(e,t="neutral"){const n=String(e??"").trim().toLowerCase();return n?kn[n]??t:t}function z(e){return e==="neutral"?null:pt(e,"eyes_standard")}function Be(e,t){return!t||t==="eyes_standard"?z(e):e==="neutral"&&t==="eyes_standard"?null:pt(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 Rn(e){return e==="open"?-1:Ce.indexOf(e)}function bn(e,t){const n=[];for(const r of t)n.push(Be(e,r));for(let r=t.length-2;r>=0;r--)n.push(Be(e,t[r]));return n.push(z(e)),n}function Dn(e,t){if(t==="open")return[z(e)];const n=Rn(t);if(n<0)return[z(e)];const r=[];for(let s=n;s>=0;s--)r.push(Be(e,Ce[s]));return r.push(z(e)),r}const xn=["t01_0.20","t02_0.40","t03_0.60","t04_0.80"];function Cn(e,t){return`${e}__${t}`}function Mn(e,t,n){return`pairs/${Cn(e,t)}/${n}_minus_sil.png`}function Fn(e,t){return xn.map(n=>Mn(e,t,n))}function we(e,t){return e+Math.random()*(t-e)}function ke(){return we(14,32)}function Pn(e={}){const{initialDelayMs:t=800+Math.random()*1200,intervalMinMs:n=2200,intervalMaxMs:r=5800,doubleBlinkChance:s=.18,doubleBlinkGapMinMs:a=120,doubleBlinkGapMaxMs:o=220,fullBlinkChance:c=.75,postEmotionChangeDelayMs:f=380,minDwellMs:h=550}=e;let _="neutral",d="neutral",u=0,i={kind:"idle",nextBlinkAt:performance.now()+t},T=null,R="__eyes_open__|neutral";function S(g,E){T=g,R=`${g??"__eyes_open__"}|${E}`}function Q(g,E){i={kind:"idle",nextBlinkAt:g+we(n,r)},d=E,S(z(E),E)}function W(g,E,k){const V=k?In:Math.random()<c?Ce:An;i={kind:"playing",paths:bn(E,V),index:0,holdUntil:g+ke(),after:"idle",blinkEmotion:E},d=E,S(i.paths[0]??null,E)}function N(g,E,k){const V=vn(T),q=[];if(V!=="open"){const I=Dn(E,V);q.push(...I.slice(0,-1))}q.push(...Fn(E,k)),q.push(z(k)),i={kind:"emotionBlend",paths:q,index:0,holdUntil:g+ke(),thenEmotion:k},S(q[0]??null,E)}function K(g){if(i.kind==="emotionBlend"){for(;g>=i.holdUntil&&i.index<i.paths.length-1;)i.index+=1,i.holdUntil=g+ke();const E=i.paths[i.index]??null;S(E,i.thenEmotion),g>=i.holdUntil&&i.index>=i.paths.length-1&&(_=i.thenEmotion,d=i.thenEmotion,S(z(i.thenEmotion),i.thenEmotion),i={kind:"idle",nextBlinkAt:g+f});return}if(i.kind==="idle"){S(z(d),d),g>=i.nextBlinkAt&&W(g,d,!1);return}if(i.kind==="doublePause"){S(z(i.blinkEmotion),i.blinkEmotion),g>=i.resumeAt&&W(g,i.blinkEmotion,!0);return}if(i.kind==="playing"){for(;g>=i.holdUntil&&i.index<i.paths.length-1;)i.index+=1,i.holdUntil=g+ke();if(S(i.paths[i.index]??null,i.blinkEmotion),g>=i.holdUntil&&i.index>=i.paths.length-1){if(i.after==="resumeIdle"){Q(g+f,_);return}if(i.after==="doublePause"){i={kind:"doublePause",resumeAt:g+we(a,o),blinkEmotion:i.blinkEmotion},S(z(i.blinkEmotion),i.blinkEmotion);return}if(i.after==="idle"&&Math.random()<s){i={kind:"doublePause",resumeAt:g+we(a,o),blinkEmotion:i.blinkEmotion},S(z(i.blinkEmotion),i.blinkEmotion);return}Q(g,i.blinkEmotion)}}}return{advance:K,setTargetEmotion(g){const E=ue(g,_);if(E===_&&i.kind!=="emotionBlend")return;const k=performance.now();if(h>0&&E!==_&&i.kind!=="emotionBlend"&&!(_==="neutral"&&E!=="neutral")&&k-u<h)return;const V=_;if(_=E,u=k,i.kind==="playing"){N(k,d,E);return}if(i.kind==="emotionBlend"){i={...i,thenEmotion:E};return}N(k,V,E)},getTargetEmotion:()=>_,getExpressionPath:()=>T,getDrawKey:()=>R,reset(){_="neutral",d="neutral",u=0,Q(performance.now()+we(n,r),"neutral")}}}function On(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 a=()=>{const o=t.duration;if(!Number.isFinite(o)||o<=0){s(new Error(`Idle video has invalid duration: ${e}`));return}n=!0,t.currentTime=0,r()};t.addEventListener("loadeddata",a,{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 Ln=50,St=400;function Nn(e,t,n){return e.filter(r=>{const s=r.queueIndex??-1;return s>=t&&s<=n})}function Un(e,t){const n=[];for(const r of e){const s=Nn(t,r.start_word,r.end_word);if(s.length===0)continue;const a=s[0],o=s[s.length-1];n.push({sentence:r,startMs:Math.max(0,a.wtime-Ln),endMs:o.wtime+o.wduration+St})}return n.sort((r,s)=>r.startMs-s.startMs)}function Vn(e,t,n,r="neutral"){const s=ue(r);if(t.length===0)return s;if(n.length===0||e<n[0].wtime)return ue(t[0]?.emotion,s);const a=Un(t,n);let o=null;for(const h of a)e>=h.startMs&&e<=h.endMs&&(o=h);if(o)return ue(o.sentence.emotion,s);const c=n[n.length-1],f=c.wtime+c.wduration;return e>f+St?ue(t[t.length-1]?.emotion,s):s}function Tt(e,t,n,r,s=je){const a=new OffscreenCanvas(n,r),o=a.getContext("2d",{willReadFrequently:!0});o.drawImage(e,0,0,n,r);const c=o.getImageData(0,0,n,r),f=o.createImageData(n,r);f.data.set(c.data);const _=new OffscreenCanvas(n,r).getContext("2d",{willReadFrequently:!0});for(const d of t){_.clearRect(0,0,n,r),_.drawImage(d,0,0,n,r);const u=_.getImageData(0,0,n,r);for(let i=0;i<f.data.length;i+=4){const T=u.data[i],R=u.data[i+1],S=u.data[i+2];Math.max(T,R,S)>s&&(f.data[i]=T,f.data[i+1]=R,f.data[i+2]=S,f.data[i+3]=255)}}return o.putImageData(f,0,0),a}let ne=null,ge=null;const be=new Map;function Bn(){ne=null,ge=null,be.clear()}Ht(Bn);function $n(e){return e??ge??void 0}function ze(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 hn(e,r):await fetch(e).then(h=>{if(!h.ok)throw new Error(`Failed to load ${e}`);return h.json()}),a=s.sheets?.[0];if(!a?.path)throw new Error(`${e} has no sheets[0].path`);const o=n?await _n(await yt(Sn(t,a.path,n),r??"")):await ze(`${t}/${a.path}`),c=new Map;for(const h of s.cells??[])h.path&&c.set(h.path,h);const f=new Map;for(const h of s.sheets??[])f.set(h.index,h);return{atlas:o,atlasMeta:s,cellByPath:c,sheetByIndex:f,diffBase:t}}async function $e(e){const t=$n(e),n=lt();if(n&&!t)throw new Error("Encrypted assets enabled but no key provided");if(ne&&(!n||ge===(t??null))){const a=await ne;return Ee(a)}ge=t??null,be.clear();const r=qt();ne=(async()=>{const a=await ze(Wt()),o=await nt(Gt(),r,n,t);let c=null;try{c=await nt(jt(),r,n,t)}catch{c=null}return{sil:a,viseme:o,expression:c}})();const s=await ne;return Ee(s)}async function It(e){if(await $e(e),!ne)throw new Error("Assets not loaded");return ne}function Ee(e){return ln(e.viseme.atlasMeta,e.sil.naturalWidth,e.sil.naturalHeight)}function Hn(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=be.get(r);if(s)return s;const a=(async()=>{const o=t.cellByPath.get(n);if(!o)throw new Error(`No atlas cell for path: ${n}`);const c=fn(t.atlasMeta,o),f=Ee(e);if(dn(o)){const d=Hn(t,o),u=document.createElement("canvas");u.width=f.width,u.height=f.height;const i=u.getContext("2d");return i.fillStyle="#000",i.fillRect(0,0,f.width,f.height),i.drawImage(d,c.x,c.y),u}const h=`${t.diffBase}/${n}`,_=await ze(h);if(_.naturalWidth===f.width&&_.naturalHeight===f.height)return _;throw new Error(`Diff PNG wrong size for ${n}`)})();return be.set(r,a),a}async function st(e,t,n,r=je,s,a){if(s){const{width:u,height:i}=s;if(a&&!a()||t.readyState<HTMLMediaElement.HAVE_CURRENT_DATA)return;const T=document.createElement("canvas");T.width=u,T.height=i;const R=T.getContext("2d");if(R.clearRect(0,0,u,i),R.drawImage(t,0,0,u,i),a&&!a())return;(e.width!==u||e.height!==i)&&(e.width=u,e.height=i);const S=e.getContext("2d");S.clearRect(0,0,u,i),S.drawImage(T,0,0);return}const o=await It(),{width:c,height:f}=Ee(o);(e.width!==c||e.height!==f)&&(e.width=c,e.height=f);const h=[],_=e.getContext("2d");if(_.clearRect(0,0,c,f),t.readyState<HTMLMediaElement.HAVE_CURRENT_DATA){const u=o.sil;_.drawImage(u,0,0,c,f);return}if(h.length===0){_.drawImage(t,0,0,c,f);return}const d=Tt(t,h,c,f,r);_.drawImage(d,0,0)}async function He(e,t,n=je){const r=await It(ge??void 0),{width:s,height:a}=Ee(r);(e.width!==s||e.height!==a)&&(e.width=s,e.height=a);const o=[];t.mouthPath&&o.push(await rt(r,r.viseme,t.mouthPath)),t.expressionPath&&r.expression&&o.push(await rt(r,r.expression,t.expressionPath));const c=e.getContext("2d");if(c.clearRect(0,0,s,a),o.length===0){c.drawImage(r.sil,0,0,s,a);return}const f=Tt(r.sil,o,s,a,n);c.drawImage(f,0,0)}async function Wn(e){await He(e,{mouthPath:null,expressionPath:null})}function Kn(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 qn(e){const t=Kn(e),n=[];for(let r=0;r<t.length-1;r++){const s=t[r].viseme,a=t[r+1].viseme,o=t[r].vtime,c=t[r+1].vtime;s===a||c<=o||n.push({from:s,to:a,fromVtime:o,toVtime:c})}return n}function Gn(e,t){let n=null;for(const r of e)t>=r.fromVtime&&t<r.toVtime&&(n=r);return n}function jn(e,t){return{gapMs:Math.max(0,t-e),holdEnd:e,transStart:e}}const zn=500,Qn="__sil__";function Jn(){return{lastDrawnKey:""}}function me(e){e.lastDrawnKey=""}function it(e){return e??Qn}function Xn(e,t){if(e.length===0)return{diffPath:null,label:"sil"};const n=qn(e),r=Gn(n,t);if(r){const a=r.toVtime-r.fromVtime,o=jn(r.fromVtime,r.toVtime);if(t>=o.transStart&&t<r.toVtime){const c=gn(r.from,r.to),f=yn(c,a);if(f.length>0){const h=pn(t,o.transStart,r.toVtime,f.length);return{diffPath:f[h]??f[f.length-1],label:`${r.from}→${r.to}`}}return{diffPath:Ve(r.to),label:r.to}}}const s=ht(e,t);return s==="sil"?{diffPath:null,label:"sil"}:{diffPath:Ve(s),label:s}}function At(e,t){const n=t??it(e.expressionPath);return`${it(e.mouthPath)}|${n}`}function Yn(e,t,n,r,s,a,o,c){const f=Xn(t,n),h={mouthPath:f.diffPath,expressionPath:r},_=At(h,s);_!==a.lastDrawnKey&&(a.lastDrawnKey=_,c(f.label),o(e,h))}function ot(e,t,n,r,s,a,o=null){const c={mouthPath:null,expressionPath:t},f=o!=null?`|idle@${Math.round(o*1e3)}`:"",h=At(c,n)+f;!(o!=null)&&h===r.lastDrawnKey||(r.lastDrawnKey=h,a(o!=null?"idle":"sil"),s(e,c))}function Zn(e){return new Worker("/assets/visemeDiffPreview.worker-D2ggcW5u.js",{name:e?.name})}function er(){return typeof Worker<"u"&&typeof OffscreenCanvas<"u"}function tr(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 at(e,t){let n=0;return{usesWorker:!1,async loadAssets(r){return await $e(r)},async renderSilOnly(){n+=1,await Wn(e)},async drawLiveFrame(r,s){await $e(),await He(r,s)},async renderViseme(r,s){n+=1;const a=n;t.onStatus?.(s),await He(r,{mouthPath:Ve(s),expressionPath:null})},dispose(){n+=1}}}function nr(e,t){const n=new Zn;let r=1,s=0,a=!1,o=!1;const c=new Map,f=(d,u)=>{o||n.postMessage(d,[])},h=(d,u,i=!1)=>{if(o)return Promise.resolve();const T=r++;return new Promise((R,S)=>{c.set(T,{resolve:Q=>R(Q),reject:S,generation:typeof d.generation=="number"?d.generation:void 0,expectRenderDone:i}),f({...d,requestId:T})})};n.onmessage=d=>{if(o)return;const u=d.data;if(u.type==="status"){t.onStatus?.(u.label);return}if(u.type==="frame"){const T=u.generation<0;if(!T&&u.generation!==s){u.bitmap.close();return}if(T&&t.shouldAcceptLiveFrame&&!t.shouldAcceptLiveFrame()){u.bitmap.close();return}tr(e,u.bitmap),u.bitmap.close();return}const i=c.get(u.requestId);if(i)switch(u.type){case"ready":c.delete(u.requestId),i.resolve();break;case"loadAssetsDone":c.delete(u.requestId),i.resolve({width:u.width,height:u.height});break;case"renderDone":if(i.expectRenderDone&&i.generation!=null&&u.generation!==i.generation)return;c.delete(u.requestId),i.resolve();break;case"renderAborted":c.delete(u.requestId),i.resolve();break;case"error":c.delete(u.requestId),t.onError?.(u.message),i.reject(new Error(u.message));break}},n.onerror=d=>{if(o)return;const u=d.message||"Worker error";t.onError?.(u);for(const[,i]of c)i.reject(new Error(u));c.clear()};const _=(async()=>{await h({type:"init"}),a=!0})();return{usesWorker:!0,async loadAssets(d){if(o)return{width:842,height:1264};if(await _,o)return{width:842,height:1264};if(!a)throw new Error("Worker init failed");return await h({type:"loadAssets",keyHex:d,urls:se()})??{width:842,height:1264}},async renderSilOnly(){if(o||(await _,o))return;s+=1;const d=s;await h({type:"renderSil",generation:d},void 0,!0)},async drawLiveFrame(d,u){o||(await _,!o&&await h({type:"drawFrame",diffPath:u.mouthPath,expressionDiffPath:u.expressionPath},void 0,!0))},async renderViseme(d,u,i={}){if(o||(await _,o))return;s+=1;const T=s;try{await h({type:"renderViseme",generation:T,to:u,from:i.from,transitionDurationMs:i.transitionDurationMs,gapMs:i.gapMs,threshold:i.threshold},void 0,!0)}catch(R){if(R?.name==="AbortError")return;throw R}},dispose(){if(!o){o=!0,s+=1;for(const[,d]of c)d.resolve();c.clear(),n.terminate()}}}}function rr(e,t={}){if(!er())return at(e,t);try{return nr(e,t)}catch{return at(e,t)}}class sr extends Error{constructor(t,n){super(`${t} timed out after ${Math.round(n/1e3)}s`),this.name="LoadTimeoutError"}}function Pe(e,t,n){return new Promise((r,s)=>{const a=globalThis.setTimeout(()=>{s(new sr(n,t))},t);e.then(o=>{globalThis.clearTimeout(a),r(o)},o=>{globalThis.clearTimeout(a),s(o)})})}const ir={position:"relative",display:"inline-block",lineHeight:0},or={display:"block",maxWidth:"100%",height:"auto"},ar={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 ve(e){return Dt(e)?gt:qe}const cr=m.forwardRef(function({id:t,assets:n,authToken:r,apiBase:s=De,facesCdnBase:a=We,ttsEngineId:o=re,voiceId:c,speakingRate:f=Ge,className:h,style:_,canvasStyle:d,onStatusChange:u,onDisplayStatus:i,onError:T,onReady:R,showErrorOverlay:S=!0},Q){const W=m.useRef(null),N=m.useRef(null),K=m.useRef(Jn()),g=m.useRef(Pn()),E=m.useRef(0),k=m.useRef(0),V=m.useRef(null),q=m.useRef(!1),I=m.useRef(null),J=m.useRef(!1),[ie,le]=m.useState("idle"),[oe,fe]=m.useState(null),[Y,Se]=m.useState(!1),[de,ae]=m.useState(!1),[Te,Qe]=m.useState({width:842,height:1264}),w=m.useRef(r??null),C=m.useRef(null),A=m.useRef(null),v=m.useRef(!1),b=m.useRef({width:842,height:1264}),F=m.useRef(R),D=m.useRef(i),G=m.useRef(T);F.current=R,D.current=i,G.current=T;const M=m.useCallback(l=>{const p=l?.ttsEngineId??o??A.current?.ttsEngineId??re,y=l?.voiceId??c??A.current?.voiceId??ve(p);return{ttsEngineId:p,voiceId:y}},[o,c]),B=m.useCallback(l=>{fe(l),G.current?.(l)},[]),$=m.useCallback(l=>{le(l),u?.(l)},[u]),P=m.useRef(Et($,s)),L=m.useCallback(()=>{V.current!=null&&(clearTimeout(V.current),V.current=null)},[]),ce=m.useCallback(async()=>{const l=k.current,p=N.current;!p||!Y||P.current.isSpeaking()||(me(K.current),await p.renderSilOnly(),l===k.current&&(P.current.isSpeaking()||(D.current?.("sil"),J.current&&I.current&&(I.current.restart(),I.current.setActive(!0)))))},[Y]),Z=m.useCallback(()=>{L();const l=k.current;ce(),V.current=setTimeout(()=>{V.current=null,l===k.current&&ce()},zn)},[L,ce]),U=m.useCallback(async()=>{const l=Math.floor(Date.now()/1e3);if(C.current&&l<C.current.expiresAt-60)return C.current.key;const p=w.current??await Oe();w.current=p,P.current.setDeveloperToken(p);const y=await Lt(p,s);return C.current={key:y.value,expiresAt:y.expiresAt},y.value},[s]);m.useEffect(()=>{r&&(w.current=r,P.current.setDeveloperToken(r))},[r]),m.useEffect(()=>{P.current.setTtsEngineId(o),A.current&&(A.current.ttsEngineId=o)},[o]),m.useEffect(()=>{const l=c??ve(o);A.current&&(A.current.voiceId=l)},[c,o]);const X=m.useMemo(()=>n?JSON.stringify(n):`id:${t??""}:${a}`,[n,t,a]);return m.useEffect(()=>{if(!t&&!n){B("AiTwin requires either `id` or `assets`");return}let l=!1;v.current=!1,Se(!1),ae(!1),fe(null),A.current=null,I.current=null,J.current=!1;const p=W.current;if(!p)return;let y=null;return(async()=>{try{let x,H,ee;if(n)x=n,H=o,ee=c??ve(H);else{D.current?.("getAiTwin");const O=await Pe(ut(t),3e4,"getAiTwin");if(l)return;if(!O.faceId?.trim())throw new Error("getAiTwin returned no faceId");H=O.ttsEngineId,ee=c??O.voiceId??ve(H),x=Bt(O.faceId,a)}A.current={ttsEngineId:H,voiceId:ee},$t(x),I.current=On(Kt()),y=rr(p,{onStatus:O=>{l||D.current?.(O)},onError:O=>{l||B(O)},shouldAcceptLiveFrame:()=>P.current.isSpeaking()}),N.current=y,D.current?.("auth");const te=w.current??r??await Pe(Oe(),3e4,"getAuthToken");if(l)return;w.current=te,P.current.setDeveloperToken(te),P.current.setTtsEngineId(H);const Me=lt()?await U():void 0;if(l)return;D.current?.("loadAssets");const j=await Pe(y.loadAssets(Me),18e4,"load face assets");if(!l&&j.width>0&&j.height>0&&(b.current=j,Qe(j)),l)return;v.current=!0,Se(!0),F.current?.(),y.renderSilOnly().then(()=>{l||D.current?.("sil")}),(async()=>{try{if(await I.current.load(),l)return;J.current=!0,ae(!0),me(K.current),I.current.setActive(!0);const O=I.current.getVideo();await st(p,O,null,void 0,b.current),l||D.current?.("idle")}catch(O){if(l)return;J.current=!1,ae(!1),console.warn("[AiTwin] Idle video unavailable:",O)}})()}catch(x){if(l)return;if(x instanceof Re){B(x.message);return}B(x instanceof Error?x.message:"Failed to load AI twin")}})(),()=>{l=!0,y?.dispose(),N.current=null}},[X,n,o,c,a,r,s,U,B]),m.useEffect(()=>{ie==="done"&&Y&&!P.current.isSpeaking()&&Z()},[ie,Y,Z]),m.useEffect(()=>{const l=P.current,p={current:!1},y=()=>{const x=W.current,H=N.current;if(!x||!H||!Y){E.current=requestAnimationFrame(y);return}const ee=l.isSpeaking(),te=l.getPlaybackElapsedMs(),Me=ee?Vn(te,l.getSentenceEmotions(),l.getWordQueue(),l.getStreamMood()):l.getStreamMood();if(ee){if(J.current&&I.current?.setActive(!1),l.getVisemeQueue().length===0){E.current=requestAnimationFrame(y);return}g.current.setTargetEmotion(Me),g.current.advance(performance.now());const O=g.current.getExpressionPath(),he=g.current.getDrawKey();Yn(x,l.getVisemeQueue(),te,O,he,K.current,(_e,kt)=>H.drawLiveFrame(_e,kt),_e=>D.current?.(_e))}else if(J.current&&I.current){const j=I.current,O=j.getVideo();O.readyState>=HTMLMediaElement.HAVE_CURRENT_DATA?(j.setActive(!0),p.current||(p.current=!0,st(x,O,null,void 0,b.current,()=>!l.isSpeaking()).then(()=>D.current?.("idle")).finally(()=>{p.current=!1}))):ot(x,null,"__sil__",K.current,(he,_e)=>H.drawLiveFrame(he,_e),he=>D.current?.(he))}else ot(x,null,"__sil__",K.current,(j,O)=>H.drawLiveFrame(j,O),j=>D.current?.(j));q.current&&!ee&&(g.current.reset(),I.current?.setActive(!1),Z()),q.current=ee,E.current=requestAnimationFrame(y)};return E.current=requestAnimationFrame(y),()=>{cancelAnimationFrame(E.current),L(),l.stop()}},[Y,de,Z,L]),m.useImperativeHandle(Q,()=>({speakText:async(l,p)=>{const y=l.trim();if(!y)return;const x=N.current;if(!x||!v.current&&!Y)throw new Error("AI twin is not ready");const{ttsEngineId:H,voiceId:ee}=M(p);fe(null),k.current+=1,L(),me(K.current),g.current.reset(),q.current=!1;try{J.current?(I.current?.setActive(!1),I.current?.restart(),me(K.current)):await x.renderSilOnly(),await P.current.speak(y,{voiceId:ee,speakingRate:p?.speakingRate??f,ttsEngineId:H})}catch(te){throw B(te instanceof Error?te.message:"TTS failed"),te}},stop:()=>{k.current+=1,L(),P.current.stop(),me(K.current),q.current=!1,Z()},setTtsEngineId:l=>{P.current.setTtsEngineId(l),A.current&&(A.current.ttsEngineId=l)},renderViseme:async(l,p)=>{const y=N.current,x=W.current;if(!y||!x||!v.current)throw new Error("AI twin is not ready");await y.renderViseme(x,l,{from:p?.from,transitionDurationMs:p?.transitionDurationMs,gapMs:p?.gapMs,onStatus:H=>D.current?.(H)})},isReady:()=>v.current,getStatus:()=>ie}),[Y,f,L,Z,B,M,ie]),Fe.jsxs("div",{className:h,style:{...ir,..._},children:[Fe.jsx("canvas",{ref:W,width:Te.width,height:Te.height,style:{...or,...d},"aria-label":t?`AI twin ${t}`:"AI twin face"}),S&&oe?Fe.jsx("div",{style:ar,children:oe}):null]})});exports.AiTwin=cr;exports.AiTwinNotFoundError=Re;exports.DEFAULT_API_BASE=De;exports.DEFAULT_FACES_CDN_BASE=We;exports.DEFAULT_TTS_ENGINE_ID=Ke;exports.OCULUS_VISEME_IDS=ft;exports.SPEAKING_RATE_MAX=wt;exports.SPEAKING_RATE_MIN=mt;exports.TTS_ENGINE_CARTESIA=pe;exports.TTS_ENGINE_GOOGLE=re;exports.TTS_ENGINE_INWORLD=ye;exports.VISEME_IDS=mn;exports.VISEME_TEST_CARTESIA_VOICE_ID=gt;exports.VISEME_TEST_SPEAKING_RATE=Ge;exports.VISEME_TEST_VOICE_ID=qe;exports.createAvatarTtsLipsyncController=Et;exports.fetchAiTwin=ut;exports.fetchDevAuthToken=Oe;exports.normalizeOculusViseme=dt;exports.resolveVisemeAtTime=ht;exports.resolveWordAtTime=_t;