@streamoji/aitwin 0.5.8 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/aitwin.cjs CHANGED
@@ -1,8 +1,8 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const F=require("react/jsx-runtime"),h=require("react"),Ni=require("@pipecat-ai/client-js"),Rn=require("@pipecat-ai/websocket-transport"),we=require("pixi.js");var pn=typeof document<"u"?document.currentScript:null;const Vi="https://aitwin.bubu.social",Lr={publicBase:Vi},Ui="0.5.8",Wi={version:Ui},zi={},ot="https://ai.aitwin.me",Cn=`${Lr.publicBase}/custom-faces`,Hi=`${Lr.publicBase}/aitwin-workers/v${Wi.version}/visemeDiffPreview.worker.js`;function $i(e){if(e)return e;const t=typeof{url:typeof document>"u"?require("url").pathToFileURL(__filename).href:pn&&pn.tagName.toUpperCase()==="SCRIPT"&&pn.src||new URL("aitwin.cjs",document.baseURI).href}<"u"?zi?.VITE_AITWIN_WORKER_URL:void 0;return t?.trim()?t.trim():Hi}const ji="https://us-central1-streamoji-265f4.cloudfunctions.net/getAiTwin",gn=3e3,Mt=16,ar=3e3,Ki=4e3,qi=.85,Gi=8,Dn=400,Bn="eng_a7f2b9c1",tn="eng_d4e8f3a2",ct="eng_c9b1e6d4",st=ct,Or=new Set([tn,ct]),Nr={[Bn]:"oculus_direct",[ct]:"oculus_direct",[tn]:"inworld_word"},or={google:Bn,inworld:tn,cartesia:ct};function Vr(e){return Nr[e]}function Yi(e){return e===ct}function Qi(e){if(e.ttsEngineId&&e.ttsEngineId in Nr)return e.ttsEngineId;const t=e.tts?.toLowerCase();return t&&t in or?or[t]:st}class Gt extends Error{constructor(t="AI twin not found"){super(t),this.name="AiTwinNotFoundError"}}async function Ur(e,t=ji){const n=new URL(t);n.searchParams.set("id",e);const r=await fetch(n.toString());if(r.status===404)throw new Gt;if(!r.ok)throw new Error(`getAiTwin failed (${r.status})`);const i=await r.json();if(!i.success)throw new Gt(i.error??"AI twin not found");const{tts:s,token:o,...a}=i.data,l=String(a.authToken??o??"").trim()||void 0;return{...a,ttsEngineId:Qi(i.data),authToken:l}}const Xi="https://us-central1-streamoji-265f4.cloudfunctions.net/getAuthToken",Ji="client_6TNvp3SCs4Og0a1ijm9TommXLql1",Zi="kk8Fq8EmexzP10jMIEwY3R44M5RKUEm1",es="6TNvp3SCs4Og0a1ijm9TommXLql1",ts="Swaraj Mali";async function Pt(){const e=await fetch(Xi,{method:"POST",headers:{"Content-Type":"application/json","Client-Id":Ji,"Client-Secret":Zi},body:JSON.stringify({userId:es,userName:ts})});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 ns(e,t=ot){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 rs(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 zt(e){return Uint8Array.from(e)}function is(e,t){const n=new Uint8Array(e.length+t.length);return n.set(e,0),n.set(t,e.length),n}async function ss(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=zt(n.subarray(0,12)),i=zt(n.subarray(12,28)),s=zt(n.subarray(28)),o=zt(is(s,i)),a=await crypto.subtle.importKey("raw",rs(t),{name:"AES-GCM"},!1,["decrypt"]);return crypto.subtle.decrypt({name:"AES-GCM",iv:r,tagLength:128},a,o)}let bn=null;const Tn=new Set;function Ht(e){return e.includes("/custom-faces/")}function Yt(e){const t=e.binBase.trim().replace(/\/$/,""),n=e.twinBase.trim().replace(/\/$/,"");if(!(e.encrypted||Ht(t)||Ht(n)))return{twinBase:n,binBase:t,encrypted:!1};const i=Ht(t)?t:Ht(n)?n:t;return{twinBase:i,binBase:i,encrypted:!0}}function ut(e){return Yt(e).encrypted}function kn(e,t=Cn){const n=`${t.replace(/\/$/,"")}/${e}`;return{twinBase:n,binBase:n,encrypted:!0}}function Wr(e,t){return(e??t)?.trim()||void 0}function zr(e){bn=Yt(e);for(const t of Tn)t()}function as(e,t){const n=typeof globalThis.location<"u"?globalThis.location.href:void 0;if(!n)return Yt(e);const r=i=>{try{return new URL(i,n).href.replace(/\/$/,"")}catch{return i}};return Yt({twinBase:r(e.twinBase),binBase:r(e.binBase),encrypted:e.encrypted})}function lt(){if(!bn)throw new Error("Twin assets not configured; call setActiveTwinAssets first");return bn}function Hr(e){return Tn.add(e),()=>Tn.delete(e)}function Qt(){const e=lt();return ut(e)?`${e.binBase}/sil.bin`:`${e.twinBase}/sil.png`}function os(){const e=lt();return ut(e)?`${e.binBase}/idle.bin`:`${e.twinBase}/idle.mp4`}function $r(){const e=lt();return ut(e)?e.binBase:e.twinBase}function Dt(){return ut(lt())}function jr(){const e=lt();return ut(e)?`${e.binBase}/atlas.bin`:`${e.twinBase}/atlas.json`}function Kr(){const e=lt();return ut(e)?`${e.binBase}/expression_atlas.bin`:`${e.twinBase}/expression_atlas.json`}function qr(e){const t=e.split(/\r?\n/);let n="",r="";for(const s of t)s.startsWith("event:")?n=s.slice(6).trim():s.startsWith("data:")&&(r=s.slice(5).trim());if(!n)return null;let i={};if(r)try{i=JSON.parse(r)}catch{i={raw:r}}return{event:n,data:i}}const Gr=["aa","CH","DD","E","FF","I","O","PP","RR","SS","TH","U","kk","nn","sil"],cs=new Map(Gr.map(e=>[e.toLowerCase(),e]));function nn(e){const t=(e??"").trim();return t?cs.get(t.toLowerCase())??"sil":"sil"}const us={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 ls(e){if(!e)return["sil"];const t=e.toLowerCase();return us[t]??["sil"]}function Yr(e,t){const n=e.word.length;if(n<=0)return 0;const r=e.wduration;if(r<=0)return 0;const i=Math.max(0,Math.min(1,(t-e.wtime)/r));return Math.min(n-1,Math.floor(i*n))}function yt(e,t){const n=Math.max(0,Math.min(e.length-1,t));return e[n]??""}function rn(e,t){const n=e.toLowerCase().replace(/[^a-z']/g,"");return!n||yt(n,t)!=="w"||t>0&&yt(n,t-1)==="q"?!1:t===0&&/^w[aeiouy]/.test(n)}function fs(e,t){const n=e.toLowerCase(),r=yt(n,t),i=n.slice(Math.max(0,t-1),t+2);return r==="i"||r==="y"?"I":i.includes("ee")||r==="e"||n.includes("ea")?"E":"aa"}function ds(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";if(rn(n,t))return"FF";const i=yt(n,t);return i==="u"||i==="w"?"U":"O"}function ms(e,t){const n=e.toLowerCase();if(rn(n,t))return"FF";const r=n.slice(Math.max(0,t-2),t+1);if(/qu/.test(r))return"U";const i=n.slice(Math.max(0,t-1),Math.min(n.length,t+3));return/wo|wh/.test(i)||yt(n,t)==="o"?"O":"U"}const $t={d:"DD",t:"DD",n:"DD",s:"SS",z:"SS",k:"kk",g:"kk",c:"CH",x:"CH",j:"CH"};function hs(e,t){const n=e.toLowerCase(),r=yt(n,t);if($t[r])return $t[r];for(let i=0;i<n.length;i++){const s=n[i];if($t[s])return $t[s]}return"DD"}function Qr(e,t,n){const r=ls(e);if(r.length===1)return r[0];const i=t.trim();if(!i)return r[0];const s=(e??"").toLowerCase(),o=Math.max(0,n);switch(s){case"aei":return fs(i,o);case"o":return ds(i,o);case"qw":return ms(i,o);case"cdgknstxyz":return hs(i,o);default:return r[0]}}const Fn=16,xn=47,Xr=new Set(["aa","E","I"]),Jr=new Set(["DD","SS","kk","CH"]),ws=[Xr,Jr];function ps(e){for(const t of ws)if(t.has(e))return t;return null}function gs(e){return ps(e)!=null}function Zr(e,t=Fn){return t<=0?e:Math.round(e/t)*t}function Ln(e,t=Fn){return e.map(n=>({...n,vtime:Zr(n.vtime,t)}))}function ei(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 On(e){if(e.length<=2)return[...e];const t=[e[0]];for(let n=1;n<e.length-1;n++){const r=e[n],i=e[n+1],s=t[t.length-1];if(!gs(r.viseme)){t.push(r);continue}const o=r.vtime-s.vtime,a=i.vtime-r.vtime;o<xn||a<xn||t.push(r)}return t.push(e[e.length-1]),t}function sn(e){return On(ei(Ln(e)))}function ti(e,t){let n="sil";for(const r of e){if(r.vtime>t)break;r.viseme!=="sil"&&(n=r.viseme)}return n}function an(e){const t=ei(Ln(e)),n=On(t),r=new Set(n.map(s=>s.vtime)),i=[];for(const s of t)r.has(s.vtime)||i.push({viseme:s.viseme,vtime:s.vtime});return i}function ys(e){return an(e).map(t=>t.viseme)}const _s=32,cr=48;function ni(e){let t=0;for(const n of e)t=Math.max(t,n.vtime+n.vduration);return t}function ri(e){let t=null,n=-1;for(const r of e){if(r.viseme==="sil")continue;const i=r.vtime+r.vduration;i>n&&(t=r,n=i)}return t}function vs(e){return sn(e).find(n=>n.viseme!=="sil")??null}function rt(e){const t=ni(e);return ri(e)?t+Dn:t}function Ss(e){const t=[],n=vs(e);n&&n.vtime>0&&t.push({from:"sil",to:n.viseme,fromVtime:0,toVtime:n.vtime});const r=ri(e),i=ni(e);return r&&t.push({from:r.viseme,to:"sil",fromVtime:i,toVtime:i+Dn}),t}function ii(e){const t=sn(e),n=[];for(let r=0;r<t.length-1;r++){const i=t[r].viseme,s=t[r+1].viseme,o=t[r].vtime,a=t[r+1].vtime;i===s||a<=o||n.push({from:i,to:s,fromVtime:o,toVtime:a})}return n}function si(e){return e.length===0?[]:[...Ss(e),...ii(e)]}function bs(e,t){let n=null;for(const r of e){const{transStart:i,transEnd:s}=ai(r.fromVtime,r.toVtime,r.from,r.to);t>=i&&t<s&&(n=r)}return n}function ai(e,t,n,r){const i=Math.max(0,t-e);if((n==="PP"||r==="PP")&&i>cr){const f=cr,u=t,c=u-f;return{gapMs:i,effectiveGapMs:f,holdEnd:c,transStart:c,transEnd:u}}const o=i>0?Math.max(i,_s):0,a=e,l=e+o;return{gapMs:i,effectiveGapMs:o,holdEnd:e,transStart:a,transEnd:l}}function oi(e,t,n,r,i,s){r.forEach(o=>{const l=String(o.word??"").trim();if(!l)return;const f=Math.round((o.start??0)*1e3),u=o.duration!=null?Math.round(o.duration*1e3):o.end!=null?Math.max(1,Math.round((o.end-(o.start??0))*1e3)):0;t.push({word:l,wtime:i+f,wduration:u,queueIndex:t.length,gesture:o.gesture??null,emphasis:o.emphasis===!0})}),n.forEach(o=>{const a=String(o.symbol??o.viseme??"").trim();if(!a)return;const l=Math.round((o.start??0)*1e3),f=Math.max(1,Math.round((o.duration??0)*1e3)),u=i+l,c=li(t,u),d=c?Yr(c,u):0;let p;Vr(s)==="oculus_direct"?(p=nn(a),p==="U"&&c&&rn(c.word,d)&&(p="FF")):p=Qr(a,c?.word??"",d),e.push({viseme:p,weight:1,vtime:u,vduration:f})})}function ci(e,t){let n=t;for(const r of e){const i=Math.round((r.start??0)*1e3),s=Math.max(1,Math.round((r.duration??0)*1e3));n=Math.max(n,t+i+s)}return n}const Nn=16e3;function ui(e){const t=Number(e);return Number.isFinite(t)&&t>0?t:Nn}function Ts(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}function ks(e){return e.length>=4&&e[0]===82&&e[1]===73&&e[2]===70&&e[3]===70}function ur(e,t,n=Nn){const r=t.byteOffset%2===0?t:t.slice(),i=new Int16Array(r.buffer,r.byteOffset,r.byteLength/2),s=new Float32Array(i.length);for(let a=0;a<i.length;a++)s[a]=i[a]>=32768?-(65536-i[a])/32768:i[a]/32767;const o=e.createBuffer(1,s.length,n);return o.copyToChannel(s,0),o}function xs(e){const t=Ts(e),n=window.atob(t),r=new Uint8Array(n.length);for(let i=0;i<n.length;i++)r[i]=n.charCodeAt(i);return r}async function lr(e,t,n=Nn){const r=xs(t),i=ui(n);if(ks(r)){const s=r.buffer.slice(r.byteOffset,r.byteOffset+r.byteLength);return e.decodeAudioData(s)}if(r.length>=2&&r.length%2===0)return ur(e,r,i);try{const s=r.buffer.slice(r.byteOffset,r.byteOffset+r.byteLength);return await e.decodeAudioData(s)}catch{return ur(e,r,i)}}function li(e,t){for(const n of e)if(t>=n.wtime&&t<n.wtime+n.wduration)return n;return null}function fi(e,t){const n=[],r=[];let i=null,s=!1,o=!1,a=!1,l=!1,f=0,u=0,c=0,d=null,p=1,T=t,m=!1,E=null,R=0,P=!1,g=!1,x=0,L=null,A=null,ne=null;const de=()=>({visemes:[],words:[],segmentOffsetMs:0}),M=()=>{g=!1,x=0},z=()=>{d!=null&&(clearTimeout(d),d=null)},$=()=>{for(const v of r){try{v.onended=null,v.stop(0)}catch{}try{v.disconnect()}catch{}}r.length=0},J=()=>{for(const v of r)v.playbackRate.value=p},Y=()=>{if(!(m||!l||s||g||r.length>0||n.length>0)){if(a&&i&&u>0){const v=(i.currentTime-u)*1e3;if(v<R){z();const O=p>0?(R-v)/p:R-v;d=setTimeout(()=>{m||(o=!1,d=null,e.onSpeakingDone(),e.onNotify())},Math.max(0,O));return}}o=!1,z(),e.onSpeakingDone(),e.onNotify()}},me=v=>{const O=rt(v);if(O<=0){e.onSpeakingDone(),e.onNotify();return}o=!0,f=performance.now(),e.onSpeakingStart(),e.onNotify(),z();const H=p>0?O/p:O;d=setTimeout(()=>{m||(o=!1,d=null,e.onSpeakingDone(),e.onNotify())},H)},K=(v,O,H,X)=>{O.length!==0&&(c=H,O.forEach(N=>{const b=String(N.word??"").trim();if(!b)return;const S=Math.round((N.start??0)*1e3),k=N.duration!=null?Math.round(N.duration*1e3):N.end!=null?Math.max(1,Math.round((N.end-(N.start??0))*1e3)):0;v.push({word:b,wtime:c+S,wduration:k,queueIndex:v.length,gesture:N.gesture??null,emphasis:N.emphasis===!0})}))},ee=(v,O,H,X,N,j)=>{H.length!==0&&(c=X,H.forEach(b=>{const S=String(b.symbol??b.viseme??"").trim();if(!S)return;const k=Math.round((b.start??0)*1e3),y=Math.max(1,Math.round((b.duration??0)*1e3)),V=c+k,Z=li(O,V),_e=Z?Yr(Z,V):0;let ve;Vr(j)==="oculus_direct"?(ve=nn(S),ve==="U"&&Z&&rn(Z.word,_e)&&(ve="FF")):ve=Qr(S,Z?.word??"",_e),v.push({viseme:ve,weight:1,vtime:V,vduration:y})}),e.onNotify())},I=(v,O,H,X,N,j,b)=>{K(O,X,N),ee(v,O,H,N,j,b)},G=(v,O,H)=>{ne===v&&v.visemes===O||(O.length=0,H.length=0,v.visemes=O,v.words=H,v.segmentOffsetMs=0,ne=v,c=0,R=0)},U=async()=>{const v=window.AudioContext||window.webkitAudioContext;return i||(i=new v),i.state==="suspended"&&await i.resume(),E||(E=i.createMediaStreamDestination()),i},ue=(v,O)=>{if(!i)return 0;const H=i,X=H.currentTime,N=X+.02;if(O.isFirstAudio){u<=0&&(u=N);const b=(N-X)*1e3;f=performance.now()+b}O.onBeforeStart?.(N);const j=H.createBufferSource();return j.buffer=v,j.playbackRate.value=p,j.connect(H.destination),E&&j.connect(E),r.push(j),m?(r.pop(),N):(O.isFirstAudio&&(o=!0,e.onSpeakingStart()),j.onended=()=>{const b=r.indexOf(j);b>=0&&r.splice(b,1),e.onNotify(),!m&&(L&&A?re(L,A):Y())},j.start(N),N)},re=async(v,O)=>{if(m||s||r.length>0)return;if(n.length===0){Y();return}s=!0;let H=!1;try{const X=await U();if(m)return;const N=n[0];if(!N)return;const j=!o;if(P&&(e.shouldHoldForWarmup?.()??!1)&&(g||j&&N.newStream)||g){G(N.utterance,v,O);for(const k of n){if(m)return;k.audioBuffer||(k.audioBuffer=await lr(X,k.audio,k.sampleRate)),a=!0,g||(g=!0,x=0,k.newStream&&k.onNewStream?.()),k.visemesQueued||(I(v,O,k.visemes,k.words,x,!0,T),k.visemesQueued=!0,x+=Math.round(k.audioBuffer.duration*1e3),R=Math.max(R,rt(v)))}e.onNotify();return}const S=n.shift();if(!S||(S.audioBuffer||(S.audioBuffer=await lr(X,S.audio,S.sampleRate)),m))return;a=!0,z(),G(S.utterance,v,O),S.visemesQueued=!1,S.newStream&&S.onNewStream?.(),ue(S.audioBuffer,{isFirstAudio:!o,isFirstOfStream:!1,onBeforeStart:k=>{u=k,c=0,f=performance.now()+(k-X.currentTime)*1e3,v.length=0,O.length=0,I(v,O,S.visemes,S.words,0,!0,T),S.visemesQueued=!0,S.utterance.segmentOffsetMs=0}}),H=r.length>0,R=rt(v),e.onNotify()}catch(X){console.error("[avatarChunkPlayback] audio chunk failed:",X)}finally{if(s=!1,m)return;if(g){n.some(N=>!N.audioBuffer||!N.visemesQueued)&&re(v,O);return}!H&&r.length===0&&n.length>0?re(v,O):r.length===0&&n.length===0&&Y()}};return{setStreamTtsEngineId:v=>{T=v},setPlaybackSpeed:v=>{p=Math.max(.1,Math.min(1,v)),J()},getPlaybackSpeed:()=>p,setLipsyncWarmupHoldEnabled:v=>{P=v,v||M()},isWarmingUp:()=>g,releaseWarmupHold:()=>{if(g){g=!1,x=0;for(const v of n)v.newStream=!1;L&&A&&re(L,A),e.onNotify()}},resetForNewStream:v=>{m=!1,l=!1,T=v,R=0},resumeBotStream:()=>{m=!1,l=!1},clearAborted:()=>{m=!1},primeAudioContext:async()=>{const v=window.AudioContext||window.webkitAudioContext;i||(i=new v),i.state==="suspended"&&await i.resume(),i&&!E&&(E=i.createMediaStreamDestination())},stop:()=>{m=!0,z(),$(),n.length=0,s=!1,o=!1,a=!1,l=!1,c=0,u=0,f=0,R=0,L=null,A=null,ne=null,M()},markStreamComplete:v=>{if(R=Math.max(R,rt(v)),l=!0,!a&&v.length>0){me(v);return}Y()},playAudioChunk:async(v,O,H,X,N,j,b)=>{if(m)return;L=v,A=O;const S=ui(b?.sampleRate),k=b?.newStream===!0,y=de();if(!H?.trim()){if(X.length===0&&N.length===0)return;G(y,v,O),k&&b?.onNewStream?.(),I(v,O,X,N,0,!0,T),R=rt(v),!o&&R>0&&me(v),e.onNotify();return}n.push({audio:H,audioBuffer:null,utterance:y,visemes:X,words:N,isNewSegment:j,sampleRate:S,newStream:k,onNewStream:b?.onNewStream,visemesQueued:!1}),await re(v,O)},queueTimingsOnly:(v,O,H,X,N,j)=>{if(m)return;const b=de();G(b,v,O),I(v,O,H,X,0,!0,T),b.segmentOffsetMs=0,R=rt(v)},getPlaybackElapsedMs:()=>a&&i&&u>0?Math.max(0,(i.currentTime-u)*1e3*p):o?Math.max(0,(performance.now()-f)*p):0,isSpeaking:()=>o?!0:!a||!i||u<=0?!1:(i.currentTime-u)*1e3<R,getVoiceStream:()=>E?E.stream:null,getPlaybackStartPerf:()=>f,bargeIn:()=>{m=!0,l=!1,z(),$(),n.length=0,s=!1,o=!1,a=!1,c=0,u=0,f=0,R=0,L=null,A=null,ne=null,M()},interrupt:()=>{m=!0,l=!1,z(),$(),n.length=0,s=!1,o=!1,a=!1,c=0,u=0,f=0,R=0,L=null,A=null,ne=null,M()}}}function Bt(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 di(e,t,n=120){const r=Bt(e,t);if(r!=="sil")return r;let i=null;for(const s of e){if(s.vtime>t)break;const o=s.vtime+s.vduration;o<=t&&t-o<=n&&(i=s)}return i?.viseme??"sil"}function Es(e,t,n=400){const r=t-n;let i=0;for(const s of e)if(s.vtime+s.vduration<r)i+=1;else break;i>0&&e.splice(0,i)}function Is(e,t){for(const n of e)if(t>=n.wtime&&t<n.wtime+n.wduration)return n;return null}function fr(e,t){const n=e.trim();if(!n)return null;try{const r=n.replace(/\s+/g,""),i=atob(r).length,s=Number.isFinite(t)&&(t??0)>0?Number(t):16e3;return i/2/s*1e3}catch{return null}}const on=.5,cn=1.5,Vn="Olivia",Un="f786b574-daa5-4673-aa0c-cbe3e8534c02",Ft=.85;function En(e,t=ot,n={}){const r=`${t.replace(/\/$/,"")}/avatar_ttsWithPoses`,i=[],s=[],o=[],a=[];let l=0;const f=[],u=[];let c="",d="neutral",p="",T=st;const m=new Set;let E=0,R=null,P=0,g=null;const x=()=>m.forEach(K=>K());let L=()=>!1;const A=fi({onSpeakingStart:()=>e("speaking"),onSpeakingDone:()=>e("done"),onNotify:x,shouldHoldForWarmup:()=>L()},st),ne=()=>A.getPlaybackElapsedMs(),de=(K,ee=c)=>{if(!n.onLipsyncDebug)return;const I=ne(),G=i,U=an(o).map(ue=>({viseme:ue.viseme,vtimeMs:ue.vtime}));n.onLipsyncDebug({event:K,spokenText:ee,mood:d,playbackAnchorPerf:A.getPlaybackStartPerf(),playbackElapsedMs:I,queueLength:G.length,activeViseme:Bt(G,I),segments:u.map(ue=>({...ue,visemes:[...ue.visemes]})),fullQueueLength:o.length,compactionSkipped:U})},M=(K,ee)=>{n.onLipsyncDebug&&(R={event:K,spokenText:ee},E===0&&(E=requestAnimationFrame(()=>{E=0;const I=R;R=null,I&&de(I.event,I.spokenText)})))},z=(K,ee,I,G,U)=>{if(!n.onLipsyncDebug)return;const ue=i.slice(ee),re=I.filter(oe=>String(oe.symbol??oe.viseme??"").trim());u.push({spokenText:K,audioOffsetMs:ue[0]?.vtime??0,isNewSegment:G,chunkDurationMs:U,receivedAtMs:performance.now(),visemes:ue.map((oe,pe)=>{const ie=re[pe];return{rawSymbol:String(ie?.symbol??ie?.viseme??oe.viseme).trim(),viseme:oe.viseme,startSec:Number(ie?.start??0),durationSec:Number(ie?.duration??0),vtimeMs:oe.vtime,vdurationMs:oe.vduration}})})},$=()=>{o.length=0,a.length=0,l=0},J=(K,ee,I,G,U)=>{if(K.length===0&&ee.length===0)return;oi(o,a,K,ee,l,U);const ue=ci(K,l),re=I?fr(I,G):null;l=Math.max(ue,re!=null?l+re:l)},Y=()=>{P+=1,g?.abort(),g=null,A.stop(),i.length=0,s.length=0,$(),f.length=0,d="neutral",u.length=0,c="",e("idle"),M("reset"),x()};return{setDeveloperToken:K=>{p=K},setTtsEngineId:K=>{T=K},getTtsEngineId:()=>T,speak:async(K,ee)=>{Y();const I=P;g=new AbortController,e("loading"),c=K,u.length=0,$();const G=p.trim();if(!G)throw new Error("Developer token required for avatar_ttsWithPoses");const U=ee?.ttsEngineId??T??st;A.resetForNewStream(U),A.setStreamTtsEngineId(U);const ue=ee?.voiceId??Vn,re=ee?.speakingRate??Ft,oe=Math.max(on,Math.min(cn,re)),pe={user_query:K,ttsEngineId:U,speakingRate:oe,tenant:"aiTwin"};Or.has(U)&&(pe.voice_id=ue);try{const ie=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${G}`},body:JSON.stringify(pe),signal:g.signal});if(!ie.ok)throw new Error(`avatar_ttsWithPoses failed (${ie.status})`);const v=ie.body;if(!v)throw new Error("No response body");const O=v.getReader(),H=new TextDecoder;let X="",N=!0;const j=async b=>{if(I!==P)return;const S=qr(b);if(S){if(S.event==="audio"){const k=S.data.chunk,y=S.data.visemes??[],V=S.data.words??[],Z=S.data.is_new_segment??!1,_e=S.data.sample_rate,ve=Number(S.data.audio_offset_ms??0),Me=i.length;if(J(y,V,k,_e,U),k){const De=N;N=!1,await A.playAudioChunk(i,s,k,y,V,Z,{sampleRate:_e,newStream:De,audioOffsetMs:ve}),z(K,Me,y,Z,fr(k,_e)),M("audio_chunk",K)}else(y.length>0||V.length>0)&&(A.queueTimingsOnly(i,s,y,V,Z,{audioOffsetMs:ve,newStream:N}),z(K,Me,y,Z,null),M("audio_chunk",K))}else if(S.event==="metadata"){const k=S.data.mood;typeof k=="string"&&k.trim()&&(d=k.trim());const y=S.data.sentence_emotions;if(Array.isArray(y)){f.length=0;for(const V of y){if(!V||typeof V!="object")continue;const Z=V;f.push({sentence_index:Number(Z.sentence_index??0),text:String(Z.text??""),sentiment:typeof Z.sentiment=="string"?Z.sentiment:void 0,emotion:String(Z.emotion??d),start_word:Number(Z.start_word??0),end_word:Number(Z.end_word??0)})}}x(),M("metadata",K)}else if(S.event==="error")throw new Error(String(S.data.message??"avatar_ttsWithPoses stream error"))}};for(;I===P;){const{done:b,value:S}=await O.read();S&&(X+=H.decode(S,{stream:!0}));const k=X.split(`
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const M=require("react/jsx-runtime"),h=require("react"),Gi=require("@pipecat-ai/client-js"),Fn=require("@pipecat-ai/websocket-transport"),we=require("pixi.js");var vn=typeof document<"u"?document.currentScript:null;const Yi="https://aitwin.bubu.social",Hr={publicBase:Yi},Qi="0.6.0",Xi={version:Qi},Ji={},ot="https://ai.aitwin.me",Ln=`${Hr.publicBase}/custom-faces`,Zi=`${Hr.publicBase}/aitwin-workers/v${Xi.version}/visemeDiffPreview.worker.js`;function es(e){if(e)return e;const t=typeof{url:typeof document>"u"?require("url").pathToFileURL(__filename).href:vn&&vn.tagName.toUpperCase()==="SCRIPT"&&vn.src||new URL("aitwin.cjs",document.baseURI).href}<"u"?Ji?.VITE_AITWIN_WORKER_URL:void 0;return t?.trim()?t.trim():Zi}const ts="https://us-central1-streamoji-265f4.cloudfunctions.net/getAiTwin",Sn=3e3,Pt=16,hr=3e3,ns=4e3,rs=.85,is=8,On=400,Nn="eng_a7f2b9c1",an="eng_d4e8f3a2",ct="eng_c9b1e6d4",st=ct,jr=new Set([an,ct]),Kr={[Nn]:"oculus_direct",[ct]:"oculus_direct",[an]:"inworld_word"},wr={google:Nn,inworld:an,cartesia:ct};function qr(e){return Kr[e]}function ss(e){return e===ct}function as(e){if(e.ttsEngineId&&e.ttsEngineId in Kr)return e.ttsEngineId;const t=e.tts?.toLowerCase();return t&&t in wr?wr[t]:st}class Jt extends Error{constructor(t="AI twin not found"){super(t),this.name="AiTwinNotFoundError"}}async function Gr(e,t=ts){const n=new URL(t);n.searchParams.set("id",e);const r=await fetch(n.toString());if(r.status===404)throw new Jt;if(!r.ok)throw new Error(`getAiTwin failed (${r.status})`);const i=await r.json();if(!i.success)throw new Jt(i.error??"AI twin not found");const{tts:s,token:o,...a}=i.data,u=String(a.authToken??o??"").trim()||void 0;return{...a,ttsEngineId:as(i.data),authToken:u}}const Vn="thumbnail.webp";function Yr(e,t=Ln){const n=e.trim();if(!n)throw new Error("faceId is required");return`${t.replace(/\/$/,"")}/${n}/${Vn}`}function pr(e){const t=e?.trim();if(!t)return null;try{return Yr(t)}catch{return null}}function os(e){if(!e)return null;const t=(e.binBase||e.twinBase).trim().replace(/\/$/,"");return t?`${t}/${Vn}`:null}const cs="https://us-central1-streamoji-265f4.cloudfunctions.net/getAuthToken",ls="client_6TNvp3SCs4Og0a1ijm9TommXLql1",us="kk8Fq8EmexzP10jMIEwY3R44M5RKUEm1",fs="6TNvp3SCs4Og0a1ijm9TommXLql1",ds="Swaraj Mali";async function Rt(){const e=await fetch(cs,{method:"POST",headers:{"Content-Type":"application/json","Client-Id":ls,"Client-Secret":us},body:JSON.stringify({userId:fs,userName:ds})});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 ms(e,t=ot){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 hs(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 Kt(e){return Uint8Array.from(e)}function ws(e,t){const n=new Uint8Array(e.length+t.length);return n.set(e,0),n.set(t,e.length),n}async function ps(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=Kt(n.subarray(0,12)),i=Kt(n.subarray(12,28)),s=Kt(n.subarray(28)),o=Kt(ws(s,i)),a=await crypto.subtle.importKey("raw",hs(t),{name:"AES-GCM"},!1,["decrypt"]);return crypto.subtle.decrypt({name:"AES-GCM",iv:r,tagLength:128},a,o)}let En=null;const In=new Set;function qt(e){return e.includes("/custom-faces/")}function Zt(e){const t=e.binBase.trim().replace(/\/$/,""),n=e.twinBase.trim().replace(/\/$/,"");if(!(e.encrypted||qt(t)||qt(n)))return{twinBase:n,binBase:t,encrypted:!1};const i=qt(t)?t:qt(n)?n:t;return{twinBase:i,binBase:i,encrypted:!0}}function lt(e){return Zt(e).encrypted}function An(e,t=Ln){const n=`${t.replace(/\/$/,"")}/${e}`;return{twinBase:n,binBase:n,encrypted:!0}}function Qr(e,t){return(e??t)?.trim()||void 0}function Xr(e){En=Zt(e);for(const t of In)t()}function gs(e,t){const n=typeof globalThis.location<"u"?globalThis.location.href:void 0;if(!n)return Zt(e);const r=i=>{try{return new URL(i,n).href.replace(/\/$/,"")}catch{return i}};return Zt({twinBase:r(e.twinBase),binBase:r(e.binBase),encrypted:e.encrypted})}function ut(){if(!En)throw new Error("Twin assets not configured; call setActiveTwinAssets first");return En}function Jr(e){return In.add(e),()=>In.delete(e)}function en(){const e=ut();return lt(e)?`${e.binBase}/sil.bin`:`${e.twinBase}/sil.png`}function ys(){const e=ut();return lt(e)?`${e.binBase}/idle.bin`:`${e.twinBase}/idle.mp4`}function Zr(){const e=ut();return lt(e)?e.binBase:e.twinBase}function Bt(){return lt(ut())}function ei(){const e=ut();return lt(e)?`${e.binBase}/atlas.bin`:`${e.twinBase}/atlas.json`}function ti(){const e=ut();return lt(e)?`${e.binBase}/expression_atlas.bin`:`${e.twinBase}/expression_atlas.json`}function ni(e){const t=e.split(/\r?\n/);let n="",r="";for(const s of t)s.startsWith("event:")?n=s.slice(6).trim():s.startsWith("data:")&&(r=s.slice(5).trim());if(!n)return null;let i={};if(r)try{i=JSON.parse(r)}catch{i={raw:r}}return{event:n,data:i}}const ri=["aa","CH","DD","E","FF","I","O","PP","RR","SS","TH","U","kk","nn","sil"],_s=new Map(ri.map(e=>[e.toLowerCase(),e]));function on(e){const t=(e??"").trim();return t?_s.get(t.toLowerCase())??"sil":"sil"}const vs={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 Ss(e){if(!e)return["sil"];const t=e.toLowerCase();return vs[t]??["sil"]}function ii(e,t){const n=e.word.length;if(n<=0)return 0;const r=e.wduration;if(r<=0)return 0;const i=Math.max(0,Math.min(1,(t-e.wtime)/r));return Math.min(n-1,Math.floor(i*n))}function St(e,t){const n=Math.max(0,Math.min(e.length-1,t));return e[n]??""}function cn(e,t){const n=e.toLowerCase().replace(/[^a-z']/g,"");return!n||St(n,t)!=="w"||t>0&&St(n,t-1)==="q"?!1:t===0&&/^w[aeiouy]/.test(n)}function bs(e,t){const n=e.toLowerCase(),r=St(n,t),i=n.slice(Math.max(0,t-1),t+2);return r==="i"||r==="y"?"I":i.includes("ee")||r==="e"||n.includes("ea")?"E":"aa"}function Ts(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";if(cn(n,t))return"FF";const i=St(n,t);return i==="u"||i==="w"?"U":"O"}function ks(e,t){const n=e.toLowerCase();if(cn(n,t))return"FF";const r=n.slice(Math.max(0,t-2),t+1);if(/qu/.test(r))return"U";const i=n.slice(Math.max(0,t-1),Math.min(n.length,t+3));return/wo|wh/.test(i)||St(n,t)==="o"?"O":"U"}const Gt={d:"DD",t:"DD",n:"DD",s:"SS",z:"SS",k:"kk",g:"kk",c:"CH",x:"CH",j:"CH"};function xs(e,t){const n=e.toLowerCase(),r=St(n,t);if(Gt[r])return Gt[r];for(let i=0;i<n.length;i++){const s=n[i];if(Gt[s])return Gt[s]}return"DD"}function si(e,t,n){const r=Ss(e);if(r.length===1)return r[0];const i=t.trim();if(!i)return r[0];const s=(e??"").toLowerCase(),o=Math.max(0,n);switch(s){case"aei":return bs(i,o);case"o":return Ts(i,o);case"qw":return ks(i,o);case"cdgknstxyz":return xs(i,o);default:return r[0]}}const Un=16,Mn=47,ai=new Set(["aa","E","I"]),oi=new Set(["DD","SS","kk","CH"]),Es=[ai,oi];function Is(e){for(const t of Es)if(t.has(e))return t;return null}function As(e){return Is(e)!=null}function ci(e,t=Un){return t<=0?e:Math.round(e/t)*t}function Wn(e,t=Un){return e.map(n=>({...n,vtime:ci(n.vtime,t)}))}function li(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 zn(e){if(e.length<=2)return[...e];const t=[e[0]];for(let n=1;n<e.length-1;n++){const r=e[n],i=e[n+1],s=t[t.length-1];if(!As(r.viseme)){t.push(r);continue}const o=r.vtime-s.vtime,a=i.vtime-r.vtime;o<Mn||a<Mn||t.push(r)}return t.push(e[e.length-1]),t}function ln(e){return zn(li(Wn(e)))}function ui(e,t){let n="sil";for(const r of e){if(r.vtime>t)break;r.viseme!=="sil"&&(n=r.viseme)}return n}function un(e){const t=li(Wn(e)),n=zn(t),r=new Set(n.map(s=>s.vtime)),i=[];for(const s of t)r.has(s.vtime)||i.push({viseme:s.viseme,vtime:s.vtime});return i}function Ms(e){return un(e).map(t=>t.viseme)}const Ps=32,gr=48;function fi(e){let t=0;for(const n of e)t=Math.max(t,n.vtime+n.vduration);return t}function di(e){let t=null,n=-1;for(const r of e){if(r.viseme==="sil")continue;const i=r.vtime+r.vduration;i>n&&(t=r,n=i)}return t}function Rs(e){return ln(e).find(n=>n.viseme!=="sil")??null}function rt(e){const t=fi(e);return di(e)?t+On:t}function Cs(e){const t=[],n=Rs(e);n&&n.vtime>0&&t.push({from:"sil",to:n.viseme,fromVtime:0,toVtime:n.vtime});const r=di(e),i=fi(e);return r&&t.push({from:r.viseme,to:"sil",fromVtime:i,toVtime:i+On}),t}function mi(e){const t=ln(e),n=[];for(let r=0;r<t.length-1;r++){const i=t[r].viseme,s=t[r+1].viseme,o=t[r].vtime,a=t[r+1].vtime;i===s||a<=o||n.push({from:i,to:s,fromVtime:o,toVtime:a})}return n}function hi(e){return e.length===0?[]:[...Cs(e),...mi(e)]}function Ds(e,t){let n=null;for(const r of e){const{transStart:i,transEnd:s}=wi(r.fromVtime,r.toVtime,r.from,r.to);t>=i&&t<s&&(n=r)}return n}function wi(e,t,n,r){const i=Math.max(0,t-e);if((n==="PP"||r==="PP")&&i>gr){const f=gr,l=t,c=l-f;return{gapMs:i,effectiveGapMs:f,holdEnd:c,transStart:c,transEnd:l}}const o=i>0?Math.max(i,Ps):0,a=e,u=e+o;return{gapMs:i,effectiveGapMs:o,holdEnd:e,transStart:a,transEnd:u}}function pi(e,t,n,r,i,s){r.forEach(o=>{const u=String(o.word??"").trim();if(!u)return;const f=Math.round((o.start??0)*1e3),l=o.duration!=null?Math.round(o.duration*1e3):o.end!=null?Math.max(1,Math.round((o.end-(o.start??0))*1e3)):0;t.push({word:u,wtime:i+f,wduration:l,queueIndex:t.length,gesture:o.gesture??null,emphasis:o.emphasis===!0})}),n.forEach(o=>{const a=String(o.symbol??o.viseme??"").trim();if(!a)return;const u=Math.round((o.start??0)*1e3),f=Math.max(1,Math.round((o.duration??0)*1e3)),l=i+u,c=_i(t,l),d=c?ii(c,l):0;let p;qr(s)==="oculus_direct"?(p=on(a),p==="U"&&c&&cn(c.word,d)&&(p="FF")):p=si(a,c?.word??"",d),e.push({viseme:p,weight:1,vtime:l,vduration:f})})}function gi(e,t){let n=t;for(const r of e){const i=Math.round((r.start??0)*1e3),s=Math.max(1,Math.round((r.duration??0)*1e3));n=Math.max(n,t+i+s)}return n}const $n=16e3;function yi(e){const t=Number(e);return Number.isFinite(t)&&t>0?t:$n}function Bs(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}function Fs(e){return e.length>=4&&e[0]===82&&e[1]===73&&e[2]===70&&e[3]===70}function yr(e,t,n=$n){const r=t.byteOffset%2===0?t:t.slice(),i=new Int16Array(r.buffer,r.byteOffset,r.byteLength/2),s=new Float32Array(i.length);for(let a=0;a<i.length;a++)s[a]=i[a]>=32768?-(65536-i[a])/32768:i[a]/32767;const o=e.createBuffer(1,s.length,n);return o.copyToChannel(s,0),o}function Ls(e){const t=Bs(e),n=window.atob(t),r=new Uint8Array(n.length);for(let i=0;i<n.length;i++)r[i]=n.charCodeAt(i);return r}async function _r(e,t,n=$n){const r=Ls(t),i=yi(n);if(Fs(r)){const s=r.buffer.slice(r.byteOffset,r.byteOffset+r.byteLength);return e.decodeAudioData(s)}if(r.length>=2&&r.length%2===0)return yr(e,r,i);try{const s=r.buffer.slice(r.byteOffset,r.byteOffset+r.byteLength);return await e.decodeAudioData(s)}catch{return yr(e,r,i)}}function _i(e,t){for(const n of e)if(t>=n.wtime&&t<n.wtime+n.wduration)return n;return null}function vi(e,t){const n=[],r=[];let i=null,s=!1,o=!1,a=!1,u=!1,f=0,l=0,c=0,d=null,p=1,T=t,m=!1,E=null,C=0,P=!1,_=!1,x=0,O=null,A=null,ie=null;const me=()=>({visemes:[],words:[],segmentOffsetMs:0}),I=()=>{_=!1,x=0},V=()=>{d!=null&&(clearTimeout(d),d=null)},G=()=>{for(const S of r){try{S.onended=null,S.stop(0)}catch{}try{S.disconnect()}catch{}}r.length=0},se=()=>{for(const S of r)S.playbackRate.value=p},te=()=>{if(!(m||!u||s||_||r.length>0||n.length>0)){if(a&&i&&l>0){const S=(i.currentTime-l)*1e3;if(S<C){V();const R=p>0?(C-S)/p:C-S;d=setTimeout(()=>{m||(o=!1,d=null,e.onSpeakingDone(),e.onNotify())},Math.max(0,R));return}}o=!1,V(),e.onSpeakingDone(),e.onNotify()}},re=S=>{const R=rt(S);if(R<=0){e.onSpeakingDone(),e.onNotify();return}o=!0,f=performance.now(),e.onSpeakingStart(),e.onNotify(),V();const ne=p>0?R/p:R;d=setTimeout(()=>{m||(o=!1,d=null,e.onSpeakingDone(),e.onNotify())},ne)},L=(S,R,ne,ee)=>{R.length!==0&&(c=ne,R.forEach(H=>{const v=String(H.word??"").trim();if(!v)return;const g=Math.round((H.start??0)*1e3),k=H.duration!=null?Math.round(H.duration*1e3):H.end!=null?Math.max(1,Math.round((H.end-(H.start??0))*1e3)):0;S.push({word:v,wtime:c+g,wduration:k,queueIndex:S.length,gesture:H.gesture??null,emphasis:H.emphasis===!0})}))},le=(S,R,ne,ee,H,W)=>{ne.length!==0&&(c=ee,ne.forEach(v=>{const g=String(v.symbol??v.viseme??"").trim();if(!g)return;const k=Math.round((v.start??0)*1e3),b=Math.max(1,Math.round((v.duration??0)*1e3)),$=c+k,q=_i(R,$),X=q?ii(q,$):0;let oe;qr(W)==="oculus_direct"?(oe=on(g),oe==="U"&&q&&cn(q.word,X)&&(oe="FF")):oe=si(g,q?.word??"",X),S.push({viseme:oe,weight:1,vtime:$,vduration:b})}),e.onNotify())},z=(S,R,ne,ee,H,W,v)=>{L(R,ee,H),le(S,R,ne,H,W,v)},pe=(S,R,ne)=>{ie===S&&S.visemes===R||(R.length=0,ne.length=0,S.visemes=R,S.words=ne,S.segmentOffsetMs=0,ie=S,c=0,C=0)},N=async()=>{const S=window.AudioContext||window.webkitAudioContext;return i||(i=new S),i.state==="suspended"&&await i.resume(),E||(E=i.createMediaStreamDestination()),i},Q=(S,R)=>{if(!i)return 0;const ne=i,ee=ne.currentTime,H=ee+.02;if(R.isFirstAudio){l<=0&&(l=H);const v=(H-ee)*1e3;f=performance.now()+v}R.onBeforeStart?.(H);const W=ne.createBufferSource();return W.buffer=S,W.playbackRate.value=p,W.connect(ne.destination),E&&W.connect(E),r.push(W),m?(r.pop(),H):(R.isFirstAudio&&(o=!0,e.onSpeakingStart()),W.onended=()=>{const v=r.indexOf(W);v>=0&&r.splice(v,1),e.onNotify(),!m&&(O&&A?j(O,A):te())},W.start(H),H)},j=async(S,R)=>{if(m||s||r.length>0)return;if(n.length===0){te();return}s=!0;let ne=!1;try{const ee=await N();if(m)return;const H=n[0];if(!H)return;const W=!o;if(P&&(e.shouldHoldForWarmup?.()??!1)&&(_||W&&H.newStream)||_){pe(H.utterance,S,R);for(const k of n){if(m)return;k.audioBuffer||(k.audioBuffer=await _r(ee,k.audio,k.sampleRate)),a=!0,_||(_=!0,x=0,k.newStream&&k.onNewStream?.()),k.visemesQueued||(z(S,R,k.visemes,k.words,x,!0,T),k.visemesQueued=!0,x+=Math.round(k.audioBuffer.duration*1e3),C=Math.max(C,rt(S)))}e.onNotify();return}const g=n.shift();if(!g||(g.audioBuffer||(g.audioBuffer=await _r(ee,g.audio,g.sampleRate)),m))return;a=!0,V(),pe(g.utterance,S,R),g.visemesQueued=!1,g.newStream&&g.onNewStream?.(),Q(g.audioBuffer,{isFirstAudio:!o,isFirstOfStream:!1,onBeforeStart:k=>{l=k,c=0,f=performance.now()+(k-ee.currentTime)*1e3,S.length=0,R.length=0,z(S,R,g.visemes,g.words,0,!0,T),g.visemesQueued=!0,g.utterance.segmentOffsetMs=0}}),ne=r.length>0,C=rt(S),e.onNotify()}catch(ee){console.error("[avatarChunkPlayback] audio chunk failed:",ee)}finally{if(s=!1,m)return;if(_){n.some(H=>!H.audioBuffer||!H.visemesQueued)&&j(S,R);return}!ne&&r.length===0&&n.length>0?j(S,R):r.length===0&&n.length===0&&te()}};return{setStreamTtsEngineId:S=>{T=S},setPlaybackSpeed:S=>{p=Math.max(.1,Math.min(1,S)),se()},getPlaybackSpeed:()=>p,setLipsyncWarmupHoldEnabled:S=>{P=S,S||I()},isWarmingUp:()=>_,releaseWarmupHold:()=>{if(_){_=!1,x=0;for(const S of n)S.newStream=!1;O&&A&&j(O,A),e.onNotify()}},resetForNewStream:S=>{m=!1,u=!1,T=S,C=0},resumeBotStream:()=>{m=!1,u=!1},clearAborted:()=>{m=!1},primeAudioContext:async()=>{const S=window.AudioContext||window.webkitAudioContext;i||(i=new S),i.state==="suspended"&&await i.resume(),i&&!E&&(E=i.createMediaStreamDestination())},stop:()=>{m=!0,V(),G(),n.length=0,s=!1,o=!1,a=!1,u=!1,c=0,l=0,f=0,C=0,O=null,A=null,ie=null,I()},markStreamComplete:S=>{if(C=Math.max(C,rt(S)),u=!0,!a&&S.length>0){re(S);return}te()},playAudioChunk:async(S,R,ne,ee,H,W,v)=>{if(m)return;O=S,A=R;const g=yi(v?.sampleRate),k=v?.newStream===!0,b=me();if(!ne?.trim()){if(ee.length===0&&H.length===0)return;pe(b,S,R),k&&v?.onNewStream?.(),z(S,R,ee,H,0,!0,T),C=rt(S),!o&&C>0&&re(S),e.onNotify();return}n.push({audio:ne,audioBuffer:null,utterance:b,visemes:ee,words:H,isNewSegment:W,sampleRate:g,newStream:k,onNewStream:v?.onNewStream,visemesQueued:!1}),await j(S,R)},queueTimingsOnly:(S,R,ne,ee,H,W)=>{if(m)return;const v=me();pe(v,S,R),z(S,R,ne,ee,0,!0,T),v.segmentOffsetMs=0,C=rt(S)},getPlaybackElapsedMs:()=>a&&i&&l>0?Math.max(0,(i.currentTime-l)*1e3*p):o?Math.max(0,(performance.now()-f)*p):0,isSpeaking:()=>o?!0:!a||!i||l<=0?!1:(i.currentTime-l)*1e3<C,getVoiceStream:()=>E?E.stream:null,getPlaybackStartPerf:()=>f,bargeIn:()=>{m=!0,u=!1,V(),G(),n.length=0,s=!1,o=!1,a=!1,c=0,l=0,f=0,C=0,O=null,A=null,ie=null,I()},interrupt:()=>{m=!0,u=!1,V(),G(),n.length=0,s=!1,o=!1,a=!1,c=0,l=0,f=0,C=0,O=null,A=null,ie=null,I()}}}function Ft(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 Si(e,t,n=120){const r=Ft(e,t);if(r!=="sil")return r;let i=null;for(const s of e){if(s.vtime>t)break;const o=s.vtime+s.vduration;o<=t&&t-o<=n&&(i=s)}return i?.viseme??"sil"}function Os(e,t,n=400){const r=t-n;let i=0;for(const s of e)if(s.vtime+s.vduration<r)i+=1;else break;i>0&&e.splice(0,i)}function Ns(e,t){for(const n of e)if(t>=n.wtime&&t<n.wtime+n.wduration)return n;return null}function vr(e,t){const n=e.trim();if(!n)return null;try{const r=n.replace(/\s+/g,""),i=atob(r).length,s=Number.isFinite(t)&&(t??0)>0?Number(t):16e3;return i/2/s*1e3}catch{return null}}const fn=.5,dn=1.5,Hn="Olivia",jn="f786b574-daa5-4673-aa0c-cbe3e8534c02",Lt=.85;function Pn(e,t=ot,n={}){const r=`${t.replace(/\/$/,"")}/avatar_ttsWithPoses`,i=[],s=[],o=[],a=[];let u=0;const f=[],l=[];let c="",d="neutral",p="",T=st;const m=new Set;let E=0,C=null,P=0,_=null;const x=()=>m.forEach(L=>L());let O=()=>!1;const A=vi({onSpeakingStart:()=>e("speaking"),onSpeakingDone:()=>e("done"),onNotify:x,shouldHoldForWarmup:()=>O()},st),ie=()=>A.getPlaybackElapsedMs(),me=(L,le=c)=>{if(!n.onLipsyncDebug)return;const z=ie(),pe=i,N=un(o).map(Q=>({viseme:Q.viseme,vtimeMs:Q.vtime}));n.onLipsyncDebug({event:L,spokenText:le,mood:d,playbackAnchorPerf:A.getPlaybackStartPerf(),playbackElapsedMs:z,queueLength:pe.length,activeViseme:Ft(pe,z),segments:l.map(Q=>({...Q,visemes:[...Q.visemes]})),fullQueueLength:o.length,compactionSkipped:N})},I=(L,le)=>{n.onLipsyncDebug&&(C={event:L,spokenText:le},E===0&&(E=requestAnimationFrame(()=>{E=0;const z=C;C=null,z&&me(z.event,z.spokenText)})))},V=(L,le,z,pe,N)=>{if(!n.onLipsyncDebug)return;const Q=i.slice(le),j=z.filter(ae=>String(ae.symbol??ae.viseme??"").trim());l.push({spokenText:L,audioOffsetMs:Q[0]?.vtime??0,isNewSegment:pe,chunkDurationMs:N,receivedAtMs:performance.now(),visemes:Q.map((ae,Se)=>{const Z=j[Se];return{rawSymbol:String(Z?.symbol??Z?.viseme??ae.viseme).trim(),viseme:ae.viseme,startSec:Number(Z?.start??0),durationSec:Number(Z?.duration??0),vtimeMs:ae.vtime,vdurationMs:ae.vduration}})})},G=()=>{o.length=0,a.length=0,u=0},se=(L,le,z,pe,N)=>{if(L.length===0&&le.length===0)return;pi(o,a,L,le,u,N);const Q=gi(L,u),j=z?vr(z,pe):null;u=Math.max(Q,j!=null?u+j:u)},te=()=>{P+=1,_?.abort(),_=null,A.stop(),i.length=0,s.length=0,G(),f.length=0,d="neutral",l.length=0,c="",e("idle"),I("reset"),x()};return{setDeveloperToken:L=>{p=L},setTtsEngineId:L=>{T=L},getTtsEngineId:()=>T,speak:async(L,le)=>{te();const z=P;_=new AbortController,e("loading"),c=L,l.length=0,G();const pe=p.trim();if(!pe)throw new Error("Developer token required for avatar_ttsWithPoses");const N=le?.ttsEngineId??T??st;A.resetForNewStream(N),A.setStreamTtsEngineId(N);const Q=le?.voiceId??Hn,j=le?.speakingRate??Lt,ae=Math.max(fn,Math.min(dn,j)),Se={user_query:L,ttsEngineId:N,speakingRate:ae,tenant:"aiTwin"};jr.has(N)&&(Se.voice_id=Q);try{const Z=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${pe}`},body:JSON.stringify(Se),signal:_.signal});if(!Z.ok)throw new Error(`avatar_ttsWithPoses failed (${Z.status})`);const S=Z.body;if(!S)throw new Error("No response body");const R=S.getReader(),ne=new TextDecoder;let ee="",H=!0;const W=async v=>{if(z!==P)return;const g=ni(v);if(g){if(g.event==="audio"){const k=g.data.chunk,b=g.data.visemes??[],$=g.data.words??[],q=g.data.is_new_segment??!1,X=g.data.sample_rate,oe=Number(g.data.audio_offset_ms??0),Be=i.length;if(se(b,$,k,X,N),k){const et=H;H=!1,await A.playAudioChunk(i,s,k,b,$,q,{sampleRate:X,newStream:et,audioOffsetMs:oe}),V(L,Be,b,q,vr(k,X)),I("audio_chunk",L)}else(b.length>0||$.length>0)&&(A.queueTimingsOnly(i,s,b,$,q,{audioOffsetMs:oe,newStream:H}),V(L,Be,b,q,null),I("audio_chunk",L))}else if(g.event==="metadata"){const k=g.data.mood;typeof k=="string"&&k.trim()&&(d=k.trim());const b=g.data.sentence_emotions;if(Array.isArray(b)){f.length=0;for(const $ of b){if(!$||typeof $!="object")continue;const q=$;f.push({sentence_index:Number(q.sentence_index??0),text:String(q.text??""),sentiment:typeof q.sentiment=="string"?q.sentiment:void 0,emotion:String(q.emotion??d),start_word:Number(q.start_word??0),end_word:Number(q.end_word??0)})}}x(),I("metadata",L)}else if(g.event==="error")throw new Error(String(g.data.message??"avatar_ttsWithPoses stream error"))}};for(;z===P;){const{done:v,value:g}=await R.read();g&&(ee+=ne.decode(g,{stream:!0}));const k=ee.split(`
2
2
 
3
- `);X=k.pop()??"";for(const y of k)await j(y);if(b){X.trim()&&await j(X.trim()),A.markStreamComplete(i),M("bot_stopped",K);break}}}catch(ie){if(I!==P||ie instanceof DOMException&&ie.name==="AbortError")return;throw console.error("[avatarTtsLipsync]",ie),Y(),e("error"),ie}},stop:Y,getVisemeQueue:()=>i,getWordQueue:()=>s,getFullVisemeQueue:()=>o,getFullWordQueue:()=>a,getSentenceEmotions:()=>f,getStreamMood:()=>d,getPlaybackElapsedMs:()=>A.getPlaybackElapsedMs(),isSpeaking:()=>A.isSpeaking(),isWarmingUp:()=>A.isWarmingUp(),releaseWarmupHold:()=>A.releaseWarmupHold(),setLipsyncWarmupHold:(K,ee)=>{ee&&(L=ee),A.setLipsyncWarmupHoldEnabled(K)},getVoiceStream:()=>A.getVoiceStream(),setPlaybackSpeed:K=>{A.setPlaybackSpeed(K)},getPlaybackSpeed:()=>A.getPlaybackSpeed(),subscribe:K=>(m.add(K),()=>m.delete(K))}}const Wn=16e3,zn=16e3;class As extends Rn.ProtobufFrameSerializer{async deserialize(t){try{return await super.deserialize(t)}catch(n){if(n instanceof Error&&n.message==="Unknown frame kind")return{type:"raw",message:null};throw n}}}class Ms extends Rn.DailyMediaManager{constructor(){super(!0,!0,void 0,void 0,512,Wn,zn)}bufferBotAudio(t,n){}}const Ps=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;function Rs(e){return Ps.test(e.trim())}function Cs(e){const t=e.replace(/\/$/,"");return t.startsWith("https://")?`wss://${t.slice(8)}`:t.startsWith("http://")?`ws://${t.slice(7)}`:t}function mi(e){if(e.wsUrl?.trim())return e.wsUrl.trim();const t=e.authToken?.trim();if(!t)throw new Error("Voice connect requires authToken (same JWT as SSE Authorization Bearer).");const n=e.apiBase??ot,r=new URL(`${Cs(n)}/ws/voice`);r.searchParams.set("authToken",t),r.searchParams.set("tenant","aiTwin");const i=e.voiceId?.trim();i&&Rs(i)&&r.searchParams.set("voiceId",i);const s=e.personaId?.trim();s&&r.searchParams.set("personaId",s);const o=e.speakingRate??Ft;r.searchParams.set("speaking_rate",String(Math.max(on,Math.min(cn,o)))),e.ttsStream===!1?r.searchParams.set("tts_stream","false"):r.searchParams.set("tts_stream","true"),e.speakOnlyWhenSpokenTo&&r.searchParams.set("speakOnlyWhenSpokenTo","true");const a=e.avatarName?.trim();return a&&r.searchParams.set("avatarName",a),r.toString()}function yn(e,t){if(!Array.isArray(e))return[];const n=[];for(const r of e)!r||typeof r!="object"||n.push({sentence_index:Number(r.sentence_index??0),text:String(r.text??""),sentiment:typeof r.sentiment=="string"?r.sentiment:void 0,emotion:String(r.emotion??t),start_word:Number(r.start_word??0),end_word:Number(r.end_word??0)});return n}function Ds(e){if(!e||typeof e!="object")return null;const t=e,r=(t.data&&typeof t.data=="object"&&!Array.isArray(t.data)?t.data:null)||t;return{...r,type:String(r.type??t.type??"server-message")}}function dr(e){return e.is_new_segment===!0||Number(e.audio_offset_ms??-1)===0?!0:Number(e.chunk_index??-1)===0}function Bs(e){return e?.transport?._mediaManager?._wavStreamPlayer??null}function hi(e,t={}){const n=[],r=[],i=[],s=[];let o=0;const a=[],l=[];let f="",u="neutral",c=ct,d=!1,p=null,T=null,m={...t},E=0,R=null;const P=new Set,g=[];let x=!1,L=null,A=!0,ne="default";const de=new Set;let M=null,z=0,$=!1,J=!1,Y=null,me=!1;const K=()=>{Y!=null&&(clearTimeout(Y),Y=null)},ee=()=>{K(),Y=setTimeout(()=>{Y=null,A&&(U.markStreamComplete(n),ie("bot_stopped"))},450)},I=()=>P.forEach(w=>w());let G=()=>!1;const U=fi({onSpeakingStart:()=>e("speaking"),onSpeakingDone:()=>{me=!1,J=!1,e("done")},onNotify:I,shouldHoldForWarmup:()=>G()},c),ue=()=>{if(L)return L;const w=new MessageChannel;return w.port1.onmessage=()=>{const C=g.shift();C!==void 0&&Me(C),g.length>0?w.port2.postMessage(null):x=!1},L=w,w},re=w=>{g.push(w),!x&&(x=!0,ue().port2.postMessage(null))},oe=()=>U.getPlaybackElapsedMs(),pe=(w,C=f)=>{if(!m.onLipsyncDebug)return;const te=oe(),le=n,be=an(i).map(ge=>({viseme:ge.viseme,vtimeMs:ge.vtime}));m.onLipsyncDebug({event:w,spokenText:C,mood:u,playbackAnchorPerf:U.getPlaybackStartPerf(),playbackElapsedMs:te,queueLength:le.length,activeViseme:Bt(le,te),segments:l.map(ge=>({...ge,visemes:[...ge.visemes]})),fullQueueLength:i.length,compactionSkipped:be})},ie=(w,C)=>{m.onLipsyncDebug&&(R={event:w,spokenText:C},E===0&&(E=requestAnimationFrame(()=>{E=0;const te=R;R=null,te&&pe(te.event,te.spokenText)})))},v=()=>{A=!0,de.clear(),U.clearAborted()},O=()=>{const w=Bs(p);if(w){ne=`bot-${Date.now()}`,w.interruptedTrackIds={[ne]:!0};try{w.interrupt?.()}catch{}}const C=T;try{C?.interrupt?.()}catch{}},H=w=>{if(me&&U.isSpeaking())return!0;const C=w.context_id?.trim();return C&&de.has(C)?!0:A?!1:!(w.type==="avatar_metadata"||dr(w))},X=w=>{A=!1,me=!1;const C=w.context_id?.trim();C&&de.add(C),K(),$=!1,J=!1,g.length=0,x=!1,M?.abort(),M=null,z+=1,O(),U.bargeIn(),N(),e("idle"),ie("interrupt"),I()},N=()=>{n.length=0,r.length=0,i.length=0,s.length=0,o=0,l.length=0,f="",u="neutral",a.length=0},j=()=>{K(),J=!1,$=!1,U.stop(),N(),ie("reset"),I()},b=()=>{j(),e("idle"),I()},S=(w,C)=>{typeof w.mood=="string"&&w.mood.trim()&&(u=w.mood.trim()),Array.isArray(w.sentence_emotions)&&w.sentence_emotions.length>0&&(C&&(a.length=0),a.push(...yn(w.sentence_emotions,u)))},k=w=>{if(H({...w,type:"avatar_metadata"}))return;v(),$=!0;const C=String(w.spoken_text??w.text??"").trim();C&&(f=C),U.resetForNewStream(c),typeof w.mood=="string"&&w.mood.trim()&&(u=w.mood.trim()),a.length=0,a.push(...yn(w.sentence_emotions,u)),Array.isArray(w.gestures)&&w.gestures,ie("metadata",C),I()},y=(w,C,te,le)=>{if(!m.onLipsyncDebug)return;const be=n.slice(te),ge=le.filter(ye=>String(ye.symbol??ye.viseme??"").trim());l.push({spokenText:C,audioOffsetMs:be[0]?.vtime??0,isNewSegment:!!w.is_new_segment,chunkDurationMs:w.chunk_duration_ms!=null?Number(w.chunk_duration_ms):null,receivedAtMs:performance.now(),visemes:be.map((ye,Be)=>{const Se=ge[Be];return{rawSymbol:String(Se?.symbol??Se?.viseme??ye.viseme).trim(),viseme:ye.viseme,startSec:Number(Se?.start??0),durationSec:Number(Se?.duration??0),vtimeMs:ye.vtime,vdurationMs:ye.vduration}})})},V=(w,C,te,le)=>{if(w.length===0&&C.length===0)return;oi(i,s,w,C,o,c);const be=ci(w,o);let ge=null;const ye=te.trim();if(ye)try{const Be=atob(ye.replace(/\s+/g,"")).length,Se=Number.isFinite(le)&&(le??0)>0?Number(le):16e3;ge=Be/2/Se*1e3}catch{ge=null}o=Math.max(be,ge!=null?o+ge:o)},Z=w=>{if(H(w))return;const C=dr(w);C&&(K(),v());const te=String(w.spoken_text??w.text??"").trim(),le=w.visemes??[],be=w.words??[],ge=String(w.chunk??"").trim(),ye=$||C||!J;$&&($=!1),ye&&(J=!0),te&&(f=te),S(w,C),ye?(U.resetForNewStream(c),i.length=0,s.length=0,o=0):C&&U.resumeBotStream(),V(le,be,ge,w.sample_rate);const Be=n.length;U.playAudioChunk(n,r,ge,le,be,C,{sampleRate:w.sample_rate,newStream:ye,audioOffsetMs:Number(w.audio_offset_ms??0),onNewStream:()=>{l.length=0}}).then(()=>{y(w,te,Be,le),ie("audio_chunk",te),ee()})},_e=w=>{if(H(w))return;(w.is_new_segment||Number(w.audio_offset_ms??-1)===0)&&v(),console.warn("[realtimeVoice] avatar_lipsync is deprecated — expect avatar_audio_chunk");const C=String(w.spoken_text??w.text??"").trim();C&&(f=C),S(w,!!w.is_new_segment),V(w.visemes??[],w.words??[],"",void 0);const te=n.length;U.queueTimingsOnly(n,r,w.visemes??[],w.words??[],!!w.is_new_segment,{audioOffsetMs:Number(w.audio_offset_ms??0)}),y(w,C,te,w.visemes??[]),ie("lipsync",C),I()},ve=async w=>{const C=String(w.text??"").trim();if(!C)return;const te=m.authToken?.trim();if(!te){console.error("[realtimeVoice] avatar_speak requires authToken");return}M?.abort();const le=new AbortController;M=le;const be=++z;v(),U.resetForNewStream(c),f=C;const ye=`${(m.apiBase??ot).replace(/\/$/,"")}/avatar_ttsWithPoses`,Be=m.voiceId?.trim()||Un,Se=m.speakingRate??Ft,$e=Math.max(on,Math.min(cn,Se)),Xe={user_query:C,ttsEngineId:c,speakingRate:$e,tenant:"aiTwin"};Or.has(c)&&(Xe.voice_id=Be);try{const Fe=await fetch(ye,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${te}`},body:JSON.stringify(Xe),signal:le.signal});if(!Fe.ok)throw new Error(`avatar_ttsWithPoses failed (${Fe.status})`);const Tt=Fe.body;if(!Tt)throw new Error("No response body");const Je=Tt.getReader(),Ue=new TextDecoder;let Ee="",Ze=!0;const et=async tt=>{if(be!==z||le.signal.aborted||!A)return;const Te=qr(tt);if(Te){if(Te.event==="audio"){const se=Te.data.chunk,Ne=Te.data.visemes??[],ft=Te.data.words??[],kt=Te.data.is_new_segment??!1,dt=Te.data.sample_rate,xt=Number(Te.data.audio_offset_ms??0);if(se){const qe=Ze;Ze=!1,await U.playAudioChunk(n,r,se,Ne,ft,kt,{sampleRate:dt,newStream:qe,audioOffsetMs:xt})}else(Ne.length>0||ft.length>0)&&U.queueTimingsOnly(n,r,Ne,ft,kt,{audioOffsetMs:xt,newStream:Ze})}else if(Te.event==="metadata"){const se=Te.data.mood;typeof se=="string"&&se.trim()&&(u=se.trim());const Ne=Te.data.sentence_emotions;Array.isArray(Ne)&&(a.length=0,a.push(...yn(Ne,u))),I()}else if(Te.event==="error")throw new Error(String(Te.data.message??"avatar_ttsWithPoses stream error"))}};for(;!(be!==z||le.signal.aborted||!A);){const{done:tt,value:Te}=await Je.read();Te&&(Ee+=Ue.decode(Te,{stream:!0}));const se=Ee.split(`
3
+ `);ee=k.pop()??"";for(const b of k)await W(b);if(v){ee.trim()&&await W(ee.trim()),A.markStreamComplete(i),I("bot_stopped",L);break}}}catch(Z){if(z!==P||Z instanceof DOMException&&Z.name==="AbortError")return;throw console.error("[avatarTtsLipsync]",Z),te(),e("error"),Z}},stop:te,getVisemeQueue:()=>i,getWordQueue:()=>s,getFullVisemeQueue:()=>o,getFullWordQueue:()=>a,getSentenceEmotions:()=>f,getStreamMood:()=>d,getPlaybackElapsedMs:()=>A.getPlaybackElapsedMs(),isSpeaking:()=>A.isSpeaking(),isWarmingUp:()=>A.isWarmingUp(),releaseWarmupHold:()=>A.releaseWarmupHold(),setLipsyncWarmupHold:(L,le)=>{le&&(O=le),A.setLipsyncWarmupHoldEnabled(L)},getVoiceStream:()=>A.getVoiceStream(),setPlaybackSpeed:L=>{A.setPlaybackSpeed(L)},getPlaybackSpeed:()=>A.getPlaybackSpeed(),subscribe:L=>(m.add(L),()=>m.delete(L))}}const Kn=16e3,qn=16e3;class Vs extends Fn.ProtobufFrameSerializer{async deserialize(t){try{return await super.deserialize(t)}catch(n){if(n instanceof Error&&n.message==="Unknown frame kind")return{type:"raw",message:null};throw n}}}class Us extends Fn.DailyMediaManager{constructor(){super(!0,!0,void 0,void 0,512,Kn,qn)}bufferBotAudio(t,n){}}const Ws=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;function zs(e){return Ws.test(e.trim())}function $s(e){const t=e.replace(/\/$/,"");return t.startsWith("https://")?`wss://${t.slice(8)}`:t.startsWith("http://")?`ws://${t.slice(7)}`:t}function bi(e){if(e.wsUrl?.trim())return e.wsUrl.trim();const t=e.authToken?.trim();if(!t)throw new Error("Voice connect requires authToken (same JWT as SSE Authorization Bearer).");const n=e.apiBase??ot,r=new URL(`${$s(n)}/ws/voice`);r.searchParams.set("authToken",t),r.searchParams.set("tenant","aiTwin");const i=e.voiceId?.trim();i&&zs(i)&&r.searchParams.set("voiceId",i);const s=e.personaId?.trim();s&&r.searchParams.set("personaId",s);const o=e.speakingRate??Lt;r.searchParams.set("speaking_rate",String(Math.max(fn,Math.min(dn,o)))),e.ttsStream===!1?r.searchParams.set("tts_stream","false"):r.searchParams.set("tts_stream","true"),e.speakOnlyWhenSpokenTo&&r.searchParams.set("speakOnlyWhenSpokenTo","true");const a=e.avatarName?.trim();return a&&r.searchParams.set("avatarName",a),r.toString()}function bn(e,t){if(!Array.isArray(e))return[];const n=[];for(const r of e)!r||typeof r!="object"||n.push({sentence_index:Number(r.sentence_index??0),text:String(r.text??""),sentiment:typeof r.sentiment=="string"?r.sentiment:void 0,emotion:String(r.emotion??t),start_word:Number(r.start_word??0),end_word:Number(r.end_word??0)});return n}function Hs(e){if(!e||typeof e!="object")return null;const t=e,r=(t.data&&typeof t.data=="object"&&!Array.isArray(t.data)?t.data:null)||t;return{...r,type:String(r.type??t.type??"server-message")}}function Sr(e){return e.is_new_segment===!0||Number(e.audio_offset_ms??-1)===0?!0:Number(e.chunk_index??-1)===0}function js(e){return e?.transport?._mediaManager?._wavStreamPlayer??null}function Ti(e,t={}){const n=[],r=[],i=[],s=[];let o=0;const a=[],u=[];let f="",l="neutral",c=ct,d=!1,p=null,T=null,m={...t},E=0,C=null;const P=new Set,_=[];let x=!1,O=null,A=!0,ie="default";const me=new Set;let I=null,V=0,G=!1,se=!1,te=null,re=!1;const L=()=>{te!=null&&(clearTimeout(te),te=null)},le=()=>{L(),te=setTimeout(()=>{te=null,A&&(N.markStreamComplete(n),Z("bot_stopped"))},450)},z=()=>P.forEach(w=>w());let pe=()=>!1;const N=vi({onSpeakingStart:()=>e("speaking"),onSpeakingDone:()=>{re=!1,se=!1,e("done")},onNotify:z,shouldHoldForWarmup:()=>pe()},c),Q=()=>{if(O)return O;const w=new MessageChannel;return w.port1.onmessage=()=>{const B=_.shift();B!==void 0&&Be(B),_.length>0?w.port2.postMessage(null):x=!1},O=w,w},j=w=>{_.push(w),!x&&(x=!0,Q().port2.postMessage(null))},ae=()=>N.getPlaybackElapsedMs(),Se=(w,B=f)=>{if(!m.onLipsyncDebug)return;const J=ae(),ue=n,be=un(i).map(ye=>({viseme:ye.viseme,vtimeMs:ye.vtime}));m.onLipsyncDebug({event:w,spokenText:B,mood:l,playbackAnchorPerf:N.getPlaybackStartPerf(),playbackElapsedMs:J,queueLength:ue.length,activeViseme:Ft(ue,J),segments:u.map(ye=>({...ye,visemes:[...ye.visemes]})),fullQueueLength:i.length,compactionSkipped:be})},Z=(w,B)=>{m.onLipsyncDebug&&(C={event:w,spokenText:B},E===0&&(E=requestAnimationFrame(()=>{E=0;const J=C;C=null,J&&Se(J.event,J.spokenText)})))},S=()=>{A=!0,me.clear(),N.clearAborted()},R=()=>{const w=js(p);if(w){ie=`bot-${Date.now()}`,w.interruptedTrackIds={[ie]:!0};try{w.interrupt?.()}catch{}}const B=T;try{B?.interrupt?.()}catch{}},ne=w=>{if(re&&N.isSpeaking())return!0;const B=w.context_id?.trim();return B&&me.has(B)?!0:A?!1:!(w.type==="avatar_metadata"||Sr(w))},ee=w=>{A=!1,re=!1;const B=w.context_id?.trim();B&&me.add(B),L(),G=!1,se=!1,_.length=0,x=!1,I?.abort(),I=null,V+=1,R(),N.bargeIn(),H(),e("idle"),Z("interrupt"),z()},H=()=>{n.length=0,r.length=0,i.length=0,s.length=0,o=0,u.length=0,f="",l="neutral",a.length=0},W=()=>{L(),se=!1,G=!1,N.stop(),H(),Z("reset"),z()},v=()=>{W(),e("idle"),z()},g=(w,B)=>{typeof w.mood=="string"&&w.mood.trim()&&(l=w.mood.trim()),Array.isArray(w.sentence_emotions)&&w.sentence_emotions.length>0&&(B&&(a.length=0),a.push(...bn(w.sentence_emotions,l)))},k=w=>{if(ne({...w,type:"avatar_metadata"}))return;S(),G=!0;const B=String(w.spoken_text??w.text??"").trim();B&&(f=B),N.resetForNewStream(c),typeof w.mood=="string"&&w.mood.trim()&&(l=w.mood.trim()),a.length=0,a.push(...bn(w.sentence_emotions,l)),Array.isArray(w.gestures)&&w.gestures,Z("metadata",B),z()},b=(w,B,J,ue)=>{if(!m.onLipsyncDebug)return;const be=n.slice(J),ye=ue.filter(Te=>String(Te.symbol??Te.viseme??"").trim());u.push({spokenText:B,audioOffsetMs:be[0]?.vtime??0,isNewSegment:!!w.is_new_segment,chunkDurationMs:w.chunk_duration_ms!=null?Number(w.chunk_duration_ms):null,receivedAtMs:performance.now(),visemes:be.map((Te,Oe)=>{const Ne=ye[Oe];return{rawSymbol:String(Ne?.symbol??Ne?.viseme??Te.viseme).trim(),viseme:Te.viseme,startSec:Number(Ne?.start??0),durationSec:Number(Ne?.duration??0),vtimeMs:Te.vtime,vdurationMs:Te.vduration}})})},$=(w,B,J,ue)=>{if(w.length===0&&B.length===0)return;pi(i,s,w,B,o,c);const be=gi(w,o);let ye=null;const Te=J.trim();if(Te)try{const Oe=atob(Te.replace(/\s+/g,"")).length,Ne=Number.isFinite(ue)&&(ue??0)>0?Number(ue):16e3;ye=Oe/2/Ne*1e3}catch{ye=null}o=Math.max(be,ye!=null?o+ye:o)},q=w=>{if(ne(w))return;const B=Sr(w);B&&(L(),S());const J=String(w.spoken_text??w.text??"").trim(),ue=w.visemes??[],be=w.words??[],ye=String(w.chunk??"").trim(),Te=G||B||!se;G&&(G=!1),Te&&(se=!0),J&&(f=J),g(w,B),Te?(N.resetForNewStream(c),i.length=0,s.length=0,o=0):B&&N.resumeBotStream(),$(ue,be,ye,w.sample_rate);const Oe=n.length;N.playAudioChunk(n,r,ye,ue,be,B,{sampleRate:w.sample_rate,newStream:Te,audioOffsetMs:Number(w.audio_offset_ms??0),onNewStream:()=>{u.length=0}}).then(()=>{b(w,J,Oe,ue),Z("audio_chunk",J),le()})},X=w=>{if(ne(w))return;(w.is_new_segment||Number(w.audio_offset_ms??-1)===0)&&S(),console.warn("[realtimeVoice] avatar_lipsync is deprecated — expect avatar_audio_chunk");const B=String(w.spoken_text??w.text??"").trim();B&&(f=B),g(w,!!w.is_new_segment),$(w.visemes??[],w.words??[],"",void 0);const J=n.length;N.queueTimingsOnly(n,r,w.visemes??[],w.words??[],!!w.is_new_segment,{audioOffsetMs:Number(w.audio_offset_ms??0)}),b(w,B,J,w.visemes??[]),Z("lipsync",B),z()},oe=async w=>{const B=String(w.text??"").trim();if(!B)return;const J=m.authToken?.trim();if(!J){console.error("[realtimeVoice] avatar_speak requires authToken");return}I?.abort();const ue=new AbortController;I=ue;const be=++V;S(),N.resetForNewStream(c),f=B;const Te=`${(m.apiBase??ot).replace(/\/$/,"")}/avatar_ttsWithPoses`,Oe=m.voiceId?.trim()||jn,Ne=m.speakingRate??Lt,wn=Math.max(fn,Math.min(dn,Ne)),Nt={user_query:B,ttsEngineId:c,speakingRate:wn,tenant:"aiTwin"};jr.has(c)&&(Nt.voice_id=Oe);try{const qe=await fetch(Te,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${J}`},body:JSON.stringify(Nt),signal:ue.signal});if(!qe.ok)throw new Error(`avatar_ttsWithPoses failed (${qe.status})`);const We=qe.body;if(!We)throw new Error("No response body");const Ge=We.getReader(),ft=new TextDecoder;let _e="",Ve=!0;const nt=async ze=>{if(be!==V||ue.signal.aborted||!A)return;const ve=ni(ze);if(ve){if(ve.event==="audio"){const Ie=ve.data.chunk,ke=ve.data.visemes??[],Pe=ve.data.words??[],dt=ve.data.is_new_segment??!1,mt=ve.data.sample_rate,ht=Number(ve.data.audio_offset_ms??0);if(Ie){const Vt=Ve;Ve=!1,await N.playAudioChunk(n,r,Ie,ke,Pe,dt,{sampleRate:mt,newStream:Vt,audioOffsetMs:ht})}else(ke.length>0||Pe.length>0)&&N.queueTimingsOnly(n,r,ke,Pe,dt,{audioOffsetMs:ht,newStream:Ve})}else if(ve.event==="metadata"){const Ie=ve.data.mood;typeof Ie=="string"&&Ie.trim()&&(l=Ie.trim());const ke=ve.data.sentence_emotions;Array.isArray(ke)&&(a.length=0,a.push(...bn(ke,l))),z()}else if(ve.event==="error")throw new Error(String(ve.data.message??"avatar_ttsWithPoses stream error"))}};for(;!(be!==V||ue.signal.aborted||!A);){const{done:ze,value:ve}=await Ge.read();ve&&(_e+=ft.decode(ve,{stream:!0}));const Ie=_e.split(`
4
4
 
5
- `);Ee=se.pop()??"";for(const Ne of se)await et(Ne);if(tt){Ee.trim()&&await et(Ee.trim()),be===z&&!le.signal.aborted&&A&&U.markStreamComplete(n);break}}}catch(Fe){if(le.signal.aborted||!A)return;console.error("[realtimeVoice] avatar_speak failed:",Fe),e("error"),I()}finally{M===le&&(M=null)}},Me=w=>{const C=Ds(w);if(!C){console.warn("[realtimeVoice] server message with no payload",w);return}const te=String(C.type??"unknown");switch(te!=="avatar_metadata"&&te!=="avatar_audio_chunk"&&te!=="avatar_lipsync"&&te!=="avatar_interrupt"&&te!=="error"&&console.debug("[realtimeVoice] server message",te,C),te){case"avatar_metadata":k(C);break;case"avatar_audio_chunk":Z(C);break;case"avatar_lipsync":_e(C);break;case"avatar_interrupt":X(C);break;case"error":{const le=String(C.message??"Voice session error");console.error("[realtimeVoice] server error:",le),e("error"),I();break}case"avatar_speak":ve(C);break}},De=()=>p||(T=new Ms,p=new Ni.PipecatClient({transport:new Rn.WebSocketTransport({mediaManager:T,serializer:new As,recorderSampleRate:Wn,playerSampleRate:zn}),enableCam:!1,enableMic:!0,callbacks:{onBotReady:()=>{d=!0,e("idle"),I()},onDisconnected:()=>{d=!1,b()},onError:w=>{const C=typeof w=="object"&&w!==null&&"data"in w?String(w.data??w):String(w);console.error("[realtimeVoice]",C,w),e("error"),I()},onTransportStateChanged:w=>{w==="error"&&(e("error"),I())},onServerMessage:w=>{re(w)},onUserStartedSpeaking:()=>{},onBotStartedSpeaking:()=>{v(),ie("bot_started")},onBotStoppedSpeaking:()=>{A&&ee()},onUserTranscript:w=>{String(w.text??""),m.onUserTranscript?.(w.text,!!w.final)},onBotOutput:w=>{m.onBotOutput?.(w.text)}}}),p);return{setDeveloperToken:w=>{},setTtsEngineId:w=>{c=w,U.setStreamTtsEngineId(w)},getTtsEngineId:()=>c,speak:async(w,C)=>{const te=w.trim();if(te){if(!p||!d)throw new Error("Realtime voice is not connected. Call connect() first.");j(),await p.sendText(te)}},stop:()=>{M?.abort(),M=null,z+=1,v(),j(),e("idle"),I()},connect:async w=>{if(w&&(m={...m,...w}),!m.authToken?.trim())throw new Error("Voice connect requires authToken (same JWT as SSE Authorization Bearer).");e("loading");const C=De();await C.initDevices();const te=mi(m);console.info("[realtimeVoice] connecting (avatar_audio_chunk RTVI):",te);try{await C.connect({wsUrl:te})}catch(le){d=!1,e("error"),I();const be=le instanceof Error?le.message:"Realtime voice connect failed (WebSocket 101 only means upgrade OK — check authToken/origin/RTVI handshake)";throw new Error(`${be} — ${te}`)}d=!0,e("idle"),I()},disconnect:async()=>{if(K(),$=!1,J=!1,g.length=0,x=!1,M?.abort(),M=null,z+=1,v(),p)try{await p.disconnect()}catch(w){console.error("[realtimeVoice] disconnect failed:",w)}d=!1,b()},isConnected:()=>d,unlockAudio:async()=>{await U.primeAudioContext()},getVisemeQueue:()=>n,getWordQueue:()=>r,getFullVisemeQueue:()=>i,getFullWordQueue:()=>s,getSentenceEmotions:()=>a,getStreamMood:()=>u,getPlaybackElapsedMs:oe,isSpeaking:()=>U.isSpeaking(),isWarmingUp:()=>U.isWarmingUp(),releaseWarmupHold:()=>U.releaseWarmupHold(),setLipsyncWarmupHold:(w,C)=>{C&&(G=C),U.setLipsyncWarmupHoldEnabled(w)},getVoiceStream:()=>U.getVoiceStream(),setPlaybackSpeed:w=>{U.setPlaybackSpeed(w)},getPlaybackSpeed:()=>U.getPlaybackSpeed(),subscribe:w=>(P.add(w),()=>P.delete(w))}}function wi(e,t,n){return{width:e.crop?.source_width??t,height:e.crop?.source_height??n}}function pi(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 gi(e){return e?(e.w??0)>0&&(e.h??0)>0:!1}async function bt(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 ss(r,t)}async function yi(e,t){if(!t)throw new Error("Missing asset key for encrypted JSON");const n=await bt(e,t),r=new TextDecoder().decode(n);return JSON.parse(r)}async function Fs(e){const t=new Blob([e],{type:"image/webp"});return createImageBitmap(t)}async function Ls(e){const t=new Blob([e],{type:"image/webp"}),n=URL.createObjectURL(t);return new Promise((r,i)=>{const s=new Image;s.decoding="async",s.onload=()=>{URL.revokeObjectURL(n),r(s)},s.onerror=()=>{URL.revokeObjectURL(n),i(new Error("Failed to decode decrypted image"))},s.src=n})}async function Os(e){const t=new Blob([e],{type:"image/png"});return createImageBitmap(t)}async function Ns(e){const t=new Blob([e],{type:"image/png"}),n=URL.createObjectURL(t);return new Promise((r,i)=>{const s=new Image;s.decoding="async",s.onload=()=>{URL.revokeObjectURL(n),r(s)},s.onerror=()=>{URL.revokeObjectURL(n),i(new Error("Failed to decode decrypted PNG"))},s.src=n})}function Vs(e){const t=new Blob([e],{type:"video/mp4"});return URL.createObjectURL(t)}async function Us(e){const t=os();if(!Dt())return t;if(!e)throw new Error("Missing asset key for encrypted idle video");const n=await bt(t,e);return Vs(n)}function gt(e,t){return`${e}/${t}_minus_sil.png`}const _i=5;function un(e){const t=e?.composite_threshold;if(typeof t=="number"&&t>0)return t;const n=e?.crop?.content_threshold;return typeof n=="number"&&n>0?n:_i}const Ws=["aa","E","I","O","U","PP","FF","DD","SS","TH","CH","RR","kk","nn"],In=["t01_0.25","t02_0.50","t03_0.75"],zs=In.length,mr=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 hr(e,t){return`${e}__${t}`}function wr(e,t){return`pairs/${e}/${t}_minus_sil.png`}function _t(e){return`${e}_minus_sil.png`}function Hn(e,t){if(t.has(e))return e;const n=/^pairs\/([^/]+)\//.exec(e);if(!n)return null;const r=n[1].split("__")[1];if(!r||r==="sil")return null;const i=_t(r);return t.has(i)?i:null}function vi(e,t){return e.filter(n=>t.has(n))}function Hs(e,t,n){const r=$n(e,t);return vi(r,n).length>0}function $n(e,t){if(e===t)return[];const n=[],r=hr(e,t);if(mr.has(r)){for(const s of In)n.push(wr(r,s));return n}const i=hr(t,e);if(mr.has(i)){for(let s=zs-1;s>=0;s--)n.push(wr(i,In[s]));return n}return[]}function $s(e){return e<16?[1]:e<24?[1]:e<35?[0,1,2]:[0,1,2]}function js(e,t){return $s(t).map(r=>e[r]).filter(r=>r!=null)}function Ks(e,t,n,r){if(r<=0)return 0;const s=Math.max(1,n-t)/r,o=e-t,a=Math.floor(o/s);return Math.min(r-1,Math.max(0,a))}function Si(e,t,n){if(!n)return`${e}/${t}`;const r=t.split("/").pop()??t,i=r.includes(".")?r.slice(0,r.lastIndexOf(".")):r;return`${e}/${i}.bin`}const qs=[.32,.24,.16,.08,0],Gs=qs.map(e=>`eyes_${e.toFixed(2)}`),Ys=["eyes_0.32","eyes_0.16","eyes_0.00"],Qs=["eyes_0.32","eyes_0.16","eyes_0.08","eyes_0.00"],Ve=2,Xs=-20,Xt=16,bi={fear:-20,anger:-20,sad:-10,neutral:0,love:0,happy:0,disgust:10};function Rt(e){return`brow_${e}`}function at(e){return bi[e]}function He(e){return Math.max(Xs,Math.min(Xt,e))}function Js(e,t){if(e===t)return[];const n=e<t,r=n?Ve:-Ve,i=[];let s=e;if(s%Ve!==0){const o=n?Math.ceil(s/Ve)*Ve:Math.floor(s/Ve)*Ve,a=He(o);if(n?a>=t:a<=t)return[t];s=a,i.push(s)}for(;;){const o=s+r;if(n?o>=t:o<=t){t!==s&&i.push(t);break}s=o,i.push(s)}return i}function pr(e){const t=He(e);if(t%Ve===0)return[t];const n=Math.floor(t/Ve)*Ve,r=Math.min(Xt,n+Ve),i=He(n);return t-i<=r-t?i===r?[i]:[i,r]:i===r?[r]:[r,i]}const Zs=["fear","anger","sad","neutral","love","happy","disgust"],ea={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 Ke(e,t="neutral"){const n=String(e??"").trim().toLowerCase();return n?ea[n]??t:t}function Ti(e){return e===0?null:gt(Rt(e),"eyes_standard")}function ki(e){return Ti(at(e))}const ta={[-20]:"anger",[-10]:"sad",0:"neutral",10:"disgust"};function jn(e,t){if(!e)return null;if(t(e))return e;const n=e.match(/^brow_(-?\d+)\/(eyes_[^/]+)_minus_sil\.png$/);if(n){const i=Number(n[1]),s=n[2];for(const a of pr(i)){if(a===i)continue;const l=gt(Rt(a),s);if(t(l))return l}const o=ta[i];if(o){const a=gt(o,s);if(t(a))return a}return null}const r=e.match(/^(fear|anger|sad|neutral|love|happy|disgust)\/(eyes_[^/]+)_minus_sil\.png$/);if(r){const i=r[1],s=r[2],o=at(i);for(const a of[o,...pr(o)]){const l=gt(Rt(a),s);if(t(l))return l}}return null}function gr(e,t){const n=Rt(at(e));return!t||t==="eyes_standard"?ki(e):e==="neutral"&&t==="eyes_standard"?null:gt(n,t)}function na(e,t){const n=[];for(const r of t)n.push(gr(e,r));for(let r=t.length-2;r>=0;r--)n.push(gr(e,t[r]));return n.push(ki(e)),n}function ra(e){return gt(Rt(e),"eyes_standard")}function ia(e,t){return Js(e,t).map(ra)}const sa=6;function aa(e,t){for(const n of e)if(t>=n.wtime&&t<n.wtime+n.wduration)return n;return null}function oa(e){const t=He(e);return t>=Xt?Xt:He(t+sa)}function ca(e,t,n){const r=He(n);return aa(t,e)?.emphasis?oa(r):r}function yr(e){if(!e)return 0;const t=e.match(/^brow_(-?\d+)\//);if(!t?.[1])return null;const n=Number.parseInt(t[1],10);return Number.isFinite(n)?He(n):null}function pt(e,t){return e+Math.random()*(t-e)}function jt(){return pt(14,32)}function ua(e={}){const{initialDelayMs:t=800+Math.random()*1200,intervalMinMs:n=2200,intervalMaxMs:r=5800,doubleBlinkChance:i=.18,doubleBlinkGapMinMs:s=120,doubleBlinkGapMaxMs:o=220,fullBlinkChance:a=.75,postEmotionChangeDelayMs:l=380,minDwellMs:f=550}=e;let u="neutral",c="neutral",d=0,p=0,T=0,m={kind:"idle",nextBlinkAt:performance.now()+t},E=null,R="__eyes_open__|neutral|brow:0";function P(M=u){R=`${E??"__eyes_open__"}|${M}|brow:${p}`}function g(M,z=u){E=M;const $=yr(M);$!=null?p=$:M==null&&(p=0),P(z)}function x(M){return Ti(M)}function L(M,z,$){const J=He(z),Y=He($);if(d=Y,J===Y){g(x(Y));return}const me=[...ia(J,Y),x(Y)];m={kind:"browBlend",paths:me,index:0,holdUntil:M+jt(),targetBrow:Y},g(me[0]??null)}function A(M,z){m={kind:"idle",nextBlinkAt:M+pt(n,r)},c=z,g(x(d),z)}function ne(M,z,$){const J=$?Ys:Math.random()<a?Gs:Qs;m={kind:"playing",paths:na(z,J),index:0,holdUntil:M+jt(),after:"idle",blinkEmotion:z},c=z,g(m.paths[0]??null,z)}function de(M){if(m.kind==="browBlend"){for(;M>=m.holdUntil&&m.index<m.paths.length-1;)m.index+=1,m.holdUntil=M+jt();const z=m.paths[m.index]??null;g(z),M>=m.holdUntil&&m.index>=m.paths.length-1&&(p=m.targetBrow,d=m.targetBrow,g(x(m.targetBrow)),m={kind:"idle",nextBlinkAt:M+l});return}if(m.kind==="idle"){g(x(d),c),M>=m.nextBlinkAt&&ne(M,c,!1);return}if(m.kind==="doublePause"){g(x(d),m.blinkEmotion),M>=m.resumeAt&&ne(M,m.blinkEmotion,!0);return}if(m.kind==="playing"){for(;M>=m.holdUntil&&m.index<m.paths.length-1;)m.index+=1,m.holdUntil=M+jt();if(g(m.paths[m.index]??null,m.blinkEmotion),M>=m.holdUntil&&m.index>=m.paths.length-1){if(m.after==="resumeIdle"){A(M+l,u);return}if(m.after==="doublePause"){m={kind:"doublePause",resumeAt:M+pt(s,o),blinkEmotion:m.blinkEmotion},g(x(d),m.blinkEmotion);return}if(m.after==="idle"&&Math.random()<i){m={kind:"doublePause",resumeAt:M+pt(s,o),blinkEmotion:m.blinkEmotion},g(x(d),m.blinkEmotion);return}A(M,m.blinkEmotion)}}}return{advance:de,setTargetEmotion(M,z){const $=Ke(M,u);if($===u)return;const J=performance.now();!z?.force&&f>0&&!(u==="neutral"&&$!=="neutral")&&J-T<f||(u=$,c=$,T=J)},setTargetEyebrow(M){const z=He(M);if(z===d)return;const $=performance.now(),J=m.kind==="browBlend"?yr(E)??p:p;d=z,!(z===J&&m.kind!=="browBlend")&&(m.kind==="playing"||m.kind==="doublePause"||L($,J,z))},snapToEmotion(M){const z=Ke(M),$=at(z);u=z,c=z,d=$,p=$,T=performance.now(),m={kind:"idle",nextBlinkAt:performance.now()+pt(4e3,7e3)},g(x($),z)},getTargetEmotion:()=>u,getTargetEyebrow:()=>d,getExpressionPath:()=>E,getDrawKey:()=>R,reset(){u="neutral",c="neutral",d=0,p=0,T=0,A(performance.now()+pt(n,r),"neutral")}}}function la(){const e=document.createElement("video");e.muted=!0,e.playsInline=!0,e.preload="auto",e.setAttribute("playsinline",""),e.loop=!0;let t=!1,n=null,r="";const i=()=>{n&&(URL.revokeObjectURL(n),n=null)};return{async load(s){t&&r===s||(i(),t=!1,r=s,s.startsWith("blob:")&&(n=s),await new Promise((o,a)=>{const l=()=>{const f=e.duration;if(!Number.isFinite(f)||f<=0){a(new Error(`Idle video has invalid duration: ${s}`));return}t=!0,e.currentTime=0,o()};e.addEventListener("loadeddata",l,{once:!0}),e.addEventListener("error",()=>a(new Error(`Failed to load idle video: ${s}`)),{once:!0}),e.src=s,e.load()}))},isReady(){return t},getVideo(){return e},setActive(s){t&&(s?e.paused&&e.play().catch(()=>{}):e.paused||e.pause())},restart(){t&&(e.currentTime=0)},dispose(){e.pause(),e.removeAttribute("src"),e.load(),i(),t=!1,r=""}}}const fa=50,xi=400;function da(e,t,n){return e.filter(r=>{const i=r.queueIndex??-1;return i>=t&&i<=n})}function ma(e,t){const n=[];for(const r of e){const i=da(t,r.start_word,r.end_word);if(i.length===0)continue;const s=i[0],o=i[i.length-1];n.push({sentence:r,startMs:Math.max(0,s.wtime-fa),endMs:o.wtime+o.wduration+xi})}return n.sort((r,i)=>r.startMs-i.startMs)}function ha(e,t,n,r="neutral"){const i=Ke(r);if(t.length===0)return i;if(n.length===0||e<n[0].wtime)return Ke(t[0]?.emotion,i);const s=ma(t,n);let o=null;for(const f of s)e>=f.startMs&&e<=f.endMs&&(o=f);if(o)return Ke(o.sentence.emotion,i);const a=n[n.length-1],l=a.wtime+a.wduration;return e>l+xi?Ke(t[t.length-1]?.emotion,i):i}function Kn(e,t,n,r,i=_i){const s=new OffscreenCanvas(n,r),o=s.getContext("2d",{willReadFrequently:!0});o.drawImage(e,0,0,n,r);const a=o.getImageData(0,0,n,r),l=o.createImageData(n,r);l.data.set(a.data);const u=new OffscreenCanvas(n,r).getContext("2d",{willReadFrequently:!0});for(const c of t){u.clearRect(0,0,n,r),u.drawImage(c,0,0,n,r);const d=u.getImageData(0,0,n,r);for(let p=0;p<l.data.length;p+=4){const T=d.data[p],m=d.data[p+1],E=d.data[p+2];Math.max(T,m,E)>i&&(l.data[p]=T,l.data[p+1]=m,l.data[p+2]=E,l.data[p+3]=255)}}return o.putImageData(l,0,0),s}let it=null,vt=null;const Jt=new Map;function wa(){it=null,vt=null,Jt.clear()}Hr(wa);function pa(e){return e??vt??void 0}function qn(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 ga(e){return Dt()?Ns(await bt(Qt(),e??"")):qn(Qt())}async function _r(e,t,n,r){const i=n?await yi(e,r):await fetch(e).then(f=>{if(!f.ok)throw new Error(`Failed to load ${e}`);return f.json()}),s=i.sheets?.[0];if(!s?.path)throw new Error(`${e} has no sheets[0].path`);const o=n?await Ls(await bt(Si(t,s.path,n),r??"")):await qn(`${t}/${s.path}`),a=new Map;for(const f of i.cells??[])f.path&&a.set(f.path,f);const l=new Map;for(const f of i.sheets??[])l.set(f.index,f);return{atlas:o,atlasMeta:i,cellByPath:a,sheetByIndex:l,diffBase:t}}async function An(e){const t=pa(e),n=Dt();if(n&&!t)throw new Error("Encrypted assets enabled but no key provided");if(it&&(!n||vt===(t??null))){const s=await it;return{...St(s),visemePaths:[...s.viseme.cellByPath.keys()]}}vt=t??null,Jt.clear();const r=$r();it=(async()=>{const s=await ga(t),o=await _r(jr(),r,n,t);let a=null;try{a=await _r(Kr(),r,n,t)}catch{a=null}return{sil:s,viseme:o,expression:a}})();const i=await it;return{...St(i),visemePaths:[...i.viseme.cellByPath.keys()]}}async function Gn(e){if(await An(e),!it)throw new Error("Assets not loaded");return it}function St(e){return wi(e.viseme.atlasMeta,e.sil.naturalWidth,e.sil.naturalHeight)}function ya(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 Zt(e,t,n){const r=`${t.diffBase}::${n}`,i=Jt.get(r);if(i)return i;const s=(async()=>{const o=t.cellByPath.get(n);if(!o)throw new Error(`No atlas cell for path: ${n}`);const a=pi(t.atlasMeta,o),l=St(e);if(gi(o)){const c=ya(t,o),d=document.createElement("canvas");d.width=l.width,d.height=l.height;const p=d.getContext("2d");return p.fillStyle="#000",p.fillRect(0,0,l.width,l.height),p.drawImage(c,a.x,a.y),d}const f=`${t.diffBase}/${n}`,u=await qn(f);if(u.naturalWidth===l.width&&u.naturalHeight===l.height)return u;throw new Error(`Diff PNG wrong size for ${n}`)})();return Jt.set(r,s),s}async function _n(e,t,n,r,i,s){if(i){const{width:p,height:T}=i;if(s&&!s()||t.readyState<HTMLMediaElement.HAVE_CURRENT_DATA)return;const m=document.createElement("canvas");m.width=p,m.height=T;const E=m.getContext("2d");if(E.clearRect(0,0,p,T),E.drawImage(t,0,0,p,T),s&&!s())return;(e.width!==p||e.height!==T)&&(e.width=p,e.height=T);const R=e.getContext("2d");R.clearRect(0,0,p,T),R.drawImage(m,0,0);return}const o=await Gn(),a=un(o.viseme.atlasMeta),{width:l,height:f}=St(o);(e.width!==l||e.height!==f)&&(e.width=l,e.height=f);const u=[],c=e.getContext("2d");if(c.clearRect(0,0,l,f),t.readyState<HTMLMediaElement.HAVE_CURRENT_DATA){const p=o.sil;c.drawImage(p,0,0,l,f);return}if(u.length===0){c.drawImage(t,0,0,l,f);return}const d=Kn(t,u,l,f,a);c.drawImage(d,0,0)}async function Mn(e,t,n){const r=await Gn(vt??void 0),i=un(r.viseme.atlasMeta),{width:s,height:o}=St(r);(e.width!==s||e.height!==o)&&(e.width=s,e.height=o);const a=[];if(t.mouthPath){const u=new Set(r.viseme.cellByPath.keys()),c=Hn(t.mouthPath,u)??(u.has(t.mouthPath)?t.mouthPath:null);c&&a.push(await Zt(r,r.viseme,c))}if(t.expressionPath&&r.expression){const u=jn(t.expressionPath,c=>r.expression.cellByPath.has(c));u&&a.push(await Zt(r,r.expression,u))}const l=e.getContext("2d");if(l.clearRect(0,0,s,o),a.length===0){l.drawImage(r.sil,0,0,s,o);return}const f=Kn(r.sil,a,s,o,i);l.drawImage(f,0,0)}async function _a(e,t){const n=await Gn(vt??void 0),r=un(n.viseme.atlasMeta),{width:i,height:s}=St(n),o=[];if(e.mouthPath){const u=new Set(n.viseme.cellByPath.keys()),c=Hn(e.mouthPath,u)??(u.has(e.mouthPath)?e.mouthPath:null);c&&o.push(await Zt(n,n.viseme,c))}if(e.expressionPath&&n.expression){const u=jn(e.expressionPath,c=>n.expression.cellByPath.has(c));u&&o.push(await Zt(n,n.expression,u))}const a=new OffscreenCanvas(i,s),l=a.getContext("2d");if(o.length===0)return l.drawImage(n.sil,0,0,i,s),a.transferToImageBitmap();const f=Kn(n.sil,o,i,s,r);return l.drawImage(f,0,0),a.transferToImageBitmap()}async function va(e){await Mn(e,{mouthPath:null,expressionPath:null})}const Kt={fontFamily:"system-ui, -apple-system, sans-serif",fontSize:"clamp(0.875rem, 2.5vw, 1.125rem)",color:"rgba(255,255,255,0.85)"};function Sa(e){return e.length===0?"":e.map(t=>t.word).join(" ")}function ba(e){if(!e)return{enabled:!1,style:Kt};const t=e===!0?{}:e;return{enabled:!0,style:{fontFamily:t.fontFamily??Kt.fontFamily,fontSize:t.fontSize??Kt.fontSize,color:t.color??Kt.color}}}const Ta={position:"absolute",bottom:0,left:0,right:0,display:"flex",justifyContent:"center",padding:"0.75rem 1rem",pointerEvents:"none"},ka={display:"inline-block",maxWidth:"100%",padding:"0.45rem 0.85rem",borderRadius:"0.75rem",background:"rgba(0,0,0,0.55)",lineHeight:1.4,textAlign:"center"},xa={display:"-webkit-box",WebkitLineClamp:2,WebkitBoxOrient:"vertical",overflow:"hidden",maxWidth:"100%",margin:0};function Ea({text:e,style:t}){return F.jsx("div",{style:Ta,"aria-live":"polite","aria-atomic":"true",children:F.jsx("div",{style:{...ka,fontFamily:t.fontFamily,fontSize:t.fontSize,color:t.color},children:F.jsx("p",{style:xa,children:e})})})}let Ei=null;function vr(e){Ei=e}function Qe(){return Ei}function Ia(e){return`${e.from}→${e.to}@${e.fromVtime}`}function Sr(){return{rafTicksSpeaking:0,rafTicksDeduped:0,drawsRequested:0,drawsDisplayed:0,queueSuperseded:0,workerStale:0,rifeFramesOmittedByGap:0,transitionFramesSampled:0,transitionFramesDisplayed:0,transitionFramesMissed:0,bufferTicks:0,bufferHits:0,bufferUnderruns:0,bufferPrefetched:0}}function Aa(){let e=Sr();const t=new Set,n=new Set,r=new Set;let i="",s=-1,o="";const a=()=>{e=Sr(),t.clear(),n.clear(),r.clear(),i="",s=-1,o=""},l=u=>{t.add(u)},f=u=>{u&&r.add(u)};return{reset:a,onRafTickSpeaking(){e.rafTicksSpeaking+=1},onDrawDeduped(){e.rafTicksDeduped+=1},onDrawRequested(){e.drawsRequested+=1},onQueueSuperseded(){e.queueSuperseded+=1},onWorkerStale(){e.workerStale+=1},onTransitionSample(u,c){const d=Ia(u);e.transitionFramesSampled+=1,d!==i&&(i=d,s=-1,o!==d&&(o=d,e.rifeFramesOmittedByGap+=u.omittedByGap)),c&&n.add(c),s>=0&&u.frameIdx>s+1&&(e.transitionFramesMissed+=u.frameIdx-s-1),s=u.frameIdx},onBufferTick(){e.bufferTicks+=1},onBufferHit(){e.bufferHits+=1},onBufferUnderrun(){e.bufferUnderruns+=1},onBufferPrefetched(){e.bufferPrefetched+=1},onBufferReset(){},onDrawDisplayed(u,c){if(e.drawsDisplayed+=1,u.transitionMeta){e.transitionFramesDisplayed+=1;const p=u.transitionMeta;l(p.fromVtime),l(p.toVtime),f(u.mouthPath);return}if(u.label.includes("→")){e.transitionFramesDisplayed+=1;return}const d=u.label.trim();if(!(!d||d==="sil")){for(const p of c)if(p.viseme===d&&u.elapsedMs>=p.vtime&&u.elapsedMs<p.vtime+p.vduration){l(p.vtime);break}}},snapshot(u,c){let d=0,p=0;for(const P of u)if(P.viseme!=="sil"){if(P.vtime>=c)break;d+=1,t.has(P.vtime)&&(p+=1)}const T=d>0?Math.round(p/d*100):100,m=e.queueSuperseded+e.workerStale+Math.max(0,e.drawsRequested-e.drawsDisplayed),E=d-p,R=e.bufferTicks>0?Math.round(e.bufferHits/e.bufferTicks*100):100;return{...e,bufferHitRate:R,renderLoss:m,visemeSlotsTotal:d,visemeSlotsCovered:p,visemeCoveragePct:T,transitionFramesUniqueSampled:n.size,transitionFramesUniquePainted:r.size,drawsDeduped:e.rafTicksDeduped,renderSkips:e.rafTicksDeduped+m,visemesShown:p,visemesSkipped:E,rifeTransitionFramesSkipped:e.transitionFramesMissed}}}}const Ii=Dn,Ma=200,br=300,Pa=100,Ra=600,Ai="__sil__";function Tr(e){return e.lastDrawnKey?e.lastDrawnKey.split("|")[0]===Ai:!1}function Yn(){return{lastDrawnKey:""}}function Ce(e){e.lastDrawnKey="",e.transitionCache=void 0}function Ca(e,t){if(t?.transitionCache&&t.transitionCache.queueLength===e.length)return t.transitionCache.transitions;const n=si(e);return t&&(t.transitionCache={queueLength:e.length,transitions:n}),n}function Da(e,t){let n="sil";for(const r of e)r.viseme!=="sil"&&(t!=null&&r.vtime>t||(n=r.viseme));return n}function Ba(e,t,n,r=120){if(n!=="sil")return n;const i=di(e,t,r);return i!=="sil"?i:Da(e,t)}function Fa(e,t){return e==="sil"?!1:t?Hs(e,"sil",t):$n(e,"sil").length>0}function La(){return Ii+Ra}function en(e){return e??Ai}function Qn(e,t,n,r,i=Pa){if(e.length===0)return{diffPath:null,label:"sil"};if(t>=rt(e))return{diffPath:null,label:"sil"};const s=Ca(e,r),o=bs(s,t);if(o){const f=ai(o.fromVtime,o.toVtime,o.from,o.to);if(t>=f.transStart&&t<f.transEnd){let u=$n(o.from,o.to);n&&(u=vi(u,n));const c=js(u,f.effectiveGapMs);if(c.length>0){const d=Ks(t,f.transStart,f.transEnd,c.length);return{diffPath:c[d]??c[c.length-1],label:`${o.from}→${o.to}`,transitionMeta:{from:o.from,to:o.to,fromVtime:o.fromVtime,toVtime:o.toVtime,frameIdx:d,frameCount:c.length,fullFrameCount:u.length,omittedByGap:Math.max(0,u.length-c.length)}}}return{diffPath:_t(o.to),label:o.to}}}const a=sn(e);let l=ti(a,t);return l==="sil"&&(l=di(e,t,i)),l==="sil"?{diffPath:null,label:"sil"}:{diffPath:_t(l),label:l}}function Ct(e,t){const n=t??en(e.expressionPath);return`${en(e.mouthPath)}|${n}`}function kr(e,t,n,r,i,s,o,a,l,f){const u=Qn(t,n,l,s),c={mouthPath:u.diffPath,expressionPath:r},d=Ct(c,i),p=Qe();if(u.transitionMeta&&p?.onTransitionSample(u.transitionMeta,u.diffPath),d===s.lastDrawnKey){p?.onDrawDeduped();return}p?.onDrawRequested(),a(u),s.lastDrawnKey=d,o(e,c,d,T=>{T===d&&(s.lastDrawnKey=d)})}function vn(e,t,n,r,i,s,o=null,a=null){const l={mouthPath:a,expressionPath:t},f=o!=null?`|idle@${Math.round(o*1e3)}`:"",u=Ct(l,n)+f;!(o!=null)&&u===r.lastDrawnKey||(s(o!=null?t?"idle · blink":"idle":t?"blink":"sil"),i(e,l,u,d=>{d===u&&(r.lastDrawnKey=u)}))}function Mi(e,t,n,r,i=Mt,s){if(n<=t||e.length===0)return[];const o=s??Yn(),a=[];let l="";for(let f=t;f<n;f+=i){const u=Qn(e,f,r,o),c=en(u.diffPath);c!==l&&(l=c,a.push({displayAtMs:f,mouthPath:u.diffPath,mouthKey:c,label:u.label}))}return a}const Oa=3;function Xn(e){let t=0;const n=[];let r=!1,i=!1;const s=async()=>{if(!r){r=!0;try{for(;n.length>0;){const a=n.shift(),l=++t;await e(a.diffs,l,a)&&l===t&&a.onDisplayed?.(a.drawKey)}}finally{r=!1,n.length>0&&s()}}},o=()=>{i||(i=!0,queueMicrotask(()=>{i=!1,s()}))};return{enqueue(a,l,f){const u=n.findIndex(c=>c.drawKey===l);u>=0?n[u]={diffs:a,drawKey:l,onDisplayed:f}:(n.length>=Oa&&(n.shift(),Qe()?.onQueueSuperseded()),n.push({diffs:a,drawKey:l,onDisplayed:f})),o()},reset(){t+=1,n.length=0},isLatestSeq(a){return a===t},getLatestSeq(){return t}}}function Na(e,t=2){const n=[],r=new Set;let i=0,s=!1,o=0;const a=(f,u)=>`${f}|${u}`,l=async()=>{if(!s){s=!0;try{for(;i<t&&n.length>0;){const f=n.shift(),u=a(f.displayAtMs,f.drawKey);if(r.has(u))continue;r.add(u),i+=1;const c=o;try{await e(f)}finally{if(r.delete(u),i-=1,c!==o)return}}}finally{s=!1,n.length>0&&i<t&&l()}}};return{enqueue(f){const u=a(f.displayAtMs,f.drawKey);r.has(u)||n.some(c=>a(c.displayAtMs,c.drawKey)===u)||(n.push(f),l())},isQueuedOrInflight(f,u){const c=a(f,u);return r.has(c)?!0:n.some(d=>a(d.displayAtMs,d.drawKey)===c)},reset(){o+=1,n.length=0,r.clear(),i=0},pendingCount(){return n.length+i}}}function Va(){const e=new Map,t=n=>{n.bitmap.close()};return{has(n,r){return e.has(r)},markRendered(n,r,i,s,o){const a=e.get(r);a&&t(a),e.set(r,{displayAtMs:n,mouthKey:r,label:i,mouthPath:s,bitmap:o})},findForMouthKey(n){return e.get(n)??null},removeThrough(n){},pruneBefore(n){},reset(){for(const n of e.values())t(n);e.clear()},size(){return e.size}}}function Ua(e,t,n,r,i,s){const o=Mi(t,n,r,i,Mt,s);if(o.length===0)return{ready:0,total:0};let a=0;for(const l of o)e.has(l.displayAtMs,l.mouthKey)&&(a+=1);return{ready:a,total:o.length}}function Wa(e){const t=Va(),n=Yn(),r=new Set;let i="",s=null;const o=Na(async c=>{try{if(!e.supportsBufferedPlayback)return;const d=await e.compositePrefetchFrame(c.diffs,c.mouthKey);if(!d)return;t.markRendered(c.displayAtMs,c.mouthKey,c.label,c.mouthPath,d),Qe()?.onBufferPrefetched()}finally{r.delete(c.mouthKey)}},Gi),a=c=>{for(const d of c)t.has(d.displayAtMs,d.mouthKey)||r.has(d.mouthKey)||o.isQueuedOrInflight(0,d.mouthKey)||(r.add(d.mouthKey),o.enqueue({...d,displayAtMs:0,drawKey:d.mouthKey,diffs:{mouthPath:d.mouthPath,expressionPath:null}}))},l=(c,d,p,T=gn)=>{if(!e.supportsBufferedPlayback)return;const m=Math.max(0,d-Mt*4),E=Mi(c,m,d+T,p,Mt,n);a(E)},f=(c,d)=>{i=c,s=d},u=(c,d)=>!(i!==c||s!==d);return{reset(){t.reset(),o.reset(),r.clear(),Ce(n),i="",s=null,Qe()?.onBufferReset()},markExternallyDisplayed(c,d){f(c.split("|")[0]??c,d)},warmupTick(c){e.supportsBufferedPlayback&&l(c.queue,0,c.availablePaths,Math.max(ar,gn))},isWarmupReady(c,d=ar){if(!e.supportsBufferedPlayback)return!0;const{ready:p,total:T}=Ua(t,c.queue,0,d,c.availablePaths,n);return T===0?!1:p/T>=qi},getBufferedFrameCount:()=>t.size(),tick(c){const d=Qe();d?.onBufferTick(),l(c.queue,c.elapsedMs,c.availablePaths),t.pruneBefore(c.elapsedMs-gn);const p=Qn(c.queue,c.elapsedMs,c.availablePaths,n),T=en(p.diffPath),m=Ct({mouthPath:p.diffPath,expressionPath:c.expressionPath},c.expressionDrawKey),E=()=>(f(T,c.expressionPath),d?.onBufferHit(),{usedBuffer:!0,underrun:!1,held:!0});if(u(T,c.expressionPath)||c.playbackState.lastDrawnKey===m)return E();const R=t.findForMouthKey(T,c.elapsedMs,Mt);return R&&c.expressionPath!=null?(d?.onBufferHit(),{usedBuffer:!1,underrun:!1,held:!1}):R?(e.blitBitmap(c.canvas,R.bitmap),f(R.mouthKey,c.expressionPath),c.playbackState.lastDrawnKey=m,c.onStatus({diffPath:R.mouthPath,label:R.label}),c.onDisplayed(m,R.mouthPath,R.label),d?.onBufferHit(),{usedBuffer:!0,underrun:!1,held:!1}):(d?.onBufferUnderrun(),{usedBuffer:!1,underrun:!0,held:!1})}}}const za=`
5
+ `);_e=Ie.pop()??"";for(const ke of Ie)await nt(ke);if(ze){_e.trim()&&await nt(_e.trim()),be===V&&!ue.signal.aborted&&A&&N.markStreamComplete(n);break}}}catch(qe){if(ue.signal.aborted||!A)return;console.error("[realtimeVoice] avatar_speak failed:",qe),e("error"),z()}finally{I===ue&&(I=null)}},Be=w=>{const B=Hs(w);if(!B){console.warn("[realtimeVoice] server message with no payload",w);return}const J=String(B.type??"unknown");switch(J!=="avatar_metadata"&&J!=="avatar_audio_chunk"&&J!=="avatar_lipsync"&&J!=="avatar_interrupt"&&J!=="error"&&console.debug("[realtimeVoice] server message",J,B),J){case"avatar_metadata":k(B);break;case"avatar_audio_chunk":q(B);break;case"avatar_lipsync":X(B);break;case"avatar_interrupt":ee(B);break;case"error":{const ue=String(B.message??"Voice session error");console.error("[realtimeVoice] server error:",ue),e("error"),z();break}case"avatar_speak":oe(B);break}},et=()=>p||(T=new Us,p=new Gi.PipecatClient({transport:new Fn.WebSocketTransport({mediaManager:T,serializer:new Vs,recorderSampleRate:Kn,playerSampleRate:qn}),enableCam:!1,enableMic:!0,callbacks:{onBotReady:()=>{d=!0,e("idle"),z()},onDisconnected:()=>{d=!1,v()},onError:w=>{const B=typeof w=="object"&&w!==null&&"data"in w?String(w.data??w):String(w);console.error("[realtimeVoice]",B,w),e("error"),z()},onTransportStateChanged:w=>{w==="error"&&(e("error"),z())},onServerMessage:w=>{j(w)},onUserStartedSpeaking:()=>{},onBotStartedSpeaking:()=>{S(),Z("bot_started")},onBotStoppedSpeaking:()=>{A&&le()},onUserTranscript:w=>{String(w.text??""),m.onUserTranscript?.(w.text,!!w.final)},onBotOutput:w=>{m.onBotOutput?.(w.text)}}}),p);return{setDeveloperToken:w=>{},setTtsEngineId:w=>{c=w,N.setStreamTtsEngineId(w)},getTtsEngineId:()=>c,speak:async(w,B)=>{const J=w.trim();if(J){if(!p||!d)throw new Error("Realtime voice is not connected. Call connect() first.");W(),await p.sendText(J)}},stop:()=>{I?.abort(),I=null,V+=1,S(),W(),e("idle"),z()},connect:async w=>{if(w&&(m={...m,...w}),!m.authToken?.trim())throw new Error("Voice connect requires authToken (same JWT as SSE Authorization Bearer).");e("loading");const B=et();await B.initDevices();const J=bi(m);console.info("[realtimeVoice] connecting (avatar_audio_chunk RTVI):",J);try{await B.connect({wsUrl:J})}catch(ue){d=!1,e("error"),z();const be=ue instanceof Error?ue.message:"Realtime voice connect failed (WebSocket 101 only means upgrade OK — check authToken/origin/RTVI handshake)";throw new Error(`${be} — ${J}`)}d=!0,e("idle"),z()},disconnect:async()=>{if(L(),G=!1,se=!1,_.length=0,x=!1,I?.abort(),I=null,V+=1,S(),p)try{await p.disconnect()}catch(w){console.error("[realtimeVoice] disconnect failed:",w)}d=!1,v()},isConnected:()=>d,unlockAudio:async()=>{await N.primeAudioContext()},getVisemeQueue:()=>n,getWordQueue:()=>r,getFullVisemeQueue:()=>i,getFullWordQueue:()=>s,getSentenceEmotions:()=>a,getStreamMood:()=>l,getPlaybackElapsedMs:ae,isSpeaking:()=>N.isSpeaking(),isWarmingUp:()=>N.isWarmingUp(),releaseWarmupHold:()=>N.releaseWarmupHold(),setLipsyncWarmupHold:(w,B)=>{B&&(pe=B),N.setLipsyncWarmupHoldEnabled(w)},getVoiceStream:()=>N.getVoiceStream(),setPlaybackSpeed:w=>{N.setPlaybackSpeed(w)},getPlaybackSpeed:()=>N.getPlaybackSpeed(),subscribe:w=>(P.add(w),()=>P.delete(w))}}function ki(e,t,n){return{width:e.crop?.source_width??t,height:e.crop?.source_height??n}}function xi(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 Ei(e){return e?(e.w??0)>0&&(e.h??0)>0:!1}async function xt(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 ps(r,t)}async function Ii(e,t){if(!t)throw new Error("Missing asset key for encrypted JSON");const n=await xt(e,t),r=new TextDecoder().decode(n);return JSON.parse(r)}async function Ks(e){const t=new Blob([e],{type:"image/webp"});return createImageBitmap(t)}async function qs(e){const t=new Blob([e],{type:"image/webp"}),n=URL.createObjectURL(t);return new Promise((r,i)=>{const s=new Image;s.decoding="async",s.onload=()=>{URL.revokeObjectURL(n),r(s)},s.onerror=()=>{URL.revokeObjectURL(n),i(new Error("Failed to decode decrypted image"))},s.src=n})}async function Gs(e){const t=new Blob([e],{type:"image/png"});return createImageBitmap(t)}async function Ys(e){const t=new Blob([e],{type:"image/png"}),n=URL.createObjectURL(t);return new Promise((r,i)=>{const s=new Image;s.decoding="async",s.onload=()=>{URL.revokeObjectURL(n),r(s)},s.onerror=()=>{URL.revokeObjectURL(n),i(new Error("Failed to decode decrypted PNG"))},s.src=n})}function Qs(e){const t=new Blob([e],{type:"video/mp4"});return URL.createObjectURL(t)}async function Xs(e){const t=ys();if(!Bt())return t;if(!e)throw new Error("Missing asset key for encrypted idle video");const n=await xt(t,e);return Qs(n)}function vt(e,t){return`${e}/${t}_minus_sil.png`}const Ai=5;function mn(e){const t=e?.composite_threshold;if(typeof t=="number"&&t>0)return t;const n=e?.crop?.content_threshold;return typeof n=="number"&&n>0?n:Ai}const Js=["aa","E","I","O","U","PP","FF","DD","SS","TH","CH","RR","kk","nn"],Rn=["t01_0.25","t02_0.50","t03_0.75"],Zs=Rn.length,br=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 Tr(e,t){return`${e}__${t}`}function kr(e,t){return`pairs/${e}/${t}_minus_sil.png`}function bt(e){return`${e}_minus_sil.png`}function Gn(e,t){if(t.has(e))return e;const n=/^pairs\/([^/]+)\//.exec(e);if(!n)return null;const r=n[1].split("__")[1];if(!r||r==="sil")return null;const i=bt(r);return t.has(i)?i:null}function Mi(e,t){return e.filter(n=>t.has(n))}function ea(e,t,n){const r=Yn(e,t);return Mi(r,n).length>0}function Yn(e,t){if(e===t)return[];const n=[],r=Tr(e,t);if(br.has(r)){for(const s of Rn)n.push(kr(r,s));return n}const i=Tr(t,e);if(br.has(i)){for(let s=Zs-1;s>=0;s--)n.push(kr(i,Rn[s]));return n}return[]}function ta(e){return e<16?[1]:e<24?[1]:e<35?[0,1,2]:[0,1,2]}function na(e,t){return ta(t).map(r=>e[r]).filter(r=>r!=null)}function ra(e,t,n,r){if(r<=0)return 0;const s=Math.max(1,n-t)/r,o=e-t,a=Math.floor(o/s);return Math.min(r-1,Math.max(0,a))}function Pi(e,t,n){if(!n)return`${e}/${t}`;const r=t.split("/").pop()??t,i=r.includes(".")?r.slice(0,r.lastIndexOf(".")):r;return`${e}/${i}.bin`}const ia=[.32,.24,.16,.08,0],sa=ia.map(e=>`eyes_${e.toFixed(2)}`),aa=["eyes_0.32","eyes_0.16","eyes_0.00"],oa=["eyes_0.32","eyes_0.16","eyes_0.08","eyes_0.00"],Ue=2,ca=-20,tn=16,Ri={fear:-20,anger:-20,sad:-10,neutral:0,love:0,happy:0,disgust:10};function Ct(e){return`brow_${e}`}function at(e){return Ri[e]}function Ke(e){return Math.max(ca,Math.min(tn,e))}function la(e,t){if(e===t)return[];const n=e<t,r=n?Ue:-Ue,i=[];let s=e;if(s%Ue!==0){const o=n?Math.ceil(s/Ue)*Ue:Math.floor(s/Ue)*Ue,a=Ke(o);if(n?a>=t:a<=t)return[t];s=a,i.push(s)}for(;;){const o=s+r;if(n?o>=t:o<=t){t!==s&&i.push(t);break}s=o,i.push(s)}return i}function xr(e){const t=Ke(e);if(t%Ue===0)return[t];const n=Math.floor(t/Ue)*Ue,r=Math.min(tn,n+Ue),i=Ke(n);return t-i<=r-t?i===r?[i]:[i,r]:i===r?[r]:[r,i]}const ua=["fear","anger","sad","neutral","love","happy","disgust"],fa={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 Qe(e,t="neutral"){const n=String(e??"").trim().toLowerCase();return n?fa[n]??t:t}function Ci(e){return e===0?null:vt(Ct(e),"eyes_standard")}function Di(e){return Ci(at(e))}const da={[-20]:"anger",[-10]:"sad",0:"neutral",10:"disgust"};function Qn(e,t){if(!e)return null;if(t(e))return e;const n=e.match(/^brow_(-?\d+)\/(eyes_[^/]+)_minus_sil\.png$/);if(n){const i=Number(n[1]),s=n[2];for(const a of xr(i)){if(a===i)continue;const u=vt(Ct(a),s);if(t(u))return u}const o=da[i];if(o){const a=vt(o,s);if(t(a))return a}return null}const r=e.match(/^(fear|anger|sad|neutral|love|happy|disgust)\/(eyes_[^/]+)_minus_sil\.png$/);if(r){const i=r[1],s=r[2],o=at(i);for(const a of[o,...xr(o)]){const u=vt(Ct(a),s);if(t(u))return u}}return null}function Er(e,t){const n=Ct(at(e));return!t||t==="eyes_standard"?Di(e):e==="neutral"&&t==="eyes_standard"?null:vt(n,t)}function ma(e,t){const n=[];for(const r of t)n.push(Er(e,r));for(let r=t.length-2;r>=0;r--)n.push(Er(e,t[r]));return n.push(Di(e)),n}function ha(e){return vt(Ct(e),"eyes_standard")}function wa(e,t){return la(e,t).map(ha)}const pa=6;function ga(e,t){for(const n of e)if(t>=n.wtime&&t<n.wtime+n.wduration)return n;return null}function ya(e){const t=Ke(e);return t>=tn?tn:Ke(t+pa)}function _a(e,t,n){const r=Ke(n);return ga(t,e)?.emphasis?ya(r):r}function Ir(e){if(!e)return 0;const t=e.match(/^brow_(-?\d+)\//);if(!t?.[1])return null;const n=Number.parseInt(t[1],10);return Number.isFinite(n)?Ke(n):null}function _t(e,t){return e+Math.random()*(t-e)}function Yt(){return _t(14,32)}function va(e={}){const{initialDelayMs:t=800+Math.random()*1200,intervalMinMs:n=2200,intervalMaxMs:r=5800,doubleBlinkChance:i=.18,doubleBlinkGapMinMs:s=120,doubleBlinkGapMaxMs:o=220,fullBlinkChance:a=.75,postEmotionChangeDelayMs:u=380,minDwellMs:f=550}=e;let l="neutral",c="neutral",d=0,p=0,T=0,m={kind:"idle",nextBlinkAt:performance.now()+t},E=null,C="__eyes_open__|neutral|brow:0";function P(I=l){C=`${E??"__eyes_open__"}|${I}|brow:${p}`}function _(I,V=l){E=I;const G=Ir(I);G!=null?p=G:I==null&&(p=0),P(V)}function x(I){return Ci(I)}function O(I,V,G){const se=Ke(V),te=Ke(G);if(d=te,se===te){_(x(te));return}const re=[...wa(se,te),x(te)];m={kind:"browBlend",paths:re,index:0,holdUntil:I+Yt(),targetBrow:te},_(re[0]??null)}function A(I,V){m={kind:"idle",nextBlinkAt:I+_t(n,r)},c=V,_(x(d),V)}function ie(I,V,G){const se=G?aa:Math.random()<a?sa:oa;m={kind:"playing",paths:ma(V,se),index:0,holdUntil:I+Yt(),after:"idle",blinkEmotion:V},c=V,_(m.paths[0]??null,V)}function me(I){if(m.kind==="browBlend"){for(;I>=m.holdUntil&&m.index<m.paths.length-1;)m.index+=1,m.holdUntil=I+Yt();const V=m.paths[m.index]??null;_(V),I>=m.holdUntil&&m.index>=m.paths.length-1&&(p=m.targetBrow,d=m.targetBrow,_(x(m.targetBrow)),m={kind:"idle",nextBlinkAt:I+u});return}if(m.kind==="idle"){_(x(d),c),I>=m.nextBlinkAt&&ie(I,c,!1);return}if(m.kind==="doublePause"){_(x(d),m.blinkEmotion),I>=m.resumeAt&&ie(I,m.blinkEmotion,!0);return}if(m.kind==="playing"){for(;I>=m.holdUntil&&m.index<m.paths.length-1;)m.index+=1,m.holdUntil=I+Yt();if(_(m.paths[m.index]??null,m.blinkEmotion),I>=m.holdUntil&&m.index>=m.paths.length-1){if(m.after==="resumeIdle"){A(I+u,l);return}if(m.after==="doublePause"){m={kind:"doublePause",resumeAt:I+_t(s,o),blinkEmotion:m.blinkEmotion},_(x(d),m.blinkEmotion);return}if(m.after==="idle"&&Math.random()<i){m={kind:"doublePause",resumeAt:I+_t(s,o),blinkEmotion:m.blinkEmotion},_(x(d),m.blinkEmotion);return}A(I,m.blinkEmotion)}}}return{advance:me,setTargetEmotion(I,V){const G=Qe(I,l);if(G===l)return;const se=performance.now();!V?.force&&f>0&&!(l==="neutral"&&G!=="neutral")&&se-T<f||(l=G,c=G,T=se)},setTargetEyebrow(I){const V=Ke(I);if(V===d)return;const G=performance.now(),se=m.kind==="browBlend"?Ir(E)??p:p;d=V,!(V===se&&m.kind!=="browBlend")&&(m.kind==="playing"||m.kind==="doublePause"||O(G,se,V))},snapToEmotion(I){const V=Qe(I),G=at(V);l=V,c=V,d=G,p=G,T=performance.now(),m={kind:"idle",nextBlinkAt:performance.now()+_t(4e3,7e3)},_(x(G),V)},getTargetEmotion:()=>l,getTargetEyebrow:()=>d,getExpressionPath:()=>E,getDrawKey:()=>C,reset(){l="neutral",c="neutral",d=0,p=0,T=0,A(performance.now()+_t(n,r),"neutral")}}}function Sa(){const e=document.createElement("video");e.muted=!0,e.playsInline=!0,e.preload="auto",e.setAttribute("playsinline",""),e.loop=!0;let t=!1,n=null,r="";const i=()=>{n&&(URL.revokeObjectURL(n),n=null)};return{async load(s){t&&r===s||(i(),t=!1,r=s,s.startsWith("blob:")&&(n=s),await new Promise((o,a)=>{const u=()=>{const f=e.duration;if(!Number.isFinite(f)||f<=0){a(new Error(`Idle video has invalid duration: ${s}`));return}t=!0,e.currentTime=0,o()};e.addEventListener("loadeddata",u,{once:!0}),e.addEventListener("error",()=>a(new Error(`Failed to load idle video: ${s}`)),{once:!0}),e.src=s,e.load()}))},isReady(){return t},getVideo(){return e},setActive(s){t&&(s?e.paused&&e.play().catch(()=>{}):e.paused||e.pause())},restart(){t&&(e.currentTime=0)},dispose(){e.pause(),e.removeAttribute("src"),e.load(),i(),t=!1,r=""}}}const ba=50,Bi=400;function Ta(e,t,n){return e.filter(r=>{const i=r.queueIndex??-1;return i>=t&&i<=n})}function ka(e,t){const n=[];for(const r of e){const i=Ta(t,r.start_word,r.end_word);if(i.length===0)continue;const s=i[0],o=i[i.length-1];n.push({sentence:r,startMs:Math.max(0,s.wtime-ba),endMs:o.wtime+o.wduration+Bi})}return n.sort((r,i)=>r.startMs-i.startMs)}function xa(e,t,n,r="neutral"){const i=Qe(r);if(t.length===0)return i;if(n.length===0||e<n[0].wtime)return Qe(t[0]?.emotion,i);const s=ka(t,n);let o=null;for(const f of s)e>=f.startMs&&e<=f.endMs&&(o=f);if(o)return Qe(o.sentence.emotion,i);const a=n[n.length-1],u=a.wtime+a.wduration;return e>u+Bi?Qe(t[t.length-1]?.emotion,i):i}function Xn(e,t,n,r,i=Ai){const s=new OffscreenCanvas(n,r),o=s.getContext("2d",{willReadFrequently:!0});o.drawImage(e,0,0,n,r);const a=o.getImageData(0,0,n,r),u=o.createImageData(n,r);u.data.set(a.data);const l=new OffscreenCanvas(n,r).getContext("2d",{willReadFrequently:!0});for(const c of t){l.clearRect(0,0,n,r),l.drawImage(c,0,0,n,r);const d=l.getImageData(0,0,n,r);for(let p=0;p<u.data.length;p+=4){const T=d.data[p],m=d.data[p+1],E=d.data[p+2];Math.max(T,m,E)>i&&(u.data[p]=T,u.data[p+1]=m,u.data[p+2]=E,u.data[p+3]=255)}}return o.putImageData(u,0,0),s}let it=null,Tt=null;const nn=new Map;function Ea(){it=null,Tt=null,nn.clear()}Jr(Ea);function Ia(e){return e??Tt??void 0}function Jn(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 Aa(e){return Bt()?Ys(await xt(en(),e??"")):Jn(en())}async function Ar(e,t,n,r){const i=n?await Ii(e,r):await fetch(e).then(f=>{if(!f.ok)throw new Error(`Failed to load ${e}`);return f.json()}),s=i.sheets?.[0];if(!s?.path)throw new Error(`${e} has no sheets[0].path`);const o=n?await qs(await xt(Pi(t,s.path,n),r??"")):await Jn(`${t}/${s.path}`),a=new Map;for(const f of i.cells??[])f.path&&a.set(f.path,f);const u=new Map;for(const f of i.sheets??[])u.set(f.index,f);return{atlas:o,atlasMeta:i,cellByPath:a,sheetByIndex:u,diffBase:t}}async function Cn(e){const t=Ia(e),n=Bt();if(n&&!t)throw new Error("Encrypted assets enabled but no key provided");if(it&&(!n||Tt===(t??null))){const s=await it;return{...kt(s),visemePaths:[...s.viseme.cellByPath.keys()]}}Tt=t??null,nn.clear();const r=Zr();it=(async()=>{const s=await Aa(t),o=await Ar(ei(),r,n,t);let a=null;try{a=await Ar(ti(),r,n,t)}catch{a=null}return{sil:s,viseme:o,expression:a}})();const i=await it;return{...kt(i),visemePaths:[...i.viseme.cellByPath.keys()]}}async function Zn(e){if(await Cn(e),!it)throw new Error("Assets not loaded");return it}function kt(e){return ki(e.viseme.atlasMeta,e.sil.naturalWidth,e.sil.naturalHeight)}function Ma(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 rn(e,t,n){const r=`${t.diffBase}::${n}`,i=nn.get(r);if(i)return i;const s=(async()=>{const o=t.cellByPath.get(n);if(!o)throw new Error(`No atlas cell for path: ${n}`);const a=xi(t.atlasMeta,o),u=kt(e);if(Ei(o)){const c=Ma(t,o),d=document.createElement("canvas");d.width=u.width,d.height=u.height;const p=d.getContext("2d");return p.fillStyle="#000",p.fillRect(0,0,u.width,u.height),p.drawImage(c,a.x,a.y),d}const f=`${t.diffBase}/${n}`,l=await Jn(f);if(l.naturalWidth===u.width&&l.naturalHeight===u.height)return l;throw new Error(`Diff PNG wrong size for ${n}`)})();return nn.set(r,s),s}async function Tn(e,t,n,r,i,s){if(i){const{width:p,height:T}=i;if(s&&!s()||t.readyState<HTMLMediaElement.HAVE_CURRENT_DATA)return;const m=document.createElement("canvas");m.width=p,m.height=T;const E=m.getContext("2d");if(E.clearRect(0,0,p,T),E.drawImage(t,0,0,p,T),s&&!s())return;(e.width!==p||e.height!==T)&&(e.width=p,e.height=T);const C=e.getContext("2d");C.clearRect(0,0,p,T),C.drawImage(m,0,0);return}const o=await Zn(),a=mn(o.viseme.atlasMeta),{width:u,height:f}=kt(o);(e.width!==u||e.height!==f)&&(e.width=u,e.height=f);const l=[],c=e.getContext("2d");if(c.clearRect(0,0,u,f),t.readyState<HTMLMediaElement.HAVE_CURRENT_DATA){const p=o.sil;c.drawImage(p,0,0,u,f);return}if(l.length===0){c.drawImage(t,0,0,u,f);return}const d=Xn(t,l,u,f,a);c.drawImage(d,0,0)}async function Dn(e,t,n){const r=await Zn(Tt??void 0),i=mn(r.viseme.atlasMeta),{width:s,height:o}=kt(r);(e.width!==s||e.height!==o)&&(e.width=s,e.height=o);const a=[];if(t.mouthPath){const l=new Set(r.viseme.cellByPath.keys()),c=Gn(t.mouthPath,l)??(l.has(t.mouthPath)?t.mouthPath:null);c&&a.push(await rn(r,r.viseme,c))}if(t.expressionPath&&r.expression){const l=Qn(t.expressionPath,c=>r.expression.cellByPath.has(c));l&&a.push(await rn(r,r.expression,l))}const u=e.getContext("2d");if(u.clearRect(0,0,s,o),a.length===0){u.drawImage(r.sil,0,0,s,o);return}const f=Xn(r.sil,a,s,o,i);u.drawImage(f,0,0)}async function Pa(e,t){const n=await Zn(Tt??void 0),r=mn(n.viseme.atlasMeta),{width:i,height:s}=kt(n),o=[];if(e.mouthPath){const l=new Set(n.viseme.cellByPath.keys()),c=Gn(e.mouthPath,l)??(l.has(e.mouthPath)?e.mouthPath:null);c&&o.push(await rn(n,n.viseme,c))}if(e.expressionPath&&n.expression){const l=Qn(e.expressionPath,c=>n.expression.cellByPath.has(c));l&&o.push(await rn(n,n.expression,l))}const a=new OffscreenCanvas(i,s),u=a.getContext("2d");if(o.length===0)return u.drawImage(n.sil,0,0,i,s),a.transferToImageBitmap();const f=Xn(n.sil,o,i,s,r);return u.drawImage(f,0,0),a.transferToImageBitmap()}async function Ra(e){await Dn(e,{mouthPath:null,expressionPath:null})}const Qt={fontFamily:"system-ui, -apple-system, sans-serif",fontSize:"clamp(0.875rem, 2.5vw, 1.125rem)",color:"rgba(255,255,255,0.85)"};function Ca(e){return e.length===0?"":e.map(t=>t.word).join(" ")}function Da(e){if(!e)return{enabled:!1,style:Qt};const t=e===!0?{}:e;return{enabled:!0,style:{fontFamily:t.fontFamily??Qt.fontFamily,fontSize:t.fontSize??Qt.fontSize,color:t.color??Qt.color}}}const Ba={position:"absolute",bottom:0,left:0,right:0,display:"flex",justifyContent:"center",padding:"0.75rem 1rem",pointerEvents:"none"},Fa={display:"inline-block",maxWidth:"100%",padding:"0.45rem 0.85rem",borderRadius:"0.75rem",background:"rgba(0,0,0,0.55)",lineHeight:1.4,textAlign:"center"},La={display:"-webkit-box",WebkitLineClamp:2,WebkitBoxOrient:"vertical",overflow:"hidden",maxWidth:"100%",margin:0};function Oa({text:e,style:t}){return M.jsx("div",{style:Ba,"aria-live":"polite","aria-atomic":"true",children:M.jsx("div",{style:{...Fa,fontFamily:t.fontFamily,fontSize:t.fontSize,color:t.color},children:M.jsx("p",{style:La,children:e})})})}const Na={inset:0,overflow:"hidden",pointerEvents:"none",position:"absolute",zIndex:3},Va={filter:"blur(22px)",height:"100%",inset:0,objectFit:"cover",objectPosition:"top",position:"absolute",transform:"scale(1.08)",width:"100%"},Ua={backdropFilter:"blur(10px)",WebkitBackdropFilter:"blur(10px)",inset:0,position:"absolute"};function Wa({thumbnailUrl:e}){const[t,n]=h.useState(!1);h.useEffect(()=>{n(!1)},[e]);const r=!!e&&t;return M.jsxs("div",{style:Na,"aria-hidden":!0,children:[e?M.jsx("img",{src:e,alt:"",style:{...Va,opacity:r?1:0,transition:"opacity 0.45s ease"},onLoad:()=>n(!0),onError:()=>n(!1)}):null,M.jsx("div",{style:{...Ua,background:r?"rgba(0, 0, 0, 0.28)":"rgba(10, 10, 11, 0.92)"}})]})}let Fi=null;function Mr(e){Fi=e}function Ze(){return Fi}function za(e){return`${e.from}→${e.to}@${e.fromVtime}`}function Pr(){return{rafTicksSpeaking:0,rafTicksDeduped:0,drawsRequested:0,drawsDisplayed:0,queueSuperseded:0,workerStale:0,rifeFramesOmittedByGap:0,transitionFramesSampled:0,transitionFramesDisplayed:0,transitionFramesMissed:0,bufferTicks:0,bufferHits:0,bufferUnderruns:0,bufferPrefetched:0}}function $a(){let e=Pr();const t=new Set,n=new Set,r=new Set;let i="",s=-1,o="";const a=()=>{e=Pr(),t.clear(),n.clear(),r.clear(),i="",s=-1,o=""},u=l=>{t.add(l)},f=l=>{l&&r.add(l)};return{reset:a,onRafTickSpeaking(){e.rafTicksSpeaking+=1},onDrawDeduped(){e.rafTicksDeduped+=1},onDrawRequested(){e.drawsRequested+=1},onQueueSuperseded(){e.queueSuperseded+=1},onWorkerStale(){e.workerStale+=1},onTransitionSample(l,c){const d=za(l);e.transitionFramesSampled+=1,d!==i&&(i=d,s=-1,o!==d&&(o=d,e.rifeFramesOmittedByGap+=l.omittedByGap)),c&&n.add(c),s>=0&&l.frameIdx>s+1&&(e.transitionFramesMissed+=l.frameIdx-s-1),s=l.frameIdx},onBufferTick(){e.bufferTicks+=1},onBufferHit(){e.bufferHits+=1},onBufferUnderrun(){e.bufferUnderruns+=1},onBufferPrefetched(){e.bufferPrefetched+=1},onBufferReset(){},onDrawDisplayed(l,c){if(e.drawsDisplayed+=1,l.transitionMeta){e.transitionFramesDisplayed+=1;const p=l.transitionMeta;u(p.fromVtime),u(p.toVtime),f(l.mouthPath);return}if(l.label.includes("→")){e.transitionFramesDisplayed+=1;return}const d=l.label.trim();if(!(!d||d==="sil")){for(const p of c)if(p.viseme===d&&l.elapsedMs>=p.vtime&&l.elapsedMs<p.vtime+p.vduration){u(p.vtime);break}}},snapshot(l,c){let d=0,p=0;for(const P of l)if(P.viseme!=="sil"){if(P.vtime>=c)break;d+=1,t.has(P.vtime)&&(p+=1)}const T=d>0?Math.round(p/d*100):100,m=e.queueSuperseded+e.workerStale+Math.max(0,e.drawsRequested-e.drawsDisplayed),E=d-p,C=e.bufferTicks>0?Math.round(e.bufferHits/e.bufferTicks*100):100;return{...e,bufferHitRate:C,renderLoss:m,visemeSlotsTotal:d,visemeSlotsCovered:p,visemeCoveragePct:T,transitionFramesUniqueSampled:n.size,transitionFramesUniquePainted:r.size,drawsDeduped:e.rafTicksDeduped,renderSkips:e.rafTicksDeduped+m,visemesShown:p,visemesSkipped:E,rifeTransitionFramesSkipped:e.transitionFramesMissed}}}}const Li=On,Ha=200,Rr=300,ja=100,Ka=600,Oi="__sil__";function Cr(e){return e.lastDrawnKey?e.lastDrawnKey.split("|")[0]===Oi:!1}function er(){return{lastDrawnKey:""}}function De(e){e.lastDrawnKey="",e.transitionCache=void 0}function qa(e,t){if(t?.transitionCache&&t.transitionCache.queueLength===e.length)return t.transitionCache.transitions;const n=hi(e);return t&&(t.transitionCache={queueLength:e.length,transitions:n}),n}function Ga(e,t){let n="sil";for(const r of e)r.viseme!=="sil"&&(t!=null&&r.vtime>t||(n=r.viseme));return n}function Ya(e,t,n,r=120){if(n!=="sil")return n;const i=Si(e,t,r);return i!=="sil"?i:Ga(e,t)}function Qa(e,t){return e==="sil"?!1:t?ea(e,"sil",t):Yn(e,"sil").length>0}function Xa(){return Li+Ka}function sn(e){return e??Oi}function tr(e,t,n,r,i=ja){if(e.length===0)return{diffPath:null,label:"sil"};if(t>=rt(e))return{diffPath:null,label:"sil"};const s=qa(e,r),o=Ds(s,t);if(o){const f=wi(o.fromVtime,o.toVtime,o.from,o.to);if(t>=f.transStart&&t<f.transEnd){let l=Yn(o.from,o.to);n&&(l=Mi(l,n));const c=na(l,f.effectiveGapMs);if(c.length>0){const d=ra(t,f.transStart,f.transEnd,c.length);return{diffPath:c[d]??c[c.length-1],label:`${o.from}→${o.to}`,transitionMeta:{from:o.from,to:o.to,fromVtime:o.fromVtime,toVtime:o.toVtime,frameIdx:d,frameCount:c.length,fullFrameCount:l.length,omittedByGap:Math.max(0,l.length-c.length)}}}return{diffPath:bt(o.to),label:o.to}}}const a=ln(e);let u=ui(a,t);return u==="sil"&&(u=Si(e,t,i)),u==="sil"?{diffPath:null,label:"sil"}:{diffPath:bt(u),label:u}}function Dt(e,t){const n=t??sn(e.expressionPath);return`${sn(e.mouthPath)}|${n}`}function Dr(e,t,n,r,i,s,o,a,u,f){const l=tr(t,n,u,s),c={mouthPath:l.diffPath,expressionPath:r},d=Dt(c,i),p=Ze();if(l.transitionMeta&&p?.onTransitionSample(l.transitionMeta,l.diffPath),d===s.lastDrawnKey){p?.onDrawDeduped();return}p?.onDrawRequested(),a(l),s.lastDrawnKey=d,o(e,c,d,T=>{T===d&&(s.lastDrawnKey=d)})}function kn(e,t,n,r,i,s,o=null,a=null){const u={mouthPath:a,expressionPath:t},f=o!=null?`|idle@${Math.round(o*1e3)}`:"",l=Dt(u,n)+f;!(o!=null)&&l===r.lastDrawnKey||(s(o!=null?t?"idle · blink":"idle":t?"blink":"sil"),i(e,u,l,d=>{d===l&&(r.lastDrawnKey=l)}))}function Ni(e,t,n,r,i=Pt,s){if(n<=t||e.length===0)return[];const o=s??er(),a=[];let u="";for(let f=t;f<n;f+=i){const l=tr(e,f,r,o),c=sn(l.diffPath);c!==u&&(u=c,a.push({displayAtMs:f,mouthPath:l.diffPath,mouthKey:c,label:l.label}))}return a}const Ja=3;function nr(e){let t=0;const n=[];let r=!1,i=!1;const s=async()=>{if(!r){r=!0;try{for(;n.length>0;){const a=n.shift(),u=++t;await e(a.diffs,u,a)&&u===t&&a.onDisplayed?.(a.drawKey)}}finally{r=!1,n.length>0&&s()}}},o=()=>{i||(i=!0,queueMicrotask(()=>{i=!1,s()}))};return{enqueue(a,u,f){const l=n.findIndex(c=>c.drawKey===u);l>=0?n[l]={diffs:a,drawKey:u,onDisplayed:f}:(n.length>=Ja&&(n.shift(),Ze()?.onQueueSuperseded()),n.push({diffs:a,drawKey:u,onDisplayed:f})),o()},reset(){t+=1,n.length=0},isLatestSeq(a){return a===t},getLatestSeq(){return t}}}function Za(e,t=2){const n=[],r=new Set;let i=0,s=!1,o=0;const a=(f,l)=>`${f}|${l}`,u=async()=>{if(!s){s=!0;try{for(;i<t&&n.length>0;){const f=n.shift(),l=a(f.displayAtMs,f.drawKey);if(r.has(l))continue;r.add(l),i+=1;const c=o;try{await e(f)}finally{if(r.delete(l),i-=1,c!==o)return}}}finally{s=!1,n.length>0&&i<t&&u()}}};return{enqueue(f){const l=a(f.displayAtMs,f.drawKey);r.has(l)||n.some(c=>a(c.displayAtMs,c.drawKey)===l)||(n.push(f),u())},isQueuedOrInflight(f,l){const c=a(f,l);return r.has(c)?!0:n.some(d=>a(d.displayAtMs,d.drawKey)===c)},reset(){o+=1,n.length=0,r.clear(),i=0},pendingCount(){return n.length+i}}}function eo(){const e=new Map,t=n=>{n.bitmap.close()};return{has(n,r){return e.has(r)},markRendered(n,r,i,s,o){const a=e.get(r);a&&t(a),e.set(r,{displayAtMs:n,mouthKey:r,label:i,mouthPath:s,bitmap:o})},findForMouthKey(n){return e.get(n)??null},removeThrough(n){},pruneBefore(n){},reset(){for(const n of e.values())t(n);e.clear()},size(){return e.size}}}function to(e,t,n,r,i,s){const o=Ni(t,n,r,i,Pt,s);if(o.length===0)return{ready:0,total:0};let a=0;for(const u of o)e.has(u.displayAtMs,u.mouthKey)&&(a+=1);return{ready:a,total:o.length}}function no(e){const t=eo(),n=er(),r=new Set;let i="",s=null;const o=Za(async c=>{try{if(!e.supportsBufferedPlayback)return;const d=await e.compositePrefetchFrame(c.diffs,c.mouthKey);if(!d)return;t.markRendered(c.displayAtMs,c.mouthKey,c.label,c.mouthPath,d),Ze()?.onBufferPrefetched()}finally{r.delete(c.mouthKey)}},is),a=c=>{for(const d of c)t.has(d.displayAtMs,d.mouthKey)||r.has(d.mouthKey)||o.isQueuedOrInflight(0,d.mouthKey)||(r.add(d.mouthKey),o.enqueue({...d,displayAtMs:0,drawKey:d.mouthKey,diffs:{mouthPath:d.mouthPath,expressionPath:null}}))},u=(c,d,p,T=Sn)=>{if(!e.supportsBufferedPlayback)return;const m=Math.max(0,d-Pt*4),E=Ni(c,m,d+T,p,Pt,n);a(E)},f=(c,d)=>{i=c,s=d},l=(c,d)=>!(i!==c||s!==d);return{reset(){t.reset(),o.reset(),r.clear(),De(n),i="",s=null,Ze()?.onBufferReset()},markExternallyDisplayed(c,d){f(c.split("|")[0]??c,d)},warmupTick(c){e.supportsBufferedPlayback&&u(c.queue,0,c.availablePaths,Math.max(hr,Sn))},isWarmupReady(c,d=hr){if(!e.supportsBufferedPlayback)return!0;const{ready:p,total:T}=to(t,c.queue,0,d,c.availablePaths,n);return T===0?!1:p/T>=rs},getBufferedFrameCount:()=>t.size(),tick(c){const d=Ze();d?.onBufferTick(),u(c.queue,c.elapsedMs,c.availablePaths),t.pruneBefore(c.elapsedMs-Sn);const p=tr(c.queue,c.elapsedMs,c.availablePaths,n),T=sn(p.diffPath),m=Dt({mouthPath:p.diffPath,expressionPath:c.expressionPath},c.expressionDrawKey),E=()=>(f(T,c.expressionPath),d?.onBufferHit(),{usedBuffer:!0,underrun:!1,held:!0});if(l(T,c.expressionPath)||c.playbackState.lastDrawnKey===m)return E();const C=t.findForMouthKey(T,c.elapsedMs,Pt);return C&&c.expressionPath!=null?(d?.onBufferHit(),{usedBuffer:!1,underrun:!1,held:!1}):C?(e.blitBitmap(c.canvas,C.bitmap),f(C.mouthKey,c.expressionPath),c.playbackState.lastDrawnKey=m,c.onStatus({diffPath:C.mouthPath,label:C.label}),c.onDisplayed(m,C.mouthPath,C.label),d?.onBufferHit(),{usedBuffer:!0,underrun:!1,held:!1}):(d?.onBufferUnderrun(),{usedBuffer:!1,underrun:!0,held:!1})}}}const ro=`
6
6
  in vec2 aPosition;
7
7
  out vec2 vTextureCoord;
8
8
 
@@ -30,7 +30,7 @@ void main(void)
30
30
  gl_Position = filterVertexPosition();
31
31
  vTextureCoord = filterTextureCoord();
32
32
  }
33
- `,Ha=`
33
+ `,io=`
34
34
  in vec2 vTextureCoord;
35
35
  out vec4 finalColor;
36
36
 
@@ -44,5 +44,5 @@ void main(void)
44
44
  float keep = step(uThreshold + 1e-6, peak);
45
45
  finalColor = vec4(color.rgb, keep);
46
46
  }
47
- `;function xr(e=5){const t=new we.Filter({glProgram:we.GlProgram.from({vertex:za,fragment:Ha,name:"threshold-key-filter"}),resources:{thresholdUniforms:{uThreshold:{value:e/255,type:"f32"}}}});return t.setThreshold=n=>{t.resources.thresholdUniforms.uniforms.uThreshold=n/255},t.getThreshold=()=>Math.round(t.resources.thresholdUniforms.uniforms.uThreshold*255),t}function $a(e,t,n){return e>n||t>n}function ja(e){return e?e.getParameter(e.MAX_TEXTURE_SIZE):4096}function Ka(e,t){return t!=null&&t>0?Math.floor(t):ja(e)}function qa(e,t){const n=document.createElement("canvas");n.width=t.w,n.height=t.h;const r=n.getContext("2d");if(!r)throw new Error("Failed to acquire 2d context for atlas cell crop");return r.drawImage(e,t.x,t.y,t.w,t.h,0,0,t.w,t.h),n}function Pi(e){return fetch(e).then(t=>{if(!t.ok)throw new Error(`Failed to load image: ${e}`);return t.blob()}).then(t=>createImageBitmap(t))}async function Er(e,t,n,r,i){const s=n?await yi(e,i):await fetch(e).then(c=>{if(!c.ok)throw new Error(`Failed to load ${e}`);return c.json()}),o=s.sheets?.[0];if(!o?.path)throw new Error(`${e} has no sheets[0].path`);const a=new Map,l=async(c,d)=>{const p=Si(t,d,n),T=n?await Fs(await bt(p,i??"")):await Pi(p);if($a(T.width,T.height,r))return console.info(`[PixiVisemeCompositor] Sheet ${d} (${T.width}x${T.height}) exceeds MAX_TEXTURE_SIZE=${r}; using per-cell crops.`),{mode:"cells",bitmap:T};const m=we.Texture.from(T);return m.source.scaleMode="nearest",{mode:"full",texture:m}};a.set(o.index,await l(o.index,o.path));for(const c of s.sheets??[])c.index!==o.index&&c.path&&a.set(c.index,await l(c.index,c.path));const f=new Map;for(const c of s.cells??[])c.path&&f.set(c.path,c);const u=new Map;for(const c of s.sheets??[])u.set(c.index,c);return{atlasMeta:s,cellByPath:f,sheetByIndex:u,diffBase:t,sheets:a}}async function Ga(e,t={}){const n=new we.Application;try{await n.init({canvas:e,width:842,height:1264,preference:"webgl",autoStart:!1,antialias:!1,resolution:1,autoDensity:!1,backgroundAlpha:1,backgroundColor:0,powerPreference:"high-performance"})}catch(b){throw n.destroy({removeView:!1}),b}if(n.renderer.type!==we.RendererType.WEBGL)throw n.destroy({removeView:!1}),new Error("Pixi did not initialize a WebGL renderer");const r=Ka(n.renderer.gl,t.maxTextureSize);let i=!1,s=!1,o=!1;const a=n.canvas,l=()=>{i=!0,!s&&!o&&(s=!0,t.onWebGlContextLost?.())};a.addEventListener("webglcontextlost",l);const f=new we.Sprite(we.Texture.EMPTY),u=new we.Sprite(we.Texture.EMPTY);u.visible=!1,u.alpha=0;const c=new we.Sprite(we.Texture.EMPTY),d=new we.Sprite(we.Texture.EMPTY),p=new we.Sprite(we.Texture.EMPTY);p.visible=!1;const T=xr(5),m=xr(5);c.filters=[T],d.filters=[m],n.stage.addChild(f),n.stage.addChild(u),n.stage.addChild(c),n.stage.addChild(d),n.stage.addChild(p);let E=null,R=null,P=null,g=null,x=null,L=null,A=null,ne=842,de=1264,M=null,z=5;const $=new Map;let J=null,Y=null,me=null;const K=Hr(()=>{$.clear(),L=null,A=null,E=null,M=null}),ee=(b,S)=>{ne=b,de=S,n.renderer.resize(b,S),(e.width!==b||e.height!==S)&&(e.width=b,e.height=S)},I=()=>{c.visible=!1,d.visible=!1,c.texture=we.Texture.EMPTY,d.texture=we.Texture.EMPTY,J=null,Y=null},G=()=>{x=null,u.visible=!1,u.alpha=0},U=()=>{f.visible=!0,f.width=ne,f.height=de,f.x=0,f.y=0},ue=()=>{u.width=ne,u.height=de,u.x=0,u.y=0},re=()=>{p.visible=!1,G(),E&&(f.texture=E,U())},oe=()=>{!x&&!u.visible||re()},pe=b=>{if(o||i||!E){re();return}const S=Math.max(0,b);if(!R||S<=0){re();return}I(),p.visible=!1,f.texture=R,U(),u.texture=E,ue(),u.alpha=0,u.visible=!0,x={startMs:performance.now(),durationMs:S},j()},ie=(b=performance.now())=>{if(!x)return!1;if(o||i)return oe(),!1;const S=(b-x.startMs)/Math.max(1,x.durationMs);if(S>=1)return re(),j(),!1;const k=Math.min(1,Math.max(0,S)),y=k*k*(3-2*k);return u.alpha=y,u.visible=!0,j(),!0},v=()=>{if(P){try{P.resource=null}catch{}P.destroy(),P=null}R&&(R.destroy(!1),R=null),g=null},O=(b,S)=>{const k=b.cellByPath.get(S);if(!k||!gi(k))return null;const y=`${b.diffBase}::${S}`;let V=$.get(y);if(!V){const Z=k.sheet??0,_e=b.sheets.get(Z);if(!_e)return null;let ve,Me=!1;if(_e.mode==="full")ve=new we.Texture({source:_e.texture.source,frame:new we.Rectangle(k.x,k.y,k.w,k.h)});else{const De=qa(_e.bitmap,k);ve=we.Texture.from(De),ve.source.scaleMode="nearest",Me=!0}V={texture:ve,ownsSource:Me},$.set(y,V)}return{texture:V.texture,cell:k}},H=(b,S,k,y)=>{if(!y||!k)return b.visible=!1,b.texture=we.Texture.EMPTY,!1;const V=O(k,y);if(!V)return b.visible=!1,b.texture=we.Texture.EMPTY,!1;const Z=pi(k.atlasMeta,V.cell);return S.setThreshold(z),b.texture=V.texture,b.x=Z.x,b.y=Z.y,b.width=V.cell.w,b.height=V.cell.h,b.visible=!0,!0},X=b=>{if(!b||!L)return null;const S=M??new Set(L.cellByPath.keys());return Hn(b,S)??(S.has(b)?b:null)},N=b=>{p.visible=!1,re();const S=X(b.mouthPath),k=b.expressionPath&&A?jn(b.expressionPath,y=>A.cellByPath.has(y)):null;S!==J?(H(c,T,L,S),J=S):S?c.visible=!0:c.visible=!1,k!==Y?(H(d,m,A,k),Y=k):k?d.visible=!0:d.visible=!1},j=()=>{if(!(o||i||document.hidden))try{n.render()}catch{}};return{async loadAssets(b){if(o)return{width:ne,height:de,visemePaths:[]};const S=Dt();if(S&&!b)throw new Error("Encrypted assets enabled but no key provided");const k=S?await Os(await bt(Qt(),b??"")):await Pi(Qt());E&&E.destroy(!0),E=we.Texture.from(k),E.source.scaleMode="linear";const y=$r();L=await Er(jr(),y,S,r,b);try{A=await Er(Kr(),y,S,r,b)}catch(Z){console.warn("[PixiVisemeCompositor] expression atlas unavailable:",Z),A=null}const V=wi(L.atlasMeta,k.width,k.height);return ee(V.width,V.height),z=un(L.atlasMeta),T.setThreshold(z),m.setThreshold(z),M=new Set(L.cellByPath.keys()),$.clear(),re(),I(),j(),{width:V.width,height:V.height,visemePaths:[...L.cellByPath.keys()]}},getVisemeAtlasPaths(){return M},drawLiveFrame(b){o||i||!E||(oe(),N(b),j())},drawIdleVideo(b,S){o||i||document.hidden||S&&!S()||b.readyState<HTMLMediaElement.HAVE_CURRENT_DATA||(G(),I(),p.visible=!1,!R||g!==b?(v(),P=new we.VideoSource({resource:b,autoPlay:!1,updateFPS:0}),P.autoUpdate=!1,R=new we.Texture({source:P}),g=b):R.source.update(),f.texture=R,U(),j())},beginIdleToSilCrossfade:pe,tickIdleToSilCrossfade:ie,finishIdleToSilCrossfade:oe,isIdleToSilCrossfading(){return x!=null},renderSilOnly(){o||i||!E||(I(),re(),j())},blitBitmap(b){o||i||(oe(),I(),me&&(me.destroy(!0),me=null),me=we.Texture.from(b),p.texture=me,p.visible=!0,p.x=0,p.y=0,p.width=ne,p.height=de,f.visible=!1,j())},async compositePrefetchFrame(b){return null},renderFrame:j,isContextLost(){return i},dispose(){if(o)return;o=!0,a.removeEventListener("webglcontextlost",l),K(),v(),me&&(me.destroy(!0),me=null);for(const{texture:S,ownsSource:k}of $.values())S.destroy(k);$.clear(),E&&(E.destroy(!0),E=null);const b=S=>{S.mode==="full"?S.texture.destroy(!0):S.bitmap.close()};if(L)for(const S of L.sheets.values())b(S);if(A)for(const S of A.sheets.values())b(S);T.destroy(!0),m.destroy(!0),n.destroy({removeView:!1},{children:!0,texture:!0})}}}const Ir=-1,qt=1e5,Ar=new Map;async function Ya(e){let t=Ar.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),Ar.set(e,t)}return new Worker(t,{name:"visemeDiffPreview"})}function Qa(){return typeof Worker<"u"&&typeof OffscreenCanvas<"u"}function Pn(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 Mr(e,t){let n=0,r=null;const i=Xn(async(s,o)=>(await An(),await Mn(e,s),i.isLatestSeq(o)));return{usesWorker:!1,usesPixi:!1,async loadAssets(s){const o=await An(s);return r=o.visemePaths?new Set(o.visemePaths):null,o},getVisemeAtlasPaths(){return r},async renderSilOnly(){n+=1,i.reset(),await va(e)},drawLiveFrame(s,o,a,l){i.enqueue(o,a,l)},async compositePrefetchFrame(s,o){try{return await _a(s)}catch{return null}},blitBitmap(s,o){Pn(s,o)},drawIdleVideo(){},beginIdleToSilCrossfade(){},tickIdleToSilCrossfade(){return!1},finishIdleToSilCrossfade(){},isIdleToSilCrossfading(){return!1},supportsBufferedPlayback:!0,async renderViseme(s,o){n+=1;const a=n;t.onStatus?.(o),await Mn(s,{mouthPath:_t(o),expressionPath:null})},dispose(){n+=1,i.reset()}}}function Xa(e,t,n){let r=null,i=1,s=0,o=!1,a=!1,l=null;const f=new Map,u=new Map;let c=qt;const d=Xn(async(P,g,x)=>(f.set(g,{drawKey:x.drawKey,onDisplayed:x.onDisplayed}),await E({type:"drawFrame",diffPath:P.mouthPath,expressionDiffPath:P.expressionPath,liveSeq:g},void 0,!0),!1)),p=P=>{if(P===Ir){let L=-1,A;for(const[ne,de]of f)ne>=L&&(L=ne,A=de);L>=0&&f.delete(L),A?.onDisplayed?.(A.drawKey);return}const g=-P,x=f.get(g);f.delete(g),x?.onDisplayed?.(x.drawKey)},T=new Map,m=(P,g)=>{a||!r||r.postMessage(P,[])},E=(P,g,x=!1)=>{if(a)return Promise.resolve();const L=i++;return new Promise((A,ne)=>{T.set(L,{resolve:de=>A(de),reject:ne,generation:typeof P.generation=="number"?P.generation:void 0,expectRenderDone:x}),m({...P,requestId:L})})},R=(async()=>{r=await Ya(n),r.onmessage=P=>{if(a)return;const g=P.data;if(g.type==="status"){t.onStatus?.(g.label);return}if(g.type==="frame"){if(g.generation<=-qt){const A=-g.generation,ne=u.get(A);u.delete(A),ne?.resolve(g.bitmap);return}const L=g.generation<0;if(!L&&g.generation!==s){g.bitmap.close();return}if(L&&!(g.generation===Ir)){const ne=-g.generation;if(!d.isLatestSeq(ne)){Qe()?.onWorkerStale(),g.bitmap.close();return}}if(L&&t.shouldAcceptLiveFrame&&!t.shouldAcceptLiveFrame()){Qe()?.onWorkerStale(),g.bitmap.close();return}Pn(e,g.bitmap),g.bitmap.close(),L&&p(g.generation);return}const x=T.get(g.requestId);if(x)switch(g.type){case"ready":T.delete(g.requestId),x.resolve();break;case"loadAssetsDone":T.delete(g.requestId),l=g.visemePaths?.length?new Set(g.visemePaths):null,x.resolve({width:g.width,height:g.height,visemePaths:g.visemePaths});break;case"renderDone":if(x.expectRenderDone&&x.generation!=null&&g.generation!==x.generation)return;T.delete(g.requestId),x.resolve();break;case"renderAborted":T.delete(g.requestId),x.resolve();break;case"error":T.delete(g.requestId),t.onError?.(g.message),x.reject(new Error(g.message));break}},r.onerror=P=>{if(a)return;const g=P.message||"Worker error";t.onError?.(g);for(const[,x]of T)x.reject(new Error(g));T.clear()},await E({type:"init"}),o=!0})();return{usesWorker:!0,usesPixi:!1,async loadAssets(P){if(a)return{width:842,height:1264};if(await R,a)return{width:842,height:1264};if(!o)throw new Error("Worker init failed");return await E({type:"loadAssets",keyHex:P,urls:as(lt())})??{width:842,height:1264}},getVisemeAtlasPaths(){return l},async renderSilOnly(){if(a||(await R,a))return;s+=1,d.reset(),f.clear(),u.forEach(({resolve:g})=>g(null)),u.clear(),c=qt;const P=s;await E({type:"cancelLiveDraws"}),await E({type:"renderSil",generation:P},void 0,!0)},drawLiveFrame(P,g,x,L){a||R.then(()=>{a||d.enqueue(g,x,L)})},compositePrefetchFrame(P,g){return a?Promise.resolve(null):R.then(()=>{if(a)return null;const x=++c;return new Promise(L=>{u.set(x,{resolve:L}),E({type:"drawFrame",diffPath:P.mouthPath,expressionDiffPath:P.expressionPath,liveSeq:x},void 0,!0).catch(()=>{u.delete(x),L(null)})})})},blitBitmap(P,g){Pn(P,g)},drawIdleVideo(){},beginIdleToSilCrossfade(){},tickIdleToSilCrossfade(){return!1},finishIdleToSilCrossfade(){},isIdleToSilCrossfading(){return!1},supportsBufferedPlayback:!0,async renderViseme(P,g,x={}){if(a||(await R,a))return;s+=1,d.reset(),f.clear();const L=s;try{await E({type:"cancelLiveDraws"}),await E({type:"renderViseme",generation:L,to:g,from:x.from,transitionDurationMs:x.transitionDurationMs,gapMs:x.gapMs,threshold:x.threshold},void 0,!0)}catch(A){if(A?.name==="AbortError")return;throw A}},dispose(){if(!a){a=!0,s+=1,d.reset(),f.clear(),u.forEach(({resolve:P})=>P(null)),u.clear(),c=qt;for(const[,P]of T)P.resolve();T.clear(),r?.terminate(),r=null}}}}async function Ja(e,t){const n=await Ga(e,{onWebGlContextLost:t.onWebGlContextLost,maxTextureSize:t.pixiMaxTextureSize});let r=0,i=null,s=!1;const o=Xn(async(a,l)=>s?!1:t.shouldAcceptLiveFrame&&!t.shouldAcceptLiveFrame()?(Qe()?.onWorkerStale(),!1):(n.drawLiveFrame(a),o.isLatestSeq(l)));return{usesWorker:!1,usesPixi:!0,async loadAssets(a){if(s)return{width:842,height:1264};const l=await n.loadAssets(a);return i=l.visemePaths?.length?new Set(l.visemePaths):null,l},getVisemeAtlasPaths(){return i},async renderSilOnly(){s||(r+=1,o.reset(),n.renderSilOnly())},drawLiveFrame(a,l,f,u){s||o.enqueue(l,f,u)},async compositePrefetchFrame(a,l){if(s)return null;try{return await n.compositePrefetchFrame(a)}catch{return null}},blitBitmap(a,l){s||t.shouldAcceptLiveFrame&&!t.shouldAcceptLiveFrame()||n.blitBitmap(l)},drawIdleVideo(a,l){s||n.drawIdleVideo(a,l)},beginIdleToSilCrossfade(a){s||n.beginIdleToSilCrossfade(a)},tickIdleToSilCrossfade(a){return s?!1:n.tickIdleToSilCrossfade(a)},finishIdleToSilCrossfade(){s||n.finishIdleToSilCrossfade()},isIdleToSilCrossfading(){return s?!1:n.isIdleToSilCrossfading()},supportsBufferedPlayback:!1,async renderViseme(a,l){if(s)return;r+=1;const f=r;o.reset(),t.onStatus?.(l),n.drawLiveFrame({mouthPath:_t(l),expressionPath:null})},dispose(){s||(s=!0,r+=1,o.reset(),n.dispose())}}}function Pr(e,t){if(!Qa())return Mr(e,t);const n=$i(t.workerScriptUrl);try{return Xa(e,t,n)}catch{return Mr(e,t)}}function Za(e,t={}){if(t.preferLegacyRenderer)return Pr(e,t);let n=null,r=!1,i=null,s=!1;const o=()=>n?Promise.resolve(n):(i||(i=(async()=>{try{const a=await Ja(e,t);if(s)throw a.dispose(),new Error("Renderer disposed during Pixi init");return r=!0,n=a,a}catch(a){if(s)throw a instanceof Error?a:new Error(String(a));return console.warn("[AiTwin] Pixi WebGL renderer unavailable, using Canvas2D fallback:",a),n=Pr(e,t),r=!1,n}})()),i);return{get usesWorker(){return n?.usesWorker??!1},get usesPixi(){return r},async loadAssets(a){return(await o()).loadAssets(a)},getVisemeAtlasPaths(){return n?.getVisemeAtlasPaths()??null},async renderSilOnly(){return(await o()).renderSilOnly()},drawLiveFrame(a,l,f,u){o().then(c=>{s||c.drawLiveFrame(a,l,f,u)})},async compositePrefetchFrame(a,l){return(await o()).compositePrefetchFrame(a,l)},blitBitmap(a,l){n&&n.blitBitmap(a,l)},drawIdleVideo(a,l){n?.usesPixi&&n.drawIdleVideo(a,l)},beginIdleToSilCrossfade(a){n?.beginIdleToSilCrossfade(a)},tickIdleToSilCrossfade(a){return n?.tickIdleToSilCrossfade(a)??!1},finishIdleToSilCrossfade(){n?.finishIdleToSilCrossfade()},isIdleToSilCrossfading(){return n?.isIdleToSilCrossfading()??!1},get supportsBufferedPlayback(){return n?.supportsBufferedPlayback??!1},async renderViseme(a,l,f){return(await o()).renderViseme(a,l,f)},dispose(){s=!0,i=null,n?.dispose(),n=null}}}class eo extends Error{constructor(t,n){super(`${t} timed out after ${Math.round(n/1e3)}s`),this.name="LoadTimeoutError"}}function Sn(e,t,n){return new Promise((r,i)=>{const s=globalThis.setTimeout(()=>{i(new eo(n,t))},t);e.then(o=>{globalThis.clearTimeout(s),r(o)},o=>{globalThis.clearTimeout(s),i(o)})})}const to={position:"relative",display:"inline-block",lineHeight:0},no={display:"block",maxWidth:"100%",height:"auto"},ro={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 At(e){return Yi(e)?Un:Vn}function je(e,t){return t?.isSpeaking()||t?.isWarmingUp()?t:e.isSpeaking()||e.isWarmingUp()?e:t?.isConnected()?t:e}const Ri=h.forwardRef(function({id:t,avatarId:n,faceId:r,assets:i,authToken:s,apiBase:o,ttsEngineId:a=st,voiceId:l,speakingRate:f=Ft,className:u,style:c,canvasStyle:d,onStatusChange:p,onDisplayStatus:T,onError:m,onReady:E,showErrorOverlay:R=!0,onUserTranscript:P,onBotOutput:g,onRealtimeLipsyncDebug:x,onFrameRenderStats:L,lipsyncBufferedPlayback:A=!0,lipsyncPlaybackWarmupMs:ne=1500,pixiMaxTextureSize:de,captions:M},z){const $=h.useRef(null),J=h.useRef(null),Y=h.useRef(null),me=h.useRef(A);me.current=A;const K=h.useRef(ne);K.current=ne;const ee=h.useRef(0),I=h.useRef(Yn()),G=h.useRef(ua()),U=h.useRef(!1),ue=h.useRef(null),re=h.useRef(null),oe=h.useRef(0),pe=h.useRef(0),ie=h.useRef(0),v=h.useRef(null),O=h.useRef(null),H=h.useRef(!1),X=h.useRef(!1),N=h.useRef(!1),j=h.useRef(!1),b=h.useRef("sil"),S=h.useRef(0),k=h.useRef(!1),y=h.useRef(null),V=h.useRef(!1),[Z,_e]=h.useState("idle"),[ve,Me]=h.useState(null),[De,ln]=h.useState(!1),[Jn,Lt]=h.useState(!1),[fn,Zn]=h.useState({width:842,height:1264}),[w,C]=h.useState(null),[te,le]=h.useState(0),be=h.useRef(!1),ge=h.useRef(s??null),ye=o?.trim()||ot,Be=h.useRef(null),Se=h.useRef(null),$e=h.useRef(!1),Xe=h.useRef({width:842,height:1264}),Fe=h.useRef(null),Tt=h.useRef("sil"),Je=h.useRef(""),Ue=h.useMemo(()=>ba(M),[M]),Ee=h.useCallback(()=>{Je.current="",C(null)},[]);h.useEffect(()=>{Ue.enabled||Ee()},[Ue.enabled,Ee]);const Ze=h.useCallback(_=>{if(!Ue.enabled)return;const D=_.isSpeaking(),W=_.isWarmingUp();if(!D||W){Je.current&&Ee();return}const B=Sa(_.getWordQueue());if(!B){Je.current&&Ee();return}B!==Je.current&&(Je.current=B,C(B))},[Ue.enabled,Ee]),et=h.useRef(void 0),tt=h.useRef(new Map),Te=h.useRef(E),se=h.useRef(T),Ne=h.useRef(m),ft=h.useRef(P),kt=h.useRef(g),dt=h.useRef(x),xt=h.useRef(L),qe=h.useRef(Aa());Te.current=E,se.current=T,Ne.current=m,ft.current=P,kt.current=g,dt.current=x,xt.current=L,h.useEffect(()=>{const _=qe.current;return vr(_),()=>vr(null)},[]);const er=h.useCallback(_=>{const D=_?.ttsEngineId??a??Se.current?.ttsEngineId??st,W=_?.voiceId??l??Se.current?.voiceId??At(D);return{ttsEngineId:D,voiceId:W}},[a,l]),Ge=h.useCallback(_=>{Me(_),Ne.current?.(_)},[]),Et=h.useCallback(_=>{_e(_),p?.(_)},[p]),ce=h.useRef(En(Et,ye,{onLipsyncDebug:_=>dt.current?.(_)})),fe=h.useRef(null),tr=h.useRef(()=>{});h.useEffect(()=>(ce.current=En(Et,ye,{onLipsyncDebug:_=>dt.current?.(_)}),s&&ce.current.setDeveloperToken(s),ce.current.setTtsEngineId(a),()=>{ce.current.stop();const _=fe.current;_&&(_.disconnect(),fe.current=null)}),[Et,s,a,ye]);const nr=h.useCallback(()=>(fe.current||(fe.current=hi(Et,{speakingRate:f,onUserTranscript:(_,D)=>ft.current?.(_,D),onBotOutput:_=>kt.current?.(_),onLipsyncDebug:_=>dt.current?.(_)}),fe.current.setTtsEngineId(a),tr.current(!0)),fe.current),[Et,f,a]),Pe=h.useCallback(()=>{v.current!=null&&(clearTimeout(v.current),v.current=null)},[]),Re=h.useCallback(()=>{O.current!=null&&(clearTimeout(O.current),O.current=null),N.current=!1},[]),Ot=h.useCallback(()=>{if(j.current)return;const _=J.current;if(j.current=!0,Re(),H.current=!1,X.current=!1,!V.current||!y.current){_?.renderSilOnly();return}y.current.setActive(!1);const D=y.current.getVideo();if(_?.usesPixi){_.drawIdleVideo(D),_.beginIdleToSilCrossfade(br);return}(async()=>{const W=$.current;W&&await _n(W,D,null,void 0,Xe.current).catch(()=>{}),await new Promise(B=>setTimeout(B,br)),j.current&&await _?.renderSilOnly()})()},[Re]),rr=h.useCallback(()=>{!V.current||!y.current||(j.current=!1,J.current?.finishIdleToSilCrossfade(),Re(),N.current=!0,O.current=setTimeout(()=>{if(O.current=null,je(ce.current,fe.current).isSpeaking()){N.current=!1;return}if(H.current){N.current=!1;return}const _=y.current;if(!_){N.current=!1;return}_.restart(),_.setActive(!0);const D=_.getVideo();let W=!1;const B=()=>{W||(W=!0,D.removeEventListener("playing",q),N.current=!1)},q=()=>{B()};if(D.addEventListener("playing",q,{once:!0}),D.readyState>=HTMLMediaElement.HAVE_CURRENT_DATA&&!D.paused){B();return}setTimeout(B,300)},Ma))},[Re]),mt=h.useCallback(()=>{if(Pe(),se.current?.("sil"),H.current=!1,j.current=!1,!V.current||!y.current){N.current=!1;return}rr()},[Pe,rr]),dn=h.useCallback(async _=>{const D=pe.current,W=J.current,B=$.current,q=()=>{_?.fallbackOnly||(H.current=!1)};if(!W||!B||!De){q();return}if(je(ce.current,fe.current).isSpeaking()){q();return}if(_?.fallbackOnly){if(!H.current||(Ce(I.current),await W.renderSilOnly(),D!==pe.current)||je(ce.current,fe.current).isSpeaking())return;mt();return}if(Tr(I.current)){Ce(I.current),mt();return}if(me.current&&W.supportsBufferedPlayback&&!_?.fallbackOnly){if(Ce(I.current),Y.current?.reset(),await W.renderSilOnly(),D!==pe.current||je(ce.current,fe.current).isSpeaking())return;mt();return}const Ie=Ba(je(ce.current,fe.current).getVisemeQueue(),S.current,b.current),Le=Fa(Ie,Fe.current);if(Ce(I.current),!Le){if(await W.renderSilOnly(),D!==pe.current||je(ce.current,fe.current).isSpeaking())return;mt();return}try{await W.renderViseme(B,"sil",{from:Ie,transitionDurationMs:Ii})}catch(Ae){if(Ae?.name!=="AbortError")throw Ae}if(D!==pe.current){q();return}if(je(ce.current,fe.current).isSpeaking()){q();return}mt()},[De,mt]),ht=h.useCallback(()=>{if(X.current||H.current)return;X.current=!0,H.current=!0,Pe();const _=pe.current;dn().finally(()=>{X.current=!1}),v.current=setTimeout(()=>{v.current=null,_===pe.current&&dn({fallbackOnly:!0})},La())},[Pe,dn]),ir=h.useCallback(async()=>{const _=Math.floor(Date.now()/1e3);if(Be.current&&_<Be.current.expiresAt-60)return Be.current.key;const D=ge.current??await Pt();ge.current=D,ce.current.setDeveloperToken(D);const W=await ns(D,ye);return Be.current={key:W.value,expiresAt:W.expiresAt},W.value},[ye]);h.useEffect(()=>{s&&(ge.current=s,ce.current.setDeveloperToken(s))},[s]),h.useEffect(()=>{ce.current.setTtsEngineId(a),fe.current?.setTtsEngineId(a),Se.current&&(Se.current.ttsEngineId=a)},[a]),h.useEffect(()=>{const _=l??At(a);Se.current&&(Se.current.voiceId=_)},[l,a]);const nt=h.useMemo(()=>Wr(n,r),[n,r]),Li=h.useMemo(()=>i?JSON.stringify(i):nt?`face:${nt}`:`id:${t??""}`,[i,nt,t]);return h.useEffect(()=>{if(!t&&!i&&!nt){Ge("AiTwin requires `assets`, `avatarId`/`faceId`, or `id`");return}let _=!1;$e.current=!1,ln(!1),Lt(!1),Me(null),Se.current=null,y.current=null,V.current=!1;const D=$.current;if(!D)return;let W=null;return(async()=>{try{let B,q,xe,Ie;if(i)B=i,q=a,xe=l??At(q);else if(nt)se.current?.("loadFace"),B=kn(nt),q=a,xe=l??At(q);else{se.current?.("getAiTwin");const Q=await Sn(Ur(t),3e4,"getAiTwin");if(_)return;if(!Q.faceId?.trim())throw new Error("getAiTwin returned no faceId");q=Q.ttsEngineId,xe=l??Q.voiceId??At(q),Ie=Q.knowledgeContextId?.trim()||void 0,B=kn(Q.faceId)}Se.current={ttsEngineId:q,voiceId:xe,personaId:Ie},zr(B),y.current=la();const Le=!!(i&&!ut(i));W=Za(D,{preferLegacyRenderer:Le,pixiMaxTextureSize:de,onStatus:Q=>{_||se.current?.(Q)},onError:Q=>{_||Ge(Q)},shouldAcceptLiveFrame:()=>{if(U.current)return!0;if(H.current)return!1;const Q=je(ce.current,fe.current);return Q.isSpeaking()||Q.isWarmingUp()},onWebGlContextLost:()=>{_||be.current||(be.current=!0,queueMicrotask(()=>{_||le(Q=>Q+1)}))}}),J.current=W,Y.current=Wa(W),be.current=!1;const Ae=Q=>{const ae=()=>{if(!Q||K.current<=0)return!1;const ke=J.current;return ke?me.current&&ke.supportsBufferedPlayback?!0:ke.usesPixi:!1};ce.current.setLipsyncWarmupHold(Q,ae),fe.current?.setLipsyncWarmupHold(Q,ae)};tr.current=Ae,Ae(!0),se.current?.("auth");const We=ge.current??s??await Sn(Pt(),3e4,"getAuthToken");if(_)return;ge.current=We,ce.current.setDeveloperToken(We),ce.current.setTtsEngineId(q);const Nt=Dt()?await ir():void 0;if(_)return;se.current?.("loadAssets");const he=await Sn(W.loadAssets(Nt),18e4,"load face assets");if(!_&&he.width>0&&he.height>0&&(Xe.current=he,Zn(he)),_)return;Fe.current=W.getVisemeAtlasPaths(),$e.current=!0,ln(!0),Te.current?.(),W.renderSilOnly().then(()=>{_||se.current?.("sil")}),(async()=>{try{const Q=await Us(Nt);if(await y.current.load(Q),_)return;V.current=!0,Lt(!0),Ce(I.current),y.current.setActive(!0);const ae=y.current.getVideo();W.usesPixi?W.drawIdleVideo(ae):await _n(D,ae,null,void 0,Xe.current)}catch(Q){if(_)return;V.current=!1,Lt(!1),console.warn("[AiTwin] Idle video unavailable:",Q)}finally{_||se.current?.("idle")}})()}catch(B){if(_)return;if(B instanceof Gt){Ge(B.message);return}Ge(B instanceof Error?B.message:"Failed to load AI twin")}})(),()=>{_=!0,y.current?.dispose(),W?.dispose(),J.current=null}},[Li,i,nt,t,a,l,s,de,ir,Ge,te]),h.useEffect(()=>{const _={current:!1},D=()=>{const W=$.current,B=J.current,q=je(ce.current,fe.current);if(!W||!B||!De){oe.current=requestAnimationFrame(D);return}if(document.hidden){y.current?.setActive(!1),oe.current=requestAnimationFrame(D);return}const xe=q.isSpeaking(),Ie=q.isWarmingUp(),Le=xe&&!k.current,Ae=k.current&&!xe;Le&&(Pe(),Re(),H.current=!1,X.current=!1,Ce(I.current),Y.current?.reset(),qe.current.reset(),et.current=void 0,ie.current=0,b.current="sil",S.current=0,Ot()),Ae&&(G.current.reset(),y.current?.setActive(!1),Y.current?.reset(),B.finishIdleToSilCrossfade(),Ee(),ht());const We=Ae||H.current||N.current||j.current,Nt=A&&B.supportsBufferedPlayback;if(Ie){if(Ot(),V.current&&y.current?.setActive(!1),B.usesPixi&&B.isIdleToSilCrossfading()){B.tickIdleToSilCrossfade(performance.now()),q.getVisemeQueue().length>0&&ee.current===0&&(ee.current=performance.now()),k.current=q.isSpeaking(),oe.current=requestAnimationFrame(D);return}const he=q.getVisemeQueue();he.length>0&&ee.current===0&&(ee.current=performance.now()),G.current.advance(performance.now());const Q=G.current.getExpressionPath(),ae=G.current.getDrawKey(),ke={queue:he,elapsedMs:0,expressionPath:Q,expressionDrawKey:ae,availablePaths:Fe.current};let Oe=!1;Nt&&Y.current?(Y.current.warmupTick(ke),Oe=Y.current.isWarmupReady(ke,K.current)):B.usesPixi&&kr(W,he,0,Q,ae,I.current,(wt,Vt,mn,Ut)=>{B.drawLiveFrame(wt,Vt,mn,ze=>{Ut?.(ze),q.isWarmingUp()&&ze!==""&&!Tr({lastDrawnKey:ze})&&(ee.current=0,q.releaseWarmupHold())})},wt=>{se.current?.(wt.label)},Fe.current);const Ye=ee.current>0&&performance.now()-ee.current>Ki;se.current?.(Oe?"buffer ready":"buffering lipsync…"),(Oe||Ye)&&(ee.current=0,q.releaseWarmupHold()),Ze(q),k.current=q.isSpeaking(),oe.current=requestAnimationFrame(D);return}if(xe){Ot(),V.current&&y.current?.setActive(!1),B.usesPixi&&B.isIdleToSilCrossfading()&&B.finishIdleToSilCrossfade();const he=q.getVisemeQueue(),Q=q.getPlaybackElapsedMs();Es(he,Q),S.current=Q;const ae=he.length>0?Bt(he,Q):"sil";ae!=="sil"&&(b.current=ae);const ke=ha(Q,q.getSentenceEmotions(),q.getWordQueue(),q.getStreamMood());G.current.setTargetEmotion(ke),G.current.setTargetEyebrow(ca(Q,q.getWordQueue(),at(ke))),G.current.advance(performance.now());const Oe=G.current.getExpressionPath(),Ye=G.current.getDrawKey(),wt=(ze,hn,It,wn)=>{const sr={label:Tt.current,elapsedMs:Q,mouthPath:hn.mouthPath,transitionMeta:et.current};tt.current.set(It,sr),Y.current?.markExternallyDisplayed(It,Oe),B.drawLiveFrame(ze,hn,It,Wt=>{const Oi=tt.current.get(Wt)??sr;tt.current.delete(Wt),qe.current.onDrawDisplayed(Oi,he),Y.current?.markExternallyDisplayed(Wt,Oe),wn?.(Wt)})},Vt=ze=>{Tt.current=ze.label,et.current=ze.transitionMeta,se.current?.(ze.label)},mn=A&&B.supportsBufferedPlayback;let Ut=!1;mn&&Y.current&&(Ut=Y.current.tick({canvas:W,queue:he,elapsedMs:Q,expressionPath:Oe,expressionDrawKey:Ye,playbackState:I.current,availablePaths:Fe.current,onStatus:Vt,onDisplayed:(hn,It,wn)=>{qe.current.onDrawDisplayed({label:wn,elapsedMs:Q,mouthPath:It,transitionMeta:et.current},he)}}).usedBuffer),Ut||kr(W,he,Q,Oe,Ye,I.current,wt,Vt,Fe.current),qe.current.onRafTickSpeaking(),xt.current?.(qe.current.snapshot(he,Q))}else if(!We&&U.current){y.current?.setActive(!1),G.current.advance(performance.now());const he=G.current.getExpressionPath(),Q=G.current.getDrawKey();vn(W,he,Q,I.current,(ae,ke,Oe,Ye)=>B.drawLiveFrame(ae,ke,Oe,Ye),ae=>{if(re.current){se.current?.(re.current);return}const ke=G.current.getTargetEmotion();se.current?.(ae==="sil"||ae==="blink"?`${ke}${ae==="blink"?" · blink":""}`:ae)},null,ue.current)}else if(!We&&V.current&&y.current){const he=y.current,Q=he.getVideo();if(Q.readyState>=HTMLMediaElement.HAVE_CURRENT_DATA){he.setActive(!0);const ae=()=>!q.isSpeaking()&&!H.current&&!N.current&&!U.current;B.usesPixi?(B.drawIdleVideo(Q,ae),ae()&&se.current?.("idle")):_.current||(_.current=!0,_n(W,Q,null,void 0,Xe.current,ae).then(()=>se.current?.("idle")).finally(()=>{_.current=!1}))}else vn(W,null,"__sil__",I.current,(ae,ke,Oe,Ye)=>B.drawLiveFrame(ae,ke,Oe,Ye),ae=>se.current?.(ae))}else We||vn(W,null,"__sil__",I.current,(he,Q,ae,ke)=>B.drawLiveFrame(he,Q,ae,ke),he=>se.current?.(he));Ue.enabled&&Ze(q),k.current=xe,oe.current=requestAnimationFrame(D)};return oe.current=requestAnimationFrame(D),()=>{cancelAnimationFrame(oe.current),Pe(),Re(),ce.current.stop(),fe.current?.stop()}},[De,Jn,ht,Pe,Re,Ot,Ze,Ee,Ue.enabled]),h.useImperativeHandle(z,()=>({speakText:async(_,D)=>{const W=_.trim();if(!W)return;const B=J.current;if(!B||!$e.current&&!De)throw new Error("AI twin is not ready");const{ttsEngineId:q,voiceId:xe}=er(D);Me(null),Ee(),pe.current+=1,Pe(),Re(),H.current=!1,X.current=!1,b.current="sil",S.current=0,Ce(I.current),U.current=!1,ue.current=null,re.current=null,G.current.reset(),k.current=!1,j.current=!1,B.finishIdleToSilCrossfade();try{await ce.current.speak(W,{voiceId:xe,speakingRate:D?.speakingRate??f,ttsEngineId:q})}catch(Ie){throw j.current=!1,B.finishIdleToSilCrossfade(),ht(),Ge(Ie instanceof Error?Ie.message:"TTS failed"),Ie}},stop:()=>{pe.current+=1,Pe(),Re(),H.current=!1,X.current=!1,j.current=!1,J.current?.finishIdleToSilCrossfade(),ce.current.stop(),fe.current?.stop(),Ce(I.current),Y.current?.reset(),ee.current=0,k.current=!1,Ee(),ht()},setTtsEngineId:_=>{ce.current.setTtsEngineId(_),fe.current?.setTtsEngineId(_),Se.current&&(Se.current.ttsEngineId=_)},renderViseme:async(_,D)=>{const W=J.current,B=$.current;if(!W||!B||!$e.current)throw new Error("AI twin is not ready");await W.renderViseme(B,_,{from:D?.from,transitionDurationMs:D?.transitionDurationMs,gapMs:D?.gapMs,onStatus:q=>se.current?.(q)})},setEmotion:_=>{if(!$e.current)throw new Error("AI twin is not ready");const D=J.current,W=$.current;if(!D||!W)throw new Error("AI twin is not ready");pe.current+=1,Pe(),Re(),H.current=!1,X.current=!1,N.current=!1,j.current=!1,ce.current.stop(),fe.current?.stop(),Ce(I.current),Y.current?.reset(),ee.current=0,k.current=!1,D.finishIdleToSilCrossfade(),y.current?.setActive(!1);const B=Ke(_);U.current=!0,ue.current=null,re.current=null,G.current.snapToEmotion(B);const q=G.current.getExpressionPath(),xe=G.current.getDrawKey(),Ie={mouthPath:null,expressionPath:q},Le=Ct(Ie,xe);I.current.lastDrawnKey="",D.drawLiveFrame(W,Ie,Le,We=>{We===Le&&(I.current.lastDrawnKey=Le)});const Ae=at(B);se.current?.(q?`${B} · brow ${Ae>0?"+":""}${Ae}`:`${B} · brow 0 (sil base)`)},getEmotion:()=>U.current?G.current.getTargetEmotion():null,clearEmotionPreview:()=>{U.current=!1,ue.current=null,re.current=null,G.current.reset(),Ce(I.current),se.current?.("idle")},setViseme:_=>{if(!$e.current)throw new Error("AI twin is not ready");const D=J.current,W=$.current;if(!D||!W)throw new Error("AI twin is not ready");pe.current+=1,Pe(),Re(),H.current=!1,X.current=!1,N.current=!1,j.current=!1,ce.current.stop(),fe.current?.stop(),Ce(I.current),Y.current?.reset(),ee.current=0,k.current=!1,D.finishIdleToSilCrossfade(),y.current?.setActive(!1);const B=nn(_);U.current=!0,re.current=B,ue.current=B==="sil"?null:_t(B),G.current.snapToEmotion("neutral");const q=G.current.getExpressionPath(),xe=G.current.getDrawKey(),Le={mouthPath:ue.current,expressionPath:q},Ae=Ct(Le,xe);I.current.lastDrawnKey="",D.drawLiveFrame(W,Le,Ae,We=>{We===Ae&&(I.current.lastDrawnKey=Ae)}),se.current?.(B)},getViseme:()=>U.current?re.current:null,isReady:()=>$e.current,getStatus:()=>Z,connect:async(_={})=>{Me(null);try{let D=_.authToken?.trim();D||(D=ge.current??s??await Pt(),ge.current=D);const W=_.voiceId?.trim()??l??Se.current?.voiceId,B=_.personaId?.trim()??Se.current?.personaId,q=nr();await q.unlockAudio(),await q.connect({..._,apiBase:_.apiBase?.trim()||ye,authToken:D,voiceId:W,personaId:B,speakingRate:_.speakingRate??f})}catch(D){throw Ge(D instanceof Error?D.message:"Voice connect failed"),D}},disconnect:async()=>{const _=fe.current;_&&(pe.current+=1,Pe(),Re(),H.current=!1,X.current=!1,j.current=!1,J.current?.finishIdleToSilCrossfade(),Ce(I.current),Y.current?.reset(),ee.current=0,k.current=!1,await _.disconnect(),ht())},isConnected:()=>fe.current?.isConnected()??!1,getVoiceStream:()=>fe.current?.getVoiceStream()??ce.current?.getVoiceStream()??null,setMuted:_=>{const D=ce.current,W=fe.current;D?.setMuted?.(_),W?.setMuted?.(_)},isMuted:()=>{const _=fe.current,D=ce.current;return _?.isMuted?.()??D?.isMuted?.()??!1},getPersonaId:()=>Se.current?.personaId?.trim()||null}),[De,f,s,l,Pe,Re,ht,Ge,er,nr,Z,ye]),F.jsxs("div",{className:u,style:{...to,...c},children:[F.jsx("canvas",{ref:$,width:fn.width,height:fn.height,style:{...no,...d},"aria-label":t?`AI twin ${t}`:"AI twin face"}),R&&ve?F.jsx("div",{style:ro,children:ve}):null,Ue.enabled&&w?F.jsx(Ea,{text:w,style:Ue.style},w):null]})});async function io(e){try{const t=await e.json();if(typeof t.detail=="string"&&t.detail.trim())return t.detail;if(typeof t.error=="string"&&t.error.trim())return t.error}catch{}return`avatarReply failed (${e.status})`}async function Ci(e){const t=e.message.trim();if(!t)throw new Error("Message is required");const n=e.authToken.trim();if(!n)throw new Error("Auth token is required");const r=(e.apiBase?.trim()||ot).replace(/\/$/,""),i=await fetch(`${r}/avatarReply`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${n}`,Accept:"text/event-stream"},body:JSON.stringify({message:t,history:e.history??[],persona_id:e.personaId?.trim()||""})});if(!i.ok)throw new Error(await io(i));if(!i.body)throw new Error("avatarReply response body is empty");const s=i.body.getReader(),o=new TextDecoder;let a="",l="",f="",u="";for(;;){const{done:c,value:d}=await s.read();if(c)break;a+=o.decode(d,{stream:!0});const p=a.split(`
48
- `);a=p.pop()||"";for(const T of p){if(T.startsWith("event: ")){u=T.slice(7).trim();continue}if(!T.startsWith("data: "))continue;const m=T.slice(6).trim();if(!m)continue;let E;try{E=JSON.parse(m)}catch{continue}if(u==="spokenText")l=E.text||"",e.onSpokenText?.(l);else if(u==="displayText")f=E.text||"";else if(u==="error")throw new Error(E.error||"avatarReply stream error")}}if(!l.trim()||!f.trim())throw new Error("avatarReply stream missing displayText or spokenText");return{displayText:f.trim(),spokenText:l.trim()}}function so({muted:e}){return e?F.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none","aria-hidden":!0,children:[F.jsx("path",{d:"M11 5 6.5 9H3v6h3.5L11 19V5Z",fill:"currentColor"}),F.jsx("path",{d:"m16 9.5 5 5m0-5-5 5",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round"})]}):F.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none","aria-hidden":!0,children:[F.jsx("path",{d:"M11 5 6.5 9H3v6h3.5L11 19V5Z",fill:"currentColor"}),F.jsx("path",{d:"M15.5 8.5a4.5 4.5 0 0 1 0 7M18.5 6a8 8 0 0 1 0 12",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round"})]})}function ao(){return F.jsx("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"currentColor","aria-hidden":!0,children:F.jsx("path",{d:"M8 5.5v13l11-6.5L8 5.5Z"})})}function oo(){return F.jsx("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"currentColor","aria-hidden":!0,children:F.jsx("rect",{x:"6",y:"6",width:"12",height:"12",rx:"1.5"})})}function co(){return F.jsx("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none","aria-hidden":!0,children:F.jsx("path",{d:"M5 6.5A2.5 2.5 0 0 1 7.5 4h9A2.5 2.5 0 0 1 19 6.5v7A2.5 2.5 0 0 1 16.5 16H10l-4 3.5V16H7.5A2.5 2.5 0 0 1 5 13.5v-7Z",stroke:"currentColor",strokeWidth:"2",strokeLinejoin:"round"})})}function Di({className:e}){return F.jsx("span",{className:e??"aitwin-widget__spinner","aria-hidden":!0,children:F.jsx("svg",{viewBox:"0 0 24 24",fill:"none",children:F.jsx("circle",{cx:"12",cy:"12",r:"9",stroke:"currentColor",strokeWidth:"2.5",strokeLinecap:"round",strokeDasharray:"40 20"})})})}function uo({muted:e,onToggle:t}){return F.jsx("button",{type:"button",className:"aitwin-widget__mute",onClick:t,"aria-label":e?"Unmute":"Mute","aria-pressed":e,children:F.jsx(so,{muted:e})})}function lo(){return F.jsxs("div",{className:"aitwin-widget__connecting",role:"status","aria-live":"polite",children:[F.jsx(Di,{className:"aitwin-widget__spinner aitwin-widget__spinner--accent"}),F.jsx("span",{children:"Connecting..."})]})}function fo(e){const t=e.connecting||e.textSending||e.status==="loading"||e.status==="speaking",n=e.connecting?"Connecting...":e.connected?"End Talk":"Talk",r=["aitwin-widget__action",e.textMode&&!e.connecting?"":"aitwin-widget__action--primary",e.connecting?"aitwin-widget__action--connecting":""].filter(Boolean).join(" ");return F.jsxs("div",{className:"aitwin-widget__controls",children:[F.jsxs("div",{className:"aitwin-widget__actions",children:[F.jsxs("button",{type:"button",className:r,onClick:e.onTalk,disabled:!e.ready||e.connecting||e.textSending,"aria-busy":e.connecting,children:[e.connecting?F.jsx(Di,{className:"aitwin-widget__spinner aitwin-widget__spinner--on-accent"}):e.connected?F.jsx(oo,{}):F.jsx(ao,{}),F.jsx("span",{children:n})]}),F.jsxs("button",{type:"button",className:e.textMode?"aitwin-widget__action aitwin-widget__action--primary":"aitwin-widget__action",onClick:e.onTextMode,disabled:!e.ready||e.connecting||e.textSending,"aria-pressed":e.textMode,children:[F.jsx(co,{}),F.jsx("span",{children:"Text"})]})]}),e.textMode?F.jsxs("form",{className:"aitwin-widget__composer",onSubmit:i=>{i.preventDefault(),e.onSendText()},children:[F.jsx("input",{type:"text",className:"aitwin-widget__composer-input",value:e.textDraft,onChange:i=>e.onTextDraftChange(i.target.value),placeholder:e.textSending?"Getting reply...":"Type a message…",autoComplete:"off",disabled:!e.ready||t}),F.jsx("button",{type:"submit",className:"aitwin-widget__composer-send",disabled:!e.ready||t||!e.textDraft.trim()&&!e.textSending,"aria-busy":e.textSending,children:e.textSending?"…":"Send"})]}):null,e.error?F.jsx("p",{className:"aitwin-widget__controls-error",role:"alert",children:e.error}):null]})}const Rr=97,mo=3500;function ho(e,t){const n=Math.max(0,e),r=1-Math.exp(-n/mo);return Math.min(Rr,Math.round(r*Rr))}function wo(e){const[t,n]=h.useState(null),[r,i]=h.useState(()=>Date.now());return h.useEffect(()=>{if(!e){n(null);return}const s=Date.now();n(s),i(s);let o=0;const a=()=>{i(Date.now()),o=window.requestAnimationFrame(a)};return o=window.requestAnimationFrame(a),()=>{window.cancelAnimationFrame(o)}},[e]),e?t==null?0:ho(r-t):100}const Cr=["Hold on, brushing my hair…","Teaching your twin your best angles…","Almost done—just picking an outfit…","Fixing the lighting… again…","Convincing the pixels to cooperate…","One sec, teaching it to smize…","Warming up the face muscles…","Applying digital moisturizer…","Finding your good side…","Telling the algorithm you're photogenic…","Checking teeth for spinach…","Practicing your signature look…","Ironing the virtual collar…","Whispering encouragement to the GPU…","Calibrating charisma levels…"],po=3e3;function go({progress:e,thumbnailUrl:t,rotateMessages:n=!0}){const[r,i]=h.useState(!1),[s,o]=h.useState(0);h.useEffect(()=>{i(!1)},[t]),h.useEffect(()=>{if(!n)return;const u=window.setInterval(()=>{o(c=>(c+1)%Cr.length)},po);return()=>window.clearInterval(u)},[n]);const a=!!t&&r,l=n?Cr[s]:"Loading face…",f=Math.max(0,Math.min(100,Math.round(e)));return F.jsxs("div",{className:"aitwin-widget__face-loading","aria-live":"polite","aria-label":`${l} ${f} percent`,children:[t?F.jsx("img",{src:t,alt:"","aria-hidden":!0,className:a?"aitwin-widget__face-loading-thumb aitwin-widget__face-loading-thumb--visible":"aitwin-widget__face-loading-thumb",onLoad:()=>i(!0),onError:()=>i(!1)}):null,F.jsx("div",{className:a?"aitwin-widget__face-loading-scrim aitwin-widget__face-loading-scrim--thumb":"aitwin-widget__face-loading-scrim"}),F.jsxs("div",{className:"aitwin-widget__face-loading-content",children:[F.jsx("p",{className:"aitwin-widget__face-loading-message",children:l},l),F.jsxs("div",{className:"aitwin-widget__face-loading-bar-wrap",children:[F.jsx("div",{role:"progressbar","aria-valuenow":f,"aria-valuemin":0,"aria-valuemax":100,className:"aitwin-widget__face-loading-track",children:F.jsx("div",{className:"aitwin-widget__face-loading-fill",style:{width:`${f}%`}})}),F.jsxs("p",{className:"aitwin-widget__face-loading-pct",children:[f,"%"]})]})]})]})}function Dr(e){const t=e.id?.trim()||void 0,n=e.faceId?.trim()||e.avatarId?.trim()||void 0;return{id:n?void 0:t,faceId:n,authToken:e.authToken?.trim()||void 0,apiBase:e.apiBase?.trim()||void 0,voiceId:e.voiceId?.trim()||void 0,speakingRate:e.speakingRate}}function yo(e){return[e.id??"",e.faceId??"",e.authToken?.slice(0,16)??"",e.voiceId??"",e.apiBase??"",String(e.speakingRate??"")].join("|")}const Br={display:"flex",alignItems:"center",justifyContent:"center",width:"100%",height:"100%",lineHeight:0},_o={display:"block",height:"100%",width:"100%",objectFit:"cover",objectPosition:"top"},vo=h.forwardRef(function({options:t},n){const r=h.useRef(null),i=h.useRef(t);i.current={...i.current,onReady:t.onReady,onStatusChange:t.onStatusChange,onError:t.onError,onUserTranscript:t.onUserTranscript,onBotOutput:t.onBotOutput};const[s,o]=h.useState(!!t.showControls),[a,l]=h.useState(()=>Dr(t)),[f,u]=h.useState(!1),[c,d]=h.useState(!1),[p,T]=h.useState(!1),[m,E]=h.useState(!1),[R,P]=h.useState("idle"),[g,x]=h.useState(null),[L,A]=h.useState(!1),[ne,de]=h.useState(!1),[M,z]=h.useState(""),[$,J]=h.useState(!1),[Y,me]=h.useState([]),[K,ee]=h.useState(t.personaId?.trim()||void 0),I=h.useCallback(y=>{i.current={...i.current,...y},y.showControls!==void 0&&o(!!y.showControls),y.personaId!==void 0&&ee(y.personaId.trim()||void 0),l(V=>Dr({id:y.id??V.id,faceId:y.faceId??y.avatarId??V.faceId,authToken:y.authToken??V.authToken,apiBase:y.apiBase??V.apiBase,voiceId:y.voiceId??V.voiceId,speakingRate:y.speakingRate??V.speakingRate}))},[]);h.useImperativeHandle(n,()=>({getTwin:()=>r.current,applyOptions:I}),[I]),h.useEffect(()=>{I(t)},[I,t.id,t.faceId,t.avatarId,t.authToken,t.apiBase,t.voiceId,t.speakingRate,t.showControls,t.personaId]);const G=h.useCallback(()=>{u(!0),x(null)},[]),U=h.useCallback(y=>{y==="idle"&&d(!0)},[]),ue=h.useCallback(y=>{P(y),i.current.onStatusChange?.(y)},[]),re=h.useCallback(y=>{x(y),u(!1),d(!1),E(!1),i.current.onError?.(y)},[]),oe=h.useCallback((y,V)=>{i.current.onUserTranscript?.(y,V)},[]),pe=h.useCallback(y=>{i.current.onBotOutput?.(y)},[]);h.useEffect(()=>{if(!s)return;const y=window.setInterval(()=>{T(!!r.current?.isConnected())},400);return()=>window.clearInterval(y)},[s,a]);const ie=yo(a),v=!!(a.id||a.faceId),O=f&&c,H=v&&!O&&!g,X=wo(H),N=h.useRef(ie);h.useEffect(()=>{O&&i.current.onReady?.()},[O]),h.useEffect(()=>{O&&r.current?.setMuted(L)},[O,L,a]),h.useEffect(()=>{me([])},[a.id,a.faceId]),h.useEffect(()=>{N.current!==ie&&(N.current=ie,u(!1),d(!1),x(null),E(!1),T(!1),P("idle"))},[ie]);const j=()=>{const y=r.current;if(!y?.isReady())return;if(x(null),de(!1),y.isConnected()){E(!1),y.disconnect().finally(()=>{T(!1)});return}E(!0);const V={authToken:a.authToken,voiceId:a.voiceId,speakingRate:a.speakingRate,apiBase:a.apiBase};y.connect(V).then(()=>{T(!!y.isConnected())}).catch(Z=>{const _e=Z instanceof Error?Z.message:"Failed to connect voice.";x(_e),i.current.onError?.(_e)}).finally(()=>{E(!1)})},b=()=>{de(y=>!y),x(null)},S=()=>{const y=M.trim(),V=r.current;!y||!V?.isReady()||$||(x(null),z(""),J(!0),i.current.onUserTranscript?.(y,!0),(async()=>{try{const Z=a.authToken?.trim()||await Pt(),_e=K||V.getPersonaId()?.trim()||void 0,ve=await Ci({message:y,authToken:Z,apiBase:a.apiBase||ot,personaId:_e,history:Y});me(Me=>[...Me,{role:"user",content:y},{role:"assistant",content:ve.displayText}]),i.current.onBotOutput?.(ve.displayText),await V.speakText(ve.spokenText,{voiceId:a.voiceId,speakingRate:a.speakingRate})}catch(Z){const _e=Z instanceof Error?Z.message:"Failed to get reply.";x(_e),i.current.onError?.(_e)}finally{J(!1)}})())},k=()=>{const y=!L;A(y),r.current?.setMuted(y)};return F.jsxs("div",{className:"aitwin-widget__layout",children:[F.jsxs("div",{className:"aitwin-widget__stage",children:[v?F.jsx("div",{style:Br,children:F.jsx(Ri,{ref:r,id:a.id,faceId:a.faceId,authToken:a.authToken,apiBase:a.apiBase,voiceId:a.voiceId,speakingRate:a.speakingRate,style:Br,canvasStyle:_o,onReady:G,onDisplayStatus:U,onStatusChange:ue,onError:re,onUserTranscript:oe,onBotOutput:pe},ie)}):F.jsx("p",{className:"aitwin-widget__hint",style:{padding:16},children:"Pass id or faceId to load a twin."}),H?F.jsx(go,{progress:X,thumbnailUrl:t.loadingThumbnailUrl}):null,s?F.jsx(uo,{muted:L,onToggle:k}):null,s&&m?F.jsx(lo,{}):null]}),s?F.jsx(fo,{ready:O,connected:p,connecting:m,status:R,textMode:ne,textDraft:M,textSending:$,error:g,onTalk:j,onTextMode:b,onTextDraftChange:z,onSendText:S}):null]})}),So=".aitwin-widget{--aitwin-border: rgba(255, 255, 255, .12);--aitwin-text: #f4f4f5;--aitwin-muted: #a1a1aa;--aitwin-accent: #f97316;--aitwin-accent-hover: #fb923c;--aitwin-font: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif;--aitwin-size: 1;--aitwin-stage-width: calc(200px * var(--aitwin-size));--aitwin-stage-height: calc(267px * var(--aitwin-size));--aitwin-action-height: calc(40px * var(--aitwin-size));--aitwin-action-font: calc(13px * var(--aitwin-size));--aitwin-action-radius: calc(10px * var(--aitwin-size));--aitwin-action-gap: calc(6px * var(--aitwin-size));--aitwin-mute-size: calc(28px * var(--aitwin-size));--aitwin-layout-gap: calc(8px * var(--aitwin-size));box-sizing:border-box;color:var(--aitwin-text);font-family:var(--aitwin-font);font-size:calc(12px * var(--aitwin-size));line-height:1.45;width:fit-content;max-width:100%}.aitwin-widget *,.aitwin-widget *:before,.aitwin-widget *:after{box-sizing:border-box}.aitwin-widget__layout{display:flex;flex-direction:column;gap:var(--aitwin-layout-gap);width:fit-content;max-width:100%}.aitwin-widget__stage{align-items:center;background:#0a0a0b;border:1px solid var(--aitwin-border);border-radius:calc(10px * var(--aitwin-size));display:flex;flex-shrink:0;height:var(--aitwin-stage-height);justify-content:center;line-height:0;overflow:hidden;position:relative;width:var(--aitwin-stage-width)}.aitwin-widget__stage .aitwin-root,.aitwin-widget__stage canvas{display:block;height:100%;object-fit:cover;object-position:top;width:100%}.aitwin-widget__hint{color:var(--aitwin-muted);font-size:calc(11px * var(--aitwin-size));margin:0}.aitwin-widget__mute{align-items:center;background:#28282cb8;border:none;border-radius:999px;color:#fff;cursor:pointer;display:inline-flex;height:var(--aitwin-mute-size);justify-content:center;padding:0;position:absolute;right:calc(8px * var(--aitwin-size));top:calc(8px * var(--aitwin-size));width:var(--aitwin-mute-size);z-index:2}.aitwin-widget__mute:hover{background:#37373cd9}.aitwin-widget__mute svg{height:calc(15px * var(--aitwin-size));width:calc(15px * var(--aitwin-size))}.aitwin-widget__controls{display:flex;flex-direction:column;gap:var(--aitwin-action-gap);width:var(--aitwin-stage-width)}.aitwin-widget__actions{display:grid;gap:var(--aitwin-action-gap);grid-template-columns:1fr 1fr;width:100%}.aitwin-widget__action{align-items:center;background:transparent;border:1.5px solid var(--aitwin-accent);border-radius:999px;color:var(--aitwin-accent);cursor:pointer;display:inline-flex;font-family:inherit;font-size:var(--aitwin-action-font);font-weight:600;gap:calc(6px * var(--aitwin-size));height:var(--aitwin-action-height);justify-content:center;padding:0 calc(10px * var(--aitwin-size))}.aitwin-widget__action svg{flex-shrink:0;height:calc(12px * var(--aitwin-size));width:calc(12px * var(--aitwin-size))}.aitwin-widget__action:hover:not(:disabled){background:#f973161a}.aitwin-widget__action:disabled{cursor:not-allowed;opacity:.45}.aitwin-widget__action--primary{background:var(--aitwin-accent);border-color:transparent;color:#fff}.aitwin-widget__action--primary:hover:not(:disabled){background:var(--aitwin-accent-hover)}.aitwin-widget__action--connecting:disabled{cursor:progress;opacity:1}.aitwin-widget__spinner{display:inline-flex;flex-shrink:0;height:calc(14px * var(--aitwin-size));width:calc(14px * var(--aitwin-size))}.aitwin-widget__spinner svg{animation:aitwin-widget-spin .8s linear infinite;display:block;height:100%;width:100%}.aitwin-widget__spinner--accent{color:var(--aitwin-accent);height:calc(16px * var(--aitwin-size));width:calc(16px * var(--aitwin-size))}.aitwin-widget__spinner--on-accent{color:#fff}@keyframes aitwin-widget-spin{to{transform:rotate(360deg)}}.aitwin-widget__connecting{align-items:center;backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);background:#ffffffe0;border-radius:999px;bottom:calc(14px * var(--aitwin-size));box-shadow:0 4px 16px #0000001f;color:#3f3f46;display:inline-flex;font-size:calc(12px * var(--aitwin-size));font-weight:600;gap:calc(8px * var(--aitwin-size));left:50%;line-height:1;padding:calc(8px * var(--aitwin-size)) calc(14px * var(--aitwin-size));pointer-events:none;position:absolute;transform:translate(-50%);z-index:3}.aitwin-widget__face-loading{background:#262626;inset:0;overflow:hidden;pointer-events:none;position:absolute;z-index:4}.aitwin-widget__face-loading-thumb{filter:blur(24px);height:100%;inset:0;object-fit:cover;object-position:top;opacity:0;position:absolute;transform:scale(1.05);transition:opacity .5s ease;width:100%}.aitwin-widget__face-loading-thumb--visible{opacity:1}.aitwin-widget__face-loading-scrim{background:#262626f2;inset:0;position:absolute}.aitwin-widget__face-loading-scrim--thumb{background:#00000040}.aitwin-widget__face-loading-content{align-items:center;bottom:0;display:flex;flex-direction:column;gap:calc(12px * var(--aitwin-size));inset-inline:0;padding:calc(40px * var(--aitwin-size)) calc(24px * var(--aitwin-size)) calc(32px * var(--aitwin-size));position:absolute;z-index:1}.aitwin-widget__face-loading-message{color:#ffffffe6;font-size:calc(14px * var(--aitwin-size));font-weight:500;line-height:1.35;margin:0;max-width:calc(240px * var(--aitwin-size));min-height:calc(2.5rem * var(--aitwin-size));text-align:center;transition:opacity .3s ease}.aitwin-widget__face-loading-bar-wrap{max-width:calc(220px * var(--aitwin-size));width:100%}.aitwin-widget__face-loading-track{background:#fff3;border-radius:999px;height:calc(4px * var(--aitwin-size));overflow:hidden;width:100%}.aitwin-widget__face-loading-fill{background:var(--aitwin-accent);border-radius:999px;height:100%;transition:width .3s ease-out}.aitwin-widget__face-loading-pct{color:#ffffffbf;font-size:calc(12px * var(--aitwin-size));margin:calc(8px * var(--aitwin-size)) 0 0;text-align:center}.aitwin-widget__composer{display:grid;gap:var(--aitwin-action-gap);grid-template-columns:1fr auto;width:100%}.aitwin-widget__composer-input{background:#ffffff0a;border:1px solid var(--aitwin-border);border-radius:var(--aitwin-action-radius);color:var(--aitwin-text);font-family:inherit;font-size:calc(12px * var(--aitwin-size));min-width:0;outline:none;padding:calc(8px * var(--aitwin-size)) calc(10px * var(--aitwin-size))}.aitwin-widget__composer-input:focus{border-color:#f973168c}.aitwin-widget__composer-send{background:var(--aitwin-accent);border:none;border-radius:var(--aitwin-action-radius);color:#fff;cursor:pointer;font-family:inherit;font-size:calc(12px * var(--aitwin-size));font-weight:600;padding:0 calc(12px * var(--aitwin-size))}.aitwin-widget__composer-send:disabled{cursor:not-allowed;opacity:.45}.aitwin-widget__controls-error{color:#fecaca;font-size:calc(11px * var(--aitwin-size));margin:0}.aitwin-widget--float{bottom:20px;filter:drop-shadow(0 12px 32px rgba(0,0,0,.45));height:fit-content;margin:0;max-width:calc(100vw - 40px);position:fixed;right:20px;width:fit-content;z-index:2147483000}",Fr="data-aitwin-widget-style";function bo(){if(typeof document>"u"||document.querySelector(`style[${Fr}]`))return;const e=document.createElement("style");e.setAttribute(Fr,"1"),e.textContent=So,document.head.appendChild(e)}const To=h.forwardRef(function(t,n){const r=h.useRef(null);h.useEffect(()=>{bo()},[]),h.useImperativeHandle(n,()=>({speakText:async(s,o)=>{const a=r.current?.getTwin();if(!a)throw new Error("AiTwinWidget: twin is not mounted");return a.speakText(s,o)},connect:async s=>{const o=r.current?.getTwin();if(!o)throw new Error("AiTwinWidget: twin is not mounted");return o.connect(s)},disconnect:async()=>{const s=r.current?.getTwin();if(s)return s.disconnect()},stop:()=>{r.current?.getTwin()?.stop()},isReady:()=>!!r.current?.getTwin()?.isReady(),isConnected:()=>!!r.current?.getTwin()?.isConnected(),getTwin:()=>r.current?.getTwin()??null}),[]);const i=!!t.float;return F.jsx("div",{className:i?"aitwin-widget aitwin-widget--float":"aitwin-widget",children:F.jsx(vo,{ref:r,options:t})})}),Bi="thumbnail.webp";function ko(e,t=Cn){const n=e.trim();if(!n)throw new Error("faceId is required");return`${t.replace(/\/$/,"")}/${n}/${Bi}`}const xo=new Set([".png",".jpg",".jpeg",".webp"]);function Fi(e=".png"){const t=e.toLowerCase();return xo.has(t)?`source${t}`:"source.png"}function Eo(e,t=Cn,n=".png"){const r=e.trim();if(!r)throw new Error("faceId is required");return`${t.replace(/\/$/,"")}/${r}/${Fi(n)}`}exports.AI_TWIN_THUMBNAIL_FILENAME=Bi;exports.AiTwin=Ri;exports.AiTwinNotFoundError=Gt;exports.AiTwinWidget=To;exports.CONSONANT_SKIP_GROUP=Jr;exports.DEFAULT_TTS_ENGINE_ID=st;exports.EMOTION_TO_EYEBROW=bi;exports.EXPRESSION_ATLAS_EMOTIONS=Zs;exports.MIC_SAMPLE_RATE=Wn;exports.OCULUS_VISEME_IDS=Gr;exports.PLAYBACK_SAMPLE_RATE=zn;exports.SPEAKING_RATE_MAX=cn;exports.SPEAKING_RATE_MIN=on;exports.TTS_ENGINE_CARTESIA=ct;exports.TTS_ENGINE_GOOGLE=Bn;exports.TTS_ENGINE_INWORLD=tn;exports.VISEME_IDS=Ws;exports.VISEME_SKIP_GAP_MS=xn;exports.VISEME_TEST_CARTESIA_VOICE_ID=Un;exports.VISEME_TEST_SPEAKING_RATE=Ft;exports.VISEME_TEST_VOICE_ID=Vn;exports.VISEME_VTIME_GRID_MS=Fn;exports.VOWEL_SKIP_GROUP=Xr;exports.aiTwinSourceFilename=Fi;exports.buildPlaybackTransitions=si;exports.buildPlaybackVisemeSeries=sn;exports.buildRawVisemeTransitions=ii;exports.buildVoiceWebSocketUrl=mi;exports.compactSkippableVisemes=On;exports.createAvatarTtsLipsyncController=En;exports.createRealtimeVoiceLipsyncController=hi;exports.emotionToEyebrow=at;exports.faceAssetUrls=kn;exports.fetchAiTwin=Ur;exports.fetchAvatarReply=Ci;exports.fetchDevAuthToken=Pt;exports.getAiTwinSourceUrl=Eo;exports.getAiTwinThumbnailUrl=ko;exports.listSkippedVisemeEntries=an;exports.listSkippedVisemes=ys;exports.normalizeOculusViseme=nn;exports.normalizeStreamEmotion=Ke;exports.resolveDirectFaceId=Wr;exports.resolveVisemeAtTime=Bt;exports.resolveVisemeFromPlaybackSeries=ti;exports.resolveWordAtTime=Is;exports.setActiveTwinAssets=zr;exports.snapVisemeQueueToGrid=Ln;exports.snapVisemeVtimeToGrid=Zr;
47
+ `;function Br(e=5){const t=new we.Filter({glProgram:we.GlProgram.from({vertex:ro,fragment:io,name:"threshold-key-filter"}),resources:{thresholdUniforms:{uThreshold:{value:e/255,type:"f32"}}}});return t.setThreshold=n=>{t.resources.thresholdUniforms.uniforms.uThreshold=n/255},t.getThreshold=()=>Math.round(t.resources.thresholdUniforms.uniforms.uThreshold*255),t}function so(e,t,n){return e>n||t>n}function ao(e){return e?e.getParameter(e.MAX_TEXTURE_SIZE):4096}function oo(e,t){return t!=null&&t>0?Math.floor(t):ao(e)}function co(e,t){const n=document.createElement("canvas");n.width=t.w,n.height=t.h;const r=n.getContext("2d");if(!r)throw new Error("Failed to acquire 2d context for atlas cell crop");return r.drawImage(e,t.x,t.y,t.w,t.h,0,0,t.w,t.h),n}function Vi(e){return fetch(e).then(t=>{if(!t.ok)throw new Error(`Failed to load image: ${e}`);return t.blob()}).then(t=>createImageBitmap(t))}async function Fr(e,t,n,r,i){const s=n?await Ii(e,i):await fetch(e).then(c=>{if(!c.ok)throw new Error(`Failed to load ${e}`);return c.json()}),o=s.sheets?.[0];if(!o?.path)throw new Error(`${e} has no sheets[0].path`);const a=new Map,u=async(c,d)=>{const p=Pi(t,d,n),T=n?await Ks(await xt(p,i??"")):await Vi(p);if(so(T.width,T.height,r))return console.info(`[PixiVisemeCompositor] Sheet ${d} (${T.width}x${T.height}) exceeds MAX_TEXTURE_SIZE=${r}; using per-cell crops.`),{mode:"cells",bitmap:T};const m=we.Texture.from(T);return m.source.scaleMode="nearest",{mode:"full",texture:m}};a.set(o.index,await u(o.index,o.path));for(const c of s.sheets??[])c.index!==o.index&&c.path&&a.set(c.index,await u(c.index,c.path));const f=new Map;for(const c of s.cells??[])c.path&&f.set(c.path,c);const l=new Map;for(const c of s.sheets??[])l.set(c.index,c);return{atlasMeta:s,cellByPath:f,sheetByIndex:l,diffBase:t,sheets:a}}async function lo(e,t={}){const n=new we.Application;try{await n.init({canvas:e,width:842,height:1264,preference:"webgl",autoStart:!1,antialias:!1,resolution:1,autoDensity:!1,backgroundAlpha:1,backgroundColor:0,powerPreference:"high-performance"})}catch(v){throw n.destroy({removeView:!1}),v}if(n.renderer.type!==we.RendererType.WEBGL)throw n.destroy({removeView:!1}),new Error("Pixi did not initialize a WebGL renderer");const r=oo(n.renderer.gl,t.maxTextureSize);let i=!1,s=!1,o=!1;const a=n.canvas,u=()=>{i=!0,!s&&!o&&(s=!0,t.onWebGlContextLost?.())};a.addEventListener("webglcontextlost",u);const f=new we.Sprite(we.Texture.EMPTY),l=new we.Sprite(we.Texture.EMPTY);l.visible=!1,l.alpha=0;const c=new we.Sprite(we.Texture.EMPTY),d=new we.Sprite(we.Texture.EMPTY),p=new we.Sprite(we.Texture.EMPTY);p.visible=!1;const T=Br(5),m=Br(5);c.filters=[T],d.filters=[m],n.stage.addChild(f),n.stage.addChild(l),n.stage.addChild(c),n.stage.addChild(d),n.stage.addChild(p);let E=null,C=null,P=null,_=null,x=null,O=null,A=null,ie=842,me=1264,I=null,V=5;const G=new Map;let se=null,te=null,re=null;const L=Jr(()=>{G.clear(),O=null,A=null,E=null,I=null}),le=(v,g)=>{ie=v,me=g,n.renderer.resize(v,g),(e.width!==v||e.height!==g)&&(e.width=v,e.height=g)},z=()=>{c.visible=!1,d.visible=!1,c.texture=we.Texture.EMPTY,d.texture=we.Texture.EMPTY,se=null,te=null},pe=()=>{x=null,l.visible=!1,l.alpha=0},N=()=>{f.visible=!0,f.width=ie,f.height=me,f.x=0,f.y=0},Q=()=>{l.width=ie,l.height=me,l.x=0,l.y=0},j=()=>{p.visible=!1,pe(),E&&(f.texture=E,N())},ae=()=>{!x&&!l.visible||j()},Se=v=>{if(o||i||!E){j();return}const g=Math.max(0,v);if(!C||g<=0){j();return}z(),p.visible=!1,f.texture=C,N(),l.texture=E,Q(),l.alpha=0,l.visible=!0,x={startMs:performance.now(),durationMs:g},W()},Z=(v=performance.now())=>{if(!x)return!1;if(o||i)return ae(),!1;const g=(v-x.startMs)/Math.max(1,x.durationMs);if(g>=1)return j(),W(),!1;const k=Math.min(1,Math.max(0,g)),b=k*k*(3-2*k);return l.alpha=b,l.visible=!0,W(),!0},S=()=>{if(P){try{P.resource=null}catch{}P.destroy(),P=null}C&&(C.destroy(!1),C=null),_=null},R=(v,g)=>{const k=v.cellByPath.get(g);if(!k||!Ei(k))return null;const b=`${v.diffBase}::${g}`;let $=G.get(b);if(!$){const q=k.sheet??0,X=v.sheets.get(q);if(!X)return null;let oe,Be=!1;if(X.mode==="full")oe=new we.Texture({source:X.texture.source,frame:new we.Rectangle(k.x,k.y,k.w,k.h)});else{const et=co(X.bitmap,k);oe=we.Texture.from(et),oe.source.scaleMode="nearest",Be=!0}$={texture:oe,ownsSource:Be},G.set(b,$)}return{texture:$.texture,cell:k}},ne=(v,g,k,b)=>{if(!b||!k)return v.visible=!1,v.texture=we.Texture.EMPTY,!1;const $=R(k,b);if(!$)return v.visible=!1,v.texture=we.Texture.EMPTY,!1;const q=xi(k.atlasMeta,$.cell);return g.setThreshold(V),v.texture=$.texture,v.x=q.x,v.y=q.y,v.width=$.cell.w,v.height=$.cell.h,v.visible=!0,!0},ee=v=>{if(!v||!O)return null;const g=I??new Set(O.cellByPath.keys());return Gn(v,g)??(g.has(v)?v:null)},H=v=>{p.visible=!1,j();const g=ee(v.mouthPath),k=v.expressionPath&&A?Qn(v.expressionPath,b=>A.cellByPath.has(b)):null;g!==se?(ne(c,T,O,g),se=g):g?c.visible=!0:c.visible=!1,k!==te?(ne(d,m,A,k),te=k):k?d.visible=!0:d.visible=!1},W=()=>{if(!(o||i||document.hidden))try{n.render()}catch{}};return{async loadAssets(v){if(o)return{width:ie,height:me,visemePaths:[]};const g=Bt();if(g&&!v)throw new Error("Encrypted assets enabled but no key provided");const k=g?await Gs(await xt(en(),v??"")):await Vi(en());E&&E.destroy(!0),E=we.Texture.from(k),E.source.scaleMode="linear";const b=Zr();O=await Fr(ei(),b,g,r,v);try{A=await Fr(ti(),b,g,r,v)}catch(q){console.warn("[PixiVisemeCompositor] expression atlas unavailable:",q),A=null}const $=ki(O.atlasMeta,k.width,k.height);return le($.width,$.height),V=mn(O.atlasMeta),T.setThreshold(V),m.setThreshold(V),I=new Set(O.cellByPath.keys()),G.clear(),j(),z(),W(),{width:$.width,height:$.height,visemePaths:[...O.cellByPath.keys()]}},getVisemeAtlasPaths(){return I},drawLiveFrame(v){o||i||!E||(ae(),H(v),W())},drawIdleVideo(v,g){o||i||document.hidden||g&&!g()||v.readyState<HTMLMediaElement.HAVE_CURRENT_DATA||(pe(),z(),p.visible=!1,!C||_!==v?(S(),P=new we.VideoSource({resource:v,autoPlay:!1,updateFPS:0}),P.autoUpdate=!1,C=new we.Texture({source:P}),_=v):C.source.update(),f.texture=C,N(),W())},beginIdleToSilCrossfade:Se,tickIdleToSilCrossfade:Z,finishIdleToSilCrossfade:ae,isIdleToSilCrossfading(){return x!=null},renderSilOnly(){o||i||!E||(z(),j(),W())},blitBitmap(v){o||i||(ae(),z(),re&&(re.destroy(!0),re=null),re=we.Texture.from(v),p.texture=re,p.visible=!0,p.x=0,p.y=0,p.width=ie,p.height=me,f.visible=!1,W())},async compositePrefetchFrame(v){return null},renderFrame:W,isContextLost(){return i},dispose(){if(o)return;o=!0,a.removeEventListener("webglcontextlost",u),L(),S(),re&&(re.destroy(!0),re=null);for(const{texture:g,ownsSource:k}of G.values())g.destroy(k);G.clear(),E&&(E.destroy(!0),E=null);const v=g=>{g.mode==="full"?g.texture.destroy(!0):g.bitmap.close()};if(O)for(const g of O.sheets.values())v(g);if(A)for(const g of A.sheets.values())v(g);T.destroy(!0),m.destroy(!0),n.destroy({removeView:!1},{children:!0,texture:!0})}}}const Lr=-1,Xt=1e5,Or=new Map;async function uo(e){let t=Or.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),Or.set(e,t)}return new Worker(t,{name:"visemeDiffPreview"})}function fo(){return typeof Worker<"u"&&typeof OffscreenCanvas<"u"}function Bn(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 Nr(e,t){let n=0,r=null;const i=nr(async(s,o)=>(await Cn(),await Dn(e,s),i.isLatestSeq(o)));return{usesWorker:!1,usesPixi:!1,async loadAssets(s){const o=await Cn(s);return r=o.visemePaths?new Set(o.visemePaths):null,o},getVisemeAtlasPaths(){return r},async renderSilOnly(){n+=1,i.reset(),await Ra(e)},drawLiveFrame(s,o,a,u){i.enqueue(o,a,u)},async compositePrefetchFrame(s,o){try{return await Pa(s)}catch{return null}},blitBitmap(s,o){Bn(s,o)},drawIdleVideo(){},beginIdleToSilCrossfade(){},tickIdleToSilCrossfade(){return!1},finishIdleToSilCrossfade(){},isIdleToSilCrossfading(){return!1},supportsBufferedPlayback:!0,async renderViseme(s,o){n+=1;const a=n;t.onStatus?.(o),await Dn(s,{mouthPath:bt(o),expressionPath:null})},dispose(){n+=1,i.reset()}}}function mo(e,t,n){let r=null,i=1,s=0,o=!1,a=!1,u=null;const f=new Map,l=new Map;let c=Xt;const d=nr(async(P,_,x)=>(f.set(_,{drawKey:x.drawKey,onDisplayed:x.onDisplayed}),await E({type:"drawFrame",diffPath:P.mouthPath,expressionDiffPath:P.expressionPath,liveSeq:_},void 0,!0),!1)),p=P=>{if(P===Lr){let O=-1,A;for(const[ie,me]of f)ie>=O&&(O=ie,A=me);O>=0&&f.delete(O),A?.onDisplayed?.(A.drawKey);return}const _=-P,x=f.get(_);f.delete(_),x?.onDisplayed?.(x.drawKey)},T=new Map,m=(P,_)=>{a||!r||r.postMessage(P,[])},E=(P,_,x=!1)=>{if(a)return Promise.resolve();const O=i++;return new Promise((A,ie)=>{T.set(O,{resolve:me=>A(me),reject:ie,generation:typeof P.generation=="number"?P.generation:void 0,expectRenderDone:x}),m({...P,requestId:O})})},C=(async()=>{r=await uo(n),r.onmessage=P=>{if(a)return;const _=P.data;if(_.type==="status"){t.onStatus?.(_.label);return}if(_.type==="frame"){if(_.generation<=-Xt){const A=-_.generation,ie=l.get(A);l.delete(A),ie?.resolve(_.bitmap);return}const O=_.generation<0;if(!O&&_.generation!==s){_.bitmap.close();return}if(O&&!(_.generation===Lr)){const ie=-_.generation;if(!d.isLatestSeq(ie)){Ze()?.onWorkerStale(),_.bitmap.close();return}}if(O&&t.shouldAcceptLiveFrame&&!t.shouldAcceptLiveFrame()){Ze()?.onWorkerStale(),_.bitmap.close();return}Bn(e,_.bitmap),_.bitmap.close(),O&&p(_.generation);return}const x=T.get(_.requestId);if(x)switch(_.type){case"ready":T.delete(_.requestId),x.resolve();break;case"loadAssetsDone":T.delete(_.requestId),u=_.visemePaths?.length?new Set(_.visemePaths):null,x.resolve({width:_.width,height:_.height,visemePaths:_.visemePaths});break;case"renderDone":if(x.expectRenderDone&&x.generation!=null&&_.generation!==x.generation)return;T.delete(_.requestId),x.resolve();break;case"renderAborted":T.delete(_.requestId),x.resolve();break;case"error":T.delete(_.requestId),t.onError?.(_.message),x.reject(new Error(_.message));break}},r.onerror=P=>{if(a)return;const _=P.message||"Worker error";t.onError?.(_);for(const[,x]of T)x.reject(new Error(_));T.clear()},await E({type:"init"}),o=!0})();return{usesWorker:!0,usesPixi:!1,async loadAssets(P){if(a)return{width:842,height:1264};if(await C,a)return{width:842,height:1264};if(!o)throw new Error("Worker init failed");return await E({type:"loadAssets",keyHex:P,urls:gs(ut())})??{width:842,height:1264}},getVisemeAtlasPaths(){return u},async renderSilOnly(){if(a||(await C,a))return;s+=1,d.reset(),f.clear(),l.forEach(({resolve:_})=>_(null)),l.clear(),c=Xt;const P=s;await E({type:"cancelLiveDraws"}),await E({type:"renderSil",generation:P},void 0,!0)},drawLiveFrame(P,_,x,O){a||C.then(()=>{a||d.enqueue(_,x,O)})},compositePrefetchFrame(P,_){return a?Promise.resolve(null):C.then(()=>{if(a)return null;const x=++c;return new Promise(O=>{l.set(x,{resolve:O}),E({type:"drawFrame",diffPath:P.mouthPath,expressionDiffPath:P.expressionPath,liveSeq:x},void 0,!0).catch(()=>{l.delete(x),O(null)})})})},blitBitmap(P,_){Bn(P,_)},drawIdleVideo(){},beginIdleToSilCrossfade(){},tickIdleToSilCrossfade(){return!1},finishIdleToSilCrossfade(){},isIdleToSilCrossfading(){return!1},supportsBufferedPlayback:!0,async renderViseme(P,_,x={}){if(a||(await C,a))return;s+=1,d.reset(),f.clear();const O=s;try{await E({type:"cancelLiveDraws"}),await E({type:"renderViseme",generation:O,to:_,from:x.from,transitionDurationMs:x.transitionDurationMs,gapMs:x.gapMs,threshold:x.threshold},void 0,!0)}catch(A){if(A?.name==="AbortError")return;throw A}},dispose(){if(!a){a=!0,s+=1,d.reset(),f.clear(),l.forEach(({resolve:P})=>P(null)),l.clear(),c=Xt;for(const[,P]of T)P.resolve();T.clear(),r?.terminate(),r=null}}}}async function ho(e,t){const n=await lo(e,{onWebGlContextLost:t.onWebGlContextLost,maxTextureSize:t.pixiMaxTextureSize});let r=0,i=null,s=!1;const o=nr(async(a,u)=>s?!1:t.shouldAcceptLiveFrame&&!t.shouldAcceptLiveFrame()?(Ze()?.onWorkerStale(),!1):(n.drawLiveFrame(a),o.isLatestSeq(u)));return{usesWorker:!1,usesPixi:!0,async loadAssets(a){if(s)return{width:842,height:1264};const u=await n.loadAssets(a);return i=u.visemePaths?.length?new Set(u.visemePaths):null,u},getVisemeAtlasPaths(){return i},async renderSilOnly(){s||(r+=1,o.reset(),n.renderSilOnly())},drawLiveFrame(a,u,f,l){s||o.enqueue(u,f,l)},async compositePrefetchFrame(a,u){if(s)return null;try{return await n.compositePrefetchFrame(a)}catch{return null}},blitBitmap(a,u){s||t.shouldAcceptLiveFrame&&!t.shouldAcceptLiveFrame()||n.blitBitmap(u)},drawIdleVideo(a,u){s||n.drawIdleVideo(a,u)},beginIdleToSilCrossfade(a){s||n.beginIdleToSilCrossfade(a)},tickIdleToSilCrossfade(a){return s?!1:n.tickIdleToSilCrossfade(a)},finishIdleToSilCrossfade(){s||n.finishIdleToSilCrossfade()},isIdleToSilCrossfading(){return s?!1:n.isIdleToSilCrossfading()},supportsBufferedPlayback:!1,async renderViseme(a,u){if(s)return;r+=1;const f=r;o.reset(),t.onStatus?.(u),n.drawLiveFrame({mouthPath:bt(u),expressionPath:null})},dispose(){s||(s=!0,r+=1,o.reset(),n.dispose())}}}function Vr(e,t){if(!fo())return Nr(e,t);const n=es(t.workerScriptUrl);try{return mo(e,t,n)}catch{return Nr(e,t)}}function wo(e,t={}){if(t.preferLegacyRenderer)return Vr(e,t);let n=null,r=!1,i=null,s=!1;const o=()=>n?Promise.resolve(n):(i||(i=(async()=>{try{const a=await ho(e,t);if(s)throw a.dispose(),new Error("Renderer disposed during Pixi init");return r=!0,n=a,a}catch(a){if(s)throw a instanceof Error?a:new Error(String(a));return console.warn("[AiTwin] Pixi WebGL renderer unavailable, using Canvas2D fallback:",a),n=Vr(e,t),r=!1,n}})()),i);return{get usesWorker(){return n?.usesWorker??!1},get usesPixi(){return r},async loadAssets(a){return(await o()).loadAssets(a)},getVisemeAtlasPaths(){return n?.getVisemeAtlasPaths()??null},async renderSilOnly(){return(await o()).renderSilOnly()},drawLiveFrame(a,u,f,l){o().then(c=>{s||c.drawLiveFrame(a,u,f,l)})},async compositePrefetchFrame(a,u){return(await o()).compositePrefetchFrame(a,u)},blitBitmap(a,u){n&&n.blitBitmap(a,u)},drawIdleVideo(a,u){n?.usesPixi&&n.drawIdleVideo(a,u)},beginIdleToSilCrossfade(a){n?.beginIdleToSilCrossfade(a)},tickIdleToSilCrossfade(a){return n?.tickIdleToSilCrossfade(a)??!1},finishIdleToSilCrossfade(){n?.finishIdleToSilCrossfade()},isIdleToSilCrossfading(){return n?.isIdleToSilCrossfading()??!1},get supportsBufferedPlayback(){return n?.supportsBufferedPlayback??!1},async renderViseme(a,u,f){return(await o()).renderViseme(a,u,f)},dispose(){s=!0,i=null,n?.dispose(),n=null}}}class po extends Error{constructor(t,n){super(`${t} timed out after ${Math.round(n/1e3)}s`),this.name="LoadTimeoutError"}}function xn(e,t,n){return new Promise((r,i)=>{const s=globalThis.setTimeout(()=>{i(new po(n,t))},t);e.then(o=>{globalThis.clearTimeout(s),r(o)},o=>{globalThis.clearTimeout(s),i(o)})})}const go={overflow:"hidden",position:"relative",display:"inline-block",lineHeight:0},yo={display:"block",maxWidth:"100%",height:"auto"},_o={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 Mt(e){return ss(e)?jn:Hn}function Ye(e,t){return t?.isSpeaking()||t?.isWarmingUp()?t:e.isSpeaking()||e.isWarmingUp()?e:t?.isConnected()?t:e}const Ui=h.forwardRef(function({id:t,avatarId:n,faceId:r,assets:i,authToken:s,apiBase:o,ttsEngineId:a=st,voiceId:u,speakingRate:f=Lt,className:l,style:c,canvasStyle:d,onStatusChange:p,onDisplayStatus:T,onError:m,onReady:E,showErrorOverlay:C=!0,loadingThumbnailUrl:P,onUserTranscript:_,onBotOutput:x,onRealtimeLipsyncDebug:O,onFrameRenderStats:A,lipsyncBufferedPlayback:ie=!0,lipsyncPlaybackWarmupMs:me=1500,idleHandoffHoldMs:I=Ha,pixiMaxTextureSize:V,captions:G},se){const te=h.useRef(null),re=h.useRef(null),L=h.useRef(null),le=h.useRef(ie);le.current=ie;const z=h.useRef(me);z.current=me;const pe=h.useRef(I);pe.current=I;const N=h.useRef(0),Q=h.useRef(er()),j=h.useRef(va()),ae=h.useRef(!1),Se=h.useRef(null),Z=h.useRef(null),S=h.useRef(0),R=h.useRef(0),ne=h.useRef(0),ee=h.useRef(null),H=h.useRef(null),W=h.useRef(!1),v=h.useRef(!1),g=h.useRef(!1),k=h.useRef(!1),b=h.useRef("sil"),$=h.useRef(0),q=h.useRef(!1),X=h.useRef(null),oe=h.useRef(!1),[Be,et]=h.useState("idle"),[Ot,Et]=h.useState(null),[tt,hn]=h.useState(!1),[rr,w]=h.useState(!1),[B,J]=h.useState(!1),[ue,be]=h.useState(),[ye,Te]=h.useState({width:842,height:1264}),[Oe,Ne]=h.useState(null),[wn,Nt]=h.useState(0),qe=h.useRef(!1),We=h.useRef(s??null),Ge=o?.trim()||ot,ft=h.useRef(null),_e=h.useRef(null),Ve=h.useRef(!1),nt=h.useRef({width:842,height:1264}),ze=h.useRef(null),ve=h.useRef("sil"),Ie=h.useRef(""),ke=h.useMemo(()=>Da(G),[G]),Pe=h.useCallback(()=>{Ie.current="",Ne(null)},[]);h.useEffect(()=>{ke.enabled||Pe()},[ke.enabled,Pe]);const dt=h.useCallback(y=>{if(!ke.enabled)return;const D=y.isSpeaking(),U=y.isWarmingUp();if(!D||U){Ie.current&&Pe();return}const F=Ca(y.getWordQueue());if(!F){Ie.current&&Pe();return}F!==Ie.current&&(Ie.current=F,Ne(F))},[ke.enabled,Pe]),mt=h.useRef(void 0),ht=h.useRef(new Map),Vt=h.useRef(E),ge=h.useRef(T),ir=h.useRef(m),sr=h.useRef(_),ar=h.useRef(x),Ut=h.useRef(O),or=h.useRef(A),wt=h.useRef($a());Vt.current=E,ge.current=T,ir.current=m,sr.current=_,ar.current=x,Ut.current=O,or.current=A,h.useEffect(()=>{const y=wt.current;return Mr(y),()=>Mr(null)},[]);const cr=h.useCallback(y=>{const D=y?.ttsEngineId??a??_e.current?.ttsEngineId??st,U=y?.voiceId??u??_e.current?.voiceId??Mt(D);return{ttsEngineId:D,voiceId:U}},[a,u]),Xe=h.useCallback(y=>{Et(y),J(!0),ir.current?.(y)},[]),It=h.useCallback(y=>{et(y),p?.(y)},[p]),fe=h.useRef(Pn(It,Ge,{onLipsyncDebug:y=>Ut.current?.(y)})),de=h.useRef(null),lr=h.useRef(()=>{});h.useEffect(()=>(fe.current=Pn(It,Ge,{onLipsyncDebug:y=>Ut.current?.(y)}),s&&fe.current.setDeveloperToken(s),fe.current.setTtsEngineId(a),()=>{fe.current.stop();const y=de.current;y&&(y.disconnect(),de.current=null)}),[It,s,a,Ge]);const ur=h.useCallback(()=>(de.current||(de.current=Ti(It,{speakingRate:f,onUserTranscript:(y,D)=>sr.current?.(y,D),onBotOutput:y=>ar.current?.(y),onLipsyncDebug:y=>Ut.current?.(y)}),de.current.setTtsEngineId(a),lr.current(!0)),de.current),[It,f,a]),Re=h.useCallback(()=>{ee.current!=null&&(clearTimeout(ee.current),ee.current=null)},[]),Ce=h.useCallback(()=>{H.current!=null&&(clearTimeout(H.current),H.current=null),g.current=!1},[]),Wt=h.useCallback(()=>{if(k.current)return;const y=re.current;if(k.current=!0,Ce(),W.current=!1,v.current=!1,!oe.current||!X.current){y?.renderSilOnly();return}X.current.setActive(!1);const D=X.current.getVideo();if(y?.usesPixi){y.drawIdleVideo(D),y.beginIdleToSilCrossfade(Rr);return}(async()=>{const U=te.current;U&&await Tn(U,D,null,void 0,nt.current).catch(()=>{}),await new Promise(F=>setTimeout(F,Rr)),k.current&&await y?.renderSilOnly()})()},[Ce]),fr=h.useCallback(()=>{!oe.current||!X.current||(k.current=!1,re.current?.finishIdleToSilCrossfade(),Ce(),g.current=!0,H.current=setTimeout(()=>{if(H.current=null,Ye(fe.current,de.current).isSpeaking()){g.current=!1;return}if(W.current){g.current=!1;return}const y=X.current;if(!y){g.current=!1;return}y.restart(),y.setActive(!0);const D=y.getVideo();let U=!1;const F=()=>{U||(U=!0,D.removeEventListener("playing",K),g.current=!1)},K=()=>{F()};if(D.addEventListener("playing",K,{once:!0}),D.readyState>=HTMLMediaElement.HAVE_CURRENT_DATA&&!D.paused){F();return}setTimeout(F,300)},pe.current))},[Ce]),pt=h.useCallback(()=>{if(Re(),ge.current?.("sil"),W.current=!1,k.current=!1,!oe.current||!X.current){g.current=!1;return}fr()},[Re,fr]),pn=h.useCallback(async y=>{const D=R.current,U=re.current,F=te.current,K=()=>{y?.fallbackOnly||(W.current=!1)};if(!U||!F||!tt){K();return}if(Ye(fe.current,de.current).isSpeaking()){K();return}if(y?.fallbackOnly){if(!W.current||(De(Q.current),await U.renderSilOnly(),D!==R.current)||Ye(fe.current,de.current).isSpeaking())return;pt();return}if(Cr(Q.current)){De(Q.current),pt();return}if(le.current&&U.supportsBufferedPlayback&&!y?.fallbackOnly){if(De(Q.current),L.current?.reset(),await U.renderSilOnly(),D!==R.current||Ye(fe.current,de.current).isSpeaking())return;pt();return}const Ae=Ya(Ye(fe.current,de.current).getVisemeQueue(),$.current,b.current),Fe=Qa(Ae,ze.current);if(De(Q.current),!Fe){if(await U.renderSilOnly(),D!==R.current||Ye(fe.current,de.current).isSpeaking())return;pt();return}try{await U.renderViseme(F,"sil",{from:Ae,transitionDurationMs:Li})}catch(Me){if(Me?.name!=="AbortError")throw Me}if(D!==R.current){K();return}if(Ye(fe.current,de.current).isSpeaking()){K();return}pt()},[tt,pt]),gt=h.useCallback(()=>{if(v.current||W.current)return;v.current=!0,W.current=!0,Re();const y=R.current;pn().finally(()=>{v.current=!1}),ee.current=setTimeout(()=>{ee.current=null,y===R.current&&pn({fallbackOnly:!0})},Xa())},[Re,pn]),dr=h.useCallback(async()=>{const y=Math.floor(Date.now()/1e3);if(ft.current&&y<ft.current.expiresAt-60)return ft.current.key;const D=We.current??await Rt();We.current=D,fe.current.setDeveloperToken(D);const U=await ms(D,Ge);return ft.current={key:U.value,expiresAt:U.expiresAt},U.value},[Ge]);h.useEffect(()=>{s&&(We.current=s,fe.current.setDeveloperToken(s))},[s]),h.useEffect(()=>{fe.current.setTtsEngineId(a),de.current?.setTtsEngineId(a),_e.current&&(_e.current.ttsEngineId=a)},[a]),h.useEffect(()=>{const y=u??Mt(a);_e.current&&(_e.current.voiceId=y)},[u,a]);const $e=h.useMemo(()=>Qr(n,r),[n,r]),ji=h.useMemo(()=>i?JSON.stringify(i):$e?`face:${$e}`:`id:${t??""}`,[i,$e,t]),Ki=h.useMemo(()=>{const y=P?.trim();return y||(pr($e)??pr(ue)??os(i))},[P,$e,ue,i]);return h.useEffect(()=>{if(!t&&!i&&!$e){Xe("AiTwin requires `assets`, `avatarId`/`faceId`, or `id`");return}let y=!1;Ve.current=!1,hn(!1),w(!1),J(!1),be($e),Et(null),_e.current=null,X.current=null,oe.current=!1;const D=te.current;if(!D)return;let U=null;return(async()=>{try{let F,K,Ee,Ae;if(i)F=i,K=a,Ee=u??Mt(K);else if($e)ge.current?.("loadFace"),F=An($e),K=a,Ee=u??Mt(K);else{ge.current?.("getAiTwin");const Y=await xn(Gr(t),3e4,"getAiTwin");if(y)return;if(!Y.faceId?.trim())throw new Error("getAiTwin returned no faceId");be(Y.faceId.trim()),K=Y.ttsEngineId,Ee=u??Y.voiceId??Mt(K),Ae=Y.knowledgeContextId?.trim()||void 0,F=An(Y.faceId)}_e.current={ttsEngineId:K,voiceId:Ee,personaId:Ae},Xr(F),X.current=Sa();const Fe=!!(i&&!lt(i));U=wo(D,{preferLegacyRenderer:Fe,pixiMaxTextureSize:V,onStatus:Y=>{y||ge.current?.(Y)},onError:Y=>{y||Xe(Y)},shouldAcceptLiveFrame:()=>{if(ae.current)return!0;if(W.current)return!1;const Y=Ye(fe.current,de.current);return Y.isSpeaking()||Y.isWarmingUp()},onWebGlContextLost:()=>{y||qe.current||(qe.current=!0,queueMicrotask(()=>{y||Nt(Y=>Y+1)}))}}),re.current=U,L.current=no(U),qe.current=!1;const Me=Y=>{const ce=()=>{if(!Y||z.current<=0)return!1;const xe=re.current;return xe?le.current&&xe.supportsBufferedPlayback?!0:xe.usesPixi:!1};fe.current.setLipsyncWarmupHold(Y,ce),de.current?.setLipsyncWarmupHold(Y,ce)};lr.current=Me,Me(!0),ge.current?.("auth");const He=We.current??s??await xn(Rt(),3e4,"getAuthToken");if(y)return;We.current=He,fe.current.setDeveloperToken(He),fe.current.setTtsEngineId(K);const zt=Bt()?await dr():void 0;if(y)return;ge.current?.("loadAssets");const he=await xn(U.loadAssets(zt),18e4,"load face assets");if(!y&&he.width>0&&he.height>0&&(nt.current=he,Te(he)),y)return;ze.current=U.getVisemeAtlasPaths(),Ve.current=!0,hn(!0),Vt.current?.(),U.renderSilOnly().then(()=>{y||ge.current?.("sil")}),(async()=>{try{const Y=await Xs(zt);if(await X.current.load(Y),y)return;oe.current=!0,w(!0),De(Q.current),X.current.setActive(!0);const ce=X.current.getVideo();U.usesPixi?U.drawIdleVideo(ce):await Tn(D,ce,null,void 0,nt.current)}catch(Y){if(y)return;oe.current=!1,w(!1),console.warn("[AiTwin] Idle video unavailable:",Y)}finally{y||(J(!0),ge.current?.("idle"))}})()}catch(F){if(y)return;if(F instanceof Jt){Xe(F.message);return}Xe(F instanceof Error?F.message:"Failed to load AI twin")}})(),()=>{y=!0,X.current?.dispose(),U?.dispose(),re.current=null}},[ji,i,$e,t,a,u,s,V,dr,Xe,wn]),h.useEffect(()=>{const y={current:!1},D=()=>{const U=te.current,F=re.current,K=Ye(fe.current,de.current);if(!U||!F||!tt){S.current=requestAnimationFrame(D);return}if(document.hidden){X.current?.setActive(!1),S.current=requestAnimationFrame(D);return}const Ee=K.isSpeaking(),Ae=K.isWarmingUp(),Fe=Ee&&!q.current,Me=q.current&&!Ee;Fe&&(Re(),Ce(),W.current=!1,v.current=!1,De(Q.current),L.current?.reset(),wt.current.reset(),mt.current=void 0,ne.current=0,b.current="sil",$.current=0,Wt()),Me&&(j.current.reset(),X.current?.setActive(!1),L.current?.reset(),F.finishIdleToSilCrossfade(),Pe(),gt());const He=Me||W.current||g.current||k.current,zt=ie&&F.supportsBufferedPlayback;if(Ae){if(Wt(),oe.current&&X.current?.setActive(!1),F.usesPixi&&F.isIdleToSilCrossfading()){F.tickIdleToSilCrossfade(performance.now()),K.getVisemeQueue().length>0&&N.current===0&&(N.current=performance.now()),q.current=K.isSpeaking(),S.current=requestAnimationFrame(D);return}const he=K.getVisemeQueue();he.length>0&&N.current===0&&(N.current=performance.now()),j.current.advance(performance.now());const Y=j.current.getExpressionPath(),ce=j.current.getDrawKey(),xe={queue:he,elapsedMs:0,expressionPath:Y,expressionDrawKey:ce,availablePaths:ze.current};let Le=!1;zt&&L.current?(L.current.warmupTick(xe),Le=L.current.isWarmupReady(xe,z.current)):F.usesPixi&&Dr(U,he,0,Y,ce,Q.current,(yt,$t,gn,Ht)=>{F.drawLiveFrame(yt,$t,gn,je=>{Ht?.(je),K.isWarmingUp()&&je!==""&&!Cr({lastDrawnKey:je})&&(N.current=0,K.releaseWarmupHold())})},yt=>{ge.current?.(yt.label)},ze.current);const Je=N.current>0&&performance.now()-N.current>ns;ge.current?.(Le?"buffer ready":"buffering lipsync…"),(Le||Je)&&(N.current=0,K.releaseWarmupHold()),dt(K),q.current=K.isSpeaking(),S.current=requestAnimationFrame(D);return}if(Ee){Wt(),oe.current&&X.current?.setActive(!1),F.usesPixi&&F.isIdleToSilCrossfading()&&F.finishIdleToSilCrossfade();const he=K.getVisemeQueue(),Y=K.getPlaybackElapsedMs();Os(he,Y),$.current=Y;const ce=he.length>0?Ft(he,Y):"sil";ce!=="sil"&&(b.current=ce);const xe=xa(Y,K.getSentenceEmotions(),K.getWordQueue(),K.getStreamMood());j.current.setTargetEmotion(xe),j.current.setTargetEyebrow(_a(Y,K.getWordQueue(),at(xe))),j.current.advance(performance.now());const Le=j.current.getExpressionPath(),Je=j.current.getDrawKey(),yt=(je,yn,At,_n)=>{const mr={label:ve.current,elapsedMs:Y,mouthPath:yn.mouthPath,transitionMeta:mt.current};ht.current.set(At,mr),L.current?.markExternallyDisplayed(At,Le),F.drawLiveFrame(je,yn,At,jt=>{const qi=ht.current.get(jt)??mr;ht.current.delete(jt),wt.current.onDrawDisplayed(qi,he),L.current?.markExternallyDisplayed(jt,Le),_n?.(jt)})},$t=je=>{ve.current=je.label,mt.current=je.transitionMeta,ge.current?.(je.label)},gn=ie&&F.supportsBufferedPlayback;let Ht=!1;gn&&L.current&&(Ht=L.current.tick({canvas:U,queue:he,elapsedMs:Y,expressionPath:Le,expressionDrawKey:Je,playbackState:Q.current,availablePaths:ze.current,onStatus:$t,onDisplayed:(yn,At,_n)=>{wt.current.onDrawDisplayed({label:_n,elapsedMs:Y,mouthPath:At,transitionMeta:mt.current},he)}}).usedBuffer),Ht||Dr(U,he,Y,Le,Je,Q.current,yt,$t,ze.current),wt.current.onRafTickSpeaking(),or.current?.(wt.current.snapshot(he,Y))}else if(!He&&ae.current){X.current?.setActive(!1),j.current.advance(performance.now());const he=j.current.getExpressionPath(),Y=j.current.getDrawKey();kn(U,he,Y,Q.current,(ce,xe,Le,Je)=>F.drawLiveFrame(ce,xe,Le,Je),ce=>{if(Z.current){ge.current?.(Z.current);return}const xe=j.current.getTargetEmotion();ge.current?.(ce==="sil"||ce==="blink"?`${xe}${ce==="blink"?" · blink":""}`:ce)},null,Se.current)}else if(!He&&oe.current&&X.current){const he=X.current,Y=he.getVideo();if(Y.readyState>=HTMLMediaElement.HAVE_CURRENT_DATA){he.setActive(!0);const ce=()=>!K.isSpeaking()&&!W.current&&!g.current&&!ae.current;F.usesPixi?(F.drawIdleVideo(Y,ce),ce()&&ge.current?.("idle")):y.current||(y.current=!0,Tn(U,Y,null,void 0,nt.current,ce).then(()=>ge.current?.("idle")).finally(()=>{y.current=!1}))}else kn(U,null,"__sil__",Q.current,(ce,xe,Le,Je)=>F.drawLiveFrame(ce,xe,Le,Je),ce=>ge.current?.(ce))}else He||kn(U,null,"__sil__",Q.current,(he,Y,ce,xe)=>F.drawLiveFrame(he,Y,ce,xe),he=>ge.current?.(he));ke.enabled&&dt(K),q.current=Ee,S.current=requestAnimationFrame(D)};return S.current=requestAnimationFrame(D),()=>{cancelAnimationFrame(S.current),Re(),Ce(),fe.current.stop(),de.current?.stop()}},[tt,rr,gt,Re,Ce,Wt,dt,Pe,ke.enabled]),h.useImperativeHandle(se,()=>({speakText:async(y,D)=>{const U=y.trim();if(!U)return;const F=re.current;if(!F||!Ve.current&&!tt)throw new Error("AI twin is not ready");const{ttsEngineId:K,voiceId:Ee}=cr(D);Et(null),Pe(),R.current+=1,Re(),Ce(),W.current=!1,v.current=!1,b.current="sil",$.current=0,De(Q.current),ae.current=!1,Se.current=null,Z.current=null,j.current.reset(),q.current=!1,k.current=!1,F.finishIdleToSilCrossfade();try{await fe.current.speak(U,{voiceId:Ee,speakingRate:D?.speakingRate??f,ttsEngineId:K})}catch(Ae){throw k.current=!1,F.finishIdleToSilCrossfade(),gt(),Xe(Ae instanceof Error?Ae.message:"TTS failed"),Ae}},stop:()=>{R.current+=1,Re(),Ce(),W.current=!1,v.current=!1,k.current=!1,re.current?.finishIdleToSilCrossfade(),fe.current.stop(),de.current?.stop(),De(Q.current),L.current?.reset(),N.current=0,q.current=!1,Pe(),gt()},setTtsEngineId:y=>{fe.current.setTtsEngineId(y),de.current?.setTtsEngineId(y),_e.current&&(_e.current.ttsEngineId=y)},renderViseme:async(y,D)=>{const U=re.current,F=te.current;if(!U||!F||!Ve.current)throw new Error("AI twin is not ready");await U.renderViseme(F,y,{from:D?.from,transitionDurationMs:D?.transitionDurationMs,gapMs:D?.gapMs,onStatus:K=>ge.current?.(K)})},setEmotion:y=>{if(!Ve.current)throw new Error("AI twin is not ready");const D=re.current,U=te.current;if(!D||!U)throw new Error("AI twin is not ready");R.current+=1,Re(),Ce(),W.current=!1,v.current=!1,g.current=!1,k.current=!1,fe.current.stop(),de.current?.stop(),De(Q.current),L.current?.reset(),N.current=0,q.current=!1,D.finishIdleToSilCrossfade(),X.current?.setActive(!1);const F=Qe(y);ae.current=!0,Se.current=null,Z.current=null,j.current.snapToEmotion(F);const K=j.current.getExpressionPath(),Ee=j.current.getDrawKey(),Ae={mouthPath:null,expressionPath:K},Fe=Dt(Ae,Ee);Q.current.lastDrawnKey="",D.drawLiveFrame(U,Ae,Fe,He=>{He===Fe&&(Q.current.lastDrawnKey=Fe)});const Me=at(F);ge.current?.(K?`${F} · brow ${Me>0?"+":""}${Me}`:`${F} · brow 0 (sil base)`)},getEmotion:()=>ae.current?j.current.getTargetEmotion():null,clearEmotionPreview:()=>{ae.current=!1,Se.current=null,Z.current=null,j.current.reset(),De(Q.current),ge.current?.("idle")},setViseme:y=>{if(!Ve.current)throw new Error("AI twin is not ready");const D=re.current,U=te.current;if(!D||!U)throw new Error("AI twin is not ready");R.current+=1,Re(),Ce(),W.current=!1,v.current=!1,g.current=!1,k.current=!1,fe.current.stop(),de.current?.stop(),De(Q.current),L.current?.reset(),N.current=0,q.current=!1,D.finishIdleToSilCrossfade(),X.current?.setActive(!1);const F=on(y);ae.current=!0,Z.current=F,Se.current=F==="sil"?null:bt(F),j.current.snapToEmotion("neutral");const K=j.current.getExpressionPath(),Ee=j.current.getDrawKey(),Fe={mouthPath:Se.current,expressionPath:K},Me=Dt(Fe,Ee);Q.current.lastDrawnKey="",D.drawLiveFrame(U,Fe,Me,He=>{He===Me&&(Q.current.lastDrawnKey=Me)}),ge.current?.(F)},getViseme:()=>ae.current?Z.current:null,isReady:()=>Ve.current,getStatus:()=>Be,connect:async(y={})=>{Et(null);try{let D=y.authToken?.trim();D||(D=We.current??s??await Rt(),We.current=D);const U=y.voiceId?.trim()??u??_e.current?.voiceId,F=y.personaId?.trim()??_e.current?.personaId,K=ur();await K.unlockAudio(),await K.connect({...y,apiBase:y.apiBase?.trim()||Ge,authToken:D,voiceId:U,personaId:F,speakingRate:y.speakingRate??f})}catch(D){throw Xe(D instanceof Error?D.message:"Voice connect failed"),D}},disconnect:async()=>{const y=de.current;y&&(R.current+=1,Re(),Ce(),W.current=!1,v.current=!1,k.current=!1,re.current?.finishIdleToSilCrossfade(),De(Q.current),L.current?.reset(),N.current=0,q.current=!1,await y.disconnect(),gt())},isConnected:()=>de.current?.isConnected()??!1,getVoiceStream:()=>de.current?.getVoiceStream()??fe.current?.getVoiceStream()??null,setMuted:y=>{const D=fe.current,U=de.current;D?.setMuted?.(y),U?.setMuted?.(y)},isMuted:()=>{const y=de.current,D=fe.current;return y?.isMuted?.()??D?.isMuted?.()??!1},getPersonaId:()=>_e.current?.personaId?.trim()||null}),[tt,f,s,u,Re,Ce,gt,Xe,cr,ur,Be,Ge]),M.jsxs("div",{className:l,style:{...go,...c},children:[M.jsx("canvas",{ref:te,width:ye.width,height:ye.height,style:{...yo,...d},"aria-label":t?`AI twin ${t}`:"AI twin face"}),!B&&!Ot?M.jsx(Wa,{thumbnailUrl:Ki}):null,C&&Ot?M.jsx("div",{style:_o,children:Ot}):null,ke.enabled&&Oe?M.jsx(Oa,{text:Oe,style:ke.style},Oe):null]})});async function vo(e){try{const t=await e.json();if(typeof t.detail=="string"&&t.detail.trim())return t.detail;if(typeof t.error=="string"&&t.error.trim())return t.error}catch{}return`avatarReply failed (${e.status})`}async function Wi(e){const t=e.message.trim();if(!t)throw new Error("Message is required");const n=e.authToken.trim();if(!n)throw new Error("Auth token is required");const r=(e.apiBase?.trim()||ot).replace(/\/$/,""),i=await fetch(`${r}/avatarReply`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${n}`,Accept:"text/event-stream"},body:JSON.stringify({message:t,history:e.history??[],persona_id:e.personaId?.trim()||""})});if(!i.ok)throw new Error(await vo(i));if(!i.body)throw new Error("avatarReply response body is empty");const s=i.body.getReader(),o=new TextDecoder;let a="",u="",f="",l="";for(;;){const{done:c,value:d}=await s.read();if(c)break;a+=o.decode(d,{stream:!0});const p=a.split(`
48
+ `);a=p.pop()||"";for(const T of p){if(T.startsWith("event: ")){l=T.slice(7).trim();continue}if(!T.startsWith("data: "))continue;const m=T.slice(6).trim();if(!m)continue;let E;try{E=JSON.parse(m)}catch{continue}if(l==="spokenText")u=E.text||"",e.onSpokenText?.(u);else if(l==="displayText")f=E.text||"";else if(l==="error")throw new Error(E.error||"avatarReply stream error")}}if(!u.trim()||!f.trim())throw new Error("avatarReply stream missing displayText or spokenText");return{displayText:f.trim(),spokenText:u.trim()}}function So({muted:e}){return e?M.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none","aria-hidden":!0,children:[M.jsx("path",{d:"M11 5 6.5 9H3v6h3.5L11 19V5Z",fill:"currentColor"}),M.jsx("path",{d:"m16 9.5 5 5m0-5-5 5",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round"})]}):M.jsxs("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none","aria-hidden":!0,children:[M.jsx("path",{d:"M11 5 6.5 9H3v6h3.5L11 19V5Z",fill:"currentColor"}),M.jsx("path",{d:"M15.5 8.5a4.5 4.5 0 0 1 0 7M18.5 6a8 8 0 0 1 0 12",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round"})]})}function bo(){return M.jsx("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"currentColor","aria-hidden":!0,children:M.jsx("path",{d:"M8 5.5v13l11-6.5L8 5.5Z"})})}function To(){return M.jsx("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"currentColor","aria-hidden":!0,children:M.jsx("rect",{x:"6",y:"6",width:"12",height:"12",rx:"1.5"})})}function ko(){return M.jsx("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none","aria-hidden":!0,children:M.jsx("path",{d:"M5 6.5A2.5 2.5 0 0 1 7.5 4h9A2.5 2.5 0 0 1 19 6.5v7A2.5 2.5 0 0 1 16.5 16H10l-4 3.5V16H7.5A2.5 2.5 0 0 1 5 13.5v-7Z",stroke:"currentColor",strokeWidth:"2",strokeLinejoin:"round"})})}function zi({className:e}){return M.jsx("span",{className:e??"aitwin-widget__spinner","aria-hidden":!0,children:M.jsx("svg",{viewBox:"0 0 24 24",fill:"none",children:M.jsx("circle",{cx:"12",cy:"12",r:"9",stroke:"currentColor",strokeWidth:"2.5",strokeLinecap:"round",strokeDasharray:"40 20"})})})}function xo({muted:e,onToggle:t}){return M.jsx("button",{type:"button",className:"aitwin-widget__mute",onClick:t,"aria-label":e?"Unmute":"Mute","aria-pressed":e,children:M.jsx(So,{muted:e})})}function Eo(){return M.jsxs("div",{className:"aitwin-widget__connecting",role:"status","aria-live":"polite",children:[M.jsx(zi,{className:"aitwin-widget__spinner aitwin-widget__spinner--accent"}),M.jsx("span",{children:"Connecting..."})]})}function Io(e){const t=e.connecting||e.textSending||e.status==="loading"||e.status==="speaking",n=e.connecting?"Connecting...":e.connected?"End Talk":"Talk",r=["aitwin-widget__action",e.textMode&&!e.connecting?"":"aitwin-widget__action--primary",e.connecting?"aitwin-widget__action--connecting":""].filter(Boolean).join(" ");return M.jsxs("div",{className:"aitwin-widget__controls",children:[M.jsxs("div",{className:"aitwin-widget__actions",children:[M.jsxs("button",{type:"button",className:r,onClick:e.onTalk,disabled:!e.ready||e.connecting||e.textSending,"aria-busy":e.connecting,children:[e.connecting?M.jsx(zi,{className:"aitwin-widget__spinner aitwin-widget__spinner--on-accent"}):e.connected?M.jsx(To,{}):M.jsx(bo,{}),M.jsx("span",{children:n})]}),M.jsxs("button",{type:"button",className:e.textMode?"aitwin-widget__action aitwin-widget__action--primary":"aitwin-widget__action",onClick:e.onTextMode,disabled:!e.ready||e.connecting||e.textSending,"aria-pressed":e.textMode,children:[M.jsx(ko,{}),M.jsx("span",{children:"Text"})]})]}),e.textMode?M.jsxs("form",{className:"aitwin-widget__composer",onSubmit:i=>{i.preventDefault(),e.onSendText()},children:[M.jsx("input",{type:"text",className:"aitwin-widget__composer-input",value:e.textDraft,onChange:i=>e.onTextDraftChange(i.target.value),placeholder:e.textSending?"Getting reply...":"Type a message…",autoComplete:"off",disabled:!e.ready||t}),M.jsx("button",{type:"submit",className:"aitwin-widget__composer-send",disabled:!e.ready||t||!e.textDraft.trim()&&!e.textSending,"aria-busy":e.textSending,children:e.textSending?"…":"Send"})]}):null,e.error?M.jsx("p",{className:"aitwin-widget__controls-error",role:"alert",children:e.error}):null]})}const Ur=97,Ao=3500;function Mo(e,t){const n=Math.max(0,e),r=1-Math.exp(-n/Ao);return Math.min(Ur,Math.round(r*Ur))}function Po(e){const[t,n]=h.useState(null),[r,i]=h.useState(()=>Date.now());return h.useEffect(()=>{if(!e){n(null);return}const s=Date.now();n(s),i(s);let o=0;const a=()=>{i(Date.now()),o=window.requestAnimationFrame(a)};return o=window.requestAnimationFrame(a),()=>{window.cancelAnimationFrame(o)}},[e]),e?t==null?0:Mo(r-t):100}const Ro="M259.01,593.87v-101.49c.33-6.31,4.94-11.26,10.21-11.88,6.42-.75,13.18,4.99,13.13,12.92-.42,45.09-.83,90.17-1.25,135.26.03,1.56.56,15.43,11.95,23.2,6.18,4.21,12.57,4.6,15.42,4.58-.42-112.77-.83-225.54-1.25-338.31-.08-2.55-1.03-46.36,21.17-55.34,2.05-.83,4.42-1.41,7.17-1.56v453.42c.07,12.06,1.98,37.84,19.03,62.73,7.01,10.23,14.79,17.71,21.4,22.99V222.42c-.01-3.72.48-11.67,5.35-19.87,7-11.77,18.13-15.82,21.4-16.95,10.42-3.61,19.49-2.06,23.48-1.11v684.96c.59,4.03,1.78,9.72,4.45,16.12,1.93,4.63,8.84,20.57,26.47,31.26,13.48,8.18,26.56,9.23,32.86,9.31-1.3-256.11-2.59-512.22-3.89-768.33.76-16.43,14.57-28.94,29.73-28.34,13.53.53,25.39,11.39,27.23,25.84-1.1,264.68-2.2,529.35-3.3,794.03,4.33.92,22.38,4.25,38.94-6.53,10.26-6.68,15.24-15.72,17.09-19.17,5.55-10.36,6.42-19.98,6.53-25.01-.72-246.99-1.43-493.97-2.15-740.96,2.27-.06,34.75-.44,48.29,22.68,3.41,5.83,4.87,11.86,5.34,17.19v674.68c5.92-2.16,39.19-14.94,50.16-47.79,3.12-9.34,3.68-18.03,3.33-25.01.03-193.22.06-386.43.09-579.65,4.12,1.18,28.28,8.48,36.17,30.08,1.64,4.49,2.32,8.88,2.43,12.92.02,146.42.05,292.84.07,439.25,3.82-1.71,19.51-9.22,25.56-26.47,2.15-6.12,2.48-11.73,2.29-15.89.01-114.91.03-229.81.04-344.72,2.36-.1,7.51.02,12.74,3.13,9.1,5.4,10.87,15.35,11.12,16.88.35,11.49.69,22.97,1.04,34.46.46,37.05.93,74.1,1.39,111.15v152.69c3.39-.72,9.77-2.67,14.31-8.34,3.62-4.52,4.51-9.46,5.56-15.28.91-5.04.95-9.31.83-12.23.02-38.81.03-77.62.05-116.43";function Co({className:e="aitwin-widget__logo",strokeWidth:t=15,durationMs:n=2600,delayMs:r=0,loop:i=!1}){return M.jsx("svg",{viewBox:"0 0 1080 1080",className:e,role:"img","aria-label":"AITWIN logo",children:M.jsx("path",{className:i?"aitwin-widget__logo-draw aitwin-widget__logo-draw--loop":"aitwin-widget__logo-draw",d:Ro,fill:"none",stroke:"currentColor",strokeWidth:t,strokeMiterlimit:10,pathLength:1,style:{animationDuration:`${n}ms`,animationDelay:`${r}ms`}})})}function Do({progress:e}){const t=Math.max(0,Math.min(100,Math.round(e)));return M.jsx("div",{className:"aitwin-widget__face-loading","aria-live":"polite","aria-label":`Loading ${t} percent`,children:M.jsxs("div",{className:"aitwin-widget__face-loading-content",children:[M.jsx(Co,{className:"aitwin-widget__logo",loop:!0,durationMs:2600}),M.jsxs("div",{className:"aitwin-widget__face-loading-bar-wrap",children:[M.jsx("div",{role:"progressbar","aria-valuenow":t,"aria-valuemin":0,"aria-valuemax":100,className:"aitwin-widget__face-loading-track",children:M.jsx("div",{className:"aitwin-widget__face-loading-fill",style:{width:`${t}%`}})}),M.jsxs("p",{className:"aitwin-widget__face-loading-pct",children:[t,"%"]})]})]})})}function Wr(e){const t=e.id?.trim()||void 0,n=e.faceId?.trim()||e.avatarId?.trim()||void 0;return{id:n?void 0:t,faceId:n,authToken:e.authToken?.trim()||void 0,apiBase:e.apiBase?.trim()||void 0,voiceId:e.voiceId?.trim()||void 0,speakingRate:e.speakingRate}}function Bo(e){return[e.id??"",e.faceId??"",e.authToken?.slice(0,16)??"",e.voiceId??"",e.apiBase??"",String(e.speakingRate??"")].join("|")}const zr={display:"flex",alignItems:"center",justifyContent:"center",width:"100%",height:"100%",lineHeight:0},Fo={display:"block",height:"100%",width:"100%",objectFit:"cover",objectPosition:"top"},Lo=h.forwardRef(function({options:t},n){const r=h.useRef(null),i=h.useRef(t);i.current={...i.current,onReady:t.onReady,onStatusChange:t.onStatusChange,onError:t.onError,onUserTranscript:t.onUserTranscript,onBotOutput:t.onBotOutput};const[s,o]=h.useState(!!t.showControls),[a,u]=h.useState(()=>Wr(t)),[f,l]=h.useState(!1),[c,d]=h.useState(!1),[p,T]=h.useState(!1),[m,E]=h.useState(!1),[C,P]=h.useState("idle"),[_,x]=h.useState(null),[O,A]=h.useState(!1),[ie,me]=h.useState(!1),[I,V]=h.useState(""),[G,se]=h.useState(!1),[te,re]=h.useState([]),[L,le]=h.useState(t.personaId?.trim()||void 0),z=h.useCallback(b=>{i.current={...i.current,...b},b.showControls!==void 0&&o(!!b.showControls),b.personaId!==void 0&&le(b.personaId.trim()||void 0),u($=>Wr({id:b.id??$.id,faceId:b.faceId??b.avatarId??$.faceId,authToken:b.authToken??$.authToken,apiBase:b.apiBase??$.apiBase,voiceId:b.voiceId??$.voiceId,speakingRate:b.speakingRate??$.speakingRate}))},[]);h.useImperativeHandle(n,()=>({getTwin:()=>r.current,applyOptions:z}),[z]),h.useEffect(()=>{z(t)},[z,t.id,t.faceId,t.avatarId,t.authToken,t.apiBase,t.voiceId,t.speakingRate,t.showControls,t.personaId]);const pe=h.useCallback(()=>{l(!0),x(null)},[]),N=h.useCallback(b=>{b==="idle"&&d(!0)},[]),Q=h.useCallback(b=>{P(b),i.current.onStatusChange?.(b)},[]),j=h.useCallback(b=>{x(b),l(!1),d(!1),E(!1),i.current.onError?.(b)},[]),ae=h.useCallback((b,$)=>{i.current.onUserTranscript?.(b,$)},[]),Se=h.useCallback(b=>{i.current.onBotOutput?.(b)},[]);h.useEffect(()=>{if(!s)return;const b=window.setInterval(()=>{T(!!r.current?.isConnected())},400);return()=>window.clearInterval(b)},[s,a]);const Z=Bo(a),S=!!(a.id||a.faceId),R=f&&c,ne=S&&!R&&!_,ee=Po(ne),H=h.useRef(Z);h.useEffect(()=>{R&&i.current.onReady?.()},[R]),h.useEffect(()=>{R&&r.current?.setMuted(O)},[R,O,a]),h.useEffect(()=>{re([])},[a.id,a.faceId]),h.useEffect(()=>{H.current!==Z&&(H.current=Z,l(!1),d(!1),x(null),E(!1),T(!1),P("idle"))},[Z]);const W=()=>{const b=r.current;if(!b?.isReady())return;if(x(null),me(!1),b.isConnected()){E(!1),b.disconnect().finally(()=>{T(!1)});return}E(!0);const $={authToken:a.authToken,voiceId:a.voiceId,speakingRate:a.speakingRate,apiBase:a.apiBase};b.connect($).then(()=>{T(!!b.isConnected())}).catch(q=>{const X=q instanceof Error?q.message:"Failed to connect voice.";x(X),i.current.onError?.(X)}).finally(()=>{E(!1)})},v=()=>{me(b=>!b),x(null)},g=()=>{const b=I.trim(),$=r.current;!b||!$?.isReady()||G||(x(null),V(""),se(!0),i.current.onUserTranscript?.(b,!0),(async()=>{try{const q=a.authToken?.trim()||await Rt(),X=L||$.getPersonaId()?.trim()||void 0,oe=await Wi({message:b,authToken:q,apiBase:a.apiBase||ot,personaId:X,history:te});re(Be=>[...Be,{role:"user",content:b},{role:"assistant",content:oe.displayText}]),i.current.onBotOutput?.(oe.displayText),await $.speakText(oe.spokenText,{voiceId:a.voiceId,speakingRate:a.speakingRate})}catch(q){const X=q instanceof Error?q.message:"Failed to get reply.";x(X),i.current.onError?.(X)}finally{se(!1)}})())},k=()=>{const b=!O;A(b),r.current?.setMuted(b)};return M.jsxs("div",{className:"aitwin-widget__layout",children:[M.jsxs("div",{className:"aitwin-widget__stage",children:[S?M.jsx("div",{style:zr,children:M.jsx(Ui,{ref:r,id:a.id,faceId:a.faceId,authToken:a.authToken,apiBase:a.apiBase,voiceId:a.voiceId,speakingRate:a.speakingRate,style:zr,canvasStyle:Fo,onReady:pe,onDisplayStatus:N,onStatusChange:Q,onError:j,onUserTranscript:ae,onBotOutput:Se,loadingThumbnailUrl:t.loadingThumbnailUrl},Z)}):M.jsx("p",{className:"aitwin-widget__hint",style:{padding:16},children:"Pass id or faceId to load a twin."}),ne?M.jsx(Do,{progress:ee}):null,s?M.jsx(xo,{muted:O,onToggle:k}):null,s&&m?M.jsx(Eo,{}):null]}),s?M.jsx(Io,{ready:R,connected:p,connecting:m,status:C,textMode:ie,textDraft:I,textSending:G,error:_,onTalk:W,onTextMode:v,onTextDraftChange:V,onSendText:g}):null]})}),Oo=".aitwin-widget{--aitwin-border: rgba(255, 255, 255, .12);--aitwin-text: #f4f4f5;--aitwin-muted: #a1a1aa;--aitwin-accent: #f97316;--aitwin-accent-hover: #fb923c;--aitwin-font: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif;--aitwin-size: 1;--aitwin-stage-width: calc(200px * var(--aitwin-size));--aitwin-stage-height: calc(267px * var(--aitwin-size));--aitwin-action-height: calc(40px * var(--aitwin-size));--aitwin-action-font: calc(13px * var(--aitwin-size));--aitwin-action-radius: calc(10px * var(--aitwin-size));--aitwin-action-gap: calc(6px * var(--aitwin-size));--aitwin-mute-size: calc(28px * var(--aitwin-size));--aitwin-layout-gap: calc(8px * var(--aitwin-size));box-sizing:border-box;color:var(--aitwin-text);font-family:var(--aitwin-font);font-size:calc(12px * var(--aitwin-size));line-height:1.45;width:fit-content;max-width:100%}.aitwin-widget *,.aitwin-widget *:before,.aitwin-widget *:after{box-sizing:border-box}.aitwin-widget__layout{display:flex;flex-direction:column;gap:var(--aitwin-layout-gap);width:fit-content;max-width:100%}.aitwin-widget__stage{align-items:center;background:#0a0a0b;border:1px solid var(--aitwin-border);border-radius:calc(10px * var(--aitwin-size));display:flex;flex-shrink:0;height:var(--aitwin-stage-height);justify-content:center;line-height:0;overflow:hidden;position:relative;width:var(--aitwin-stage-width)}.aitwin-widget__stage .aitwin-root,.aitwin-widget__stage canvas{display:block;height:100%;object-fit:cover;object-position:top;width:100%}.aitwin-widget__hint{color:var(--aitwin-muted);font-size:calc(11px * var(--aitwin-size));margin:0}.aitwin-widget__mute{align-items:center;background:#28282cb8;border:none;border-radius:999px;color:#fff;cursor:pointer;display:inline-flex;height:var(--aitwin-mute-size);justify-content:center;padding:0;position:absolute;right:calc(8px * var(--aitwin-size));top:calc(8px * var(--aitwin-size));width:var(--aitwin-mute-size);z-index:2}.aitwin-widget__mute:hover{background:#37373cd9}.aitwin-widget__mute svg{height:calc(15px * var(--aitwin-size));width:calc(15px * var(--aitwin-size))}.aitwin-widget__controls{display:flex;flex-direction:column;gap:var(--aitwin-action-gap);width:var(--aitwin-stage-width)}.aitwin-widget__actions{display:grid;gap:var(--aitwin-action-gap);grid-template-columns:1fr 1fr;width:100%}.aitwin-widget__action{align-items:center;background:transparent;border:1.5px solid var(--aitwin-accent);border-radius:999px;color:var(--aitwin-accent);cursor:pointer;display:inline-flex;font-family:inherit;font-size:var(--aitwin-action-font);font-weight:600;gap:calc(6px * var(--aitwin-size));height:var(--aitwin-action-height);justify-content:center;padding:0 calc(10px * var(--aitwin-size))}.aitwin-widget__action svg{flex-shrink:0;height:calc(12px * var(--aitwin-size));width:calc(12px * var(--aitwin-size))}.aitwin-widget__action:hover:not(:disabled){background:#f973161a}.aitwin-widget__action:disabled{cursor:not-allowed;opacity:.45}.aitwin-widget__action--primary{background:var(--aitwin-accent);border-color:transparent;color:#fff}.aitwin-widget__action--primary:hover:not(:disabled){background:var(--aitwin-accent-hover)}.aitwin-widget__action--connecting:disabled{cursor:progress;opacity:1}.aitwin-widget__spinner{display:inline-flex;flex-shrink:0;height:calc(14px * var(--aitwin-size));width:calc(14px * var(--aitwin-size))}.aitwin-widget__spinner svg{animation:aitwin-widget-spin .8s linear infinite;display:block;height:100%;width:100%}.aitwin-widget__spinner--accent{color:var(--aitwin-accent);height:calc(16px * var(--aitwin-size));width:calc(16px * var(--aitwin-size))}.aitwin-widget__spinner--on-accent{color:#fff}@keyframes aitwin-widget-spin{to{transform:rotate(360deg)}}.aitwin-widget__connecting{align-items:center;backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);background:#ffffffe0;border-radius:999px;bottom:calc(14px * var(--aitwin-size));box-shadow:0 4px 16px #0000001f;color:#3f3f46;display:inline-flex;font-size:calc(12px * var(--aitwin-size));font-weight:600;gap:calc(8px * var(--aitwin-size));left:50%;line-height:1;padding:calc(8px * var(--aitwin-size)) calc(14px * var(--aitwin-size));pointer-events:none;position:absolute;transform:translate(-50%);z-index:3}.aitwin-widget__face-loading{background:transparent;inset:0;overflow:hidden;pointer-events:none;position:absolute;z-index:4}.aitwin-widget__face-loading-content{align-items:center;display:flex;flex-direction:column;gap:calc(12px * var(--aitwin-size));inset:0;justify-content:center;padding:calc(24px * var(--aitwin-size));position:absolute;z-index:1}.aitwin-widget__logo{color:#fff;display:block;flex-shrink:0;height:calc(64px * var(--aitwin-size));margin-bottom:calc(4px * var(--aitwin-size));width:calc(64px * var(--aitwin-size))}.aitwin-widget__logo-draw{stroke-dasharray:1;stroke-dashoffset:1;animation:aitwin-widget-logo-draw 2.6s ease-in-out forwards}.aitwin-widget__logo-draw--loop{animation:aitwin-widget-logo-draw-loop 2.6s ease-in-out infinite}@keyframes aitwin-widget-logo-draw{to{stroke-dashoffset:0}}@keyframes aitwin-widget-logo-draw-loop{0%{stroke-dashoffset:1}45%{stroke-dashoffset:0}55%{stroke-dashoffset:0}to{stroke-dashoffset:-1}}@media(prefers-reduced-motion:reduce){.aitwin-widget__logo-draw,.aitwin-widget__logo-draw--loop{animation:none;stroke-dashoffset:0}}.aitwin-widget__face-loading-bar-wrap{max-width:calc(220px * var(--aitwin-size));width:100%}.aitwin-widget__face-loading-track{background:#fff3;border-radius:999px;height:calc(4px * var(--aitwin-size));overflow:hidden;width:100%}.aitwin-widget__face-loading-fill{background:var(--aitwin-accent);border-radius:999px;height:100%;transition:width .3s ease-out}.aitwin-widget__face-loading-pct{color:#ffffffbf;font-size:calc(12px * var(--aitwin-size));margin:calc(8px * var(--aitwin-size)) 0 0;text-align:center}.aitwin-widget__composer{display:grid;gap:var(--aitwin-action-gap);grid-template-columns:1fr auto;width:100%}.aitwin-widget__composer-input{background:#ffffff0a;border:1px solid var(--aitwin-border);border-radius:var(--aitwin-action-radius);color:var(--aitwin-text);font-family:inherit;font-size:calc(12px * var(--aitwin-size));min-width:0;outline:none;padding:calc(8px * var(--aitwin-size)) calc(10px * var(--aitwin-size))}.aitwin-widget__composer-input:focus{border-color:#f973168c}.aitwin-widget__composer-send{background:var(--aitwin-accent);border:none;border-radius:var(--aitwin-action-radius);color:#fff;cursor:pointer;font-family:inherit;font-size:calc(12px * var(--aitwin-size));font-weight:600;padding:0 calc(12px * var(--aitwin-size))}.aitwin-widget__composer-send:disabled{cursor:not-allowed;opacity:.45}.aitwin-widget__controls-error{color:#fecaca;font-size:calc(11px * var(--aitwin-size));margin:0}.aitwin-widget--float{bottom:20px;filter:drop-shadow(0 12px 32px rgba(0,0,0,.45));height:fit-content;margin:0;max-width:calc(100vw - 40px);position:fixed;right:20px;width:fit-content;z-index:2147483000}",$r="data-aitwin-widget-style";function $i(){if(typeof document>"u")return;const e=Oo.trim();if(!e){console.warn("[AiTwinWidget] styles.css?inline resolved empty — chrome will be unstyled");return}const t=document.querySelector(`style[${$r}]`);if(t){if((t.textContent??"").trim().length>0)return;t.textContent=e;return}const n=document.createElement("style");n.setAttribute($r,"1"),n.textContent=e,(document.head??document.documentElement).appendChild(n)}typeof document<"u"&&$i();const No=h.forwardRef(function(t,n){$i();const r=h.useRef(null);h.useImperativeHandle(n,()=>({speakText:async(s,o)=>{const a=r.current?.getTwin();if(!a)throw new Error("AiTwinWidget: twin is not mounted");return a.speakText(s,o)},connect:async s=>{const o=r.current?.getTwin();if(!o)throw new Error("AiTwinWidget: twin is not mounted");return o.connect(s)},disconnect:async()=>{const s=r.current?.getTwin();if(s)return s.disconnect()},stop:()=>{r.current?.getTwin()?.stop()},isReady:()=>!!r.current?.getTwin()?.isReady(),isConnected:()=>!!r.current?.getTwin()?.isConnected(),getTwin:()=>r.current?.getTwin()??null}),[]);const i=!!t.float;return M.jsx("div",{className:i?"aitwin-widget aitwin-widget--float":"aitwin-widget",children:M.jsx(Lo,{ref:r,options:t})})}),Vo=new Set([".png",".jpg",".jpeg",".webp"]);function Hi(e=".png"){const t=e.toLowerCase();return Vo.has(t)?`source${t}`:"source.png"}function Uo(e,t=Ln,n=".png"){const r=e.trim();if(!r)throw new Error("faceId is required");return`${t.replace(/\/$/,"")}/${r}/${Hi(n)}`}exports.AI_TWIN_THUMBNAIL_FILENAME=Vn;exports.AiTwin=Ui;exports.AiTwinNotFoundError=Jt;exports.AiTwinWidget=No;exports.CONSONANT_SKIP_GROUP=oi;exports.DEFAULT_TTS_ENGINE_ID=st;exports.EMOTION_TO_EYEBROW=Ri;exports.EXPRESSION_ATLAS_EMOTIONS=ua;exports.MIC_SAMPLE_RATE=Kn;exports.OCULUS_VISEME_IDS=ri;exports.PLAYBACK_SAMPLE_RATE=qn;exports.SPEAKING_RATE_MAX=dn;exports.SPEAKING_RATE_MIN=fn;exports.TTS_ENGINE_CARTESIA=ct;exports.TTS_ENGINE_GOOGLE=Nn;exports.TTS_ENGINE_INWORLD=an;exports.VISEME_IDS=Js;exports.VISEME_SKIP_GAP_MS=Mn;exports.VISEME_TEST_CARTESIA_VOICE_ID=jn;exports.VISEME_TEST_SPEAKING_RATE=Lt;exports.VISEME_TEST_VOICE_ID=Hn;exports.VISEME_VTIME_GRID_MS=Un;exports.VOWEL_SKIP_GROUP=ai;exports.aiTwinSourceFilename=Hi;exports.buildPlaybackTransitions=hi;exports.buildPlaybackVisemeSeries=ln;exports.buildRawVisemeTransitions=mi;exports.buildVoiceWebSocketUrl=bi;exports.compactSkippableVisemes=zn;exports.createAvatarTtsLipsyncController=Pn;exports.createRealtimeVoiceLipsyncController=Ti;exports.emotionToEyebrow=at;exports.faceAssetUrls=An;exports.fetchAiTwin=Gr;exports.fetchAvatarReply=Wi;exports.fetchDevAuthToken=Rt;exports.getAiTwinSourceUrl=Uo;exports.getAiTwinThumbnailUrl=Yr;exports.listSkippedVisemeEntries=un;exports.listSkippedVisemes=Ms;exports.normalizeOculusViseme=on;exports.normalizeStreamEmotion=Qe;exports.resolveDirectFaceId=Qr;exports.resolveVisemeAtTime=Ft;exports.resolveVisemeFromPlaybackSeries=ui;exports.resolveWordAtTime=Ns;exports.setActiveTwinAssets=Xr;exports.snapVisemeQueueToGrid=Wn;exports.snapVisemeVtimeToGrid=ci;