@streamoji/aitwin 0.1.5 → 0.1.6

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 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.6",Mt={version:Ct},Ft={},ke="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",Ke="eng_a7f2b9c1",Re="eng_d4e8f3a2",ae="eng_c9b1e6d4",re=ae,Nt=new Set([Re,ae]),ft={[Ke]:"oculus_direct",[ae]:"oculus_direct",[Re]:"inworld_word"},Je={google:Ke,inworld:Re,cartesia:ae};function Bt(e){return ft[e]}function Vt(e){return e===ae}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]:re}class Ae 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 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,...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=ke){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 Ee(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=Ee(n.subarray(0,12)),s=Ee(n.subarray(12,28)),i=Ee(n.subarray(28)),a=Ee(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 Se={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(Se[r])return Se[r];for(let s=0;s<n.length;s++){const i=n[s];if(Se[i])return Se[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=ke){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()),ce=()=>{E!=null&&(clearTimeout(E),E=null)},ge=()=>{for(const h of l)try{h.stop()}catch{}l.length=0},X=()=>{C=!0,ce(),ge(),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,ce(),e("done"),W())},ye=()=>{const h=Xe(r);if(h<=0){e("done"),W();return}_=!0,x=performance.now(),e("speaking"),W(),ce();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})}))},ue=(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),ue(h,B,P,k)},pe=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 pe(k.audio,k.visemes,k.words,k.isNewSegment):K()}},Z=()=>{if(o=!0,!I&&r.length>0){ye();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??re;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 fe=async de=>{const f=an(de);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 pe(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: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 A of T)await fe(A);if(de){H.trim()&&await fe(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 _e(e,t){return e+Math.random()*(t-e)}function Te(){return _e(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+_e(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+Te(),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+Te(),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+Te();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+Te();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,a),blinkEmotion:o.blinkEmotion},u(z(o.blinkEmotion),o.blinkEmotion);return}if(o.after==="idle"&&Math.random()<s){o={kind:"doublePause",resumeAt:y+_e(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()+_e(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,me=null;const ve=new Map;function Xn(){ne=null,me=null,ve.clear()}en(Xn);function Zn(e){return e??me??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||me===(t??null))){const i=await ne;return we(i)}me=t??null,ve.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 we(s)}async function vt(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 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=ve.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=we(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 ve.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}=we(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(me??void 0),{width:s,height:i}=we(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 he(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 Ie(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,ce]=p.useState("idle"),[ge,X]=p.useState(null),[K,ye]=p.useState(!1),[xe,ue]=p.useState(!1),[ie,pe]=p.useState({width:842,height:1264}),Z=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),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??Ie(T);return{ttsEngineId:T,voiceId:A}},[s,i]),V=p.useCallback(f=>{X(f),U.current?.(f)},[]),L=p.useCallback(f=>{ce(f),m?.(f)},[m]),F=p.useRef(St(L,ke)),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()||(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]),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=Z.current??await Ue();Z.current=T,F.current.setDeveloperToken(T);const A=await jt(T,ke);return le.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??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),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??Ie(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??Ie(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 fe():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,pe(j)),f)return;M.current=!0,ye(!0),P.current?.(),A.renderSilOnly().then(()=>{f||k.current?.("sil")}),(async()=>{try{if(await D.current.load(),f)return;q.current=!0,ue(!0),he(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,ue(!1),console.warn("[AiTwin] Idle video unavailable:",N)}})()}catch(v){if(f)return;if(v instanceof Ae){V(v.message);return}V(v instanceof Error?v.message:"Failed to load AI twin")}})(),()=>{f=!0,A?.dispose(),g.current=null}},[de,n,s,i,r,fe,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(),he(E.current),R.current.reset(),C.current=!1;try{q.current?(D.current?.setActive(!1),D.current?.restart(),he(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(),he(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&&ge?Oe.jsx("div",{style:pr,children:ge}):null]})});exports.AiTwin=Er;exports.AiTwinNotFoundError=Ae;exports.DEFAULT_TTS_ENGINE_ID=re;exports.OCULUS_VISEME_IDS=_t;exports.SPEAKING_RATE_MAX=pt;exports.SPEAKING_RATE_MIN=yt;exports.TTS_ENGINE_CARTESIA=ae;exports.TTS_ENGINE_GOOGLE=Ke;exports.TTS_ENGINE_INWORLD=Re;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;
package/dist/aitwin.js CHANGED
@@ -2,39 +2,39 @@ import { jsxs as Tt, jsx as je } from "react/jsx-runtime";
2
2
  import { forwardRef as vt, useRef as B, useState as _e, useCallback as ne, useEffect as oe, useMemo as It, useImperativeHandle as At } from "react";
3
3
  const Rt = "https://pub-607ad1fc22e2400eb57d17240aab857c.r2.dev", ut = {
4
4
  publicBase: Rt
5
- }, bt = "0.1.5", Dt = {
5
+ }, bt = "0.1.6", Dt = {
6
6
  version: bt
7
- }, xt = {}, Ae = "https://ai.streamoji.com", Ct = `${ut.publicBase}/custom-faces`, Mt = `${ut.publicBase}/aitwin-workers/v${Dt.version}/visemeDiffPreview.worker.js`;
7
+ }, xt = {}, Re = "https://ai.streamoji.com", Ct = `${ut.publicBase}/custom-faces`, Mt = `${ut.publicBase}/aitwin-workers/v${Dt.version}/visemeDiffPreview.worker.js`;
8
8
  function Ft(e) {
9
9
  if (e) return e;
10
10
  const t = typeof import.meta < "u" ? xt?.VITE_AITWIN_WORKER_URL : void 0;
11
11
  return t?.trim() ? t.trim() : Mt;
12
12
  }
