@streamoji/aitwin 0.5.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/assets/{visemeDiffPreview.worker-gbXevyWw.js → visemeDiffPreview.worker-DABw0e8B.js}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(){"use strict";function it(t,e,n){return{width:t.crop?.source_width??e,height:t.crop?.source_height??n}}function ct(t,e){const n=t.crop;return{x:e?.source_x??n?.x??0,y:e?.source_y??n?.y??0,width:e?.source_w??n?.width??t.frame_width??0,height:e?.source_h??n?.height??t.frame_height??0}}function lt(t){return t?(t.w??0)>0&&(t.h??0)>0:!1}function M(t){return t.includes("/custom-faces/")}function K(t){const e=t.binBase.trim().replace(/\/$/,""),n=t.twinBase.trim().replace(/\/$/,"");if(!(t.encrypted||M(e)||M(n)))return{twinBase:n,binBase:e,encrypted:!1};const s=M(e)?e:M(n)?n:e;return{twinBase:s,binBase:s,encrypted:!0}}function m(t){return K(t).encrypted}function _t(t){const e=t.trim();if(e.length%2!==0)throw new Error("Invalid hex key");const n=new Uint8Array(e.length/2);for(let r=0;r<e.length;r+=2)n[r/2]=Number.parseInt(e.slice(r,r+2),16);return n}function B(t){return Uint8Array.from(t)}function ut(t,e){const n=new Uint8Array(t.length+e.length);return n.set(t,0),n.set(e,t.length),n}async function ft(t,e){if(!e)throw new Error("Asset key is required for encrypted assets");if(t.byteLength<28)throw new Error("Encrypted payload too small");const n=new Uint8Array(t),r=B(n.subarray(0,12)),s=B(n.subarray(12,28)),o=B(n.subarray(28)),a=B(ut(o,s)),c=await crypto.subtle.importKey("raw",_t(e),{name:"AES-GCM"},!1,["decrypt"]);return crypto.subtle.decrypt({name:"AES-GCM",iv:r,tagLength:128},c,a)}async function $(t,e){const n=await fetch(t);if(!n.ok)throw new Error(`Failed to load encrypted asset: ${t}`);const r=await n.arrayBuffer();return ft(r,e)}async function dt(t,e){if(!e)throw new Error("Missing asset key for encrypted JSON");const n=await $(t,e),r=new TextDecoder().decode(n);return JSON.parse(r)}async function wt(t){const e=new Blob([t],{type:"image/webp"});return createImageBitmap(e)}async function pt(t){const e=new Blob([t],{type:"image/png"});return createImageBitmap(e)}function C(t,e){return`${t}/${e}_minus_sil.png`}const Y=5;function J(t){const e=t?.composite_threshold;if(typeof e=="number"&&e>0)return e;const n=t?.crop?.content_threshold;return typeof n=="number"&&n>0?n:Y}const v=["t01_0.25","t02_0.50","t03_0.75"],ht=v.length,G=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 Q(t,e){return`${t}__${e}`}function X(t,e){return`pairs/${t}/${e}_minus_sil.png`}function q(t){return`${t}_minus_sil.png`}function yt(t,e){if(e.has(t))return t;const n=/^pairs\/([^/]+)\//.exec(t);if(!n)return null;const r=n[1].split("__")[1];if(!r||r==="sil")return null;const s=q(r);return e.has(s)?s:null}function mt(t,e){return t.filter(n=>e.has(n))}function gt(t,e){if(t===e)return[];const n=[],r=Q(t,e);if(G.has(r)){for(const o of v)n.push(X(r,o));return n}const s=Q(e,t);if(G.has(s)){for(let o=ht-1;o>=0;o--)n.push(X(s,v[o]));return n}return[]}function Et(t){return t<16?[1]:t<24?[1]:t<35?[0,1,2]:[0,1,2]}function It(t,e){return Et(e).map(r=>t[r]).filter(r=>r!=null)}function bt(t,e,n){if(!n)return`${t}/${e}`;const r=e.split("/").pop()??e,s=r.includes(".")?r.slice(0,r.lastIndexOf(".")):r;return`${t}/${s}.bin`}function Dt(t,e,n,r,s=Y){const o=new OffscreenCanvas(n,r),a=o.getContext("2d",{willReadFrequently:!0});a.drawImage(t,0,0,n,r);const c=a.getImageData(0,0,n,r),i=a.createImageData(n,r);i.data.set(c.data);const f=new OffscreenCanvas(n,r).getContext("2d",{willReadFrequently:!0});for(const d of e){f.clearRect(0,0,n,r),f.drawImage(d,0,0,n,r);const _=f.getImageData(0,0,n,r);for(let u=0;u<i.data.length;u+=4){const y=_.data[u],F=_.data[u+1],x=_.data[u+2];Math.max(y,F,x)>s&&(i.data[u]=y,i.data[u+1]=F,i.data[u+2]=x,i.data[u+3]=255)}}return a.putImageData(i,0,0),o}[.32,.24,.16,.08,0].map(t=>`eyes_${t.toFixed(2)}`);const P=2,St=-30,j=20,Ft={fear:-20,anger:-20,sad:-10,neutral:0,love:0,happy:0,disgust:10};function Z(t){return`brow_${t}`}function Mt(t){return Ft[t]}function V(t){return Math.max(St,Math.min(j,t))}function tt(t){const e=V(t);if(e%P===0)return[e];const n=Math.floor(e/P)*P,r=Math.min(j,n+P),s=V(n);return e-s<=r-e?s===r?[s]:[s,r]:s===r?[r]:[r,s]}const Bt={[-20]:"anger",[-10]:"sad",0:"neutral",10:"disgust"};function Pt(t,e){if(!t)return null;if(e(t))return t;const n=t.match(/^brow_(-?\d+)\/(eyes_[^/]+)_minus_sil\.png$/);if(n){const s=Number(n[1]),o=n[2];for(const c of tt(s)){if(c===s)continue;const i=C(Z(c),o);if(e(i))return i}const a=Bt[s];if(a){const c=C(a,o);if(e(c))return c}return null}const r=t.match(/^(fear|anger|sad|neutral|love|happy|disgust)\/(eyes_[^/]+)_minus_sil\.png$/);if(r){const s=r[1],o=r[2],a=Mt(s);for(const c of[a,...tt(a)]){const i=C(Z(c),o);if(e(i))return i}}return null}const et=-1,kt=1e5;function Ot(t){return t>=kt}function Rt(t){return t<0}let g=0,nt=Promise.resolve(),E=!1;function H(t){const e=nt.then(t);return nt=e.then(()=>{},()=>{}),e}function I(t,e){const n=e>0?-e:et,r={type:"renderDone",requestId:t,generation:n};self.postMessage(r)}async function At(t){const e=typeof t.liveSeq=="number"?t.liveSeq:0,n=Ot(e);if(E&&!n){I(t.requestId,e);return}if(e>0&&!n&&(g=e),!w)throw new Error("Worker not initialized");if(e>0&&!n&&e!==g){I(t.requestId,e);return}if(await S(h??void 0),e>0&&!n&&e!==g){I(t.requestId,e);return}if(await at(w,t.diffPath,t.expressionDiffPath??null,t.threshold),e>0&&!n&&e!==g){I(t.requestId,e);return}const r=e>0?-e:et;await L(r),I(t.requestId,e)}let w=null,b=null,h=null,U=null,k="sil";const O=new Map;function D(){if(!U)throw new Error("Worker assets not configured");return U}function rt(){const t=D();return m(t)?`${t.binBase}/sil.bin`:`${t.twinBase}/sil.png`}function Tt(){const t=D();return m(t)?`${t.binBase}/atlas.bin`:`${t.twinBase}/atlas.json`}function xt(){const t=D();return m(t)?`${t.binBase}/expression_atlas.bin`:`${t.twinBase}/expression_atlas.json`}function $t(){const t=D();return m(t)?t.binBase:t.twinBase}function R(){return m(D())}async function N(t){const e=await fetch(t);if(!e.ok)throw new Error(`Failed to load image: ${t}`);const n=await e.blob();return createImageBitmap(n)}async function Ct(t){return R()?pt(await $(rt(),t??"")):N(rt())}async function st(t,e,n){const r=R(),s=r?await dt(t,n):await fetch(t).then(l=>{if(!l.ok)throw new Error(`Failed to load ${t}`);return l.json()}),o=s.sheets?.[0];if(!o?.path)throw new Error(`${t} has no sheets[0].path`);const a=r?await wt(await $(bt(e,o.path,r),n??"")):await N(`${e}/${o.path}`),c=new Map;for(const l of s.cells??[])l.path&&c.set(l.path,l);const i=new Map;for(const l of s.sheets??[])i.set(l.index,l);return{atlas:a,atlasMeta:s,cellByPath:c,sheetByIndex:i,diffBase:e}}async function S(t){if(R()&&!t)throw new Error("Encrypted assets enabled but no key provided");if(b&&(!R()||h===(t??null)))return b;h=t??null,O.clear();const e=$t();return b=(async()=>{const n=await Ct(t),r=await st(Tt(),e,t);let s=null;try{s=await st(xt(),e,t)}catch{s=null}return{sil:n,viseme:r,expression:s}})(),b}function A(t){return it(t.viseme.atlasMeta,t.sil.width,t.sil.height)}function vt(t,e){if(!t.sheetByIndex.get(e.sheet??0))throw new Error(`Unknown sheet index: ${e.sheet}`);const r=new OffscreenCanvas(e.w,e.h);return r.getContext("2d",{willReadFrequently:!0}).drawImage(t.atlas,e.x,e.y,e.w,e.h,0,0,e.w,e.h),r}async function qt(t){return createImageBitmap(t)}async function ot(t,e,n){const r=`${e.diffBase}::${n}`,s=O.get(r);if(s)return s;const o=(async()=>{const a=e.cellByPath.get(n);if(!a)throw new Error(`No atlas cell for path: ${n}`);const c=ct(e.atlasMeta,a),i=A(t);if(lt(a)){const d=vt(e,a),_=new OffscreenCanvas(i.width,i.height),u=_.getContext("2d");return u.fillStyle="#000",u.fillRect(0,0,i.width,i.height),u.drawImage(d,c.x,c.y),qt(_)}const l=`${e.diffBase}/${n}`,f=await N(l);if(f.width===i.width&&f.height===i.height)return f;throw f.close(),new Error(`Diff PNG wrong size for ${n}`)})();return O.set(r,o),o}function T(t,e){const n={type:"status",label:t,generation:e};self.postMessage(n)}function Ht(t,e){const n={type:"error",requestId:t,message:e};self.postMessage(n)}async function L(t){if(!w)return;const e=Rt(t);if(!e&&t!==p)return;const n=await createImageBitmap(w);if(!e&&t!==p){n.close();return}const r={type:"frame",bitmap:n,generation:t};self.postMessage(r,{transfer:[n]})}function Ut(t,e,n){return new Promise((r,s)=>{setTimeout(()=>{e!==n?s(new DOMException("Aborted","AbortError")):r()},t)})}async function at(t,e,n,r){const s=await S(h??void 0),o=r??J(s.viseme.atlasMeta),{width:a,height:c}=A(s);(t.width!==a||t.height!==c)&&(t.width=a,t.height=c);const i=[];if(e){const d=new Set(s.viseme.cellByPath.keys()),_=yt(e,d)??(d.has(e)?e:null);_&&i.push(await ot(s,s.viseme,_))}if(n&&s.expression){const d=Pt(n,_=>s.expression.cellByPath.has(_));d&&i.push(await ot(s,s.expression,d))}const l=t.getContext("2d");if(l.clearRect(0,0,a,c),i.length===0){l.drawImage(s.sil,0,0,a,c);return}const f=Dt(s.sil,i,a,c,o);l.drawImage(f,0,0)}async function W(t,e,n,r,s){await at(t,e,n,s),await L(r)}async function z(t,e,n){k="sil";const r=await S(h??void 0);if(e!==n)throw new DOMException("Aborted","AbortError");const{width:s,height:o}=A(r);t.width=s,t.height=o;const a=t.getContext("2d");a.clearRect(0,0,s,o),a.drawImage(r.sil,0,0,s,o),await L(e)}async function Nt(t,e,n,r,s={}){const o=s.from??k,a=s.transitionDurationMs??400,c=s.gapMs??a,i=await S(h??void 0),l=s.threshold??J(i.viseme.atlasMeta);if(o===e){if(T(e,n),e==="sil"?await z(t,n,r):await W(t,q(e),null,n,l),n!==r)throw new DOMException("Aborted","AbortError");k=e;return}const f=gt(o,e),d=new Set(i.viseme.cellByPath.keys());let _=It(f,c);_=mt(_,d);const u=_.length>0?a/_.length:0;_.length===0&&T(`${o} → ${e} (no pair; final only)`,n);for(let y=0;y<_.length;y++){if(n!==r)throw new DOMException("Aborted","AbortError");const F=_[y],x=F.split("/").pop()?.replace("_minus_sil.png","")??`frame ${y}`;if(T(`${o} → ${e} (${x})`,n),await W(t,F,null,n,l),n!==r)throw new DOMException("Aborted","AbortError");u>0&&await Ut(u,n,r)}if(n!==r)throw new DOMException("Aborted","AbortError");if(T(e,n),e==="sil"?await z(t,n,r):await W(t,q(e),null,n,l),n!==r)throw new DOMException("Aborted","AbortError");k=e}let p=0;self.onmessage=t=>{const e=t.data;(async()=>{try{switch(e.type){case"init":{w=new OffscreenCanvas(1,1);const n={type:"ready",requestId:e.requestId};self.postMessage(n);break}case"loadAssets":{U=K(e.urls),b=null,h=null,O.clear();const n=await S(e.keyHex),{width:r,height:s}=A(n),o={type:"loadAssetsDone",requestId:e.requestId,width:r,height:s,visemePaths:[...n.viseme.cellByPath.keys()]};self.postMessage(o);break}case"cancelLiveDraws":{g+=1;const n={type:"renderDone",requestId:e.requestId,generation:p};self.postMessage(n);break}case"drawFrame":{await H(()=>At(e));break}case"renderSil":{await H(async()=>{E=!0;try{if(p=e.generation,!w)throw new Error("Worker not initialized");await z(w,e.generation,p)}finally{E=!1}});const n={type:"renderDone",requestId:e.requestId,generation:e.generation};self.postMessage(n);break}case"renderViseme":{await H(async()=>{E=!0;try{if(p=e.generation,!w)throw new Error("Worker not initialized");await Nt(w,e.to,e.generation,p,{from:e.from,transitionDurationMs:e.transitionDurationMs,gapMs:e.gapMs,threshold:e.threshold})}finally{E=!1}});const n={type:"renderDone",requestId:e.requestId,generation:e.generation};self.postMessage(n);break}default:break}}catch(n){if(n instanceof DOMException&&n.name==="AbortError"){const r={type:"renderAborted",requestId:e.requestId,generation:"generation"in e?e.generation:p};self.postMessage(r);return}Ht(e.requestId,n instanceof Error?n.message:String(n))}})()}})();
|
|
1
|
+
(function(){"use strict";function it(t,e,n){return{width:t.crop?.source_width??e,height:t.crop?.source_height??n}}function ct(t,e){const n=t.crop;return{x:e?.source_x??n?.x??0,y:e?.source_y??n?.y??0,width:e?.source_w??n?.width??t.frame_width??0,height:e?.source_h??n?.height??t.frame_height??0}}function lt(t){return t?(t.w??0)>0&&(t.h??0)>0:!1}function M(t){return t.includes("/custom-faces/")}function K(t){const e=t.binBase.trim().replace(/\/$/,""),n=t.twinBase.trim().replace(/\/$/,"");if(!(t.encrypted||M(e)||M(n)))return{twinBase:n,binBase:e,encrypted:!1};const s=M(e)?e:M(n)?n:e;return{twinBase:s,binBase:s,encrypted:!0}}function m(t){return K(t).encrypted}function _t(t){const e=t.trim();if(e.length%2!==0)throw new Error("Invalid hex key");const n=new Uint8Array(e.length/2);for(let r=0;r<e.length;r+=2)n[r/2]=Number.parseInt(e.slice(r,r+2),16);return n}function B(t){return Uint8Array.from(t)}function ut(t,e){const n=new Uint8Array(t.length+e.length);return n.set(t,0),n.set(e,t.length),n}async function ft(t,e){if(!e)throw new Error("Asset key is required for encrypted assets");if(t.byteLength<28)throw new Error("Encrypted payload too small");const n=new Uint8Array(t),r=B(n.subarray(0,12)),s=B(n.subarray(12,28)),o=B(n.subarray(28)),a=B(ut(o,s)),c=await crypto.subtle.importKey("raw",_t(e),{name:"AES-GCM"},!1,["decrypt"]);return crypto.subtle.decrypt({name:"AES-GCM",iv:r,tagLength:128},c,a)}async function $(t,e){const n=await fetch(t);if(!n.ok)throw new Error(`Failed to load encrypted asset: ${t}`);const r=await n.arrayBuffer();return ft(r,e)}async function dt(t,e){if(!e)throw new Error("Missing asset key for encrypted JSON");const n=await $(t,e),r=new TextDecoder().decode(n);return JSON.parse(r)}async function wt(t){const e=new Blob([t],{type:"image/webp"});return createImageBitmap(e)}async function pt(t){const e=new Blob([t],{type:"image/png"});return createImageBitmap(e)}function C(t,e){return`${t}/${e}_minus_sil.png`}const Y=5;function J(t){const e=t?.composite_threshold;if(typeof e=="number"&&e>0)return e;const n=t?.crop?.content_threshold;return typeof n=="number"&&n>0?n:Y}const v=["t01_0.25","t02_0.50","t03_0.75"],ht=v.length,G=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 Q(t,e){return`${t}__${e}`}function X(t,e){return`pairs/${t}/${e}_minus_sil.png`}function q(t){return`${t}_minus_sil.png`}function yt(t,e){if(e.has(t))return t;const n=/^pairs\/([^/]+)\//.exec(t);if(!n)return null;const r=n[1].split("__")[1];if(!r||r==="sil")return null;const s=q(r);return e.has(s)?s:null}function mt(t,e){return t.filter(n=>e.has(n))}function gt(t,e){if(t===e)return[];const n=[],r=Q(t,e);if(G.has(r)){for(const o of v)n.push(X(r,o));return n}const s=Q(e,t);if(G.has(s)){for(let o=ht-1;o>=0;o--)n.push(X(s,v[o]));return n}return[]}function Et(t){return t<16?[1]:t<24?[1]:t<35?[0,1,2]:[0,1,2]}function It(t,e){return Et(e).map(r=>t[r]).filter(r=>r!=null)}function bt(t,e,n){if(!n)return`${t}/${e}`;const r=e.split("/").pop()??e,s=r.includes(".")?r.slice(0,r.lastIndexOf(".")):r;return`${t}/${s}.bin`}function Dt(t,e,n,r,s=Y){const o=new OffscreenCanvas(n,r),a=o.getContext("2d",{willReadFrequently:!0});a.drawImage(t,0,0,n,r);const c=a.getImageData(0,0,n,r),i=a.createImageData(n,r);i.data.set(c.data);const f=new OffscreenCanvas(n,r).getContext("2d",{willReadFrequently:!0});for(const d of e){f.clearRect(0,0,n,r),f.drawImage(d,0,0,n,r);const _=f.getImageData(0,0,n,r);for(let u=0;u<i.data.length;u+=4){const y=_.data[u],F=_.data[u+1],x=_.data[u+2];Math.max(y,F,x)>s&&(i.data[u]=y,i.data[u+1]=F,i.data[u+2]=x,i.data[u+3]=255)}}return a.putImageData(i,0,0),o}[.32,.24,.16,.08,0].map(t=>`eyes_${t.toFixed(2)}`);const P=2,St=-20,j=16,Ft={fear:-20,anger:-20,sad:-10,neutral:0,love:0,happy:0,disgust:10};function Z(t){return`brow_${t}`}function Mt(t){return Ft[t]}function V(t){return Math.max(St,Math.min(j,t))}function tt(t){const e=V(t);if(e%P===0)return[e];const n=Math.floor(e/P)*P,r=Math.min(j,n+P),s=V(n);return e-s<=r-e?s===r?[s]:[s,r]:s===r?[r]:[r,s]}const Bt={[-20]:"anger",[-10]:"sad",0:"neutral",10:"disgust"};function Pt(t,e){if(!t)return null;if(e(t))return t;const n=t.match(/^brow_(-?\d+)\/(eyes_[^/]+)_minus_sil\.png$/);if(n){const s=Number(n[1]),o=n[2];for(const c of tt(s)){if(c===s)continue;const i=C(Z(c),o);if(e(i))return i}const a=Bt[s];if(a){const c=C(a,o);if(e(c))return c}return null}const r=t.match(/^(fear|anger|sad|neutral|love|happy|disgust)\/(eyes_[^/]+)_minus_sil\.png$/);if(r){const s=r[1],o=r[2],a=Mt(s);for(const c of[a,...tt(a)]){const i=C(Z(c),o);if(e(i))return i}}return null}const et=-1,kt=1e5;function Ot(t){return t>=kt}function Rt(t){return t<0}let g=0,nt=Promise.resolve(),E=!1;function H(t){const e=nt.then(t);return nt=e.then(()=>{},()=>{}),e}function I(t,e){const n=e>0?-e:et,r={type:"renderDone",requestId:t,generation:n};self.postMessage(r)}async function At(t){const e=typeof t.liveSeq=="number"?t.liveSeq:0,n=Ot(e);if(E&&!n){I(t.requestId,e);return}if(e>0&&!n&&(g=e),!w)throw new Error("Worker not initialized");if(e>0&&!n&&e!==g){I(t.requestId,e);return}if(await S(h??void 0),e>0&&!n&&e!==g){I(t.requestId,e);return}if(await at(w,t.diffPath,t.expressionDiffPath??null,t.threshold),e>0&&!n&&e!==g){I(t.requestId,e);return}const r=e>0?-e:et;await L(r),I(t.requestId,e)}let w=null,b=null,h=null,U=null,k="sil";const O=new Map;function D(){if(!U)throw new Error("Worker assets not configured");return U}function rt(){const t=D();return m(t)?`${t.binBase}/sil.bin`:`${t.twinBase}/sil.png`}function Tt(){const t=D();return m(t)?`${t.binBase}/atlas.bin`:`${t.twinBase}/atlas.json`}function xt(){const t=D();return m(t)?`${t.binBase}/expression_atlas.bin`:`${t.twinBase}/expression_atlas.json`}function $t(){const t=D();return m(t)?t.binBase:t.twinBase}function R(){return m(D())}async function N(t){const e=await fetch(t);if(!e.ok)throw new Error(`Failed to load image: ${t}`);const n=await e.blob();return createImageBitmap(n)}async function Ct(t){return R()?pt(await $(rt(),t??"")):N(rt())}async function st(t,e,n){const r=R(),s=r?await dt(t,n):await fetch(t).then(l=>{if(!l.ok)throw new Error(`Failed to load ${t}`);return l.json()}),o=s.sheets?.[0];if(!o?.path)throw new Error(`${t} has no sheets[0].path`);const a=r?await wt(await $(bt(e,o.path,r),n??"")):await N(`${e}/${o.path}`),c=new Map;for(const l of s.cells??[])l.path&&c.set(l.path,l);const i=new Map;for(const l of s.sheets??[])i.set(l.index,l);return{atlas:a,atlasMeta:s,cellByPath:c,sheetByIndex:i,diffBase:e}}async function S(t){if(R()&&!t)throw new Error("Encrypted assets enabled but no key provided");if(b&&(!R()||h===(t??null)))return b;h=t??null,O.clear();const e=$t();return b=(async()=>{const n=await Ct(t),r=await st(Tt(),e,t);let s=null;try{s=await st(xt(),e,t)}catch{s=null}return{sil:n,viseme:r,expression:s}})(),b}function A(t){return it(t.viseme.atlasMeta,t.sil.width,t.sil.height)}function vt(t,e){if(!t.sheetByIndex.get(e.sheet??0))throw new Error(`Unknown sheet index: ${e.sheet}`);const r=new OffscreenCanvas(e.w,e.h);return r.getContext("2d",{willReadFrequently:!0}).drawImage(t.atlas,e.x,e.y,e.w,e.h,0,0,e.w,e.h),r}async function qt(t){return createImageBitmap(t)}async function ot(t,e,n){const r=`${e.diffBase}::${n}`,s=O.get(r);if(s)return s;const o=(async()=>{const a=e.cellByPath.get(n);if(!a)throw new Error(`No atlas cell for path: ${n}`);const c=ct(e.atlasMeta,a),i=A(t);if(lt(a)){const d=vt(e,a),_=new OffscreenCanvas(i.width,i.height),u=_.getContext("2d");return u.fillStyle="#000",u.fillRect(0,0,i.width,i.height),u.drawImage(d,c.x,c.y),qt(_)}const l=`${e.diffBase}/${n}`,f=await N(l);if(f.width===i.width&&f.height===i.height)return f;throw f.close(),new Error(`Diff PNG wrong size for ${n}`)})();return O.set(r,o),o}function T(t,e){const n={type:"status",label:t,generation:e};self.postMessage(n)}function Ht(t,e){const n={type:"error",requestId:t,message:e};self.postMessage(n)}async function L(t){if(!w)return;const e=Rt(t);if(!e&&t!==p)return;const n=await createImageBitmap(w);if(!e&&t!==p){n.close();return}const r={type:"frame",bitmap:n,generation:t};self.postMessage(r,{transfer:[n]})}function Ut(t,e,n){return new Promise((r,s)=>{setTimeout(()=>{e!==n?s(new DOMException("Aborted","AbortError")):r()},t)})}async function at(t,e,n,r){const s=await S(h??void 0),o=r??J(s.viseme.atlasMeta),{width:a,height:c}=A(s);(t.width!==a||t.height!==c)&&(t.width=a,t.height=c);const i=[];if(e){const d=new Set(s.viseme.cellByPath.keys()),_=yt(e,d)??(d.has(e)?e:null);_&&i.push(await ot(s,s.viseme,_))}if(n&&s.expression){const d=Pt(n,_=>s.expression.cellByPath.has(_));d&&i.push(await ot(s,s.expression,d))}const l=t.getContext("2d");if(l.clearRect(0,0,a,c),i.length===0){l.drawImage(s.sil,0,0,a,c);return}const f=Dt(s.sil,i,a,c,o);l.drawImage(f,0,0)}async function W(t,e,n,r,s){await at(t,e,n,s),await L(r)}async function z(t,e,n){k="sil";const r=await S(h??void 0);if(e!==n)throw new DOMException("Aborted","AbortError");const{width:s,height:o}=A(r);t.width=s,t.height=o;const a=t.getContext("2d");a.clearRect(0,0,s,o),a.drawImage(r.sil,0,0,s,o),await L(e)}async function Nt(t,e,n,r,s={}){const o=s.from??k,a=s.transitionDurationMs??400,c=s.gapMs??a,i=await S(h??void 0),l=s.threshold??J(i.viseme.atlasMeta);if(o===e){if(T(e,n),e==="sil"?await z(t,n,r):await W(t,q(e),null,n,l),n!==r)throw new DOMException("Aborted","AbortError");k=e;return}const f=gt(o,e),d=new Set(i.viseme.cellByPath.keys());let _=It(f,c);_=mt(_,d);const u=_.length>0?a/_.length:0;_.length===0&&T(`${o} → ${e} (no pair; final only)`,n);for(let y=0;y<_.length;y++){if(n!==r)throw new DOMException("Aborted","AbortError");const F=_[y],x=F.split("/").pop()?.replace("_minus_sil.png","")??`frame ${y}`;if(T(`${o} → ${e} (${x})`,n),await W(t,F,null,n,l),n!==r)throw new DOMException("Aborted","AbortError");u>0&&await Ut(u,n,r)}if(n!==r)throw new DOMException("Aborted","AbortError");if(T(e,n),e==="sil"?await z(t,n,r):await W(t,q(e),null,n,l),n!==r)throw new DOMException("Aborted","AbortError");k=e}let p=0;self.onmessage=t=>{const e=t.data;(async()=>{try{switch(e.type){case"init":{w=new OffscreenCanvas(1,1);const n={type:"ready",requestId:e.requestId};self.postMessage(n);break}case"loadAssets":{U=K(e.urls),b=null,h=null,O.clear();const n=await S(e.keyHex),{width:r,height:s}=A(n),o={type:"loadAssetsDone",requestId:e.requestId,width:r,height:s,visemePaths:[...n.viseme.cellByPath.keys()]};self.postMessage(o);break}case"cancelLiveDraws":{g+=1;const n={type:"renderDone",requestId:e.requestId,generation:p};self.postMessage(n);break}case"drawFrame":{await H(()=>At(e));break}case"renderSil":{await H(async()=>{E=!0;try{if(p=e.generation,!w)throw new Error("Worker not initialized");await z(w,e.generation,p)}finally{E=!1}});const n={type:"renderDone",requestId:e.requestId,generation:e.generation};self.postMessage(n);break}case"renderViseme":{await H(async()=>{E=!0;try{if(p=e.generation,!w)throw new Error("Worker not initialized");await Nt(w,e.to,e.generation,p,{from:e.from,transitionDurationMs:e.transitionDurationMs,gapMs:e.gapMs,threshold:e.threshold})}finally{E=!1}});const n={type:"renderDone",requestId:e.requestId,generation:e.generation};self.postMessage(n);break}default:break}}catch(n){if(n instanceof DOMException&&n.name==="AbortError"){const r={type:"renderAborted",requestId:e.requestId,generation:"generation"in e?e.generation:p};self.postMessage(r);return}Ht(e.requestId,n instanceof Error?n.message:String(n))}})()}})();
|
package/dist/index.d.ts
CHANGED
|
@@ -139,6 +139,9 @@ export declare type AvatarTtsLipsyncController = {
|
|
|
139
139
|
stop: () => void;
|
|
140
140
|
getVisemeQueue: () => VisemeQueueItem[];
|
|
141
141
|
getWordQueue: () => WordQueueItem[];
|
|
142
|
+
/** Full utterance viseme queue (all SSE chunks, cumulative vtimes) for debug. */
|
|
143
|
+
getFullVisemeQueue: () => VisemeQueueItem[];
|
|
144
|
+
getFullWordQueue: () => WordQueueItem[];
|
|
142
145
|
getSentenceEmotions: () => SentenceEmotion[];
|
|
143
146
|
getStreamMood: () => string;
|
|
144
147
|
getPlaybackElapsedMs: () => number;
|
|
@@ -266,6 +269,8 @@ export declare function getAiTwinSourceUrl(faceId: string, cdnBase?: string, ext
|
|
|
266
269
|
/** Public CDN thumbnail for custom-faces/{faceId}/ (same id as pipeline avatarId). */
|
|
267
270
|
export declare function getAiTwinThumbnailUrl(faceId: string, cdnBase?: string): string;
|
|
268
271
|
|
|
272
|
+
export declare function listSkippedVisemeEntries(queue: VisemeQueueItem[]): SkippedVisemeEntry[];
|
|
273
|
+
|
|
269
274
|
/** Visemes removed by compaction (for debug). */
|
|
270
275
|
export declare function listSkippedVisemes(queue: VisemeQueueItem[]): string[];
|
|
271
276
|
|
|
@@ -298,6 +303,10 @@ export declare type RealtimeLipsyncDebugSnapshot = {
|
|
|
298
303
|
queueLength: number;
|
|
299
304
|
activeViseme: string;
|
|
300
305
|
segments: RealtimeLipsyncSegmentDebug[];
|
|
306
|
+
/** Full-utterance viseme count (all SSE chunks, cumulative vtimes). */
|
|
307
|
+
fullQueueLength: number;
|
|
308
|
+
/** Visemes dropped by playback compaction (tight same-group slots). */
|
|
309
|
+
compactionSkipped: SkippedVisemeDebugEntry[];
|
|
301
310
|
};
|
|
302
311
|
|
|
303
312
|
export declare type RealtimeLipsyncSegmentDebug = {
|
|
@@ -355,6 +364,17 @@ export declare interface SentenceEmotion {
|
|
|
355
364
|
|
|
356
365
|
export declare function setActiveTwinAssets(urls: TwinAssetUrls): void;
|
|
357
366
|
|
|
367
|
+
export declare type SkippedVisemeDebugEntry = {
|
|
368
|
+
viseme: string;
|
|
369
|
+
vtimeMs: number;
|
|
370
|
+
};
|
|
371
|
+
|
|
372
|
+
/** Visemes removed by compaction (for debug). */
|
|
373
|
+
declare type SkippedVisemeEntry = {
|
|
374
|
+
viseme: string;
|
|
375
|
+
vtime: number;
|
|
376
|
+
};
|
|
377
|
+
|
|
358
378
|
export declare const SPEAKING_RATE_MAX = 1.5;
|
|
359
379
|
|
|
360
380
|
export declare const SPEAKING_RATE_MIN = 0.5;
|
|
@@ -380,7 +400,7 @@ export declare type TwinAssetUrls = {
|
|
|
380
400
|
export declare const VISEME_IDS: readonly ["aa", "E", "I", "O", "U", "PP", "FF", "DD", "SS", "TH", "CH", "RR", "kk", "nn"];
|
|
381
401
|
|
|
382
402
|
/** Minimum gap (ms) between consecutive vtimes to keep a skippable viseme. */
|
|
383
|
-
export declare const VISEME_SKIP_GAP_MS =
|
|
403
|
+
export declare const VISEME_SKIP_GAP_MS = 47;
|
|
384
404
|
|
|
385
405
|
/** Preset Cartesia voice (Katie) for testing without a custom clone. */
|
|
386
406
|
export declare const VISEME_TEST_CARTESIA_VOICE_ID = "f786b574-daa5-4673-aa0c-cbe3e8534c02";
|
|
@@ -423,7 +443,7 @@ export declare interface WordQueueItem {
|
|
|
423
443
|
queueIndex: number;
|
|
424
444
|
gesture?: string | null;
|
|
425
445
|
emotion?: string;
|
|
426
|
-
/** When true, raise eyebrows +6 (capped at +
|
|
446
|
+
/** When true, raise eyebrows +6 (capped at +16) for this word's duration. */
|
|
427
447
|
emphasis?: boolean;
|
|
428
448
|
}
|
|
429
449
|
|