moodi 0.3.2 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.5.0
4
+
5
+ - New default color `#2b15d1` (also the `Iris` palette entry); black face by default.
6
+
7
+ ## 0.4.0
8
+
9
+ - `settle-mood` (React `settleMood`): with `settle`, switch to this mood once the time is
10
+ up, e.g. `mood="happy" settle={3000} settleMood="idle"` plays happy for 3 s, then rests in
11
+ idle. The `mood` prop itself is unchanged; a new mood or reaction restarts the timer.
12
+
3
13
  ## 0.3.2
4
14
 
5
15
  - Eyes and mouth sit in soft sockets and read as rounded, slightly raised features
package/README.md CHANGED
@@ -24,7 +24,7 @@ npm i moodi three
24
24
  ### Web Component
25
25
 
26
26
  ```html
27
- <moodi-buddy shape="ghost" mood="happy" color="#6c5ce7" size="160"></moodi-buddy>
27
+ <moodi-buddy shape="ghost" mood="happy" color="#2b15d1" size="160"></moodi-buddy>
28
28
  <script type="module">import 'moodi';</script>
29
29
  ```
30
30
 
@@ -65,7 +65,7 @@ With the Web Component, put an `<img>` inside `<moodi-buddy>`; it shows until th
65
65
  | ----------------------------- | ------------------------------------------------------------ | ----------- | --------------------------------------------- |
66
66
  | `shape` | `'ghost' \| 'pebble' \| 'blob' \| 'drop' \| 'bean' \| 'cube'` | `'ghost'` | Body shape |
67
67
  | `mood` | `Mood` (see below) | `'idle'` | Changes are interpolated, never instant |
68
- | `color` | any CSS color | `'#6c5ce7'` | Body color |
68
+ | `color` | any CSS color | `'#2b15d1'` | Body color |
69
69
  | `faceColor` (`face-color`) | any CSS color | auto | Eyes & mouth, auto-contrast with the body |
70
70
  | `cheekColor` (`cheek-color`) | any CSS color | auto | Blush, derived from the body color |
71
71
  | `size` | `number \| string` | `160` | px, or any CSS length (`"10rem"`, `"40vw"`) |
@@ -75,6 +75,7 @@ With the Web Component, put an `<img>` inside `<moodi-buddy>`; it shows until th
75
75
  | `shadow` | `boolean` | `true` | Soft ground shadow |
76
76
  | `sound` | `boolean` | `false` | Short synthesized effect per mood (and when it appears) |
77
77
  | `settle` | `number` | `0` | ms after a mood change when the body calms to idle breathing (expression stays); `0` = never |
78
+ | `settleMood` (`settle-mood`) | `Mood` | — | With `settle`: the mood to rest in once the time is up (e.g. happy for 2 s, then idle) |
78
79
 
79
80
  Boolean attributes on the Web Component take `"true"` / `"false"`.
80
81
 
