@idosgames/characters 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +38 -2
- package/dist/PartsManager-CAVBKvp6.d.ts +589 -0
- package/dist/PartsManager-Cn3MU-VS.d.cts +589 -0
- package/dist/chunk-64D567CX.js +1 -0
- package/dist/chunk-BU66AZ2Z.js +1 -0
- package/dist/chunk-CGF2TQVK.js +1 -0
- package/dist/chunk-OF4BH3JZ.js +2 -0
- package/dist/chunk-WKHHFTK2.js +1 -0
- package/dist/chunk-Z5I76WRJ.js +1 -0
- package/dist/contract-DhZuKNIf.d.cts +24 -0
- package/dist/contract-DhZuKNIf.d.ts +24 -0
- package/dist/gltf/index.cjs +1 -0
- package/dist/gltf/index.d.cts +150 -0
- package/dist/gltf/index.d.ts +150 -0
- package/dist/gltf/index.js +1 -0
- package/dist/image-D5NaQeFz.d.cts +8 -0
- package/dist/image-D5NaQeFz.d.ts +8 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +65 -0
- package/dist/index.d.ts +65 -0
- package/dist/index.js +1 -0
- package/dist/rig2d/editor/index.cjs +81 -0
- package/dist/rig2d/editor/index.d.cts +25 -0
- package/dist/rig2d/editor/index.d.ts +25 -0
- package/dist/rig2d/editor/index.js +81 -0
- package/dist/rig2d/index.cjs +17 -0
- package/dist/rig2d/index.d.cts +190 -0
- package/dist/rig2d/index.d.ts +190 -0
- package/dist/rig2d/index.js +17 -0
- package/dist/rig2d/phaser/index.cjs +2 -0
- package/dist/rig2d/phaser/index.d.cts +106 -0
- package/dist/rig2d/phaser/index.d.ts +106 -0
- package/dist/rig2d/phaser/index.js +1 -0
- package/dist/rig2d/three/index.cjs +2 -0
- package/dist/rig2d/three/index.d.cts +63 -0
- package/dist/rig2d/three/index.d.ts +63 -0
- package/dist/rig2d/three/index.js +1 -0
- package/dist/thumbnail-BhGEEXux.d.cts +49 -0
- package/dist/thumbnail-Bp-jK70T.d.ts +49 -0
- package/dist/voxel/index.cjs +54 -0
- package/dist/voxel/index.d.cts +972 -0
- package/dist/voxel/index.d.ts +972 -0
- package/dist/voxel/index.js +54 -0
- package/package.json +101 -4
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var Tt="#1f1a21";var Qt="currentColor";function zt(s,t,e=1,n={}){let o=Math.max(1,Math.ceil(t.w*e)),r=Math.max(1,Math.ceil(t.h*e)),a=n.paint??s.paint,i=n.light?$t(t,n.light):"";return `<svg xmlns="http://www.w3.org/2000/svg" width="${o}" height="${r}" viewBox="0 0 ${t.w} ${t.h}"${a?` color="${a}"`:""}>${i}<g stroke-linejoin="round" stroke-linecap="round"${i?' filter="url(#cel)"':""}>${s.svg}</g></svg>`}var K={depth:.18,min:2.6,max:11,dark:.3,shine:.36};function $t(s,t){let e=Math.max(K.min,Math.min(K.max,Math.min(s.w,s.h)*K.depth)),n=o=>+o.toFixed(2);return `<defs><filter id="cel" filterUnits="userSpaceOnUse" x="0" y="0" width="${s.w}" height="${s.h}" color-interpolation-filters="sRGB"><feMorphology in="SourceAlpha" operator="erode" radius="${n(3.6*.7)}" result="body"/><feOffset in="body" dx="${n(t.x*e)}" dy="${n(t.y*e)}" result="moved"/><feComposite in="body" in2="moved" operator="out" result="far"/><feFlood flood-color="#000000" flood-opacity="${K.dark}"/><feComposite in2="far" operator="in" result="dark"/><feMorphology in="SourceAlpha" operator="erode" radius="${n(3.6*1.05)}" result="inner"/><feOffset in="inner" dx="${n(-t.x*e*.42)}" dy="${n(-t.y*e*.42)}" result="back"/><feComposite in="inner" in2="back" operator="out" result="near"/><feFlood flood-color="#ffffff" flood-opacity="${K.shine}"/><feComposite in2="near" operator="in" result="shine"/><feMerge><feMergeNode in="SourceGraphic"/><feMergeNode in="dark"/><feMergeNode in="shine"/></feMerge></filter></defs>`}function lt(s={}){let t=s.stroke??Tt,e=(s.opacity!==void 0?` opacity="${s.opacity}"`:"")+(s.holes?' fill-rule="evenodd"':"");return t==="none"?` stroke="none"${e}`:` stroke="${t}" stroke-width="${s.width??3.6}"${e}`}var Rt=(s,t,e)=>`<path d="${s}" fill="${t}"${lt(e)}/>`,Ft=(s,t,e,n,o,r)=>`<ellipse cx="${s}" cy="${t}" rx="${e}" ry="${n}" fill="${o}"${lt(r)}/>`,te=(s,t,e,n,o)=>Ft(s,t,e,e,n,o),ee=(s,t,e,n,o,r,a)=>`<rect x="${s}" y="${t}" width="${e}" height="${n}" rx="${o}" fill="${r}"${lt(a)}/>`,ne=(s,t=Tt,e=2.2)=>`<path d="${s}" fill="none" stroke="${t}" stroke-width="${e}"/>`,oe=(s,t,e)=>Rt(s,t,{stroke:"none",...e!==void 0?{opacity:e}:{}}),se=(s,t,...e)=>`<clipPath id="${s}"><path d="${t}" clip-rule="evenodd"/></clipPath><g clip-path="url(#${s})">${e.join("")}</g>`,re=(s,...t)=>`<g transform="${s}">${t.join("")}</g>`;function ie(s,t){let e=parseInt(s.replace("#",""),16),n=i=>Math.max(0,Math.min(255,Math.round(t<0?i*(1+t):i+(255-i)*t))),o=n(e>>16&255),r=n(e>>8&255),a=n(e&255);return `#${(o<<16|r<<8|a).toString(16).padStart(6,"0")}`}var le="#ffffff";function ce(s){let t=/^#?([0-9a-f]{6})$/i.exec(s.trim());return t?parseInt(t[1],16):16777215}function he(s){return `#${(s&16777215).toString(16).padStart(6,"0")}`}function O(s){let t=(s??"ffffffff").replace("#","").padEnd(8,"f"),e=n=>parseInt(t.slice(n,n+2),16)/255;return {r:e(0),g:e(2),b:e(4),a:e(6)}}var L=Math.PI/180,ct=1e-5;function At(s,t){return s.type==="ik"?new I(s,t):new pt(s,t)}var ht=s=>s>180?s-360:s<=-180?s+360:s,I=class{constructor(t,e){this.data=t;this.bones=t.bones.map(n=>e.bones[n.index]),this.target=e.bones[t.target.index],this.mix=t.mix,this.bendDirection=t.bendDirection;}data;mix;bendDirection;bones;target;setupPose(){this.mix=this.data.mix,this.bendDirection=this.data.bendDirection;}sort(t){t.sortBone(this.target);let e=this.bones[0];t.sortBone(e),t.pushConstraint(this),e.sorted=false,t.sortReset(e.children);}update(t){if(this.mix===0)return;let e=this.target.applied;this.bones.length===1?Pt(t,this.bones[0].applied,e.worldX,e.worldY,this.mix):Nt(t,this.bones[0].applied,this.bones[1].applied,e.worldX,e.worldY,this.bendDirection,this.mix);}};function Pt(s,t,e,n,o){let r=t.bone.parent;if(!r)return;t.modifyLocal(s);let a=r.applied,i=a.a,p=a.b,l=a.c,c=a.d,d=-t.shearX-t.rotation,h=i*c-p*l,u=e-a.worldX,m=n-a.worldY,f=(u*c-m*p)/h-t.x,b=(m*i-u*l)/h-t.y;d+=Math.atan2(b,f)/L,t.scaleX<0&&(d+=180),t.rotation+=ht(d)*o;}function Nt(s,t,e,n,o,r,a){t.modifyLocal(s),e.modifyLocal(s);let i=t.x,p=t.y,l=t.scaleX,c=t.scaleY,d=e.scaleX,h,u,m;l<0?(l=-l,h=180,m=-1):(h=0,m=1),c<0&&(c=-c,m=-m),d<0?(d=-d,u=180):u=0;let f=Math.abs(l-c)<=ct,b,y;f?(b=t.a*e.x+t.b*e.y+t.worldX,y=t.c*e.x+t.d*e.y+t.worldY):(e.y=0,b=t.a*e.x+t.worldX,y=t.c*e.x+t.worldY);let x=t.bone.parent;if(!x)return;let g=x.applied,w=g.a,M=g.b,st=g.c,rt=g.d,Y=w*rt-M*st,F=b-g.worldX,N=y-g.worldY;Y=Math.abs(Y)<=ct?0:1/Y;let gt=(F*rt-N*M)*Y-i,xt=(N*w-F*st)*Y-p,k=Math.sqrt(gt*gt+xt*xt),P=e.bone.data.length*d;if(k<ct){Pt(s,t,n,o,a),e.rotation=0;return}F=n-g.worldX,N=o-g.worldY;let H=(F*rt-N*M)*Y-i,J=(N*w-F*st)*Y-p,G=H*H+J*J,D=0,T=0;if(f){P*=l;let v=(G-k*k-P*P)/(2*k*P);v<-1?(v=-1,T=Math.PI*r):v>1?(v=1,T=0):T=Math.acos(v)*r;let $=k+P*v,X=P*Math.sin(T);D=Math.atan2(J*$-H*X,H*$+J*X);}else {let v=l*P,$=c*P,X=v*v,q=$*$,it=Math.atan2(J,H),S=q*k*k+X*G-X*q,V=-2*q*k,vt=q-X,wt=V*V-4*vt*S,St=false;if(wt>=0){let A=Math.sqrt(wt);V<0&&(A=-A),A=-(V+A)*.5;let E=A/vt,R=S/A,B=Math.abs(E)<Math.abs(R)?E:R,W=G-B*B;if(W>=0){let C=Math.sqrt(W)*r;D=it-Math.atan2(C,B),T=Math.atan2(C/c,(B-k)/l),St=true;}}if(!St){let A=Math.PI,E=k-v,R=E*E,B=0,W=0,C=k+v,at=C*C,Mt=0;if(S=-v*k/(X-q),S>=-1&&S<=1){S=Math.acos(S);let U=v*Math.cos(S)+k,_=$*Math.sin(S),Z=U*U+_*_;Z<R&&(A=S,R=Z,E=U,B=_),Z>at&&(W=S,at=Z,C=U,Mt=_);}G<=(R+at)*.5?(D=it-Math.atan2(B*r,E),T=A*r):(D=it-Math.atan2(Mt*r,C),T=W*r);}}let kt=Math.atan2(e.y,e.x)*m;D=ht((D-kt)/L+h-t.rotation),T=ht(((T+kt)/L-e.shearX)*m+u-e.rotation),t.rotation+=D*a,e.rotation+=T*a;}var pt=class{constructor(t,e){this.data=t;this.source=e.bones[t.source.index],this.bones=t.bones.map(n=>e.bones[n.index]),this.mix={...t.mix};}data;mix;source;bones;setupPose(){Object.assign(this.mix,this.data.mix);}sort(t){t.sortBone(this.source);for(let e of this.bones)t.sortBone(e);t.pushConstraint(this);for(let e of this.bones)t.sortReset(e.children);for(let e of this.bones)e.sorted=true;}update(t){let e=this.mix;if(!e.rotate&&!e.x&&!e.y&&!e.scaleX&&!e.scaleY&&!e.shearY)return;let n=this.source.applied,o=this.data.offsets;for(let r of this.bones){let a=r.applied;a.modifyWorld(t);for(let i of this.data.properties){let p=Ht(t,n,i.prop,o)-i.offset;for(let l of i.to){let c=e[l.prop];c!==0&&Jt(t,a,l.prop,l.offset+p*l.scale,c);}}}}};function Ht(s,t,e,n){let o=s.scaleX,r=s.scaleY;switch(e){case "rotate":{let a=(t.a*t.d-t.b*t.c)*o*r>0?1:-1,i=Math.atan2(t.c/r,t.a/o)/L+a*n.rotate;return i<0&&(i+=360),i}case "x":return (n.x*t.a+n.y*t.b+t.worldX)/o;case "y":return (n.x*t.c+n.y*t.d+t.worldY)/r;case "scaleX":return Math.hypot(t.a/o,t.c/r)+n.scaleX;case "scaleY":return Math.hypot(t.b/o,t.d/r)+n.scaleY;case "shearY":return (Math.atan2(t.d/r,t.b/o)-Math.atan2(t.c/r,t.a/o))/L-90+n.shearY}}function Jt(s,t,e,n,o){let r=s.scaleX,a=s.scaleY;switch(e){case "rotate":{let i=t.a/r,p=t.b/r,l=t.c/a,c=t.d/a,d=n*L-Math.atan2(l,i);d>Math.PI?d-=2*Math.PI:d<-Math.PI&&(d+=2*Math.PI),d*=o;let h=Math.cos(d),u=Math.sin(d);t.a=(h*i-u*l)*r,t.b=(h*p-u*c)*r,t.c=(u*i+h*l)*a,t.d=(u*p+h*c)*a;return}case "x":t.worldX+=(n-t.worldX/r)*o*r;return;case "y":t.worldY+=(n-t.worldY/a)*o*a;return;case "scaleX":{let i=Math.hypot(t.a/r,t.c/a);i!==0&&(i=1+(n-i)*o/i,t.a*=i,t.c*=i);return}case "scaleY":{let i=Math.hypot(t.b/r,t.d/a);i!==0&&(i=1+(n-i)*o/i,t.b*=i,t.d*=i);return}case "shearY":{let i=t.b/r,p=t.d/a,l=Math.atan2(p,i),c=(n+90)*L;c-=l-Math.atan2(t.c/a,t.a/r),c>Math.PI?c-=2*Math.PI:c<-Math.PI&&(c+=2*Math.PI),c=l+c*o;let d=Math.hypot(i,p);t.b=Math.cos(c)*d*r,t.d=Math.sin(c)*d*a;return}}}var Q=class{constructor(t){this.channels=t;}channels;times=[];values=[];kinds=[];samples=[];get count(){return this.times.length}add(t,e){this.times.push(t);for(let n=0;n<this.channels;n++)this.values.push(e[n]??0);this.kinds.push(0);for(let n=0;n<this.channels;n++)this.samples.push(null);}setCurve(t,e){if(e==="stepped"){this.kinds[t]=1;return}if(!Array.isArray(e)||t+1>=this.count)return;this.kinds[t]=2;let n=this.times[t],o=this.times[t+1];for(let r=0;r<this.channels;r++){let a=r*4;if(e.length<a+4)continue;let i=this.values[t*this.channels+r],p=this.values[(t+1)*this.channels+r];this.samples[t*this.channels+r]=qt(n,i,Number(e[a]),Number(e[a+1]),Number(e[a+2]),Number(e[a+3]),o,p);}}keyAt(t){let e=this.times;if(!e.length||t<e[0])return -1;let n=0,o=e.length-1;for(;n<o;){let r=n+o+1>>1;e[r]<=t?n=r:o=r-1;}return n}value(t,e=0){let n=Math.max(0,this.keyAt(t)),o=this.channels,r=this.values[n*o+e];if(n+1>=this.count)return r;let a=this.kinds[n];if(a===1)return r;let i=this.times[n],p=this.times[n+1],l=this.values[(n+1)*o+e],c=this.samples[n*o+e];if(a!==2||!c)return r+(t-i)/(p-i)*(l-r);if(c[0]>t)return r+(t-i)/(c[0]-i)*(c[1]-r);for(let u=2;u<18;u+=2)if(c[u]>=t){let m=c[u-2],f=c[u-1];return f+(t-m)/(c[u]-m)*(c[u+1]-f)}let d=c[16],h=c[17];return h+(t-d)/(p-d)*(l-h)}};function qt(s,t,e,n,o,r,a,i){let p=new Float32Array(18);for(let l=1;l<=9;l++){let c=l/10,d=1-c,h=d*d*d,u=3*d*d*c,m=3*d*c*c,f=c*c*c;p[(l-1)*2]=h*s+u*e+m*o+f*a,p[(l-1)*2+1]=h*t+u*n+m*r+f*i;}return p}var It=(s,t)=>s.bone!==void 0&&t.bones.has(s.bone)||s.slot!==void 0&&t.slots.has(s.slot),dt=class{constructor(t,e,n,o){this.name=t;this.duration=e;this.timelines=n;this.events=o;}name;duration;timelines;events;apply(t,e){for(let n of this.timelines)n.apply(t,e);}applyOnly(t,e,n){for(let o of this.timelines)It(o,n)&&o.apply(t,e);}touches(t){return this.timelines.some(e=>It(e,t))}},ut=class{constructor(t,e,n){this.bone=t;this.keys=e;this.props=n;}bone;keys;props;apply(t,e){if(this.keys.keyAt(e)<0)return;let n=t.bones[this.bone],o=n.pose,r=n.data;this.props.forEach((a,i)=>{let p=this.keys.value(e,i);switch(a){case "rotate":o.rotation=r.rotation+p;break;case "x":o.x=r.x+p;break;case "y":o.y=r.y+p;break;case "scaleX":o.scaleX=r.scaleX*p;break;case "scaleY":o.scaleY=r.scaleY*p;break}});}},tt=class{constructor(t,e,n){this.slot=t;this.keys=e;this.channels=n;}slot;keys;channels;apply(t,e){if(this.keys.keyAt(e)<0)return;let n=t.slots[this.slot].color;this.channels.forEach((o,r)=>n[o]=this.keys.value(e,r));}},mt=class{constructor(t,e,n){this.slot=t;this.times=e;this.names=n;}slot;times;names;apply(t,e){if(e<this.times[0])return;let n=0;for(;n+1<this.times.length&&this.times[n+1]<=e;)n++;t.slots[this.slot].attachmentKey=this.names[n];}},ft=class{constructor(t,e,n){this.constraint=t;this.keys=e;this.bends=n;}constraint;keys;bends;apply(t,e){let n=this.keys.keyAt(e);if(n<0)return;let o=t.constraints[this.constraint];o instanceof I&&(o.mix=this.keys.value(e,0),o.bendDirection=this.bends[n]);}};function z(s,t,e){let n=new Q(t);for(let o of s)n.add(o.time??0,e(o));return s.forEach((o,r)=>n.setCurve(r,o.curve)),n}var Wt={rotate:{props:["rotate"],read:s=>[s.value??0]},translate:{props:["x","y"],read:s=>[s.x??0,s.y??0]},translatex:{props:["x"],read:s=>[s.value??0]},translatey:{props:["y"],read:s=>[s.value??0]},scale:{props:["scaleX","scaleY"],read:s=>[s.x??1,s.y??1]},scalex:{props:["scaleX"],read:s=>[s.value??1]},scaley:{props:["scaleY"],read:s=>[s.value??1]}};function Yt(s,t,e){let n=[],o=0,r=i=>{for(let p of i)o=Math.max(o,p.time??0);};for(let[i,p]of Object.entries(t.bones??{})){let l=e.bone(i).index;for(let[c,d]of Object.entries(p)){let h=Wt[c];!h||!d.length||(r(d),n.push(new ut(l,z(d,h.props.length,h.read),h.props)));}}for(let[i,p]of Object.entries(t.slots??{})){let l=e.slot(i).index;for(let[c,d]of Object.entries(p))if(d.length)if(r(d),c==="attachment")n.push(new mt(l,d.map(h=>h.time??0),d.map(h=>h.name??null)));else if(c==="rgba"||c==="rgb"){let h=c==="rgba"?["r","g","b","a"]:["r","g","b"],u=z(d,h.length,m=>{let f=O(m.color);return h.map(b=>f[b])});n.push(new tt(l,u,[...h]));}else c==="alpha"&&n.push(new tt(l,z(d,1,h=>[h.value??0]),["a"]));}for(let[i,p]of Object.entries(t.ik??{})){let l=e.constraints.find(c=>c.type==="ik"&&c.name===i);!l||!p.length||(r(p),n.push(new ft(l.index,z(p,1,c=>[c.mix??1]),p.map(c=>c.bendPositive===false?-1:1))));}let a=(t.events??[]).map(i=>({time:i.time??0,name:i.name}));for(let i of a)o=Math.max(o,i.time);return new dt(s,o,n,a)}function ve(s){let t=[],e=new Map;for(let h of s.bones){let u=h.parent?e.get(h.parent)??null:null,m={index:t.length,name:h.name,parent:u,children:[],length:h.length??0,x:h.x??0,y:h.y??0,rotation:h.rotation??0,scaleX:h.scaleX??1,scaleY:h.scaleY??1};u?.children.push(m),t.push(m),e.set(m.name,m);}let n=h=>{let u=e.get(h);if(!u)throw new Error(`no bone ${h}`);return u},o=[],r=new Map;for(let h of s.slots){let u={index:o.length,name:h.name,bone:n(h.bone),attachment:h.attachment??null,color:O(h.color)};o.push(u),r.set(u.name,u);}let a=h=>{let u=r.get(h);if(!u)throw new Error(`no slot ${h}`);return u},i=[];for(let h of s.constraints??[])if(h.type==="ik")i.push({type:"ik",index:i.length,name:h.name,bones:h.bones.map(n),target:n(h.target),mix:h.mix??1,bendDirection:h.bendPositive===false?-1:1});else if(h.type==="transform"){let u=[],m=new Set;for(let[y,x]of Object.entries(h.properties??{})){let g=[];for(let[w,M]of Object.entries(x.to??{}))m.add(w),g.push({prop:w,offset:M.offset??0,max:M.max??1,scale:M.scale??1});g.length&&u.push({prop:y,offset:x.offset??0,to:g});}let f=h.mixX??1,b=h.mixScaleX??1;i.push({type:"transform",index:i.length,name:h.name,source:n(h.source),bones:h.bones.map(n),offsets:{rotate:h.rotation??0,x:h.x??0,y:h.y??0,scaleX:h.scaleX??0,scaleY:h.scaleY??0,shearY:h.shearY??0},mix:{rotate:m.has("rotate")?h.mixRotate??1:0,x:m.has("x")?f:0,y:m.has("y")?h.mixY??f:0,scaleX:m.has("scaleX")?b:0,scaleY:m.has("scaleY")?h.mixScaleY??b:0,shearY:m.has("shearY")?h.mixShearY??1:0},properties:u});}let p=new Map,l=[],c=[];for(let h of s.skins){let u={name:h.name,attachments:new Map};for(let[m,f]of Object.entries(h.attachments??{})){let b=a(m).index,y=new Map;u.attachments.set(b,y);for(let[x,g]of Object.entries(f)){let w=g.type??"region";w==="linkedmesh"?c.push({skin:u,slot:b,key:x,a:g}):y.set(x,Kt(x,g,w));}}p.set(u.name,u),l.push(u.name);}for(let{skin:h,slot:u,key:m,a:f}of c){let y=(p.get(f.skin??"default")??h).attachments.get(u)?.get(f.source??f.parent);if(!y||y.type!=="mesh")throw new Error(`linked mesh ${h.name}/${m}: no source mesh`);h.attachments.get(u).set(m,{...y,key:m,path:f.path??f.name??m,width:f.width??y.width,height:f.height??y.height,color:O(f.color)});}let d={width:s.skeleton?.width??0,height:s.skeleton?.height??0,x:s.skeleton?.x??0,y:s.skeleton?.y??0,bones:t,slots:o,constraints:i,skins:p,skinOrder:l,animations:new Map,events:Object.keys(s.events??{}),bone:n,slot:a};for(let[h,u]of Object.entries(s.animations??{}))d.animations.set(h,Yt(h,u,d));return d}function Kt(s,t,e){let n=t.path??t.name??s;if(e==="mesh"){let o=Float32Array.from(t.uvs),r=o.length/2,a=t.vertices;return {type:"mesh",key:s,path:n,uvs:o,triangles:Uint16Array.from(t.triangles),vertices:Float32Array.from(a),weighted:a.length>o.length,vertexCount:r,width:t.width??0,height:t.height??0,color:O(t.color)}}return {type:"region",key:s,path:n,x:t.x??0,y:t.y??0,rotation:t.rotation??0,scaleX:t.scaleX??1,scaleY:t.scaleY??1,width:t.width??0,height:t.height??0,color:O(t.color)}}var Dt=new WeakMap;function we(s){let t=Dt.get(s);if(t)return t;t=new Map;for(let e of s.skins.values())for(let n of e.attachments.values())for(let o of n.values())t.has(o.path)||t.set(o.path,{w:o.width,h:o.height});return Dt.set(s,t),t}function Se(s,t){let e=s.skins.get(t);if(!e)return [];let n=new Set;for(let o of e.attachments.values())for(let r of o.values())n.add(r.path);return [...n]}var j=Math.PI/180,yt=1e-5,et=class{constructor(t){this.bone=t;}bone;x=0;y=0;rotation=0;scaleX=1;scaleY=1;shearX=0;shearY=0;a=1;b=0;c=0;d=1;worldX=0;worldY=0;world=0;local=0;copyLocal(t){this.x=t.x,this.y=t.y,this.rotation=t.rotation,this.scaleX=t.scaleX,this.scaleY=t.scaleY,this.shearX=t.shearX,this.shearY=t.shearY;}update(t){this.world!==t.updateId&&this.updateWorldTransform(t);}updateWorldTransform(t){this.local===t.updateId?this.updateLocalTransform(t):this.world=t.updateId;let e=(this.rotation+this.shearX)*j,n=(this.rotation+90+this.shearY)*j,o=Math.cos(e)*this.scaleX,r=Math.cos(n)*this.scaleY,a=Math.sin(e)*this.scaleX,i=Math.sin(n)*this.scaleY,p=this.bone.parent;if(!p){let c=t.scaleX,d=t.scaleY;this.a=o*c,this.b=r*c,this.c=a*d,this.d=i*d,this.worldX=this.x*c+t.x,this.worldY=this.y*d+t.y;return}let l=p.applied;this.worldX=l.a*this.x+l.b*this.y+l.worldX,this.worldY=l.c*this.x+l.d*this.y+l.worldY,this.a=l.a*o+l.b*a,this.b=l.a*r+l.b*i,this.c=l.c*o+l.d*a,this.d=l.c*r+l.d*i;}updateLocalTransform(t){this.local=0,this.world=t.updateId;let e=this.bone.parent;if(!e){this.x=(this.worldX-t.x)/t.scaleX,this.y=(this.worldY-t.y)/t.scaleY,this.set5(this.a/t.scaleX,this.b/t.scaleX,this.c/t.scaleY,this.d/t.scaleY);return}let n=e.applied,o=1/(n.a*n.d-n.b*n.c),r=n.d*o,a=n.b*o,i=n.c*o,p=n.a*o,l=this.worldX-n.worldX,c=this.worldY-n.worldY;this.x=l*r-c*a,this.y=c*p-l*i,this.set5(r*this.a-a*this.c,r*this.b-a*this.d,p*this.c-i*this.a,p*this.d-i*this.b);}set5(t,e,n,o){this.shearX=0;let r=t*t+n*n,a=e*e+o*o;if(r>yt){let i=Math.atan2(n,t)/j;this.rotation=i,this.scaleX=Math.sqrt(r),this.scaleY=Math.sqrt(a),a>yt?(this.shearY=Math.atan2(o,e)/j,t*o-e*n<0?(this.scaleY=-this.scaleY,this.shearY+=90-i):this.shearY-=90+i,this.shearY>180?this.shearY-=360:this.shearY<=-180&&(this.shearY+=360)):this.shearY=0;}else this.scaleX=0,this.scaleY=Math.sqrt(a),this.shearY=0,this.rotation=a>yt?Math.atan2(o,e)/j-90:0;}modifyLocal(t){this.local===t.updateId&&this.updateLocalTransform(t),this.world=0,this.resetWorld(t);}modifyWorld(t){this.local=t.updateId,this.world=t.updateId,this.resetWorld(t);}resetWorld(t){for(let e of this.bone.children){let n=e.applied;n.world===t.updateId&&(n.local===t.updateId&&n.updateLocalTransform(t),n.world=0,n.resetWorld(t));}}},nt=class{constructor(t){this.data=t;this.pose=new et(this),this.applied=new et(this),this.setupPose();}data;pose;applied;parent=null;children=[];sorted=false;setupPose(){let t=this.data,e=this.pose;e.x=t.x,e.y=t.y,e.rotation=t.rotation,e.scaleX=t.scaleX,e.scaleY=t.scaleY,e.shearX=0,e.shearY=0;}},bt=class{constructor(t,e){this.data=t;this.bone=e;this.color={...t.color},this.attachmentKey=t.attachment;}data;bone;color;attachmentKey;attachment=null},ot=class{constructor(t){this.data=t;this.bones=t.bones.map(e=>new nt(e));for(let e of this.bones)e.data.parent&&(e.parent=this.bones[e.data.parent.index],e.parent.children.push(e));this.slots=t.slots.map(e=>new bt(e,this.bones[e.bone.index])),this.constraints=t.constraints.map(e=>At(e,this)),this.updateCache();}data;bones;slots;constraints;skins=[];scaleX=1;scaleY=1;x=0;y=0;updateId=0;cache=[];bone(t){return this.bones[this.data.bone(t).index]}slot(t){return this.slots[this.data.slot(t).index]}setSkins(t){this.skins=[...t],this.resolveAttachments();}getAttachment(t,e){for(let n=this.skins.length-1;n>=0;n--){let o=this.skins[n].attachments.get(t)?.get(e);if(o)return o}return null}resolveAttachments(){for(let t of this.slots)t.attachment=t.attachmentKey?this.getAttachment(t.data.index,t.attachmentKey):null;}setupPose(){for(let t of this.bones)t.setupPose();for(let t of this.constraints)t.setupPose();for(let t of this.slots)Object.assign(t.color,t.data.color),t.attachmentKey=t.data.attachment;}updateWorldTransform(){this.updateId++;for(let t of this.bones)t.applied.copyLocal(t.pose),t.applied.world=0,t.applied.local=0;for(let t of this.cache)t instanceof nt?t.applied.update(this):t.update(this);}updateCache(){this.cache=[];for(let t of this.bones)t.sorted=false;for(let t of this.constraints)t.sort(this);for(let t of this.bones)this.sortBone(t);}sortBone(t){t.sorted||(t.parent&&this.sortBone(t.parent),t.sorted=true,this.cache.push(t));}sortReset(t){for(let e of t)e.sorted&&this.sortReset(e.children),e.sorted=false;}pushConstraint(t){this.cache.push(t);}};var Xt=class{constructor(t,e,n=.2){this.skeleton=t;this.data=e;this.defaultMix=n;this.snapshot=new Float32Array(t.bones.length*5),this.slotSnapshot=new Float32Array(t.slots.length*4),this.ikSnapshot=new Float32Array(t.constraints.length);}skeleton;data;defaultMix;track=null;previous=null;mixTime=0;mixDuration=0;listeners=new Map;snapshot;slotSnapshot;ikSnapshot;blink=null;setBlink(t){let e=t?this.data.animations.get(t.animation):void 0;if(!t||!e){this.blink=null;return}let n={bones:new Set(t.bones.map(o=>this.data.bone(o).index)),slots:new Set(t.slots.map(o=>this.data.slot(o).index))};this.blink={source:e,filter:n,options:t,wait:this.nextBlink(t),at:-1};}blinkNow(){this.blink&&(this.blink.at=0);}blinking(){return (this.blink?.at??-1)>=0}setRandom(t){this.random=t;}random=Math.random;nextBlink(t){return t.every[0]+this.random()*(t.every[1]-t.every[0])}names(){return [...this.data.animations.keys()]}has(t){return this.data.animations.has(t)}play(t,e={}){let n=this.data.animations.get(t);if(!n)return false;let o=e.mix??this.defaultMix;return this.previous=this.track&&o>0?this.track:null,this.mixTime=0,this.mixDuration=this.previous?o:0,this.track={animation:n,time:Math.max(0,e.from??0),speed:e.speed??1,loop:e.loop??true,done:false},true}current(){return this.track?.animation.name??null}time(){return this.track?this.local(this.track):0}duration(){return this.track?.animation.duration??0}finished(){return this.track?.done??false}setSpeed(t){this.track&&(this.track.speed=t);}on(t,e){let n=this.listeners.get(t)??new Set;return n.add(e),this.listeners.set(t,n),()=>n.delete(e)}update(t){let e=[],n=this.track;if(n&&!n.done){let o=n.time;n.time+=Math.max(0,t)*n.speed,this.collect(n,o,n.time,e),!n.loop&&n.time>=n.animation.duration&&(n.time=n.animation.duration,n.done=true,e.push({name:"end",animation:n.animation.name}));}if(this.previous){let o=this.previous;o.time+=Math.max(0,t)*o.speed,this.mixTime+=Math.max(0,t),this.mixTime>=this.mixDuration&&(this.previous=null);}this.advanceBlink(Math.max(0,t)),this.pose();for(let o of e){for(let r of this.listeners.get(o.name)??[])r(o);for(let r of this.listeners.get("*")??[])r(o);}}pose(){let t=this.skeleton,e=this.previous;e&&this.mixDuration>0&&(t.setupPose(),e.animation.apply(t,this.local(e)),this.save()),t.setupPose(),this.track&&this.track.animation.apply(t,this.local(this.track)),e&&this.mixDuration>0&&this.blendFromSaved(Math.min(1,this.mixTime/this.mixDuration));let n=this.blink;n&&n.at>=0&&n.source.applyOnly(t,n.options.from+n.at,n.filter),t.resolveAttachments();}advanceBlink(t){let e=this.blink;if(e){if(this.track?.animation.touches(e.filter)){e.at=-1;return}if(e.at>=0){e.at+=t,e.at>=e.options.to-e.options.from&&(e.at=-1,e.wait=this.nextBlink(e.options));return}e.wait-=t,e.wait<=0&&(e.at=0);}}local(t){let e=t.animation.duration;return e<=0?0:t.loop?t.time%e:Math.min(t.time,e)}collect(t,e,n,o){let r=t.animation.duration;if(r<=0||n<=e)return;let a=Math.floor(e/r),i=t.loop?Math.floor(n/r):0;for(let p=a;p<=i;p++)for(let l of t.animation.events){let c=p*r+l.time;c>=e&&(c<n||!t.loop&&c<=n)&&o.push({name:l.name,animation:t.animation.name});}}save(){let t=this.skeleton;t.bones.forEach((e,n)=>{let o=e.pose;this.snapshot.set([o.x,o.y,o.rotation,o.scaleX,o.scaleY],n*5);}),t.slots.forEach((e,n)=>this.slotSnapshot.set([e.color.r,e.color.g,e.color.b,e.color.a],n*4)),t.constraints.forEach((e,n)=>{e instanceof I&&(this.ikSnapshot[n]=e.mix);});}blendFromSaved(t){let e=this.skeleton,n=(o,r)=>o+(r-o)*t;e.bones.forEach((o,r)=>{let a=this.snapshot,i=o.pose,p=r*5;i.x=n(a[p],i.x),i.y=n(a[p+1],i.y);let l=i.rotation-a[p+2];l-=Math.round(l/360)*360,i.rotation=a[p+2]+l*t,i.scaleX=n(a[p+3],i.scaleX),i.scaleY=n(a[p+4],i.scaleY);}),e.slots.forEach((o,r)=>{let a=this.slotSnapshot;o.color.r=n(a[r*4],o.color.r),o.color.g=n(a[r*4+1],o.color.g),o.color.b=n(a[r*4+2],o.color.b),o.color.a=n(a[r*4+3],o.color.a);}),e.constraints.forEach((o,r)=>{o instanceof I&&(o.mix=n(this.ikSnapshot[r],o.mix));});}};var Et=Math.PI/180,jt=new Float32Array([0,1,0,0,1,0,1,1]),Gt=new Uint16Array([0,1,2,2,3,0]),Bt=new WeakMap;function Vt(s){let t=Bt.get(s);if(t)return t;let e=-s.width/2*s.scaleX,n=-s.height/2*s.scaleY,o=s.width/2*s.scaleX,r=s.height/2*s.scaleY,a=Math.cos(s.rotation*Et),i=Math.sin(s.rotation*Et),p=(l,c)=>[l*a-c*i+s.x,l*i+c*a+s.y];return t=Float32Array.from([...p(e,n),...p(e,r),...p(o,r),...p(o,n)]),Bt.set(s,t),t}function Ct(s,t,e,n){if(e.type==="region"){let o=n&&n.length===8?n:new Float32Array(8),r=Vt(e),a=t.bone.applied;for(let i=0;i<8;i+=2){let p=r[i],l=r[i+1];o[i]=p*a.a+l*a.b+a.worldX,o[i+1]=p*a.c+l*a.d+a.worldY;}return {positions:o,uvs:jt,triangles:Gt}}return Ut(s,t,e,n)}function Ut(s,t,e,n){let o=e.vertexCount*2,r=n&&n.length===o?n:new Float32Array(o),a=e.vertices;if(e.weighted){let i=0;for(let p=0;p<o;p+=2){let l=a[i++],c=0,d=0;for(let h=0;h<l;h++,i+=4){let u=s.bones[a[i]].applied,m=a[i+1],f=a[i+2],b=a[i+3];c+=(m*u.a+f*u.b+u.worldX)*b,d+=(m*u.c+f*u.d+u.worldY)*b;}r[p]=c,r[p+1]=d;}}else {let i=t.bone.applied;for(let p=0;p<o;p+=2){let l=a[p],c=a[p+1];r[p]=l*i.a+c*i.b+i.worldX,r[p+1]=l*i.c+c*i.d+i.worldY;}}return {positions:r,uvs:e.uvs,triangles:e.triangles}}var _t=1;function De(...s){let t={v:1,parts:{},colors:{}};for(let e of s)e&&(Object.assign(t.parts,e.parts),Object.assign(t.colors,e.colors));return t}function Xe(s){if(!s||typeof s!="object")return null;let t=s;if(t.v!==1)return null;let e={},n={};if(t.parts&&typeof t.parts=="object")for(let[o,r]of Object.entries(t.parts))(r===null||typeof r=="string")&&(e[o]=r);if(t.colors&&typeof t.colors=="object")for(let[o,r]of Object.entries(t.colors))typeof r=="string"&&/^#[0-9a-f]{6}$/i.test(r)&&(n[o]=r);return {v:1,parts:e,colors:n}}var Ot=class{constructor(t,e=()=>true){this.rig=t;this.drawable=e;let n=(o,r)=>t.colorTargets.find(a=>(a.into??"tint")===r&&a.slotPrefixes.some(i=>o.startsWith(i)))?.id??null;this.slotTarget=t.data.slots.map(o=>n(o.name,"tint")),this.slotArt=t.data.slots.map(o=>n(o.name,"art")),this.rebuildLists(),this.init();}rig;drawable;chosen=new Map;hidden=new Map;colors=new Map;lists=new Map;listeners=new Set;slotTarget;slotArt;face=null;emotionFace=null;speech="rest";setDrawable(t){let e=new Set(this.rig.partTypes.filter(n=>!this.count(n.id)).map(n=>n.id));this.drawable=t,this.rebuildLists();for(let n of this.rig.partTypes){if(n.auto)continue;let o=this.chosen.get(n.id);(o&&!this.lists.get(n.id).includes(o)||!o&&e.has(n.id))&&this.chosen.set(n.id,this.first(n));}this.emit({kind:"part",type:"*",skin:null});}on(t){return this.listeners.add(t),()=>this.listeners.delete(t)}emit(t){for(let e of [...this.listeners])e(t);}typeDef(t){return this.rig.partTypes.find(e=>e.id===t)}list(t){return this.lists.get(t)??[]}count(t){return this.list(t).length}part(t){return this.chosen.get(t)??null}index(t){let e=this.part(t);return e?this.list(t).indexOf(e):-1}isHidden(t){return this.hidden.get(t)??false}isWorn(t){return this.part(t)!==null&&!this.isHidden(t)}color(t){return this.colors.get(t)??null}wornSkins(){let t=new Map;for(let l of this.rig.partTypes)t.set(l.id,!l.auto&&this.isWorn(l.id)?this.part(l.id):null);let e={worn:l=>t.get(l)??null,setWorn:(l,c)=>t.set(l,c),exists:l=>this.rig.data.skins.has(l)&&this.drawable(l)};for(let l of this.rig.rules)l.apply(e);let n=this.rig.expressions,o=this.face??this.emotionFace,r=o?n?.faces[o]:void 0;for(let[l,c]of Object.entries(r??{}))t.get(l)&&e.exists(c)&&t.set(l,c);let a=this.speech!=="rest"?n?.speech:void 0,i=a?.visemes[this.speech];a&&i&&t.get(a.type)&&e.exists(i)&&t.set(a.type,i);let p=[];for(let l of this.rig.partTypes){let c=t.get(l.id);c&&p.push(c);}return p}slotColor(t){let e=this.slotTarget[t];return e?this.color(e):null}artColor(t){let e=this.slotArt[t];return e?this.color(e):null}expression(){return this.face}equip(t,e){let n=this.lists.get(t);if(!n)return;let o;if(e===null||e===-1)o=null;else if(typeof e=="number")o=n[Math.max(0,Math.min(n.length-1,e))]??null;else if(n.includes(e))o=e;else return;o===null&&!this.typeDef(t)?.canHide||(this.chosen.set(t,o),this.emit({kind:"part",type:t,skin:o}));}unequip(t){this.equip(t,null);}setHidden(t,e){this.typeDef(t)?.canHide&&(this.hidden.set(t,e),this.emit({kind:"hidden",type:t,hidden:e}));}next(t){let e=this.count(t);if(!e)return;let n=this.index(t);this.typeDef(t)?.canHide?this.equip(t,n>=e-1?-1:n+1):this.equip(t,(n+1)%e);}prev(t){let e=this.count(t);if(!e)return;let n=this.index(t);this.typeDef(t)?.canHide?this.equip(t,n<=-1?e-1:n-1):this.equip(t,(n-1+e)%e);}setColor(t,e){this.colors.set(t,e),this.emit({kind:"color",target:t,color:e});}setExpression(t){let e=t&&this.rig.expressions?.faces[t]?t:null;e!==this.face&&(this.face=e,this.emit({kind:"expression",name:e}));}setEmotion(t){let e=this.rig.expressions?.emotions?.[t]??null,n=e&&this.rig.expressions?.faces[e]?e:null;n!==this.emotionFace&&(this.emotionFace=n,this.emit({kind:"expression",name:this.face??n}));}setSpeech(t){t!==this.speech&&(this.speech=t,this.emit({kind:"speech",viseme:t}));}randomize(t=Math.random){for(let e of this.rig.partTypes){if(e.auto)continue;let n=this.count(e.id);n&&this.equip(e.id,e.canHide&&t()<.3?-1:Math.floor(t()*n));}}reset(){this.init();for(let t of this.rig.partTypes)this.emit({kind:"part",type:t.id,skin:this.part(t.id)});}toLook(){let t={};for(let n of this.rig.partTypes)n.auto||(t[n.id]=this.isWorn(n.id)?this.part(n.id):null);let e={};for(let[n,o]of this.colors)o&&(e[n]=o);return {v:1,parts:t,colors:e}}applyLook(t){for(let[e,n]of Object.entries(t.parts??{}))n===void 0||this.typeDef(e)?.auto||(this.equip(e,n),n!==null&&this.part(e)===n&&this.hidden.set(e,false));for(let[e,n]of Object.entries(t.colors??{}))n&&this.setColor(e,n);}rebuildLists(){for(let t of this.rig.partTypes)this.lists.set(t.id,this.rig.data.skinOrder.filter(e=>e.startsWith(t.skinPrefix)&&this.drawable(e)));}first(t){return this.lists.get(t.id)?.[0]??null}init(){this.chosen.clear(),this.hidden.clear(),this.colors.clear();for(let t of this.rig.partTypes)this.chosen.set(t.id,t.auto?null:this.first(t));}};var Lt=new WeakMap;function Le(s,t){let e=Lt.get(s);if(e)return e;e=new Map;let n=new ot(s);n.setupPose(),n.updateWorldTransform();let[o,r]=t.light;for(let a of s.skins.values())for(let[i,p]of a.attachments)for(let l of p.values()){if(e.has(l.path)||t.skip?.some(b=>l.path.startsWith(b)))continue;let c=Ct(n,n.slots[i],l,null),d=Zt(c.positions,c.uvs,l.width,l.height);if(!d)continue;let h=d.a*d.d-d.b*d.c;if(Math.abs(h)<1e-9)continue;let u=(d.d*o-d.b*r)/h,m=(-d.c*o+d.a*r)/h,f=Math.hypot(u,m)||1;e.set(l.path,{x:u/f,y:m/f});}return Lt.set(s,e),e}function Zt(s,t,e,n){let o=t.length/2;if(o<3)return null;let r=0,a=0,i=0,p=0;for(let y=0;y<o;y++)r+=t[y*2]*e,a+=t[y*2+1]*n,i+=s[y*2],p+=s[y*2+1];r/=o,a/=o,i/=o,p/=o;let l=0,c=0,d=0,h=0,u=0,m=0,f=0;for(let y=0;y<o;y++){let x=t[y*2]*e-r,g=t[y*2+1]*n-a,w=s[y*2]-i,M=s[y*2+1]-p;l+=x*x,c+=x*g,d+=g*g,h+=w*x,u+=w*g,m+=M*x,f+=M*g;}let b=l*d-c*c;return Math.abs(b)<1e-9?null:{a:(h*d-u*c)/b,b:(u*l-h*c)/b,c:(m*d-f*c)/b,d:(f*l-m*c)/b}}
|
|
2
|
+
export{De as A,Xe as B,Ot as C,Le as D,Tt as a,Qt as b,zt as c,Rt as d,Ft as e,te as f,ee as g,ne as h,oe as i,se as j,re as k,ie as l,le as m,ce as n,he as o,O as p,dt as q,ve as r,we as s,Se as t,nt as u,bt as v,ot as w,Xt as x,Ct as y,_t as z};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var g=["ru","kk","uk","be","ky","uz","tg"],d="idos:language",p="idos:language";function k(){try{let e=globalThis.localStorage?.getItem(d);if(e==="en"||e==="ru")return e}catch{}if(typeof navigator>"u")return "en";let t=(navigator.language||"").toLowerCase();return g.some(e=>t.startsWith(e))?"ru":"en"}var a=k();function L(){return a}function S(t){a=t;}typeof window<"u"&&window.addEventListener(p,t=>{let e=t.detail;(e==="en"||e==="ru")&&(a=e);});function u(t,e){let n=typeof t=="string"?t:t[a]??t.en;if(e)for(let[o,i]of Object.entries(e))n=n.split(`{${o}}`).join(String(i));return n}function h(t){let e=t.trim(),n=/```(?:json)?\s*([\s\S]*?)(?:```|$)/i.exec(e);n&&n[1]!==void 0&&(e=n[1]);let o=e.indexOf("{");if(o<0)return {ok:false,error:u({en:"the answer has no JSON object",ru:"\u0432 \u043E\u0442\u0432\u0435\u0442\u0435 \u043D\u0435\u0442 JSON-\u043E\u0431\u044A\u0435\u043A\u0442\u0430"}),truncated:false};let i=0,f=false,c=false,l=-1;for(let s=o;s<e.length;s++){let r=e[s];if(f){c?c=false:r==="\\"?c=true:r==='"'&&(f=false);continue}if(r==='"')f=true;else if(r==="{"||r==="[")i++;else if((r==="}"||r==="]")&&(i--,i===0)){l=s;break}}if(l<0)return {ok:false,error:u({en:"the JSON is cut off",ru:"JSON \u043E\u0431\u043E\u0440\u0432\u0430\u043D"}),truncated:true};try{return {ok:!0,value:JSON.parse(e.slice(o,l+1))}}catch{return {ok:false,error:u({en:"invalid JSON",ru:"\u043D\u0435\u0432\u0430\u043B\u0438\u0434\u043D\u044B\u0439 JSON"}),truncated:false}}}export{L as a,S as b,u as c,h as d};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import {s,D,c,w,y}from'./chunk-OF4BH3JZ.js';function Y(o,g,h=2){let b=s(o.data),y=o.shading?D(o.data,o.shading):new Map,p=new Map;return {image(n,t){let i=g.get(n),l=i?.paint?t??null:null,f=l?`${n}${l}`:n,m=p.get(f);if(m)return m;let c$1=b.get(n);return m=i&&c$1?new Promise(r=>{let e=new Image;e.onload=()=>r(e),e.onerror=()=>r(null),e.src=`data:image/svg+xml;charset=utf-8,${encodeURIComponent(c(i,c$1,h,{paint:l,light:y.get(n)??null}))}`;}):Promise.resolve(null),p.set(f,m),m}}}function J(o,g){let h=new Map,b=new w(o.data),y$1=(n,t,i)=>{let[l,f,m]=i.tint;if(!i.fill&&l===1&&f===1&&m===1)return t;let c=`${n}|${i.fill??`${l.toFixed(3)},${f.toFixed(3)},${m.toFixed(3)}`}`,r=h.get(c);if(r)return r;r=document.createElement("canvas"),r.width=t.width,r.height=t.height;let e=r.getContext("2d");return e.drawImage(t,0,0),e.globalCompositeOperation=i.fill?"source-in":"multiply",e.fillStyle=i.fill??`rgb(${l*255}, ${f*255}, ${m*255})`,e.fillRect(0,0,r.width,r.height),i.fill||(e.globalCompositeOperation="destination-in",e.drawImage(t,0,0)),h.set(c,r),r},p=(n,t,i,l,f,m)=>{let c=b;c.setSkins(n.flatMap(a=>o.data.skins.get(a)?[o.data.skins.get(a)]:[])),c.setupPose(),o.data.animations.get(m.animation)?.apply(c,m.time),c.resolveAttachments(),c.updateWorldTransform();let r=t?new Set(t):null,e=[];return c.slots.forEach((a,x)=>{let d=a.attachment;if(!d||r&&!r.has(a.data.name))return;let w=i?.(x)??null,M=w?O(w):[a.color.r,a.color.g,a.color.b],s=a.color.a*d.color.a;if(s<=0)return;let I=y(c,a,d,null);e.push({path:d.path,paint:l?.(x)??null,positions:Float32Array.from(I.positions),uvs:I.uvs,triangles:I.triangles,tint:[M[0]*d.color.r,M[1]*d.color.g,M[2]*d.color.b],alpha:s,fill:f});}),e};return {async draw(n,t){let i=t.pose??{animation:o.defaultAnimation,time:0},l=t.backdrop?p(t.backdrop.skins,t.backdrop.slots,void 0,void 0,t.backdrop.color,i):[],f=p(t.skins,t.slots,t.slotColor,t.artColor,null,i),m=[...l,...f],c=await Promise.all(m.map(s=>g.image(s.path,s.paint))),r=t.frame==="content"||!l.length?f:l,e=U(r.length?r:m),a=n.getContext("2d");if(a.setTransform(1,0,0,1,0,0),a.clearRect(0,0,n.width,n.height),!e)return;let x=(t.padding??.08)*Math.min(n.width,n.height),d=Math.min((n.width-x*2)/Math.max(1,e.w),(n.height-x*2)/Math.max(1,e.h)),w=n.width/2-(e.x+e.w/2)*d,M=n.height/2+(e.y+e.h/2)*d;m.forEach((s,I)=>{let H=c[I];if(!H)return;let E=y$1(s.paint?`${s.path}${s.paint}`:s.path,H,s);a.globalAlpha=s.alpha;let T=s.triangles,v=u=>w+s.positions[u*2]*d,A=u=>M-s.positions[u*2+1]*d,$=u=>s.uvs[u*2]*H.width,R=u=>s.uvs[u*2+1]*H.height;for(let u=0;u<T.length;u+=3){let k=T[u],C=T[u+1],P=T[u+2];B(a,E,v(k),A(k),v(C),A(C),v(P),A(P),$(k),R(k),$(C),R(C),$(P),R(P));}}),a.globalAlpha=1;}}}function U(o){let g=1/0,h=1/0,b=-1/0,y=-1/0;for(let p of o)for(let n=0;n<p.positions.length;n+=2)g=Math.min(g,p.positions[n]),b=Math.max(b,p.positions[n]),h=Math.min(h,p.positions[n+1]),y=Math.max(y,p.positions[n+1]);return g===1/0?null:{x:g,y:h,w:b-g,h:y-h}}function B(o,g,h,b,y,p,n,t,i,l,f,m,c,r){let e=f-i,a=m-l,x=c-i,d=r-l,w=e*d-x*a;if(Math.abs(w)<1e-9)return;let M=y-h,s=p-b,I=n-h,H=t-b,E=(M*d-I*a)/w,T=(s*d-H*a)/w,v=(I*e-M*x)/w,A=(H*e-s*x)/w,$=(h+y+n)/3,R=(b+p+t)/3,u=(k,C)=>{let P=Math.hypot(k-$,C-R)||1;return [k+(k-$)/P*.6,C+(C-R)/P*.6]};o.save(),o.beginPath(),o.moveTo(...u(h,b)),o.lineTo(...u(y,p)),o.lineTo(...u(n,t)),o.closePath(),o.clip(),o.transform(E,T,v,A,h-E*i-v*l,b-T*i-A*l),o.drawImage(g,0,0),o.restore();}function O(o){let g=parseInt(o.replace("#",""),16);return [(g>>16&255)/255,(g>>8&255)/255,(g&255)/255]}export{Y as a,J as b};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/** Эмоции. Шесть из стандарта ассетов (нейтрально, радость, грусть, злость, удивление, страх) + устал и больно. */
|
|
2
|
+
declare const EMOTIONS: readonly ["neutral", "happy", "sad", "angry", "surprised", "scared", "tired", "hurt"];
|
|
3
|
+
type Emotion = (typeof EMOTIONS)[number];
|
|
4
|
+
declare function isEmotion(v: unknown): v is Emotion;
|
|
5
|
+
/**
|
|
6
|
+
* Фонемы рта (визимы) — шесть форм, которых хватает мультяшной речи: покой, «А», «Э/И», «О/У»,
|
|
7
|
+
* сомкнутые губы (М, Б, П) и губа к зубам (Ф, В).
|
|
8
|
+
*/
|
|
9
|
+
declare const VISEMES: readonly ["rest", "A", "E", "O", "MBP", "FV"];
|
|
10
|
+
type Viseme = (typeof VISEMES)[number];
|
|
11
|
+
declare function isViseme(v: unknown): v is Viseme;
|
|
12
|
+
/** Позы, которые умеет любой гуманоид контракта (у 2D — анимации рига, у вокселей — жесты, у GLB — клипы). */
|
|
13
|
+
declare const ACTOR_POSES: readonly ["idle", "talk", "walk", "run", "surprised", "point", "sit", "wave", "jump", "fall", "dance"];
|
|
14
|
+
type ActorPose = (typeof ACTOR_POSES)[number];
|
|
15
|
+
/** Сокеты для пропсов: правая и левая рука, головной убор. */
|
|
16
|
+
declare const ACTOR_SOCKETS: readonly ["handR", "handL", "head"];
|
|
17
|
+
type ActorSocket = (typeof ACTOR_SOCKETS)[number];
|
|
18
|
+
/** Вид актёра (вид ассета каталога). */
|
|
19
|
+
type ActorKind = "voxel" | "rig2d" | "gltf" | "cutout";
|
|
20
|
+
/** Стилевые семейства: ассеты разных семейств по умолчанию не смешиваются в одном ролике. */
|
|
21
|
+
declare const STYLE_FAMILIES: readonly ["voxel-warm", "flat-cartoon", "chibi-2d", "low-poly-3d", "photo-sticker"];
|
|
22
|
+
type StyleFamily = (typeof STYLE_FAMILIES)[number];
|
|
23
|
+
|
|
24
|
+
export { type ActorSocket as A, type Emotion as E, STYLE_FAMILIES as S, type Viseme as V, ACTOR_POSES as a, ACTOR_SOCKETS as b, type ActorKind as c, type ActorPose as d, EMOTIONS as e, type StyleFamily as f, VISEMES as g, isViseme as h, isEmotion as i };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/** Эмоции. Шесть из стандарта ассетов (нейтрально, радость, грусть, злость, удивление, страх) + устал и больно. */
|
|
2
|
+
declare const EMOTIONS: readonly ["neutral", "happy", "sad", "angry", "surprised", "scared", "tired", "hurt"];
|
|
3
|
+
type Emotion = (typeof EMOTIONS)[number];
|
|
4
|
+
declare function isEmotion(v: unknown): v is Emotion;
|
|
5
|
+
/**
|
|
6
|
+
* Фонемы рта (визимы) — шесть форм, которых хватает мультяшной речи: покой, «А», «Э/И», «О/У»,
|
|
7
|
+
* сомкнутые губы (М, Б, П) и губа к зубам (Ф, В).
|
|
8
|
+
*/
|
|
9
|
+
declare const VISEMES: readonly ["rest", "A", "E", "O", "MBP", "FV"];
|
|
10
|
+
type Viseme = (typeof VISEMES)[number];
|
|
11
|
+
declare function isViseme(v: unknown): v is Viseme;
|
|
12
|
+
/** Позы, которые умеет любой гуманоид контракта (у 2D — анимации рига, у вокселей — жесты, у GLB — клипы). */
|
|
13
|
+
declare const ACTOR_POSES: readonly ["idle", "talk", "walk", "run", "surprised", "point", "sit", "wave", "jump", "fall", "dance"];
|
|
14
|
+
type ActorPose = (typeof ACTOR_POSES)[number];
|
|
15
|
+
/** Сокеты для пропсов: правая и левая рука, головной убор. */
|
|
16
|
+
declare const ACTOR_SOCKETS: readonly ["handR", "handL", "head"];
|
|
17
|
+
type ActorSocket = (typeof ACTOR_SOCKETS)[number];
|
|
18
|
+
/** Вид актёра (вид ассета каталога). */
|
|
19
|
+
type ActorKind = "voxel" | "rig2d" | "gltf" | "cutout";
|
|
20
|
+
/** Стилевые семейства: ассеты разных семейств по умолчанию не смешиваются в одном ролике. */
|
|
21
|
+
declare const STYLE_FAMILIES: readonly ["voxel-warm", "flat-cartoon", "chibi-2d", "low-poly-3d", "photo-sticker"];
|
|
22
|
+
type StyleFamily = (typeof STYLE_FAMILIES)[number];
|
|
23
|
+
|
|
24
|
+
export { type ActorSocket as A, type Emotion as E, STYLE_FAMILIES as S, type Viseme as V, ACTOR_POSES as a, ACTOR_SOCKETS as b, type ActorKind as c, type ActorPose as d, EMOTIONS as e, type StyleFamily as f, VISEMES as g, isViseme as h, isEmotion as i };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
'use strict';var d=require('three'),GLTFLoader_js=require('three/examples/jsm/loaders/GLTFLoader.js'),KTX2Loader_js=require('three/examples/jsm/loaders/KTX2Loader.js'),meshopt_decoder_module_js=require('three/examples/jsm/libs/meshopt_decoder.module.js'),SkeletonUtils_js=require('three/examples/jsm/utils/SkeletonUtils.js');function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var d__namespace=/*#__PURE__*/_interopNamespace(d);var P="humanoid-v1",$=["hips","spine","chest","upperChest","neck","head","leftShoulder","leftUpperArm","leftLowerArm","leftHand","rightShoulder","rightUpperArm","rightLowerArm","rightHand","leftUpperLeg","leftLowerLeg","leftFoot","leftToes","rightUpperLeg","rightLowerLeg","rightFoot","rightToes"],O=["hips","spine","chest","neck","head","leftUpperArm","leftLowerArm","leftHand","rightUpperArm","rightLowerArm","rightHand","leftUpperLeg","leftLowerLeg","leftFoot","rightUpperLeg","rightLowerLeg","rightFoot"],U={hips:"hips",pelvis:"hips",spine:"spine",spine1:"chest",chest:"chest",spine2:"upperChest",upperchest:"upperChest",neck:"neck",head:"head",leftshoulder:"leftShoulder",shoulderl:"leftShoulder",leftarm:"leftUpperArm",leftupperarm:"leftUpperArm",upperarml:"leftUpperArm",leftforearm:"leftLowerArm",leftlowerarm:"leftLowerArm",forearml:"leftLowerArm",lefthand:"leftHand",handl:"leftHand",rightshoulder:"rightShoulder",shoulderr:"rightShoulder",rightarm:"rightUpperArm",rightupperarm:"rightUpperArm",upperarmr:"rightUpperArm",rightforearm:"rightLowerArm",rightlowerarm:"rightLowerArm",forearmr:"rightLowerArm",righthand:"rightHand",handr:"rightHand",leftupleg:"leftUpperLeg",leftupperleg:"leftUpperLeg",thighl:"leftUpperLeg",leftleg:"leftLowerLeg",leftlowerleg:"leftLowerLeg",shinl:"leftLowerLeg",leftfoot:"leftFoot",footl:"leftFoot",lefttoebase:"leftToes",lefttoes:"leftToes",toel:"leftToes",rightupleg:"rightUpperLeg",rightupperleg:"rightUpperLeg",thighr:"rightUpperLeg",rightleg:"rightLowerLeg",rightlowerleg:"rightLowerLeg",shinr:"rightLowerLeg",rightfoot:"rightFoot",footr:"rightFoot",righttoebase:"rightToes",righttoes:"rightToes",toer:"rightToes"};function x(o){let e=o.replace(/^mixamorig\d*[:_]?/i,"").replace(/^(DEF|ORG|MCH)[-_.]/i,"").replace(/[\s._:-]/g,"").toLowerCase();return U[e]??null}var v={A:["v_A","aa","vrc.v_aa","mouth_a"],E:["v_E","ee","ih","vrc.v_e","vrc.v_ih","mouth_e"],O:["v_O","oh","ou","vrc.v_oh","vrc.v_ou","mouth_o"],MBP:["v_MBP","vrc.v_pp","mouth_m"],FV:["v_FV","vrc.v_ff","mouth_f"]},M={happy:["e_happy","happy","joy"],sad:["e_sad","sad","sorrow"],angry:["e_angry","angry"],surprised:["e_surprised","surprised"],scared:["e_scared","scared","fear"],tired:["e_tired","tired"],hurt:["e_hurt","hurt","pain"]},y=["blink","e_blink","eyes_closed"],B={handR:["socket_handR","rightHand"],handL:["socket_handL","leftHand"],head:["socket_head","head"]},g={maxTriangles:15e3,maxMaterials:2,maxTextureSize:2048,maxFileBytes:6*1024*1024};function F(o){let e=[],t=(a,u)=>e.push({level:"error",code:a,message:u}),r=(a,u)=>e.push({level:"warning",code:a,message:u}),n={};for(let a of o.bones){let u=x(a);u&&!n[u]&&(n[u]=a);}let i=O.filter(a=>!n[a]);o.bones.length===0?t("NO_SKELETON","the model has no skeleton (skin)"):i.length>0&&t("BONES_MISSING",`humanoid-v1 bones missing: ${i.join(", ")}`);let h=new Set(o.morphTargets.map(a=>a.toLowerCase())),s=a=>a.some(u=>h.has(u.toLowerCase())),l=Object.entries(v).filter(([,a])=>s(a)).map(([a])=>a),p=Object.entries(M).filter(([,a])=>s(a)).map(([a])=>a),m=s(y);l.length===0?r("NO_VISEMES","no mouth shape keys (v_A, v_E, v_O, v_MBP, v_FV): the mouth will not move"):l.length<5&&r("VISEMES_PARTIAL",`mouth shape keys: ${l.join(", ")} of A, E, O, MBP, FV`),p.length<6&&r("EMOTIONS_PARTIAL",`emotion shape keys: ${p.join(", ")||"none"} (the standard asks for happy, sad, angry, surprised, scared + neutral)`),m||r("NO_BLINK","no blink shape key"),o.triangles>g.maxTriangles&&t("TRIANGLES",`${o.triangles} triangles, budget ${g.maxTriangles}`),o.materials>g.maxMaterials&&t("MATERIALS",`${o.materials} materials, budget ${g.maxMaterials}`);let f=o.textureSizes.filter(a=>a>g.maxTextureSize);f.length>0&&t("TEXTURES",`textures over ${g.maxTextureSize}px: ${f.join(", ")}`),o.fileBytes>g.maxFileBytes&&t("FILE_SIZE",`${(o.fileBytes/1048576).toFixed(1)} MB, budget ${g.maxFileBytes/1048576} MB`);let[c,E,L]=o.bounds.min,[b,G,C]=o.bounds.max,T=G-E;return (T<.3||T>4)&&t("SCALE",`height ${T.toFixed(2)} m \u2014 units must be metres (a person is ~1.7 m)`),Math.abs(E)>.05*Math.max(T,1)&&r("PIVOT",`feet at y=${E.toFixed(2)}: the pivot must be between the feet (y = 0)`),(Math.abs((c+b)/2)>.25||Math.abs((L+C)/2)>.25)&&r("CENTER","the model is off the origin: the pivot must be between the feet"),b-c>T*1.5&&T>0&&r("AXES","wider than tall \u2014 is +Y up?"),o.animations>0&&r("EMBEDDED_CLIPS",`${o.animations} clips inside the character: clips belong to the shared library`),{ok:!e.some(a=>a.level==="error"),issues:e,boneMap:n,visemes:l,emotions:p,blink:m}}function I(o){let e=o>>>0;return function(){e|=0,e=e+1831565813|0;let t=Math.imul(e^e>>>15,1|e);return t=t+Math.imul(t^t>>>7,61|t)^t,((t^t>>>14)>>>0)/4294967296}}var w=null;function R(o){let e=new GLTFLoader_js.GLTFLoader;return e.setMeshoptDecoder(meshopt_decoder_module_js.MeshoptDecoder),o.renderer&&o.ktx2TranscoderPath&&(w||(w=new KTX2Loader_js.KTX2Loader().setTranscoderPath(o.ktx2TranscoderPath),w.detectSupport(o.renderer)),e.setKTX2Loader(w)),e}var _=class o{constructor(e,t){this.gltf=e;this.report=F(t);}gltf;report;static async load(e,t={}){let r=await R(t).loadAsync(e);return new o(r,k(r,t.fileBytes??0))}static async parse(e,t={}){let r=await R(t).parseAsync(e,"");return new o(r,k(r,e.byteLength))}instance(e=1){return new S(SkeletonUtils_js.clone(this.gltf.scene),this.report,e)}};function k(o,e){let t=new Set,r=new Set,n=new Set,i=[],h=0;o.scene.updateMatrixWorld(true);let s=new d__namespace.Box3().setFromObject(o.scene);return o.scene.traverse(l=>{let p=l;if(l.isSkinnedMesh)for(let c of l.skeleton.bones)t.add(c.name);if(!p.isMesh)return;let m=p.geometry;h+=(m.index?m.index.count:m.attributes.position.count)/3;for(let c of Object.keys(p.morphTargetDictionary??{}))r.add(c);let f=Array.isArray(p.material)?p.material:[p.material];for(let c of f){n.add(c.uuid);for(let E of Object.values(c)){let L=E,b=L?.isTexture?L.image:null;b?.width&&b.height&&i.push(Math.max(b.width,b.height));}}}),{bones:[...t],morphTargets:[...r],triangles:Math.round(h),materials:n.size,textureSizes:i,fileBytes:e,bounds:{min:[s.min.x,s.min.y,s.min.z],max:[s.max.x,s.max.y,s.max.z]},animations:o.animations.length}}var S=class{constructor(e,t,r=1){this.report=t;this.rnd=I(r),this.blinkIn=2+this.rnd()*3,this.root=new d__namespace.Group,this.root.add(e),this.mixer=new d__namespace.AnimationMixer(e);let n=new Map;e.traverse(i=>{n.set(i.name,i);let h=x(i.name);h&&!this.bones[h]&&i.isBone&&(this.bones[h]=i);let s=i;if(!s.isMesh||!s.morphTargetDictionary)return;let l=j(s.morphTargetDictionary),p=m=>m.flatMap(f=>{let c=l.get(f.toLowerCase());return c===void 0?[]:[{mesh:s,index:c}]});for(let[m,f]of Object.entries(v))this.visemeMorphs.set(m,[...this.visemeMorphs.get(m)??[],...p(f)]);for(let[m,f]of Object.entries(M))this.emotionMorphs.set(m,[...this.emotionMorphs.get(m)??[],...p(f)]);this.blinkMorphs.push(...p(y));});for(let[i,h]of Object.entries(B)){let s=h.map(l=>n.get(l)??this.bones[l]).find(Boolean);s&&this.sockets.set(i,s);}}report;root;mixer;bones={};visemeMorphs=new Map;emotionMorphs=new Map;blinkMorphs=[];sockets=new Map;current=null;viseme="rest";visemeWeights=new Map;emotion="neutral";emotionWeight=0;blinkIn;blinkT=-1;rnd;play(e,t={}){let r=this.mixer.clipAction(e);r.reset(),r.setLoop(t.loop===false?d__namespace.LoopOnce:d__namespace.LoopRepeat,1/0),r.clampWhenFinished=t.loop===false,r.timeScale=t.timeScale??1;let n=t.fade??.2;this.current&&this.current!==r&&r.crossFadeFrom(this.current,n,false),r.play(),this.current=r;}setEmotion(e){this.emotion=e;}setViseme(e){this.viseme=e;}attach(e,t){let r=this.sockets.get(e);return r?(r.add(t),true):false}update(e){this.mixer.update(e);let t=1-Math.exp(-e/.06);for(let[n,i]of this.visemeMorphs){let h=n===this.viseme?1:0,s=(this.visemeWeights.get(n)??0)+(h-(this.visemeWeights.get(n)??0))*t;this.visemeWeights.set(n,s);for(let l of i)A(l,s);}let r=1-Math.exp(-e/.15);this.emotionWeight+=((this.emotion==="neutral"?0:1)-this.emotionWeight)*r;for(let[n,i]of this.emotionMorphs)for(let h of i)A(h,n===this.emotion?this.emotionWeight:0);if(this.blinkT>=0){this.blinkT+=e;let n=this.blinkT/.15,i=n<.5?n*2:Math.max(0,2-n*2);for(let h of this.blinkMorphs)A(h,i);n>=1&&(this.blinkT=-1,this.blinkIn=2+this.rnd()*3);}else (this.blinkIn-=e)<=0&&(this.blinkT=0);}dispose(){this.mixer.stopAllAction(),this.root.removeFromParent(),this.root.traverse(e=>{let t=e;t.isMesh&&t.geometry.dispose();});}};function A(o,e){let t=o.mesh.morphTargetInfluences;t&&(t[o.index]=e);}function j(o){return new Map(Object.entries(o).map(([e,t])=>[e.toLowerCase(),t]))}var H=class{clips=new Map;perTarget=new WeakMap;add(e,t){this.clips.set(e,t);}async load(e,t,r={}){let i=(await R(r).loadAsync(t)).animations[0];if(!i)throw new Error(`${t}: no animation`);this.add(e,i);}has(e){return this.clips.has(e)}names(){return [...this.clips.keys()]}clipFor(e,t){let r=this.perTarget.get(e);r||this.perTarget.set(e,r=new Map);let n=r.get(t);if(n)return n;let i=this.clips.get(t);if(!i)return null;let h=[];for(let l of i.tracks){let p=l.name.lastIndexOf("."),m=x(l.name.slice(0,p)),f=l.name.slice(p+1);if(!m)continue;let c=e.bones[m];if(!c||f==="position"&&m!=="hips"||f==="scale")continue;let E=l.clone();E.name=`${c.name}.${f}`,h.push(E);}let s=new d__namespace.AnimationClip(`${t}`,i.duration,h);return r.set(t,s),s}};exports.BLINK_KEYS=y;exports.EMOTION_KEYS=M;exports.GLTF_BUDGET=g;exports.GltfCharacter=S;exports.GltfCharacterAsset=_;exports.GltfClipLibrary=H;exports.HUMANOID_BONES=$;exports.HUMANOID_V1=P;exports.REQUIRED_BONES=O;exports.SOCKET_NODES=B;exports.VISEME_KEYS=v;exports.canonicalBone=x;exports.gltfFacts=k;exports.validateGltfCharacter=F;
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import { GLTF } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
|
3
|
+
import { E as Emotion, V as Viseme, A as ActorSocket } from '../contract-DhZuKNIf.cjs';
|
|
4
|
+
|
|
5
|
+
declare const HUMANOID_V1 = "humanoid-v1";
|
|
6
|
+
/** Кости эталона. Обязательные — без них клипы библиотеки не встанут. */
|
|
7
|
+
declare const HUMANOID_BONES: readonly ["hips", "spine", "chest", "upperChest", "neck", "head", "leftShoulder", "leftUpperArm", "leftLowerArm", "leftHand", "rightShoulder", "rightUpperArm", "rightLowerArm", "rightHand", "leftUpperLeg", "leftLowerLeg", "leftFoot", "leftToes", "rightUpperLeg", "rightLowerLeg", "rightFoot", "rightToes"];
|
|
8
|
+
type HumanoidBone = (typeof HUMANOID_BONES)[number];
|
|
9
|
+
declare const REQUIRED_BONES: readonly HumanoidBone[];
|
|
10
|
+
/** Имя кости в файле → кость эталона (или null — не гуманоидная кость: хвост, волосы, сокет). */
|
|
11
|
+
declare function canonicalBone(name: string): HumanoidBone | null;
|
|
12
|
+
/** Shape keys лица: фонемы рта, эмоции, моргание (имена в файле). VRM-пресеты — синонимы. */
|
|
13
|
+
declare const VISEME_KEYS: {
|
|
14
|
+
readonly A: readonly ["v_A", "aa", "vrc.v_aa", "mouth_a"];
|
|
15
|
+
readonly E: readonly ["v_E", "ee", "ih", "vrc.v_e", "vrc.v_ih", "mouth_e"];
|
|
16
|
+
readonly O: readonly ["v_O", "oh", "ou", "vrc.v_oh", "vrc.v_ou", "mouth_o"];
|
|
17
|
+
readonly MBP: readonly ["v_MBP", "vrc.v_pp", "mouth_m"];
|
|
18
|
+
readonly FV: readonly ["v_FV", "vrc.v_ff", "mouth_f"];
|
|
19
|
+
};
|
|
20
|
+
declare const EMOTION_KEYS: {
|
|
21
|
+
readonly happy: readonly ["e_happy", "happy", "joy"];
|
|
22
|
+
readonly sad: readonly ["e_sad", "sad", "sorrow"];
|
|
23
|
+
readonly angry: readonly ["e_angry", "angry"];
|
|
24
|
+
readonly surprised: readonly ["e_surprised", "surprised"];
|
|
25
|
+
readonly scared: readonly ["e_scared", "scared", "fear"];
|
|
26
|
+
readonly tired: readonly ["e_tired", "tired"];
|
|
27
|
+
readonly hurt: readonly ["e_hurt", "hurt", "pain"];
|
|
28
|
+
};
|
|
29
|
+
declare const BLINK_KEYS: readonly ["blink", "e_blink", "eyes_closed"];
|
|
30
|
+
/** Сокеты пропсов: своя пустышка в файле или кость эталона. */
|
|
31
|
+
declare const SOCKET_NODES: {
|
|
32
|
+
readonly handR: readonly ["socket_handR", "rightHand"];
|
|
33
|
+
readonly handL: readonly ["socket_handL", "leftHand"];
|
|
34
|
+
readonly head: readonly ["socket_head", "head"];
|
|
35
|
+
};
|
|
36
|
+
/** Стартовые бюджеты контракта (проверить на телефонах — значения в стандарте ассетов стартовые). */
|
|
37
|
+
declare const GLTF_BUDGET: {
|
|
38
|
+
readonly maxTriangles: 15000;
|
|
39
|
+
readonly maxMaterials: 2;
|
|
40
|
+
readonly maxTextureSize: 2048;
|
|
41
|
+
readonly maxFileBytes: number;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/** Что известно о файле. */
|
|
45
|
+
interface GltfFacts {
|
|
46
|
+
/** Имена узлов-костей скинов. */
|
|
47
|
+
bones: readonly string[];
|
|
48
|
+
/** Имена shape keys (morph targets) всех мешей. */
|
|
49
|
+
morphTargets: readonly string[];
|
|
50
|
+
triangles: number;
|
|
51
|
+
materials: number;
|
|
52
|
+
/** Наибольшая сторона каждой текстуры, px. */
|
|
53
|
+
textureSizes: readonly number[];
|
|
54
|
+
fileBytes: number;
|
|
55
|
+
/** Габарит в метрах: минимум и максимум по осям. */
|
|
56
|
+
bounds: {
|
|
57
|
+
min: [number, number, number];
|
|
58
|
+
max: [number, number, number];
|
|
59
|
+
};
|
|
60
|
+
/** Встроенные клипы — по контракту клипы живут в общей библиотеке, не в персонаже. */
|
|
61
|
+
animations: number;
|
|
62
|
+
}
|
|
63
|
+
type IssueLevel = "error" | "warning";
|
|
64
|
+
interface ValidationIssue {
|
|
65
|
+
level: IssueLevel;
|
|
66
|
+
code: string;
|
|
67
|
+
message: string;
|
|
68
|
+
}
|
|
69
|
+
interface GltfReport {
|
|
70
|
+
ok: boolean;
|
|
71
|
+
issues: ValidationIssue[];
|
|
72
|
+
/** Найденные кости эталона: имя в файле → кость. */
|
|
73
|
+
boneMap: Partial<Record<HumanoidBone, string>>;
|
|
74
|
+
visemes: string[];
|
|
75
|
+
emotions: string[];
|
|
76
|
+
blink: boolean;
|
|
77
|
+
}
|
|
78
|
+
declare function validateGltfCharacter(f: GltfFacts): GltfReport;
|
|
79
|
+
|
|
80
|
+
interface GltfLoadOptions {
|
|
81
|
+
/** Рендерер — KTX2 узнаёт по нему, какие сжатые форматы есть у видеокарты. */
|
|
82
|
+
renderer?: THREE.WebGLRenderer;
|
|
83
|
+
/** Папка транскодера Basis (файлы three/examples/jsm/libs/basis) на нашем CDN. */
|
|
84
|
+
ktx2TranscoderPath?: string;
|
|
85
|
+
/** Размер файла, если известен (для отчёта контракта). */
|
|
86
|
+
fileBytes?: number;
|
|
87
|
+
}
|
|
88
|
+
/** Загруженный файл персонажа: из него делаются экземпляры (`instance()`), файл грузится один раз. */
|
|
89
|
+
declare class GltfCharacterAsset {
|
|
90
|
+
private readonly gltf;
|
|
91
|
+
readonly report: GltfReport;
|
|
92
|
+
private constructor();
|
|
93
|
+
static load(url: string, opts?: GltfLoadOptions): Promise<GltfCharacterAsset>;
|
|
94
|
+
static parse(data: ArrayBuffer, opts?: GltfLoadOptions): Promise<GltfCharacterAsset>;
|
|
95
|
+
/** Новый экземпляр со своим скелетом (два одинаковых героя в кадре не делят позу). */
|
|
96
|
+
instance(seed?: number): GltfCharacter;
|
|
97
|
+
}
|
|
98
|
+
/** Факты файла для проверки контракта. */
|
|
99
|
+
declare function gltfFacts(gltf: GLTF, fileBytes: number): GltfFacts;
|
|
100
|
+
/** Экземпляр персонажа в сцене. */
|
|
101
|
+
declare class GltfCharacter {
|
|
102
|
+
readonly report: GltfReport;
|
|
103
|
+
readonly root: THREE.Group;
|
|
104
|
+
readonly mixer: THREE.AnimationMixer;
|
|
105
|
+
/** Кость эталона → узел этого экземпляра. */
|
|
106
|
+
readonly bones: Partial<Record<HumanoidBone, THREE.Object3D>>;
|
|
107
|
+
private readonly visemeMorphs;
|
|
108
|
+
private readonly emotionMorphs;
|
|
109
|
+
private readonly blinkMorphs;
|
|
110
|
+
private readonly sockets;
|
|
111
|
+
private current;
|
|
112
|
+
private viseme;
|
|
113
|
+
private visemeWeights;
|
|
114
|
+
private emotion;
|
|
115
|
+
private emotionWeight;
|
|
116
|
+
private blinkIn;
|
|
117
|
+
private blinkT;
|
|
118
|
+
private readonly rnd;
|
|
119
|
+
constructor(scene: THREE.Object3D, report: GltfReport, seed?: number);
|
|
120
|
+
/** Сыграть клип библиотеки (уже перенацеленный на этот экземпляр — `GltfClipLibrary.clipFor`). */
|
|
121
|
+
play(clip: THREE.AnimationClip, opts?: {
|
|
122
|
+
fade?: number;
|
|
123
|
+
loop?: boolean;
|
|
124
|
+
timeScale?: number;
|
|
125
|
+
}): void;
|
|
126
|
+
setEmotion(e: Emotion): void;
|
|
127
|
+
setViseme(v: Viseme): void;
|
|
128
|
+
/** Повесить пропс на сокет (правая/левая рука, голова). false — сокета у модели нет. */
|
|
129
|
+
attach(socket: ActorSocket, object: THREE.Object3D): boolean;
|
|
130
|
+
/** Шаг времени: клипы, лицо, моргание. */
|
|
131
|
+
update(dt: number): void;
|
|
132
|
+
dispose(): void;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Общая библиотека клипов: клипы на эталонном скелете (отдельные GLB), играют на любом персонаже
|
|
136
|
+
* контракта. Дорожки переименовываются под кости экземпляра; смещение — только у таза (шаг на
|
|
137
|
+
* месте), остальные кости — только поворот, иначе пропорции чужого скелета ломали бы тело.
|
|
138
|
+
*/
|
|
139
|
+
declare class GltfClipLibrary {
|
|
140
|
+
private readonly clips;
|
|
141
|
+
private readonly perTarget;
|
|
142
|
+
add(name: string, clip: THREE.AnimationClip): void;
|
|
143
|
+
load(name: string, url: string, opts?: GltfLoadOptions): Promise<void>;
|
|
144
|
+
has(name: string): boolean;
|
|
145
|
+
names(): string[];
|
|
146
|
+
/** Клип, перенацеленный на кости `target`; null — такого клипа нет. */
|
|
147
|
+
clipFor(target: GltfCharacter, name: string): THREE.AnimationClip | null;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export { BLINK_KEYS, EMOTION_KEYS, GLTF_BUDGET, GltfCharacter, GltfCharacterAsset, GltfClipLibrary, type GltfFacts, type GltfLoadOptions, type GltfReport, HUMANOID_BONES, HUMANOID_V1, type HumanoidBone, type IssueLevel, REQUIRED_BONES, SOCKET_NODES, VISEME_KEYS, type ValidationIssue, canonicalBone, gltfFacts, validateGltfCharacter };
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
import { GLTF } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
|
3
|
+
import { E as Emotion, V as Viseme, A as ActorSocket } from '../contract-DhZuKNIf.js';
|
|
4
|
+
|
|
5
|
+
declare const HUMANOID_V1 = "humanoid-v1";
|
|
6
|
+
/** Кости эталона. Обязательные — без них клипы библиотеки не встанут. */
|
|
7
|
+
declare const HUMANOID_BONES: readonly ["hips", "spine", "chest", "upperChest", "neck", "head", "leftShoulder", "leftUpperArm", "leftLowerArm", "leftHand", "rightShoulder", "rightUpperArm", "rightLowerArm", "rightHand", "leftUpperLeg", "leftLowerLeg", "leftFoot", "leftToes", "rightUpperLeg", "rightLowerLeg", "rightFoot", "rightToes"];
|
|
8
|
+
type HumanoidBone = (typeof HUMANOID_BONES)[number];
|
|
9
|
+
declare const REQUIRED_BONES: readonly HumanoidBone[];
|
|
10
|
+
/** Имя кости в файле → кость эталона (или null — не гуманоидная кость: хвост, волосы, сокет). */
|
|
11
|
+
declare function canonicalBone(name: string): HumanoidBone | null;
|
|
12
|
+
/** Shape keys лица: фонемы рта, эмоции, моргание (имена в файле). VRM-пресеты — синонимы. */
|
|
13
|
+
declare const VISEME_KEYS: {
|
|
14
|
+
readonly A: readonly ["v_A", "aa", "vrc.v_aa", "mouth_a"];
|
|
15
|
+
readonly E: readonly ["v_E", "ee", "ih", "vrc.v_e", "vrc.v_ih", "mouth_e"];
|
|
16
|
+
readonly O: readonly ["v_O", "oh", "ou", "vrc.v_oh", "vrc.v_ou", "mouth_o"];
|
|
17
|
+
readonly MBP: readonly ["v_MBP", "vrc.v_pp", "mouth_m"];
|
|
18
|
+
readonly FV: readonly ["v_FV", "vrc.v_ff", "mouth_f"];
|
|
19
|
+
};
|
|
20
|
+
declare const EMOTION_KEYS: {
|
|
21
|
+
readonly happy: readonly ["e_happy", "happy", "joy"];
|
|
22
|
+
readonly sad: readonly ["e_sad", "sad", "sorrow"];
|
|
23
|
+
readonly angry: readonly ["e_angry", "angry"];
|
|
24
|
+
readonly surprised: readonly ["e_surprised", "surprised"];
|
|
25
|
+
readonly scared: readonly ["e_scared", "scared", "fear"];
|
|
26
|
+
readonly tired: readonly ["e_tired", "tired"];
|
|
27
|
+
readonly hurt: readonly ["e_hurt", "hurt", "pain"];
|
|
28
|
+
};
|
|
29
|
+
declare const BLINK_KEYS: readonly ["blink", "e_blink", "eyes_closed"];
|
|
30
|
+
/** Сокеты пропсов: своя пустышка в файле или кость эталона. */
|
|
31
|
+
declare const SOCKET_NODES: {
|
|
32
|
+
readonly handR: readonly ["socket_handR", "rightHand"];
|
|
33
|
+
readonly handL: readonly ["socket_handL", "leftHand"];
|
|
34
|
+
readonly head: readonly ["socket_head", "head"];
|
|
35
|
+
};
|
|
36
|
+
/** Стартовые бюджеты контракта (проверить на телефонах — значения в стандарте ассетов стартовые). */
|
|
37
|
+
declare const GLTF_BUDGET: {
|
|
38
|
+
readonly maxTriangles: 15000;
|
|
39
|
+
readonly maxMaterials: 2;
|
|
40
|
+
readonly maxTextureSize: 2048;
|
|
41
|
+
readonly maxFileBytes: number;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/** Что известно о файле. */
|
|
45
|
+
interface GltfFacts {
|
|
46
|
+
/** Имена узлов-костей скинов. */
|
|
47
|
+
bones: readonly string[];
|
|
48
|
+
/** Имена shape keys (morph targets) всех мешей. */
|
|
49
|
+
morphTargets: readonly string[];
|
|
50
|
+
triangles: number;
|
|
51
|
+
materials: number;
|
|
52
|
+
/** Наибольшая сторона каждой текстуры, px. */
|
|
53
|
+
textureSizes: readonly number[];
|
|
54
|
+
fileBytes: number;
|
|
55
|
+
/** Габарит в метрах: минимум и максимум по осям. */
|
|
56
|
+
bounds: {
|
|
57
|
+
min: [number, number, number];
|
|
58
|
+
max: [number, number, number];
|
|
59
|
+
};
|
|
60
|
+
/** Встроенные клипы — по контракту клипы живут в общей библиотеке, не в персонаже. */
|
|
61
|
+
animations: number;
|
|
62
|
+
}
|
|
63
|
+
type IssueLevel = "error" | "warning";
|
|
64
|
+
interface ValidationIssue {
|
|
65
|
+
level: IssueLevel;
|
|
66
|
+
code: string;
|
|
67
|
+
message: string;
|
|
68
|
+
}
|
|
69
|
+
interface GltfReport {
|
|
70
|
+
ok: boolean;
|
|
71
|
+
issues: ValidationIssue[];
|
|
72
|
+
/** Найденные кости эталона: имя в файле → кость. */
|
|
73
|
+
boneMap: Partial<Record<HumanoidBone, string>>;
|
|
74
|
+
visemes: string[];
|
|
75
|
+
emotions: string[];
|
|
76
|
+
blink: boolean;
|
|
77
|
+
}
|
|
78
|
+
declare function validateGltfCharacter(f: GltfFacts): GltfReport;
|
|
79
|
+
|
|
80
|
+
interface GltfLoadOptions {
|
|
81
|
+
/** Рендерер — KTX2 узнаёт по нему, какие сжатые форматы есть у видеокарты. */
|
|
82
|
+
renderer?: THREE.WebGLRenderer;
|
|
83
|
+
/** Папка транскодера Basis (файлы three/examples/jsm/libs/basis) на нашем CDN. */
|
|
84
|
+
ktx2TranscoderPath?: string;
|
|
85
|
+
/** Размер файла, если известен (для отчёта контракта). */
|
|
86
|
+
fileBytes?: number;
|
|
87
|
+
}
|
|
88
|
+
/** Загруженный файл персонажа: из него делаются экземпляры (`instance()`), файл грузится один раз. */
|
|
89
|
+
declare class GltfCharacterAsset {
|
|
90
|
+
private readonly gltf;
|
|
91
|
+
readonly report: GltfReport;
|
|
92
|
+
private constructor();
|
|
93
|
+
static load(url: string, opts?: GltfLoadOptions): Promise<GltfCharacterAsset>;
|
|
94
|
+
static parse(data: ArrayBuffer, opts?: GltfLoadOptions): Promise<GltfCharacterAsset>;
|
|
95
|
+
/** Новый экземпляр со своим скелетом (два одинаковых героя в кадре не делят позу). */
|
|
96
|
+
instance(seed?: number): GltfCharacter;
|
|
97
|
+
}
|
|
98
|
+
/** Факты файла для проверки контракта. */
|
|
99
|
+
declare function gltfFacts(gltf: GLTF, fileBytes: number): GltfFacts;
|
|
100
|
+
/** Экземпляр персонажа в сцене. */
|
|
101
|
+
declare class GltfCharacter {
|
|
102
|
+
readonly report: GltfReport;
|
|
103
|
+
readonly root: THREE.Group;
|
|
104
|
+
readonly mixer: THREE.AnimationMixer;
|
|
105
|
+
/** Кость эталона → узел этого экземпляра. */
|
|
106
|
+
readonly bones: Partial<Record<HumanoidBone, THREE.Object3D>>;
|
|
107
|
+
private readonly visemeMorphs;
|
|
108
|
+
private readonly emotionMorphs;
|
|
109
|
+
private readonly blinkMorphs;
|
|
110
|
+
private readonly sockets;
|
|
111
|
+
private current;
|
|
112
|
+
private viseme;
|
|
113
|
+
private visemeWeights;
|
|
114
|
+
private emotion;
|
|
115
|
+
private emotionWeight;
|
|
116
|
+
private blinkIn;
|
|
117
|
+
private blinkT;
|
|
118
|
+
private readonly rnd;
|
|
119
|
+
constructor(scene: THREE.Object3D, report: GltfReport, seed?: number);
|
|
120
|
+
/** Сыграть клип библиотеки (уже перенацеленный на этот экземпляр — `GltfClipLibrary.clipFor`). */
|
|
121
|
+
play(clip: THREE.AnimationClip, opts?: {
|
|
122
|
+
fade?: number;
|
|
123
|
+
loop?: boolean;
|
|
124
|
+
timeScale?: number;
|
|
125
|
+
}): void;
|
|
126
|
+
setEmotion(e: Emotion): void;
|
|
127
|
+
setViseme(v: Viseme): void;
|
|
128
|
+
/** Повесить пропс на сокет (правая/левая рука, голова). false — сокета у модели нет. */
|
|
129
|
+
attach(socket: ActorSocket, object: THREE.Object3D): boolean;
|
|
130
|
+
/** Шаг времени: клипы, лицо, моргание. */
|
|
131
|
+
update(dt: number): void;
|
|
132
|
+
dispose(): void;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Общая библиотека клипов: клипы на эталонном скелете (отдельные GLB), играют на любом персонаже
|
|
136
|
+
* контракта. Дорожки переименовываются под кости экземпляра; смещение — только у таза (шаг на
|
|
137
|
+
* месте), остальные кости — только поворот, иначе пропорции чужого скелета ломали бы тело.
|
|
138
|
+
*/
|
|
139
|
+
declare class GltfClipLibrary {
|
|
140
|
+
private readonly clips;
|
|
141
|
+
private readonly perTarget;
|
|
142
|
+
add(name: string, clip: THREE.AnimationClip): void;
|
|
143
|
+
load(name: string, url: string, opts?: GltfLoadOptions): Promise<void>;
|
|
144
|
+
has(name: string): boolean;
|
|
145
|
+
names(): string[];
|
|
146
|
+
/** Клип, перенацеленный на кости `target`; null — такого клипа нет. */
|
|
147
|
+
clipFor(target: GltfCharacter, name: string): THREE.AnimationClip | null;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export { BLINK_KEYS, EMOTION_KEYS, GLTF_BUDGET, GltfCharacter, GltfCharacterAsset, GltfClipLibrary, type GltfFacts, type GltfLoadOptions, type GltfReport, HUMANOID_BONES, HUMANOID_V1, type HumanoidBone, type IssueLevel, REQUIRED_BONES, SOCKET_NODES, VISEME_KEYS, type ValidationIssue, canonicalBone, gltfFacts, validateGltfCharacter };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import {a}from'../chunk-CGF2TQVK.js';import*as d from'three';import {GLTFLoader}from'three/examples/jsm/loaders/GLTFLoader.js';import {KTX2Loader}from'three/examples/jsm/loaders/KTX2Loader.js';import {MeshoptDecoder}from'three/examples/jsm/libs/meshopt_decoder.module.js';import {clone}from'three/examples/jsm/utils/SkeletonUtils.js';var P="humanoid-v1",$=["hips","spine","chest","upperChest","neck","head","leftShoulder","leftUpperArm","leftLowerArm","leftHand","rightShoulder","rightUpperArm","rightLowerArm","rightHand","leftUpperLeg","leftLowerLeg","leftFoot","leftToes","rightUpperLeg","rightLowerLeg","rightFoot","rightToes"],B=["hips","spine","chest","neck","head","leftUpperArm","leftLowerArm","leftHand","rightUpperArm","rightLowerArm","rightHand","leftUpperLeg","leftLowerLeg","leftFoot","rightUpperLeg","rightLowerLeg","rightFoot"],C={hips:"hips",pelvis:"hips",spine:"spine",spine1:"chest",chest:"chest",spine2:"upperChest",upperchest:"upperChest",neck:"neck",head:"head",leftshoulder:"leftShoulder",shoulderl:"leftShoulder",leftarm:"leftUpperArm",leftupperarm:"leftUpperArm",upperarml:"leftUpperArm",leftforearm:"leftLowerArm",leftlowerarm:"leftLowerArm",forearml:"leftLowerArm",lefthand:"leftHand",handl:"leftHand",rightshoulder:"rightShoulder",shoulderr:"rightShoulder",rightarm:"rightUpperArm",rightupperarm:"rightUpperArm",upperarmr:"rightUpperArm",rightforearm:"rightLowerArm",rightlowerarm:"rightLowerArm",forearmr:"rightLowerArm",righthand:"rightHand",handr:"rightHand",leftupleg:"leftUpperLeg",leftupperleg:"leftUpperLeg",thighl:"leftUpperLeg",leftleg:"leftLowerLeg",leftlowerleg:"leftLowerLeg",shinl:"leftLowerLeg",leftfoot:"leftFoot",footl:"leftFoot",lefttoebase:"leftToes",lefttoes:"leftToes",toel:"leftToes",rightupleg:"rightUpperLeg",rightupperleg:"rightUpperLeg",thighr:"rightUpperLeg",rightleg:"rightLowerLeg",rightlowerleg:"rightLowerLeg",shinr:"rightLowerLeg",rightfoot:"rightFoot",footr:"rightFoot",righttoebase:"rightToes",righttoes:"rightToes",toer:"rightToes"};function x(o){let e=o.replace(/^mixamorig\d*[:_]?/i,"").replace(/^(DEF|ORG|MCH)[-_.]/i,"").replace(/[\s._:-]/g,"").toLowerCase();return C[e]??null}var v={A:["v_A","aa","vrc.v_aa","mouth_a"],E:["v_E","ee","ih","vrc.v_e","vrc.v_ih","mouth_e"],O:["v_O","oh","ou","vrc.v_oh","vrc.v_ou","mouth_o"],MBP:["v_MBP","vrc.v_pp","mouth_m"],FV:["v_FV","vrc.v_ff","mouth_f"]},y={happy:["e_happy","happy","joy"],sad:["e_sad","sad","sorrow"],angry:["e_angry","angry"],surprised:["e_surprised","surprised"],scared:["e_scared","scared","fear"],tired:["e_tired","tired"],hurt:["e_hurt","hurt","pain"]},M=["blink","e_blink","eyes_closed"],F={handR:["socket_handR","rightHand"],handL:["socket_handL","leftHand"],head:["socket_head","head"]},u={maxTriangles:15e3,maxMaterials:2,maxTextureSize:2048,maxFileBytes:6*1024*1024};function I(o){let e=[],t=(a,g)=>e.push({level:"error",code:a,message:g}),r=(a,g)=>e.push({level:"warning",code:a,message:g}),n={};for(let a of o.bones){let g=x(a);g&&!n[g]&&(n[g]=a);}let i=B.filter(a=>!n[a]);o.bones.length===0?t("NO_SKELETON","the model has no skeleton (skin)"):i.length>0&&t("BONES_MISSING",`humanoid-v1 bones missing: ${i.join(", ")}`);let h=new Set(o.morphTargets.map(a=>a.toLowerCase())),s=a=>a.some(g=>h.has(g.toLowerCase())),l=Object.entries(v).filter(([,a])=>s(a)).map(([a])=>a),p=Object.entries(y).filter(([,a])=>s(a)).map(([a])=>a),m=s(M);l.length===0?r("NO_VISEMES","no mouth shape keys (v_A, v_E, v_O, v_MBP, v_FV): the mouth will not move"):l.length<5&&r("VISEMES_PARTIAL",`mouth shape keys: ${l.join(", ")} of A, E, O, MBP, FV`),p.length<6&&r("EMOTIONS_PARTIAL",`emotion shape keys: ${p.join(", ")||"none"} (the standard asks for happy, sad, angry, surprised, scared + neutral)`),m||r("NO_BLINK","no blink shape key"),o.triangles>u.maxTriangles&&t("TRIANGLES",`${o.triangles} triangles, budget ${u.maxTriangles}`),o.materials>u.maxMaterials&&t("MATERIALS",`${o.materials} materials, budget ${u.maxMaterials}`);let f=o.textureSizes.filter(a=>a>u.maxTextureSize);f.length>0&&t("TEXTURES",`textures over ${u.maxTextureSize}px: ${f.join(", ")}`),o.fileBytes>u.maxFileBytes&&t("FILE_SIZE",`${(o.fileBytes/1048576).toFixed(1)} MB, budget ${u.maxFileBytes/1048576} MB`);let[c,E,L]=o.bounds.min,[b,G,U]=o.bounds.max,T=G-E;return (T<.3||T>4)&&t("SCALE",`height ${T.toFixed(2)} m \u2014 units must be metres (a person is ~1.7 m)`),Math.abs(E)>.05*Math.max(T,1)&&r("PIVOT",`feet at y=${E.toFixed(2)}: the pivot must be between the feet (y = 0)`),(Math.abs((c+b)/2)>.25||Math.abs((L+U)/2)>.25)&&r("CENTER","the model is off the origin: the pivot must be between the feet"),b-c>T*1.5&&T>0&&r("AXES","wider than tall \u2014 is +Y up?"),o.animations>0&&r("EMBEDDED_CLIPS",`${o.animations} clips inside the character: clips belong to the shared library`),{ok:!e.some(a=>a.level==="error"),issues:e,boneMap:n,visemes:l,emotions:p,blink:m}}var w=null;function R(o){let e=new GLTFLoader;return e.setMeshoptDecoder(MeshoptDecoder),o.renderer&&o.ktx2TranscoderPath&&(w||(w=new KTX2Loader().setTranscoderPath(o.ktx2TranscoderPath),w.detectSupport(o.renderer)),e.setKTX2Loader(w)),e}var _=class o{constructor(e,t){this.gltf=e;this.report=I(t);}gltf;report;static async load(e,t={}){let r=await R(t).loadAsync(e);return new o(r,k(r,t.fileBytes??0))}static async parse(e,t={}){let r=await R(t).parseAsync(e,"");return new o(r,k(r,e.byteLength))}instance(e=1){return new S(clone(this.gltf.scene),this.report,e)}};function k(o,e){let t=new Set,r=new Set,n=new Set,i=[],h=0;o.scene.updateMatrixWorld(true);let s=new d.Box3().setFromObject(o.scene);return o.scene.traverse(l=>{let p=l;if(l.isSkinnedMesh)for(let c of l.skeleton.bones)t.add(c.name);if(!p.isMesh)return;let m=p.geometry;h+=(m.index?m.index.count:m.attributes.position.count)/3;for(let c of Object.keys(p.morphTargetDictionary??{}))r.add(c);let f=Array.isArray(p.material)?p.material:[p.material];for(let c of f){n.add(c.uuid);for(let E of Object.values(c)){let L=E,b=L?.isTexture?L.image:null;b?.width&&b.height&&i.push(Math.max(b.width,b.height));}}}),{bones:[...t],morphTargets:[...r],triangles:Math.round(h),materials:n.size,textureSizes:i,fileBytes:e,bounds:{min:[s.min.x,s.min.y,s.min.z],max:[s.max.x,s.max.y,s.max.z]},animations:o.animations.length}}var S=class{constructor(e,t,r=1){this.report=t;this.rnd=a(r),this.blinkIn=2+this.rnd()*3,this.root=new d.Group,this.root.add(e),this.mixer=new d.AnimationMixer(e);let n=new Map;e.traverse(i=>{n.set(i.name,i);let h=x(i.name);h&&!this.bones[h]&&i.isBone&&(this.bones[h]=i);let s=i;if(!s.isMesh||!s.morphTargetDictionary)return;let l=j(s.morphTargetDictionary),p=m=>m.flatMap(f=>{let c=l.get(f.toLowerCase());return c===void 0?[]:[{mesh:s,index:c}]});for(let[m,f]of Object.entries(v))this.visemeMorphs.set(m,[...this.visemeMorphs.get(m)??[],...p(f)]);for(let[m,f]of Object.entries(y))this.emotionMorphs.set(m,[...this.emotionMorphs.get(m)??[],...p(f)]);this.blinkMorphs.push(...p(M));});for(let[i,h]of Object.entries(F)){let s=h.map(l=>n.get(l)??this.bones[l]).find(Boolean);s&&this.sockets.set(i,s);}}report;root;mixer;bones={};visemeMorphs=new Map;emotionMorphs=new Map;blinkMorphs=[];sockets=new Map;current=null;viseme="rest";visemeWeights=new Map;emotion="neutral";emotionWeight=0;blinkIn;blinkT=-1;rnd;play(e,t={}){let r=this.mixer.clipAction(e);r.reset(),r.setLoop(t.loop===false?d.LoopOnce:d.LoopRepeat,1/0),r.clampWhenFinished=t.loop===false,r.timeScale=t.timeScale??1;let n=t.fade??.2;this.current&&this.current!==r&&r.crossFadeFrom(this.current,n,false),r.play(),this.current=r;}setEmotion(e){this.emotion=e;}setViseme(e){this.viseme=e;}attach(e,t){let r=this.sockets.get(e);return r?(r.add(t),true):false}update(e){this.mixer.update(e);let t=1-Math.exp(-e/.06);for(let[n,i]of this.visemeMorphs){let h=n===this.viseme?1:0,s=(this.visemeWeights.get(n)??0)+(h-(this.visemeWeights.get(n)??0))*t;this.visemeWeights.set(n,s);for(let l of i)A(l,s);}let r=1-Math.exp(-e/.15);this.emotionWeight+=((this.emotion==="neutral"?0:1)-this.emotionWeight)*r;for(let[n,i]of this.emotionMorphs)for(let h of i)A(h,n===this.emotion?this.emotionWeight:0);if(this.blinkT>=0){this.blinkT+=e;let n=this.blinkT/.15,i=n<.5?n*2:Math.max(0,2-n*2);for(let h of this.blinkMorphs)A(h,i);n>=1&&(this.blinkT=-1,this.blinkIn=2+this.rnd()*3);}else (this.blinkIn-=e)<=0&&(this.blinkT=0);}dispose(){this.mixer.stopAllAction(),this.root.removeFromParent(),this.root.traverse(e=>{let t=e;t.isMesh&&t.geometry.dispose();});}};function A(o,e){let t=o.mesh.morphTargetInfluences;t&&(t[o.index]=e);}function j(o){return new Map(Object.entries(o).map(([e,t])=>[e.toLowerCase(),t]))}var H=class{clips=new Map;perTarget=new WeakMap;add(e,t){this.clips.set(e,t);}async load(e,t,r={}){let i=(await R(r).loadAsync(t)).animations[0];if(!i)throw new Error(`${t}: no animation`);this.add(e,i);}has(e){return this.clips.has(e)}names(){return [...this.clips.keys()]}clipFor(e,t){let r=this.perTarget.get(e);r||this.perTarget.set(e,r=new Map);let n=r.get(t);if(n)return n;let i=this.clips.get(t);if(!i)return null;let h=[];for(let l of i.tracks){let p=l.name.lastIndexOf("."),m=x(l.name.slice(0,p)),f=l.name.slice(p+1);if(!m)continue;let c=e.bones[m];if(!c||f==="position"&&m!=="hips"||f==="scale")continue;let E=l.clone();E.name=`${c.name}.${f}`,h.push(E);}let s=new d.AnimationClip(`${t}`,i.duration,h);return r.set(t,s),s}};export{M as BLINK_KEYS,y as EMOTION_KEYS,u as GLTF_BUDGET,S as GltfCharacter,_ as GltfCharacterAsset,H as GltfClipLibrary,$ as HUMANOID_BONES,P as HUMANOID_V1,B as REQUIRED_BONES,F as SOCKET_NODES,v as VISEME_KEYS,x as canonicalBone,k as gltfFacts,I as validateGltfCharacter};
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
'use strict';var E=["neutral","happy","sad","angry","surprised","scared","tired","hurt"];function j(e){return typeof e=="string"&&E.includes(e)}var b=["rest","A","E","O","MBP","FV"];function P(e){return typeof e=="string"&&b.includes(e)}var F=["idle","talk","walk","run","surprised","point","sit","wave","jump","fall","dance"],B=["handR","handL","head"],Y=["voxel-warm","flat-cartoon","chibi-2d","low-poly-3d","photo-sticker"];var k=new Set([..."a\u0430\u044F\xE4"]),L=new Set([..."eiy\u044D\u0435\u0438\u044B\u0439\u0451\xE9\xE8\xEA"]),O=new Set([..."ou\u043E\u0443\u044Ew\xF6\xFC"]),v=new Set([..."mbp\u043C\u0431\u043F"]),V=new Set([..."fv\u0444\u0432"]);function y(e){let t=e.toLowerCase();return k.has(t)?"A":L.has(t)?"E":O.has(t)?"O":v.has(t)?"MBP":V.has(t)?"FV":null}var S=e=>/\p{L}|\p{N}/u.test(e),w=e=>{let t=y(e);return t==="A"||t==="E"||t==="O"};function m(e){return S(e)?w(e)?1:.6:/[.!?…]/.test(e)?3:/[,;:—–-]/.test(e)?1.6:/\s/.test(e)?.35:0}function z(e,t,n){let o=Math.max(0,t),a=e.match(/\S+/g)??[];if(a.length===0||o===0)return {words:[],visemes:[{t:0,v:"rest"}]};let c=n&&n.length===a.length?n.map(r=>({...r})):A(e,o),s=[{t:0,v:"rest"}];for(let r of c){let i=[...r.text].filter(S),u=i.reduce((p,f)=>p+m(f),0)||1,g=r.start;for(let p of i){let f=y(p)??"E";s[s.length-1].v!==f&&s.push({t:l(g),v:f}),g+=(r.end-r.start)*m(p)/u;}s.push({t:l(r.end),v:"rest"});}return {words:c,visemes:T(s)}}function A(e,t){let n=[...e],o=n.reduce((r,i)=>r+m(i),0)||1,a=[],c=0,s=null;for(let r of n){let i=t*m(r)/o;/\s/.test(r)?(s&&a.push({text:s.text,start:l(s.start),end:l(c)}),s=null):s?s.text+=r:s={text:r,start:c},c+=i;}return s&&a.push({text:s.text,start:l(s.start),end:l(c)}),a.map(r=>{let i=/[^\p{L}\p{N}]+$/u.exec(r.text)?.[0].length??0;if(i===0)return r;let u=[...r.text],g=u.reduce((f,x)=>f+m(x),0)||1,p=u.slice(u.length-i).reduce((f,x)=>f+m(x),0);return {...r,end:l(r.end-(r.end-r.start)*p/g)}})}function G(e,t){let n="rest";for(let o of e){if(o.t>t)break;n=o.v;}return n}function H(e,t){for(let n=0;n<e.length;n++){let o=e[n];if(t>=o.start&&t<o.end)return n}return -1}var l=e=>Math.round(e*1e3)/1e3;function T(e){let t=[];for(let n of e){let o=t[t.length-1];o&&o.t===n.t?t[t.length-1]=n:(!o||o.v!==n.v)&&t.push(n);}return t}var M=["ru","kk","uk","be","ky","uz","tg"],I="idos:language",J="idos:language";function K(){try{let t=globalThis.localStorage?.getItem(I);if(t==="en"||t==="ru")return t}catch{}if(typeof navigator>"u")return "en";let e=(navigator.language||"").toLowerCase();return M.some(t=>e.startsWith(t))?"ru":"en"}var h=K();function N(){return h}function W(e){h=e;}typeof window<"u"&&window.addEventListener(J,e=>{let t=e.detail;(t==="en"||t==="ru")&&(h=t);});function d(e,t){let n=typeof e=="string"?e:e[h]??e.en;if(t)for(let[o,a]of Object.entries(t))n=n.split(`{${o}}`).join(String(a));return n}function C(e){let t=e>>>0;return function(){t|=0,t=t+1831565813|0;let n=Math.imul(t^t>>>15,1|t);return n=n+Math.imul(n^n>>>7,61|n)^n,((n^n>>>14)>>>0)/4294967296}}function _(e){let t=2166136261;for(let n=0;n<e.length;n++)t^=e.charCodeAt(n),t=Math.imul(t,16777619);return t>>>0}function R(e){let t=e.trim(),n=/```(?:json)?\s*([\s\S]*?)(?:```|$)/i.exec(t);n&&n[1]!==void 0&&(t=n[1]);let o=t.indexOf("{");if(o<0)return {ok:false,error:d({en:"the answer has no JSON object",ru:"\u0432 \u043E\u0442\u0432\u0435\u0442\u0435 \u043D\u0435\u0442 JSON-\u043E\u0431\u044A\u0435\u043A\u0442\u0430"}),truncated:false};let a=0,c=false,s=false,r=-1;for(let i=o;i<t.length;i++){let u=t[i];if(c){s?s=false:u==="\\"?s=true:u==='"'&&(c=false);continue}if(u==='"')c=true;else if(u==="{"||u==="[")a++;else if((u==="}"||u==="]")&&(a--,a===0)){r=i;break}}if(r<0)return {ok:false,error:d({en:"the JSON is cut off",ru:"JSON \u043E\u0431\u043E\u0440\u0432\u0430\u043D"}),truncated:true};try{return {ok:!0,value:JSON.parse(t.slice(o,r+1))}}catch{return {ok:false,error:d({en:"invalid JSON",ru:"\u043D\u0435\u0432\u0430\u043B\u0438\u0434\u043D\u044B\u0439 JSON"}),truncated:false}}}exports.ACTOR_POSES=F;exports.ACTOR_SOCKETS=B;exports.EMOTIONS=E;exports.STYLE_FAMILIES=Y;exports.VISEMES=b;exports.extractJsonObject=R;exports.hashString=_;exports.isEmotion=j;exports.isViseme=P;exports.lang=N;exports.layoutSpeech=z;exports.mulberry32=C;exports.setLang=W;exports.tr=d;exports.visemeAt=G;exports.visemeOfLetter=y;exports.wordAt=H;
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { V as Viseme } from './contract-DhZuKNIf.cjs';
|
|
2
|
+
export { a as ACTOR_POSES, b as ACTOR_SOCKETS, c as ActorKind, d as ActorPose, A as ActorSocket, e as EMOTIONS, E as Emotion, S as STYLE_FAMILIES, f as StyleFamily, g as VISEMES, i as isEmotion, h as isViseme } from './contract-DhZuKNIf.cjs';
|
|
3
|
+
export { R as RGBAImage } from './image-D5NaQeFz.cjs';
|
|
4
|
+
|
|
5
|
+
/** Слово реплики со временем от начала реплики, секунды. */
|
|
6
|
+
interface SpokenWord {
|
|
7
|
+
text: string;
|
|
8
|
+
start: number;
|
|
9
|
+
end: number;
|
|
10
|
+
}
|
|
11
|
+
/** Ключ формы рта: с `t` (секунды от начала реплики) до следующего ключа. */
|
|
12
|
+
interface VisemeKey {
|
|
13
|
+
t: number;
|
|
14
|
+
v: Viseme;
|
|
15
|
+
}
|
|
16
|
+
interface SpeechLayout {
|
|
17
|
+
words: SpokenWord[];
|
|
18
|
+
visemes: VisemeKey[];
|
|
19
|
+
}
|
|
20
|
+
/** Форма рта для буквы; null — буква не двигает губы заметно (рот чуть приоткрыт — «Э»). */
|
|
21
|
+
declare function visemeOfLetter(ch: string): Viseme | null;
|
|
22
|
+
/**
|
|
23
|
+
* Раскладка реплики на `duration` секунд. `words` — таймкоды слов выравнивания (если есть);
|
|
24
|
+
* их тексты должны идти в том же порядке, что слова `text`.
|
|
25
|
+
*/
|
|
26
|
+
declare function layoutSpeech(text: string, duration: number, words?: readonly SpokenWord[]): SpeechLayout;
|
|
27
|
+
/** Форма рта в момент `t` (секунды от начала реплики). */
|
|
28
|
+
declare function visemeAt(keys: readonly VisemeKey[], t: number): Viseme;
|
|
29
|
+
/** Слово под курсором `t`: индекс в `words` или -1 (пауза). */
|
|
30
|
+
declare function wordAt(words: readonly SpokenWord[], t: number): number;
|
|
31
|
+
|
|
32
|
+
type Lang = "en" | "ru";
|
|
33
|
+
/** Текущий язык текстов пакета. */
|
|
34
|
+
declare function lang(): Lang;
|
|
35
|
+
/** Сменить язык в памяти (игра при своём выборе языка, тесты). */
|
|
36
|
+
declare function setLang(l: Lang): void;
|
|
37
|
+
/** Текст на двух языках; строка — один текст для обоих (числа, эмодзи, имена). */
|
|
38
|
+
type Loc = string | {
|
|
39
|
+
en: string;
|
|
40
|
+
ru: string;
|
|
41
|
+
};
|
|
42
|
+
/** Текст на текущем языке; `{name}` в нём заменяются из vars. */
|
|
43
|
+
declare function tr(text: Loc, vars?: Record<string, string | number>): string;
|
|
44
|
+
|
|
45
|
+
/** Генератор случайных чисел [0, 1) по 32-битному сиду. */
|
|
46
|
+
declare function mulberry32(seed: number): () => number;
|
|
47
|
+
/** Хэш строки в 32-битный сид (FNV-1a). */
|
|
48
|
+
declare function hashString(str: string): number;
|
|
49
|
+
|
|
50
|
+
type JsonExtract = {
|
|
51
|
+
ok: true;
|
|
52
|
+
value: unknown;
|
|
53
|
+
} | {
|
|
54
|
+
ok: false;
|
|
55
|
+
error: string;
|
|
56
|
+
truncated: boolean;
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Достаёт первый JSON-объект из текста модели: срезает ```json-обёртку и болтовню вокруг.
|
|
60
|
+
* Обрезанный ответ (модель упёрлась в лимит токенов — движок такой считает успехом и списывает)
|
|
61
|
+
* распознаётся по незакрытым скобкам: `truncated: true`.
|
|
62
|
+
*/
|
|
63
|
+
declare function extractJsonObject(text: string): JsonExtract;
|
|
64
|
+
|
|
65
|
+
export { type JsonExtract, type Lang, type Loc, type SpeechLayout, type SpokenWord, Viseme, type VisemeKey, extractJsonObject, hashString, lang, layoutSpeech, mulberry32, setLang, tr, visemeAt, visemeOfLetter, wordAt };
|