13
- const Pt = "https://us-central1-streamoji-265f4.cloudfunctions.net/getAiTwin", ce = "eng_a7f2b9c1", be = "eng_d4e8f3a2", De = "eng_c9b1e6d4", lt = be, Ot = /* @__PURE__ */ new Set([
14
- be,
15
- De
13
+ const Pt = "https://us-central1-streamoji-265f4.cloudfunctions.net/getAiTwin", lt = "eng_a7f2b9c1", qe = "eng_d4e8f3a2", pe = "eng_c9b1e6d4", ce = pe, Ot = /* @__PURE__ */ new Set([
14
+ qe,
15
+ pe
16
16
  ]), ft = {
17
- [ce]: "oculus_direct",
18
- [De]: "oculus_direct",
19
- [be]: "inworld_word"
17
+ [lt]: "oculus_direct",
18
+ [pe]: "oculus_direct",
19
+ [qe]: "inworld_word"
20
20
  }, ze = {
21
- google: ce,
22
- inworld: be,
23
- cartesia: De
21
+ google: lt,
22
+ inworld: qe,
23
+ cartesia: pe
24
24
  };
25
25
  function Lt(e) {
26
26
  return ft[e];
27
27
  }
28
28
  function Ut(e) {
29
- return e === De;
29
+ return e === pe;
30
30
  }
31
31
  function Bt(e) {
32
32
  if (e.ttsEngineId && e.ttsEngineId in ft)
33
33
  return e.ttsEngineId;
34
34
  const t = e.tts?.toLowerCase();
35
- return t && t in ze ? ze[t] : lt;
35
+ return t && t in ze ? ze[t] : ce;
36
36
  }
37
- class Ue extends Error {
37
+ class Le extends Error {
38
38
  constructor(t = "AI twin not found") {
39
39
  super(t), this.name = "AiTwinNotFoundError";
40
40
  }
@@ -44,12 +44,12 @@ async function Nt(e, t = Pt) {
44
44
  n.searchParams.set("id", e);
45
45
  const r = await fetch(n.toString());
46
46
  if (r.status === 404)
47
- throw new Ue();
47
+ throw new Le();
48
48
  if (!r.ok)
49
49
  throw new Error(`getAiTwin failed (${r.status})`);
50
50
  const i = await r.json();
51
51
  if (!i.success)
52
- throw new Ue(i.error ?? "AI twin not found");
52
+ throw new Le(i.error ?? "AI twin not found");
53
53
  const { tts: s, ...a } = i.data;
54
54
  return {
55
55
  ...a,
@@ -77,7 +77,7 @@ async function Qe() {
77
77
  throw new Error("getAuthToken returned no token");
78
78
  return n;
79
79
  }
80
- async function Kt(e, t = Ae) {
80
+ async function Kt(e, t = Re) {
81
81
  const n = await fetch(`${t.replace(/\/$/, "")}/api/session-value`, {
82
82
  headers: { Authorization: `Bearer ${e}` }
83
83
  });
@@ -95,7 +95,7 @@ function Gt(e) {
95
95
  n[r / 2] = Number.parseInt(t.slice(r, r + 2), 16);
96
96
  return n;
97
97
  }
98
- function Se(e) {
98
+ function Te(e) {
99
99
  return Uint8Array.from(e);
100
100
  }
101
101
  function jt(e, t) {
@@ -106,7 +106,7 @@ async function zt(e, t) {
106
106
  if (!t) throw new Error("Asset key is required for encrypted assets");
107
107
  if (e.byteLength < 28)
108
108
  throw new Error("Encrypted payload too small");
109
- const n = new Uint8Array(e), r = Se(n.subarray(0, 12)), i = Se(n.subarray(12, 28)), s = Se(n.subarray(28)), a = Se(jt(s, i)), c = await crypto.subtle.importKey(
109
+ const n = new Uint8Array(e), r = Te(n.subarray(0, 12)), i = Te(n.subarray(12, 28)), s = Te(n.subarray(28)), a = Te(jt(s, i)), c = await crypto.subtle.importKey(
110
110
  "raw",
111
111
  Gt(t),
112
112
  { name: "AES-GCM" },
@@ -119,15 +119,15 @@ async function zt(e, t) {
119
119
  a
120
120
  );
121
121
  }
122
- let Be = null;
123
- const Ne = /* @__PURE__ */ new Set();
122
+ let Ue = null;
123
+ const Be = /* @__PURE__ */ new Set();
124
124
  function Qt(e, t = Ct) {
125
125
  const n = `${t.replace(/\/$/, "")}/${e}`;
126
126
  return { twinBase: n, binBase: n, encrypted: !0 };
127
127
  }
128
128
  function Jt(e) {
129
- Be = e;
130
- for (const t of Ne) t();
129
+ Ue = e;
130
+ for (const t of Be) t();
131
131
  }
132
132
  function Yt(e, t) {
133
133
  const n = typeof globalThis.location < "u" ? globalThis.location.href : void 0;
@@ -146,12 +146,12 @@ function Yt(e, t) {
146
146
  };
147
147
  }
148
148
  function ie() {
149
- if (!Be)
149
+ if (!Ue)
150
150
  throw new Error("Twin assets not configured; call setActiveTwinAssets first");
151
- return Be;
151
+ return Ue;
152
152
  }
153
153
  function Xt(e) {
154
- return Ne.add(e), () => Ne.delete(e);
154
+ return Be.add(e), () => Be.delete(e);
155
155
  }
156
156
  function Zt() {
157
157
  return `${ie().twinBase}/sil.png`;
@@ -237,12 +237,12 @@ function fn(e, t) {
237
237
  const i = Math.max(0, Math.min(1, (t - e.wtime) / r));
238
238
  return Math.min(n - 1, Math.floor(i * n));
239
239
  }
240
- function xe(e, t) {
240
+ function De(e, t) {
241
241
  const n = Math.max(0, Math.min(e.length - 1, t));
242
242
  return e[n] ?? "";
243
243
  }
244
244
  function dn(e, t) {
245
- const n = e.toLowerCase(), r = xe(n, t), i = n.slice(Math.max(0, t - 1), t + 2);
245
+ const n = e.toLowerCase(), r = De(n, t), i = n.slice(Math.max(0, t - 1), t + 2);
246
246
  return r === "i" || r === "y" ? "I" : i.includes("ee") || r === "e" || n.includes("ea") ? "E" : "aa";
247
247
  }
248
248
  function hn(e, t) {
@@ -251,7 +251,7 @@ function hn(e, t) {
251
251
  Math.min(n.length, t + 3)
252
252
  );
253
253
  if (/oo|ou|uw/.test(r)) return "U";
254
- const i = xe(n, t);
254
+ const i = De(n, t);
255
255
  return i === "u" || i === "w" ? "U" : "O";
256
256
  }
257
257
  function _n(e, t) {
@@ -261,9 +261,9 @@ function _n(e, t) {
261
261
  Math.max(0, t - 1),
262
262
  Math.min(n.length, t + 3)
263
263
  );
264
- return /wo|wh/.test(i) || xe(n, t) === "o" ? "O" : "U";
264
+ return /wo|wh/.test(i) || De(n, t) === "o" ? "O" : "U";
265
265
  }
266
- const Te = {
266
+ const ve = {
267
267
  d: "DD",
268
268
  t: "DD",
269
269
  n: "DD",
@@ -276,11 +276,11 @@ const Te = {
276
276
  j: "CH"
277
277
  };
278
278
  function mn(e, t) {
279
- const n = e.toLowerCase(), r = xe(n, t);
280
- if (Te[r]) return Te[r];
279
+ const n = e.toLowerCase(), r = De(n, t);
280
+ if (ve[r]) return ve[r];
281
281
  for (let i = 0; i < n.length; i++) {
282
282
  const s = n[i];
283
- if (Te[s]) return Te[s];
283
+ if (ve[s]) return ve[s];
284
284
  }
285
285
  return "DD";
286
286
  }
@@ -371,7 +371,7 @@ function Ye(e) {
371
371
  return t;
372
372
  }
373
373
  const vn = 0.5, In = 1.5, ht = "Olivia", An = "f786b574-daa5-4673-aa0c-cbe3e8534c02", _t = 0.85;
374
- function Rn(e, t = Ae) {
374
+ function Rn(e, t = Re) {
375
375
  const n = `${t.replace(/\/$/, "")}/avatar_ttsWithPoses`, r = [], i = [], s = [];
376
376
  let a = "neutral";
377
377
  const c = [], l = [];
@@ -381,7 +381,7 @@ function Rn(e, t = Ae) {
381
381
  h.playbackRate.value = A;
382
382
  }, q = () => b.forEach((h) => h()), ue = () => {
383
383
  p != null && (clearTimeout(p), p = null);
384
- }, pe = () => {
384
+ }, Ee = () => {
385
385
  for (const h of l)
386
386
  try {
387
387
  h.stop();
@@ -389,10 +389,10 @@ function Rn(e, t = Ae) {
389
389
  }
390
390
  l.length = 0;
391
391
  }, X = () => {
392
- x = !0, ue(), pe(), c.length = 0, m = !1, _ = !1, S = !1, o = !1, r.length = 0, i.length = 0, s.length = 0, a = "neutral", u = 0, g = 0, w = 0, e("idle"), q();
392
+ x = !0, ue(), Ee(), c.length = 0, m = !1, _ = !1, S = !1, o = !1, r.length = 0, i.length = 0, s.length = 0, a = "neutral", u = 0, g = 0, w = 0, e("idle"), q();
393
393
  }, K = () => {
394
394
  !o || m || l.length > 0 || c.length > 0 || (_ = !1, ue(), e("done"), q());
395
- }, Ee = () => {
395
+ }, ke = () => {
396
396
  const h = Ye(r);
397
397
  if (h <= 0) {
398
398
  e("done"), q();
@@ -403,7 +403,7 @@ function Rn(e, t = Ae) {
403
403
  p = setTimeout(() => {
404
404
  x || (_ = !1, p = null, e("done"), q());
405
405
  }, C);
406
- }, Me = (h, C, N) => {
406
+ }, Ce = (h, C, N) => {
407
407
  h.length !== 0 && (N && (u = C), h.forEach((P) => {
408
408
  const L = String(P.word ?? "").trim();
409
409
  if (!L) return;
@@ -442,8 +442,8 @@ function Rn(e, t = Ae) {
442
442
  });
443
443
  }), q());
444
444
  }, se = (h, C, N, P, T) => {
445
- Me(C, N, P), le(h, N, P, T);
446
- }, ke = async (h, C, N, P) => {
445
+ Ce(C, N, P), le(h, N, P, T);
446
+ }, Se = async (h, C, N, P) => {
447
447
  if (x || !h?.trim()) {
448
448
  (C.length > 0 || N.length > 0) && !S && se(
449
449
  C,
@@ -500,7 +500,7 @@ function Rn(e, t = Ae) {
500
500
  } finally {
501
501
  m = !1;
502
502
  const T = c.shift();
503
- T ? await ke(
503
+ T ? await Se(
504
504
  T.audio,
505
505
  T.visemes,
506
506
  T.words,
@@ -509,7 +509,7 @@ function Rn(e, t = Ae) {
509
509
  }
510
510
  }, Z = () => {
511
511
  if (o = !0, !S && r.length > 0) {
512
- Ee();
512
+ ke();
513
513
  return;
514
514
  }
515
515
  K();
@@ -527,7 +527,7 @@ function Rn(e, t = Ae) {
527
527
  const N = V.trim();
528
528
  if (!N)
529
529
  throw new Error("Developer token required for avatar_ttsWithPoses");
530
- const P = C?.ttsEngineId ?? y ?? lt;
530
+ const P = C?.ttsEngineId ?? y ?? ce;
531
531
  E = P;
532
532
  const T = C?.voiceId ?? ht, L = C?.speakingRate ?? _t, Q = Math.max(
533
533
  vn,
@@ -559,7 +559,7 @@ function Rn(e, t = Ae) {
559
559
  if (f.event === "audio") {
560
560
  const k = f.data.chunk, v = f.data.visemes ?? [], I = f.data.words ?? [], R = f.data.is_new_segment ?? !1;
561
561
  if (k)
562
- await ke(k, v, I, R);
562
+ await Se(k, v, I, R);
563
563
  else if (v.length > 0 || I.length > 0) {
564
564
  const G = R && r.length > 0 ? Ye(r) : u;
565
565
  se(v, I, G, R, P);
@@ -682,13 +682,13 @@ const Ke = 15, Rr = [
682
682
  "RR",
683
683
  "kk",
684
684
  "nn"
685
- ], $e = [
685
+ ], Ne = [
686
686
  "t01_0.17",
687
687
  "t02_0.33",
688
688
  "t03_0.50",
689
689
  "t04_0.67",
690
690
  "t05_0.83"
691
- ], Fn = $e.length, Xe = /* @__PURE__ */ new Set([
691
+ ], Fn = Ne.length, Xe = /* @__PURE__ */ new Set([
692
692
  "aa__kk",
693
693
  "aa__nn",
694
694
  "aa__sil",
@@ -801,21 +801,21 @@ function Ze(e, t) {
801
801
  function et(e, t) {
802
802
  return `pairs/${e}/${t}_minus_sil.png`;
803
803
  }
804
- function Ve(e) {
804
+ function $e(e) {
805
805
  return `${e}_minus_sil.png`;
806
806
  }
807
807
  function Pn(e, t) {
808
808
  if (e === t) return [];
809
809
  const n = [], r = Ze(e, t);
810
810
  if (Xe.has(r)) {
811
- for (const s of $e)
811
+ for (const s of Ne)
812
812
  n.push(et(r, s));
813
813
  return n;
814
814
  }
815
815
  const i = Ze(t, e);
816
816
  if (Xe.has(i)) {
817
817
  for (let s = Fn - 1; s >= 0; s--)
818
- n.push(et(i, $e[s]));
818
+ n.push(et(i, Ne[s]));
819
819
  return n;
820
820
  }
821
821
  return [];
@@ -836,7 +836,7 @@ function Bn(e, t, n) {
836
836
  const r = t.split("/").pop() ?? t, i = r.includes(".") ? r.slice(0, r.lastIndexOf(".")) : r;
837
837
  return `${e}/${i}.bin`;
838
838
  }
839
- const Nn = [0.32, 0.24, 0.16, 0.08, 0], Ce = Nn.map(
839
+ const Nn = [0.32, 0.24, 0.16, 0.08, 0], xe = Nn.map(
840
840
  (e) => `eyes_${e.toFixed(2)}`
841
841
  ), $n = [
842
842
  "eyes_0.32",
@@ -877,7 +877,7 @@ function ae(e, t = "neutral") {
877
877
  function z(e) {
878
878
  return e === "neutral" ? null : wt(e, "eyes_standard");
879
879
  }
880
- function He(e, t) {
880
+ function Ve(e, t) {
881
881
  return !t || t === "eyes_standard" ? z(e) : e === "neutral" && t === "eyes_standard" ? null : wt(e, t);
882
882
  }
883
883
  function Wn(e) {
@@ -885,17 +885,17 @@ function Wn(e) {
885
885
  const t = e.match(/\/(eyes_[^/]+)_minus_sil\.png$/);
886
886
  if (!t?.[1]) return "open";
887
887
  const n = t[1];
888
- return Ce.includes(n) ? n : "open";
888
+ return xe.includes(n) ? n : "open";
889
889
  }
890
890
  function qn(e) {
891
- return e === "open" ? -1 : Ce.indexOf(e);
891
+ return e === "open" ? -1 : xe.indexOf(e);
892
892
  }
893
893
  function Kn(e, t) {
894
894
  const n = [];
895
895
  for (const r of t)
896
- n.push(He(e, r));
896
+ n.push(Ve(e, r));
897
897
  for (let r = t.length - 2; r >= 0; r--)
898
- n.push(He(e, t[r]));
898
+ n.push(Ve(e, t[r]));
899
899
  return n.push(z(e)), n;
900
900
  }
901
901
  function Gn(e, t) {
@@ -904,7 +904,7 @@ function Gn(e, t) {
904
904
  if (n < 0) return [z(e)];
905
905
  const r = [];
906
906
  for (let i = n; i >= 0; i--)
907
- r.push(He(e, Ce[i]));
907
+ r.push(Ve(e, xe[i]));
908
908
  return r.push(z(e)), r;
909
909
  }
910
910
  const jn = [
@@ -927,7 +927,7 @@ function Jn(e, t) {
927
927
  function we(e, t) {
928
928
  return e + Math.random() * (t - e);
929
929
  }
930
- function ve() {
930
+ function Ie() {
931
931
  return we(14, 32);
932
932
  }
933
933
  function Yn(e = {}) {
@@ -956,12 +956,12 @@ function Yn(e = {}) {
956
956
  }, _ = E, u(z(E), E);
957
957
  }
958
958
  function p(y, E, x) {
959
- const b = x ? $n : Math.random() < c ? Ce : Vn;
959
+ const b = x ? $n : Math.random() < c ? xe : Vn;
960
960
  o = {
961
961
  kind: "playing",
962
962
  paths: Kn(E, b),
963
963
  index: 0,
964
- holdUntil: y + ve(),
964
+ holdUntil: y + Ie(),
965
965
  after: "idle",
966
966
  blinkEmotion: E
967
967
  }, _ = E, u(o.paths[0] ?? null, E);
@@ -976,14 +976,14 @@ function Yn(e = {}) {
976
976
  kind: "emotionBlend",
977
977
  paths: W,
978
978
  index: 0,
979
- holdUntil: y + ve(),
979
+ holdUntil: y + Ie(),
980
980
  thenEmotion: x
981
981
  }, u(W[0] ?? null, E);
982
982
  }
983
983
  function V(y) {
984
984
  if (o.kind === "emotionBlend") {
985
985
  for (; y >= o.holdUntil && o.index < o.paths.length - 1; )
986
- o.index += 1, o.holdUntil = y + ve();
986
+ o.index += 1, o.holdUntil = y + Ie();
987
987
  const E = o.paths[o.index] ?? null;
988
988
  u(E, o.thenEmotion), y >= o.holdUntil && o.index >= o.paths.length - 1 && (m = o.thenEmotion, _ = o.thenEmotion, u(z(o.thenEmotion), o.thenEmotion), o = {
989
989
  kind: "idle",
@@ -1001,7 +1001,7 @@ function Yn(e = {}) {
1001
1001
  }
1002
1002
  if (o.kind === "playing") {
1003
1003
  for (; y >= o.holdUntil && o.index < o.paths.length - 1; )
1004
- o.index += 1, o.holdUntil = y + ve();
1004
+ o.index += 1, o.holdUntil = y + Ie();
1005
1005
  if (u(o.paths[o.index] ?? null, o.blinkEmotion), y >= o.holdUntil && o.index >= o.paths.length - 1) {
1006
1006
  if (o.after === "resumeIdle") {
1007
1007
  g(y + l, m);
@@ -1156,9 +1156,9 @@ function yt(e, t, n, r, i = Ke) {
1156
1156
  return a.putImageData(l, 0, 0), s;
1157
1157
  }
1158
1158
  let re = null, ge = null;
1159
- const Re = /* @__PURE__ */ new Map();
1159
+ const be = /* @__PURE__ */ new Map();
1160
1160
  function rr() {
1161
- re = null, ge = null, Re.clear();
1161
+ re = null, ge = null, be.clear();
1162
1162
  }
1163
1163
  Xt(rr);
1164
1164
  function ir(e) {
@@ -1189,7 +1189,7 @@ async function tt(e, t, n, r) {
1189
1189
  l.set(d.index, d);
1190
1190
  return { atlas: a, atlasMeta: i, cellByPath: c, sheetByIndex: l, diffBase: t };
1191
1191
  }
1192
- async function We(e) {
1192
+ async function He(e) {
1193
1193
  const t = ir(e), n = dt();
1194
1194
  if (n && !t)
1195
1195
  throw new Error("Encrypted assets enabled but no key provided");
@@ -1197,7 +1197,7 @@ async function We(e) {
1197
1197
  const s = await re;
1198
1198
  return ye(s);
1199
1199
  }
1200
- ge = t ?? null, Re.clear();
1200
+ ge = t ?? null, be.clear();
1201
1201
  const r = tn();
1202
1202
  re = (async () => {
1203
1203
  const s = await Ge(Zt()), a = await tt(
@@ -1223,7 +1223,7 @@ async function We(e) {
1223
1223
  return ye(i);
1224
1224
  }
1225
1225
  async function pt(e) {
1226
- if (await We(e), !re) throw new Error("Assets not loaded");
1226
+ if (await He(e), !re) throw new Error("Assets not loaded");
1227
1227
  return re;
1228
1228
  }
1229
1229
  function ye(e) {
@@ -1238,7 +1238,7 @@ function sr(e, t) {
1238
1238
  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;
1239
1239
  }
1240
1240
  async function nt(e, t, n) {
1241
- const r = `${t.diffBase}::${n}`, i = Re.get(r);
1241
+ const r = `${t.diffBase}::${n}`, i = be.get(r);
1242
1242
  if (i) return i;
1243
1243
  const s = (async () => {
1244
1244
  const a = t.cellByPath.get(n);
@@ -1255,7 +1255,7 @@ async function nt(e, t, n) {
1255
1255
  return m;
1256
1256
  throw new Error(`Diff PNG wrong size for ${n}`);
1257
1257
  })();
1258
- return Re.set(r, s), s;
1258
+ return be.set(r, s), s;
1259
1259
  }
1260
1260
  async function rt(e, t, n, r = Ke, i, s) {
1261
1261
  if (i) {
@@ -1286,7 +1286,7 @@ async function rt(e, t, n, r = Ke, i, s) {
1286
1286
  const _ = yt(t, d, c, l, r);
1287
1287
  m.drawImage(_, 0, 0);
1288
1288
  }
1289
- async function qe(e, t, n = Ke) {
1289
+ async function We(e, t, n = Ke) {
1290
1290
  const r = await pt(ge ?? void 0), { width: i, height: s } = ye(r);
1291
1291
  (e.width !== i || e.height !== s) && (e.width = i, e.height = s);
1292
1292
  const a = [];
@@ -1308,7 +1308,7 @@ async function qe(e, t, n = Ke) {
1308
1308
  c.drawImage(l, 0, 0);
1309
1309
  }
1310
1310
  async function or(e) {
1311
- await qe(e, { mouthPath: null, expressionPath: null });
1311
+ await We(e, { mouthPath: null, expressionPath: null });
1312
1312
  }
1313
1313
  function ar(e) {
1314
1314
  const t = /* @__PURE__ */ new Map();
@@ -1360,11 +1360,11 @@ function _r(e, t) {
1360
1360
  );
1361
1361
  return { diffPath: l[d] ?? l[l.length - 1], label: `${r.from}→${r.to}` };
1362
1362
  }
1363
- return { diffPath: Ve(r.to), label: r.to };
1363
+ return { diffPath: $e(r.to), label: r.to };
1364
1364
  }
1365
1365
  }
1366
1366
  const i = Sn(e, t);
1367
- return i === "sil" ? { diffPath: null, label: "sil" } : { diffPath: Ve(i), label: i };
1367
+ return i === "sil" ? { diffPath: null, label: "sil" } : { diffPath: $e(i), label: i };
1368
1368
  }
1369
1369
  function Et(e, t) {
1370
1370
  const n = t ?? it(e.expressionPath);
@@ -1447,11 +1447,11 @@ function yr(e, t) {
1447
1447
  }
1448
1448
  function ct(e, t) {
1449
1449
  let n = 0;
1450
- const r = kt(async (i, s) => (await We(), await qe(e, i), r.isLatestSeq(s)));
1450
+ const r = kt(async (i, s) => (await He(), await We(e, i), r.isLatestSeq(s)));
1451
1451
  return {
1452
1452
  usesWorker: !1,
1453
1453
  async loadAssets(i) {
1454
- return await We(i);
1454
+ return await He(i);
1455
1455
  },
1456
1456
  async renderSilOnly() {
1457
1457
  n += 1, r.reset(), await or(e);
@@ -1462,8 +1462,8 @@ function ct(e, t) {
1462
1462
  async renderViseme(i, s) {
1463
1463
  n += 1;
1464
1464
  const a = n;
1465
- t.onStatus?.(s), await qe(i, {
1466
- mouthPath: Ve(s),
1465
+ t.onStatus?.(s), await We(i, {
1466
+ mouthPath: $e(s),
1467
1467
  expressionPath: null
1468
1468
  });
1469
1469
  },
@@ -1642,7 +1642,7 @@ class kr extends Error {
1642
1642
  super(`${t} timed out after ${Math.round(n / 1e3)}s`), this.name = "LoadTimeoutError";
1643
1643
  }
1644
1644
  }
1645
- function Le(e, t, n) {
1645
+ function Oe(e, t, n) {
1646
1646
  return new Promise((r, i) => {
1647
1647
  const s = globalThis.setTimeout(() => {
1648
1648
  i(new kr(n, t));
@@ -1677,7 +1677,7 @@ const Sr = {
1677
1677
  fontSize: "0.875rem",
1678
1678
  textAlign: "center"
1679
1679
  };
1680
- function Ie(e) {
1680
+ function Ae(e) {
1681
1681
  return Ut(e) ? An : ht;
1682
1682
  }
1683
1683
  const br = vt(function({
@@ -1698,11 +1698,11 @@ const br = vt(function({
1698
1698
  }, w) {
1699
1699
  const u = B(null), g = B(null), p = B(hr()), A = B(Yn()), V = B(0), y = B(0), E = B(null), x = B(!1), b = B(
1700
1700
  null
1701
- ), W = B(!1), [q, ue] = _e("idle"), [pe, X] = _e(null), [K, Ee] = _e(!1), [Me, le] = _e(!1), [se, ke] = _e({ width: 842, height: 1264 }), Z = B(r ?? null), fe = B(null), h = B(null), C = B(!1), N = B({ width: 842, height: 1264 }), P = B(o), T = B(_), L = B(S);
1701
+ ), W = B(!1), [q, ue] = _e("idle"), [Ee, X] = _e(null), [K, ke] = _e(!1), [Ce, le] = _e(!1), [se, Se] = _e({ width: 842, height: 1264 }), Z = B(r ?? null), fe = B(null), h = B(null), C = B(!1), N = B({ width: 842, height: 1264 }), P = B(o), T = B(_), L = B(S);
1702
1702
  P.current = o, T.current = _, L.current = S;
1703
1703
  const Q = ne(
1704
1704
  (f) => {
1705
- const k = f?.ttsEngineId ?? i ?? h.current?.ttsEngineId ?? ce, v = f?.voiceId ?? s ?? h.current?.voiceId ?? Ie(k);
1705
+ const k = f?.ttsEngineId ?? i ?? h.current?.ttsEngineId ?? ce, v = f?.voiceId ?? s ?? h.current?.voiceId ?? Ae(k);
1706
1706
  return { ttsEngineId: k, voiceId: v };
1707
1707
  },
1708
1708
  [i, s]
@@ -1714,7 +1714,7 @@ const br = vt(function({
1714
1714
  },
1715
1715
  [m]
1716
1716
  ), M = B(
1717
- Rn(O, Ae)
1717
+ Rn(O, Re)
1718
1718
  ), F = ne(() => {
1719
1719
  E.current != null && (clearTimeout(E.current), E.current = null);
1720
1720
  }, []), J = ne(async () => {
@@ -1732,7 +1732,7 @@ const br = vt(function({
1732
1732
  return fe.current.key;
1733
1733
  const k = Z.current ?? await Qe();
1734
1734
  Z.current = k, M.current.setDeveloperToken(k);
1735
- const v = await Kt(k, Ae);
1735
+ const v = await Kt(k, Re);
1736
1736
  return fe.current = {
1737
1737
  key: v.value,
1738
1738
  expiresAt: v.expiresAt
@@ -1743,7 +1743,7 @@ const br = vt(function({
1743
1743
  }, [r]), oe(() => {
1744
1744
  M.current.setTtsEngineId(i), h.current && (h.current.ttsEngineId = i);
1745
1745
  }, [i]), oe(() => {
1746
- const f = s ?? Ie(i);
1746
+ const f = s ?? Ae(i);
1747
1747
  h.current && (h.current.voiceId = f);
1748
1748
  }, [s, i]);
1749
1749
  const he = It(
@@ -1756,7 +1756,7 @@ const br = vt(function({
1756
1756
  return;
1757
1757
  }
1758
1758
  let f = !1;
1759
- C.current = !1, Ee(!1), le(!1), X(null), h.current = null, b.current = null, W.current = !1;
1759
+ C.current = !1, ke(!1), le(!1), X(null), h.current = null, b.current = null, W.current = !1;
1760
1760
  const k = u.current;
1761
1761
  if (!k) return;
1762
1762
  let v = null;
@@ -1764,10 +1764,10 @@ const br = vt(function({
1764
1764
  try {
1765
1765
  let I, R, G;
1766
1766
  if (n)
1767
- I = n, R = i, G = s ?? Ie(R);
1767
+ I = n, R = i, G = s ?? Ae(R);
1768
1768
  else {
1769
1769
  T.current?.("getAiTwin");
1770
- const U = await Le(
1770
+ const U = await Oe(
1771
1771
  Nt(t),
1772
1772
  3e4,
1773
1773
  "getAiTwin"
@@ -1775,7 +1775,7 @@ const br = vt(function({
1775
1775
  if (f) return;
1776
1776
  if (!U.faceId?.trim())
1777
1777
  throw new Error("getAiTwin returned no faceId");
1778
- R = U.ttsEngineId, G = s ?? U.voiceId ?? Ie(R), I = Qt(U.faceId);
1778
+ R = U.ttsEngineId, G = s ?? U.voiceId ?? Ae(R), I = Qt(U.faceId);
1779
1779
  }
1780
1780
  h.current = { ttsEngineId: R, voiceId: G }, Jt(I), b.current = Xn(en()), v = Er(k, {
1781
1781
  onStatus: (U) => {
@@ -1786,19 +1786,19 @@ const br = vt(function({
1786
1786
  },
1787
1787
  shouldAcceptLiveFrame: () => M.current.isSpeaking()
1788
1788
  }), g.current = v, T.current?.("auth");
1789
- const Y = Z.current ?? r ?? await Le(Qe(), 3e4, "getAuthToken");
1789
+ const Y = Z.current ?? r ?? await Oe(Qe(), 3e4, "getAuthToken");
1790
1790
  if (f) return;
1791
1791
  Z.current = Y, M.current.setDeveloperToken(Y), M.current.setTtsEngineId(R);
1792
- const Fe = dt() ? await de() : void 0;
1792
+ const Me = dt() ? await de() : void 0;
1793
1793
  if (f) return;
1794
1794
  T.current?.("loadAssets");
1795
- const j = await Le(
1796
- v.loadAssets(Fe),
1795
+ const j = await Oe(
1796
+ v.loadAssets(Me),
1797
1797
  18e4,
1798
1798
  "load face assets"
1799
1799
  );
1800
- if (!f && j.width > 0 && j.height > 0 && (N.current = j, ke(j)), f) return;
1801
- C.current = !0, Ee(!0), P.current?.(), v.renderSilOnly().then(() => {
1800
+ if (!f && j.width > 0 && j.height > 0 && (N.current = j, Se(j)), f) return;
1801
+ C.current = !0, ke(!0), P.current?.(), v.renderSilOnly().then(() => {
1802
1802
  f || T.current?.("sil");
1803
1803
  }), (async () => {
1804
1804
  try {
@@ -1819,7 +1819,7 @@ const br = vt(function({
1819
1819
  })();
1820
1820
  } catch (I) {
1821
1821
  if (f) return;
1822
- if (I instanceof Ue) {
1822
+ if (I instanceof Le) {
1823
1823
  $(I.message);
1824
1824
  return;
1825
1825
  }
@@ -1837,7 +1837,7 @@ const br = vt(function({
1837
1837
  V.current = requestAnimationFrame(v);
1838
1838
  return;
1839
1839
  }
1840
- const G = f.isSpeaking(), Y = f.getPlaybackElapsedMs(), Fe = G ? nr(
1840
+ const G = f.isSpeaking(), Y = f.getPlaybackElapsedMs(), Me = G ? nr(
1841
1841
  Y,
1842
1842
  f.getSentenceEmotions(),
1843
1843
  f.getWordQueue(),
@@ -1848,7 +1848,7 @@ const br = vt(function({
1848
1848
  V.current = requestAnimationFrame(v);
1849
1849
  return;
1850
1850
  }
1851
- A.current.setTargetEmotion(Fe), A.current.advance(performance.now());
1851
+ A.current.setTargetEmotion(Me), A.current.advance(performance.now());
1852
1852
  const U = A.current.getExpressionPath(), ee = A.current.getDrawKey();
1853
1853
  mr(
1854
1854
  I,
@@ -1857,7 +1857,7 @@ const br = vt(function({
1857
1857
  U,
1858
1858
  ee,
1859
1859
  p.current,
1860
- (te, Pe, Oe, St) => R.drawLiveFrame(te, Pe, Oe, St),
1860
+ (te, Fe, Pe, St) => R.drawLiveFrame(te, Fe, Pe, St),
1861
1861
  (te) => T.current?.(te)
1862
1862
  );
1863
1863
  } else if (W.current && b.current) {
@@ -1876,7 +1876,7 @@ const br = vt(function({
1876
1876
  null,
1877
1877
  "__sil__",
1878
1878
  p.current,
1879
- (ee, te, Pe, Oe) => R.drawLiveFrame(ee, te, Pe, Oe),
1879
+ (ee, te, Fe, Pe) => R.drawLiveFrame(ee, te, Fe, Pe),
1880
1880
  (ee) => T.current?.(ee)
1881
1881
  );
1882
1882
  } else
@@ -1893,7 +1893,7 @@ const br = vt(function({
1893
1893
  return V.current = requestAnimationFrame(v), () => {
1894
1894
  cancelAnimationFrame(V.current), F(), f.stop();
1895
1895
  };
1896
- }, [K, Me, H, F]), At(
1896
+ }, [K, Ce, H, F]), At(
1897
1897
  w,
1898
1898
  () => ({
1899
1899
  speakText: async (f, k) => {
@@ -1954,19 +1954,19 @@ const br = vt(function({
1954
1954
  "aria-label": t ? `AI twin ${t}` : "AI twin face"
1955
1955
  }
1956
1956
  ),
1957
- D && pe ? /* @__PURE__ */ je("div", { style: vr, children: pe }) : null
1957
+ D && Ee ? /* @__PURE__ */ je("div", { style: vr, children: Ee }) : null
1958
1958
  ] });
1959
1959
  });
1960
1960
  export {
1961
1961
  br as AiTwin,
1962
- Ue as AiTwinNotFoundError,
1963
- lt as DEFAULT_TTS_ENGINE_ID,
1962
+ Le as AiTwinNotFoundError,
1963
+ ce as DEFAULT_TTS_ENGINE_ID,
1964
1964
  on as OCULUS_VISEME_IDS,
1965
1965
  In as SPEAKING_RATE_MAX,
1966
1966
  vn as SPEAKING_RATE_MIN,
1967
- De as TTS_ENGINE_CARTESIA,
1968
- ce as TTS_ENGINE_GOOGLE,
1969
- be as TTS_ENGINE_INWORLD,
1967
+ pe as TTS_ENGINE_CARTESIA,
1968
+ lt as TTS_ENGINE_GOOGLE,
1969
+ qe as TTS_ENGINE_INWORLD,
1970
1970
  Rr as VISEME_IDS,
1971
1971
  An as VISEME_TEST_CARTESIA_VOICE_ID,
1972
1972
  _t as VISEME_TEST_SPEAKING_RATE,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@streamoji/aitwin",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "Embeddable React AI twin face with TTS lipsync",
5
5
  "type": "module",
6
6
  "main": "./dist/aitwin.cjs",