package/dist/index.cjs CHANGED
@@ -1,4 +1,4 @@
1
- 'use strict';var three=require('three');var Qe=["ghost","pebble","blob","drop","bean","cube"],et=["idle","thinking","loading","listening","speaking","happy","surprised","sad","error","sleeping","love"],y={shape:"ghost",mood:"idle",color:"#6c5ce7",size:160,speed:1,followCursor:true,interactive:true,shadow:true,sound:false,settle:0},Ot={Iris:"#6c5ce7",Peach:"#f2a07b",Sage:"#8fb996",Sky:"#8ec5e8",Lilac:"#b9a3e3",Butter:"#f3d36b",Coral:"#f07167",Ink:"#2b2d42",Cloud:"#ecebe8"},Lt={idle:{label:"Idle",description:"Breathing softly. Blinks now and then."},thinking:{label:"Thinking",description:"Eyes drift up. Little thoughts pop."},loading:{label:"Loading",description:"Half-lidded, wobbling patiently."},listening:{label:"Listening",description:"All eyes. Nods along to every word."},speaking:{label:"Speaking",description:"Chatty mouth, bouncing to the rhythm."},happy:{label:"Happy",description:"Bounces with joy. Cheeks glow."},surprised:{label:"Surprised",description:"Wide eyes, tiny o. Did not see that coming."},sad:{label:"Sad",description:"Slumps a little. Needs a minute."},error:{label:"Error",description:"Something broke. Shakes it off."},sleeping:{label:"Sleeping",description:"Deep, slow breaths. Do not disturb."},love:{label:"Love",description:"Heart eyes, floating on air."}},Gt={pebble:"Pebble",blob:"Blob",drop:"Drop",bean:"Bean",cube:"Cube",ghost:"Ghost"},de=e=>Qe.includes(e),pe=e=>et.includes(e);var G=null;function X(e,o){if(!e)return o;let t=/^#?([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(e.trim());if(t)return Be(t[1]);if(G||(G=document.createElement("canvas").getContext("2d")),!G)return o;G.fillStyle="#010203",G.fillStyle=e;let i=String(G.fillStyle);if(i==="#010203"&&e.trim()!=="#010203")return o;if(i.startsWith("#"))return Be(i.slice(1));G.canvas.width=G.canvas.height=1,G.clearRect(0,0,1,1),G.fillRect(0,0,1,1);let s=G.getImageData(0,0,1,1).data;return [s[0]/255,s[1]/255,s[2]/255]}function Be(e){e.length===3&&(e=e[0]+e[0]+e[1]+e[1]+e[2]+e[2]);let o=parseInt(e,16);return [(o>>16&255)/255,(o>>8&255)/255,(o&255)/255]}var D=e=>`rgb(${Math.round(e[0]*255)},${Math.round(e[1]*255)},${Math.round(e[2]*255)})`,R=(e,o,t)=>[e[0]+(o[0]-e[0])*t,e[1]+(o[1]-e[1])*t,e[2]+(o[2]-e[2])*t],me=e=>e<=.04045?e/12.92:Math.pow((e+.055)/1.055,2.4),fe=e=>.2126*me(e[0])+.7152*me(e[1])+.0722*me(e[2]),tt=[.07,.06,.08],ot=[209/255,190/255,173/255],it=[1,.42,.48],te=e=>fe(e)>.06?R(tt,e,.06):ot,oe=e=>R(e,it,.78);var J=["eyeOpen","eyeSize","lookX","lookY","lidCover","lidTilt","happyEye","closedEye","xEye","heartEye","mouthW","mouthCurve","mouthOpen","mouthRound","mouthSkew","mouthWave","blush"],Y={eyeOpen:1,eyeSize:1,lookX:0,lookY:0,lidCover:0,lidTilt:0,happyEye:0,closedEye:0,xEye:0,heartEye:0,mouthW:.1,mouthCurve:.35,mouthOpen:0,mouthRound:0,mouthSkew:0,mouthWave:0,blush:.45},ie={idle:{...Y},thinking:{...Y,eyeOpen:.92,lookX:.7,lookY:-0.8,lidCover:.12,mouthW:.065,mouthCurve:0,mouthSkew:.8,blush:.3},loading:{...Y,lidCover:.48,mouthW:.06,mouthCurve:.12,blush:.3},listening:{...Y,eyeOpen:1.12,eyeSize:1.16,mouthW:.06,mouthCurve:.2,mouthOpen:.02},speaking:{...Y,mouthW:.09,mouthCurve:.25},happy:{...Y,happyEye:1,mouthW:.13,mouthCurve:1,mouthOpen:.08,blush:1},surprised:{...Y,eyeOpen:1.25,eyeSize:1.22,mouthW:.06,mouthCurve:0,mouthOpen:.12,mouthRound:1,blush:.35},sad:{...Y,eyeOpen:.95,lidCover:.32,lidTilt:.5,lookY:.45,mouthW:.08,mouthCurve:-0.75,blush:.2},error:{...Y,xEye:1,mouthW:.1,mouthCurve:-0.2,mouthWave:1,blush:.15},sleeping:{...Y,closedEye:1,mouthW:.04,mouthCurve:0,mouthOpen:.035,mouthRound:.7,blush:.55},love:{...Y,heartEye:1,mouthW:.11,mouthCurve:.9,mouthOpen:.03,blush:1}},Le={idle:1,thinking:.15,loading:0,listening:1,speaking:.9,happy:.6,surprised:.8,sad:.3,error:.3,sleeping:0,love:.7},ve=e=>({...e}),st=.31,nt=-0.04,at=.098,be=.128,rt=.2,ge=.05;function ye(e,o,t,i,s,n,u,r,l,d,a=false){let h=e.canvas.width;e.setTransform(1,0,0,1,0,0),e.clearRect(0,0,h,h),e.setTransform(h/2,0,0,h/2,h/2,h/2),e.lineCap="round",e.lineJoin="round";let p=o.lookX*.075,m=o.lookY*.06;if(o.blush>.01&&!a){let T=h*.018;e.save(),"filter"in e&&(e.filter=`blur(${T}px)`);for(let g of [-1,1]){let b=g*.52+p,c=.16+m,v=e.createRadialGradient(b,c,0,b,c,.16);v.addColorStop(0,s),v.addColorStop(1,"rgba(0,0,0,0)"),e.globalAlpha=Math.min(1,o.blush)*.62,e.fillStyle=v,e.beginPath(),e.ellipse(b,c,.17,.12,0,0,Math.PI*2),e.fill();}e.restore();let f=Math.min(1,Math.max(0,(o.blush-.6)/.4));if(f>.01){e.save(),e.globalAlpha=f*.55,e.strokeStyle=s,e.lineWidth=.016,e.lineCap="round";for(let g of [-1,1]){let b=g*.52+p,c=.16+m;for(let v=-1;v<=1;v++){let P=b+v*.045;e.beginPath(),e.moveTo(P+.018,c-.035),e.lineTo(P-.018,c+.035),e.stroke();}}e.restore();}}e.fillStyle=i,e.strokeStyle=i,e.lineWidth=ge;let E=Math.min(1,o.happyEye+o.closedEye+o.xEye+o.heartEye),S=1-E;for(let T of [-1,1]){let f=T*st+p,g=nt+m,b=at*o.eyeSize;if(S>.01){e.globalAlpha=S;let c=Math.max(.06,o.eyeOpen*t),v=be*o.eyeSize*c;if(e.save(),o.lidCover>.01||o.lidTilt>.01){let W=g-be*o.eyeSize+2*be*o.eyeSize*o.lidCover;e.translate(f,W),e.rotate(T*o.lidTilt*.6),e.beginPath(),e.rect(-1,0,2,2),e.clip(),e.rotate(-T*o.lidTilt*.6),e.translate(-f,-W);}n>.5&&!a&&Oe(e,f,g,b*2.1,v*1.9,i,.35*S);let P=e.createRadialGradient(f,g-v*.2,0,f,g,Math.max(b,v));if(P.addColorStop(0,u),P.addColorStop(1,i),e.fillStyle=P,e.beginPath(),e.ellipse(f,g,b,v,0,0,Math.PI*2),e.fill(),e.fillStyle=i,c>.35&&!a){let F=Math.max(-1,Math.min(1,o.lookX)),W=Math.max(-1,Math.min(1,o.lookY)),ue=r==="#fff"?.3:.34;e.globalAlpha=S*Math.min(1,(c-.35)*3),e.fillStyle=r,e.beginPath(),e.arc(f-b*.1+F*b*.5,g-v*.16+W*v*.42,b*ue,0,Math.PI*2),e.fill(),e.fillStyle=i;}e.restore();}if(n>.5&&!a&&E>.01&&Oe(e,f,g,b*2,b*1.8,i,.3*E),e.fillStyle=i,o.happyEye>.01){let c=.6+.4*o.happyEye;e.globalAlpha=Math.min(1,o.happyEye),e.beginPath(),e.arc(f,g+.045,b*1.15*c,Math.PI*1.12,Math.PI*1.88),e.stroke();}if(o.closedEye>.01){let c=.6+.4*o.closedEye;e.globalAlpha=Math.min(1,o.closedEye),e.beginPath(),e.moveTo(f-b*1.15*c,g+.01),e.quadraticCurveTo(f,g+.07*c,f+b*1.15*c,g+.01),e.stroke();}if(o.xEye>.01){let c=b*.95*(.6+.4*o.xEye);e.globalAlpha=Math.min(1,o.xEye),e.beginPath(),e.moveTo(f-c,g-c),e.lineTo(f+c,g+c),e.moveTo(f+c,g-c),e.lineTo(f-c,g+c),e.stroke();}o.heartEye>.01&&(e.globalAlpha=Math.min(1,o.heartEye),Me(e,f,g,b*1.35*(.5+.5*o.heartEye)),e.fill());}let w=p+o.mouthSkew*.07,k=rt+m,C=Math.min(1,Math.max(0,o.mouthRound)),L=o.mouthW,B=e.createLinearGradient(w-L-.02,k,w+L+.02,k);B.addColorStop(0,d),B.addColorStop(.5,u),B.addColorStop(1,d);let A=(T,f,g,b)=>{e.fillStyle=l,T(),e.fill(),f>.02&&!a&&(e.save(),T(),e.clip(),e.fillStyle=s,e.globalAlpha*=Math.min(1,(f-.02)*12),e.beginPath(),e.ellipse(w,g,b,f*.55,0,0,Math.PI*2),e.fill(),e.restore()),e.strokeStyle=B;let c=e.lineWidth;e.lineWidth=c*.6,T(),e.stroke(),e.lineWidth=c;};if(C<.99){e.globalAlpha=1-C;let T=18,f=v=>o.mouthCurve*.075*(1-v*v),g=(v,P)=>{let F=v/T*2-1,W=w+F*L,ue=k+f(F)+o.mouthSkew*F*.03+o.mouthWave*.018*Math.sin((F+1)*Math.PI*2)+P*(1-F*F);return [W,ue]},b=Math.max(0,o.mouthOpen),c=()=>{for(let v=0;v<=T;v++){let[P,F]=g(v,-b*.15);v?e.lineTo(P,F):e.moveTo(P,F);}};b>.003?A(()=>{e.beginPath(),c();for(let P=T;P>=0;P--){let[F,W]=g(P,b);e.lineTo(F,W);}e.closePath();},b,g(T/2,b)[1],L*.55):(e.strokeStyle=B,e.beginPath(),c(),e.stroke());}if(C>.01){e.globalAlpha=C;let T=Math.max(.02,o.mouthOpen*.55+.01),f=()=>{e.beginPath(),e.ellipse(w,k+.01,T*.85,T,0,0,Math.PI*2);};e.lineWidth=ge*.8,A(f,o.mouthOpen,k+.01+T*.8,T*.6),e.lineWidth=ge;}e.globalAlpha=1;}function Oe(e,o,t,i,s,n,u){let r=e.createRadialGradient(o,t,0,o,t,1);r.addColorStop(0,n),r.addColorStop(1,"rgba(0,0,0,0)"),e.save(),e.globalAlpha=u,e.translate(o,t),e.scale(i,s),e.translate(-o,-t),e.fillStyle=r,e.beginPath(),e.arc(o,t,1,0,Math.PI*2),e.fill(),e.restore();}function Me(e,o,t,i){e.beginPath(),e.moveTo(o,t+i*.85),e.bezierCurveTo(o-i*1.25,t+i*.05,o-i*.75,t-i*.95,o,t-i*.35),e.bezierCurveTo(o+i*.75,t-i*.95,o+i*1.25,t+i*.05,o,t+i*.85),e.closePath();}var Z=()=>({y:0,rx:0,ry:0,rz:0,st:0,mouth:0,lookX:0,lookY:0}),{sin:M,cos:ht,abs:lt,max:se,exp:ct,PI:ne}=Math;function ae(e,o,t,i){switch(i.y=i.rx=i.ry=i.rz=i.st=i.mouth=i.lookX=i.lookY=0,e){case "idle":{let s=M(o*1.6);i.y=.015*s,i.st=.018*s;break}case "thinking":{i.rz=.07*M(o*1.1),i.y=.02*M(o*2.2),i.ry=.15,i.rx=-0.06;break}case "loading":{let s=o*2.4;i.rx=.12*M(s),i.rz=.12*ht(s),i.ry=.22*M(s),i.y=.02*M(s*2),i.lookX=.55*M(s);break}case "listening":{let s=se(0,M(o*3.2));i.rx=.09*s*s;let n=lt(M(o*7.1)*.5+M(o*11.3)*.3+M(o*3.7)*.2);i.st=.03*n;break}case "speaking":{let s=se(0,M(o*9)*.6+M(o*14.3)*.4)*(.65+.35*M(o*1.7));i.mouth=.11*s,i.st=.04*s,i.rz=.03*M(o*2.1);break}case "happy":{let s=o*1.35%1;i.y=.2*M(ne*s);let n=se(0,1-s/.14)+se(0,(s-.9)/.1);i.st=.08*M(ne*s)-.14*n,i.rz=.05*M(o*1.35*ne);break}case "surprised":{if(t<.45){let s=M(ne*t/.45);i.y=.16*s,i.st=.12*s;}i.rz=.01*M(o*38)*ct(-t*2),i.rx=-0.06;break}case "sad":{let s=M(o*1.1);i.y=-0.06,i.rx=.2,i.st=-0.04+.015*s,i.rz=-0.04;break}case "error":{let s=t%2.8;if(s<.55){let n=1-s/.55;i.ry=.26*M(s*42)*n,i.rz=.05*M(s*42+1)*n;}i.st=-0.02;break}case "sleeping":{let s=M(o*1);i.st=.04*s,i.y=-0.03,i.rz=.1,i.rx=.1;break}case "love":{i.y=.07+.06*M(o*1.6),i.rz=.05*M(o*.8),i.st=.015*M(o*1.6+1);break}}return i}function we(e,o,t,i){for(let s of Object.keys(i))i[s]=e[s]+(o[s]-e[s])*t;return i}var Ge={thinking:"dots",sleeping:"zz",love:"hearts",listening:"waves",surprised:"bang"};var K=new Set,x=null,$=0,V=0,re=0,Ce,De=false,j="idle",_={x:0,y:0,lastMove:-1e9,known:false},O={reducedMotion:false,lowPower:false};function dt(){if(De)return;De=true,addEventListener("pointermove",o=>{_.x=o.clientX,_.y=o.clientY,_.lastMove=performance.now(),_.known=true;},{passive:true}),document.addEventListener("visibilitychange",H);let e=matchMedia("(prefers-reduced-motion: reduce)");O.reducedMotion=e.matches,e.addEventListener?.("change",o=>O.reducedMotion=o.matches);}function Ie(e,o){return x||(x=new three.WebGLRenderer({antialias:true,alpha:true,powerPreference:"low-power",preserveDrawingBuffer:true}),x.setPixelRatio(1),x.setClearColor(0,0),O.lowPower=pt(x.getContext()),x.setScissorTest(true),x.domElement.addEventListener("webglcontextlost",t=>{t.preventDefault(),x?.dispose(),x=null,$=V=0,j="idle";})),(e>$||o>V)&&($=Math.max($,e),V=Math.max(V,o),x.setSize($,V,false)),x}var qe=()=>V;function pt(e){try{let o=e.getExtension("WEBGL_debug_renderer_info"),t=String(e.getParameter(o?o.UNMASKED_RENDERER_WEBGL:e.RENDERER));return /swiftshader|llvmpipe|softpipe|software|basic render/i.test(t)}catch{return false}}function We(e,o){if(j==="ready")return true;if(j==="idle"&&x){j="compiling";let t=x;t.compileAsync(e,o).catch(()=>{}).then(()=>{t===x&&(j="ready"),H();});}return false}function _e(e){dt(),clearTimeout(Ce),K.add(e),H();}function He(e){K.delete(e),K.size===0&&(clearTimeout(Ce),Ce=setTimeout(()=>{K.size||!x||(x.dispose(),x.forceContextLoss(),x=null,$=V=0,j="idle");},1500));}function H(){if(!re){for(let e of K)if(e.active){re=requestAnimationFrame(Ne);return}}}var mt=10,Ye=new WeakMap,ke=0;function Ne(e){re=0;let o=[...K].filter(n=>n.active);if(!o.length)return;let t=performance.now(),i=o.length,s=0;for(;s<i;s++){let n=o[(ke+s)%i],u=Ye.get(n)??e-16;if(Ye.set(n,e),n.tick(Math.min(.05,Math.max(0,(e-u)/1e3)),e),performance.now()-t>mt){s++;break}}ke=(ke+s)%i,re=requestAnimationFrame(Ne);}var Q={pebble:{faceY:.02,faceScale:1.3,animated:false},blob:{faceY:.02,faceScale:1.28,animated:true},drop:{faceY:-0.24,faceScale:1.22,animated:false},bean:{faceY:.14,faceScale:.92,animated:false},cube:{faceY:0,faceScale:1.22,animated:false},ghost:{faceY:.22,faceScale:1.24,animated:true}};function Ve(e){let o=new three.SphereGeometry(1,e*2,Math.round(e*1.5)),t=o.getAttribute("position"),i=o.getIndex(),s=new Map,n=[],u=new Uint32Array(t.count);for(let a=0;a<t.count;a++){let h=t.getX(a),p=t.getY(a),m=t.getZ(a),E=`${Math.round(h*1e4)},${Math.round(p*1e4)},${Math.round(m*1e4)}`,S=s.get(E);if(S===void 0){S=n.length/3,s.set(E,S);let w=Math.hypot(h,p,m)||1;n.push(h/w,p/w,m/w);}u[a]=S;}let r=[];for(let a=0;a<i.count;a+=3){let h=u[i.getX(a)],p=u[i.getX(a+1)],m=u[i.getX(a+2)];h!==p&&p!==m&&h!==m&&r.push(h,p,m);}o.dispose();let l=new three.BufferGeometry,d=new Float32Array(n);return l.setAttribute("position",new three.BufferAttribute(new Float32Array(d),3)),l.setIndex(r),{geometry:l,dirs:d}}var vt=(e,o,t)=>{let i=Math.min(1,Math.max(0,(t-e)/(o-e)));return i*i*(3-2*i)};function Se(e,o,t,i,s,n,u){let r=o,l=t,d=i;switch(e){case "pebble":{r=o*1.1+.04*t,l=t*.92*(.95+.05*Math.tanh(3*t))+.03*o,d=i*.94;break}case "blob":{let a=.97+.045*Math.sin(2.1*o+1.3*s)*Math.sin(2.4*t+1.7*s+1)+.035*Math.sin(2.7*i+2.3*o+1.1*s);r=o*a,l=t*a,d=i*a;break}case "drop":{let a=Math.max(t,0),h=1-.8*Math.pow(a,1.6);r=o*h*.98+.1*a*a*a,l=(t<0?t*.9:t*1.32)-.12,d=i*h*.98;break}case "bean":{let a=t*.78+.42*Math.tanh(t*3);r=(o*.8+.14*(a*a/1.44)-.07)*.9,l=a*.88,d=i*.8*.9;break}case "cube":{let h=Math.pow(Math.pow(Math.abs(o),4.5)+Math.pow(Math.abs(t),4.5)+Math.pow(Math.abs(i),4.5),-0.2222222222222222);r=o*h*.84,l=t*h*.82,d=i*h*.84;break}case "ghost":{if(t>=0)r=o,l=t,d=i;else {let h=(Math.acos(Math.max(-1,t))-Math.PI/2)/(Math.PI/2),p=Math.hypot(o,i)||1,m=o/p,E=i/p,S=Math.atan2(i,o),w=.085*Math.sin(5*S+2.2*s),k=1.04,C=.13,L=-1.05+w,B;if(h<.45){let A=h/.45;B=1+.04*A,l=-A*(1.05-C)+w*vt(.45,1,A);}else if(h<.75){let A=(h-.45)/.3*(Math.PI/2);B=k-C+C*Math.cos(A),l=L+C-C*Math.sin(A);}else {let A=(h-.75)/.25;B=(k-C)*(1-A),l=L+.22*A*A*(3-2*A);}r=m*B,d=E*B;}r*=.9,l=(l+.1)*.9,d*=.9;break}}n[u]=r,n[u+1]=l,n[u+2]=d;}var I=null,he=null;function yt(){if(typeof window>"u"||!("AudioContext"in window))return null;if(Mt(),!I){I=new AudioContext;let e=I.createBiquadFilter();e.type="lowpass",e.frequency.value=3200,he=I.createGain(),he.gain.value=.55,he.connect(e).connect(I.destination);}return I.state==="suspended"&&I.resume(),I}function z(e,{freq:o,to:t,at:i=0,dur:s=.12,type:n="sine",gain:u=.1,wobble:r=0}){let l=e.currentTime+i,d=e.createOscillator(),a=e.createGain();if(d.type=n,d.frequency.setValueAtTime(o,l),t&&d.frequency.exponentialRampToValueAtTime(t,l+s),r){let h=e.createOscillator(),p=e.createGain();h.frequency.value=7,p.gain.value=r,h.connect(p).connect(d.frequency),h.start(l),h.stop(l+s+.05);}a.gain.setValueAtTime(1e-4,l),a.gain.exponentialRampToValueAtTime(u,l+Math.min(.012,s/4)),a.gain.exponentialRampToValueAtTime(1e-4,l+s),d.connect(a).connect(he),d.start(l),d.stop(l+s+.02);}var Te={idle:e=>z(e,{freq:520,to:780,dur:.09,gain:.08}),thinking:e=>[660,760,900].forEach((o,t)=>z(e,{freq:o,to:o*1.08,at:t*.1,dur:.07,type:"triangle",gain:.06})),loading:e=>[0,.14,.28].forEach(o=>z(e,{freq:940,at:o,dur:.04,gain:.05})),listening:e=>{z(e,{freq:523,dur:.12,type:"triangle",gain:.07}),z(e,{freq:784,at:.1,dur:.22,type:"triangle",gain:.07});},speaking:e=>[380,460,340,520,420].forEach((o,t)=>z(e,{freq:o,to:o*1.15,at:t*.075,dur:.06,type:"triangle",gain:.06})),happy:e=>[523,659,784,1047].forEach((o,t)=>z(e,{freq:o,at:t*.07,dur:.14,type:"triangle",gain:.07})),surprised:e=>z(e,{freq:280,to:980,dur:.18,gain:.09,wobble:30}),sad:e=>{z(e,{freq:560,to:300,dur:.5,gain:.07}),z(e,{freq:420,to:240,at:.12,dur:.5,gain:.04});},error:e=>[0,.14].forEach(o=>z(e,{freq:170,to:150,at:o,dur:.1,type:"sawtooth",gain:.045})),sleeping:e=>{z(e,{freq:150,to:115,dur:.6,gain:.07,wobble:6}),z(e,{freq:300,to:230,at:.05,dur:.5,gain:.02});},love:e=>[1319,1568,2093,1760].forEach((o,t)=>z(e,{freq:o,at:t*.08,dur:.22,gain:.04}))},q=null,Xe=false;function Mt(){if(Xe)return;Xe=true;let e=()=>{I&&I.resume().then(()=>{q&&performance.now()<q.until&&Te[q.mood](I),q=null;});};for(let o of ["pointerdown","touchend","keydown"])addEventListener(o,e,{passive:true});}function le(e,o=false){let t=yt();if(t){if(t.state==="running"){q=null,Te[e](t);return}q={mood:e,until:performance.now()+(o?6e3:1200)},t.resume().then(()=>{q&&performance.now()<q.until&&Te[q.mood](t),q=null;});}}var Ee=-0.85,Je=new Map;function Et(e){let o=Je.get(e);if(!o){let{geometry:t,dirs:i}=Ve(e);o={dirs:i,index:new Uint32Array(t.getIndex().array)},t.dispose(),Je.set(e,o);}return o}var U=(e,o)=>1-Math.exp(-e*o),Pe=e=>1-Math.pow(1-e,3),ce=class{constructor(){this.scene=new three.Scene;this.camera=new three.PerspectiveCamera(30,1,.1,50);this.group=new three.Group;this.v=new three.Vector3;this.geometry=new three.BufferGeometry;this.faceCanvas=document.createElement("canvas");this.heightCanvas=document.createElement("canvas");this.uniforms={uFace:{value:null},uHeight:{value:null},uFaceY:{value:0},uFaceScale:{value:1.5}};this.state={...y};this.visible=false;this.connected=false;this.w=0;this.h=0;this.t=Math.random()*100;this.shapeFrom=y.shape;this.shapeTo=y.shape;this.morph=1;this.shapeDirty=true;this.shown=y.mood;this.prevShown=y.mood;this.tau=10;this.prevTau=10;this.blend=1;this.reaction=null;this.pose=Z();this.poseIdle=Z();this.moodTime=0;this.poseA=Z();this.poseB=Z();this.face=ve(ie.idle);this.target=ve(ie.idle);this.drawn=new Float32Array(J.length+7).fill(NaN);this.blink=1;this.blinkT=-1;this.nextBlink=2+Math.random()*3;this.body=X(y.color,[.95,.63,.48]);this.bodyT=this.body;this.faceC=te(this.body);this.faceCT=this.faceC;this.cheek=oe(this.body);this.cheekT=this.cheek;this.look={x:0,y:0};this.wander={x:0,y:0,next:0};this.squash=0;this.squashV=0;this.pop=.6;this.popV=0;this.hover=0;this.hovering=false;this.overlay={dots:0,zz:0,hearts:0,waves:0,bang:0};this.needsFrame=true;this.ready=false;this.css=[0,0];this.quality=1;this.lowPowerApplied=false;this.cost=0;this.costFrames=0;this.lastFrame=[];this.canvas=document.createElement("canvas"),this.ctx=this.canvas.getContext("2d"),this.faceCtx=this.faceCanvas.getContext("2d"),this.faceCanvas.width=this.faceCanvas.height=256,this.faceTex=new three.CanvasTexture(this.faceCanvas),this.faceTex.colorSpace=three.SRGBColorSpace,this.faceTex.minFilter=three.LinearMipmapLinearFilter,this.faceTex.anisotropy=4,this.uniforms.uFace.value=this.faceTex,this.heightCtx=this.heightCanvas.getContext("2d"),this.heightCanvas.width=this.heightCanvas.height=256,this.heightTex=new three.CanvasTexture(this.heightCanvas),this.heightTex.minFilter=three.LinearMipmapLinearFilter,this.uniforms.uHeight.value=this.heightTex,this.setSegments(24),this.material=this.createMaterial(),this.mesh=new three.Mesh(this.geometry,this.material),this.mesh.frustumCulled=false,this.mesh.position.y=-Ee,this.group.add(this.mesh),this.scene.add(this.group),this.scene.add(new three.HemisphereLight(16774120,7234140,1.7));let o=new three.DirectionalLight(16777215,1.9);o.position.set(2.5,3.5,4);let t=new three.DirectionalLight(16770770,1.4);t.position.set(-3.5,2,-3);let i=new three.DirectionalLight(16773350,.45);i.position.set(-2,-1,3),this.scene.add(o,t,i),this.camera.position.set(0,.3,6.6),this.camera.lookAt(0,.12,0);}get active(){return this.visible&&this.connected&&this.w>0}createMaterial(){let o=new three.MeshStandardMaterial({roughness:.62,metalness:0});return o.color.setRGB(...this.body,three.SRGBColorSpace),o.customProgramCacheKey=()=>"moodi-1",o.onBeforeCompile=t=>{Object.assign(t.uniforms,this.uniforms),t.vertexShader=t.vertexShader.replace("#include <common>",`#include <common>
1
+ 'use strict';var three=require('three');var Qe=["ghost","pebble","blob","drop","bean","cube"],et=["idle","thinking","loading","listening","speaking","happy","surprised","sad","error","sleeping","love"],y={shape:"ghost",mood:"idle",color:"#2b15d1",size:160,speed:1,followCursor:true,interactive:true,shadow:true,sound:false,settle:0},Ot={Iris:"#2b15d1",Peach:"#f2a07b",Sage:"#8fb996",Sky:"#8ec5e8",Lilac:"#b9a3e3",Butter:"#f3d36b",Coral:"#f07167",Ink:"#2b2d42",Cloud:"#ecebe8"},Lt={idle:{label:"Idle",description:"Breathing softly. Blinks now and then."},thinking:{label:"Thinking",description:"Eyes drift up. Little thoughts pop."},loading:{label:"Loading",description:"Half-lidded, wobbling patiently."},listening:{label:"Listening",description:"All eyes. Nods along to every word."},speaking:{label:"Speaking",description:"Chatty mouth, bouncing to the rhythm."},happy:{label:"Happy",description:"Bounces with joy. Cheeks glow."},surprised:{label:"Surprised",description:"Wide eyes, tiny o. Did not see that coming."},sad:{label:"Sad",description:"Slumps a little. Needs a minute."},error:{label:"Error",description:"Something broke. Shakes it off."},sleeping:{label:"Sleeping",description:"Deep, slow breaths. Do not disturb."},love:{label:"Love",description:"Heart eyes, floating on air."}},Gt={pebble:"Pebble",blob:"Blob",drop:"Drop",bean:"Bean",cube:"Cube",ghost:"Ghost"},pe=e=>Qe.includes(e),J=e=>et.includes(e);var G=null;function X(e,o){if(!e)return o;let t=/^#?([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(e.trim());if(t)return Be(t[1]);if(G||(G=document.createElement("canvas").getContext("2d")),!G)return o;G.fillStyle="#010203",G.fillStyle=e;let i=String(G.fillStyle);if(i==="#010203"&&e.trim()!=="#010203")return o;if(i.startsWith("#"))return Be(i.slice(1));G.canvas.width=G.canvas.height=1,G.clearRect(0,0,1,1),G.fillRect(0,0,1,1);let s=G.getImageData(0,0,1,1).data;return [s[0]/255,s[1]/255,s[2]/255]}function Be(e){e.length===3&&(e=e[0]+e[0]+e[1]+e[1]+e[2]+e[2]);let o=parseInt(e,16);return [(o>>16&255)/255,(o>>8&255)/255,(o&255)/255]}var D=e=>`rgb(${Math.round(e[0]*255)},${Math.round(e[1]*255)},${Math.round(e[2]*255)})`,R=(e,o,t)=>[e[0]+(o[0]-e[0])*t,e[1]+(o[1]-e[1])*t,e[2]+(o[2]-e[2])*t],me=e=>e<=.04045?e/12.92:Math.pow((e+.055)/1.055,2.4),fe=e=>.2126*me(e[0])+.7152*me(e[1])+.0722*me(e[2]),tt=[.07,.06,.08],ot=[209/255,190/255,173/255],it=[1,.42,.48],oe=e=>fe(e)>.042?R(tt,e,.06):ot,ie=e=>R(e,it,.78);var Z=["eyeOpen","eyeSize","lookX","lookY","lidCover","lidTilt","happyEye","closedEye","xEye","heartEye","mouthW","mouthCurve","mouthOpen","mouthRound","mouthSkew","mouthWave","blush"],Y={eyeOpen:1,eyeSize:1,lookX:0,lookY:0,lidCover:0,lidTilt:0,happyEye:0,closedEye:0,xEye:0,heartEye:0,mouthW:.1,mouthCurve:.35,mouthOpen:0,mouthRound:0,mouthSkew:0,mouthWave:0,blush:.45},se={idle:{...Y},thinking:{...Y,eyeOpen:.92,lookX:.7,lookY:-0.8,lidCover:.12,mouthW:.065,mouthCurve:0,mouthSkew:.8,blush:.3},loading:{...Y,lidCover:.48,mouthW:.06,mouthCurve:.12,blush:.3},listening:{...Y,eyeOpen:1.12,eyeSize:1.16,mouthW:.06,mouthCurve:.2,mouthOpen:.02},speaking:{...Y,mouthW:.09,mouthCurve:.25},happy:{...Y,happyEye:1,mouthW:.13,mouthCurve:1,mouthOpen:.08,blush:1},surprised:{...Y,eyeOpen:1.25,eyeSize:1.22,mouthW:.06,mouthCurve:0,mouthOpen:.12,mouthRound:1,blush:.35},sad:{...Y,eyeOpen:.95,lidCover:.32,lidTilt:.5,lookY:.45,mouthW:.08,mouthCurve:-0.75,blush:.2},error:{...Y,xEye:1,mouthW:.1,mouthCurve:-0.2,mouthWave:1,blush:.15},sleeping:{...Y,closedEye:1,mouthW:.04,mouthCurve:0,mouthOpen:.035,mouthRound:.7,blush:.55},love:{...Y,heartEye:1,mouthW:.11,mouthCurve:.9,mouthOpen:.03,blush:1}},Le={idle:1,thinking:.15,loading:0,listening:1,speaking:.9,happy:.6,surprised:.8,sad:.3,error:.3,sleeping:0,love:.7},ve=e=>({...e}),st=.31,nt=-0.04,at=.098,be=.128,rt=.2,ge=.05;function ye(e,o,t,i,s,n,u,r,l,d,a=false){let h=e.canvas.width;e.setTransform(1,0,0,1,0,0),e.clearRect(0,0,h,h),e.setTransform(h/2,0,0,h/2,h/2,h/2),e.lineCap="round",e.lineJoin="round";let p=o.lookX*.075,m=o.lookY*.06;if(o.blush>.01&&!a){let T=h*.018;e.save(),"filter"in e&&(e.filter=`blur(${T}px)`);for(let g of [-1,1]){let b=g*.52+p,c=.16+m,v=e.createRadialGradient(b,c,0,b,c,.16);v.addColorStop(0,s),v.addColorStop(1,"rgba(0,0,0,0)"),e.globalAlpha=Math.min(1,o.blush)*.62,e.fillStyle=v,e.beginPath(),e.ellipse(b,c,.17,.12,0,0,Math.PI*2),e.fill();}e.restore();let f=Math.min(1,Math.max(0,(o.blush-.6)/.4));if(f>.01){e.save(),e.globalAlpha=f*.55,e.strokeStyle=s,e.lineWidth=.016,e.lineCap="round";for(let g of [-1,1]){let b=g*.52+p,c=.16+m;for(let v=-1;v<=1;v++){let P=b+v*.045;e.beginPath(),e.moveTo(P+.018,c-.035),e.lineTo(P-.018,c+.035),e.stroke();}}e.restore();}}e.fillStyle=i,e.strokeStyle=i,e.lineWidth=ge;let E=Math.min(1,o.happyEye+o.closedEye+o.xEye+o.heartEye),S=1-E;for(let T of [-1,1]){let f=T*st+p,g=nt+m,b=at*o.eyeSize;if(S>.01){e.globalAlpha=S;let c=Math.max(.06,o.eyeOpen*t),v=be*o.eyeSize*c;if(e.save(),o.lidCover>.01||o.lidTilt>.01){let W=g-be*o.eyeSize+2*be*o.eyeSize*o.lidCover;e.translate(f,W),e.rotate(T*o.lidTilt*.6),e.beginPath(),e.rect(-1,0,2,2),e.clip(),e.rotate(-T*o.lidTilt*.6),e.translate(-f,-W);}n>.5&&!a&&Oe(e,f,g,b*2.1,v*1.9,i,.35*S);let P=e.createRadialGradient(f,g-v*.2,0,f,g,Math.max(b,v));if(P.addColorStop(0,u),P.addColorStop(1,i),e.fillStyle=P,e.beginPath(),e.ellipse(f,g,b,v,0,0,Math.PI*2),e.fill(),e.fillStyle=i,c>.35&&!a){let F=Math.max(-1,Math.min(1,o.lookX)),W=Math.max(-1,Math.min(1,o.lookY)),de=r==="#fff"?.3:.34;e.globalAlpha=S*Math.min(1,(c-.35)*3),e.fillStyle=r,e.beginPath(),e.arc(f-b*.1+F*b*.5,g-v*.16+W*v*.42,b*de,0,Math.PI*2),e.fill(),e.fillStyle=i;}e.restore();}if(n>.5&&!a&&E>.01&&Oe(e,f,g,b*2,b*1.8,i,.3*E),e.fillStyle=i,o.happyEye>.01){let c=.6+.4*o.happyEye;e.globalAlpha=Math.min(1,o.happyEye),e.beginPath(),e.arc(f,g+.045,b*1.15*c,Math.PI*1.12,Math.PI*1.88),e.stroke();}if(o.closedEye>.01){let c=.6+.4*o.closedEye;e.globalAlpha=Math.min(1,o.closedEye),e.beginPath(),e.moveTo(f-b*1.15*c,g+.01),e.quadraticCurveTo(f,g+.07*c,f+b*1.15*c,g+.01),e.stroke();}if(o.xEye>.01){let c=b*.95*(.6+.4*o.xEye);e.globalAlpha=Math.min(1,o.xEye),e.beginPath(),e.moveTo(f-c,g-c),e.lineTo(f+c,g+c),e.moveTo(f+c,g-c),e.lineTo(f-c,g+c),e.stroke();}o.heartEye>.01&&(e.globalAlpha=Math.min(1,o.heartEye),Me(e,f,g,b*1.35*(.5+.5*o.heartEye)),e.fill());}let w=p+o.mouthSkew*.07,k=rt+m,C=Math.min(1,Math.max(0,o.mouthRound)),L=o.mouthW,B=e.createLinearGradient(w-L-.02,k,w+L+.02,k);B.addColorStop(0,d),B.addColorStop(.5,u),B.addColorStop(1,d);let A=(T,f,g,b)=>{e.fillStyle=l,T(),e.fill(),f>.02&&!a&&(e.save(),T(),e.clip(),e.fillStyle=s,e.globalAlpha*=Math.min(1,(f-.02)*12),e.beginPath(),e.ellipse(w,g,b,f*.55,0,0,Math.PI*2),e.fill(),e.restore()),e.strokeStyle=B;let c=e.lineWidth;e.lineWidth=c*.6,T(),e.stroke(),e.lineWidth=c;};if(C<.99){e.globalAlpha=1-C;let T=18,f=v=>o.mouthCurve*.075*(1-v*v),g=(v,P)=>{let F=v/T*2-1,W=w+F*L,de=k+f(F)+o.mouthSkew*F*.03+o.mouthWave*.018*Math.sin((F+1)*Math.PI*2)+P*(1-F*F);return [W,de]},b=Math.max(0,o.mouthOpen),c=()=>{for(let v=0;v<=T;v++){let[P,F]=g(v,-b*.15);v?e.lineTo(P,F):e.moveTo(P,F);}};b>.003?A(()=>{e.beginPath(),c();for(let P=T;P>=0;P--){let[F,W]=g(P,b);e.lineTo(F,W);}e.closePath();},b,g(T/2,b)[1],L*.55):(e.strokeStyle=B,e.beginPath(),c(),e.stroke());}if(C>.01){e.globalAlpha=C;let T=Math.max(.02,o.mouthOpen*.55+.01),f=()=>{e.beginPath(),e.ellipse(w,k+.01,T*.85,T,0,0,Math.PI*2);};e.lineWidth=ge*.8,A(f,o.mouthOpen,k+.01+T*.8,T*.6),e.lineWidth=ge;}e.globalAlpha=1;}function Oe(e,o,t,i,s,n,u){let r=e.createRadialGradient(o,t,0,o,t,1);r.addColorStop(0,n),r.addColorStop(1,"rgba(0,0,0,0)"),e.save(),e.globalAlpha=u,e.translate(o,t),e.scale(i,s),e.translate(-o,-t),e.fillStyle=r,e.beginPath(),e.arc(o,t,1,0,Math.PI*2),e.fill(),e.restore();}function Me(e,o,t,i){e.beginPath(),e.moveTo(o,t+i*.85),e.bezierCurveTo(o-i*1.25,t+i*.05,o-i*.75,t-i*.95,o,t-i*.35),e.bezierCurveTo(o+i*.75,t-i*.95,o+i*1.25,t+i*.05,o,t+i*.85),e.closePath();}var Q=()=>({y:0,rx:0,ry:0,rz:0,st:0,mouth:0,lookX:0,lookY:0}),{sin:M,cos:ht,abs:lt,max:ne,exp:ct,PI:ae}=Math;function re(e,o,t,i){switch(i.y=i.rx=i.ry=i.rz=i.st=i.mouth=i.lookX=i.lookY=0,e){case "idle":{let s=M(o*1.6);i.y=.015*s,i.st=.018*s;break}case "thinking":{i.rz=.07*M(o*1.1),i.y=.02*M(o*2.2),i.ry=.15,i.rx=-0.06;break}case "loading":{let s=o*2.4;i.rx=.12*M(s),i.rz=.12*ht(s),i.ry=.22*M(s),i.y=.02*M(s*2),i.lookX=.55*M(s);break}case "listening":{let s=ne(0,M(o*3.2));i.rx=.09*s*s;let n=lt(M(o*7.1)*.5+M(o*11.3)*.3+M(o*3.7)*.2);i.st=.03*n;break}case "speaking":{let s=ne(0,M(o*9)*.6+M(o*14.3)*.4)*(.65+.35*M(o*1.7));i.mouth=.11*s,i.st=.04*s,i.rz=.03*M(o*2.1);break}case "happy":{let s=o*1.35%1;i.y=.2*M(ae*s);let n=ne(0,1-s/.14)+ne(0,(s-.9)/.1);i.st=.08*M(ae*s)-.14*n,i.rz=.05*M(o*1.35*ae);break}case "surprised":{if(t<.45){let s=M(ae*t/.45);i.y=.16*s,i.st=.12*s;}i.rz=.01*M(o*38)*ct(-t*2),i.rx=-0.06;break}case "sad":{let s=M(o*1.1);i.y=-0.06,i.rx=.2,i.st=-0.04+.015*s,i.rz=-0.04;break}case "error":{let s=t%2.8;if(s<.55){let n=1-s/.55;i.ry=.26*M(s*42)*n,i.rz=.05*M(s*42+1)*n;}i.st=-0.02;break}case "sleeping":{let s=M(o*1);i.st=.04*s,i.y=-0.03,i.rz=.1,i.rx=.1;break}case "love":{i.y=.07+.06*M(o*1.6),i.rz=.05*M(o*.8),i.st=.015*M(o*1.6+1);break}}return i}function we(e,o,t,i){for(let s of Object.keys(i))i[s]=e[s]+(o[s]-e[s])*t;return i}var Ge={thinking:"dots",sleeping:"zz",love:"hearts",listening:"waves",surprised:"bang"};var K=new Set,x=null,$=0,V=0,he=0,Ce,De=false,j="idle",_={x:0,y:0,lastMove:-1e9,known:false},O={reducedMotion:false,lowPower:false};function dt(){if(De)return;De=true,addEventListener("pointermove",o=>{_.x=o.clientX,_.y=o.clientY,_.lastMove=performance.now(),_.known=true;},{passive:true}),document.addEventListener("visibilitychange",H);let e=matchMedia("(prefers-reduced-motion: reduce)");O.reducedMotion=e.matches,e.addEventListener?.("change",o=>O.reducedMotion=o.matches);}function Ie(e,o){return x||(x=new three.WebGLRenderer({antialias:true,alpha:true,powerPreference:"low-power",preserveDrawingBuffer:true}),x.setPixelRatio(1),x.setClearColor(0,0),O.lowPower=pt(x.getContext()),x.setScissorTest(true),x.domElement.addEventListener("webglcontextlost",t=>{t.preventDefault(),x?.dispose(),x=null,$=V=0,j="idle";})),(e>$||o>V)&&($=Math.max($,e),V=Math.max(V,o),x.setSize($,V,false)),x}var qe=()=>V;function pt(e){try{let o=e.getExtension("WEBGL_debug_renderer_info"),t=String(e.getParameter(o?o.UNMASKED_RENDERER_WEBGL:e.RENDERER));return /swiftshader|llvmpipe|softpipe|software|basic render/i.test(t)}catch{return false}}function We(e,o){if(j==="ready")return true;if(j==="idle"&&x){j="compiling";let t=x;t.compileAsync(e,o).catch(()=>{}).then(()=>{t===x&&(j="ready"),H();});}return false}function _e(e){dt(),clearTimeout(Ce),K.add(e),H();}function He(e){K.delete(e),K.size===0&&(clearTimeout(Ce),Ce=setTimeout(()=>{K.size||!x||(x.dispose(),x.forceContextLoss(),x=null,$=V=0,j="idle");},1500));}function H(){if(!he){for(let e of K)if(e.active){he=requestAnimationFrame(Ne);return}}}var mt=10,Ye=new WeakMap,ke=0;function Ne(e){he=0;let o=[...K].filter(n=>n.active);if(!o.length)return;let t=performance.now(),i=o.length,s=0;for(;s<i;s++){let n=o[(ke+s)%i],u=Ye.get(n)??e-16;if(Ye.set(n,e),n.tick(Math.min(.05,Math.max(0,(e-u)/1e3)),e),performance.now()-t>mt){s++;break}}ke=(ke+s)%i,he=requestAnimationFrame(Ne);}var ee={pebble:{faceY:.02,faceScale:1.3,animated:false},blob:{faceY:.02,faceScale:1.28,animated:true},drop:{faceY:-0.24,faceScale:1.22,animated:false},bean:{faceY:.14,faceScale:.92,animated:false},cube:{faceY:0,faceScale:1.22,animated:false},ghost:{faceY:.22,faceScale:1.24,animated:true}};function Ve(e){let o=new three.SphereGeometry(1,e*2,Math.round(e*1.5)),t=o.getAttribute("position"),i=o.getIndex(),s=new Map,n=[],u=new Uint32Array(t.count);for(let a=0;a<t.count;a++){let h=t.getX(a),p=t.getY(a),m=t.getZ(a),E=`${Math.round(h*1e4)},${Math.round(p*1e4)},${Math.round(m*1e4)}`,S=s.get(E);if(S===void 0){S=n.length/3,s.set(E,S);let w=Math.hypot(h,p,m)||1;n.push(h/w,p/w,m/w);}u[a]=S;}let r=[];for(let a=0;a<i.count;a+=3){let h=u[i.getX(a)],p=u[i.getX(a+1)],m=u[i.getX(a+2)];h!==p&&p!==m&&h!==m&&r.push(h,p,m);}o.dispose();let l=new three.BufferGeometry,d=new Float32Array(n);return l.setAttribute("position",new three.BufferAttribute(new Float32Array(d),3)),l.setIndex(r),{geometry:l,dirs:d}}var vt=(e,o,t)=>{let i=Math.min(1,Math.max(0,(t-e)/(o-e)));return i*i*(3-2*i)};function Se(e,o,t,i,s,n,u){let r=o,l=t,d=i;switch(e){case "pebble":{r=o*1.1+.04*t,l=t*.92*(.95+.05*Math.tanh(3*t))+.03*o,d=i*.94;break}case "blob":{let a=.97+.045*Math.sin(2.1*o+1.3*s)*Math.sin(2.4*t+1.7*s+1)+.035*Math.sin(2.7*i+2.3*o+1.1*s);r=o*a,l=t*a,d=i*a;break}case "drop":{let a=Math.max(t,0),h=1-.8*Math.pow(a,1.6);r=o*h*.98+.1*a*a*a,l=(t<0?t*.9:t*1.32)-.12,d=i*h*.98;break}case "bean":{let a=t*.78+.42*Math.tanh(t*3);r=(o*.8+.14*(a*a/1.44)-.07)*.9,l=a*.88,d=i*.8*.9;break}case "cube":{let h=Math.pow(Math.pow(Math.abs(o),4.5)+Math.pow(Math.abs(t),4.5)+Math.pow(Math.abs(i),4.5),-0.2222222222222222);r=o*h*.84,l=t*h*.82,d=i*h*.84;break}case "ghost":{if(t>=0)r=o,l=t,d=i;else {let h=(Math.acos(Math.max(-1,t))-Math.PI/2)/(Math.PI/2),p=Math.hypot(o,i)||1,m=o/p,E=i/p,S=Math.atan2(i,o),w=.085*Math.sin(5*S+2.2*s),k=1.04,C=.13,L=-1.05+w,B;if(h<.45){let A=h/.45;B=1+.04*A,l=-A*(1.05-C)+w*vt(.45,1,A);}else if(h<.75){let A=(h-.45)/.3*(Math.PI/2);B=k-C+C*Math.cos(A),l=L+C-C*Math.sin(A);}else {let A=(h-.75)/.25;B=(k-C)*(1-A),l=L+.22*A*A*(3-2*A);}r=m*B,d=E*B;}r*=.9,l=(l+.1)*.9,d*=.9;break}}n[u]=r,n[u+1]=l,n[u+2]=d;}var I=null,le=null;function yt(){if(typeof window>"u"||!("AudioContext"in window))return null;if(Mt(),!I){I=new AudioContext;let e=I.createBiquadFilter();e.type="lowpass",e.frequency.value=3200,le=I.createGain(),le.gain.value=.55,le.connect(e).connect(I.destination);}return I.state==="suspended"&&I.resume(),I}function z(e,{freq:o,to:t,at:i=0,dur:s=.12,type:n="sine",gain:u=.1,wobble:r=0}){let l=e.currentTime+i,d=e.createOscillator(),a=e.createGain();if(d.type=n,d.frequency.setValueAtTime(o,l),t&&d.frequency.exponentialRampToValueAtTime(t,l+s),r){let h=e.createOscillator(),p=e.createGain();h.frequency.value=7,p.gain.value=r,h.connect(p).connect(d.frequency),h.start(l),h.stop(l+s+.05);}a.gain.setValueAtTime(1e-4,l),a.gain.exponentialRampToValueAtTime(u,l+Math.min(.012,s/4)),a.gain.exponentialRampToValueAtTime(1e-4,l+s),d.connect(a).connect(le),d.start(l),d.stop(l+s+.02);}var Te={idle:e=>z(e,{freq:520,to:780,dur:.09,gain:.08}),thinking:e=>[660,760,900].forEach((o,t)=>z(e,{freq:o,to:o*1.08,at:t*.1,dur:.07,type:"triangle",gain:.06})),loading:e=>[0,.14,.28].forEach(o=>z(e,{freq:940,at:o,dur:.04,gain:.05})),listening:e=>{z(e,{freq:523,dur:.12,type:"triangle",gain:.07}),z(e,{freq:784,at:.1,dur:.22,type:"triangle",gain:.07});},speaking:e=>[380,460,340,520,420].forEach((o,t)=>z(e,{freq:o,to:o*1.15,at:t*.075,dur:.06,type:"triangle",gain:.06})),happy:e=>[523,659,784,1047].forEach((o,t)=>z(e,{freq:o,at:t*.07,dur:.14,type:"triangle",gain:.07})),surprised:e=>z(e,{freq:280,to:980,dur:.18,gain:.09,wobble:30}),sad:e=>{z(e,{freq:560,to:300,dur:.5,gain:.07}),z(e,{freq:420,to:240,at:.12,dur:.5,gain:.04});},error:e=>[0,.14].forEach(o=>z(e,{freq:170,to:150,at:o,dur:.1,type:"sawtooth",gain:.045})),sleeping:e=>{z(e,{freq:150,to:115,dur:.6,gain:.07,wobble:6}),z(e,{freq:300,to:230,at:.05,dur:.5,gain:.02});},love:e=>[1319,1568,2093,1760].forEach((o,t)=>z(e,{freq:o,at:t*.08,dur:.22,gain:.04}))},q=null,Xe=false;function Mt(){if(Xe)return;Xe=true;let e=()=>{I&&I.resume().then(()=>{q&&performance.now()<q.until&&Te[q.mood](I),q=null;});};for(let o of ["pointerdown","touchend","keydown"])addEventListener(o,e,{passive:true});}function ce(e,o=false){let t=yt();if(t){if(t.state==="running"){q=null,Te[e](t);return}q={mood:e,until:performance.now()+(o?6e3:1200)},t.resume().then(()=>{q&&performance.now()<q.until&&Te[q.mood](t),q=null;});}}var Ee=-0.85,Je=new Map;function Et(e){let o=Je.get(e);if(!o){let{geometry:t,dirs:i}=Ve(e);o={dirs:i,index:new Uint32Array(t.getIndex().array)},t.dispose(),Je.set(e,o);}return o}var U=(e,o)=>1-Math.exp(-e*o),Pe=e=>1-Math.pow(1-e,3),ue=class{constructor(){this.scene=new three.Scene;this.camera=new three.PerspectiveCamera(30,1,.1,50);this.group=new three.Group;this.v=new three.Vector3;this.geometry=new three.BufferGeometry;this.faceCanvas=document.createElement("canvas");this.heightCanvas=document.createElement("canvas");this.uniforms={uFace:{value:null},uHeight:{value:null},uFaceY:{value:0},uFaceScale:{value:1.5}};this.state={...y};this.visible=false;this.connected=false;this.w=0;this.h=0;this.t=Math.random()*100;this.shapeFrom=y.shape;this.shapeTo=y.shape;this.morph=1;this.shapeDirty=true;this.shown=y.mood;this.prevShown=y.mood;this.tau=10;this.prevTau=10;this.blend=1;this.reaction=null;this.pose=Q();this.poseIdle=Q();this.moodTime=0;this.poseA=Q();this.poseB=Q();this.face=ve(se.idle);this.target=ve(se.idle);this.drawn=new Float32Array(Z.length+7).fill(NaN);this.blink=1;this.blinkT=-1;this.nextBlink=2+Math.random()*3;this.body=X(y.color,[.95,.63,.48]);this.bodyT=this.body;this.faceC=oe(this.body);this.faceCT=this.faceC;this.cheek=ie(this.body);this.cheekT=this.cheek;this.look={x:0,y:0};this.wander={x:0,y:0,next:0};this.squash=0;this.squashV=0;this.pop=.6;this.popV=0;this.hover=0;this.hovering=false;this.overlay={dots:0,zz:0,hearts:0,waves:0,bang:0};this.needsFrame=true;this.ready=false;this.css=[0,0];this.quality=1;this.lowPowerApplied=false;this.cost=0;this.costFrames=0;this.lastFrame=[];this.canvas=document.createElement("canvas"),this.ctx=this.canvas.getContext("2d"),this.faceCtx=this.faceCanvas.getContext("2d"),this.faceCanvas.width=this.faceCanvas.height=256,this.faceTex=new three.CanvasTexture(this.faceCanvas),this.faceTex.colorSpace=three.SRGBColorSpace,this.faceTex.minFilter=three.LinearMipmapLinearFilter,this.faceTex.anisotropy=4,this.uniforms.uFace.value=this.faceTex,this.heightCtx=this.heightCanvas.getContext("2d"),this.heightCanvas.width=this.heightCanvas.height=256,this.heightTex=new three.CanvasTexture(this.heightCanvas),this.heightTex.minFilter=three.LinearMipmapLinearFilter,this.uniforms.uHeight.value=this.heightTex,this.setSegments(24),this.material=this.createMaterial(),this.mesh=new three.Mesh(this.geometry,this.material),this.mesh.frustumCulled=false,this.mesh.position.y=-Ee,this.group.add(this.mesh),this.scene.add(this.group),this.scene.add(new three.HemisphereLight(16774120,7234140,1.7));let o=new three.DirectionalLight(16777215,1.9);o.position.set(2.5,3.5,4);let t=new three.DirectionalLight(16770770,1.4);t.position.set(-3.5,2,-3);let i=new three.DirectionalLight(16773350,.45);i.position.set(-2,-1,3),this.scene.add(o,t,i),this.camera.position.set(0,.3,6.6),this.camera.lookAt(0,.12,0);}get active(){return this.visible&&this.connected&&this.w>0}createMaterial(){let o=new three.MeshStandardMaterial({roughness:.62,metalness:0});return o.color.setRGB(...this.body,three.SRGBColorSpace),o.customProgramCacheKey=()=>"moodi-1",o.onBeforeCompile=t=>{Object.assign(t.uniforms,this.uniforms),t.vertexShader=t.vertexShader.replace("#include <common>",`#include <common>
2
2
  varying vec3 vFaceP;
3
3
  varying vec3 vFaceN;
4
4
  varying vec3 vTanX;
@@ -41,9 +41,9 @@ outgoingLight *= mix(0.62, 1.0, smoothstep(-0.95, 0.35, normalize(vFaceN).y));
41
41
  // eyes and mouth glow a little: mostly unlit, so they read as light, not paint
42
42
  float emis = smoothstep(0.75, 1.0, fc.a) * inb * smoothstep(0.12, 0.45, normalize(vFaceN).z);
43
43
  outgoingLight = mix(outgoingLight, diffuseColor.rgb * 1.12, emis * 0.65);
44
- #include <opaque_fragment>`);},o}setSegments(o){let t=Et(o);this.dirs!==t.dirs&&(this.dirs=t.dirs,this.geometry.dispose(),this.geometry=new three.BufferGeometry,this.geometry.setAttribute("position",new three.BufferAttribute(new Float32Array(t.dirs.length),3)),this.geometry.setIndex(new three.BufferAttribute(t.index,1)),this.mesh&&(this.mesh.geometry=this.geometry),this.shapeDirty=true);}connect(){this.connected=true,_e(this);}disconnect(){this.connected=false,He(this);}setVisible(o){this.visible=o,o&&H();}resize(o,t){this.css=[o,t];let i=(O.lowPower?1:Math.min(2,devicePixelRatio||1))*this.quality,s=Math.max(1,Math.round(o*i)),n=Math.max(1,Math.round(t*i));if(s===this.w&&n===this.h)return;this.w=this.canvas.width=s,this.h=this.canvas.height=n;let u=Math.min(s,n),r=Math.min(o,t);this.camera.position.set(0,.3,r<90?5.1:6.1),this.camera.lookAt(0,r<90?.02:.12,0),this.camera.aspect=s/n,this.camera.updateProjectionMatrix(),this.setSegments(u<160?16:u<400?24:32);let l=u<220?256:512;this.faceCanvas.width!==l&&(this.faceCanvas.width=this.faceCanvas.height=l,this.faceTex.dispose(),this.drawn.fill(NaN)),this.needsFrame=true,H();}update(o){let t=this.state;this.state={...t,...o};let i=this.state;i.shape!==this.shapeTo&&(this.shapeFrom=this.shapeTo,this.shapeTo=i.shape,this.morph=0,O.reducedMotion||(this.squashV-=2.2)),(i.color!==t.color||i.faceColor!==t.faceColor||i.cheekColor!==t.cheekColor)&&(this.bodyT=X(i.color,X(y.color,this.bodyT)),this.faceCT=i.faceColor?X(i.faceColor,te(this.bodyT)):te(this.bodyT),this.cheekT=i.cheekColor?X(i.cheekColor,oe(this.bodyT)):oe(this.bodyT)),i.mood!==t.mood&&!this.reaction&&this.show(i.mood),i.sound&&!t.sound&&this.ready&&le(this.shown),this.needsFrame=true,H();}bump(o=1){O.reducedMotion||(this.squashV-=1.6*o,this.needsFrame=true,H());}react(o,t=1200){this.reaction={mood:o,left:t/1e3},this.show(o);}get currentMood(){return this.shown}dispose(){this.disconnect(),this.geometry.dispose(),this.material.dispose(),this.faceTex.dispose(),this.heightTex.dispose(),this.onMoodChange=void 0;}show(o,t=true){if(o===this.shown)return;t&&this.state.sound&&this.ready&&le(o);let i=this.shown;this.prevShown=i,this.prevTau=this.tau,this.shown=o,this.tau=0,this.moodTime=0,this.blend=0,O.reducedMotion||(this.squashV-=1.1),this.onMoodChange?.({mood:o,previous:i,reaction:!!this.reaction});}tick(o,t){let i=this.state,s=O.reducedMotion,n=O.lowPower?0:o*Math.max(0,i.speed);this.t+=n,this.tau+=n,this.prevTau+=n,this.reaction&&(this.reaction.left-=o,this.reaction.left<=0&&(this.reaction=null,this.show(i.mood,false))),this.moodTime+=o;let u=i.settle>0&&this.shown!=="idle"?Pe(Math.min(1,Math.max(0,(this.moodTime-i.settle/1e3)/.7))):0;ae(this.shown,this.t,this.tau,this.poseB),u>0&&we(this.poseB,ae("idle",this.t,this.tau,this.poseIdle),u,this.poseB),this.blend<1?(this.blend=Math.min(1,this.blend+o/.45),ae(this.prevShown,this.t,this.prevTau,this.poseA),we(this.poseA,this.poseB,Pe(this.blend),this.pose)):Object.assign(this.pose,this.poseB);let r=this.pose;s&&(r.y=r.rx=r.ry=r.rz=r.st=r.lookX=0);let l=i.followCursor&&!s&&i.speed>0?Le[this.shown]:0,d=0,a=0;if(l>0&&_.known){let c=this.canvas.getBoundingClientRect(),v=Math.max(200,c.width*.85);d=Math.max(-1,Math.min(1,(_.x-(c.left+c.width/2))/v)),a=Math.max(-1,Math.min(1,(_.y-(c.top+c.height*.45))/v)),d*=l,a*=l;}else if(this.shown==="idle"&&!s&&i.speed>0){if(this.t>this.wander.next){let c=Math.random()<.4;this.wander.x=c?0:(Math.random()*2-1)*.6,this.wander.y=c?0:(Math.random()*2-1)*.35,this.wander.next=this.t+1.8+Math.random()*2.6;}d=this.wander.x,a=this.wander.y;}let h=U(7,o);this.look.x+=(d-this.look.x)*h,this.look.y+=(a-this.look.y)*h;let p=ie[this.shown],m=this.target;for(let c of J)m[c]=p[c];m.lookX+=this.look.x+r.lookX,m.lookY+=this.look.y+r.lookY,m.mouthOpen+=r.mouth,m.eyeOpen+=this.hover*.08;let E=U(11,o);for(let c of J)this.face[c]+=(m[c]-this.face[c])*E;let S=U(16,o);if(this.face.lookX+=(m.lookX-this.face.lookX)*S,this.face.lookY+=(m.lookY-this.face.lookY)*S,this.face.mouthOpen+=(m.mouthOpen-this.face.mouthOpen)*S,this.nextBlink-=n,this.nextBlink<=0&&this.blinkT<0&&(this.blinkT=0,this.nextBlink=Math.random()<.2?.25:2.2+Math.random()*3.8),this.blinkT>=0){this.blinkT+=n;let c=this.blinkT/.16;this.blink=c>=1?1:1-Math.sin(Math.PI*c),c>=1&&(this.blinkT=-1);}let w=Math.min(o,1/30);this.squashV+=(-170*this.squash-11*this.squashV)*w,this.squash+=this.squashV*w,s&&(this.squash=this.squashV=0),s?this.pop=1:(this.popV+=(-140*(this.pop-1)-13*this.popV)*w,this.pop+=this.popV*w),this.hover+=((this.hovering&&i.interactive?1:0)-this.hover)*U(12,o);let k=U(9,o);this.body=R(this.body,this.bodyT,k),this.faceC=R(this.faceC,this.faceCT,k),this.cheek=R(this.cheek,this.cheekT,k),this.material.color.setRGB(this.body[0],this.body[1],this.body[2],three.SRGBColorSpace);let C=Ge[this.shown],L=U(6,o);for(let c of Object.keys(this.overlay))this.overlay[c]+=((C===c?1-u:0)-this.overlay[c])*L;this.morph<1&&(this.morph=Math.min(1,this.morph+o/(s?.2:.38)),this.shapeDirty=true);let B=Q[this.shapeTo].animated||this.morph<1&&Q[this.shapeFrom].animated;(this.shapeDirty||B&&n>0)&&this.rebuild();let A=this.group,T=(1+r.st+this.squash)*(1+this.hover*.04),f=1/Math.sqrt(Math.max(.3,1+r.st+this.squash))*(1+this.hover*.04);A.position.y=Ee+r.y,A.rotation.set(r.rx+this.look.y*.22*(l>0?1:0),r.ry+this.look.x*.42,r.rz),A.scale.set(f*this.pop,T*this.pop,f*this.pop);let g=this.drawFaceIfNeeded();if((i.speed===0||O.lowPower)&&!g&&!this.needsFrame&&this.settled())return;let b=performance.now();this.render(r)&&(this.needsFrame=false,this.ready||(this.ready=true,this.state.sound&&le(this.shown,true),this.onReady?.(),this.onReady=void 0),this.adapt(performance.now()-b));}adapt(o){this.cost=this.costFrames?this.cost*.9+o*.1:o,!(++this.costFrames<20||this.cost<9||this.quality<=.5)&&(this.quality=Math.max(.5,this.quality-.25),this.costFrames=0,this.resize(this.css[0],this.css[1]));}settled(){let o=this.group,t=this.overlay,i=[t.bang,o.position.y,o.rotation.x,o.rotation.y,o.rotation.z,o.scale.x,o.scale.y,...this.body,this.morph,t.dots,t.zz,t.hearts,t.waves],s=this.lastFrame,n=s.length===i.length;for(let u=0;n&&u<i.length;u++)n=Math.abs(i[u]-s[u])<1e-4;return this.lastFrame=i,n}rebuild(){let o=this.geometry.getAttribute("position"),t=o.array,i=this.dirs,s=Pe(this.morph),n=this.shapeFrom,u=this.shapeTo,r=new Float32Array(3);for(let a=0;a<i.length;a+=3)Se(u,i[a],i[a+1],i[a+2],this.t,t,a),s<1&&(Se(n,i[a],i[a+1],i[a+2],this.t,r,0),t[a]=r[0]+(t[a]-r[0])*s,t[a+1]=r[1]+(t[a+1]-r[1])*s,t[a+2]=r[2]+(t[a+2]-r[2])*s);o.needsUpdate=true,this.geometry.computeVertexNormals();let l=Q[n],d=Q[u];this.uniforms.uFaceY.value=l.faceY+(d.faceY-l.faceY)*s,this.uniforms.uFaceScale.value=l.faceScale+(d.faceScale-l.faceScale)*s,this.shapeDirty=false;}drawFaceIfNeeded(){let o=this.face,t=this.drawn,i=false,s=0;for(let r of J)Math.abs(t[s]-o[r])<.002||(i=true,t[s]=o[r]),s++;let n=[this.blink,...this.faceC,...this.cheek];for(let r of n)Math.abs(t[s]-r)<.002||(i=true,t[s]=r),s++;if(!i)return false;let u=fe(this.faceC)>.45;return ye(this.faceCtx,o,this.blink,D(this.faceC),D(this.cheek),u?1:.3,D(R(this.faceC,[1,1,1],u?.6:.16)),u?D(R(this.body,[.04,.03,.06],.86)):"#fff",D(u?R(this.body,[.03,.02,.05],.78):R(this.faceC,[0,0,0],.35)),D(this.faceC)),this.faceTex.needsUpdate=true,ye(this.heightCtx,o,this.blink,"#fff","#fff",0,"#fff","#fff","#fff","#fff",true),this.heightTex.needsUpdate=true,true}project(o,t,i){let s=this.v.set(o,t,i).applyMatrix4(this.group.matrixWorld).project(this.camera);return [(s.x*.5+.5)*this.w,(-s.y*.5+.5)*this.h]}render(o){let{w:t,h:i,ctx:s}=this,n=Ie(t,i);if(O.lowPower&&!this.lowPowerApplied){this.lowPowerApplied=true;let[u,r]=this.css;return this.w=this.h=0,this.resize(u,r),false}if(!We(this.scene,this.camera))return false;if(s.clearRect(0,0,t,i),this.group.updateMatrixWorld(),this.state.shadow){let u=this.v.set(0,Ee-.08,0).project(this.camera),r=(u.x*.5+.5)*t,l=(-u.y*.5+.5)*i,d=Math.max(0,o.y)*3,a=Math.min(t,i)*.26*(1-d*.25)*this.pop,h=s.createRadialGradient(r,l,0,r,l,a),p=R(this.body,[.05,.03,.02],.75);h.addColorStop(0,`rgba(${p[0]*255|0},${p[1]*255|0},${p[2]*255|0},${.42*(1-d*.4)})`),h.addColorStop(1,"rgba(0,0,0,0)"),s.fillStyle=h,s.save(),s.translate(r,l),s.scale(1,.22),s.translate(-r,-l),s.beginPath(),s.arc(r,l,a,0,Math.PI*2),s.fill(),s.restore();}return n.setViewport(0,0,t,i),n.setScissor(0,0,t,i),n.render(this.scene,this.camera),s.drawImage(n.domElement,0,qe()-i,t,i,0,0,t,i),this.drawOverlays(),true}drawOverlays(){let o=this.overlay;if(o.dots+o.zz+o.hearts+o.waves+o.bang<.01)return;let{ctx:t}=this,i=this.t,s=O.reducedMotion,n=Math.min(this.w,this.h),u=R(this.body,[1,1,1],.22),r=D(u);if(t.save(),o.dots>.01){let[l,d]=this.project(.6,.92,.2),a=s?2:i*.55%1.6,h=[.014,.022,.052];for(let p=0;p<3;p++){let m=s?1:ze(Re((a-p*.18)/.32)),E=s?0:Math.sin(i*2.2+p)*n*.006,S=l+[0,.05,.12][p]*n,w=d-[0,.05,.12][p]*n+E,k=h[p]*n*m;if(!(k<=.2)&&(t.globalAlpha=o.dots*.95,t.fillStyle=r,t.beginPath(),p<2?t.arc(S,w,k,0,Math.PI*2):Pt(t,S,w,k),t.fill(),p===2&&m>.6)){t.fillStyle=D(R(this.body,[0,0,0],.35));for(let C=0;C<3;C++){let L=s?0:Math.max(0,Math.sin(i*7-C*.9))*k*.16;t.beginPath(),t.arc(S+(C-1)*k*.34,w-L,k*.1,0,Math.PI*2),t.fill();}}}}if(o.zz>.01){let[l,d]=this.project(.45,.85,.2);t.textAlign="center",t.textBaseline="middle",t.fillStyle=r;for(let a=0;a<3;a++){let h=s?.25+a*.25:(i*.33+a/3)%1,p=l+h*n*.17+Math.sin(h*7+a)*n*.018,m=d-Fe(h)*n*.26;t.globalAlpha=o.zz*Math.min(1,h*5)*(1-h)*1.3,t.save(),t.translate(p,m),t.rotate(-0.25+Math.sin(h*5+a)*.22),t.font=`800 ${Math.round(n*(.05+.06*h))}px ui-rounded, system-ui, sans-serif`,t.fillText("z",0,0),t.restore();}}if(o.hearts>.01){let[l,d]=this.project(0,.8,.2),a=R(this.cheek,[1,.3,.45],.55);for(let h=0;h<4;h++){let p=s?.4:(i*.3+h/4)%1,m=h%2?1:-1,E=l+m*n*(.16+.07*(h>>1))+Math.sin(p*6+h)*n*.025,S=d-n*.02-Fe(p)*n*.28,w=s?1:ze(Re(p/.22)),k=n*(.026+.008*(h%3))*w;t.globalAlpha=o.hearts*(1-Math.max(0,(p-.6)/.4)),t.save(),t.translate(E,S),t.rotate(Math.sin(i*3+h)*.25);let C=t.createLinearGradient(0,-k,0,k);C.addColorStop(0,D(R(a,[1,1,1],.35))),C.addColorStop(1,D(a)),t.fillStyle=C,Me(t,0,0,k),t.fill(),t.restore();}}if(o.waves>.01){t.lineCap="round",t.strokeStyle=r;for(let l of [-1,1]){let[d,a]=this.project(l*1,.12,0);for(let h=0;h<3;h++){let p=s?.3+h*.2:(i*.8+h/3)%1,m=Fe(p);t.globalAlpha=o.waves*Math.sin(Math.PI*p)*.9,t.lineWidth=n*(.016-.008*p),t.beginPath();let E=n*(.03+.11*m);l>0?t.arc(d-n*.03,a,E,-0.55,.55):t.arc(d+n*.03,a,E,Math.PI-.55,Math.PI+.55),t.stroke();}}}if(o.bang>.01){let[l,d]=this.project(.55,1,.2),a=s?1:ze(Re(this.tau/.35));t.globalAlpha=o.bang,t.fillStyle=r,t.save(),t.translate(l,d),t.rotate(.18),t.scale(a,a),t.beginPath(),t.roundRect(-n*.016,-n*.1,n*.032,n*.07,n*.016),t.arc(0,n*.005,n*.018,0,Math.PI*2),t.fill(),t.restore();}t.restore();}},Re=e=>e<0?0:e>1?1:e,Fe=e=>1-(1-e)*(1-e),ze=e=>1+(1.9+1)*Math.pow(e-1,3)+1.9*Math.pow(e-1,2);function Pt(e,o,t,i){e.ellipse(o,t,i,i*.72,0,0,Math.PI*2),e.moveTo(o-i*.35+i*.45,t-i*.38),e.arc(o-i*.35,t-i*.38,i*.45,0,Math.PI*2),e.moveTo(o+i*.3+i*.5,t-i*.32),e.arc(o+i*.3,t-i*.32,i*.5,0,Math.PI*2);}var Rt=["shape","mood","color","face-color","cheek-color","size","speed","follow-cursor","interactive","shadow","sound","settle"],N=(e,o)=>e===null?o:e!=="false"&&e!=="0",Ft=e=>e==null||e===""?`${y.size}px`:typeof e=="number"||/^\d+(\.\d+)?$/.test(String(e))?`${e}px`:String(e),zt=`:host{display:inline-block;position:relative;cursor:pointer;vertical-align:middle;contain:layout paint style;-webkit-tap-highlight-color:transparent}
44
+ #include <opaque_fragment>`);},o}setSegments(o){let t=Et(o);this.dirs!==t.dirs&&(this.dirs=t.dirs,this.geometry.dispose(),this.geometry=new three.BufferGeometry,this.geometry.setAttribute("position",new three.BufferAttribute(new Float32Array(t.dirs.length),3)),this.geometry.setIndex(new three.BufferAttribute(t.index,1)),this.mesh&&(this.mesh.geometry=this.geometry),this.shapeDirty=true);}connect(){this.connected=true,_e(this);}disconnect(){this.connected=false,He(this);}setVisible(o){this.visible=o,o&&H();}resize(o,t){this.css=[o,t];let i=(O.lowPower?1:Math.min(2,devicePixelRatio||1))*this.quality,s=Math.max(1,Math.round(o*i)),n=Math.max(1,Math.round(t*i));if(s===this.w&&n===this.h)return;this.w=this.canvas.width=s,this.h=this.canvas.height=n;let u=Math.min(s,n),r=Math.min(o,t);this.camera.position.set(0,.3,r<90?5.1:6.1),this.camera.lookAt(0,r<90?.02:.12,0),this.camera.aspect=s/n,this.camera.updateProjectionMatrix(),this.setSegments(u<160?16:u<400?24:32);let l=u<220?256:512;this.faceCanvas.width!==l&&(this.faceCanvas.width=this.faceCanvas.height=l,this.faceTex.dispose(),this.drawn.fill(NaN)),this.needsFrame=true,H();}update(o){let t=this.state;this.state={...t,...o};let i=this.state;i.shape!==this.shapeTo&&(this.shapeFrom=this.shapeTo,this.shapeTo=i.shape,this.morph=0,O.reducedMotion||(this.squashV-=2.2)),(i.color!==t.color||i.faceColor!==t.faceColor||i.cheekColor!==t.cheekColor)&&(this.bodyT=X(i.color,X(y.color,this.bodyT)),this.faceCT=i.faceColor?X(i.faceColor,oe(this.bodyT)):oe(this.bodyT),this.cheekT=i.cheekColor?X(i.cheekColor,ie(this.bodyT)):ie(this.bodyT)),i.mood!==t.mood&&!this.reaction&&this.show(i.mood),i.sound&&!t.sound&&this.ready&&ce(this.shown),this.needsFrame=true,H();}bump(o=1){O.reducedMotion||(this.squashV-=1.6*o,this.needsFrame=true,H());}react(o,t=1200){this.reaction={mood:o,left:t/1e3},this.show(o);}get currentMood(){return this.shown}dispose(){this.disconnect(),this.geometry.dispose(),this.material.dispose(),this.faceTex.dispose(),this.heightTex.dispose(),this.onMoodChange=void 0;}show(o,t=true){if(o===this.shown)return;t&&this.state.sound&&this.ready&&ce(o);let i=this.shown;this.prevShown=i,this.prevTau=this.tau,this.shown=o,this.tau=0,this.moodTime=0,this.blend=0,O.reducedMotion||(this.squashV-=1.1),this.onMoodChange?.({mood:o,previous:i,reaction:!!this.reaction});}tick(o,t){let i=this.state,s=O.reducedMotion,n=O.lowPower?0:o*Math.max(0,i.speed);this.t+=n,this.tau+=n,this.prevTau+=n,this.reaction&&(this.reaction.left-=o,this.reaction.left<=0&&(this.reaction=null,this.show(i.mood,false))),this.moodTime+=o,i.settle>0&&i.settleMood&&!this.reaction&&this.shown===i.mood&&this.shown!==i.settleMood&&this.moodTime>=i.settle/1e3&&this.show(i.settleMood,false);let u=i.settle>0&&this.shown!=="idle"?Pe(Math.min(1,Math.max(0,(this.moodTime-i.settle/1e3)/.7))):0;re(this.shown,this.t,this.tau,this.poseB),u>0&&we(this.poseB,re("idle",this.t,this.tau,this.poseIdle),u,this.poseB),this.blend<1?(this.blend=Math.min(1,this.blend+o/.45),re(this.prevShown,this.t,this.prevTau,this.poseA),we(this.poseA,this.poseB,Pe(this.blend),this.pose)):Object.assign(this.pose,this.poseB);let r=this.pose;s&&(r.y=r.rx=r.ry=r.rz=r.st=r.lookX=0);let l=i.followCursor&&!s&&i.speed>0?Le[this.shown]:0,d=0,a=0;if(l>0&&_.known){let c=this.canvas.getBoundingClientRect(),v=Math.max(200,c.width*.85);d=Math.max(-1,Math.min(1,(_.x-(c.left+c.width/2))/v)),a=Math.max(-1,Math.min(1,(_.y-(c.top+c.height*.45))/v)),d*=l,a*=l;}else if(this.shown==="idle"&&!s&&i.speed>0){if(this.t>this.wander.next){let c=Math.random()<.4;this.wander.x=c?0:(Math.random()*2-1)*.6,this.wander.y=c?0:(Math.random()*2-1)*.35,this.wander.next=this.t+1.8+Math.random()*2.6;}d=this.wander.x,a=this.wander.y;}let h=U(7,o);this.look.x+=(d-this.look.x)*h,this.look.y+=(a-this.look.y)*h;let p=se[this.shown],m=this.target;for(let c of Z)m[c]=p[c];m.lookX+=this.look.x+r.lookX,m.lookY+=this.look.y+r.lookY,m.mouthOpen+=r.mouth,m.eyeOpen+=this.hover*.08;let E=U(11,o);for(let c of Z)this.face[c]+=(m[c]-this.face[c])*E;let S=U(16,o);if(this.face.lookX+=(m.lookX-this.face.lookX)*S,this.face.lookY+=(m.lookY-this.face.lookY)*S,this.face.mouthOpen+=(m.mouthOpen-this.face.mouthOpen)*S,this.nextBlink-=n,this.nextBlink<=0&&this.blinkT<0&&(this.blinkT=0,this.nextBlink=Math.random()<.2?.25:2.2+Math.random()*3.8),this.blinkT>=0){this.blinkT+=n;let c=this.blinkT/.16;this.blink=c>=1?1:1-Math.sin(Math.PI*c),c>=1&&(this.blinkT=-1);}let w=Math.min(o,1/30);this.squashV+=(-170*this.squash-11*this.squashV)*w,this.squash+=this.squashV*w,s&&(this.squash=this.squashV=0),s?this.pop=1:(this.popV+=(-140*(this.pop-1)-13*this.popV)*w,this.pop+=this.popV*w),this.hover+=((this.hovering&&i.interactive?1:0)-this.hover)*U(12,o);let k=U(9,o);this.body=R(this.body,this.bodyT,k),this.faceC=R(this.faceC,this.faceCT,k),this.cheek=R(this.cheek,this.cheekT,k),this.material.color.setRGB(this.body[0],this.body[1],this.body[2],three.SRGBColorSpace);let C=Ge[this.shown],L=U(6,o);for(let c of Object.keys(this.overlay))this.overlay[c]+=((C===c?1-u:0)-this.overlay[c])*L;this.morph<1&&(this.morph=Math.min(1,this.morph+o/(s?.2:.38)),this.shapeDirty=true);let B=ee[this.shapeTo].animated||this.morph<1&&ee[this.shapeFrom].animated;(this.shapeDirty||B&&n>0)&&this.rebuild();let A=this.group,T=(1+r.st+this.squash)*(1+this.hover*.04),f=1/Math.sqrt(Math.max(.3,1+r.st+this.squash))*(1+this.hover*.04);A.position.y=Ee+r.y,A.rotation.set(r.rx+this.look.y*.22*(l>0?1:0),r.ry+this.look.x*.42,r.rz),A.scale.set(f*this.pop,T*this.pop,f*this.pop);let g=this.drawFaceIfNeeded();if((i.speed===0||O.lowPower)&&!g&&!this.needsFrame&&this.settled())return;let b=performance.now();this.render(r)&&(this.needsFrame=false,this.ready||(this.ready=true,this.state.sound&&ce(this.shown,true),this.onReady?.(),this.onReady=void 0),this.adapt(performance.now()-b));}adapt(o){this.cost=this.costFrames?this.cost*.9+o*.1:o,!(++this.costFrames<20||this.cost<9||this.quality<=.5)&&(this.quality=Math.max(.5,this.quality-.25),this.costFrames=0,this.resize(this.css[0],this.css[1]));}settled(){let o=this.group,t=this.overlay,i=[t.bang,o.position.y,o.rotation.x,o.rotation.y,o.rotation.z,o.scale.x,o.scale.y,...this.body,this.morph,t.dots,t.zz,t.hearts,t.waves],s=this.lastFrame,n=s.length===i.length;for(let u=0;n&&u<i.length;u++)n=Math.abs(i[u]-s[u])<1e-4;return this.lastFrame=i,n}rebuild(){let o=this.geometry.getAttribute("position"),t=o.array,i=this.dirs,s=Pe(this.morph),n=this.shapeFrom,u=this.shapeTo,r=new Float32Array(3);for(let a=0;a<i.length;a+=3)Se(u,i[a],i[a+1],i[a+2],this.t,t,a),s<1&&(Se(n,i[a],i[a+1],i[a+2],this.t,r,0),t[a]=r[0]+(t[a]-r[0])*s,t[a+1]=r[1]+(t[a+1]-r[1])*s,t[a+2]=r[2]+(t[a+2]-r[2])*s);o.needsUpdate=true,this.geometry.computeVertexNormals();let l=ee[n],d=ee[u];this.uniforms.uFaceY.value=l.faceY+(d.faceY-l.faceY)*s,this.uniforms.uFaceScale.value=l.faceScale+(d.faceScale-l.faceScale)*s,this.shapeDirty=false;}drawFaceIfNeeded(){let o=this.face,t=this.drawn,i=false,s=0;for(let r of Z)Math.abs(t[s]-o[r])<.002||(i=true,t[s]=o[r]),s++;let n=[this.blink,...this.faceC,...this.cheek];for(let r of n)Math.abs(t[s]-r)<.002||(i=true,t[s]=r),s++;if(!i)return false;let u=fe(this.faceC)>.45;return ye(this.faceCtx,o,this.blink,D(this.faceC),D(this.cheek),u?1:.3,D(R(this.faceC,[1,1,1],u?.6:.16)),u?D(R(this.body,[.04,.03,.06],.86)):"#fff",D(u?R(this.body,[.03,.02,.05],.78):R(this.faceC,[0,0,0],.35)),D(this.faceC)),this.faceTex.needsUpdate=true,ye(this.heightCtx,o,this.blink,"#fff","#fff",0,"#fff","#fff","#fff","#fff",true),this.heightTex.needsUpdate=true,true}project(o,t,i){let s=this.v.set(o,t,i).applyMatrix4(this.group.matrixWorld).project(this.camera);return [(s.x*.5+.5)*this.w,(-s.y*.5+.5)*this.h]}render(o){let{w:t,h:i,ctx:s}=this,n=Ie(t,i);if(O.lowPower&&!this.lowPowerApplied){this.lowPowerApplied=true;let[u,r]=this.css;return this.w=this.h=0,this.resize(u,r),false}if(!We(this.scene,this.camera))return false;if(s.clearRect(0,0,t,i),this.group.updateMatrixWorld(),this.state.shadow){let u=this.v.set(0,Ee-.08,0).project(this.camera),r=(u.x*.5+.5)*t,l=(-u.y*.5+.5)*i,d=Math.max(0,o.y)*3,a=Math.min(t,i)*.26*(1-d*.25)*this.pop,h=s.createRadialGradient(r,l,0,r,l,a),p=R(this.body,[.05,.03,.02],.75);h.addColorStop(0,`rgba(${p[0]*255|0},${p[1]*255|0},${p[2]*255|0},${.42*(1-d*.4)})`),h.addColorStop(1,"rgba(0,0,0,0)"),s.fillStyle=h,s.save(),s.translate(r,l),s.scale(1,.22),s.translate(-r,-l),s.beginPath(),s.arc(r,l,a,0,Math.PI*2),s.fill(),s.restore();}return n.setViewport(0,0,t,i),n.setScissor(0,0,t,i),n.render(this.scene,this.camera),s.drawImage(n.domElement,0,qe()-i,t,i,0,0,t,i),this.drawOverlays(),true}drawOverlays(){let o=this.overlay;if(o.dots+o.zz+o.hearts+o.waves+o.bang<.01)return;let{ctx:t}=this,i=this.t,s=O.reducedMotion,n=Math.min(this.w,this.h),u=R(this.body,[1,1,1],.22),r=D(u);if(t.save(),o.dots>.01){let[l,d]=this.project(.6,.92,.2),a=s?2:i*.55%1.6,h=[.014,.022,.052];for(let p=0;p<3;p++){let m=s?1:ze(Re((a-p*.18)/.32)),E=s?0:Math.sin(i*2.2+p)*n*.006,S=l+[0,.05,.12][p]*n,w=d-[0,.05,.12][p]*n+E,k=h[p]*n*m;if(!(k<=.2)&&(t.globalAlpha=o.dots*.95,t.fillStyle=r,t.beginPath(),p<2?t.arc(S,w,k,0,Math.PI*2):Pt(t,S,w,k),t.fill(),p===2&&m>.6)){t.fillStyle=D(R(this.body,[0,0,0],.35));for(let C=0;C<3;C++){let L=s?0:Math.max(0,Math.sin(i*7-C*.9))*k*.16;t.beginPath(),t.arc(S+(C-1)*k*.34,w-L,k*.1,0,Math.PI*2),t.fill();}}}}if(o.zz>.01){let[l,d]=this.project(.45,.85,.2);t.textAlign="center",t.textBaseline="middle",t.fillStyle=r;for(let a=0;a<3;a++){let h=s?.25+a*.25:(i*.33+a/3)%1,p=l+h*n*.17+Math.sin(h*7+a)*n*.018,m=d-Fe(h)*n*.26;t.globalAlpha=o.zz*Math.min(1,h*5)*(1-h)*1.3,t.save(),t.translate(p,m),t.rotate(-0.25+Math.sin(h*5+a)*.22),t.font=`800 ${Math.round(n*(.05+.06*h))}px ui-rounded, system-ui, sans-serif`,t.fillText("z",0,0),t.restore();}}if(o.hearts>.01){let[l,d]=this.project(0,.8,.2),a=R(this.cheek,[1,.3,.45],.55);for(let h=0;h<4;h++){let p=s?.4:(i*.3+h/4)%1,m=h%2?1:-1,E=l+m*n*(.16+.07*(h>>1))+Math.sin(p*6+h)*n*.025,S=d-n*.02-Fe(p)*n*.28,w=s?1:ze(Re(p/.22)),k=n*(.026+.008*(h%3))*w;t.globalAlpha=o.hearts*(1-Math.max(0,(p-.6)/.4)),t.save(),t.translate(E,S),t.rotate(Math.sin(i*3+h)*.25);let C=t.createLinearGradient(0,-k,0,k);C.addColorStop(0,D(R(a,[1,1,1],.35))),C.addColorStop(1,D(a)),t.fillStyle=C,Me(t,0,0,k),t.fill(),t.restore();}}if(o.waves>.01){t.lineCap="round",t.strokeStyle=r;for(let l of [-1,1]){let[d,a]=this.project(l*1,.12,0);for(let h=0;h<3;h++){let p=s?.3+h*.2:(i*.8+h/3)%1,m=Fe(p);t.globalAlpha=o.waves*Math.sin(Math.PI*p)*.9,t.lineWidth=n*(.016-.008*p),t.beginPath();let E=n*(.03+.11*m);l>0?t.arc(d-n*.03,a,E,-0.55,.55):t.arc(d+n*.03,a,E,Math.PI-.55,Math.PI+.55),t.stroke();}}}if(o.bang>.01){let[l,d]=this.project(.55,1,.2),a=s?1:ze(Re(this.tau/.35));t.globalAlpha=o.bang,t.fillStyle=r,t.save(),t.translate(l,d),t.rotate(.18),t.scale(a,a),t.beginPath(),t.roundRect(-n*.016,-n*.1,n*.032,n*.07,n*.016),t.arc(0,n*.005,n*.018,0,Math.PI*2),t.fill(),t.restore();}t.restore();}},Re=e=>e<0?0:e>1?1:e,Fe=e=>1-(1-e)*(1-e),ze=e=>1+(1.9+1)*Math.pow(e-1,3)+1.9*Math.pow(e-1,2);function Pt(e,o,t,i){e.ellipse(o,t,i,i*.72,0,0,Math.PI*2),e.moveTo(o-i*.35+i*.45,t-i*.38),e.arc(o-i*.35,t-i*.38,i*.45,0,Math.PI*2),e.moveTo(o+i*.3+i*.5,t-i*.32),e.arc(o+i*.3,t-i*.32,i*.5,0,Math.PI*2);}var Rt=["shape","mood","color","face-color","cheek-color","size","speed","follow-cursor","interactive","shadow","sound","settle","settle-mood"],N=(e,o)=>e===null?o:e!=="false"&&e!=="0",Ft=e=>e==null||e===""?`${y.size}px`:typeof e=="number"||/^\d+(\.\d+)?$/.test(String(e))?`${e}px`:String(e),zt=`:host{display:inline-block;position:relative;cursor:pointer;vertical-align:middle;contain:layout paint style;-webkit-tap-highlight-color:transparent}
45
45
  :host([interactive="false"]){pointer-events:none}
46
46
  canvas{position:absolute;inset:0;display:block;width:100%;height:100%}
47
47
  slot{display:block;width:100%;height:100%}
48
48
  ::slotted(img){display:block;width:100%;height:100%;object-fit:contain}
49
- :host([ready]) slot{display:none}`,Bt=typeof HTMLElement>"u"?class{}:HTMLElement,ee=class extends Bt{constructor(){super();this.buddy=null;this.sizeStyle=document.createElement("style");this.onEnter=()=>{this.buddy&&(this.buddy.hovering=true);};this.onLeave=()=>{this.buddy&&(this.buddy.hovering=false);};this.onClick=()=>{this.buddy?.state.interactive&&this.react(Math.random()<.5?"happy":"surprised",{duration:1100});};this.root=this.attachShadow({mode:"open"});let t=document.createElement("style");t.textContent=zt,this.root.append(t,document.createElement("slot")),this.root.append(this.sizeStyle),this.applySize(this.getAttribute("size"));}connectedCallback(){if(this.hasAttribute("role")||this.setAttribute("role","img"),!this.buddy){let t=this.buddy=new ce;t.onMoodChange=i=>{this.syncLabel(i.mood),this.dispatchEvent(new CustomEvent("moodchange",{detail:i,bubbles:true}));},t.onReady=()=>{this.setAttribute("ready",""),this.dispatchEvent(new Event("ready"));},this.root.append(t.canvas),t.update(this.readState()),this.addEventListener("pointerenter",this.onEnter),this.addEventListener("pointerleave",this.onLeave),this.addEventListener("click",this.onClick);}this.syncLabel(this.buddy.currentMood),this.buddy.connect(),this.io=new IntersectionObserver(([t])=>this.buddy?.setVisible(t.isIntersecting),{rootMargin:"64px"}),this.io.observe(this),this.ro=new ResizeObserver(([t])=>{let i=t.contentRect;this.buddy?.resize(i.width,i.height);}),this.ro.observe(this);}disconnectedCallback(){this.io?.disconnect(),this.ro?.disconnect(),this.buddy&&(this.buddy.canvas.remove(),this.buddy.dispose(),this.buddy=null),this.removeEventListener("pointerenter",this.onEnter),this.removeEventListener("pointerleave",this.onLeave),this.removeEventListener("click",this.onClick);}attributeChangedCallback(t,i,s){i!==s&&(t==="size"&&(this.applySize(s),i!==null&&this.buddy?.bump()),t!=="aria-label"&&(this.buddy?.update(this.readState()),t==="mood"&&this.buddy&&this.syncLabel(this.buddy.currentMood)));}applySize(t){let i=Ft(t);this.sizeStyle.textContent=`:host{width:${i};height:${i}}`;}readState(){let t=this.getAttribute("shape"),i=this.getAttribute("mood"),s=parseFloat(this.getAttribute("speed")??""),n=parseFloat(this.getAttribute("settle")??"");return {shape:de(t)?t:y.shape,mood:pe(i)?i:y.mood,color:this.getAttribute("color")||y.color,faceColor:this.getAttribute("face-color")||void 0,cheekColor:this.getAttribute("cheek-color")||void 0,speed:Number.isFinite(s)?Math.max(0,s):y.speed,followCursor:N(this.getAttribute("follow-cursor"),y.followCursor),interactive:N(this.getAttribute("interactive"),y.interactive),shadow:N(this.getAttribute("shadow"),y.shadow),sound:N(this.getAttribute("sound"),y.sound),settle:Number.isFinite(n)?Math.max(0,n):y.settle}}syncLabel(t){let i=this.getAttribute("aria-label");i&&!i.startsWith("moodi: ")||this.setAttribute("aria-label",`moodi: ${t}`);}react(t,i={}){this.buddy?.react(t,i.duration??1200);}get shape(){let t=this.getAttribute("shape");return de(t)?t:y.shape}set shape(t){this.setAttribute("shape",t);}get mood(){let t=this.getAttribute("mood");return pe(t)?t:y.mood}set mood(t){this.setAttribute("mood",t);}get color(){return this.getAttribute("color")||y.color}set color(t){this.setAttribute("color",t);}get faceColor(){return this.getAttribute("face-color")||void 0}set faceColor(t){t?this.setAttribute("face-color",t):this.removeAttribute("face-color");}get cheekColor(){return this.getAttribute("cheek-color")||void 0}set cheekColor(t){t?this.setAttribute("cheek-color",t):this.removeAttribute("cheek-color");}get size(){let t=this.getAttribute("size");return t?/^\d+(\.\d+)?$/.test(t)?Number(t):t:y.size}set size(t){this.setAttribute("size",String(t));}get speed(){return this.readState().speed}set speed(t){this.setAttribute("speed",String(t));}get followCursor(){return N(this.getAttribute("follow-cursor"),y.followCursor)}set followCursor(t){this.setAttribute("follow-cursor",String(t));}get interactive(){return N(this.getAttribute("interactive"),y.interactive)}set interactive(t){this.setAttribute("interactive",String(t));}get shadow(){return N(this.getAttribute("shadow"),y.shadow)}set shadow(t){this.setAttribute("shadow",String(t));}get settle(){return this.readState().settle}set settle(t){this.setAttribute("settle",String(t));}get sound(){return N(this.getAttribute("sound"),y.sound)}set sound(t){this.setAttribute("sound",String(t));}};ee.observedAttributes=Rt;function Ze(e="moodi-buddy"){typeof window>"u"||!("customElements"in window)||customElements.get(e)||customElements.define(e,class extends ee{});}Ze();exports.DEFAULTS=y;exports.MOODS=et;exports.MOOD_INFO=Lt;exports.MoodiBuddyElement=ee;exports.PALETTES=Ot;exports.SHAPES=Qe;exports.SHAPE_LABELS=Gt;exports.defineMoodi=Ze;exports.isMood=pe;exports.isShape=de;
49
+ :host([ready]) slot{display:none}`,Bt=typeof HTMLElement>"u"?class{}:HTMLElement,te=class extends Bt{constructor(){super();this.buddy=null;this.sizeStyle=document.createElement("style");this.onEnter=()=>{this.buddy&&(this.buddy.hovering=true);};this.onLeave=()=>{this.buddy&&(this.buddy.hovering=false);};this.onClick=()=>{this.buddy?.state.interactive&&this.react(Math.random()<.5?"happy":"surprised",{duration:1100});};this.root=this.attachShadow({mode:"open"});let t=document.createElement("style");t.textContent=zt,this.root.append(t,document.createElement("slot")),this.root.append(this.sizeStyle),this.applySize(this.getAttribute("size"));}connectedCallback(){if(this.hasAttribute("role")||this.setAttribute("role","img"),!this.buddy){let t=this.buddy=new ue;t.onMoodChange=i=>{this.syncLabel(i.mood),this.dispatchEvent(new CustomEvent("moodchange",{detail:i,bubbles:true}));},t.onReady=()=>{this.setAttribute("ready",""),this.dispatchEvent(new Event("ready"));},this.root.append(t.canvas),t.update(this.readState()),this.addEventListener("pointerenter",this.onEnter),this.addEventListener("pointerleave",this.onLeave),this.addEventListener("click",this.onClick);}this.syncLabel(this.buddy.currentMood),this.buddy.connect(),this.io=new IntersectionObserver(([t])=>this.buddy?.setVisible(t.isIntersecting),{rootMargin:"64px"}),this.io.observe(this),this.ro=new ResizeObserver(([t])=>{let i=t.contentRect;this.buddy?.resize(i.width,i.height);}),this.ro.observe(this);}disconnectedCallback(){this.io?.disconnect(),this.ro?.disconnect(),this.buddy&&(this.buddy.canvas.remove(),this.buddy.dispose(),this.buddy=null),this.removeEventListener("pointerenter",this.onEnter),this.removeEventListener("pointerleave",this.onLeave),this.removeEventListener("click",this.onClick);}attributeChangedCallback(t,i,s){i!==s&&(t==="size"&&(this.applySize(s),i!==null&&this.buddy?.bump()),t!=="aria-label"&&(this.buddy?.update(this.readState()),t==="mood"&&this.buddy&&this.syncLabel(this.buddy.currentMood)));}applySize(t){let i=Ft(t);this.sizeStyle.textContent=`:host{width:${i};height:${i}}`;}readState(){let t=this.getAttribute("shape"),i=this.getAttribute("mood"),s=parseFloat(this.getAttribute("speed")??""),n=parseFloat(this.getAttribute("settle")??""),u=this.getAttribute("settle-mood");return {shape:pe(t)?t:y.shape,mood:J(i)?i:y.mood,color:this.getAttribute("color")||y.color,faceColor:this.getAttribute("face-color")||void 0,cheekColor:this.getAttribute("cheek-color")||void 0,speed:Number.isFinite(s)?Math.max(0,s):y.speed,followCursor:N(this.getAttribute("follow-cursor"),y.followCursor),interactive:N(this.getAttribute("interactive"),y.interactive),shadow:N(this.getAttribute("shadow"),y.shadow),sound:N(this.getAttribute("sound"),y.sound),settle:Number.isFinite(n)?Math.max(0,n):y.settle,settleMood:J(u)?u:void 0}}syncLabel(t){let i=this.getAttribute("aria-label");i&&!i.startsWith("moodi: ")||this.setAttribute("aria-label",`moodi: ${t}`);}react(t,i={}){this.buddy?.react(t,i.duration??1200);}get shape(){let t=this.getAttribute("shape");return pe(t)?t:y.shape}set shape(t){this.setAttribute("shape",t);}get mood(){let t=this.getAttribute("mood");return J(t)?t:y.mood}set mood(t){this.setAttribute("mood",t);}get color(){return this.getAttribute("color")||y.color}set color(t){this.setAttribute("color",t);}get faceColor(){return this.getAttribute("face-color")||void 0}set faceColor(t){t?this.setAttribute("face-color",t):this.removeAttribute("face-color");}get cheekColor(){return this.getAttribute("cheek-color")||void 0}set cheekColor(t){t?this.setAttribute("cheek-color",t):this.removeAttribute("cheek-color");}get size(){let t=this.getAttribute("size");return t?/^\d+(\.\d+)?$/.test(t)?Number(t):t:y.size}set size(t){this.setAttribute("size",String(t));}get speed(){return this.readState().speed}set speed(t){this.setAttribute("speed",String(t));}get followCursor(){return N(this.getAttribute("follow-cursor"),y.followCursor)}set followCursor(t){this.setAttribute("follow-cursor",String(t));}get interactive(){return N(this.getAttribute("interactive"),y.interactive)}set interactive(t){this.setAttribute("interactive",String(t));}get shadow(){return N(this.getAttribute("shadow"),y.shadow)}set shadow(t){this.setAttribute("shadow",String(t));}get settle(){return this.readState().settle}set settle(t){this.setAttribute("settle",String(t));}get settleMood(){let t=this.getAttribute("settle-mood");return J(t)?t:void 0}set settleMood(t){t?this.setAttribute("settle-mood",t):this.removeAttribute("settle-mood");}get sound(){return N(this.getAttribute("sound"),y.sound)}set sound(t){this.setAttribute("sound",String(t));}};te.observedAttributes=Rt;function Ze(e="moodi-buddy"){typeof window>"u"||!("customElements"in window)||customElements.get(e)||customElements.define(e,class extends te{});}Ze();exports.DEFAULTS=y;exports.MOODS=et;exports.MOOD_INFO=Lt;exports.MoodiBuddyElement=te;exports.PALETTES=Ot;exports.SHAPES=Qe;exports.SHAPE_LABELS=Gt;exports.defineMoodi=Ze;exports.isMood=J;exports.isShape=pe;
package/dist/index.d.cts CHANGED
@@ -5,7 +5,7 @@ interface MoodiProps {
5
5
  shape?: Shape;
6
6
  /** Current mood / state. Default `'idle'`. */
7
7
  mood?: Mood;
8
- /** Body color, any CSS color. Default `'#6c5ce7'`. */
8
+ /** Body color, any CSS color. Default `'#2b15d1'`. */
9
9
  color?: string;
10
10
  /** Eyes / mouth color. Auto-contrast by default. */
11
11
  faceColor?: string;
@@ -28,6 +28,11 @@ interface MoodiProps {
28
28
  * (hopping, shaking, hearts… stop; the facial expression stays). `0` = never. Default `0`.
29
29
  */
30
30
  settle?: number;
31
+ /**
32
+ * With `settle`: once it has elapsed, switch to this mood (face and body), e.g.
33
+ * `mood="happy" settle={3000} settleMood="idle"`. The `mood` prop is unchanged.
34
+ */
35
+ settleMood?: Mood;
31
36
  }
32
37
  interface MoodChangeDetail {
33
38
  mood: Mood;
@@ -60,7 +65,7 @@ declare const isMood: (v: unknown) => v is Mood;
60
65
 
61
66
  declare const Base: typeof HTMLElement;
62
67
  declare class MoodiBuddyElement extends Base {
63
- static observedAttributes: readonly ["shape", "mood", "color", "face-color", "cheek-color", "size", "speed", "follow-cursor", "interactive", "shadow", "sound", "settle"];
68
+ static observedAttributes: readonly ["shape", "mood", "color", "face-color", "cheek-color", "size", "speed", "follow-cursor", "interactive", "shadow", "sound", "settle", "settle-mood"];
64
69
  private buddy;
65
70
  private io?;
66
71
  private ro?;
@@ -103,6 +108,8 @@ declare class MoodiBuddyElement extends Base {
103
108
  set shadow(v: boolean);
104
109
  get settle(): number;
105
110
  set settle(v: number);
111
+ get settleMood(): Mood | undefined;
112
+ set settleMood(v: Mood | undefined);
106
113
  get sound(): boolean;
107
114
  set sound(v: boolean);
108
115
  }
package/dist/index.d.ts CHANGED
@@ -5,7 +5,7 @@ interface MoodiProps {
5
5
  shape?: Shape;
6
6
  /** Current mood / state. Default `'idle'`. */
7
7
  mood?: Mood;
8
- /** Body color, any CSS color. Default `'#6c5ce7'`. */
8
+ /** Body color, any CSS color. Default `'#2b15d1'`. */
9
9
  color?: string;
10
10
  /** Eyes / mouth color. Auto-contrast by default. */
11
11
  faceColor?: string;
@@ -28,6 +28,11 @@ interface MoodiProps {
28
28
  * (hopping, shaking, hearts… stop; the facial expression stays). `0` = never. Default `0`.
29
29
  */
30
30
  settle?: number;
31
+ /**
32
+ * With `settle`: once it has elapsed, switch to this mood (face and body), e.g.
33
+ * `mood="happy" settle={3000} settleMood="idle"`. The `mood` prop is unchanged.
34
+ */
35
+ settleMood?: Mood;
31
36
  }
32
37
  interface MoodChangeDetail {
33
38
  mood: Mood;
@@ -60,7 +65,7 @@ declare const isMood: (v: unknown) => v is Mood;
60
65
 
61
66
  declare const Base: typeof HTMLElement;
62
67
  declare class MoodiBuddyElement extends Base {
63
- static observedAttributes: readonly ["shape", "mood", "color", "face-color", "cheek-color", "size", "speed", "follow-cursor", "interactive", "shadow", "sound", "settle"];
68
+ static observedAttributes: readonly ["shape", "mood", "color", "face-color", "cheek-color", "size", "speed", "follow-cursor", "interactive", "shadow", "sound", "settle", "settle-mood"];
64
69
  private buddy;
65
70
  private io?;
66
71
  private ro?;
@@ -103,6 +108,8 @@ declare class MoodiBuddyElement extends Base {
103
108
  set shadow(v: boolean);
104
109
  get settle(): number;
105
110
  set settle(v: number);
111
+ get settleMood(): Mood | undefined;
112
+ set settleMood(v: Mood | undefined);
106
113
  get sound(): boolean;
107
114
  set sound(v: boolean);
108
115
  }
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import {Scene,PerspectiveCamera,Group,Vector3,BufferGeometry,CanvasTexture,SRGBColorSpace,LinearMipmapLinearFilter,Mesh,HemisphereLight,DirectionalLight,MeshStandardMaterial,BufferAttribute,WebGLRenderer,SphereGeometry}from'three';var Qe=["ghost","pebble","blob","drop","bean","cube"],et=["idle","thinking","loading","listening","speaking","happy","surprised","sad","error","sleeping","love"],y={shape:"ghost",mood:"idle",color:"#6c5ce7",size:160,speed:1,followCursor:true,interactive:true,shadow:true,sound:false,settle:0},Ot={Iris:"#6c5ce7",Peach:"#f2a07b",Sage:"#8fb996",Sky:"#8ec5e8",Lilac:"#b9a3e3",Butter:"#f3d36b",Coral:"#f07167",Ink:"#2b2d42",Cloud:"#ecebe8"},Lt={idle:{label:"Idle",description:"Breathing softly. Blinks now and then."},thinking:{label:"Thinking",description:"Eyes drift up. Little thoughts pop."},loading:{label:"Loading",description:"Half-lidded, wobbling patiently."},listening:{label:"Listening",description:"All eyes. Nods along to every word."},speaking:{label:"Speaking",description:"Chatty mouth, bouncing to the rhythm."},happy:{label:"Happy",description:"Bounces with joy. Cheeks glow."},surprised:{label:"Surprised",description:"Wide eyes, tiny o. Did not see that coming."},sad:{label:"Sad",description:"Slumps a little. Needs a minute."},error:{label:"Error",description:"Something broke. Shakes it off."},sleeping:{label:"Sleeping",description:"Deep, slow breaths. Do not disturb."},love:{label:"Love",description:"Heart eyes, floating on air."}},Gt={pebble:"Pebble",blob:"Blob",drop:"Drop",bean:"Bean",cube:"Cube",ghost:"Ghost"},de=e=>Qe.includes(e),pe=e=>et.includes(e);var G=null;function X(e,o){if(!e)return o;let t=/^#?([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(e.trim());if(t)return Be(t[1]);if(G||(G=document.createElement("canvas").getContext("2d")),!G)return o;G.fillStyle="#010203",G.fillStyle=e;let i=String(G.fillStyle);if(i==="#010203"&&e.trim()!=="#010203")return o;if(i.startsWith("#"))return Be(i.slice(1));G.canvas.width=G.canvas.height=1,G.clearRect(0,0,1,1),G.fillRect(0,0,1,1);let s=G.getImageData(0,0,1,1).data;return [s[0]/255,s[1]/255,s[2]/255]}function Be(e){e.length===3&&(e=e[0]+e[0]+e[1]+e[1]+e[2]+e[2]);let o=parseInt(e,16);return [(o>>16&255)/255,(o>>8&255)/255,(o&255)/255]}var D=e=>`rgb(${Math.round(e[0]*255)},${Math.round(e[1]*255)},${Math.round(e[2]*255)})`,R=(e,o,t)=>[e[0]+(o[0]-e[0])*t,e[1]+(o[1]-e[1])*t,e[2]+(o[2]-e[2])*t],me=e=>e<=.04045?e/12.92:Math.pow((e+.055)/1.055,2.4),fe=e=>.2126*me(e[0])+.7152*me(e[1])+.0722*me(e[2]),tt=[.07,.06,.08],ot=[209/255,190/255,173/255],it=[1,.42,.48],te=e=>fe(e)>.06?R(tt,e,.06):ot,oe=e=>R(e,it,.78);var J=["eyeOpen","eyeSize","lookX","lookY","lidCover","lidTilt","happyEye","closedEye","xEye","heartEye","mouthW","mouthCurve","mouthOpen","mouthRound","mouthSkew","mouthWave","blush"],Y={eyeOpen:1,eyeSize:1,lookX:0,lookY:0,lidCover:0,lidTilt:0,happyEye:0,closedEye:0,xEye:0,heartEye:0,mouthW:.1,mouthCurve:.35,mouthOpen:0,mouthRound:0,mouthSkew:0,mouthWave:0,blush:.45},ie={idle:{...Y},thinking:{...Y,eyeOpen:.92,lookX:.7,lookY:-0.8,lidCover:.12,mouthW:.065,mouthCurve:0,mouthSkew:.8,blush:.3},loading:{...Y,lidCover:.48,mouthW:.06,mouthCurve:.12,blush:.3},listening:{...Y,eyeOpen:1.12,eyeSize:1.16,mouthW:.06,mouthCurve:.2,mouthOpen:.02},speaking:{...Y,mouthW:.09,mouthCurve:.25},happy:{...Y,happyEye:1,mouthW:.13,mouthCurve:1,mouthOpen:.08,blush:1},surprised:{...Y,eyeOpen:1.25,eyeSize:1.22,mouthW:.06,mouthCurve:0,mouthOpen:.12,mouthRound:1,blush:.35},sad:{...Y,eyeOpen:.95,lidCover:.32,lidTilt:.5,lookY:.45,mouthW:.08,mouthCurve:-0.75,blush:.2},error:{...Y,xEye:1,mouthW:.1,mouthCurve:-0.2,mouthWave:1,blush:.15},sleeping:{...Y,closedEye:1,mouthW:.04,mouthCurve:0,mouthOpen:.035,mouthRound:.7,blush:.55},love:{...Y,heartEye:1,mouthW:.11,mouthCurve:.9,mouthOpen:.03,blush:1}},Le={idle:1,thinking:.15,loading:0,listening:1,speaking:.9,happy:.6,surprised:.8,sad:.3,error:.3,sleeping:0,love:.7},ve=e=>({...e}),st=.31,nt=-0.04,at=.098,be=.128,rt=.2,ge=.05;function ye(e,o,t,i,s,n,u,r,l,d,a=false){let h=e.canvas.width;e.setTransform(1,0,0,1,0,0),e.clearRect(0,0,h,h),e.setTransform(h/2,0,0,h/2,h/2,h/2),e.lineCap="round",e.lineJoin="round";let p=o.lookX*.075,m=o.lookY*.06;if(o.blush>.01&&!a){let T=h*.018;e.save(),"filter"in e&&(e.filter=`blur(${T}px)`);for(let g of [-1,1]){let b=g*.52+p,c=.16+m,v=e.createRadialGradient(b,c,0,b,c,.16);v.addColorStop(0,s),v.addColorStop(1,"rgba(0,0,0,0)"),e.globalAlpha=Math.min(1,o.blush)*.62,e.fillStyle=v,e.beginPath(),e.ellipse(b,c,.17,.12,0,0,Math.PI*2),e.fill();}e.restore();let f=Math.min(1,Math.max(0,(o.blush-.6)/.4));if(f>.01){e.save(),e.globalAlpha=f*.55,e.strokeStyle=s,e.lineWidth=.016,e.lineCap="round";for(let g of [-1,1]){let b=g*.52+p,c=.16+m;for(let v=-1;v<=1;v++){let P=b+v*.045;e.beginPath(),e.moveTo(P+.018,c-.035),e.lineTo(P-.018,c+.035),e.stroke();}}e.restore();}}e.fillStyle=i,e.strokeStyle=i,e.lineWidth=ge;let E=Math.min(1,o.happyEye+o.closedEye+o.xEye+o.heartEye),S=1-E;for(let T of [-1,1]){let f=T*st+p,g=nt+m,b=at*o.eyeSize;if(S>.01){e.globalAlpha=S;let c=Math.max(.06,o.eyeOpen*t),v=be*o.eyeSize*c;if(e.save(),o.lidCover>.01||o.lidTilt>.01){let W=g-be*o.eyeSize+2*be*o.eyeSize*o.lidCover;e.translate(f,W),e.rotate(T*o.lidTilt*.6),e.beginPath(),e.rect(-1,0,2,2),e.clip(),e.rotate(-T*o.lidTilt*.6),e.translate(-f,-W);}n>.5&&!a&&Oe(e,f,g,b*2.1,v*1.9,i,.35*S);let P=e.createRadialGradient(f,g-v*.2,0,f,g,Math.max(b,v));if(P.addColorStop(0,u),P.addColorStop(1,i),e.fillStyle=P,e.beginPath(),e.ellipse(f,g,b,v,0,0,Math.PI*2),e.fill(),e.fillStyle=i,c>.35&&!a){let F=Math.max(-1,Math.min(1,o.lookX)),W=Math.max(-1,Math.min(1,o.lookY)),ue=r==="#fff"?.3:.34;e.globalAlpha=S*Math.min(1,(c-.35)*3),e.fillStyle=r,e.beginPath(),e.arc(f-b*.1+F*b*.5,g-v*.16+W*v*.42,b*ue,0,Math.PI*2),e.fill(),e.fillStyle=i;}e.restore();}if(n>.5&&!a&&E>.01&&Oe(e,f,g,b*2,b*1.8,i,.3*E),e.fillStyle=i,o.happyEye>.01){let c=.6+.4*o.happyEye;e.globalAlpha=Math.min(1,o.happyEye),e.beginPath(),e.arc(f,g+.045,b*1.15*c,Math.PI*1.12,Math.PI*1.88),e.stroke();}if(o.closedEye>.01){let c=.6+.4*o.closedEye;e.globalAlpha=Math.min(1,o.closedEye),e.beginPath(),e.moveTo(f-b*1.15*c,g+.01),e.quadraticCurveTo(f,g+.07*c,f+b*1.15*c,g+.01),e.stroke();}if(o.xEye>.01){let c=b*.95*(.6+.4*o.xEye);e.globalAlpha=Math.min(1,o.xEye),e.beginPath(),e.moveTo(f-c,g-c),e.lineTo(f+c,g+c),e.moveTo(f+c,g-c),e.lineTo(f-c,g+c),e.stroke();}o.heartEye>.01&&(e.globalAlpha=Math.min(1,o.heartEye),Me(e,f,g,b*1.35*(.5+.5*o.heartEye)),e.fill());}let w=p+o.mouthSkew*.07,k=rt+m,C=Math.min(1,Math.max(0,o.mouthRound)),L=o.mouthW,B=e.createLinearGradient(w-L-.02,k,w+L+.02,k);B.addColorStop(0,d),B.addColorStop(.5,u),B.addColorStop(1,d);let A=(T,f,g,b)=>{e.fillStyle=l,T(),e.fill(),f>.02&&!a&&(e.save(),T(),e.clip(),e.fillStyle=s,e.globalAlpha*=Math.min(1,(f-.02)*12),e.beginPath(),e.ellipse(w,g,b,f*.55,0,0,Math.PI*2),e.fill(),e.restore()),e.strokeStyle=B;let c=e.lineWidth;e.lineWidth=c*.6,T(),e.stroke(),e.lineWidth=c;};if(C<.99){e.globalAlpha=1-C;let T=18,f=v=>o.mouthCurve*.075*(1-v*v),g=(v,P)=>{let F=v/T*2-1,W=w+F*L,ue=k+f(F)+o.mouthSkew*F*.03+o.mouthWave*.018*Math.sin((F+1)*Math.PI*2)+P*(1-F*F);return [W,ue]},b=Math.max(0,o.mouthOpen),c=()=>{for(let v=0;v<=T;v++){let[P,F]=g(v,-b*.15);v?e.lineTo(P,F):e.moveTo(P,F);}};b>.003?A(()=>{e.beginPath(),c();for(let P=T;P>=0;P--){let[F,W]=g(P,b);e.lineTo(F,W);}e.closePath();},b,g(T/2,b)[1],L*.55):(e.strokeStyle=B,e.beginPath(),c(),e.stroke());}if(C>.01){e.globalAlpha=C;let T=Math.max(.02,o.mouthOpen*.55+.01),f=()=>{e.beginPath(),e.ellipse(w,k+.01,T*.85,T,0,0,Math.PI*2);};e.lineWidth=ge*.8,A(f,o.mouthOpen,k+.01+T*.8,T*.6),e.lineWidth=ge;}e.globalAlpha=1;}function Oe(e,o,t,i,s,n,u){let r=e.createRadialGradient(o,t,0,o,t,1);r.addColorStop(0,n),r.addColorStop(1,"rgba(0,0,0,0)"),e.save(),e.globalAlpha=u,e.translate(o,t),e.scale(i,s),e.translate(-o,-t),e.fillStyle=r,e.beginPath(),e.arc(o,t,1,0,Math.PI*2),e.fill(),e.restore();}function Me(e,o,t,i){e.beginPath(),e.moveTo(o,t+i*.85),e.bezierCurveTo(o-i*1.25,t+i*.05,o-i*.75,t-i*.95,o,t-i*.35),e.bezierCurveTo(o+i*.75,t-i*.95,o+i*1.25,t+i*.05,o,t+i*.85),e.closePath();}var Z=()=>({y:0,rx:0,ry:0,rz:0,st:0,mouth:0,lookX:0,lookY:0}),{sin:M,cos:ht,abs:lt,max:se,exp:ct,PI:ne}=Math;function ae(e,o,t,i){switch(i.y=i.rx=i.ry=i.rz=i.st=i.mouth=i.lookX=i.lookY=0,e){case "idle":{let s=M(o*1.6);i.y=.015*s,i.st=.018*s;break}case "thinking":{i.rz=.07*M(o*1.1),i.y=.02*M(o*2.2),i.ry=.15,i.rx=-0.06;break}case "loading":{let s=o*2.4;i.rx=.12*M(s),i.rz=.12*ht(s),i.ry=.22*M(s),i.y=.02*M(s*2),i.lookX=.55*M(s);break}case "listening":{let s=se(0,M(o*3.2));i.rx=.09*s*s;let n=lt(M(o*7.1)*.5+M(o*11.3)*.3+M(o*3.7)*.2);i.st=.03*n;break}case "speaking":{let s=se(0,M(o*9)*.6+M(o*14.3)*.4)*(.65+.35*M(o*1.7));i.mouth=.11*s,i.st=.04*s,i.rz=.03*M(o*2.1);break}case "happy":{let s=o*1.35%1;i.y=.2*M(ne*s);let n=se(0,1-s/.14)+se(0,(s-.9)/.1);i.st=.08*M(ne*s)-.14*n,i.rz=.05*M(o*1.35*ne);break}case "surprised":{if(t<.45){let s=M(ne*t/.45);i.y=.16*s,i.st=.12*s;}i.rz=.01*M(o*38)*ct(-t*2),i.rx=-0.06;break}case "sad":{let s=M(o*1.1);i.y=-0.06,i.rx=.2,i.st=-0.04+.015*s,i.rz=-0.04;break}case "error":{let s=t%2.8;if(s<.55){let n=1-s/.55;i.ry=.26*M(s*42)*n,i.rz=.05*M(s*42+1)*n;}i.st=-0.02;break}case "sleeping":{let s=M(o*1);i.st=.04*s,i.y=-0.03,i.rz=.1,i.rx=.1;break}case "love":{i.y=.07+.06*M(o*1.6),i.rz=.05*M(o*.8),i.st=.015*M(o*1.6+1);break}}return i}function we(e,o,t,i){for(let s of Object.keys(i))i[s]=e[s]+(o[s]-e[s])*t;return i}var Ge={thinking:"dots",sleeping:"zz",love:"hearts",listening:"waves",surprised:"bang"};var K=new Set,x=null,$=0,V=0,re=0,Ce,De=false,j="idle",_={x:0,y:0,lastMove:-1e9,known:false},O={reducedMotion:false,lowPower:false};function dt(){if(De)return;De=true,addEventListener("pointermove",o=>{_.x=o.clientX,_.y=o.clientY,_.lastMove=performance.now(),_.known=true;},{passive:true}),document.addEventListener("visibilitychange",H);let e=matchMedia("(prefers-reduced-motion: reduce)");O.reducedMotion=e.matches,e.addEventListener?.("change",o=>O.reducedMotion=o.matches);}function Ie(e,o){return x||(x=new WebGLRenderer({antialias:true,alpha:true,powerPreference:"low-power",preserveDrawingBuffer:true}),x.setPixelRatio(1),x.setClearColor(0,0),O.lowPower=pt(x.getContext()),x.setScissorTest(true),x.domElement.addEventListener("webglcontextlost",t=>{t.preventDefault(),x?.dispose(),x=null,$=V=0,j="idle";})),(e>$||o>V)&&($=Math.max($,e),V=Math.max(V,o),x.setSize($,V,false)),x}var qe=()=>V;function pt(e){try{let o=e.getExtension("WEBGL_debug_renderer_info"),t=String(e.getParameter(o?o.UNMASKED_RENDERER_WEBGL:e.RENDERER));return /swiftshader|llvmpipe|softpipe|software|basic render/i.test(t)}catch{return false}}function We(e,o){if(j==="ready")return true;if(j==="idle"&&x){j="compiling";let t=x;t.compileAsync(e,o).catch(()=>{}).then(()=>{t===x&&(j="ready"),H();});}return false}function _e(e){dt(),clearTimeout(Ce),K.add(e),H();}function He(e){K.delete(e),K.size===0&&(clearTimeout(Ce),Ce=setTimeout(()=>{K.size||!x||(x.dispose(),x.forceContextLoss(),x=null,$=V=0,j="idle");},1500));}function H(){if(!re){for(let e of K)if(e.active){re=requestAnimationFrame(Ne);return}}}var mt=10,Ye=new WeakMap,ke=0;function Ne(e){re=0;let o=[...K].filter(n=>n.active);if(!o.length)return;let t=performance.now(),i=o.length,s=0;for(;s<i;s++){let n=o[(ke+s)%i],u=Ye.get(n)??e-16;if(Ye.set(n,e),n.tick(Math.min(.05,Math.max(0,(e-u)/1e3)),e),performance.now()-t>mt){s++;break}}ke=(ke+s)%i,re=requestAnimationFrame(Ne);}var Q={pebble:{faceY:.02,faceScale:1.3,animated:false},blob:{faceY:.02,faceScale:1.28,animated:true},drop:{faceY:-0.24,faceScale:1.22,animated:false},bean:{faceY:.14,faceScale:.92,animated:false},cube:{faceY:0,faceScale:1.22,animated:false},ghost:{faceY:.22,faceScale:1.24,animated:true}};function Ve(e){let o=new SphereGeometry(1,e*2,Math.round(e*1.5)),t=o.getAttribute("position"),i=o.getIndex(),s=new Map,n=[],u=new Uint32Array(t.count);for(let a=0;a<t.count;a++){let h=t.getX(a),p=t.getY(a),m=t.getZ(a),E=`${Math.round(h*1e4)},${Math.round(p*1e4)},${Math.round(m*1e4)}`,S=s.get(E);if(S===void 0){S=n.length/3,s.set(E,S);let w=Math.hypot(h,p,m)||1;n.push(h/w,p/w,m/w);}u[a]=S;}let r=[];for(let a=0;a<i.count;a+=3){let h=u[i.getX(a)],p=u[i.getX(a+1)],m=u[i.getX(a+2)];h!==p&&p!==m&&h!==m&&r.push(h,p,m);}o.dispose();let l=new BufferGeometry,d=new Float32Array(n);return l.setAttribute("position",new BufferAttribute(new Float32Array(d),3)),l.setIndex(r),{geometry:l,dirs:d}}var vt=(e,o,t)=>{let i=Math.min(1,Math.max(0,(t-e)/(o-e)));return i*i*(3-2*i)};function Se(e,o,t,i,s,n,u){let r=o,l=t,d=i;switch(e){case "pebble":{r=o*1.1+.04*t,l=t*.92*(.95+.05*Math.tanh(3*t))+.03*o,d=i*.94;break}case "blob":{let a=.97+.045*Math.sin(2.1*o+1.3*s)*Math.sin(2.4*t+1.7*s+1)+.035*Math.sin(2.7*i+2.3*o+1.1*s);r=o*a,l=t*a,d=i*a;break}case "drop":{let a=Math.max(t,0),h=1-.8*Math.pow(a,1.6);r=o*h*.98+.1*a*a*a,l=(t<0?t*.9:t*1.32)-.12,d=i*h*.98;break}case "bean":{let a=t*.78+.42*Math.tanh(t*3);r=(o*.8+.14*(a*a/1.44)-.07)*.9,l=a*.88,d=i*.8*.9;break}case "cube":{let h=Math.pow(Math.pow(Math.abs(o),4.5)+Math.pow(Math.abs(t),4.5)+Math.pow(Math.abs(i),4.5),-0.2222222222222222);r=o*h*.84,l=t*h*.82,d=i*h*.84;break}case "ghost":{if(t>=0)r=o,l=t,d=i;else {let h=(Math.acos(Math.max(-1,t))-Math.PI/2)/(Math.PI/2),p=Math.hypot(o,i)||1,m=o/p,E=i/p,S=Math.atan2(i,o),w=.085*Math.sin(5*S+2.2*s),k=1.04,C=.13,L=-1.05+w,B;if(h<.45){let A=h/.45;B=1+.04*A,l=-A*(1.05-C)+w*vt(.45,1,A);}else if(h<.75){let A=(h-.45)/.3*(Math.PI/2);B=k-C+C*Math.cos(A),l=L+C-C*Math.sin(A);}else {let A=(h-.75)/.25;B=(k-C)*(1-A),l=L+.22*A*A*(3-2*A);}r=m*B,d=E*B;}r*=.9,l=(l+.1)*.9,d*=.9;break}}n[u]=r,n[u+1]=l,n[u+2]=d;}var I=null,he=null;function yt(){if(typeof window>"u"||!("AudioContext"in window))return null;if(Mt(),!I){I=new AudioContext;let e=I.createBiquadFilter();e.type="lowpass",e.frequency.value=3200,he=I.createGain(),he.gain.value=.55,he.connect(e).connect(I.destination);}return I.state==="suspended"&&I.resume(),I}function z(e,{freq:o,to:t,at:i=0,dur:s=.12,type:n="sine",gain:u=.1,wobble:r=0}){let l=e.currentTime+i,d=e.createOscillator(),a=e.createGain();if(d.type=n,d.frequency.setValueAtTime(o,l),t&&d.frequency.exponentialRampToValueAtTime(t,l+s),r){let h=e.createOscillator(),p=e.createGain();h.frequency.value=7,p.gain.value=r,h.connect(p).connect(d.frequency),h.start(l),h.stop(l+s+.05);}a.gain.setValueAtTime(1e-4,l),a.gain.exponentialRampToValueAtTime(u,l+Math.min(.012,s/4)),a.gain.exponentialRampToValueAtTime(1e-4,l+s),d.connect(a).connect(he),d.start(l),d.stop(l+s+.02);}var Te={idle:e=>z(e,{freq:520,to:780,dur:.09,gain:.08}),thinking:e=>[660,760,900].forEach((o,t)=>z(e,{freq:o,to:o*1.08,at:t*.1,dur:.07,type:"triangle",gain:.06})),loading:e=>[0,.14,.28].forEach(o=>z(e,{freq:940,at:o,dur:.04,gain:.05})),listening:e=>{z(e,{freq:523,dur:.12,type:"triangle",gain:.07}),z(e,{freq:784,at:.1,dur:.22,type:"triangle",gain:.07});},speaking:e=>[380,460,340,520,420].forEach((o,t)=>z(e,{freq:o,to:o*1.15,at:t*.075,dur:.06,type:"triangle",gain:.06})),happy:e=>[523,659,784,1047].forEach((o,t)=>z(e,{freq:o,at:t*.07,dur:.14,type:"triangle",gain:.07})),surprised:e=>z(e,{freq:280,to:980,dur:.18,gain:.09,wobble:30}),sad:e=>{z(e,{freq:560,to:300,dur:.5,gain:.07}),z(e,{freq:420,to:240,at:.12,dur:.5,gain:.04});},error:e=>[0,.14].forEach(o=>z(e,{freq:170,to:150,at:o,dur:.1,type:"sawtooth",gain:.045})),sleeping:e=>{z(e,{freq:150,to:115,dur:.6,gain:.07,wobble:6}),z(e,{freq:300,to:230,at:.05,dur:.5,gain:.02});},love:e=>[1319,1568,2093,1760].forEach((o,t)=>z(e,{freq:o,at:t*.08,dur:.22,gain:.04}))},q=null,Xe=false;function Mt(){if(Xe)return;Xe=true;let e=()=>{I&&I.resume().then(()=>{q&&performance.now()<q.until&&Te[q.mood](I),q=null;});};for(let o of ["pointerdown","touchend","keydown"])addEventListener(o,e,{passive:true});}function le(e,o=false){let t=yt();if(t){if(t.state==="running"){q=null,Te[e](t);return}q={mood:e,until:performance.now()+(o?6e3:1200)},t.resume().then(()=>{q&&performance.now()<q.until&&Te[q.mood](t),q=null;});}}var Ee=-0.85,Je=new Map;function Et(e){let o=Je.get(e);if(!o){let{geometry:t,dirs:i}=Ve(e);o={dirs:i,index:new Uint32Array(t.getIndex().array)},t.dispose(),Je.set(e,o);}return o}var U=(e,o)=>1-Math.exp(-e*o),Pe=e=>1-Math.pow(1-e,3),ce=class{constructor(){this.scene=new Scene;this.camera=new PerspectiveCamera(30,1,.1,50);this.group=new Group;this.v=new Vector3;this.geometry=new BufferGeometry;this.faceCanvas=document.createElement("canvas");this.heightCanvas=document.createElement("canvas");this.uniforms={uFace:{value:null},uHeight:{value:null},uFaceY:{value:0},uFaceScale:{value:1.5}};this.state={...y};this.visible=false;this.connected=false;this.w=0;this.h=0;this.t=Math.random()*100;this.shapeFrom=y.shape;this.shapeTo=y.shape;this.morph=1;this.shapeDirty=true;this.shown=y.mood;this.prevShown=y.mood;this.tau=10;this.prevTau=10;this.blend=1;this.reaction=null;this.pose=Z();this.poseIdle=Z();this.moodTime=0;this.poseA=Z();this.poseB=Z();this.face=ve(ie.idle);this.target=ve(ie.idle);this.drawn=new Float32Array(J.length+7).fill(NaN);this.blink=1;this.blinkT=-1;this.nextBlink=2+Math.random()*3;this.body=X(y.color,[.95,.63,.48]);this.bodyT=this.body;this.faceC=te(this.body);this.faceCT=this.faceC;this.cheek=oe(this.body);this.cheekT=this.cheek;this.look={x:0,y:0};this.wander={x:0,y:0,next:0};this.squash=0;this.squashV=0;this.pop=.6;this.popV=0;this.hover=0;this.hovering=false;this.overlay={dots:0,zz:0,hearts:0,waves:0,bang:0};this.needsFrame=true;this.ready=false;this.css=[0,0];this.quality=1;this.lowPowerApplied=false;this.cost=0;this.costFrames=0;this.lastFrame=[];this.canvas=document.createElement("canvas"),this.ctx=this.canvas.getContext("2d"),this.faceCtx=this.faceCanvas.getContext("2d"),this.faceCanvas.width=this.faceCanvas.height=256,this.faceTex=new CanvasTexture(this.faceCanvas),this.faceTex.colorSpace=SRGBColorSpace,this.faceTex.minFilter=LinearMipmapLinearFilter,this.faceTex.anisotropy=4,this.uniforms.uFace.value=this.faceTex,this.heightCtx=this.heightCanvas.getContext("2d"),this.heightCanvas.width=this.heightCanvas.height=256,this.heightTex=new CanvasTexture(this.heightCanvas),this.heightTex.minFilter=LinearMipmapLinearFilter,this.uniforms.uHeight.value=this.heightTex,this.setSegments(24),this.material=this.createMaterial(),this.mesh=new Mesh(this.geometry,this.material),this.mesh.frustumCulled=false,this.mesh.position.y=-Ee,this.group.add(this.mesh),this.scene.add(this.group),this.scene.add(new HemisphereLight(16774120,7234140,1.7));let o=new DirectionalLight(16777215,1.9);o.position.set(2.5,3.5,4);let t=new DirectionalLight(16770770,1.4);t.position.set(-3.5,2,-3);let i=new DirectionalLight(16773350,.45);i.position.set(-2,-1,3),this.scene.add(o,t,i),this.camera.position.set(0,.3,6.6),this.camera.lookAt(0,.12,0);}get active(){return this.visible&&this.connected&&this.w>0}createMaterial(){let o=new MeshStandardMaterial({roughness:.62,metalness:0});return o.color.setRGB(...this.body,SRGBColorSpace),o.customProgramCacheKey=()=>"moodi-1",o.onBeforeCompile=t=>{Object.assign(t.uniforms,this.uniforms),t.vertexShader=t.vertexShader.replace("#include <common>",`#include <common>
1
+ import {Scene,PerspectiveCamera,Group,Vector3,BufferGeometry,CanvasTexture,SRGBColorSpace,LinearMipmapLinearFilter,Mesh,HemisphereLight,DirectionalLight,MeshStandardMaterial,BufferAttribute,WebGLRenderer,SphereGeometry}from'three';var Qe=["ghost","pebble","blob","drop","bean","cube"],et=["idle","thinking","loading","listening","speaking","happy","surprised","sad","error","sleeping","love"],y={shape:"ghost",mood:"idle",color:"#2b15d1",size:160,speed:1,followCursor:true,interactive:true,shadow:true,sound:false,settle:0},Ot={Iris:"#2b15d1",Peach:"#f2a07b",Sage:"#8fb996",Sky:"#8ec5e8",Lilac:"#b9a3e3",Butter:"#f3d36b",Coral:"#f07167",Ink:"#2b2d42",Cloud:"#ecebe8"},Lt={idle:{label:"Idle",description:"Breathing softly. Blinks now and then."},thinking:{label:"Thinking",description:"Eyes drift up. Little thoughts pop."},loading:{label:"Loading",description:"Half-lidded, wobbling patiently."},listening:{label:"Listening",description:"All eyes. Nods along to every word."},speaking:{label:"Speaking",description:"Chatty mouth, bouncing to the rhythm."},happy:{label:"Happy",description:"Bounces with joy. Cheeks glow."},surprised:{label:"Surprised",description:"Wide eyes, tiny o. Did not see that coming."},sad:{label:"Sad",description:"Slumps a little. Needs a minute."},error:{label:"Error",description:"Something broke. Shakes it off."},sleeping:{label:"Sleeping",description:"Deep, slow breaths. Do not disturb."},love:{label:"Love",description:"Heart eyes, floating on air."}},Gt={pebble:"Pebble",blob:"Blob",drop:"Drop",bean:"Bean",cube:"Cube",ghost:"Ghost"},pe=e=>Qe.includes(e),J=e=>et.includes(e);var G=null;function X(e,o){if(!e)return o;let t=/^#?([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(e.trim());if(t)return Be(t[1]);if(G||(G=document.createElement("canvas").getContext("2d")),!G)return o;G.fillStyle="#010203",G.fillStyle=e;let i=String(G.fillStyle);if(i==="#010203"&&e.trim()!=="#010203")return o;if(i.startsWith("#"))return Be(i.slice(1));G.canvas.width=G.canvas.height=1,G.clearRect(0,0,1,1),G.fillRect(0,0,1,1);let s=G.getImageData(0,0,1,1).data;return [s[0]/255,s[1]/255,s[2]/255]}function Be(e){e.length===3&&(e=e[0]+e[0]+e[1]+e[1]+e[2]+e[2]);let o=parseInt(e,16);return [(o>>16&255)/255,(o>>8&255)/255,(o&255)/255]}var D=e=>`rgb(${Math.round(e[0]*255)},${Math.round(e[1]*255)},${Math.round(e[2]*255)})`,R=(e,o,t)=>[e[0]+(o[0]-e[0])*t,e[1]+(o[1]-e[1])*t,e[2]+(o[2]-e[2])*t],me=e=>e<=.04045?e/12.92:Math.pow((e+.055)/1.055,2.4),fe=e=>.2126*me(e[0])+.7152*me(e[1])+.0722*me(e[2]),tt=[.07,.06,.08],ot=[209/255,190/255,173/255],it=[1,.42,.48],oe=e=>fe(e)>.042?R(tt,e,.06):ot,ie=e=>R(e,it,.78);var Z=["eyeOpen","eyeSize","lookX","lookY","lidCover","lidTilt","happyEye","closedEye","xEye","heartEye","mouthW","mouthCurve","mouthOpen","mouthRound","mouthSkew","mouthWave","blush"],Y={eyeOpen:1,eyeSize:1,lookX:0,lookY:0,lidCover:0,lidTilt:0,happyEye:0,closedEye:0,xEye:0,heartEye:0,mouthW:.1,mouthCurve:.35,mouthOpen:0,mouthRound:0,mouthSkew:0,mouthWave:0,blush:.45},se={idle:{...Y},thinking:{...Y,eyeOpen:.92,lookX:.7,lookY:-0.8,lidCover:.12,mouthW:.065,mouthCurve:0,mouthSkew:.8,blush:.3},loading:{...Y,lidCover:.48,mouthW:.06,mouthCurve:.12,blush:.3},listening:{...Y,eyeOpen:1.12,eyeSize:1.16,mouthW:.06,mouthCurve:.2,mouthOpen:.02},speaking:{...Y,mouthW:.09,mouthCurve:.25},happy:{...Y,happyEye:1,mouthW:.13,mouthCurve:1,mouthOpen:.08,blush:1},surprised:{...Y,eyeOpen:1.25,eyeSize:1.22,mouthW:.06,mouthCurve:0,mouthOpen:.12,mouthRound:1,blush:.35},sad:{...Y,eyeOpen:.95,lidCover:.32,lidTilt:.5,lookY:.45,mouthW:.08,mouthCurve:-0.75,blush:.2},error:{...Y,xEye:1,mouthW:.1,mouthCurve:-0.2,mouthWave:1,blush:.15},sleeping:{...Y,closedEye:1,mouthW:.04,mouthCurve:0,mouthOpen:.035,mouthRound:.7,blush:.55},love:{...Y,heartEye:1,mouthW:.11,mouthCurve:.9,mouthOpen:.03,blush:1}},Le={idle:1,thinking:.15,loading:0,listening:1,speaking:.9,happy:.6,surprised:.8,sad:.3,error:.3,sleeping:0,love:.7},ve=e=>({...e}),st=.31,nt=-0.04,at=.098,be=.128,rt=.2,ge=.05;function ye(e,o,t,i,s,n,u,r,l,d,a=false){let h=e.canvas.width;e.setTransform(1,0,0,1,0,0),e.clearRect(0,0,h,h),e.setTransform(h/2,0,0,h/2,h/2,h/2),e.lineCap="round",e.lineJoin="round";let p=o.lookX*.075,m=o.lookY*.06;if(o.blush>.01&&!a){let T=h*.018;e.save(),"filter"in e&&(e.filter=`blur(${T}px)`);for(let g of [-1,1]){let b=g*.52+p,c=.16+m,v=e.createRadialGradient(b,c,0,b,c,.16);v.addColorStop(0,s),v.addColorStop(1,"rgba(0,0,0,0)"),e.globalAlpha=Math.min(1,o.blush)*.62,e.fillStyle=v,e.beginPath(),e.ellipse(b,c,.17,.12,0,0,Math.PI*2),e.fill();}e.restore();let f=Math.min(1,Math.max(0,(o.blush-.6)/.4));if(f>.01){e.save(),e.globalAlpha=f*.55,e.strokeStyle=s,e.lineWidth=.016,e.lineCap="round";for(let g of [-1,1]){let b=g*.52+p,c=.16+m;for(let v=-1;v<=1;v++){let P=b+v*.045;e.beginPath(),e.moveTo(P+.018,c-.035),e.lineTo(P-.018,c+.035),e.stroke();}}e.restore();}}e.fillStyle=i,e.strokeStyle=i,e.lineWidth=ge;let E=Math.min(1,o.happyEye+o.closedEye+o.xEye+o.heartEye),S=1-E;for(let T of [-1,1]){let f=T*st+p,g=nt+m,b=at*o.eyeSize;if(S>.01){e.globalAlpha=S;let c=Math.max(.06,o.eyeOpen*t),v=be*o.eyeSize*c;if(e.save(),o.lidCover>.01||o.lidTilt>.01){let W=g-be*o.eyeSize+2*be*o.eyeSize*o.lidCover;e.translate(f,W),e.rotate(T*o.lidTilt*.6),e.beginPath(),e.rect(-1,0,2,2),e.clip(),e.rotate(-T*o.lidTilt*.6),e.translate(-f,-W);}n>.5&&!a&&Oe(e,f,g,b*2.1,v*1.9,i,.35*S);let P=e.createRadialGradient(f,g-v*.2,0,f,g,Math.max(b,v));if(P.addColorStop(0,u),P.addColorStop(1,i),e.fillStyle=P,e.beginPath(),e.ellipse(f,g,b,v,0,0,Math.PI*2),e.fill(),e.fillStyle=i,c>.35&&!a){let F=Math.max(-1,Math.min(1,o.lookX)),W=Math.max(-1,Math.min(1,o.lookY)),de=r==="#fff"?.3:.34;e.globalAlpha=S*Math.min(1,(c-.35)*3),e.fillStyle=r,e.beginPath(),e.arc(f-b*.1+F*b*.5,g-v*.16+W*v*.42,b*de,0,Math.PI*2),e.fill(),e.fillStyle=i;}e.restore();}if(n>.5&&!a&&E>.01&&Oe(e,f,g,b*2,b*1.8,i,.3*E),e.fillStyle=i,o.happyEye>.01){let c=.6+.4*o.happyEye;e.globalAlpha=Math.min(1,o.happyEye),e.beginPath(),e.arc(f,g+.045,b*1.15*c,Math.PI*1.12,Math.PI*1.88),e.stroke();}if(o.closedEye>.01){let c=.6+.4*o.closedEye;e.globalAlpha=Math.min(1,o.closedEye),e.beginPath(),e.moveTo(f-b*1.15*c,g+.01),e.quadraticCurveTo(f,g+.07*c,f+b*1.15*c,g+.01),e.stroke();}if(o.xEye>.01){let c=b*.95*(.6+.4*o.xEye);e.globalAlpha=Math.min(1,o.xEye),e.beginPath(),e.moveTo(f-c,g-c),e.lineTo(f+c,g+c),e.moveTo(f+c,g-c),e.lineTo(f-c,g+c),e.stroke();}o.heartEye>.01&&(e.globalAlpha=Math.min(1,o.heartEye),Me(e,f,g,b*1.35*(.5+.5*o.heartEye)),e.fill());}let w=p+o.mouthSkew*.07,k=rt+m,C=Math.min(1,Math.max(0,o.mouthRound)),L=o.mouthW,B=e.createLinearGradient(w-L-.02,k,w+L+.02,k);B.addColorStop(0,d),B.addColorStop(.5,u),B.addColorStop(1,d);let A=(T,f,g,b)=>{e.fillStyle=l,T(),e.fill(),f>.02&&!a&&(e.save(),T(),e.clip(),e.fillStyle=s,e.globalAlpha*=Math.min(1,(f-.02)*12),e.beginPath(),e.ellipse(w,g,b,f*.55,0,0,Math.PI*2),e.fill(),e.restore()),e.strokeStyle=B;let c=e.lineWidth;e.lineWidth=c*.6,T(),e.stroke(),e.lineWidth=c;};if(C<.99){e.globalAlpha=1-C;let T=18,f=v=>o.mouthCurve*.075*(1-v*v),g=(v,P)=>{let F=v/T*2-1,W=w+F*L,de=k+f(F)+o.mouthSkew*F*.03+o.mouthWave*.018*Math.sin((F+1)*Math.PI*2)+P*(1-F*F);return [W,de]},b=Math.max(0,o.mouthOpen),c=()=>{for(let v=0;v<=T;v++){let[P,F]=g(v,-b*.15);v?e.lineTo(P,F):e.moveTo(P,F);}};b>.003?A(()=>{e.beginPath(),c();for(let P=T;P>=0;P--){let[F,W]=g(P,b);e.lineTo(F,W);}e.closePath();},b,g(T/2,b)[1],L*.55):(e.strokeStyle=B,e.beginPath(),c(),e.stroke());}if(C>.01){e.globalAlpha=C;let T=Math.max(.02,o.mouthOpen*.55+.01),f=()=>{e.beginPath(),e.ellipse(w,k+.01,T*.85,T,0,0,Math.PI*2);};e.lineWidth=ge*.8,A(f,o.mouthOpen,k+.01+T*.8,T*.6),e.lineWidth=ge;}e.globalAlpha=1;}function Oe(e,o,t,i,s,n,u){let r=e.createRadialGradient(o,t,0,o,t,1);r.addColorStop(0,n),r.addColorStop(1,"rgba(0,0,0,0)"),e.save(),e.globalAlpha=u,e.translate(o,t),e.scale(i,s),e.translate(-o,-t),e.fillStyle=r,e.beginPath(),e.arc(o,t,1,0,Math.PI*2),e.fill(),e.restore();}function Me(e,o,t,i){e.beginPath(),e.moveTo(o,t+i*.85),e.bezierCurveTo(o-i*1.25,t+i*.05,o-i*.75,t-i*.95,o,t-i*.35),e.bezierCurveTo(o+i*.75,t-i*.95,o+i*1.25,t+i*.05,o,t+i*.85),e.closePath();}var Q=()=>({y:0,rx:0,ry:0,rz:0,st:0,mouth:0,lookX:0,lookY:0}),{sin:M,cos:ht,abs:lt,max:ne,exp:ct,PI:ae}=Math;function re(e,o,t,i){switch(i.y=i.rx=i.ry=i.rz=i.st=i.mouth=i.lookX=i.lookY=0,e){case "idle":{let s=M(o*1.6);i.y=.015*s,i.st=.018*s;break}case "thinking":{i.rz=.07*M(o*1.1),i.y=.02*M(o*2.2),i.ry=.15,i.rx=-0.06;break}case "loading":{let s=o*2.4;i.rx=.12*M(s),i.rz=.12*ht(s),i.ry=.22*M(s),i.y=.02*M(s*2),i.lookX=.55*M(s);break}case "listening":{let s=ne(0,M(o*3.2));i.rx=.09*s*s;let n=lt(M(o*7.1)*.5+M(o*11.3)*.3+M(o*3.7)*.2);i.st=.03*n;break}case "speaking":{let s=ne(0,M(o*9)*.6+M(o*14.3)*.4)*(.65+.35*M(o*1.7));i.mouth=.11*s,i.st=.04*s,i.rz=.03*M(o*2.1);break}case "happy":{let s=o*1.35%1;i.y=.2*M(ae*s);let n=ne(0,1-s/.14)+ne(0,(s-.9)/.1);i.st=.08*M(ae*s)-.14*n,i.rz=.05*M(o*1.35*ae);break}case "surprised":{if(t<.45){let s=M(ae*t/.45);i.y=.16*s,i.st=.12*s;}i.rz=.01*M(o*38)*ct(-t*2),i.rx=-0.06;break}case "sad":{let s=M(o*1.1);i.y=-0.06,i.rx=.2,i.st=-0.04+.015*s,i.rz=-0.04;break}case "error":{let s=t%2.8;if(s<.55){let n=1-s/.55;i.ry=.26*M(s*42)*n,i.rz=.05*M(s*42+1)*n;}i.st=-0.02;break}case "sleeping":{let s=M(o*1);i.st=.04*s,i.y=-0.03,i.rz=.1,i.rx=.1;break}case "love":{i.y=.07+.06*M(o*1.6),i.rz=.05*M(o*.8),i.st=.015*M(o*1.6+1);break}}return i}function we(e,o,t,i){for(let s of Object.keys(i))i[s]=e[s]+(o[s]-e[s])*t;return i}var Ge={thinking:"dots",sleeping:"zz",love:"hearts",listening:"waves",surprised:"bang"};var K=new Set,x=null,$=0,V=0,he=0,Ce,De=false,j="idle",_={x:0,y:0,lastMove:-1e9,known:false},O={reducedMotion:false,lowPower:false};function dt(){if(De)return;De=true,addEventListener("pointermove",o=>{_.x=o.clientX,_.y=o.clientY,_.lastMove=performance.now(),_.known=true;},{passive:true}),document.addEventListener("visibilitychange",H);let e=matchMedia("(prefers-reduced-motion: reduce)");O.reducedMotion=e.matches,e.addEventListener?.("change",o=>O.reducedMotion=o.matches);}function Ie(e,o){return x||(x=new WebGLRenderer({antialias:true,alpha:true,powerPreference:"low-power",preserveDrawingBuffer:true}),x.setPixelRatio(1),x.setClearColor(0,0),O.lowPower=pt(x.getContext()),x.setScissorTest(true),x.domElement.addEventListener("webglcontextlost",t=>{t.preventDefault(),x?.dispose(),x=null,$=V=0,j="idle";})),(e>$||o>V)&&($=Math.max($,e),V=Math.max(V,o),x.setSize($,V,false)),x}var qe=()=>V;function pt(e){try{let o=e.getExtension("WEBGL_debug_renderer_info"),t=String(e.getParameter(o?o.UNMASKED_RENDERER_WEBGL:e.RENDERER));return /swiftshader|llvmpipe|softpipe|software|basic render/i.test(t)}catch{return false}}function We(e,o){if(j==="ready")return true;if(j==="idle"&&x){j="compiling";let t=x;t.compileAsync(e,o).catch(()=>{}).then(()=>{t===x&&(j="ready"),H();});}return false}function _e(e){dt(),clearTimeout(Ce),K.add(e),H();}function He(e){K.delete(e),K.size===0&&(clearTimeout(Ce),Ce=setTimeout(()=>{K.size||!x||(x.dispose(),x.forceContextLoss(),x=null,$=V=0,j="idle");},1500));}function H(){if(!he){for(let e of K)if(e.active){he=requestAnimationFrame(Ne);return}}}var mt=10,Ye=new WeakMap,ke=0;function Ne(e){he=0;let o=[...K].filter(n=>n.active);if(!o.length)return;let t=performance.now(),i=o.length,s=0;for(;s<i;s++){let n=o[(ke+s)%i],u=Ye.get(n)??e-16;if(Ye.set(n,e),n.tick(Math.min(.05,Math.max(0,(e-u)/1e3)),e),performance.now()-t>mt){s++;break}}ke=(ke+s)%i,he=requestAnimationFrame(Ne);}var ee={pebble:{faceY:.02,faceScale:1.3,animated:false},blob:{faceY:.02,faceScale:1.28,animated:true},drop:{faceY:-0.24,faceScale:1.22,animated:false},bean:{faceY:.14,faceScale:.92,animated:false},cube:{faceY:0,faceScale:1.22,animated:false},ghost:{faceY:.22,faceScale:1.24,animated:true}};function Ve(e){let o=new SphereGeometry(1,e*2,Math.round(e*1.5)),t=o.getAttribute("position"),i=o.getIndex(),s=new Map,n=[],u=new Uint32Array(t.count);for(let a=0;a<t.count;a++){let h=t.getX(a),p=t.getY(a),m=t.getZ(a),E=`${Math.round(h*1e4)},${Math.round(p*1e4)},${Math.round(m*1e4)}`,S=s.get(E);if(S===void 0){S=n.length/3,s.set(E,S);let w=Math.hypot(h,p,m)||1;n.push(h/w,p/w,m/w);}u[a]=S;}let r=[];for(let a=0;a<i.count;a+=3){let h=u[i.getX(a)],p=u[i.getX(a+1)],m=u[i.getX(a+2)];h!==p&&p!==m&&h!==m&&r.push(h,p,m);}o.dispose();let l=new BufferGeometry,d=new Float32Array(n);return l.setAttribute("position",new BufferAttribute(new Float32Array(d),3)),l.setIndex(r),{geometry:l,dirs:d}}var vt=(e,o,t)=>{let i=Math.min(1,Math.max(0,(t-e)/(o-e)));return i*i*(3-2*i)};function Se(e,o,t,i,s,n,u){let r=o,l=t,d=i;switch(e){case "pebble":{r=o*1.1+.04*t,l=t*.92*(.95+.05*Math.tanh(3*t))+.03*o,d=i*.94;break}case "blob":{let a=.97+.045*Math.sin(2.1*o+1.3*s)*Math.sin(2.4*t+1.7*s+1)+.035*Math.sin(2.7*i+2.3*o+1.1*s);r=o*a,l=t*a,d=i*a;break}case "drop":{let a=Math.max(t,0),h=1-.8*Math.pow(a,1.6);r=o*h*.98+.1*a*a*a,l=(t<0?t*.9:t*1.32)-.12,d=i*h*.98;break}case "bean":{let a=t*.78+.42*Math.tanh(t*3);r=(o*.8+.14*(a*a/1.44)-.07)*.9,l=a*.88,d=i*.8*.9;break}case "cube":{let h=Math.pow(Math.pow(Math.abs(o),4.5)+Math.pow(Math.abs(t),4.5)+Math.pow(Math.abs(i),4.5),-0.2222222222222222);r=o*h*.84,l=t*h*.82,d=i*h*.84;break}case "ghost":{if(t>=0)r=o,l=t,d=i;else {let h=(Math.acos(Math.max(-1,t))-Math.PI/2)/(Math.PI/2),p=Math.hypot(o,i)||1,m=o/p,E=i/p,S=Math.atan2(i,o),w=.085*Math.sin(5*S+2.2*s),k=1.04,C=.13,L=-1.05+w,B;if(h<.45){let A=h/.45;B=1+.04*A,l=-A*(1.05-C)+w*vt(.45,1,A);}else if(h<.75){let A=(h-.45)/.3*(Math.PI/2);B=k-C+C*Math.cos(A),l=L+C-C*Math.sin(A);}else {let A=(h-.75)/.25;B=(k-C)*(1-A),l=L+.22*A*A*(3-2*A);}r=m*B,d=E*B;}r*=.9,l=(l+.1)*.9,d*=.9;break}}n[u]=r,n[u+1]=l,n[u+2]=d;}var I=null,le=null;function yt(){if(typeof window>"u"||!("AudioContext"in window))return null;if(Mt(),!I){I=new AudioContext;let e=I.createBiquadFilter();e.type="lowpass",e.frequency.value=3200,le=I.createGain(),le.gain.value=.55,le.connect(e).connect(I.destination);}return I.state==="suspended"&&I.resume(),I}function z(e,{freq:o,to:t,at:i=0,dur:s=.12,type:n="sine",gain:u=.1,wobble:r=0}){let l=e.currentTime+i,d=e.createOscillator(),a=e.createGain();if(d.type=n,d.frequency.setValueAtTime(o,l),t&&d.frequency.exponentialRampToValueAtTime(t,l+s),r){let h=e.createOscillator(),p=e.createGain();h.frequency.value=7,p.gain.value=r,h.connect(p).connect(d.frequency),h.start(l),h.stop(l+s+.05);}a.gain.setValueAtTime(1e-4,l),a.gain.exponentialRampToValueAtTime(u,l+Math.min(.012,s/4)),a.gain.exponentialRampToValueAtTime(1e-4,l+s),d.connect(a).connect(le),d.start(l),d.stop(l+s+.02);}var Te={idle:e=>z(e,{freq:520,to:780,dur:.09,gain:.08}),thinking:e=>[660,760,900].forEach((o,t)=>z(e,{freq:o,to:o*1.08,at:t*.1,dur:.07,type:"triangle",gain:.06})),loading:e=>[0,.14,.28].forEach(o=>z(e,{freq:940,at:o,dur:.04,gain:.05})),listening:e=>{z(e,{freq:523,dur:.12,type:"triangle",gain:.07}),z(e,{freq:784,at:.1,dur:.22,type:"triangle",gain:.07});},speaking:e=>[380,460,340,520,420].forEach((o,t)=>z(e,{freq:o,to:o*1.15,at:t*.075,dur:.06,type:"triangle",gain:.06})),happy:e=>[523,659,784,1047].forEach((o,t)=>z(e,{freq:o,at:t*.07,dur:.14,type:"triangle",gain:.07})),surprised:e=>z(e,{freq:280,to:980,dur:.18,gain:.09,wobble:30}),sad:e=>{z(e,{freq:560,to:300,dur:.5,gain:.07}),z(e,{freq:420,to:240,at:.12,dur:.5,gain:.04});},error:e=>[0,.14].forEach(o=>z(e,{freq:170,to:150,at:o,dur:.1,type:"sawtooth",gain:.045})),sleeping:e=>{z(e,{freq:150,to:115,dur:.6,gain:.07,wobble:6}),z(e,{freq:300,to:230,at:.05,dur:.5,gain:.02});},love:e=>[1319,1568,2093,1760].forEach((o,t)=>z(e,{freq:o,at:t*.08,dur:.22,gain:.04}))},q=null,Xe=false;function Mt(){if(Xe)return;Xe=true;let e=()=>{I&&I.resume().then(()=>{q&&performance.now()<q.until&&Te[q.mood](I),q=null;});};for(let o of ["pointerdown","touchend","keydown"])addEventListener(o,e,{passive:true});}function ce(e,o=false){let t=yt();if(t){if(t.state==="running"){q=null,Te[e](t);return}q={mood:e,until:performance.now()+(o?6e3:1200)},t.resume().then(()=>{q&&performance.now()<q.until&&Te[q.mood](t),q=null;});}}var Ee=-0.85,Je=new Map;function Et(e){let o=Je.get(e);if(!o){let{geometry:t,dirs:i}=Ve(e);o={dirs:i,index:new Uint32Array(t.getIndex().array)},t.dispose(),Je.set(e,o);}return o}var U=(e,o)=>1-Math.exp(-e*o),Pe=e=>1-Math.pow(1-e,3),ue=class{constructor(){this.scene=new Scene;this.camera=new PerspectiveCamera(30,1,.1,50);this.group=new Group;this.v=new Vector3;this.geometry=new BufferGeometry;this.faceCanvas=document.createElement("canvas");this.heightCanvas=document.createElement("canvas");this.uniforms={uFace:{value:null},uHeight:{value:null},uFaceY:{value:0},uFaceScale:{value:1.5}};this.state={...y};this.visible=false;this.connected=false;this.w=0;this.h=0;this.t=Math.random()*100;this.shapeFrom=y.shape;this.shapeTo=y.shape;this.morph=1;this.shapeDirty=true;this.shown=y.mood;this.prevShown=y.mood;this.tau=10;this.prevTau=10;this.blend=1;this.reaction=null;this.pose=Q();this.poseIdle=Q();this.moodTime=0;this.poseA=Q();this.poseB=Q();this.face=ve(se.idle);this.target=ve(se.idle);this.drawn=new Float32Array(Z.length+7).fill(NaN);this.blink=1;this.blinkT=-1;this.nextBlink=2+Math.random()*3;this.body=X(y.color,[.95,.63,.48]);this.bodyT=this.body;this.faceC=oe(this.body);this.faceCT=this.faceC;this.cheek=ie(this.body);this.cheekT=this.cheek;this.look={x:0,y:0};this.wander={x:0,y:0,next:0};this.squash=0;this.squashV=0;this.pop=.6;this.popV=0;this.hover=0;this.hovering=false;this.overlay={dots:0,zz:0,hearts:0,waves:0,bang:0};this.needsFrame=true;this.ready=false;this.css=[0,0];this.quality=1;this.lowPowerApplied=false;this.cost=0;this.costFrames=0;this.lastFrame=[];this.canvas=document.createElement("canvas"),this.ctx=this.canvas.getContext("2d"),this.faceCtx=this.faceCanvas.getContext("2d"),this.faceCanvas.width=this.faceCanvas.height=256,this.faceTex=new CanvasTexture(this.faceCanvas),this.faceTex.colorSpace=SRGBColorSpace,this.faceTex.minFilter=LinearMipmapLinearFilter,this.faceTex.anisotropy=4,this.uniforms.uFace.value=this.faceTex,this.heightCtx=this.heightCanvas.getContext("2d"),this.heightCanvas.width=this.heightCanvas.height=256,this.heightTex=new CanvasTexture(this.heightCanvas),this.heightTex.minFilter=LinearMipmapLinearFilter,this.uniforms.uHeight.value=this.heightTex,this.setSegments(24),this.material=this.createMaterial(),this.mesh=new Mesh(this.geometry,this.material),this.mesh.frustumCulled=false,this.mesh.position.y=-Ee,this.group.add(this.mesh),this.scene.add(this.group),this.scene.add(new HemisphereLight(16774120,7234140,1.7));let o=new DirectionalLight(16777215,1.9);o.position.set(2.5,3.5,4);let t=new DirectionalLight(16770770,1.4);t.position.set(-3.5,2,-3);let i=new DirectionalLight(16773350,.45);i.position.set(-2,-1,3),this.scene.add(o,t,i),this.camera.position.set(0,.3,6.6),this.camera.lookAt(0,.12,0);}get active(){return this.visible&&this.connected&&this.w>0}createMaterial(){let o=new MeshStandardMaterial({roughness:.62,metalness:0});return o.color.setRGB(...this.body,SRGBColorSpace),o.customProgramCacheKey=()=>"moodi-1",o.onBeforeCompile=t=>{Object.assign(t.uniforms,this.uniforms),t.vertexShader=t.vertexShader.replace("#include <common>",`#include <common>
2
2
  varying vec3 vFaceP;
3
3
  varying vec3 vFaceN;
4
4
  varying vec3 vTanX;
@@ -41,9 +41,9 @@ outgoingLight *= mix(0.62, 1.0, smoothstep(-0.95, 0.35, normalize(vFaceN).y));
41
41
  // eyes and mouth glow a little: mostly unlit, so they read as light, not paint
42
42
  float emis = smoothstep(0.75, 1.0, fc.a) * inb * smoothstep(0.12, 0.45, normalize(vFaceN).z);
43
43
  outgoingLight = mix(outgoingLight, diffuseColor.rgb * 1.12, emis * 0.65);
44
- #include <opaque_fragment>`);},o}setSegments(o){let t=Et(o);this.dirs!==t.dirs&&(this.dirs=t.dirs,this.geometry.dispose(),this.geometry=new BufferGeometry,this.geometry.setAttribute("position",new BufferAttribute(new Float32Array(t.dirs.length),3)),this.geometry.setIndex(new BufferAttribute(t.index,1)),this.mesh&&(this.mesh.geometry=this.geometry),this.shapeDirty=true);}connect(){this.connected=true,_e(this);}disconnect(){this.connected=false,He(this);}setVisible(o){this.visible=o,o&&H();}resize(o,t){this.css=[o,t];let i=(O.lowPower?1:Math.min(2,devicePixelRatio||1))*this.quality,s=Math.max(1,Math.round(o*i)),n=Math.max(1,Math.round(t*i));if(s===this.w&&n===this.h)return;this.w=this.canvas.width=s,this.h=this.canvas.height=n;let u=Math.min(s,n),r=Math.min(o,t);this.camera.position.set(0,.3,r<90?5.1:6.1),this.camera.lookAt(0,r<90?.02:.12,0),this.camera.aspect=s/n,this.camera.updateProjectionMatrix(),this.setSegments(u<160?16:u<400?24:32);let l=u<220?256:512;this.faceCanvas.width!==l&&(this.faceCanvas.width=this.faceCanvas.height=l,this.faceTex.dispose(),this.drawn.fill(NaN)),this.needsFrame=true,H();}update(o){let t=this.state;this.state={...t,...o};let i=this.state;i.shape!==this.shapeTo&&(this.shapeFrom=this.shapeTo,this.shapeTo=i.shape,this.morph=0,O.reducedMotion||(this.squashV-=2.2)),(i.color!==t.color||i.faceColor!==t.faceColor||i.cheekColor!==t.cheekColor)&&(this.bodyT=X(i.color,X(y.color,this.bodyT)),this.faceCT=i.faceColor?X(i.faceColor,te(this.bodyT)):te(this.bodyT),this.cheekT=i.cheekColor?X(i.cheekColor,oe(this.bodyT)):oe(this.bodyT)),i.mood!==t.mood&&!this.reaction&&this.show(i.mood),i.sound&&!t.sound&&this.ready&&le(this.shown),this.needsFrame=true,H();}bump(o=1){O.reducedMotion||(this.squashV-=1.6*o,this.needsFrame=true,H());}react(o,t=1200){this.reaction={mood:o,left:t/1e3},this.show(o);}get currentMood(){return this.shown}dispose(){this.disconnect(),this.geometry.dispose(),this.material.dispose(),this.faceTex.dispose(),this.heightTex.dispose(),this.onMoodChange=void 0;}show(o,t=true){if(o===this.shown)return;t&&this.state.sound&&this.ready&&le(o);let i=this.shown;this.prevShown=i,this.prevTau=this.tau,this.shown=o,this.tau=0,this.moodTime=0,this.blend=0,O.reducedMotion||(this.squashV-=1.1),this.onMoodChange?.({mood:o,previous:i,reaction:!!this.reaction});}tick(o,t){let i=this.state,s=O.reducedMotion,n=O.lowPower?0:o*Math.max(0,i.speed);this.t+=n,this.tau+=n,this.prevTau+=n,this.reaction&&(this.reaction.left-=o,this.reaction.left<=0&&(this.reaction=null,this.show(i.mood,false))),this.moodTime+=o;let u=i.settle>0&&this.shown!=="idle"?Pe(Math.min(1,Math.max(0,(this.moodTime-i.settle/1e3)/.7))):0;ae(this.shown,this.t,this.tau,this.poseB),u>0&&we(this.poseB,ae("idle",this.t,this.tau,this.poseIdle),u,this.poseB),this.blend<1?(this.blend=Math.min(1,this.blend+o/.45),ae(this.prevShown,this.t,this.prevTau,this.poseA),we(this.poseA,this.poseB,Pe(this.blend),this.pose)):Object.assign(this.pose,this.poseB);let r=this.pose;s&&(r.y=r.rx=r.ry=r.rz=r.st=r.lookX=0);let l=i.followCursor&&!s&&i.speed>0?Le[this.shown]:0,d=0,a=0;if(l>0&&_.known){let c=this.canvas.getBoundingClientRect(),v=Math.max(200,c.width*.85);d=Math.max(-1,Math.min(1,(_.x-(c.left+c.width/2))/v)),a=Math.max(-1,Math.min(1,(_.y-(c.top+c.height*.45))/v)),d*=l,a*=l;}else if(this.shown==="idle"&&!s&&i.speed>0){if(this.t>this.wander.next){let c=Math.random()<.4;this.wander.x=c?0:(Math.random()*2-1)*.6,this.wander.y=c?0:(Math.random()*2-1)*.35,this.wander.next=this.t+1.8+Math.random()*2.6;}d=this.wander.x,a=this.wander.y;}let h=U(7,o);this.look.x+=(d-this.look.x)*h,this.look.y+=(a-this.look.y)*h;let p=ie[this.shown],m=this.target;for(let c of J)m[c]=p[c];m.lookX+=this.look.x+r.lookX,m.lookY+=this.look.y+r.lookY,m.mouthOpen+=r.mouth,m.eyeOpen+=this.hover*.08;let E=U(11,o);for(let c of J)this.face[c]+=(m[c]-this.face[c])*E;let S=U(16,o);if(this.face.lookX+=(m.lookX-this.face.lookX)*S,this.face.lookY+=(m.lookY-this.face.lookY)*S,this.face.mouthOpen+=(m.mouthOpen-this.face.mouthOpen)*S,this.nextBlink-=n,this.nextBlink<=0&&this.blinkT<0&&(this.blinkT=0,this.nextBlink=Math.random()<.2?.25:2.2+Math.random()*3.8),this.blinkT>=0){this.blinkT+=n;let c=this.blinkT/.16;this.blink=c>=1?1:1-Math.sin(Math.PI*c),c>=1&&(this.blinkT=-1);}let w=Math.min(o,1/30);this.squashV+=(-170*this.squash-11*this.squashV)*w,this.squash+=this.squashV*w,s&&(this.squash=this.squashV=0),s?this.pop=1:(this.popV+=(-140*(this.pop-1)-13*this.popV)*w,this.pop+=this.popV*w),this.hover+=((this.hovering&&i.interactive?1:0)-this.hover)*U(12,o);let k=U(9,o);this.body=R(this.body,this.bodyT,k),this.faceC=R(this.faceC,this.faceCT,k),this.cheek=R(this.cheek,this.cheekT,k),this.material.color.setRGB(this.body[0],this.body[1],this.body[2],SRGBColorSpace);let C=Ge[this.shown],L=U(6,o);for(let c of Object.keys(this.overlay))this.overlay[c]+=((C===c?1-u:0)-this.overlay[c])*L;this.morph<1&&(this.morph=Math.min(1,this.morph+o/(s?.2:.38)),this.shapeDirty=true);let B=Q[this.shapeTo].animated||this.morph<1&&Q[this.shapeFrom].animated;(this.shapeDirty||B&&n>0)&&this.rebuild();let A=this.group,T=(1+r.st+this.squash)*(1+this.hover*.04),f=1/Math.sqrt(Math.max(.3,1+r.st+this.squash))*(1+this.hover*.04);A.position.y=Ee+r.y,A.rotation.set(r.rx+this.look.y*.22*(l>0?1:0),r.ry+this.look.x*.42,r.rz),A.scale.set(f*this.pop,T*this.pop,f*this.pop);let g=this.drawFaceIfNeeded();if((i.speed===0||O.lowPower)&&!g&&!this.needsFrame&&this.settled())return;let b=performance.now();this.render(r)&&(this.needsFrame=false,this.ready||(this.ready=true,this.state.sound&&le(this.shown,true),this.onReady?.(),this.onReady=void 0),this.adapt(performance.now()-b));}adapt(o){this.cost=this.costFrames?this.cost*.9+o*.1:o,!(++this.costFrames<20||this.cost<9||this.quality<=.5)&&(this.quality=Math.max(.5,this.quality-.25),this.costFrames=0,this.resize(this.css[0],this.css[1]));}settled(){let o=this.group,t=this.overlay,i=[t.bang,o.position.y,o.rotation.x,o.rotation.y,o.rotation.z,o.scale.x,o.scale.y,...this.body,this.morph,t.dots,t.zz,t.hearts,t.waves],s=this.lastFrame,n=s.length===i.length;for(let u=0;n&&u<i.length;u++)n=Math.abs(i[u]-s[u])<1e-4;return this.lastFrame=i,n}rebuild(){let o=this.geometry.getAttribute("position"),t=o.array,i=this.dirs,s=Pe(this.morph),n=this.shapeFrom,u=this.shapeTo,r=new Float32Array(3);for(let a=0;a<i.length;a+=3)Se(u,i[a],i[a+1],i[a+2],this.t,t,a),s<1&&(Se(n,i[a],i[a+1],i[a+2],this.t,r,0),t[a]=r[0]+(t[a]-r[0])*s,t[a+1]=r[1]+(t[a+1]-r[1])*s,t[a+2]=r[2]+(t[a+2]-r[2])*s);o.needsUpdate=true,this.geometry.computeVertexNormals();let l=Q[n],d=Q[u];this.uniforms.uFaceY.value=l.faceY+(d.faceY-l.faceY)*s,this.uniforms.uFaceScale.value=l.faceScale+(d.faceScale-l.faceScale)*s,this.shapeDirty=false;}drawFaceIfNeeded(){let o=this.face,t=this.drawn,i=false,s=0;for(let r of J)Math.abs(t[s]-o[r])<.002||(i=true,t[s]=o[r]),s++;let n=[this.blink,...this.faceC,...this.cheek];for(let r of n)Math.abs(t[s]-r)<.002||(i=true,t[s]=r),s++;if(!i)return false;let u=fe(this.faceC)>.45;return ye(this.faceCtx,o,this.blink,D(this.faceC),D(this.cheek),u?1:.3,D(R(this.faceC,[1,1,1],u?.6:.16)),u?D(R(this.body,[.04,.03,.06],.86)):"#fff",D(u?R(this.body,[.03,.02,.05],.78):R(this.faceC,[0,0,0],.35)),D(this.faceC)),this.faceTex.needsUpdate=true,ye(this.heightCtx,o,this.blink,"#fff","#fff",0,"#fff","#fff","#fff","#fff",true),this.heightTex.needsUpdate=true,true}project(o,t,i){let s=this.v.set(o,t,i).applyMatrix4(this.group.matrixWorld).project(this.camera);return [(s.x*.5+.5)*this.w,(-s.y*.5+.5)*this.h]}render(o){let{w:t,h:i,ctx:s}=this,n=Ie(t,i);if(O.lowPower&&!this.lowPowerApplied){this.lowPowerApplied=true;let[u,r]=this.css;return this.w=this.h=0,this.resize(u,r),false}if(!We(this.scene,this.camera))return false;if(s.clearRect(0,0,t,i),this.group.updateMatrixWorld(),this.state.shadow){let u=this.v.set(0,Ee-.08,0).project(this.camera),r=(u.x*.5+.5)*t,l=(-u.y*.5+.5)*i,d=Math.max(0,o.y)*3,a=Math.min(t,i)*.26*(1-d*.25)*this.pop,h=s.createRadialGradient(r,l,0,r,l,a),p=R(this.body,[.05,.03,.02],.75);h.addColorStop(0,`rgba(${p[0]*255|0},${p[1]*255|0},${p[2]*255|0},${.42*(1-d*.4)})`),h.addColorStop(1,"rgba(0,0,0,0)"),s.fillStyle=h,s.save(),s.translate(r,l),s.scale(1,.22),s.translate(-r,-l),s.beginPath(),s.arc(r,l,a,0,Math.PI*2),s.fill(),s.restore();}return n.setViewport(0,0,t,i),n.setScissor(0,0,t,i),n.render(this.scene,this.camera),s.drawImage(n.domElement,0,qe()-i,t,i,0,0,t,i),this.drawOverlays(),true}drawOverlays(){let o=this.overlay;if(o.dots+o.zz+o.hearts+o.waves+o.bang<.01)return;let{ctx:t}=this,i=this.t,s=O.reducedMotion,n=Math.min(this.w,this.h),u=R(this.body,[1,1,1],.22),r=D(u);if(t.save(),o.dots>.01){let[l,d]=this.project(.6,.92,.2),a=s?2:i*.55%1.6,h=[.014,.022,.052];for(let p=0;p<3;p++){let m=s?1:ze(Re((a-p*.18)/.32)),E=s?0:Math.sin(i*2.2+p)*n*.006,S=l+[0,.05,.12][p]*n,w=d-[0,.05,.12][p]*n+E,k=h[p]*n*m;if(!(k<=.2)&&(t.globalAlpha=o.dots*.95,t.fillStyle=r,t.beginPath(),p<2?t.arc(S,w,k,0,Math.PI*2):Pt(t,S,w,k),t.fill(),p===2&&m>.6)){t.fillStyle=D(R(this.body,[0,0,0],.35));for(let C=0;C<3;C++){let L=s?0:Math.max(0,Math.sin(i*7-C*.9))*k*.16;t.beginPath(),t.arc(S+(C-1)*k*.34,w-L,k*.1,0,Math.PI*2),t.fill();}}}}if(o.zz>.01){let[l,d]=this.project(.45,.85,.2);t.textAlign="center",t.textBaseline="middle",t.fillStyle=r;for(let a=0;a<3;a++){let h=s?.25+a*.25:(i*.33+a/3)%1,p=l+h*n*.17+Math.sin(h*7+a)*n*.018,m=d-Fe(h)*n*.26;t.globalAlpha=o.zz*Math.min(1,h*5)*(1-h)*1.3,t.save(),t.translate(p,m),t.rotate(-0.25+Math.sin(h*5+a)*.22),t.font=`800 ${Math.round(n*(.05+.06*h))}px ui-rounded, system-ui, sans-serif`,t.fillText("z",0,0),t.restore();}}if(o.hearts>.01){let[l,d]=this.project(0,.8,.2),a=R(this.cheek,[1,.3,.45],.55);for(let h=0;h<4;h++){let p=s?.4:(i*.3+h/4)%1,m=h%2?1:-1,E=l+m*n*(.16+.07*(h>>1))+Math.sin(p*6+h)*n*.025,S=d-n*.02-Fe(p)*n*.28,w=s?1:ze(Re(p/.22)),k=n*(.026+.008*(h%3))*w;t.globalAlpha=o.hearts*(1-Math.max(0,(p-.6)/.4)),t.save(),t.translate(E,S),t.rotate(Math.sin(i*3+h)*.25);let C=t.createLinearGradient(0,-k,0,k);C.addColorStop(0,D(R(a,[1,1,1],.35))),C.addColorStop(1,D(a)),t.fillStyle=C,Me(t,0,0,k),t.fill(),t.restore();}}if(o.waves>.01){t.lineCap="round",t.strokeStyle=r;for(let l of [-1,1]){let[d,a]=this.project(l*1,.12,0);for(let h=0;h<3;h++){let p=s?.3+h*.2:(i*.8+h/3)%1,m=Fe(p);t.globalAlpha=o.waves*Math.sin(Math.PI*p)*.9,t.lineWidth=n*(.016-.008*p),t.beginPath();let E=n*(.03+.11*m);l>0?t.arc(d-n*.03,a,E,-0.55,.55):t.arc(d+n*.03,a,E,Math.PI-.55,Math.PI+.55),t.stroke();}}}if(o.bang>.01){let[l,d]=this.project(.55,1,.2),a=s?1:ze(Re(this.tau/.35));t.globalAlpha=o.bang,t.fillStyle=r,t.save(),t.translate(l,d),t.rotate(.18),t.scale(a,a),t.beginPath(),t.roundRect(-n*.016,-n*.1,n*.032,n*.07,n*.016),t.arc(0,n*.005,n*.018,0,Math.PI*2),t.fill(),t.restore();}t.restore();}},Re=e=>e<0?0:e>1?1:e,Fe=e=>1-(1-e)*(1-e),ze=e=>1+(1.9+1)*Math.pow(e-1,3)+1.9*Math.pow(e-1,2);function Pt(e,o,t,i){e.ellipse(o,t,i,i*.72,0,0,Math.PI*2),e.moveTo(o-i*.35+i*.45,t-i*.38),e.arc(o-i*.35,t-i*.38,i*.45,0,Math.PI*2),e.moveTo(o+i*.3+i*.5,t-i*.32),e.arc(o+i*.3,t-i*.32,i*.5,0,Math.PI*2);}var Rt=["shape","mood","color","face-color","cheek-color","size","speed","follow-cursor","interactive","shadow","sound","settle"],N=(e,o)=>e===null?o:e!=="false"&&e!=="0",Ft=e=>e==null||e===""?`${y.size}px`:typeof e=="number"||/^\d+(\.\d+)?$/.test(String(e))?`${e}px`:String(e),zt=`:host{display:inline-block;position:relative;cursor:pointer;vertical-align:middle;contain:layout paint style;-webkit-tap-highlight-color:transparent}
44
+ #include <opaque_fragment>`);},o}setSegments(o){let t=Et(o);this.dirs!==t.dirs&&(this.dirs=t.dirs,this.geometry.dispose(),this.geometry=new BufferGeometry,this.geometry.setAttribute("position",new BufferAttribute(new Float32Array(t.dirs.length),3)),this.geometry.setIndex(new BufferAttribute(t.index,1)),this.mesh&&(this.mesh.geometry=this.geometry),this.shapeDirty=true);}connect(){this.connected=true,_e(this);}disconnect(){this.connected=false,He(this);}setVisible(o){this.visible=o,o&&H();}resize(o,t){this.css=[o,t];let i=(O.lowPower?1:Math.min(2,devicePixelRatio||1))*this.quality,s=Math.max(1,Math.round(o*i)),n=Math.max(1,Math.round(t*i));if(s===this.w&&n===this.h)return;this.w=this.canvas.width=s,this.h=this.canvas.height=n;let u=Math.min(s,n),r=Math.min(o,t);this.camera.position.set(0,.3,r<90?5.1:6.1),this.camera.lookAt(0,r<90?.02:.12,0),this.camera.aspect=s/n,this.camera.updateProjectionMatrix(),this.setSegments(u<160?16:u<400?24:32);let l=u<220?256:512;this.faceCanvas.width!==l&&(this.faceCanvas.width=this.faceCanvas.height=l,this.faceTex.dispose(),this.drawn.fill(NaN)),this.needsFrame=true,H();}update(o){let t=this.state;this.state={...t,...o};let i=this.state;i.shape!==this.shapeTo&&(this.shapeFrom=this.shapeTo,this.shapeTo=i.shape,this.morph=0,O.reducedMotion||(this.squashV-=2.2)),(i.color!==t.color||i.faceColor!==t.faceColor||i.cheekColor!==t.cheekColor)&&(this.bodyT=X(i.color,X(y.color,this.bodyT)),this.faceCT=i.faceColor?X(i.faceColor,oe(this.bodyT)):oe(this.bodyT),this.cheekT=i.cheekColor?X(i.cheekColor,ie(this.bodyT)):ie(this.bodyT)),i.mood!==t.mood&&!this.reaction&&this.show(i.mood),i.sound&&!t.sound&&this.ready&&ce(this.shown),this.needsFrame=true,H();}bump(o=1){O.reducedMotion||(this.squashV-=1.6*o,this.needsFrame=true,H());}react(o,t=1200){this.reaction={mood:o,left:t/1e3},this.show(o);}get currentMood(){return this.shown}dispose(){this.disconnect(),this.geometry.dispose(),this.material.dispose(),this.faceTex.dispose(),this.heightTex.dispose(),this.onMoodChange=void 0;}show(o,t=true){if(o===this.shown)return;t&&this.state.sound&&this.ready&&ce(o);let i=this.shown;this.prevShown=i,this.prevTau=this.tau,this.shown=o,this.tau=0,this.moodTime=0,this.blend=0,O.reducedMotion||(this.squashV-=1.1),this.onMoodChange?.({mood:o,previous:i,reaction:!!this.reaction});}tick(o,t){let i=this.state,s=O.reducedMotion,n=O.lowPower?0:o*Math.max(0,i.speed);this.t+=n,this.tau+=n,this.prevTau+=n,this.reaction&&(this.reaction.left-=o,this.reaction.left<=0&&(this.reaction=null,this.show(i.mood,false))),this.moodTime+=o,i.settle>0&&i.settleMood&&!this.reaction&&this.shown===i.mood&&this.shown!==i.settleMood&&this.moodTime>=i.settle/1e3&&this.show(i.settleMood,false);let u=i.settle>0&&this.shown!=="idle"?Pe(Math.min(1,Math.max(0,(this.moodTime-i.settle/1e3)/.7))):0;re(this.shown,this.t,this.tau,this.poseB),u>0&&we(this.poseB,re("idle",this.t,this.tau,this.poseIdle),u,this.poseB),this.blend<1?(this.blend=Math.min(1,this.blend+o/.45),re(this.prevShown,this.t,this.prevTau,this.poseA),we(this.poseA,this.poseB,Pe(this.blend),this.pose)):Object.assign(this.pose,this.poseB);let r=this.pose;s&&(r.y=r.rx=r.ry=r.rz=r.st=r.lookX=0);let l=i.followCursor&&!s&&i.speed>0?Le[this.shown]:0,d=0,a=0;if(l>0&&_.known){let c=this.canvas.getBoundingClientRect(),v=Math.max(200,c.width*.85);d=Math.max(-1,Math.min(1,(_.x-(c.left+c.width/2))/v)),a=Math.max(-1,Math.min(1,(_.y-(c.top+c.height*.45))/v)),d*=l,a*=l;}else if(this.shown==="idle"&&!s&&i.speed>0){if(this.t>this.wander.next){let c=Math.random()<.4;this.wander.x=c?0:(Math.random()*2-1)*.6,this.wander.y=c?0:(Math.random()*2-1)*.35,this.wander.next=this.t+1.8+Math.random()*2.6;}d=this.wander.x,a=this.wander.y;}let h=U(7,o);this.look.x+=(d-this.look.x)*h,this.look.y+=(a-this.look.y)*h;let p=se[this.shown],m=this.target;for(let c of Z)m[c]=p[c];m.lookX+=this.look.x+r.lookX,m.lookY+=this.look.y+r.lookY,m.mouthOpen+=r.mouth,m.eyeOpen+=this.hover*.08;let E=U(11,o);for(let c of Z)this.face[c]+=(m[c]-this.face[c])*E;let S=U(16,o);if(this.face.lookX+=(m.lookX-this.face.lookX)*S,this.face.lookY+=(m.lookY-this.face.lookY)*S,this.face.mouthOpen+=(m.mouthOpen-this.face.mouthOpen)*S,this.nextBlink-=n,this.nextBlink<=0&&this.blinkT<0&&(this.blinkT=0,this.nextBlink=Math.random()<.2?.25:2.2+Math.random()*3.8),this.blinkT>=0){this.blinkT+=n;let c=this.blinkT/.16;this.blink=c>=1?1:1-Math.sin(Math.PI*c),c>=1&&(this.blinkT=-1);}let w=Math.min(o,1/30);this.squashV+=(-170*this.squash-11*this.squashV)*w,this.squash+=this.squashV*w,s&&(this.squash=this.squashV=0),s?this.pop=1:(this.popV+=(-140*(this.pop-1)-13*this.popV)*w,this.pop+=this.popV*w),this.hover+=((this.hovering&&i.interactive?1:0)-this.hover)*U(12,o);let k=U(9,o);this.body=R(this.body,this.bodyT,k),this.faceC=R(this.faceC,this.faceCT,k),this.cheek=R(this.cheek,this.cheekT,k),this.material.color.setRGB(this.body[0],this.body[1],this.body[2],SRGBColorSpace);let C=Ge[this.shown],L=U(6,o);for(let c of Object.keys(this.overlay))this.overlay[c]+=((C===c?1-u:0)-this.overlay[c])*L;this.morph<1&&(this.morph=Math.min(1,this.morph+o/(s?.2:.38)),this.shapeDirty=true);let B=ee[this.shapeTo].animated||this.morph<1&&ee[this.shapeFrom].animated;(this.shapeDirty||B&&n>0)&&this.rebuild();let A=this.group,T=(1+r.st+this.squash)*(1+this.hover*.04),f=1/Math.sqrt(Math.max(.3,1+r.st+this.squash))*(1+this.hover*.04);A.position.y=Ee+r.y,A.rotation.set(r.rx+this.look.y*.22*(l>0?1:0),r.ry+this.look.x*.42,r.rz),A.scale.set(f*this.pop,T*this.pop,f*this.pop);let g=this.drawFaceIfNeeded();if((i.speed===0||O.lowPower)&&!g&&!this.needsFrame&&this.settled())return;let b=performance.now();this.render(r)&&(this.needsFrame=false,this.ready||(this.ready=true,this.state.sound&&ce(this.shown,true),this.onReady?.(),this.onReady=void 0),this.adapt(performance.now()-b));}adapt(o){this.cost=this.costFrames?this.cost*.9+o*.1:o,!(++this.costFrames<20||this.cost<9||this.quality<=.5)&&(this.quality=Math.max(.5,this.quality-.25),this.costFrames=0,this.resize(this.css[0],this.css[1]));}settled(){let o=this.group,t=this.overlay,i=[t.bang,o.position.y,o.rotation.x,o.rotation.y,o.rotation.z,o.scale.x,o.scale.y,...this.body,this.morph,t.dots,t.zz,t.hearts,t.waves],s=this.lastFrame,n=s.length===i.length;for(let u=0;n&&u<i.length;u++)n=Math.abs(i[u]-s[u])<1e-4;return this.lastFrame=i,n}rebuild(){let o=this.geometry.getAttribute("position"),t=o.array,i=this.dirs,s=Pe(this.morph),n=this.shapeFrom,u=this.shapeTo,r=new Float32Array(3);for(let a=0;a<i.length;a+=3)Se(u,i[a],i[a+1],i[a+2],this.t,t,a),s<1&&(Se(n,i[a],i[a+1],i[a+2],this.t,r,0),t[a]=r[0]+(t[a]-r[0])*s,t[a+1]=r[1]+(t[a+1]-r[1])*s,t[a+2]=r[2]+(t[a+2]-r[2])*s);o.needsUpdate=true,this.geometry.computeVertexNormals();let l=ee[n],d=ee[u];this.uniforms.uFaceY.value=l.faceY+(d.faceY-l.faceY)*s,this.uniforms.uFaceScale.value=l.faceScale+(d.faceScale-l.faceScale)*s,this.shapeDirty=false;}drawFaceIfNeeded(){let o=this.face,t=this.drawn,i=false,s=0;for(let r of Z)Math.abs(t[s]-o[r])<.002||(i=true,t[s]=o[r]),s++;let n=[this.blink,...this.faceC,...this.cheek];for(let r of n)Math.abs(t[s]-r)<.002||(i=true,t[s]=r),s++;if(!i)return false;let u=fe(this.faceC)>.45;return ye(this.faceCtx,o,this.blink,D(this.faceC),D(this.cheek),u?1:.3,D(R(this.faceC,[1,1,1],u?.6:.16)),u?D(R(this.body,[.04,.03,.06],.86)):"#fff",D(u?R(this.body,[.03,.02,.05],.78):R(this.faceC,[0,0,0],.35)),D(this.faceC)),this.faceTex.needsUpdate=true,ye(this.heightCtx,o,this.blink,"#fff","#fff",0,"#fff","#fff","#fff","#fff",true),this.heightTex.needsUpdate=true,true}project(o,t,i){let s=this.v.set(o,t,i).applyMatrix4(this.group.matrixWorld).project(this.camera);return [(s.x*.5+.5)*this.w,(-s.y*.5+.5)*this.h]}render(o){let{w:t,h:i,ctx:s}=this,n=Ie(t,i);if(O.lowPower&&!this.lowPowerApplied){this.lowPowerApplied=true;let[u,r]=this.css;return this.w=this.h=0,this.resize(u,r),false}if(!We(this.scene,this.camera))return false;if(s.clearRect(0,0,t,i),this.group.updateMatrixWorld(),this.state.shadow){let u=this.v.set(0,Ee-.08,0).project(this.camera),r=(u.x*.5+.5)*t,l=(-u.y*.5+.5)*i,d=Math.max(0,o.y)*3,a=Math.min(t,i)*.26*(1-d*.25)*this.pop,h=s.createRadialGradient(r,l,0,r,l,a),p=R(this.body,[.05,.03,.02],.75);h.addColorStop(0,`rgba(${p[0]*255|0},${p[1]*255|0},${p[2]*255|0},${.42*(1-d*.4)})`),h.addColorStop(1,"rgba(0,0,0,0)"),s.fillStyle=h,s.save(),s.translate(r,l),s.scale(1,.22),s.translate(-r,-l),s.beginPath(),s.arc(r,l,a,0,Math.PI*2),s.fill(),s.restore();}return n.setViewport(0,0,t,i),n.setScissor(0,0,t,i),n.render(this.scene,this.camera),s.drawImage(n.domElement,0,qe()-i,t,i,0,0,t,i),this.drawOverlays(),true}drawOverlays(){let o=this.overlay;if(o.dots+o.zz+o.hearts+o.waves+o.bang<.01)return;let{ctx:t}=this,i=this.t,s=O.reducedMotion,n=Math.min(this.w,this.h),u=R(this.body,[1,1,1],.22),r=D(u);if(t.save(),o.dots>.01){let[l,d]=this.project(.6,.92,.2),a=s?2:i*.55%1.6,h=[.014,.022,.052];for(let p=0;p<3;p++){let m=s?1:ze(Re((a-p*.18)/.32)),E=s?0:Math.sin(i*2.2+p)*n*.006,S=l+[0,.05,.12][p]*n,w=d-[0,.05,.12][p]*n+E,k=h[p]*n*m;if(!(k<=.2)&&(t.globalAlpha=o.dots*.95,t.fillStyle=r,t.beginPath(),p<2?t.arc(S,w,k,0,Math.PI*2):Pt(t,S,w,k),t.fill(),p===2&&m>.6)){t.fillStyle=D(R(this.body,[0,0,0],.35));for(let C=0;C<3;C++){let L=s?0:Math.max(0,Math.sin(i*7-C*.9))*k*.16;t.beginPath(),t.arc(S+(C-1)*k*.34,w-L,k*.1,0,Math.PI*2),t.fill();}}}}if(o.zz>.01){let[l,d]=this.project(.45,.85,.2);t.textAlign="center",t.textBaseline="middle",t.fillStyle=r;for(let a=0;a<3;a++){let h=s?.25+a*.25:(i*.33+a/3)%1,p=l+h*n*.17+Math.sin(h*7+a)*n*.018,m=d-Fe(h)*n*.26;t.globalAlpha=o.zz*Math.min(1,h*5)*(1-h)*1.3,t.save(),t.translate(p,m),t.rotate(-0.25+Math.sin(h*5+a)*.22),t.font=`800 ${Math.round(n*(.05+.06*h))}px ui-rounded, system-ui, sans-serif`,t.fillText("z",0,0),t.restore();}}if(o.hearts>.01){let[l,d]=this.project(0,.8,.2),a=R(this.cheek,[1,.3,.45],.55);for(let h=0;h<4;h++){let p=s?.4:(i*.3+h/4)%1,m=h%2?1:-1,E=l+m*n*(.16+.07*(h>>1))+Math.sin(p*6+h)*n*.025,S=d-n*.02-Fe(p)*n*.28,w=s?1:ze(Re(p/.22)),k=n*(.026+.008*(h%3))*w;t.globalAlpha=o.hearts*(1-Math.max(0,(p-.6)/.4)),t.save(),t.translate(E,S),t.rotate(Math.sin(i*3+h)*.25);let C=t.createLinearGradient(0,-k,0,k);C.addColorStop(0,D(R(a,[1,1,1],.35))),C.addColorStop(1,D(a)),t.fillStyle=C,Me(t,0,0,k),t.fill(),t.restore();}}if(o.waves>.01){t.lineCap="round",t.strokeStyle=r;for(let l of [-1,1]){let[d,a]=this.project(l*1,.12,0);for(let h=0;h<3;h++){let p=s?.3+h*.2:(i*.8+h/3)%1,m=Fe(p);t.globalAlpha=o.waves*Math.sin(Math.PI*p)*.9,t.lineWidth=n*(.016-.008*p),t.beginPath();let E=n*(.03+.11*m);l>0?t.arc(d-n*.03,a,E,-0.55,.55):t.arc(d+n*.03,a,E,Math.PI-.55,Math.PI+.55),t.stroke();}}}if(o.bang>.01){let[l,d]=this.project(.55,1,.2),a=s?1:ze(Re(this.tau/.35));t.globalAlpha=o.bang,t.fillStyle=r,t.save(),t.translate(l,d),t.rotate(.18),t.scale(a,a),t.beginPath(),t.roundRect(-n*.016,-n*.1,n*.032,n*.07,n*.016),t.arc(0,n*.005,n*.018,0,Math.PI*2),t.fill(),t.restore();}t.restore();}},Re=e=>e<0?0:e>1?1:e,Fe=e=>1-(1-e)*(1-e),ze=e=>1+(1.9+1)*Math.pow(e-1,3)+1.9*Math.pow(e-1,2);function Pt(e,o,t,i){e.ellipse(o,t,i,i*.72,0,0,Math.PI*2),e.moveTo(o-i*.35+i*.45,t-i*.38),e.arc(o-i*.35,t-i*.38,i*.45,0,Math.PI*2),e.moveTo(o+i*.3+i*.5,t-i*.32),e.arc(o+i*.3,t-i*.32,i*.5,0,Math.PI*2);}var Rt=["shape","mood","color","face-color","cheek-color","size","speed","follow-cursor","interactive","shadow","sound","settle","settle-mood"],N=(e,o)=>e===null?o:e!=="false"&&e!=="0",Ft=e=>e==null||e===""?`${y.size}px`:typeof e=="number"||/^\d+(\.\d+)?$/.test(String(e))?`${e}px`:String(e),zt=`:host{display:inline-block;position:relative;cursor:pointer;vertical-align:middle;contain:layout paint style;-webkit-tap-highlight-color:transparent}
45
45
  :host([interactive="false"]){pointer-events:none}
46
46
  canvas{position:absolute;inset:0;display:block;width:100%;height:100%}
47
47
  slot{display:block;width:100%;height:100%}
48
48
  ::slotted(img){display:block;width:100%;height:100%;object-fit:contain}
49
- :host([ready]) slot{display:none}`,Bt=typeof HTMLElement>"u"?class{}:HTMLElement,ee=class extends Bt{constructor(){super();this.buddy=null;this.sizeStyle=document.createElement("style");this.onEnter=()=>{this.buddy&&(this.buddy.hovering=true);};this.onLeave=()=>{this.buddy&&(this.buddy.hovering=false);};this.onClick=()=>{this.buddy?.state.interactive&&this.react(Math.random()<.5?"happy":"surprised",{duration:1100});};this.root=this.attachShadow({mode:"open"});let t=document.createElement("style");t.textContent=zt,this.root.append(t,document.createElement("slot")),this.root.append(this.sizeStyle),this.applySize(this.getAttribute("size"));}connectedCallback(){if(this.hasAttribute("role")||this.setAttribute("role","img"),!this.buddy){let t=this.buddy=new ce;t.onMoodChange=i=>{this.syncLabel(i.mood),this.dispatchEvent(new CustomEvent("moodchange",{detail:i,bubbles:true}));},t.onReady=()=>{this.setAttribute("ready",""),this.dispatchEvent(new Event("ready"));},this.root.append(t.canvas),t.update(this.readState()),this.addEventListener("pointerenter",this.onEnter),this.addEventListener("pointerleave",this.onLeave),this.addEventListener("click",this.onClick);}this.syncLabel(this.buddy.currentMood),this.buddy.connect(),this.io=new IntersectionObserver(([t])=>this.buddy?.setVisible(t.isIntersecting),{rootMargin:"64px"}),this.io.observe(this),this.ro=new ResizeObserver(([t])=>{let i=t.contentRect;this.buddy?.resize(i.width,i.height);}),this.ro.observe(this);}disconnectedCallback(){this.io?.disconnect(),this.ro?.disconnect(),this.buddy&&(this.buddy.canvas.remove(),this.buddy.dispose(),this.buddy=null),this.removeEventListener("pointerenter",this.onEnter),this.removeEventListener("pointerleave",this.onLeave),this.removeEventListener("click",this.onClick);}attributeChangedCallback(t,i,s){i!==s&&(t==="size"&&(this.applySize(s),i!==null&&this.buddy?.bump()),t!=="aria-label"&&(this.buddy?.update(this.readState()),t==="mood"&&this.buddy&&this.syncLabel(this.buddy.currentMood)));}applySize(t){let i=Ft(t);this.sizeStyle.textContent=`:host{width:${i};height:${i}}`;}readState(){let t=this.getAttribute("shape"),i=this.getAttribute("mood"),s=parseFloat(this.getAttribute("speed")??""),n=parseFloat(this.getAttribute("settle")??"");return {shape:de(t)?t:y.shape,mood:pe(i)?i:y.mood,color:this.getAttribute("color")||y.color,faceColor:this.getAttribute("face-color")||void 0,cheekColor:this.getAttribute("cheek-color")||void 0,speed:Number.isFinite(s)?Math.max(0,s):y.speed,followCursor:N(this.getAttribute("follow-cursor"),y.followCursor),interactive:N(this.getAttribute("interactive"),y.interactive),shadow:N(this.getAttribute("shadow"),y.shadow),sound:N(this.getAttribute("sound"),y.sound),settle:Number.isFinite(n)?Math.max(0,n):y.settle}}syncLabel(t){let i=this.getAttribute("aria-label");i&&!i.startsWith("moodi: ")||this.setAttribute("aria-label",`moodi: ${t}`);}react(t,i={}){this.buddy?.react(t,i.duration??1200);}get shape(){let t=this.getAttribute("shape");return de(t)?t:y.shape}set shape(t){this.setAttribute("shape",t);}get mood(){let t=this.getAttribute("mood");return pe(t)?t:y.mood}set mood(t){this.setAttribute("mood",t);}get color(){return this.getAttribute("color")||y.color}set color(t){this.setAttribute("color",t);}get faceColor(){return this.getAttribute("face-color")||void 0}set faceColor(t){t?this.setAttribute("face-color",t):this.removeAttribute("face-color");}get cheekColor(){return this.getAttribute("cheek-color")||void 0}set cheekColor(t){t?this.setAttribute("cheek-color",t):this.removeAttribute("cheek-color");}get size(){let t=this.getAttribute("size");return t?/^\d+(\.\d+)?$/.test(t)?Number(t):t:y.size}set size(t){this.setAttribute("size",String(t));}get speed(){return this.readState().speed}set speed(t){this.setAttribute("speed",String(t));}get followCursor(){return N(this.getAttribute("follow-cursor"),y.followCursor)}set followCursor(t){this.setAttribute("follow-cursor",String(t));}get interactive(){return N(this.getAttribute("interactive"),y.interactive)}set interactive(t){this.setAttribute("interactive",String(t));}get shadow(){return N(this.getAttribute("shadow"),y.shadow)}set shadow(t){this.setAttribute("shadow",String(t));}get settle(){return this.readState().settle}set settle(t){this.setAttribute("settle",String(t));}get sound(){return N(this.getAttribute("sound"),y.sound)}set sound(t){this.setAttribute("sound",String(t));}};ee.observedAttributes=Rt;function Ze(e="moodi-buddy"){typeof window>"u"||!("customElements"in window)||customElements.get(e)||customElements.define(e,class extends ee{});}Ze();export{y as DEFAULTS,et as MOODS,Lt as MOOD_INFO,ee as MoodiBuddyElement,Ot as PALETTES,Qe as SHAPES,Gt as SHAPE_LABELS,Ze as defineMoodi,pe as isMood,de as isShape};
49
+ :host([ready]) slot{display:none}`,Bt=typeof HTMLElement>"u"?class{}:HTMLElement,te=class extends Bt{constructor(){super();this.buddy=null;this.sizeStyle=document.createElement("style");this.onEnter=()=>{this.buddy&&(this.buddy.hovering=true);};this.onLeave=()=>{this.buddy&&(this.buddy.hovering=false);};this.onClick=()=>{this.buddy?.state.interactive&&this.react(Math.random()<.5?"happy":"surprised",{duration:1100});};this.root=this.attachShadow({mode:"open"});let t=document.createElement("style");t.textContent=zt,this.root.append(t,document.createElement("slot")),this.root.append(this.sizeStyle),this.applySize(this.getAttribute("size"));}connectedCallback(){if(this.hasAttribute("role")||this.setAttribute("role","img"),!this.buddy){let t=this.buddy=new ue;t.onMoodChange=i=>{this.syncLabel(i.mood),this.dispatchEvent(new CustomEvent("moodchange",{detail:i,bubbles:true}));},t.onReady=()=>{this.setAttribute("ready",""),this.dispatchEvent(new Event("ready"));},this.root.append(t.canvas),t.update(this.readState()),this.addEventListener("pointerenter",this.onEnter),this.addEventListener("pointerleave",this.onLeave),this.addEventListener("click",this.onClick);}this.syncLabel(this.buddy.currentMood),this.buddy.connect(),this.io=new IntersectionObserver(([t])=>this.buddy?.setVisible(t.isIntersecting),{rootMargin:"64px"}),this.io.observe(this),this.ro=new ResizeObserver(([t])=>{let i=t.contentRect;this.buddy?.resize(i.width,i.height);}),this.ro.observe(this);}disconnectedCallback(){this.io?.disconnect(),this.ro?.disconnect(),this.buddy&&(this.buddy.canvas.remove(),this.buddy.dispose(),this.buddy=null),this.removeEventListener("pointerenter",this.onEnter),this.removeEventListener("pointerleave",this.onLeave),this.removeEventListener("click",this.onClick);}attributeChangedCallback(t,i,s){i!==s&&(t==="size"&&(this.applySize(s),i!==null&&this.buddy?.bump()),t!=="aria-label"&&(this.buddy?.update(this.readState()),t==="mood"&&this.buddy&&this.syncLabel(this.buddy.currentMood)));}applySize(t){let i=Ft(t);this.sizeStyle.textContent=`:host{width:${i};height:${i}}`;}readState(){let t=this.getAttribute("shape"),i=this.getAttribute("mood"),s=parseFloat(this.getAttribute("speed")??""),n=parseFloat(this.getAttribute("settle")??""),u=this.getAttribute("settle-mood");return {shape:pe(t)?t:y.shape,mood:J(i)?i:y.mood,color:this.getAttribute("color")||y.color,faceColor:this.getAttribute("face-color")||void 0,cheekColor:this.getAttribute("cheek-color")||void 0,speed:Number.isFinite(s)?Math.max(0,s):y.speed,followCursor:N(this.getAttribute("follow-cursor"),y.followCursor),interactive:N(this.getAttribute("interactive"),y.interactive),shadow:N(this.getAttribute("shadow"),y.shadow),sound:N(this.getAttribute("sound"),y.sound),settle:Number.isFinite(n)?Math.max(0,n):y.settle,settleMood:J(u)?u:void 0}}syncLabel(t){let i=this.getAttribute("aria-label");i&&!i.startsWith("moodi: ")||this.setAttribute("aria-label",`moodi: ${t}`);}react(t,i={}){this.buddy?.react(t,i.duration??1200);}get shape(){let t=this.getAttribute("shape");return pe(t)?t:y.shape}set shape(t){this.setAttribute("shape",t);}get mood(){let t=this.getAttribute("mood");return J(t)?t:y.mood}set mood(t){this.setAttribute("mood",t);}get color(){return this.getAttribute("color")||y.color}set color(t){this.setAttribute("color",t);}get faceColor(){return this.getAttribute("face-color")||void 0}set faceColor(t){t?this.setAttribute("face-color",t):this.removeAttribute("face-color");}get cheekColor(){return this.getAttribute("cheek-color")||void 0}set cheekColor(t){t?this.setAttribute("cheek-color",t):this.removeAttribute("cheek-color");}get size(){let t=this.getAttribute("size");return t?/^\d+(\.\d+)?$/.test(t)?Number(t):t:y.size}set size(t){this.setAttribute("size",String(t));}get speed(){return this.readState().speed}set speed(t){this.setAttribute("speed",String(t));}get followCursor(){return N(this.getAttribute("follow-cursor"),y.followCursor)}set followCursor(t){this.setAttribute("follow-cursor",String(t));}get interactive(){return N(this.getAttribute("interactive"),y.interactive)}set interactive(t){this.setAttribute("interactive",String(t));}get shadow(){return N(this.getAttribute("shadow"),y.shadow)}set shadow(t){this.setAttribute("shadow",String(t));}get settle(){return this.readState().settle}set settle(t){this.setAttribute("settle",String(t));}get settleMood(){let t=this.getAttribute("settle-mood");return J(t)?t:void 0}set settleMood(t){t?this.setAttribute("settle-mood",t):this.removeAttribute("settle-mood");}get sound(){return N(this.getAttribute("sound"),y.sound)}set sound(t){this.setAttribute("sound",String(t));}};te.observedAttributes=Rt;function Ze(e="moodi-buddy"){typeof window>"u"||!("customElements"in window)||customElements.get(e)||customElements.define(e,class extends te{});}Ze();export{y as DEFAULTS,et as MOODS,Lt as MOOD_INFO,te as MoodiBuddyElement,Ot as PALETTES,Qe as SHAPES,Gt as SHAPE_LABELS,Ze as defineMoodi,J as isMood,pe as isShape};
package/dist/react.cjs CHANGED
@@ -1,2 +1,2 @@
1
1
  "use client";
2
- "use strict";var O=Object.create;var c=Object.defineProperty;var F=Object.getOwnPropertyDescriptor;var N=Object.getOwnPropertyNames;var j=Object.getPrototypeOf,q=Object.prototype.hasOwnProperty;var W=(e,o)=>{for(var t in o)c(e,t,{get:o[t],enumerable:!0})},M=(e,o,t,i)=>{if(o&&typeof o=="object"||typeof o=="function")for(let d of N(o))!q.call(e,d)&&d!==t&&c(e,d,{get:()=>o[d],enumerable:!(i=F(o,d))||i.enumerable});return e};var _=(e,o,t)=>(t=e!=null?O(j(e)):{},M(o||!e||!e.__esModule?c(t,"default",{value:e,enumerable:!0}):t,e)),$=e=>M(c({},"__esModule",{value:!0}),e);var Y={};W(Y,{DEFAULTS:()=>z,MOODS:()=>v,MOOD_INFO:()=>U,Moodi:()=>X,PALETTES:()=>G,SHAPES:()=>S,SHAPE_LABELS:()=>J,isMood:()=>Q,isShape:()=>K,loadMoodi:()=>l});module.exports=$(Y);var n=require("react");var S=["ghost","pebble","blob","drop","bean","cube"],v=["idle","thinking","loading","listening","speaking","happy","surprised","sad","error","sleeping","love"],z={shape:"ghost",mood:"idle",color:"#6c5ce7",size:160,speed:1,followCursor:!0,interactive:!0,shadow:!0,sound:!1,settle:0},G={Iris:"#6c5ce7",Peach:"#f2a07b",Sage:"#8fb996",Sky:"#8ec5e8",Lilac:"#b9a3e3",Butter:"#f3d36b",Coral:"#f07167",Ink:"#2b2d42",Cloud:"#ecebe8"},U={idle:{label:"Idle",description:"Breathing softly. Blinks now and then."},thinking:{label:"Thinking",description:"Eyes drift up. Little thoughts pop."},loading:{label:"Loading",description:"Half-lidded, wobbling patiently."},listening:{label:"Listening",description:"All eyes. Nods along to every word."},speaking:{label:"Speaking",description:"Chatty mouth, bouncing to the rhythm."},happy:{label:"Happy",description:"Bounces with joy. Cheeks glow."},surprised:{label:"Surprised",description:"Wide eyes, tiny o. Did not see that coming."},sad:{label:"Sad",description:"Slumps a little. Needs a minute."},error:{label:"Error",description:"Something broke. Shakes it off."},sleeping:{label:"Sleeping",description:"Deep, slow breaths. Do not disturb."},love:{label:"Love",description:"Heart eyes, floating on air."}},J={pebble:"Pebble",blob:"Blob",drop:"Drop",bean:"Bean",cube:"Cube",ghost:"Ghost"},K=e=>S.includes(e),Q=e=>v.includes(e);var w=null,k=!1,l=()=>w??(w=import("moodi").then(e=>e.defineMoodi()));function V(e){if(w||e==="eager")return void l();if(e==="idle"){typeof requestIdleCallback=="function"?requestIdleCallback(()=>l(),{timeout:1200}):setTimeout(l,1);return}if(k)return;k=!0;let o=["pointermove","pointerdown","touchstart","keydown","wheel","scroll"],t=()=>{o.forEach(i=>removeEventListener(i,t)),l()};o.forEach(i=>addEventListener(i,t,{passive:!0,once:!0}))}var u=e=>e===void 0?void 0:String(e),E=e=>e===void 0?"160px":typeof e=="number"||/^\d+(\.\d+)?$/.test(e)?`${e}px`:e,X=(0,n.forwardRef)(function({shape:o,mood:t,color:i,faceColor:d,cheekColor:x,size:a,speed:b,followCursor:L,interactive:C,shadow:P,sound:B,settle:h,onMoodChange:g,onReady:s,poster:f,loading:m="idle",className:D,style:A,...H},T){let p=(0,n.useRef)(null);(0,n.useImperativeHandle)(T,()=>p.current,[]),(0,n.useEffect)(()=>{V(m)},[m]),(0,n.useEffect)(()=>{let r=p.current;if(!(!r||!s))return r.hasAttribute("ready")?void s():(r.addEventListener("ready",s,{once:!0}),()=>r.removeEventListener("ready",s))},[s]),(0,n.useEffect)(()=>{let r=p.current;if(!r||!g)return;let y=R=>g(R.detail);return r.addEventListener("moodchange",y),()=>r.removeEventListener("moodchange",y)},[g]);let I=f?(0,n.createElement)("img",{src:f,alt:"","aria-hidden":!0,decoding:"async",draggable:!1,style:{display:"block",width:"100%",height:"100%",objectFit:"contain"}}):null;return(0,n.createElement)("moodi-buddy",{ref:p,className:D,shape:o,mood:t,color:i,"face-color":d,"cheek-color":x,size:a===void 0?void 0:String(a),speed:b===void 0?void 0:String(b),"follow-cursor":u(L),interactive:u(C),shadow:u(P),sound:u(B),settle:h===void 0?void 0:String(h),style:{display:"inline-block",width:E(a),height:E(a),verticalAlign:"middle",...A},suppressHydrationWarning:!0,...H},I)});0&&(module.exports={DEFAULTS,MOODS,MOOD_INFO,Moodi,PALETTES,SHAPES,SHAPE_LABELS,isMood,isShape,loadMoodi});
2
+ "use strict";var F=Object.create;var c=Object.defineProperty;var N=Object.getOwnPropertyDescriptor;var j=Object.getOwnPropertyNames;var q=Object.getPrototypeOf,W=Object.prototype.hasOwnProperty;var _=(e,o)=>{for(var t in o)c(e,t,{get:o[t],enumerable:!0})},M=(e,o,t,i)=>{if(o&&typeof o=="object"||typeof o=="function")for(let d of j(o))!W.call(e,d)&&d!==t&&c(e,d,{get:()=>o[d],enumerable:!(i=N(o,d))||i.enumerable});return e};var $=(e,o,t)=>(t=e!=null?F(q(e)):{},M(o||!e||!e.__esModule?c(t,"default",{value:e,enumerable:!0}):t,e)),z=e=>M(c({},"__esModule",{value:!0}),e);var Z={};_(Z,{DEFAULTS:()=>G,MOODS:()=>v,MOOD_INFO:()=>J,Moodi:()=>Y,PALETTES:()=>U,SHAPES:()=>S,SHAPE_LABELS:()=>K,isMood:()=>V,isShape:()=>Q,loadMoodi:()=>l});module.exports=z(Z);var n=require("react");var S=["ghost","pebble","blob","drop","bean","cube"],v=["idle","thinking","loading","listening","speaking","happy","surprised","sad","error","sleeping","love"],G={shape:"ghost",mood:"idle",color:"#2b15d1",size:160,speed:1,followCursor:!0,interactive:!0,shadow:!0,sound:!1,settle:0},U={Iris:"#2b15d1",Peach:"#f2a07b",Sage:"#8fb996",Sky:"#8ec5e8",Lilac:"#b9a3e3",Butter:"#f3d36b",Coral:"#f07167",Ink:"#2b2d42",Cloud:"#ecebe8"},J={idle:{label:"Idle",description:"Breathing softly. Blinks now and then."},thinking:{label:"Thinking",description:"Eyes drift up. Little thoughts pop."},loading:{label:"Loading",description:"Half-lidded, wobbling patiently."},listening:{label:"Listening",description:"All eyes. Nods along to every word."},speaking:{label:"Speaking",description:"Chatty mouth, bouncing to the rhythm."},happy:{label:"Happy",description:"Bounces with joy. Cheeks glow."},surprised:{label:"Surprised",description:"Wide eyes, tiny o. Did not see that coming."},sad:{label:"Sad",description:"Slumps a little. Needs a minute."},error:{label:"Error",description:"Something broke. Shakes it off."},sleeping:{label:"Sleeping",description:"Deep, slow breaths. Do not disturb."},love:{label:"Love",description:"Heart eyes, floating on air."}},K={pebble:"Pebble",blob:"Blob",drop:"Drop",bean:"Bean",cube:"Cube",ghost:"Ghost"},Q=e=>S.includes(e),V=e=>v.includes(e);var w=null,k=!1,l=()=>w??(w=import("moodi").then(e=>e.defineMoodi()));function X(e){if(w||e==="eager")return void l();if(e==="idle"){typeof requestIdleCallback=="function"?requestIdleCallback(()=>l(),{timeout:1200}):setTimeout(l,1);return}if(k)return;k=!0;let o=["pointermove","pointerdown","touchstart","keydown","wheel","scroll"],t=()=>{o.forEach(i=>removeEventListener(i,t)),l()};o.forEach(i=>addEventListener(i,t,{passive:!0,once:!0}))}var u=e=>e===void 0?void 0:String(e),E=e=>e===void 0?"160px":typeof e=="number"||/^\d+(\.\d+)?$/.test(e)?`${e}px`:e,Y=(0,n.forwardRef)(function({shape:o,mood:t,color:i,faceColor:d,cheekColor:x,size:a,speed:b,followCursor:L,interactive:C,shadow:P,sound:B,settle:h,settleMood:D,onMoodChange:g,onReady:s,poster:f,loading:m="idle",className:A,style:H,...T},I){let p=(0,n.useRef)(null);(0,n.useImperativeHandle)(I,()=>p.current,[]),(0,n.useEffect)(()=>{X(m)},[m]),(0,n.useEffect)(()=>{let r=p.current;if(!(!r||!s))return r.hasAttribute("ready")?void s():(r.addEventListener("ready",s,{once:!0}),()=>r.removeEventListener("ready",s))},[s]),(0,n.useEffect)(()=>{let r=p.current;if(!r||!g)return;let y=O=>g(O.detail);return r.addEventListener("moodchange",y),()=>r.removeEventListener("moodchange",y)},[g]);let R=f?(0,n.createElement)("img",{src:f,alt:"","aria-hidden":!0,decoding:"async",draggable:!1,style:{display:"block",width:"100%",height:"100%",objectFit:"contain"}}):null;return(0,n.createElement)("moodi-buddy",{ref:p,className:A,shape:o,mood:t,color:i,"face-color":d,"cheek-color":x,size:a===void 0?void 0:String(a),speed:b===void 0?void 0:String(b),"follow-cursor":u(L),interactive:u(C),shadow:u(P),sound:u(B),settle:h===void 0?void 0:String(h),"settle-mood":D,style:{display:"inline-block",width:E(a),height:E(a),verticalAlign:"middle",...H},suppressHydrationWarning:!0,...T},R)});0&&(module.exports={DEFAULTS,MOODS,MOOD_INFO,Moodi,PALETTES,SHAPES,SHAPE_LABELS,isMood,isShape,loadMoodi});
package/dist/react.d.cts CHANGED
@@ -8,7 +8,7 @@ interface MoodiProps {
8
8
  shape?: Shape;
9
9
  /** Current mood / state. Default `'idle'`. */
10
10
  mood?: Mood;
11
- /** Body color, any CSS color. Default `'#6c5ce7'`. */
11
+ /** Body color, any CSS color. Default `'#2b15d1'`. */
12
12
  color?: string;
13
13
  /** Eyes / mouth color. Auto-contrast by default. */
14
14
  faceColor?: string;
@@ -31,6 +31,11 @@ interface MoodiProps {
31
31
  * (hopping, shaking, hearts… stop; the facial expression stays). `0` = never. Default `0`.
32
32
  */
33
33
  settle?: number;
34
+ /**
35
+ * With `settle`: once it has elapsed, switch to this mood (face and body), e.g.
36
+ * `mood="happy" settle={3000} settleMood="idle"`. The `mood` prop is unchanged.
37
+ */
38
+ settleMood?: Mood;
34
39
  }
35
40
  interface MoodChangeDetail {
36
41
  mood: Mood;
@@ -63,7 +68,7 @@ declare const isMood: (v: unknown) => v is Mood;
63
68
 
64
69
  declare const Base: typeof HTMLElement;
65
70
  declare class MoodiBuddyElement extends Base {
66
- static observedAttributes: readonly ["shape", "mood", "color", "face-color", "cheek-color", "size", "speed", "follow-cursor", "interactive", "shadow", "sound", "settle"];
71
+ static observedAttributes: readonly ["shape", "mood", "color", "face-color", "cheek-color", "size", "speed", "follow-cursor", "interactive", "shadow", "sound", "settle", "settle-mood"];
67
72
  private buddy;
68
73
  private io?;
69
74
  private ro?;
@@ -106,6 +111,8 @@ declare class MoodiBuddyElement extends Base {
106
111
  set shadow(v: boolean);
107
112
  get settle(): number;
108
113
  set settle(v: number);
114
+ get settleMood(): Mood | undefined;
115
+ set settleMood(v: Mood | undefined);
109
116
  get sound(): boolean;
110
117
  set sound(v: boolean);
111
118
  }
package/dist/react.d.ts CHANGED
@@ -8,7 +8,7 @@ interface MoodiProps {
8
8
  shape?: Shape;
9
9
  /** Current mood / state. Default `'idle'`. */
10
10
  mood?: Mood;
11
- /** Body color, any CSS color. Default `'#6c5ce7'`. */
11
+ /** Body color, any CSS color. Default `'#2b15d1'`. */
12
12
  color?: string;
13
13
  /** Eyes / mouth color. Auto-contrast by default. */
14
14
  faceColor?: string;
@@ -31,6 +31,11 @@ interface MoodiProps {
31
31
  * (hopping, shaking, hearts… stop; the facial expression stays). `0` = never. Default `0`.
32
32
  */
33
33
  settle?: number;
34
+ /**
35
+ * With `settle`: once it has elapsed, switch to this mood (face and body), e.g.
36
+ * `mood="happy" settle={3000} settleMood="idle"`. The `mood` prop is unchanged.
37
+ */
38
+ settleMood?: Mood;
34
39
  }
35
40
  interface MoodChangeDetail {
36
41
  mood: Mood;
@@ -63,7 +68,7 @@ declare const isMood: (v: unknown) => v is Mood;
63
68
 
64
69
  declare const Base: typeof HTMLElement;
65
70
  declare class MoodiBuddyElement extends Base {
66
- static observedAttributes: readonly ["shape", "mood", "color", "face-color", "cheek-color", "size", "speed", "follow-cursor", "interactive", "shadow", "sound", "settle"];
71
+ static observedAttributes: readonly ["shape", "mood", "color", "face-color", "cheek-color", "size", "speed", "follow-cursor", "interactive", "shadow", "sound", "settle", "settle-mood"];
67
72
  private buddy;
68
73
  private io?;
69
74
  private ro?;
@@ -106,6 +111,8 @@ declare class MoodiBuddyElement extends Base {
106
111
  set shadow(v: boolean);
107
112
  get settle(): number;
108
113
  set settle(v: number);
114
+ get settleMood(): Mood | undefined;
115
+ set settleMood(v: Mood | undefined);
109
116
  get sound(): boolean;
110
117
  set sound(v: boolean);
111
118
  }
package/dist/react.js CHANGED
@@ -1,2 +1,2 @@
1
1
  "use client";
2
- import{createElement as m,forwardRef as R,useEffect as c,useImperativeHandle as O,useRef as F}from"react";var T=["ghost","pebble","blob","drop","bean","cube"],I=["idle","thinking","loading","listening","speaking","happy","surprised","sad","error","sleeping","love"],j={shape:"ghost",mood:"idle",color:"#6c5ce7",size:160,speed:1,followCursor:!0,interactive:!0,shadow:!0,sound:!1,settle:0},q={Iris:"#6c5ce7",Peach:"#f2a07b",Sage:"#8fb996",Sky:"#8ec5e8",Lilac:"#b9a3e3",Butter:"#f3d36b",Coral:"#f07167",Ink:"#2b2d42",Cloud:"#ecebe8"},W={idle:{label:"Idle",description:"Breathing softly. Blinks now and then."},thinking:{label:"Thinking",description:"Eyes drift up. Little thoughts pop."},loading:{label:"Loading",description:"Half-lidded, wobbling patiently."},listening:{label:"Listening",description:"All eyes. Nods along to every word."},speaking:{label:"Speaking",description:"Chatty mouth, bouncing to the rhythm."},happy:{label:"Happy",description:"Bounces with joy. Cheeks glow."},surprised:{label:"Surprised",description:"Wide eyes, tiny o. Did not see that coming."},sad:{label:"Sad",description:"Slumps a little. Needs a minute."},error:{label:"Error",description:"Something broke. Shakes it off."},sleeping:{label:"Sleeping",description:"Deep, slow breaths. Do not disturb."},love:{label:"Love",description:"Heart eyes, floating on air."}},_={pebble:"Pebble",blob:"Blob",drop:"Drop",bean:"Bean",cube:"Cube",ghost:"Ghost"},$=e=>T.includes(e),z=e=>I.includes(e);var S=null,y=!1,l=()=>S??(S=import("moodi").then(e=>e.defineMoodi()));function N(e){if(S||e==="eager")return void l();if(e==="idle"){typeof requestIdleCallback=="function"?requestIdleCallback(()=>l(),{timeout:1200}):setTimeout(l,1);return}if(y)return;y=!0;let i=["pointermove","pointerdown","touchstart","keydown","wheel","scroll"],r=()=>{i.forEach(t=>removeEventListener(t,r)),l()};i.forEach(t=>addEventListener(t,r,{passive:!0,once:!0}))}var a=e=>e===void 0?void 0:String(e),M=e=>e===void 0?"160px":typeof e=="number"||/^\d+(\.\d+)?$/.test(e)?`${e}px`:e,J=R(function({shape:i,mood:r,color:t,faceColor:v,cheekColor:k,size:d,speed:u,followCursor:E,interactive:w,shadow:x,sound:L,settle:g,onMoodChange:p,onReady:n,poster:b,loading:h="idle",className:C,style:P,...B},D){let s=F(null);O(D,()=>s.current,[]),c(()=>{N(h)},[h]),c(()=>{let o=s.current;if(!(!o||!n))return o.hasAttribute("ready")?void n():(o.addEventListener("ready",n,{once:!0}),()=>o.removeEventListener("ready",n))},[n]),c(()=>{let o=s.current;if(!o||!p)return;let f=H=>p(H.detail);return o.addEventListener("moodchange",f),()=>o.removeEventListener("moodchange",f)},[p]);let A=b?m("img",{src:b,alt:"","aria-hidden":!0,decoding:"async",draggable:!1,style:{display:"block",width:"100%",height:"100%",objectFit:"contain"}}):null;return m("moodi-buddy",{ref:s,className:C,shape:i,mood:r,color:t,"face-color":v,"cheek-color":k,size:d===void 0?void 0:String(d),speed:u===void 0?void 0:String(u),"follow-cursor":a(E),interactive:a(w),shadow:a(x),sound:a(L),settle:g===void 0?void 0:String(g),style:{display:"inline-block",width:M(d),height:M(d),verticalAlign:"middle",...P},suppressHydrationWarning:!0,...B},A)});export{j as DEFAULTS,I as MOODS,W as MOOD_INFO,J as Moodi,q as PALETTES,T as SHAPES,_ as SHAPE_LABELS,z as isMood,$ as isShape,l as loadMoodi};
2
+ import{createElement as m,forwardRef as O,useEffect as c,useImperativeHandle as F,useRef as N}from"react";var I=["ghost","pebble","blob","drop","bean","cube"],R=["idle","thinking","loading","listening","speaking","happy","surprised","sad","error","sleeping","love"],q={shape:"ghost",mood:"idle",color:"#2b15d1",size:160,speed:1,followCursor:!0,interactive:!0,shadow:!0,sound:!1,settle:0},W={Iris:"#2b15d1",Peach:"#f2a07b",Sage:"#8fb996",Sky:"#8ec5e8",Lilac:"#b9a3e3",Butter:"#f3d36b",Coral:"#f07167",Ink:"#2b2d42",Cloud:"#ecebe8"},_={idle:{label:"Idle",description:"Breathing softly. Blinks now and then."},thinking:{label:"Thinking",description:"Eyes drift up. Little thoughts pop."},loading:{label:"Loading",description:"Half-lidded, wobbling patiently."},listening:{label:"Listening",description:"All eyes. Nods along to every word."},speaking:{label:"Speaking",description:"Chatty mouth, bouncing to the rhythm."},happy:{label:"Happy",description:"Bounces with joy. Cheeks glow."},surprised:{label:"Surprised",description:"Wide eyes, tiny o. Did not see that coming."},sad:{label:"Sad",description:"Slumps a little. Needs a minute."},error:{label:"Error",description:"Something broke. Shakes it off."},sleeping:{label:"Sleeping",description:"Deep, slow breaths. Do not disturb."},love:{label:"Love",description:"Heart eyes, floating on air."}},$={pebble:"Pebble",blob:"Blob",drop:"Drop",bean:"Bean",cube:"Cube",ghost:"Ghost"},z=e=>I.includes(e),G=e=>R.includes(e);var S=null,y=!1,l=()=>S??(S=import("moodi").then(e=>e.defineMoodi()));function j(e){if(S||e==="eager")return void l();if(e==="idle"){typeof requestIdleCallback=="function"?requestIdleCallback(()=>l(),{timeout:1200}):setTimeout(l,1);return}if(y)return;y=!0;let i=["pointermove","pointerdown","touchstart","keydown","wheel","scroll"],r=()=>{i.forEach(t=>removeEventListener(t,r)),l()};i.forEach(t=>addEventListener(t,r,{passive:!0,once:!0}))}var a=e=>e===void 0?void 0:String(e),M=e=>e===void 0?"160px":typeof e=="number"||/^\d+(\.\d+)?$/.test(e)?`${e}px`:e,K=O(function({shape:i,mood:r,color:t,faceColor:v,cheekColor:k,size:d,speed:u,followCursor:E,interactive:w,shadow:x,sound:L,settle:g,settleMood:C,onMoodChange:p,onReady:n,poster:b,loading:h="idle",className:P,style:B,...D},A){let s=N(null);F(A,()=>s.current,[]),c(()=>{j(h)},[h]),c(()=>{let o=s.current;if(!(!o||!n))return o.hasAttribute("ready")?void n():(o.addEventListener("ready",n,{once:!0}),()=>o.removeEventListener("ready",n))},[n]),c(()=>{let o=s.current;if(!o||!p)return;let f=T=>p(T.detail);return o.addEventListener("moodchange",f),()=>o.removeEventListener("moodchange",f)},[p]);let H=b?m("img",{src:b,alt:"","aria-hidden":!0,decoding:"async",draggable:!1,style:{display:"block",width:"100%",height:"100%",objectFit:"contain"}}):null;return m("moodi-buddy",{ref:s,className:P,shape:i,mood:r,color:t,"face-color":v,"cheek-color":k,size:d===void 0?void 0:String(d),speed:u===void 0?void 0:String(u),"follow-cursor":a(E),interactive:a(w),shadow:a(x),sound:a(L),settle:g===void 0?void 0:String(g),"settle-mood":C,style:{display:"inline-block",width:M(d),height:M(d),verticalAlign:"middle",...B},suppressHydrationWarning:!0,...D},H)});export{q as DEFAULTS,R as MOODS,_ as MOOD_INFO,K as Moodi,W as PALETTES,I as SHAPES,$ as SHAPE_LABELS,G as isMood,z as isShape,l as loadMoodi};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "moodi",
3
- "version": "0.3.2",
3
+ "version": "0.5.0",
4
4
  "description": "Tiny 3D mood buddies for your UI.",
5
5
  "license": "MIT",
6
6
  "type": "module",