diff --git a/gen/ui/403/door.js b/gen/ui/403/door.js new file mode 100644 index 0000000..81f69c6 --- /dev/null +++ b/gen/ui/403/door.js @@ -0,0 +1,31 @@ +// a closed door chained shut with a big padlock, it rattles as someone tries it but the lock just swings and holds +const{sin,cos,PI,min,max,exp,hypot,atan2}=Math,T=2*PI +export const frames=20,delay=70 +const chain=(c,x0,y0,x1,y1,j)=>{ + const L=hypot(x1-x0,y1-y0),n=Math.round(L/17),a=atan2(y1-y0,x1-x0) + for(const odd of[1,0])for(let k=odd;k<=n;k+=2){ + const v=k/n,x=x0+(x1-x0)*v,y=y0+(y1-y0)*v+j*sin(PI*v) + c.save();c.translate(x,y);c.rotate(a) + if(odd){c.lineWidth=13;c.beginPath();c.moveTo(-8,0);c.lineTo(8,0);c.stroke()} + else{c.lineWidth=5;c.beginPath();c.ellipse(0,0,12,8,0,0,T);c.fill();c.stroke();c.lineWidth=4;c.beginPath();c.moveTo(-4,0);c.lineTo(4,0);c.stroke()} + c.restore() + } +} +export default(c,t,i)=>{ + const u=t*2%1,sh=u<.3?(i%2?3:-3):0,a=.34*sin(3*T*t)*exp(-2.6*u),j=sh*.7 + if(sh)for(const d of[-1,1])for(const y of[84,112,140])for(const[w,k]of[[11,'#111'],[4,'#fff']])c.lineWidth=w,c.strokeStyle=k,c.beginPath(),c.moveTo(128+d*(100+(i%2)*3),y),c.lineTo(128+d*(114+(i%2)*3),y-6),c.stroke() + c.lineWidth=7;c.strokeStyle='#111' + c.beginPath();c.roundRect(46,12,164,232,[30,30,4,4]);c.fill();c.stroke() + c.save();c.translate(sh,0) + c.beginPath();c.roundRect(60,26,136,218,[20,20,2,2]);c.fill();c.stroke() + c.lineWidth=5;c.beginPath();c.roundRect(76,44,104,64,10);c.roundRect(76,124,104,100,10);c.stroke() + c.lineWidth=7;c.beginPath();c.arc(176,140,9,0,T);c.fill();c.stroke() + chain(c,72,52,184,214,j);chain(c,184,52,72,214,-j) + c.fillStyle='#111';for(const[x,y]of[[72,52],[184,52],[72,214],[184,214]])c.beginPath(),c.arc(x,y,7,0,T),c.fill() + c.fillStyle='#fff';c.restore() + c.save();c.translate(128+sh,128);c.rotate(a) + for(const[w,k]of[[30,'#111'],[16,'#fff']])c.lineWidth=w,c.strokeStyle=k,c.beginPath(),c.moveTo(-20,34),c.lineTo(-20,20),c.arc(0,20,20,PI,0),c.lineTo(20,34),c.stroke() + c.lineWidth=7;c.strokeStyle='#111';c.beginPath();c.roundRect(-36,30,72,58,14);c.fill();c.stroke() + c.fillStyle='#111';c.beginPath();c.arc(0,52,9,0,T);c.moveTo(-5,56);c.lineTo(-8,76);c.lineTo(8,76);c.lineTo(5,56);c.fill() + c.restore() +} diff --git a/gen/ui/404/hole.js b/gen/ui/404/hole.js new file mode 100644 index 0000000..c366e40 --- /dev/null +++ b/gen/ui/404/hole.js @@ -0,0 +1,46 @@ +// a little 404 signpost stands by a hole; a mole pops up, looks left and right, shrugs and ducks back down +const{sin,cos,PI,min,max}=Math,T=2*PI +export const frames=32,delay=70 +const cl=u=>min(1,max(0,u)),io=u=>(u=cl(u),u<.5?2*u*u:1-2*(1-u)**2),bk=u=>(u=cl(u),1+2.7*(u-1)**3+1.7*(u-1)**2) +const HX=172,HY=198 +const Q=(c,x,y,s)=>{ + c.save();c.translate(x,y);c.scale(s,s) + for(const[w,st]of[[18,'#111'],[7,'#fff']])c.lineWidth=w,c.strokeStyle=st,c.beginPath(),c.arc(0,-10,10,PI,PI*2.3),c.quadraticCurveTo(0,3,0,8),c.stroke() + c.lineWidth=5;c.strokeStyle='#111';c.beginPath();c.arc(0,22,5.5,0,T);c.fill();c.stroke();c.restore() +} +export default(c,t)=>{ + const up=bk((t-.08)/.12)-io((t-.8)/.08),lk=sin(T*cl((t-.24)/.24)),sh=min(1,2.2*sin(PI*cl((t-.52)/.24))),u0=cl((t-.1)/.3),wb=.05*sin(T*2*u0)*(1-u0) + c.beginPath();c.roundRect(10,178,236,54,27);c.fill();c.stroke() + c.fillStyle='#111';for(const[x,y]of[[32,214],[58,222],[112,218],[228,214]])c.beginPath(),c.arc(x,y,3.5,0,T),c.fill() + c.beginPath();c.ellipse(HX,HY,48,13,0,0,T);c.fill();c.fillStyle='#fff' + c.lineWidth=6;for(const[x,r]of[[HX-56,13],[HX+57,10]])c.beginPath(),c.arc(x,HY+4,r,PI,0),c.closePath(),c.fill(),c.stroke() + c.lineWidth=7 + c.save();c.translate(72,204);c.rotate(.02+wb);c.translate(-72,-204) + c.beginPath();c.roundRect(65,110,14,96,4);c.fill();c.stroke() + c.beginPath();c.roundRect(20,62,104,56,10);c.fill();c.stroke() + c.lineWidth=9;for(const x of[42,102])c.beginPath(),c.moveTo(x+7,104),c.lineTo(x+7,76),c.lineTo(x-11,96),c.lineTo(x+11,96),c.stroke() + c.beginPath();c.ellipse(72,90,8,14,0,0,T);c.stroke() + c.restore() + const v=cl((t-.08)/.2) + if(v>0&&v<1){c.lineWidth=4;for(const[d,h]of[[-1,40],[1,52],[-.5,58],[.6,34]])c.beginPath(),c.arc(HX+d*(26+34*v),HY-4-h*sin(PI*v)+20*v*v,6*(1-v**3),0,T),c.fill(),c.stroke()} + if(up>.01){ + c.save();c.beginPath();c.rect(0,0,256,HY);c.ellipse(HX,HY,48,13,0,0,T);c.clip() + c.translate(HX,HY+20+96*(1-up));c.rotate(.08*sh) + c.lineWidth=7;c.beginPath();c.roundRect(-32,-106,64,130,32);c.fill();c.stroke() + const e=7*lk + c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.arc(d*12+e,-72,4.5,0,T),c.fill() + c.beginPath();c.ellipse(e*1.3,-58,11,8,0,0,T);c.fill() + c.fillStyle='#fff';c.beginPath();c.arc(e*1.3-4,-61,2.5,0,T);c.fill() + c.lineWidth=3;c.beginPath();c.roundRect(e-6,-50,12,9,2);c.fill();c.stroke();c.beginPath();c.moveTo(e,-50);c.lineTo(e,-41);c.stroke() + for(const d of[-1,1])for(const a of[-.15,.15])c.beginPath(),c.moveTo(e*1.3+d*14,-58+a*20),c.lineTo(e*1.3+d*26,-58+a*44),c.stroke() + if(sh>.1){c.lineWidth=4;for(const d of[-1,1])c.beginPath(),c.arc(d*12+e,-80-4*sh,6,PI*1.2,PI*1.8),c.stroke()} + for(const d of[-1,1]){ + c.save();c.translate(d*(30+14*sh),-10-38*sh);c.rotate(d*(-.2-.9*sh));c.lineWidth=5 + c.beginPath();c.ellipse(0,0,14,10,0,0,T);c.fill();c.stroke() + c.lineWidth=3;for(const k of[-5,0,5])c.beginPath(),c.moveTo(k,-9),c.lineTo(k,-15),c.stroke() + c.restore() + } + c.restore() + } + if(sh>.05)Q(c,HX+50,74,sh) +} diff --git a/gen/ui/404/magnifier.js b/gen/ui/404/magnifier.js new file mode 100644 index 0000000..d679de3 --- /dev/null +++ b/gen/ui/404/magnifier.js @@ -0,0 +1,37 @@ +// a magnifying glass sweeps back and forth over 404, and when it hovers the 0 it swells up big with a confused little face +const{sin,PI,max,abs}=Math,T=2*PI +export const frames=24,delay=70 +const N=(c,g)=>{for(const[w,s]of[[28,'#111'],[14,'#fff']]){ + c.lineWidth=w;c.strokeStyle=s + for(const x of[60,196])c.beginPath(),c.moveTo(x+8,150),c.lineTo(x+8,78),c.lineTo(x-20,126),c.lineTo(x+20,126),c.stroke() + c.beginPath();c.ellipse(128,114,22+14*g,36+6*g,0,0,T);c.stroke() +}} +const Q=(c,x,y,s,a)=>{ + c.save();c.translate(x,y);c.rotate(a);c.scale(s,s) + for(const[w,st]of[[20,'#111'],[8,'#fff']])c.lineWidth=w,c.strokeStyle=st,c.beginPath(),c.arc(0,-10,11,PI,PI*2.3),c.quadraticCurveTo(0,4,0,9),c.stroke() + c.lineWidth=5;c.strokeStyle='#111';c.beginPath();c.arc(0,24,6,0,T);c.fill();c.stroke();c.restore() +} +export default(c,t)=>{ + const s=sin(T*t)**3,lx=128+58*s,ly=112,g=max(0,1-abs(lx-128)/30)**1.5,m=1.6 + N(c,0) + c.lineWidth=7;c.strokeStyle='#111' + c.save();c.translate(lx,ly);c.rotate(1.25+.3*s) + c.beginPath();c.roundRect(56,-9,20,18,3);c.fill();c.stroke() + c.beginPath();c.roundRect(74,-15,52,30,13);c.fill();c.stroke() + c.lineWidth=4;for(const u of[90,104])c.beginPath(),c.moveTo(u,-8),c.lineTo(u,8),c.stroke() + c.restore() + c.save();c.beginPath();c.arc(lx,ly,52,0,T);c.fill();c.clip() + c.translate(lx,ly);c.scale(m,m);c.translate(-lx,-ly);N(c,g) + if(g>.05){ + c.translate(128,114);c.scale(1.25*g,1.25*g);c.fillStyle='#111' + for(const d of[-1,1])c.beginPath(),c.arc(d*7,-5,3.5,0,T),c.fill() + c.lineWidth=2.5;c.strokeStyle='#111' + c.beginPath();c.moveTo(-11,-14);c.lineTo(-4,-17);c.moveTo(4,-12);c.lineTo(11,-12);c.stroke() + c.beginPath();c.moveTo(-8,9);c.lineTo(-4,6);c.lineTo(0,9);c.lineTo(4,6);c.lineTo(8,9);c.stroke() + } + c.restore() + c.strokeStyle='#111';c.lineWidth=18;c.beginPath();c.arc(lx,ly,52,0,T);c.stroke() + c.strokeStyle='#fff';c.lineWidth=6;c.stroke() + c.strokeStyle='#ddd';c.lineWidth=7;c.beginPath();c.arc(lx,ly,38,PI*1.1,PI*1.4);c.stroke() + if(g>.3)Q(c,lx+52,ly-62,(g-.3)/.7,.2*sin(T*t*2)) +} diff --git a/gen/ui/404/signpost.js b/gen/ui/404/signpost.js new file mode 100644 index 0000000..419ca4c --- /dev/null +++ b/gen/ui/404/signpost.js @@ -0,0 +1,20 @@ +// a signpost whose arrow boards keep swinging round to point every which way, while a question mark bobs on top +const{sin,cos,PI,min,max}=Math,T=2*PI +export const frames=24,delay=70 +const bk=u=>(u=min(1,max(0,u)),1+2.7*(u-1)**3+1.7*(u-1)**2) +const B=[[112,94,0,-.12,[[.02,1],[.5,1]]],[154,82,PI,.1,[[.18,2],[.66,-2]]],[196,90,0,-.05,[[.34,1],[.84,1]]]] +export default(c,t)=>{ + const bs=B.map(([y,L,b,tl,S])=>[y,L,b+S.reduce((a,[t0,n])=>a+n*PI*bk((t-t0)/.14),0),tl]) + const board=([y,L,a,tl])=>{ + const k=cos(a),P=[[-14,-16],[L-22,-16],[L,0],[L-22,16],[-14,16]] + c.lineWidth=7;c.beginPath();for(const[u,v]of P)c.lineTo(128+u*k,y+v+u*k*tl);c.closePath();c.fill();c.stroke() + c.lineWidth=4;c.beginPath();c.moveTo(128+16*k,y+16*k*tl);c.lineTo(128+(L-34)*k,y+(L-34)*k*tl);c.stroke() + } + c.beginPath();c.roundRect(52,214,152,24,12);c.fill();c.stroke() + for(const b of bs)if(sin(b[2])<0)board(b) + c.lineWidth=7;c.beginPath();c.roundRect(118,86,20,140,6);c.fill();c.stroke() + for(const b of bs)if(sin(b[2])>=0)board(b) + c.save();c.translate(128,50+5*sin(T*t*2));c.rotate(.18*sin(T*t));c.scale(.88,.88) + for(const[w,st]of[[24,'#111'],[11,'#fff']])c.lineWidth=w,c.strokeStyle=st,c.beginPath(),c.arc(0,-12,12,PI,PI*2.3),c.quadraticCurveTo(0,2,0,8),c.stroke() + c.lineWidth=6;c.strokeStyle='#111';c.beginPath();c.arc(0,24,7,0,T);c.fill();c.stroke();c.restore() +} diff --git a/gen/ui/404/tumbleweed.js b/gen/ui/404/tumbleweed.js new file mode 100644 index 0000000..2d6595d --- /dev/null +++ b/gen/ui/404/tumbleweed.js @@ -0,0 +1,32 @@ +// chunky 404 digits stand in the desert like rocks under a hot sun while a tumbleweed bounces across in front, kicking up dust puffs +const{sin,cos,PI,min}=Math,T=2*PI +export const frames=18,delay=70 +const X=t=>-46+348*t +const weed=(c,x,y,r,a,s)=>{ + c.save();c.translate(x,y+r);c.scale(2-s,s);c.translate(0,-r);c.rotate(a) + c.beginPath();for(let k=0;k<36;k++){const b=k*T/36,q=r*(1+.05*sin(b*7));c.lineTo(cos(b)*q,sin(b)*q)} + c.closePath();c.fill();c.stroke() + c.lineWidth=4;for(const[u,v,R,a]of[[.25,.15,.55,0],[-.3,.1,.5,2.2],[.05,-.3,.5,4],[-.1,.3,.42,1],[.1,0,.72,3.4]])c.beginPath(),c.arc(u*r,v*r,R*r,a,a+3),c.stroke() + c.lineWidth=5;for(const b of[.4,2.3,4.1,5.4])c.beginPath(),c.moveTo(cos(b)*r,sin(b)*r),c.lineTo(cos(b+.25)*(r+8),sin(b+.25)*(r+8)),c.stroke() + c.restore() +} +export default(c,t)=>{ + c.save();c.translate(210,42) + for(let k=0;k<8;k++){const a=k*T/8;for(const[w,s]of[[11,'#111'],[4,'#fff']])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.moveTo(cos(a)*21,sin(a)*21),c.lineTo(cos(a)*27,sin(a)*27),c.stroke()} + c.lineWidth=6;c.strokeStyle='#111';c.beginPath();c.arc(0,0,14,0,T);c.fill();c.stroke();c.restore() + c.lineWidth=7;c.beginPath();c.roundRect(10,190,236,46,23);c.fill();c.stroke() + c.fillStyle='#111';for(const[x,y]of[[30,214],[92,226],[160,222],[228,214]])c.beginPath(),c.arc(x,y,3.5,0,T),c.fill() + c.fillStyle='#fff' + for(const[x,a,z]of[[50,-.07,0],[128,.03,1],[206,.07,0]]){ + c.save();c.translate(x,202);c.rotate(a) + for(const[w,s]of[[34,'#111'],[20,'#fff']]){c.lineWidth=w;c.strokeStyle=s;c.beginPath();z?c.ellipse(0,-52,22,52,0,0,T):(c.moveTo(12,0),c.lineTo(12,-104),c.lineTo(-24,-36),c.lineTo(24,-36));c.stroke()} + c.restore() + } + c.lineWidth=7;c.strokeStyle='#111' + const q=t*3%1,x=X(t),r=30,y=230-r-76*4*q*(1-q),e=min(q,1-q),s=e<.07?.8+.2*e/.07:1 + const lx=X(Math.floor(t*3)/3),p=q/.5 + if(p<1){c.lineWidth=5;for(const d of[-1,1])for(const[o,v,R]of[[16,30,12],[30,44,8]])c.beginPath(),c.arc(lx+d*(o+v*p),226-(R+4)*p,R*(1-p)+1,0,T),c.fill(),c.stroke()} + for(const[dy,L]of[[-10,24],[8,16]])for(const[w,st]of[[11,'#111'],[4,'#fff']])c.lineWidth=w,c.strokeStyle=st,c.beginPath(),c.moveTo(x-r-14,y+dy),c.lineTo(x-r-14-L,y+dy),c.stroke() + c.lineWidth=6;c.strokeStyle='#111' + weed(c,x,y,r,x/r,s) +} diff --git a/gen/ui/500/server.js b/gen/ui/500/server.js new file mode 100644 index 0000000..c316263 --- /dev/null +++ b/gen/ui/500/server.js @@ -0,0 +1,20 @@ +// overheated server tower with dizzy x eyes, its lights blinking erratically, trembling while puffs of smoke rise from the top +const{sin,PI}=Math,T=2*PI +export const frames=16,delay=90 +export default(c,t,i)=>{ + const P=[0,1,2].map(k=>{const p=(t+k/3)%1,r=19*sin(PI*p)**.7;return[(k%2?150:110)+16*sin(T*p+k*2)*p,76-54*p,r]}) + for(const f of[0,1])for(const[x,y,r]of P)if(r>1)for(const[dx,dy,q]of[[-r*.6,r*.15,.7],[r*.6,r*.15,.7],[0,-r*.2,.9]]){c.beginPath();c.arc(x+dx,y+dy,r*q,0,T);f?(c.fillStyle='#ddd',c.fill()):(c.lineWidth=14,c.stroke())} + c.lineWidth=7;c.fillStyle='#fff' + c.translate(i%2?1.5:-1.5,0) + for(const x of[84,172])c.beginPath(),c.roundRect(x-12,214,24,20,6),c.fill(),c.stroke() + c.beginPath();c.roundRect(62,74,132,150,16);c.fill();c.stroke() + for(let k=0;k<2;k++){ + const y=88+k*38 + c.beginPath();c.roundRect(76,y,104,28,8);c.fill();c.stroke() + c.lineWidth=5;c.beginPath();c.moveTo(88,y+14);c.lineTo(124,y+14);c.stroke() + for(let j=0;j<2;j++){c.beginPath();c.arc(146+j*18,y+14,5.5,0,T);c.fillStyle=(i*7+k*5+j*3)%5<2?'#111':'#fff';c.fill();c.stroke()} + c.fillStyle='#fff';c.lineWidth=7 + } + c.lineWidth=6;for(const x of[106,150])c.beginPath(),c.moveTo(x-8,170),c.lineTo(x+8,186),c.moveTo(x+8,170),c.lineTo(x-8,186),c.stroke() + c.lineWidth=5;c.beginPath();for(let k=0;k<=6;k++)c.lineTo(110+k*6,204+(k%2?-4:3));c.stroke() +} diff --git a/gen/ui/bell/quiet.js b/gen/ui/bell/quiet.js new file mode 100644 index 0000000..69ad351 --- /dev/null +++ b/gen/ui/bell/quiet.js @@ -0,0 +1,22 @@ +// notification bell fast asleep, no badge, gently rocking and breathing with a snot bubble while Zzz float up +const{sin,PI,max}=Math,T=2*PI +export const frames=20,delay=90 +export default(c,t)=>{ + const D=(f,a=13,b=5)=>{for(const[w,s]of[[a,'#111'],[b,'#fff']])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),f(),c.stroke();c.lineWidth=7;c.strokeStyle='#111'} + for(const k of[0,1,2]){ + const p=(t+k/3)%1,s=(6+10*p)*max(0,sin(PI*p))**.4,x=164+54*p+6*sin(T*p),y=108-84*p + if(s>1)D(()=>{c.moveTo(x-s,y-s);c.lineTo(x+s,y-s);c.lineTo(x-s,y+s);c.lineTo(x+s,y+s)},s>8?14:12,s>8?6:5) + } + const br=sin(T*t),S=1.1 + c.translate(108,36);c.rotate(.04*br);c.scale(S,S*(1+.02*br));c.lineWidth=7/S + c.beginPath();c.arc(0,160,13,0,T);c.fill();c.stroke() + c.beginPath();c.arc(0,4,10,0,T);c.fill();c.stroke() + c.beginPath();c.moveTo(-46,128);c.bezierCurveTo(-46,86,-42,16,0,14);c.bezierCurveTo(42,16,46,86,46,128);c.closePath();c.fill();c.stroke() + c.beginPath();c.roundRect(-60,122,120,20,10);c.fill();c.stroke() + c.lineWidth=5/S;c.beginPath();c.moveTo(-28,40);c.quadraticCurveTo(-34,62,-35,84);c.stroke() + for(const d of[-1,1])c.beginPath(),c.arc(d*16,78,7,.1*PI,.9*PI),c.stroke() + c.fillStyle='#ddd';for(const d of[-1,1])c.beginPath(),c.ellipse(d*25,92,6,4,0,0,T),c.fill() + c.fillStyle='#111';c.beginPath();c.ellipse(0,100,4.5,3.5+.8*br,0,0,T);c.fill() + const b=5+6*(1+br)/2;c.fillStyle='#fff';c.lineWidth=4/S;c.beginPath();c.arc(8+b*.8,102,b,0,T);c.fill();c.stroke() + c.lineWidth=2.5/S;c.beginPath();c.arc(8+b*.8-b*.35,102-b*.35,b*.35,PI,1.5*PI);c.stroke() +} diff --git a/gen/ui/box/empty.js b/gen/ui/box/empty.js new file mode 100644 index 0000000..f0e3a0a --- /dev/null +++ b/gen/ui/box/empty.js @@ -0,0 +1,33 @@ +// cardboard box flaps pop open on an empty box, a spider drops in on its thread and dangles inside, climbs back out and the flaps close +const{sin,cos,PI,min,max}=Math,T=2*PI +export const frames=24,delay=70 +const cl=u=>min(1,max(0,u)),ease=u=>(u=cl(u),u<.5?2*u*u:1-2*(1-u)**2),back=u=>(u=cl(u),1+2.6*(u-1)**3+1.6*(u-1)**2) +const G=232,W=72,H=84,Z=70,F=36,S=42,P=(x,y,z)=>[116+x+z*.32,G-y-z*.5] +export default(c,t)=>{ + const o=back((t-.02)/.12)-ease((t-.86)/.12),dn=back((t-.14)/.16)-cl((t-.7)/.14)**2,sx=127,sy=-36+164*dn+6*sin(2*T*t)*dn + const q=Q=>{c.beginPath();for(const p of Q)c.lineTo(...P(...p));c.closePath();c.fill();c.stroke()} + const fb=(z,d,a)=>{const y=H+sin(a)*F,w=z+d*cos(a)*F;q([[-W,H,z],[W,H,z],[W,y,w],[-W,y,w]])} + const fs=(d,a)=>{const x=d*W-d*cos(a)*S,y=H+sin(a)*S;q([[d*W,H,0],[d*W,H,Z],[x,y,Z],[x,y,0]])} + fb(Z,-1,o*1.9) + c.fillStyle='#999';q([[-W,H,0],[W,H,0],[W,H,Z],[-W,H,Z]]);c.fillStyle='#fff' + if(dn>0){ + for(const[l,s]of[[6,'#111'],[2,'#fff']])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),c.moveTo(sx,0),c.lineTo(sx,sy-18),c.stroke() + const L=[] + for(const d of[-1,1])for(let k=0;k<4;k++){const wg=5*sin(2*T*t+k*1.3+(d>0?1:0)),by=sy-8+k*6;L.push([[sx+d*14,by],[sx+d*(38+k*2),sy-24+k*12+wg*.5],[sx+d*(54-k*2),sy-6+k*16+wg]])} + const pl=p=>{c.beginPath();c.moveTo(...p[0]);c.lineTo(...p[1]);c.lineTo(...p[2])} + c.strokeStyle='#fff';c.lineWidth=14;for(const p of L)pl(p),c.stroke() + c.beginPath();c.ellipse(sx,sy,24,21,0,0,T);c.stroke() + c.strokeStyle='#111';c.lineWidth=6;for(const p of L)pl(p),c.stroke() + c.fillStyle='#111';c.beginPath();c.ellipse(sx,sy,24,21,0,0,T);c.fill() + c.fillStyle='#fff';for(const d of[-1,1])c.beginPath(),c.arc(sx+d*9,sy-3,7,0,T),c.fill() + c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.arc(sx+d*8,sy-1,4,0,T),c.fill() + c.strokeStyle='#fff';c.lineWidth=3;c.beginPath();c.arc(sx,sy+6,5,.15*PI,.85*PI);c.stroke() + c.strokeStyle='#111';c.fillStyle='#fff';c.lineWidth=7 + } + q([[W,0,0],[W,0,Z],[W,H,Z],[W,H,0]]) + q([[-W,0,0],[W,0,0],[W,H,0],[-W,H,0]]) + c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.arc(116+d*26,G-30,6.5,0,T),c.fill() + c.lineWidth=5;c.beginPath();dn>.3?c.ellipse(116,G-14,6,7,0,0,T):c.arc(116,G-21,9,.15*PI,.85*PI);c.stroke();c.lineWidth=7;c.fillStyle='#fff' + fb(0,1,o*3.6) + for(const d of[-1,1])fs(d,o*2.2) +} diff --git a/gen/ui/buffering/video.js b/gen/ui/buffering/video.js new file mode 100644 index 0000000..e24c162 --- /dev/null +++ b/gen/ui/buffering/video.js @@ -0,0 +1,13 @@ +// video player stuck buffering: a ring of dots spins where the play button would be while the scrubber sits frozen partway +const{cos,sin,PI}=Math,T=2*PI +export const frames=16,delay=70 +export default(c,t)=>{ + c.beginPath();c.roundRect(14,36,228,184,20);c.fill();c.stroke() + c.fillStyle='#111';c.beginPath();c.roundRect(28,50,200,124,10);c.fill() + c.fillStyle='#fff' + for(let k=0;k<8;k++){const a=k*T/8-PI/2,g=((t-k/8)%1+1)%1;c.beginPath();c.arc(128+cos(a)*34,112+sin(a)*34,4+8*(1-g)**1.6,0,T);c.fill()} + c.lineWidth=5;c.beginPath();c.moveTo(34,186);c.lineTo(34,208);c.lineTo(53,197);c.closePath();c.fill();c.stroke() + c.lineCap='round';c.lineWidth=12 + for(const[a,b,s]of[[74,222,'#ddd'],[74,168,'#999'],[74,132,'#111']])c.strokeStyle=s,c.beginPath(),c.moveTo(a,197),c.lineTo(b,197),c.stroke() + c.strokeStyle='#111';c.lineWidth=6;c.beginPath();c.arc(132,197,11,0,T);c.fill();c.stroke() +} diff --git a/gen/ui/calendar/empty.js b/gen/ui/calendar/empty.js new file mode 100644 index 0000000..fb9ad9e --- /dev/null +++ b/gen/ui/calendar/empty.js @@ -0,0 +1,23 @@ +// tear-off calendar pad, the top page flips up over the binding and away, but every page underneath is blank too +const{sin,cos,PI,min,max}=Math +export const frames=32,delay=55 +const ease=u=>(u=min(1,max(0,u)),u<.5?2*u*u:1-2*(1-u)**2) +const X=128,Y=102,W=160,H=124 +const flip=(c,a)=>{ + const k=cos(a),y=Y+H*k*(k>0?1:.62),w=W/2*(1+.2*sin(a)),y0=k>0?Y-20:Y + c.fillStyle=k>0?'#fff':'#ddd' + c.beginPath();c.moveTo(X-W/2,y0);c.lineTo(X-w,y);c.lineTo(X+w,y);c.lineTo(X+W/2,y0);c.closePath();c.fill();c.stroke() + c.fillStyle='#fff' +} +export default(c,t)=>{ + const a=1.5*PI*ease((t*2%1)/.78) + if(a>PI)flip(c,a) + c.beginPath();c.rect(X-W/2+5,Y-10,W-10,H+20);c.fill();c.stroke() + c.beginPath();c.rect(X-W/2,Y-20,W,H+20);c.fill();c.stroke() + if(a=PI/2&&a<=PI)flip(c,a) +} diff --git a/gen/ui/cart/empty.js b/gen/ui/cart/empty.js new file mode 100644 index 0000000..593a38a --- /dev/null +++ b/gen/ui/cart/empty.js @@ -0,0 +1,25 @@ +// empty shopping cart rolling back and forth on its own, wheels spinning, leaving little dust puffs behind its wheels +const{sin,cos,PI,min}=Math,T=2*PI +export const frames=20,delay=80 +export default(c,t)=>{ + const D=(f,a=12,b=5)=>{for(const[w,s]of[[a,'#111'],[b,'#fff']])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),f(),c.stroke();c.lineWidth=7;c.strokeStyle='#111'} + const S=.94,x=140+14*sin(T*t),G=216,a=(x-140)/(15*S) + D(()=>{c.moveTo(18,G+6);c.lineTo(238,G+6)},11,4) + c.translate(x,G);c.rotate(.03*sin(T*t));c.scale(S,S);const w=7/S;c.lineWidth=w + const D2=(f)=>D(f,20/S,7/S) + D2(()=>{c.moveTo(-52,-78);c.lineTo(-56,-44);c.lineTo(70,-44)}) + D2(()=>{c.moveTo(-64,-140);c.lineTo(-86,-166)}) + c.lineWidth=w;c.beginPath();c.roundRect(-106,-176,32,16,8);c.fill();c.stroke() + c.beginPath();c.moveTo(-66,-140);c.lineTo(80,-140);c.lineTo(64,-78);c.lineTo(-52,-78);c.closePath();c.fill();c.stroke() + c.lineWidth=5/S;for(const u of[.25,.5,.75])c.beginPath(),c.moveTo(-66+146*u,-140),c.lineTo(-52+116*u,-78),c.stroke() + c.beginPath();c.moveTo(-59,-109);c.lineTo(72,-109);c.stroke() + for(const wx of[-38,54]){ + c.lineWidth=w;c.beginPath();c.arc(wx,-17,15,0,T);c.fill();c.stroke() + c.lineWidth=4/S;c.beginPath();for(const k of[0,1])c.moveTo(wx+cos(a+k*PI/2)*9,-17+sin(a+k*PI/2)*9),c.lineTo(wx-cos(a+k*PI/2)*9,-17-sin(a+k*PI/2)*9);c.stroke() + } + c.setTransform(1,0,0,1,0,0);c.strokeStyle='#111';c.fillStyle='#fff' + for(const[o,d]of[[0,1],[.5,-1]]){ + const q=((t-o)%1+1)%1/.4,g=sin(PI*min(1,q)),wx=140+(d>0?-44:59) + if(q<1)for(const[k,r]of[[0,14],[1,10],[2,8]])if(r*g>1)c.lineWidth=5,c.beginPath(),c.arc(wx-d*(k*12+8*q),G-6-(k==1?9:0)-8*q,r*g,0,T),c.fill(),c.stroke() + } +} diff --git a/gen/ui/chat/crickets.js b/gen/ui/chat/crickets.js new file mode 100644 index 0000000..31fc028 --- /dev/null +++ b/gen/ui/chat/crickets.js @@ -0,0 +1,26 @@ +// an empty speech bubble hangs in awkward silence while a little cricket beside it rubs its wings and chirps +const{sin,cos,PI}=Math,T=2*PI +export const frames=20,delay=70 +const ln=(c,w,f)=>{for(const[l,s]of[[w,'#111'],[w-7,'#fff']])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),f(),c.stroke();c.lineWidth=7;c.strokeStyle='#111'} +export default(c,t,i)=>{ + const ch=t*2%1<.4,j=ch?(i%2?1:-1):0,b=3*sin(t*T) + c.save();c.translate(92,68+b);c.rotate(.03*sin(t*T)) + c.beginPath();c.moveTo(-36,-50);c.arcTo(76,-50,76,50,36);c.arcTo(76,50,-76,50,36);c.lineTo(-12,50);c.lineTo(-50,86);c.lineTo(-38,50);c.arcTo(-76,50,-76,-50,36);c.arcTo(-76,-50,76,-50,36);c.closePath();c.fill();c.stroke() + c.restore() + c.save();c.translate(142,198-(ch&&i%2?2:0));c.scale(1.15,1.15) + if(ch)for(const a of[-1.5,-1.05,-.6])ln(c,10,()=>{const r=j>0?4:0;c.moveTo(46+cos(a)*(42+r),-32+sin(a)*(42+r));c.lineTo(46+cos(a)*(56+r),-32+sin(a)*(56+r))}) + for(const o of[0,1])ln(c,9,()=>{c.moveTo(-36-o*8,-22);c.quadraticCurveTo(-30+o*14,-80,10+o*22+5*sin(t*T*2+o*2),-92+o*12)}) + for(const[x,y,fx,fy]of[[-22,10,-36,30],[2,14,-6,30]])ln(c,11,()=>{c.moveTo(x,y);c.lineTo(fx,fy);c.lineTo(fx-10,fy)}) + c.beginPath();c.ellipse(20,0,46,24,0,0,T);c.fill();c.stroke() + c.save();c.translate(-12,-16);c.rotate(ch?-.32+.1*j:-.06) + c.beginPath();c.moveTo(0,0);c.quadraticCurveTo(40,-24,78,6);c.quadraticCurveTo(40,4,0,0);c.fill();c.stroke() + c.lineWidth=4;c.beginPath();c.moveTo(14,-2);c.quadraticCurveTo(40,-10,62,2);c.stroke() + c.restore() + ln(c,11,()=>{c.moveTo(58,-30);c.lineTo(74,26);c.lineTo(84,26)}) + c.save();c.translate(40,-10);c.rotate(-.55);c.beginPath();c.ellipse(0,0,32,13,0,0,T);c.fill();c.stroke();c.restore() + c.beginPath();c.arc(-36,-4,25,0,T);c.fill();c.stroke() + c.fillStyle='#111';c.beginPath();c.arc(-44,-10,7,0,T);c.fill() + c.fillStyle='#fff';c.beginPath();c.arc(-46,-12,2.5,0,T);c.fill() + c.lineWidth=4;c.beginPath();c.arc(-46,4,7,.2*PI,.8*PI);c.stroke() + c.restore() +} diff --git a/gen/ui/comingsoon/curtain.js b/gen/ui/comingsoon/curtain.js new file mode 100644 index 0000000..31ffa4e --- /dev/null +++ b/gen/ui/comingsoon/curtain.js @@ -0,0 +1,29 @@ +// closed stage curtains sway and twitch as if they're about to part, while a spotlight wobbles across them +const{sin,cos,PI,max}=Math,T=2*PI +export const frames=20,delay=80 +export default(c,t)=>{ + const g=3+9*max(0,sin(T*t))**3,sp=[128+34*sin(T*t),132+18*sin(2*T*t+1),50+4*sin(3*T*t)] + const cur=d=>{ + c.beginPath();c.moveTo(128+d*118,44);c.lineTo(128+d*118,222) + const ix=y=>128+d*(g+(y-44)/178*10*(1+sin(T*t))+3*sin(y/26-T*t*2)) + c.lineTo(128+d*118,224);c.quadraticCurveTo(128+d*(g+60),232,ix(222),222) + for(let y=222;y>=44;y-=6)c.lineTo(ix(y),y) + c.closePath() + } + c.fillStyle='#111';c.fillRect(20,40,216,184) + for(const d of[-1,1]){ + cur(d);c.fillStyle='#bbb';c.fill() + c.save();c.clip() + c.fillStyle='#fff';c.beginPath();c.ellipse(sp[0],sp[1],sp[2],sp[2]*1.1,0,0,T);c.fill() + c.strokeStyle='#888';c.lineWidth=8 + for(const f of[.3,.58,.84]){c.beginPath();for(let y=44;y<=230;y+=6)c.lineTo(128+d*(g+f*108+(y-44)*.04*(1+sin(T*t))+3*sin(y/26-T*t*2+f*5)),y);c.stroke()} + c.restore();c.strokeStyle='#111';c.lineWidth=7;cur(d);c.stroke() + } + c.fillStyle='#fff' + c.beginPath();c.roundRect(8,218,240,28,8);c.fill();c.stroke() + c.lineWidth=5;c.beginPath();c.moveTo(18,230);c.lineTo(238,230);c.stroke();c.lineWidth=7 + c.beginPath();c.moveTo(8,14);c.lineTo(248,14);c.lineTo(248,50) + for(let k=0;k<5;k++)c.arc(248-24-k*48,50,24,0,PI) + c.closePath();c.fill();c.stroke() + c.lineWidth=5;c.beginPath();c.moveTo(16,30);c.lineTo(240,30);c.stroke() +} diff --git a/gen/ui/confirmed/handshake.js b/gen/ui/confirmed/handshake.js new file mode 100644 index 0000000..8cfd7e8 --- /dev/null +++ b/gen/ui/confirmed/handshake.js @@ -0,0 +1,21 @@ +// two hands clasped in a handshake, pumping up and down, with little shake lines above and below +const{sin,cos,PI,atan2,hypot}=Math,T=2*PI +export const frames=16,delay=70 +export default(c,t)=>{ + const D=(f,a=12,b=5)=>{for(const[w,s]of[[a,'#111'],[b,'#fff']])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),f(),c.stroke();c.lineWidth=7;c.strokeStyle='#111'} + const v=sin(2*T*t),cx=128,cy=108+14*v,S=1.35,w=7/S + for(const s of[-1,1])if(s*cos(2*T*t)<-.3)for(const k of[0,1])D(()=>{const y=cy+s*(s<0?56:62)+s*k*14;c.moveTo(cx-24+k*6,y+s*6);c.quadraticCurveTo(cx,y-s*4,cx+24-k*6,y+s*6)},11,4) + for(const d of[-1,1]){ + const wx=cx+d*66,wy=cy+12,ex=128+d*88,ey=224,r=atan2(ey-wy,ex-wx),l=hypot(ex-wx,ey-wy) + c.save();c.translate(wx,wy);c.rotate(r) + c.fillStyle=d<0?'#777':'#fff';c.beginPath();c.roundRect(6,-25,l,50,14);c.fill();c.stroke() + c.fillStyle='#fff';c.beginPath();c.roundRect(-6,-30,18,60,7);c.fill();c.stroke() + c.restore() + } + c.save();c.translate(cx,cy);c.rotate(.05*v);c.scale(S,S);c.lineWidth=w + c.beginPath();c.roundRect(-14,-22,62,46,20);c.fill();c.stroke() + c.beginPath();c.roundRect(-52,-24,52,46,20);c.fill();c.stroke() + for(const[y,l]of[[16,22],[6,32],[-4,36],[-14,32]])c.beginPath(),c.roundRect(-10,y-6,l,12,6),c.fill(),c.stroke() + c.beginPath();c.roundRect(-40,-31,48,15,7.5);c.fill();c.stroke();c.lineWidth=w*.7;c.beginPath();c.moveTo(-31,-27);c.lineTo(-31,-20);c.stroke() + c.restore() +} diff --git a/gen/ui/construction/cone.js b/gen/ui/construction/cone.js new file mode 100644 index 0000000..0c2479c --- /dev/null +++ b/gen/ui/construction/cone.js @@ -0,0 +1,21 @@ +// a little traffic cone sways beside a striped road barrier while the warning lamp on top blinks on and off +const{sin,cos,PI}=Math,T=2*PI +export const frames=16,delay=80 +const ln=(c,w,f)=>{for(const[l,s]of[[w,'#111'],[w-7,'#fff']])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),f(),c.stroke();c.lineWidth=7;c.strokeStyle='#111'} +export default(c,t,i)=>{ + const on=i%8<4,sw=.05*sin(t*T*2),cx=(y,d)=>70+d*(10+(y-46)*.17) + for(const[x,d]of[[122,-1],[214,1]])ln(c,18,()=>{c.moveTo(x,130);c.lineTo(x+d*14,234)}) + c.save();c.beginPath();c.roundRect(94,104,150,40,10);c.fill();c.clip() + c.fillStyle='#111';for(let x=80;x<260;x+=36)c.beginPath(),c.moveTo(x,104),c.lineTo(x+18,104),c.lineTo(x-4,144),c.lineTo(x-22,144),c.fill() + c.restore();c.beginPath();c.roundRect(94,104,150,40,10);c.stroke() + if(on)for(const a of[-2.8,-2.2,-1.57,-.94,-.34])ln(c,11,()=>{c.moveTo(208+cos(a)*32,80+sin(a)*32);c.lineTo(208+cos(a)*46,80+sin(a)*46)}) + c.fillStyle=on?'#fff':'#888';c.beginPath();c.arc(208,84,20,PI,0);c.lineTo(228,92);c.lineTo(188,92);c.closePath();c.fill();c.stroke() + c.fillStyle='#fff';c.beginPath();c.roundRect(184,90,48,16,5);c.fill();c.stroke() + if(on){c.lineWidth=5;c.beginPath();c.arc(208,84,11,PI*1.15,PI*1.45);c.stroke();c.lineWidth=7} + c.translate(70,228);c.rotate(sw);c.translate(-70,-228) + c.beginPath();c.roundRect(14,212,112,22,8);c.fill();c.stroke() + c.beginPath();c.moveTo(cx(46,-1),46);c.lineTo(cx(46,1),46);c.lineTo(cx(214,1),214);c.lineTo(cx(214,-1),214);c.closePath();c.fill();c.stroke() + c.fillStyle='#111';c.beginPath();c.moveTo(cx(90,-1),90);c.lineTo(cx(90,1),90);c.lineTo(cx(118,1),118);c.lineTo(cx(118,-1),118);c.fill() + const e=on?2:-1;for(const d of[-1,1])c.beginPath(),c.arc(70+d*13+e,160-(on?2:0),5.5,0,T),c.fill() + c.lineWidth=5;c.beginPath();c.arc(70+e,172,9,.15*PI,.85*PI);c.stroke() +} diff --git a/gen/ui/construction/crane.js b/gen/ui/construction/crane.js new file mode 100644 index 0000000..73dede0 --- /dev/null +++ b/gen/ui/construction/crane.js @@ -0,0 +1,45 @@ +// a tower crane lowers a content block into the empty slot of a half-built web page, the page scrolls down to make room and a fresh block pops onto the hook +const{sin,PI,min,max}=Math,T=2*PI +export const frames=28,delay=70 +const ease=u=>(u=min(1,max(0,u)),u<.5?2*u*u:1-2*(1-u)**2) +const back=u=>(u=min(1,max(0,u)),1+2.7*(u-1)**3+1.7*(u-1)**2) +const ln=(c,w,f)=>{for(const[l,s]of[[w,'#111'],[w-7,'#fff']])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),f(),c.stroke();c.lineWidth=7;c.strokeStyle='#111'} +const brick=(c,x,y)=>{ + c.lineWidth=5;c.beginPath();c.roundRect(x,y,124,26,6);c.fill();c.stroke() + c.fillStyle='#bbb';c.beginPath();c.roundRect(x+8,y+6,24,14,3);c.fill();c.fillStyle='#fff' + c.strokeStyle='#bbb';for(const[d,w]of[[9,72],[17,48]])c.beginPath(),c.moveTo(x+42,y+d),c.lineTo(x+42+w,y+d),c.stroke() + c.strokeStyle='#111';c.lineWidth=7 +} +export default(c,t)=>{ + const p=ease(t/.42),land=t>=.5,o=32*ease((t-.54)/.28),sx=land?0:6*sin(T*t/.42*1.5)*(1-p) + const hy=land?114-56*ease((t-.5)/.3):58+56*p,sc=t>.82?back((t-.82)/.16):1 + c.beginPath();c.roundRect(14,100,152,138,12);c.fill();c.stroke() + c.lineWidth=5;c.beginPath();c.moveTo(14,122);c.lineTo(166,122);c.stroke() + c.fillStyle='#111';for(const x of[30,44,58])c.beginPath(),c.arc(x,111,4,0,T),c.fill() + c.fillStyle='#fff';c.save();c.beginPath();c.rect(18,124,144,110);c.clip() + for(let k=-2;k<4;k++){ + const y=132+32*k+o + if(k>0||k==0&&land)brick(c,28,y) + else c.setLineDash([8,7]),c.lineWidth=4,c.strokeStyle='#888',c.beginPath(),c.roundRect(28,y,124,26,6),c.stroke(),c.setLineDash([]),c.strokeStyle='#111' + } + c.restore() + if(t>.42&&t<.56)for(const d of[-1,1]){const u=(t-.42)/.14;c.lineWidth=5;c.beginPath();c.arc(90+d*(66+10*u),156-6*u,7*(1-u)+3,0,T);c.fill();c.stroke()} + c.lineWidth=7 + ln(c,9,()=>{c.moveTo(24,34);c.lineTo(200,14);c.lineTo(244,34)}) + c.beginPath();c.roundRect(188,40,24,196,4);c.fill();c.stroke() + c.lineWidth=4;c.beginPath();for(let y=40;y<230;y+=24)c.moveTo(188,y),c.lineTo(212,y+12),c.lineTo(188,y+24);c.stroke() + c.lineWidth=7;c.beginPath();c.roundRect(172,226,56,14,5);c.fill();c.stroke() + c.beginPath();c.roundRect(20,30,228,14,4);c.fill();c.stroke() + c.lineWidth=4;c.beginPath();for(let x=26;x<240;x+=16)c.moveTo(x,31),c.lineTo(x+8,43),c.lineTo(x+16,31);c.stroke() + c.lineWidth=7;c.beginPath();c.roundRect(220,44,24,26,4);c.fill();c.stroke() + c.beginPath();c.moveTo(200,12);c.lineTo(212,30);c.lineTo(188,30);c.closePath();c.fill();c.stroke() + const hx=90+sx + ln(c,9,()=>{c.moveTo(90,52);c.lineTo(hx,hy-10)}) + c.beginPath();c.roundRect(78,42,24,12,4);c.fill();c.stroke() + if(!land||t>.82){ + c.save();c.translate(hx,hy+31);c.scale(sc,sc);c.translate(-hx,-hy-31) + ln(c,8,()=>{c.moveTo(hx-50,hy+18);c.lineTo(hx,hy);c.lineTo(hx+50,hy+18)}) + brick(c,hx-62,hy+18);c.restore() + } + ln(c,11,()=>{c.moveTo(hx,hy-12);c.lineTo(hx,hy);c.arc(hx-6,hy,6,0,PI*.9)}) +} diff --git a/gen/ui/crash/browser.js b/gen/ui/crash/browser.js new file mode 100644 index 0000000..960ff2b --- /dev/null +++ b/gen/ui/crash/browser.js @@ -0,0 +1,31 @@ +// browser window with a dizzy sad face: a crack zigzags down it while it shakes, both halves sag apart, then it blinks off and reloads +const{sin,PI,min,max,hypot}=Math,T=2*PI +export const frames=24,delay=70 +const cl=u=>min(1,max(0,u)),ease=u=>(u=cl(u),u<.5?2*u*u:1-2*(1-u)**2),back=u=>(u=cl(u),1+3*(u-1)**3+2*(u-1)**2) +const K=[[150,30],[150,44],[140,70],[154,96],[134,122],[148,148],[128,174],[140,212],[140,240]],B=[[[154,96],[178,90],[194,104]],[[134,122],[110,128],[96,118]],[[148,148],[170,160],[176,180]]] +const len=P=>P.slice(1).reduce((s,p,k)=>s+hypot(p[0]-P[k][0],p[1]-P[k][1]),0),LK=len(K.slice(1,8)) +export default(c,t,i)=>{ + const r=t<.9,p=r?cl((t-.08)/.26):0,g=r?ease((t-.36)/.1):0,wb=t>.36&&t<.84?.02*sin((t-.36)*T*4)*(1-cl((t-.4)/.4)):0,off=cl((t-.84)/.06),on=back((t-.9)/.1) + const pl=P=>{c.beginPath();for(const q of P)c.lineTo(...q)} + const W=()=>{ + c.beginPath();c.roundRect(24,44,208,168,14);c.fill();c.stroke() + c.beginPath();c.moveTo(24,72);c.lineTo(232,72);c.stroke() + c.lineWidth=4;for(const k of[0,1,2])c.beginPath(),c.arc(42+k*16,58,5,0,T),c.stroke() + c.beginPath();c.roundRect(96,51,122,14,7);c.stroke() + c.lineWidth=7;for(const x of[96,162])c.beginPath(),c.moveTo(x-11,113),c.lineTo(x+11,135),c.moveTo(x+11,113),c.lineTo(x-11,135),c.stroke() + c.lineWidth=6;c.beginPath();c.arc(129,194,24,1.2*PI,1.8*PI);c.stroke() + if(p>0){ + c.lineWidth=9;c.setLineDash([LK*p,999]);pl(K.slice(1,8));c.stroke() + B.forEach((b,k)=>{const q=cl((p-[.29,.46,.62][k])/.25);if(q>0)c.lineWidth=5,c.setLineDash([len(b)*q,999]),pl(b),c.stroke()}) + c.setLineDash([]);c.lineWidth=7 + } + } + if(t>=.9&&on<.02||t>.84&&t<.9&&off>.98)return + const s=t<.84?1:t<.9?1-off:on,sy=t<.84||t>=.9?s:max(.03,1-off),sx=t<.84||t>=.9?s:1+.05*off + c.translate(128+(t>.08&&t<.36?(i%2?3:-3):0),128);c.scale(sx*.94,sy*.94);c.translate(-128,-128) + if(!g&&!wb)return W() + for(const[d,px,py,a]of[[-1,24,44,.07*g+wb],[1,232,44,-.08*g-wb]]){ + c.save();c.translate(px,py);c.rotate(a);c.translate(-px,-py) + pl([[d*999+128,0],...K,[d*999+128,256]]);c.clip();W();c.restore() + } +} diff --git a/gen/ui/deleted/shredder.js b/gen/ui/deleted/shredder.js new file mode 100644 index 0000000..6876798 --- /dev/null +++ b/gen/ui/deleted/shredder.js @@ -0,0 +1,32 @@ +// a sheet of paper pops up and feeds into a chomping shredder, and thin wavy strips stream out the bottom into the bin +const{sin,cos,PI,min,max}=Math,T=2*PI +export const frames=24,delay=70 +const back=u=>(u=min(1,max(0,u)),1+2.7*(u-1)**3+1.7*(u-1)**2) +export default(c,t,i)=>{ + const H=84,s=back(t/.16),f=t<.2?0:min(210,(t-.2)/.58*210),go=t>.2&&t<.8,j=go?(i%2?2:-2):0 + if(f2*sin(y*.1+k*2.1-T*t*3) + if(y1<146||y0>216)continue + c.beginPath();for(let y=max(y0,142);y<=min(y1,218);y+=4)c.lineTo(x+w(y),y);for(let y=min(y1,218);y>=max(y0,142);y-=4)c.lineTo(x+12+w(y),y);c.closePath();c.fill();c.stroke() + } + c.restore();c.lineWidth=5 + for(const[x,a]of[[86,-.6],[116,.3],[146,-.25],[172,.5]])c.save(),c.translate(x,216),c.rotate(a),c.beginPath(),c.roundRect(-5,-16,10,20,4),c.fill(),c.stroke(),c.restore() + c.lineWidth=7 + c.beginPath();c.moveTo(48,208);c.lineTo(208,208);c.lineTo(196,244);c.lineTo(60,244);c.closePath();c.fill();c.stroke() + c.lineWidth=5;for(const x of[96,128,160])c.beginPath(),c.moveTo(x,218),c.lineTo(x,234),c.stroke() + c.translate(j,0);c.lineWidth=7 + c.beginPath();c.roundRect(22,96,212,56,18);c.fill();c.stroke() + c.lineWidth=8;c.beginPath();c.moveTo(66,106);c.lineTo(190,106);c.stroke() + c.fillStyle='#111' + if(go){c.lineWidth=5;for(const d of[-1,1])c.beginPath(),c.moveTo(128+d*36,120),c.lineTo(128+d*26,126),c.lineTo(128+d*36,132),c.stroke() + c.beginPath();c.ellipse(128,138,9,i%2?7:3,0,0,T);c.fill()} + else{for(const d of[-1,1])c.beginPath(),c.arc(128+d*28,124,6,0,T),c.fill();c.lineWidth=5;c.beginPath();c.arc(128,132,9,PI*.15,PI*.85);c.stroke()} +} diff --git a/gen/ui/done/checklist.js b/gen/ui/done/checklist.js new file mode 100644 index 0000000..486b225 --- /dev/null +++ b/gen/ui/done/checklist.js @@ -0,0 +1,24 @@ +// clipboard checklist: the three boxes get ticked one by one, the clipboard does a happy hop, then the ticks pop away +const{sin,PI,min,max,hypot}=Math,T=2*PI +export const frames=24,delay=70 +const cl=u=>min(1,max(0,u)),L=hypot(9,10)+hypot(21,27) +export default(c,t)=>{ + const h=t>.66&&t<.82?sin((t-.66)/.16*PI):0,out=1-cl((t-.88)/.08) + c.translate(128,234-10*h);c.scale(1-.03*h,1+.02*h);c.translate(-128,-234) + c.fillStyle='#ddd';c.beginPath();c.roundRect(50,52,156,182,16);c.fill();c.stroke() + c.fillStyle='#fff';c.lineWidth=5;c.beginPath();c.roundRect(66,70,124,148,6);c.fill();c.stroke() + c.lineWidth=7;c.beginPath();c.arc(128,40,16,0,T);c.fill();c.stroke() + c.beginPath();c.roundRect(92,44,72,26,9);c.fill();c.stroke() + c.lineWidth=5;c.beginPath();c.arc(128,38,5,0,T);c.stroke() + for(let k=0;k<3;k++){ + const y=104+k*48,s=.06+k*.18,p=cl((t-s)/.12),q=cl((t-s-.12)/.1),b=1+.22*sin(q*PI) + c.save();c.translate(96,y);c.scale(b,b) + c.lineWidth=6;c.beginPath();c.roundRect(-15,-15,30,30,7);c.fill();c.stroke();c.restore() + c.lineWidth=10;c.strokeStyle='#bbb';c.beginPath();c.moveTo(126,y-6);c.lineTo([168,154,174][k],y-6);c.moveTo(126,y+8);c.lineTo([150,166,140][k],y+8);c.stroke() + c.strokeStyle='#111' + if(p>0&&out>0){ + c.save();c.translate(96,y);c.scale(out,out);c.lineWidth=11;c.setLineDash([L*p,999]) + c.beginPath();c.moveTo(-10,-1);c.lineTo(-1,9);c.lineTo(20,-18);c.stroke();c.restore() + } + } +} diff --git a/gen/ui/download/tray.js b/gen/ui/download/tray.js new file mode 100644 index 0000000..fdf37a2 --- /dev/null +++ b/gen/ui/download/tray.js @@ -0,0 +1,23 @@ +// a down arrow pops up and drops into a smiling tray, which squashes and bounces as it catches it +const{sin,cos,PI,min,max,exp}=Math,T=2*PI +export const frames=18,delay=70 +const back=u=>(u=min(1,max(0,u)),1+2.7*(u-1)**3+1.7*(u-1)**2) +const ln=(c,w,f)=>{for(const[l,s]of[[w,'#111'],[w-7,'#fff']])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),f(),c.stroke();c.lineWidth=7;c.strokeStyle='#111'} +export default(c,t)=>{ + const s=back(t/.16),v=max(0,(t-.14)/.3),y=58+142*v*v,h=t-.44,b=h>0?.16*exp(-7*h)*cos(h*T*3):0,hit=h>0&&h<.16 + c.translate(128,238);c.scale(1+b*.6,1-b);c.translate(-128,-238) + c.fillStyle='#ddd';c.beginPath();c.roundRect(36,132,184,34,14);c.fill();c.stroke();c.fillStyle='#fff' + if(v<1){ + c.save();c.beginPath();c.rect(0,0,256,226);c.clip() + if(v>.25)for(const x of[-12,12])ln(c,11,()=>{c.moveTo(128+x,y-46);c.lineTo(128+x,y-46-34*v)}) + c.translate(128,y);c.scale(s,s) + c.beginPath();c.moveTo(0,40);c.lineTo(36,2);c.lineTo(15,2);c.lineTo(15,-38);c.lineTo(-15,-38);c.lineTo(-15,2);c.lineTo(-36,2);c.closePath();c.fill();c.stroke() + c.restore() + } + if(hit)for(const d of[-1,1])for(const a of[-.5,0,.5])ln(c,11,()=>{const q=-PI/2+d*(.9+a*.45);c.moveTo(128+d*96+cos(q)*14,134+sin(q)*14);c.lineTo(128+d*96+cos(q)*30,134+sin(q)*30)}) + c.beginPath();c.moveTo(24,150);c.lineTo(232,150);c.lineTo(214,236);c.lineTo(42,236);c.closePath();c.fill();c.stroke() + c.fillStyle='#111';c.lineWidth=6 + if(hit)for(const d of[-1,1])c.beginPath(),c.arc(128+d*26,192,9,PI*1.15,PI*1.85),c.stroke() + else for(const d of[-1,1])c.beginPath(),c.arc(128+d*26,188,7,0,T),c.fill() + c.beginPath();if(hit)c.arc(128,200,11,0,PI),c.closePath(),c.fill();else c.arc(128,198,11,PI*.15,PI*.85),c.stroke() +} diff --git a/gen/ui/error/bug.js b/gen/ui/error/bug.js new file mode 100644 index 0000000..f4b6227 --- /dev/null +++ b/gen/ui/error/bug.js @@ -0,0 +1,26 @@ +// a little beetle scuttles in a figure eight over a code editor, the line it's crawling on lights up as the buggy one +const{sin,cos,PI,atan2,round,min,max}=Math,T=2*PI +export const frames=24,delay=70 +const C=[[0,[28,1],[40,0],[22,0]],[1,[22,1],[58,0]],[2,[30,0],[18,1],[36,0]],[2,[46,0],[26,0]],[1,[16,1],[40,0]],[0,[12,1]],[0,[34,1],[50,0]]] +export default(c,t)=>{ + const x=128+74*sin(T*t),y=148+44*sin(2*T*t),h=atan2(88*cos(2*T*t),74*cos(T*t)),r=min(6,max(0,round((y-88)/20))),st=sin(T*t*8) + c.beginPath();c.roundRect(16,36,224,188,14);c.fill();c.stroke() + c.beginPath();c.moveTo(16,64);c.lineTo(240,64);c.stroke() + c.lineWidth=4;for(const k of[0,1,2])c.beginPath(),c.arc(36+k*18,50,5,0,T),k?c.stroke():(c.fillStyle='#111',c.fill(),c.stroke()) + c.fillStyle='#ddd';c.beginPath();c.roundRect(26,79+r*20,204,18,5);c.fill() + C.forEach(([n,...s],k)=>{ + const y=88+k*20;let x=60+n*18 + c.lineWidth=8;c.strokeStyle='#bbb';c.beginPath();c.moveTo(34,y);c.lineTo(42,y);c.stroke() + for(const[l,d]of s)c.strokeStyle=d?'#111':'#aaa',c.beginPath(),c.moveTo(x,y),c.lineTo(x+l,y),c.stroke(),x+=l+12 + }) + c.strokeStyle='#111';c.lineWidth=3;c.beginPath();for(let k=0;k<=30;k++)c.lineTo(60+k*4,88+r*20+10+(k%2?2:-2));c.stroke() + c.translate(x,y);c.rotate(h);c.scale(1.25,1.25) + c.lineWidth=4.5 + for(const s of[-1,1])for(const k of[-1,0,1]){const g=(k+s)%2?st:-st;c.beginPath();c.moveTo(k*9,s*10);c.lineTo(k*12+g*6,s*22);c.lineTo(k*16+g*7,s*28);c.stroke()} + for(const s of[-1,1]){c.beginPath();c.moveTo(26,s*5);c.quadraticCurveTo(36,s*8,40,s*16+st*2*s);c.stroke()} + c.fillStyle='#111';c.lineWidth=6;c.beginPath();c.arc(22,0,11,0,T);c.fill();c.stroke() + c.beginPath();c.ellipse(-2,0,23,18,0,0,T);c.fill();c.stroke() + c.strokeStyle='#fff';c.lineWidth=3;c.beginPath();c.moveTo(14,0);c.lineTo(-22,0);c.stroke() + c.fillStyle='#fff';for(const[a,b,r]of[[2,-9,4],[-12,-8,3],[2,9,4],[-12,8,3]])c.beginPath(),c.arc(a,b,r,0,T),c.fill() + for(const s of[-1,1])c.beginPath(),c.arc(26,s*5,4,0,T),c.fill();c.fillStyle='#111';for(const s of[-1,1])c.beginPath(),c.arc(28,s*5,2,0,T),c.fill() +} diff --git a/gen/ui/error/cross.js b/gen/ui/error/cross.js new file mode 100644 index 0000000..7fb2ec5 --- /dev/null +++ b/gen/ui/error/cross.js @@ -0,0 +1,13 @@ +// round error badge with a big X shaking its head side to side like "nope nope", then pausing +const{sin,PI,abs,min}=Math,T=2*PI +export const frames=20,delay=60 +export default(c,t)=>{ + const D=(f,a=12,b=5)=>{for(const[w,s]of[[a,'#111'],[b,'#fff']])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),f(),c.stroke();c.lineWidth=7;c.strokeStyle='#111'} + const u=min(1,t/.6),s=sin(T*u*3)*sin(PI*u)**.6 + if(abs(s)>.6){const d=s>0?-1:1;for(const r of[96,114])D(()=>c.arc(128+16*s,128,r,d>0?-.4:PI-.4,d>0?.4:PI+.4),11,4)} + c.translate(128+16*s,128);c.rotate(.1*s);c.scale(1-.06*abs(s),1) + c.beginPath();c.arc(0,0,84,0,T);c.fill();c.stroke() + c.lineWidth=5;c.beginPath();c.arc(0,0,70,0,T);c.stroke() + c.translate(18*s,0);c.scale(1-.2*abs(s),1);c.lineWidth=26 + c.beginPath();c.moveTo(-30,-30);c.lineTo(30,30);c.moveTo(30,-30);c.lineTo(-30,30);c.stroke() +} diff --git a/gen/ui/error/robot.js b/gen/ui/error/robot.js new file mode 100644 index 0000000..2e61c4f --- /dev/null +++ b/gen/ui/error/robot.js @@ -0,0 +1,34 @@ +// broken robot slumped on the floor: head drooping, bent antenna sparking, one eye flickering, a loose spring boinging out of its head +const{sin,cos,PI}=Math,T=2*PI +export const frames=16,delay=90 +const FL=[1,1,0,1,0,0,1,1,1,1,0,1,1,0,1,1],SP=[1,0,0,1,1,0,0,0,1,0,1,1,0,0,0,0] +export default(c,t,i)=>{ + const D=(f,a=20,b=8)=>{for(const[l,s]of[[a,'#111'],[b,'#fff']])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),f(),c.stroke();c.lineWidth=7;c.strokeStyle='#111'} + c.translate(-8,0) + const br=2*sin(T*t),ha=.5+.04*sin(T*t-.6) + for(const d of[-1,1]){D(()=>{c.moveTo(118+d*24,206);c.lineTo(118+d*44,220)});c.beginPath();c.roundRect(118+d*50-18,210,36,22,9);c.fill();c.stroke()} + for(const d of[-1,1]){ + D(()=>{c.moveTo(118+d*44,160+br);c.quadraticCurveTo(118+d*66,176,118+d*66,206)}) + c.lineWidth=6;c.beginPath();c.arc(118+d*66,214,10,0,T);c.fill();c.stroke();c.lineWidth=7 + } + c.beginPath();c.roundRect(72,144+br,92,70-br,14);c.fill();c.stroke() + c.fillStyle='#111';c.beginPath();c.arc(100,168+br,6,0,T);c.fill() + c.lineWidth=4;c.beginPath();c.arc(118,168+br,6,0,T);c.stroke() + c.beginPath();c.moveTo(131,162+br);c.lineTo(141,172+br);c.moveTo(141,162+br);c.lineTo(131,172+br);c.stroke() + for(const y of[188,198])c.beginPath(),c.moveTo(98,y+br*.5),c.lineTo(138,y+br*.5),c.stroke() + c.fillStyle='#fff';c.lineWidth=7 + c.translate(126,146+br);c.rotate(ha) + c.beginPath();c.rect(-8,-10,16,12);c.fill();c.stroke() + c.save();c.translate(-44,-48);c.rotate(-1.75+.35*sin(2*T*t)) + D(()=>{for(let k=0;k<=60;k++){const u=k/60;c.lineTo(9*sin(u*T*4.5),-u*46)}},13,5) + c.beginPath();c.arc(0,-52,9,0,T);c.fill();c.stroke();c.restore() + D(()=>{c.moveTo(16,-70);c.lineTo(26,-92);c.lineTo(50,-90)},12,5) + if(SP[i])for(let k=0;k<4;k++){const a=-1.6+k*1.05+(i%3)*.25,x=55+cos(a)*13,y=-90+sin(a)*13,p=a+1.4;D(()=>{c.moveTo(x,y);c.lineTo(x+cos(a)*10+cos(p)*5,y+sin(a)*10+sin(p)*5);c.lineTo(x+cos(a)*12-cos(p)*5,y+sin(a)*12-sin(p)*5);c.lineTo(x+cos(a)*19,y+sin(a)*19)},10,4)} + c.beginPath();c.arc(55,-90,8,0,T);c.fill();c.stroke() + c.beginPath();c.roundRect(-46,-72,92,64,15);c.fill();c.stroke() + c.fillStyle='#111' + if(FL[i])c.beginPath(),c.roundRect(-28,-52,14,20,7),c.fill() + else c.lineWidth=5,c.beginPath(),c.moveTo(-28,-41),c.lineTo(-14,-41),c.stroke() + c.lineWidth=6;c.beginPath();c.moveTo(13,-51);c.lineTo(27,-35);c.moveTo(27,-51);c.lineTo(13,-35);c.stroke() + c.lineWidth=5;c.beginPath();for(let k=0;k<=4;k++)c.lineTo(-14+k*7,-20+(k%2?-4:2));c.stroke() +} diff --git a/gen/ui/folder/empty.js b/gen/ui/folder/empty.js new file mode 100644 index 0000000..67b727d --- /dev/null +++ b/gen/ui/folder/empty.js @@ -0,0 +1,36 @@ +// folder flap swings open showing nothing inside, a little moth flutters out and flies off, then the flap closes +const{sin,cos,PI,min,max,abs}=Math,T=2*PI +export const frames=24,delay=70 +const cl=u=>min(1,max(0,u)),ease=u=>(u=cl(u),u<.5?2*u*u:1-2*(1-u)**2) +const moth=(c,f)=>{ + for(const d of[-1,1]){ + for(const[w,s]of[[11,'#111'],[4,'#fff']]){c.lineWidth=w;c.strokeStyle=s;c.beginPath();c.moveTo(d*3,-14);c.quadraticCurveTo(d*6,-26,d*16,-31);for(const k of[0,1,2]){const x=d*(6+k*4),y=-22-k*3.5;c.moveTo(x,y);c.lineTo(x+d*5,y+4)}c.stroke()} + c.strokeStyle='#111';c.lineWidth=5 + c.save();c.scale(d*f,1) + c.beginPath();c.moveTo(4,2);c.quadraticCurveTo(30,4,26,22);c.quadraticCurveTo(12,26,4,12);c.closePath();c.fill();c.stroke() + c.beginPath();c.moveTo(4,-8);c.lineTo(48,-20);c.quadraticCurveTo(48,2,8,6);c.closePath();c.fill();c.stroke() + c.fillStyle='#bbb';c.beginPath();c.arc(30,-9,5,0,T);c.fill();c.fillStyle='#fff' + c.lineWidth=3.5;c.beginPath();c.moveTo(14,-2);c.lineTo(40,-12);c.stroke() + c.restore() + } + c.lineWidth=5;c.beginPath();c.ellipse(0,2,8,18,0,0,T);c.fill();c.stroke() + c.beginPath();c.arc(0,-11,9,0,T);c.fill();c.stroke() + c.lineWidth=3.5;for(const y of[6,13])c.beginPath(),c.moveTo(-6,y),c.lineTo(6,y),c.stroke() + c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.arc(d*3.5,-12,2.3,0,T),c.fill() +} +export default(c,t)=>{ + const o=ease((t-.04)/.16)-ease((t-.84)/.12),u=(t-.2)/.6 + c.beginPath();c.roundRect(32,56,80,34,11);c.fill();c.stroke() + c.beginPath();c.roundRect(32,74,192,150,12);c.fill();c.stroke() + if(o>0)c.fillStyle='#ddd',c.beginPath(),c.roundRect(40,84,176,136,8),c.fill(),c.fillStyle='#fff' + const mo=()=>{if(u>0&&u<1){const s=cl(u/.1)*(1-.45*u)*(u>.9?1-(u-.9)/.1:1),x=128+34*sin(u*T*1.5)+40*u,y=150-112*u**.9 + c.save();c.translate(x,y);c.rotate(.25*sin(u*T*1.5+1));c.scale(s*1.25,s*1.25);moth(c,.3+.7*abs(cos(T*t*5)));c.restore();c.lineWidth=7}} + if(u<.12)mo() + const fy=1-.36*o + c.save();c.translate(128,224);c.transform(1,0,-.12*o,fy,0,0) + c.beginPath();c.roundRect(-96,-128,192,128,12);c.fill();c.stroke() + c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),o>.5?c.ellipse(d*26,-68,7,9,0,0,T):c.ellipse(d*26,-64,7,7,0,0,T),c.fill() + c.lineWidth=5;c.beginPath();o>.5?c.ellipse(0,-46,7,8,0,0,T):c.arc(0,-52,9,.15*PI,.85*PI);c.stroke() + c.restore() + if(u>=.12)mo() +} diff --git a/gen/ui/inbox/empty.js b/gen/ui/inbox/empty.js new file mode 100644 index 0000000..75eb4b1 --- /dev/null +++ b/gen/ui/inbox/empty.js @@ -0,0 +1,26 @@ +// empty inbox tray looking bored while a fly buzzes loop-de-loops around it, leaving a dotted trail +const{sin,cos,PI,atan2}=Math,T=2*PI +export const frames=24,delay=70 +const F=u=>{const a=T*u;return[128+80*cos(a)+16*cos(4*a),116+60*sin(a)+18*sin(4*a)]} +export default(c,t,i)=>{ + const fly=(u,back)=>{ + for(let j=12;j>0;j--){const v=u-j*.012;if((sin(T*v)<0)!=back)continue;const[x,y]=F(v);c.lineWidth=3;c.beginPath();c.arc(x,y,3.2,0,T);c.fill();c.stroke()} + if((sin(T*u)<0)!=back)return + const[x,y]=F(u),[px,py]=F(u-.004),h=atan2(y-py,x-px),f=i%2 + c.save();c.translate(x,y);c.rotate(h);c.scale(1.45,1.45) + c.lineWidth=3.5;for(const d of[-1,1])c.save(),c.translate(-3,d*5),c.rotate(d*(f?.5:1.1)),c.beginPath(),c.ellipse(-8,0,11,6,0,0,T),c.fill(),c.stroke(),c.restore() + c.strokeStyle='#fff';c.lineWidth=5;c.beginPath();c.ellipse(-2,0,11,7.5,0,0,T);c.stroke();c.beginPath();c.arc(10,0,6.5,0,T);c.stroke() + c.fillStyle='#111';c.beginPath();c.ellipse(-2,0,11,7.5,0,0,T);c.fill();c.beginPath();c.arc(10,0,6.5,0,T);c.fill() + c.fillStyle='#fff';for(const d of[-1,1])c.beginPath(),c.arc(12,d*3.5,3,0,T),c.fill() + c.restore();c.fillStyle='#fff';c.strokeStyle='#111';c.lineWidth=7 + } + fly(t,1) + c.lineWidth=7 + c.fillStyle='#ddd';c.beginPath();c.moveTo(64,100);c.lineTo(192,100);c.lineTo(222,138);c.lineTo(34,138);c.closePath();c.fill();c.stroke() + c.fillStyle='#fff';c.beginPath();c.moveTo(34,138);c.lineTo(82,138);c.lineTo(94,162);c.lineTo(162,162);c.lineTo(174,138);c.lineTo(222,138);c.lineTo(222,208);c.quadraticCurveTo(222,224,206,224);c.lineTo(50,224);c.quadraticCurveTo(34,224,34,208);c.closePath();c.fill();c.stroke() + c.fillStyle='#111';for(const x of[106,150])c.beginPath(),c.arc(x,188,7,0,PI),c.fill() + c.lineWidth=5;for(const x of[106,150])c.beginPath(),c.moveTo(x-10,188),c.lineTo(x+10,188),c.stroke() + c.beginPath();c.moveTo(119,206);c.lineTo(137,206);c.stroke() + c.fillStyle='#fff';c.lineWidth=7 + fly(t,0) +} diff --git a/gen/ui/loading/bar.js b/gen/ui/loading/bar.js new file mode 100644 index 0000000..11f9725 --- /dev/null +++ b/gen/ui/loading/bar.js @@ -0,0 +1,15 @@ +// rounded progress bar: the striped fill eases out to full while its stripes slide, then slips off the end and wraps round to start again +const{min,max}=Math +export const frames=24,delay=70 +const io=u=>(u=min(1,max(0,u)),u<.5?2*u*u:1-2*(1-u)**2) +export default(c,t)=>{ + const X=32,W=192,b=X+W*io(t/.7),a=X+W*io((t-.72)/.26) + c.beginPath();c.roundRect(18,92,220,72,36);c.fill();c.stroke() + if(b-a<1)return + c.save();c.beginPath();c.roundRect(32,106,192,44,22);c.clip() + c.beginPath();c.roundRect(a,106,b-a,44,22);c.clip() + c.fillStyle='#111';c.fillRect(0,0,256,256) + c.fillStyle='#888';const o=t*72%24 + for(let x=-48+o;x<256;x+=24)c.beginPath(),c.moveTo(x,150),c.lineTo(x+12,150),c.lineTo(x+34,106),c.lineTo(x+22,106),c.fill() + c.restore() +} diff --git a/gen/ui/loading/blocks.js b/gen/ui/loading/blocks.js new file mode 100644 index 0000000..8f60f1a --- /dev/null +++ b/gen/ui/loading/blocks.js @@ -0,0 +1,18 @@ +// sliding puzzle loader: rounded blocks in a 2x2 tray take turns sliding into the one empty slot, so the gap walks round and round +const{min,max}=Math +export const frames=24,delay=70 +const S=[[44,44],[132,44],[132,132],[44,132]],io=u=>(u=min(1,max(0,u)),u<.5?2*u*u:1-2*(1-u)**2) +export default(c,t)=>{ + const n=Math.floor(t*4),p=io((t*4%1)/.6),g=(7-n)%4 + c.beginPath();c.roundRect(28,28,200,200,28);c.fill();c.stroke() + c.fillStyle='#ddd';for(const[x,y]of S)c.beginPath(),c.roundRect(x+6,y+6,68,68,14),c.fill() + c.fillStyle='#fff' + for(let k=0;k<4;k++){ + if(k==g)continue + const m=k==(g+3)%4,[x0,y0]=S[k],[x1,y1]=S[g],x=m?x0+(x1-x0)*p:x0,y=m?y0+(y1-y0)*p:y0 + c.beginPath();c.roundRect(x,y,80,80,18);c.fill();c.stroke() + const dx=m&&p<1?(x1-x0)/88*6:0,dy=m&&p<1?(y1-y0)/88*6:0 + c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.arc(x+40+d*13+dx,y+38+dy,5,0,2*Math.PI),c.fill() + c.fillStyle='#fff' + } +} diff --git a/gen/ui/loading/dots.js b/gen/ui/loading/dots.js new file mode 100644 index 0000000..97ebe57 --- /dev/null +++ b/gen/ui/loading/dots.js @@ -0,0 +1,12 @@ +// three chunky dots hop up one after another in a wave, stretching as they fly and squashing as they land +const{sin,cos,PI,max,abs}=Math,T=2*PI +export const frames=20,delay=60 +export default(c,t)=>{ + for(let k=0;k<3;k++){ + const x=54+k*74,u=((t-k*.13)%1+1)%1,h=u<.5?sin(T*u):0,v=u<.5?abs(sin(2*T*u)):0,q=u>.5&&u<.62?sin(PI*(u-.5)/.12):0 + const sx=1-.05*v+.16*q,sy=1+.07*v-.18*q,r=31,y=196-80*h + c.fillStyle='#bbb';c.beginPath();c.ellipse(x,200,24*(1-.45*h)*sx,5*(1-.4*h),0,0,T);c.fill() + c.fillStyle='#fff';c.save();c.translate(x,y);c.scale(sx,sy) + c.lineWidth=7/((sx+sy)/2);c.beginPath();c.arc(0,-r,r,0,T);c.fill();c.stroke();c.restore() + } +} diff --git a/gen/ui/loading/orbit.js b/gen/ui/loading/orbit.js new file mode 100644 index 0000000..37a7b00 --- /dev/null +++ b/gen/ui/loading/orbit.js @@ -0,0 +1,20 @@ +// a little smiling planet while two moons circle it at different speeds along dashed orbit paths +const{sin,cos,PI}=Math,T=2*PI +export const frames=24,delay=70 +const O=[[72,38,-.42,2,12],[102,58,.3,1,15]] +export default(c,t)=>{ + const pt=([rx,ry,a],f)=>[128+rx*cos(f)*cos(a)-ry*sin(f)*sin(a),128+rx*cos(f)*sin(a)+ry*sin(f)*cos(a)] + const orb=(o,a0,a1)=>{for(const[w,s]of[[9,'#111'],[3.5,'#fff']]){c.lineWidth=w;c.strokeStyle=s;c.setLineDash([9,18]);c.beginPath();c.ellipse(128,128,o[0],o[1],o[2],a0,a1);c.stroke()}c.setLineDash([])} + const M=O.map(o=>{const f=o[3]*T*t+o[3];return[...pt(o,f),o[4]*(1+.15*sin(f)),sin(f)]}) + const moon=([x,y,r])=>{c.lineWidth=6;c.strokeStyle='#111';c.beginPath();c.arc(x,y,r,0,T);c.fill();c.stroke();c.fillStyle='#ccc';c.beginPath();c.arc(x+r*.3,y-r*.25,r*.28,0,T);c.fill();c.fillStyle='#fff'} + for(const o of O)orb(o,PI,T) + for(const m of M)if(m[3]<0)moon(m) + const b=3*sin(T*t*2) + c.lineWidth=7;c.strokeStyle='#111';c.beginPath();c.arc(128,128+b,40,0,T);c.fill() + c.save();c.clip();c.fillStyle='#ddd';c.beginPath();c.ellipse(128,152+b,52,10,-.12,0,T);c.fill();c.restore() + c.beginPath();c.arc(128,128+b,40,0,T);c.stroke() + c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.arc(128+d*12,122+b,4.5,0,T),c.fill() + c.lineWidth=4;c.beginPath();c.arc(128,130+b,7,.15*PI,.85*PI);c.stroke();c.fillStyle='#fff' + for(const o of O)orb(o,0,PI) + for(const m of M)if(m[3]>=0)moon(m) +} diff --git a/gen/ui/loading/pulse.js b/gen/ui/loading/pulse.js new file mode 100644 index 0000000..054b91b --- /dev/null +++ b/gen/ui/loading/pulse.js @@ -0,0 +1,12 @@ +// a dot sends out radar ripple rings that grow wider and thinner until they fade away +const{cos,PI}=Math,T=2*PI +export const frames=15,delay=80 +export default(c,t)=>{ + for(let k=0;k<3;k++){ + const p=(t+k/3)%1,r=28+88*p + c.lineWidth=16*(1-p)**.7;c.strokeStyle='#999';c.beginPath();c.arc(128,128,r,0,T);c.stroke() + } + const s=1+.08*cos(T*3*t) + c.lineWidth=7;c.strokeStyle='#111';c.beginPath();c.arc(128,128,30*s,0,T);c.fill();c.stroke() + c.fillStyle='#111';c.beginPath();c.arc(128,128,13*s,0,T);c.fill() +} diff --git a/gen/ui/loading/ring.js b/gen/ui/loading/ring.js new file mode 100644 index 0000000..a5737e4 --- /dev/null +++ b/gen/ui/loading/ring.js @@ -0,0 +1,8 @@ +// material style spinner: one thick arc spins round, stretching long and then shrinking short as it goes +const{PI,min,max,floor}=Math,T=2*PI +export const frames=30,delay=50 +const e=u=>(u=min(1,max(0,u)),u<.5?4*u**3:1-4*(1-u)**3) +export default(c,t)=>{ + const q=t*2%1,G=1.5*PI,o=T*t*1.5+floor(t*2)*G-PI/2,a=o+G*e(q*2-1),b=o+.6+G*e(q*2) + for(const[w,s]of[[42,'#111'],[28,'#fff']])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.arc(128,128,86,a,b),c.stroke() +} diff --git a/gen/ui/loading/skeleton.js b/gen/ui/loading/skeleton.js new file mode 100644 index 0000000..c5920ae --- /dev/null +++ b/gen/ui/loading/skeleton.js @@ -0,0 +1,13 @@ +// skeleton placeholder card: gray avatar, text lines and image box with a soft shimmer band sweeping across them +const T=2*Math.PI +export const frames=20,delay=70 +export default(c,t)=>{ + c.beginPath();c.roundRect(22,22,212,212,22);c.fill();c.stroke() + const x=-70+t*400,g=c.createLinearGradient(x-56,150,x+56,106) + for(const[o,s]of[[0,'#d6d6d6'],[.5,'#f4f4f4'],[1,'#d6d6d6']])g.addColorStop(o,s) + c.fillStyle=g;c.beginPath();c.arc(68,68,24,0,T) + for(const[x,y,w]of[[104,52,104],[104,74,70],[42,188,172],[42,208,116]])c.roundRect(x,y,w,13,6.5) + c.roundRect(42,106,172,70,12);c.fill() + c.fillStyle='#c4c4c4';c.beginPath();c.moveTo(96,166);c.lineTo(122,132);c.lineTo(140,152);c.lineTo(152,140);c.lineTo(172,166);c.fill() + c.beginPath();c.arc(170,128,9,0,T);c.fill() +} diff --git a/gen/ui/maintenance/wrench.js b/gen/ui/maintenance/wrench.js new file mode 100644 index 0000000..89fcb72 --- /dev/null +++ b/gen/ui/maintenance/wrench.js @@ -0,0 +1,26 @@ +// a ring wrench cranks a hex bolt a sixth of a turn and ratchets back for another go, while a big gear turns behind them +const{sin,cos,PI,min,max}=Math,T=2*PI +export const frames=16,delay=80 +const ease=u=>(u=min(1,max(0,u)),u<.5?2*u*u:1-2*(1-u)**2) +const ln=(c,w,f)=>{for(const[l,s]of[[w,'#111'],[w-7,'#fff']])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),f(),c.stroke();c.lineWidth=7;c.strokeStyle='#111'} +const gear=(c,x,y,n,R,th)=>{ + const p=T/n,ri=R-10,ro=R+9 + c.beginPath();for(let k=0;k{ + const p=ease(t/.5),q=ease((t-.6)/.32),a=-.55+(p-q)*PI/3,b=p*PI/3,X=112,Y=160 + gear(c,82,92,10,54,-t*T/5) + if(p>.15&&p<.95)for(const r of[128,110])ln(c,11,()=>c.arc(X,Y,r,a-.42,a-.16)) + c.save();c.translate(X,Y);c.rotate(a) + const sh=()=>{c.beginPath();c.roundRect(20,-15,104,30,15);c.moveTo(38,0);c.arc(0,0,38,0,T)} + c.lineWidth=14;sh();c.stroke();sh();c.fill() + c.lineWidth=4;c.beginPath();c.roundRect(52,-5,52,10,5);c.stroke() + c.lineWidth=6;c.beginPath();c.arc(0,0,27,0,T);c.stroke() + c.restore() + c.lineWidth=6;c.beginPath();for(let k=0;k<6;k++)c.lineTo(X+cos(b+k*PI/3)*21,Y+sin(b+k*PI/3)*21);c.closePath();c.fill();c.stroke() + c.lineWidth=5;c.beginPath();c.arc(X,Y,10,0,T);c.stroke() +} diff --git a/gen/ui/offline/plug.js b/gen/ui/offline/plug.js new file mode 100644 index 0000000..ebc76ea --- /dev/null +++ b/gen/ui/offline/plug.js @@ -0,0 +1,34 @@ +// a plug gets yanked out of the wall socket with a tiny spark, it dangles sadly while its cord wiggles, then slides back in +const{sin,cos,PI,min,max}=Math,T=2*PI +export const frames=24,delay=70 +const ease=u=>(u=min(1,max(0,u)),u<.5?2*u*u:1-2*(1-u)**2) +const ln=(c,w,f)=>{for(const[l,s]of[[w,'#111'],[w-8,'#fff']])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),f(),c.stroke();c.lineWidth=7;c.strokeStyle='#111'} +export default(c,t,i)=>{ + const u=min(1,max(0,(t-.1)/.1)),d=56*(1-(1-u)**2)-56*ease((t-.78)/.16),out=d>4,w=out?max(0,1-(t-.2)/.5):0 + const dy=out?5*sin(T*t*3)*w:0,a=out?.07*sin(T*t*3+1)*w:0,A=2+9*w + ln(c,18,()=>{ + const x0=168+d,y0=128+dy + c.moveTo(x0,y0) + for(let k=1;k<=24;k++){ + const v=k/24,m=1-v,bx=m**3*x0+3*m*m*v*(x0+56)+3*m*v*v*230+v**3*202,by=m**3*y0+3*m*m*v*y0+3*m*v*v*200+v**3*244 + c.lineTo(bx+A*sin(v*12-T*t*4)*v*m*4,by) + } + }) + c.beginPath();c.roundRect(12,14,26,232,8);c.fill();c.stroke() + c.save();c.translate(116+d,128+dy);c.rotate(a) + for(const y of[-18,18])c.beginPath(),c.roundRect(-58,y-5,30,10,3),c.fill(),c.stroke() + c.beginPath();c.roundRect(48,-16,16,32,6);c.fill();c.stroke() + c.beginPath();c.roundRect(-30,-38,80,76,18);c.fill();c.stroke() + c.fillStyle='#111' + if(out){c.lineWidth=5;for(const x of[-6,26])c.beginPath(),c.moveTo(x-6,-12),c.lineTo(x+6,-6),c.moveTo(x-6,-6),c.lineTo(x+6,-12),c.stroke();c.beginPath();c.ellipse(10,14,7,8,0,0,T);c.fill()} + else{for(const x of[-6,26])c.beginPath(),c.arc(x,-8,5.5,0,T),c.fill();c.lineWidth=5;c.beginPath();c.arc(10,6,10,.15*PI,.85*PI);c.stroke()} + c.restore();c.fillStyle='#fff';c.lineWidth=7 + c.beginPath();c.roundRect(32,70,58,116,14);c.fill();c.stroke() + c.fillStyle='#111';for(const y of[110,146])c.beginPath(),c.roundRect(76,y-7,14,14,3),c.fill() + c.fillStyle='#fff' + if(t>.1&&t<.24){ + const s=1-(t-.1)/.14 + for(const a of[-2.3,-1.57,-.84,.84,1.57,2.3])ln(c,11,()=>{c.moveTo(98+cos(a)*16,128+sin(a)*16);c.lineTo(98+cos(a)*(16+18*s),128+sin(a)*(16+18*s))}) + c.lineWidth=5;c.beginPath();for(let k=0;k<8;k++){const r=k%2?5:13*s+4;c.lineTo(98+cos(k*PI/4)*r,128+sin(k*PI/4)*r)};c.closePath();c.fill();c.stroke() + } +} diff --git a/gen/ui/offline/wifi.js b/gen/ui/offline/wifi.js new file mode 100644 index 0000000..9f31653 --- /dev/null +++ b/gen/ui/offline/wifi.js @@ -0,0 +1,20 @@ +// wifi arcs flicker out one by one from the outside in, a big X pops up and shakes, then the arcs flicker back on +const{sin,cos,PI,min,max}=Math,T=2*PI +export const frames=28,delay=70 +const back=u=>(u=min(1,max(0,u)),1+2.7*(u-1)**3+1.7*(u-1)**2) +export default(c,t,i)=>{ + const R=[50,94,138],O=[9,6,3],N=[20,22,24] + for(let k=2;k>=0;k--){ + const o=O[k],n=N[k],on=i=n+2 + if(on)for(const[w,s]of[[32,'#111'],[18,'#fff']])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.arc(128,206,R[k],-PI*.75,-PI*.25),c.stroke() + else{c.setLineDash([1,15]);for(const[w,s]of[[11,'#111'],[4,'#bbb']])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.arc(128,206,R[k],-PI*.75,-PI*.25),c.stroke();c.setLineDash([])} + } + c.lineWidth=7;c.strokeStyle='#111' + c.beginPath();c.arc(128,206,20,0,T);c.fill();c.stroke() + if(i>=12&&i<20){ + const s=i<19?back((i-11)/3):.45,r=i>13&&i<19?(i%2?.14:-.14):0 + c.save();c.translate(128,112);c.rotate(r);c.scale(s,s) + for(const[w,k]of[[40,'#111'],[24,'#fff']])c.lineWidth=w,c.strokeStyle=k,c.beginPath(),c.moveTo(-36,-36),c.lineTo(36,36),c.moveTo(36,-36),c.lineTo(-36,36),c.stroke() + c.restore() + } +} diff --git a/gen/ui/payment/card.js b/gen/ui/payment/card.js new file mode 100644 index 0000000..dc8be50 --- /dev/null +++ b/gen/ui/payment/card.js @@ -0,0 +1,35 @@ +// a credit card pops in and swipes down the side slot of a card terminal, the screen thinks, then a check pops up with a beep +const{sin,cos,PI,min,max,hypot}=Math,T=2*PI +export const frames=24,delay=70 +const cl=u=>min(1,max(0,u)),ease=u=>(u=cl(u),u<.5?2*u*u:1-2*(1-u)**2),back=u=>(u=cl(u),1+3*(u-1)**3+2*(u-1)**2) +const L=hypot(11,11)+hypot(24,26) +export default(c,t)=>{ + const D=(f,a=12,b=5)=>{for(const[w,s]of[[a,'#111'],[b,'#fff']])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),f(),c.stroke();c.lineWidth=7;c.strokeStyle='#111'} + const sw=ease((t-.12)/.2),cy=72+96*sw,cs=back(t/.1)*(1-ease((t-.8)/.08)),ck=cl((t-.42)/.12),v=sin(cl((t-.12)/.2)*PI) + c.beginPath();c.roundRect(112,56,104,180,18);c.fill();c.stroke() + c.fillStyle='#111';c.beginPath();c.roundRect(126,72,76,60,9);c.fill() + c.fillStyle='#fff';c.lineWidth=4 + for(let r=0;r<3;r++)for(let k=0;k<3;k++)c.beginPath(),c.arc(140+k*24,156+r*24,8,0,T),c.fill(),c.stroke() + c.lineWidth=7 + if(ck>0&&t<.94){ + const s=t>.88?1-(t-.88)/.06:1;c.save();c.translate(164,102);c.scale(s,s) + c.strokeStyle='#fff';c.lineWidth=10;c.setLineDash([L*ck,999]);c.beginPath();c.moveTo(-17,0);c.lineTo(-6,11);c.lineTo(18,-15);c.stroke();c.restore() + }else for(let k=0;k<3;k++){ + const j=t>.12&&t<.42?max(0,sin(T*(t*5-k*.25))):0 + c.fillStyle='#fff';c.beginPath();c.arc(146+k*18,104-9*j,5,0,T);c.fill() + } + c.fillStyle='#fff' + if(ck>.5&&t<.66)for(const a of[-1.65,-.95,-.25])D(()=>{c.moveTo(210+cos(a)*20,60+sin(a)*20);c.lineTo(210+cos(a)*32,60+sin(a)*32)},11,4) + if(cs>.01){ + if(v>.2)for(const x of[50,70,90])D(()=>{c.moveTo(x,cy-58-6*v);c.lineTo(x,max(12,cy-58-40*v))},11,4) + c.save();c.translate(70,cy);c.scale(cs,cs) + c.beginPath();c.roundRect(-34,-52,68,104,10);c.fill();c.stroke() + c.fillStyle='#111';c.fillRect(14,-48,12,96) + c.fillStyle='#fff';c.lineWidth=4;c.beginPath();c.roundRect(-24,-34,22,26,5);c.fill();c.stroke() + c.beginPath();c.moveTo(-24,-21);c.lineTo(-2,-21);c.moveTo(-13,-34);c.lineTo(-13,-8);c.stroke() + c.lineWidth=6;for(const y of[12,30])c.beginPath(),c.moveTo(-18,y),c.lineTo(-18,y+10),c.stroke() + c.restore() + } + c.lineWidth=7;c.beginPath();c.roundRect(98,36,22,184,10);c.fill();c.stroke() + c.lineWidth=4;c.beginPath();c.moveTo(109,48);c.lineTo(109,208);c.stroke() +} diff --git a/gen/ui/saved/floppy.js b/gen/ui/saved/floppy.js new file mode 100644 index 0000000..3d319d4 --- /dev/null +++ b/gen/ui/saved/floppy.js @@ -0,0 +1,26 @@ +// a floppy disk squishes as it saves, then a check badge pops onto its corner, the check draws itself and the disk smiles +const{sin,cos,PI,min,max,hypot}=Math,T=2*PI +export const frames=24,delay=70 +const cl=u=>min(1,max(0,u)),bk=u=>(u=cl(u),1+2.7*(u-1)**3+1.7*(u-1)**2) +const P=[[-17,1],[-5,13],[18,-12]],LL=hypot(12,12)+hypot(23,25) +export default(c,t)=>{ + const q=sin(PI*cl(t/.16)),s=t<.86?bk((t-.16)/.14):1-cl((t-.86)/.12)**2,p=cl((t-.26)/.16),b=(t-.42)/.18,hp=t>.36&&t<.92 + c.save();c.translate(116,198);c.scale(1+.07*q,1-.09*q);c.translate(-116,-198) + c.beginPath();c.moveTo(30,46);c.quadraticCurveTo(30,30,46,30);c.lineTo(174,30);c.lineTo(202,58);c.lineTo(202,182);c.quadraticCurveTo(202,198,186,198);c.lineTo(46,198);c.quadraticCurveTo(30,198,30,182);c.closePath();c.fill();c.stroke() + c.fillStyle='#ddd';c.beginPath();c.roundRect(66,30,100,58,[0,0,8,8]);c.fill();c.stroke() + c.fillStyle='#111';c.beginPath();c.roundRect(132,42,18,34,3);c.fill() + c.fillStyle='#fff';c.beginPath();c.roundRect(56,112,120,86,[12,12,0,0]);c.fill();c.stroke() + c.fillStyle='#111';c.lineWidth=5 + if(hp)for(const d of[-1,1])c.beginPath(),c.arc(116+d*20,152,7,PI*1.1,PI*1.9),c.stroke() + else for(const d of[-1,1])c.beginPath(),c.arc(116+d*20,148,6,0,T),c.fill() + c.beginPath();c.arc(116,160,hp?14:9,.15*PI,.85*PI);c.stroke() + c.restore() + c.fillStyle='#fff';c.strokeStyle='#111' + if(b>0&&b<1)for(let k=0;k<8;k++){const a=k*T/8+PI/8,r1=44+12*b,r2=r1+12*(1-b);for(const[w,st]of[[11,'#111'],[4,'#fff']])c.lineWidth=w,c.strokeStyle=st,c.beginPath(),c.moveTo(190+cos(a)*r1,190+sin(a)*r1),c.lineTo(190+cos(a)*r2,190+sin(a)*r2),c.stroke()} + if(s>.01){ + c.strokeStyle='#111';c.save();c.translate(190,190);c.scale(s,s);c.lineWidth=7/s + c.beginPath();c.arc(0,0,36,0,T);c.fill();c.stroke() + if(p>0){c.lineWidth=11;c.setLineDash([LL*p,999]);c.beginPath();for(const[x,y]of P)c.lineTo(x,y);c.stroke()} + c.restore() + } +} diff --git a/gen/ui/search/none.js b/gen/ui/search/none.js new file mode 100644 index 0000000..31013b5 --- /dev/null +++ b/gen/ui/search/none.js @@ -0,0 +1,27 @@ +// binoculars with big worried eyes in the lenses sweep left and right looking for something, find nothing, and break a sweat +const{sin,PI,min,max}=Math,T=2*PI +export const frames=20,delay=90 +const cl=u=>min(1,max(0,u)) +export default(c,t)=>{ + const s=sin(T*t),x=128+27*s,y=130,lk=sin(T*t+.5),S=1.04 + c.save();c.translate(x,y);c.rotate(.1*s);c.scale(S,S);c.lineWidth=7/S + c.beginPath();c.roundRect(-24,-30,48,40,9);c.fill();c.stroke() + c.beginPath();c.arc(0,-40,11,0,T);c.fill();c.stroke() + for(const d of[-1,1]){ + const cx=d*44 + c.beginPath();c.roundRect(cx-17,-66,34,24,7);c.fill();c.stroke() + c.beginPath();c.roundRect(cx-34,-48,68,100,30);c.fill();c.stroke() + c.beginPath();c.arc(cx,18,28,0,T);c.fill();c.stroke() + const px=cx+9*lk,py=20 + c.fillStyle='#111';c.beginPath();c.arc(px,py,13,0,T);c.fill() + c.fillStyle='#fff';c.beginPath();c.arc(px-4,py-5,4.5,0,T);c.fill() + c.lineWidth=5/S;c.beginPath();c.moveTo(cx-18,-16-d*3);c.lineTo(cx+18,-16+d*3);c.stroke();c.lineWidth=7/S + } + c.restore() + const g=cl((t-.12)/.1)*(1-cl((t-.74)/.1)),dy=50*cl((t-.22)/.52)**1.4 + if(g>0){ + c.save();c.translate(x+64+4*s,y-62+dy*.8);c.scale(g,g);c.lineWidth=6 + c.beginPath();c.moveTo(0,-20);c.bezierCurveTo(4,-8,14,0,14,9);c.arc(0,9,14,0,PI);c.bezierCurveTo(-14,0,-4,-8,0,-20);c.fill();c.stroke() + c.restore() + } +} diff --git a/gen/ui/sent/plane.js b/gen/ui/sent/plane.js new file mode 100644 index 0000000..1dc758a --- /dev/null +++ b/gen/ui/sent/plane.js @@ -0,0 +1,23 @@ +// a paper plane swoops in, flies a loop-the-loop and zooms off the other side, leaving a dashed trail behind it +const{sin,cos,PI,atan2,min,max,hypot}=Math,T=2*PI +export const frames=24,delay=60 +const sm=u=>(u=min(1,max(0,u)),u*u*(3-2*u)) +const P=s=>{const w=sm((s-.28)/.38);return[-52+360*s-56*sin(T*w),176-56*(1-cos(T*w))-22*sin(PI*min(1,max(0,s)))]} +const Q=[];{let l=0,q=P(-1);for(let s=-1;s<=2.001;s+=.004){const p=P(s);l+=hypot(p[0]-q[0],p[1]-q[1]);Q.push([s,...p,l]);q=p}} +const L=.46 +const trail=(c,h)=>{ + const D=[];let cur=null + for(const[s,x,y,l]of Q){if(sh-.06){cur=null;continue}if(l%30<17){if(!cur)D.push(cur=[]);cur.push([x,y,s])}else cur=null} + for(const k of[0,1])for(const d of D){const f=(d[0][2]-h+L)/L;c.lineWidth=k?max(0,9*f-1):4+9*f;c.strokeStyle=k?'#fff':'#111';c.beginPath();for(const[x,y]of d)c.lineTo(x,y);c.stroke()} +} +const plane=(c,h)=>{ + const[x,y]=P(h),[a,b]=P(h-.01),[e,f]=P(h+.01) + c.save();c.translate(x,y);c.rotate(atan2(f-b,e-a));c.scale(1.4,1.4);c.strokeStyle='#111';c.lineWidth=5 + c.fillStyle='#ddd';c.beginPath();c.moveTo(32,0);c.lineTo(-14,4);c.lineTo(-22,18);c.closePath();c.fill();c.stroke() + c.fillStyle='#fff';c.beginPath();c.moveTo(32,0);c.lineTo(-30,-20);c.lineTo(-14,4);c.closePath();c.fill();c.stroke() + c.restore() +} +export default(c,t)=>{ + for(const h of[t,t+1])trail(c,h) + for(const h of[t,t+1])plane(c,h) +} diff --git a/gen/ui/signal/none.js b/gen/ui/signal/none.js new file mode 100644 index 0000000..9253b72 --- /dev/null +++ b/gen/ui/signal/none.js @@ -0,0 +1,21 @@ +// a phone with no signal, its empty bars light up one by one as it searches and then blink, while its little face looks round sadly +const{sin,PI}=Math,T=2*PI +export const frames=16,delay=90 +export default(c,t,i)=>{ + c.beginPath();c.roundRect(58,10,140,236,28);c.fill();c.stroke() + c.lineWidth=5;c.beginPath();c.roundRect(72,38,112,176,12);c.stroke() + c.lineWidth=6;c.beginPath();c.moveTo(112,24);c.lineTo(144,24);c.stroke() + c.lineWidth=5;c.beginPath();c.arc(128,230,7,0,T);c.stroke() + const scan=i<8?i>>1:-1,dim=i>=8&&i%4>1 + for(let k=0;k<4;k++){ + const h=18+16*k,x=82+k*24 + c.fillStyle=k==scan?'#bbb':'#fff';c.strokeStyle=dim?'#bbb':'#111';c.lineWidth=5 + c.beginPath();c.roundRect(x,126-h,18,h,4);c.fill();c.stroke() + } + c.fillStyle='#111';c.strokeStyle='#111' + const e=i<8?(scan-1.5)*3:0 + for(const d of[-1,1])c.beginPath(),c.arc(128+d*16+e,160,6,0,T),c.fill() + c.lineWidth=5;c.beginPath();c.arc(128+e*.5,192,12,PI*1.15,PI*1.85);c.stroke() + c.lineWidth=4;c.beginPath();c.moveTo(100+e,151);c.lineTo(112+e,145);c.moveTo(156+e,151);c.lineTo(144+e,145);c.stroke() + c.fillStyle='#fff';c.lineWidth=4;c.beginPath();c.moveTo(164,140+(i%8));c.bezierCurveTo(158,152+(i%8),160,160+(i%8),166,160+(i%8));c.bezierCurveTo(172,160+(i%8),174,152+(i%8),164,140+(i%8));c.fill();c.stroke() +} diff --git a/gen/ui/success/confetti.js b/gen/ui/success/confetti.js new file mode 100644 index 0000000..dcb3cdf --- /dev/null +++ b/gen/ui/success/confetti.js @@ -0,0 +1,35 @@ +// a party popper shakes, then bursts with a bang and confetti pieces and streamers flutter down, spinning as they fall +const{sin,cos,PI,min,max,exp}=Math,T=2*PI +export const frames=28,delay=70 +let z=11;const R=()=>(z=z*16807%2147483647)/2147483647 +const C=[...Array(14)].map((_,k)=>[-PI/4+(R()-.5)*1.7,90+R()*120,k%4,R()<.3?'#bbb':'#fff',R()*T,1+R()*2,R()*T,.7+R()*.6]) +const t0=.12 +export default(c,t)=>{ + const s=t-t0,mx=110,my=150 + if(s>0){ + const sc=min(1,(1-t)/.07),fall=u=>320*max(0,u-.12)**1.5 + for(const[a,d,k,f,r0,sp,ph,fz]of C){ + const e=1-exp(-11*s),x=mx+cos(a)*d*e+14*sin(T*s*2*fz+ph)*min(1,s*4),y=my+sin(a)*d*e+fall(s)*fz + c.save();c.translate(x,y);c.rotate(r0+s*sp*T);c.scale(cos(T*s*3*fz+ph)*sc,sc);c.beginPath() + if(k==0)c.rect(-11,-7,22,14);else if(k==1)c.arc(0,0,9,0,T);else if(k==2)c.moveTo(0,-11),c.lineTo(10,7),c.lineTo(-10,7),c.closePath();else c.ellipse(0,0,13,6,0,0,T) + c.restore();c.lineWidth=5;c.fillStyle=f;c.fill();c.stroke() + } + c.fillStyle='#fff' + for(const[a,d,o]of[[-1.15,120,0],[-.5,130,2]]){ + const e=1-exp(-9*s);for(const[w,st]of[[10,'#111'],[4,'#fff']]){c.lineWidth=w*sc;c.strokeStyle=st;c.beginPath() + for(let u=0;u<=1;u+=.05){const L=d*e*(.35+.65*u),n=7*sin(u*12+s*20+o)*min(1,s*6);c.lineTo(mx+cos(a)*L-sin(a)*n,my+sin(a)*L+cos(a)*n+fall(s)*(1.1-.4*u)+40*s*u*u)}c.stroke()} + } + c.strokeStyle='#111' + if(s<.12){const b=s/.12;for(let k=0;k<7;k++){const a=-PI/4+(k-3)*.42,r1=24+40*b,r2=r1+20*(1-b);for(const[w,st]of[[12,'#111'],[5,'#fff']])c.lineWidth=w,c.strokeStyle=st,c.beginPath(),c.moveTo(mx+cos(a)*r1,my+sin(a)*r1),c.lineTo(mx+cos(a)*r2,my+sin(a)*r2),c.stroke()}} + } + const sh=t.9?.05*sin(T*t*20)*(t-.9)/.1:0,rc=s>0&&s<.15?sin(PI*s/.15):0 + c.strokeStyle='#111';c.lineWidth=7 + c.save();c.translate(42-8*rc,222+8*rc);c.rotate(PI/4+sh) + const cone=()=>{c.beginPath();c.moveTo(-9,6);c.lineTo(-38,-92);c.lineTo(38,-92);c.lineTo(9,6);c.quadraticCurveTo(0,11,-9,6)} + cone();c.fill();c.save();cone();c.clip();c.fillStyle='#111' + for(const v of[-70,-36])c.beginPath(),c.moveTo(-40,v),c.lineTo(40,v-20),c.lineTo(40,v-6),c.lineTo(-40,v+14),c.fill() + c.restore();cone();c.stroke() + c.beginPath();c.ellipse(0,-92,38,12,0,0,T);c.fill();c.stroke() + if(s<0||s>.5){c.fillStyle='#111';c.beginPath();c.ellipse(0,-92,27,6,0,0,T);c.fill()} + c.restore() +} diff --git a/gen/ui/success/stamp.js b/gen/ui/success/stamp.js new file mode 100644 index 0000000..993b7d6 --- /dev/null +++ b/gen/ui/success/stamp.js @@ -0,0 +1,24 @@ +// a rubber stamp winds up, slams down on a sheet of paper and bounces back up leaving a check mark imprint, then the sheet slides away for a fresh one +const{sin,cos,PI,min,max}=Math,T=2*PI +export const frames=28,delay=70 +const cl=u=>min(1,max(0,u)),io=u=>(u=cl(u),u<.5?2*u*u:1-2*(1-u)**2),bk=u=>(u=cl(u),1+2.4*(u-1)**3+1.4*(u-1)**2) +const paper=(c,x)=>{c.beginPath();c.moveTo(62+x,162);c.lineTo(194+x,162);c.lineTo(224+x,230);c.lineTo(32+x,230);c.closePath();c.fill();c.stroke()} +const ink=(c,x)=>{c.save();c.translate(128+x,196);c.scale(1,.42);c.lineWidth=10;c.beginPath();c.arc(0,0,44,0,T);c.stroke();c.lineWidth=14;c.beginPath();c.moveTo(-20,0);c.lineTo(-6,16);c.lineTo(22,-16);c.stroke();c.restore()} +export default(c,t)=>{ + const sl=-264*io((t-.74)/.22),q=sin(PI*cl((t-.31)/.11)) + const y=t<.24?124-10*io((t-.06)/.18):t<.31?114+82*cl((t-.24)/.07)**2:t<.42?196:196-72*bk((t-.42)/.16) + paper(c,sl);paper(c,sl+264) + const h=(y-124)/72 + if(t<.31||t>.42&&t<.74||t>.96){c.fillStyle='#ccc';c.beginPath();c.ellipse(128,196,30+22*h,9+4*h,0,0,T);c.fill();c.fillStyle='#fff'} + if(t>.31)ink(c,sl) + if(t>.6&&t<.74){const p=(t-.6)/.14;c.lineWidth=5;for(const[x,yy,r]of[[52,146,12],[206,154,10]]){const s=sin(PI*p)*r;c.beginPath();c.moveTo(x,yy-s*2);c.quadraticCurveTo(x,yy,x+s*2,yy);c.quadraticCurveTo(x,yy,x,yy+s*2);c.quadraticCurveTo(x,yy,x-s*2,yy);c.quadraticCurveTo(x,yy,x,yy-s*2);c.fill();c.stroke()}} + if(q>.01)for(const d of[-1,1])for(const a of[-.5,0,.5]){const r1=72+14*q,r2=r1+16*q;for(const[w,s]of[[11,'#111'],[4,'#fff']])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.moveTo(128+d*r1*cos(a),188-r1*.5*sin(a+.4)),c.lineTo(128+d*r2*cos(a),188-r2*.5*sin(a+.4)),c.stroke()} + c.strokeStyle='#111';c.lineWidth=7 + c.save();c.translate(128,y);c.scale(1+.08*q,1-.12*q) + c.fillStyle='#888';c.beginPath();c.roundRect(-48,-12,96,12,3);c.fill();c.stroke();c.fillStyle='#fff' + c.beginPath();c.roundRect(-58,-38,116,28,9);c.fill();c.stroke() + c.beginPath();c.roundRect(-14,-62,28,26,4);c.fill();c.stroke() + c.beginPath();c.ellipse(0,-82,31,19,0,0,T);c.fill();c.stroke() + c.lineWidth=5;c.beginPath();c.arc(0,-82,14,PI*1.15,PI*1.5);c.stroke() + c.restore() +} diff --git a/gen/ui/sync/arrows.js b/gen/ui/sync/arrows.js new file mode 100644 index 0000000..1c00c99 --- /dev/null +++ b/gen/ui/sync/arrows.js @@ -0,0 +1,16 @@ +// two curved arrows chase each other round and round a little face that watches them go +const{sin,cos,PI}=Math,T=2*PI +export const frames=16,delay=60 +export default(c,t)=>{ + const a0=PI*t+.2*sin(T*t),R=80,S=2.15 + for(const[w,k]of[[34,'#111'],[20,'#fff']])for(const o of[0,PI]){ + const a=a0+o,e=a+S,px=128+R*cos(e),py=128+R*sin(e),tx=-sin(e),ty=cos(e),nx=cos(e),ny=sin(e) + c.lineWidth=w;c.strokeStyle=k;c.beginPath();c.arc(128,128,R,a,e);c.stroke() + c.fillStyle=k;c.lineWidth=w>30?14:0;c.beginPath();c.moveTo(px+nx*28,py+ny*28);c.lineTo(px+tx*34,py+ty*34);c.lineTo(px-nx*28,py-ny*28);c.closePath();c.fill();if(w>30)c.stroke() + } + c.lineWidth=7;c.strokeStyle='#111';c.fillStyle='#fff' + c.beginPath();c.arc(128,128,38,0,T);c.fill();c.stroke() + const ex=4*sin(T*t*2) + c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.arc(128+d*13+ex,121,6,0,T),c.fill() + c.lineWidth=5;c.beginPath();c.arc(128+ex*.5,132,9,PI*.15,PI*.85);c.stroke() +} diff --git a/gen/ui/thanks/card.js b/gen/ui/thanks/card.js new file mode 100644 index 0000000..71293ab --- /dev/null +++ b/gen/ui/thanks/card.js @@ -0,0 +1,28 @@ +// a folded thank-you card swings open, a smiling heart pops out and floats up, bursts into lines, and the card closes again +const{sin,cos,PI,min,max}=Math,T=2*PI +export const frames=24,delay=70 +const cl=u=>min(1,max(0,u)),ease=u=>(u=cl(u),u<.5?2*u*u:1-2*(1-u)**2),back=u=>(u=cl(u),1+3*(u-1)**3+2*(u-1)**2) +const heart=(c,r)=>{c.beginPath();c.moveTo(0,r);c.bezierCurveTo(-r*1.7,-r*.1,-r*.9,-r*1.45,0,-r*.6);c.bezierCurveTo(r*.9,-r*1.45,r*1.7,-r*.1,0,r);c.closePath()} +export default(c,t)=>{ + const D=(f,a=12,b=5)=>{for(const[w,s]of[[a,'#111'],[b,'#fff']])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),f(),c.stroke();c.lineWidth=7;c.strokeStyle='#111'} + const o=ease((t-.04)/.2)-ease((t-.84)/.14),th=o*PI,hx=76+52*o,Y=102,H=132,W=104 + c.beginPath();c.roundRect(hx,Y,W,H,6);c.fill();c.stroke() + c.lineWidth=8;c.strokeStyle='#bbb';for(const[y,l]of[[Y+76,56],[Y+94,70],[Y+112,44]])c.beginPath(),c.moveTo(hx+16,y),c.lineTo(hx+16+l,y),c.stroke() + c.strokeStyle='#111';c.lineWidth=7 + const k=cos(th),lift=.1*sin(th) + c.save();c.transform(k,-lift,0,1,hx,0);c.beginPath();c.roundRect(0,Y,W,H,6);c.fill();c.lineWidth=7;c.stroke() + if(k>0){ + c.save();c.translate(W/2,Y+54);c.lineWidth=6;heart(c,22);c.stroke();c.restore() + c.lineWidth=7;c.strokeStyle='#bbb';for(const[y,l]of[[Y+96,48],[Y+111,32]])c.beginPath(),c.moveTo(W/2-l/2,y),c.lineTo(W/2+l/2,y),c.stroke() + }else{c.translate(W/2,Y+H-30);c.scale(-1,1);c.lineWidth=5;c.strokeStyle='#bbb';heart(c,10);c.stroke();c.beginPath();c.moveTo(-36,26);c.lineTo(36,26);c.stroke()} + c.restore() + const P=u=>[128+14*sin(u*T),170-108*u],u=min((t-.26)/.54,.96),b=cl((t-.78)/.08),[x,y]=P(u) + if(u>0&&b<1){ + const s=back((t-.26)/.08)*(1-b) + c.save();c.translate(x,y);c.rotate(.16*sin(u*T+1));c.scale(s,s);c.lineWidth=7/max(s,.2) + heart(c,32);c.fill();c.stroke() + c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.arc(d*11,-4,4.5,0,T),c.fill() + c.lineWidth=4.5/max(s,.2);c.beginPath();c.arc(0,4,7,.15*PI,.85*PI);c.stroke();c.restore() + } + if(b>0&&b<1)for(let i=0;i<8;i++){const a=i*T/8,r1=22+26*b,r2=r1+14*(1-b);D(()=>{c.moveTo(x+cos(a)*r1,y+sin(a)*r1);c.lineTo(x+cos(a)*r2,y+sin(a)*r2)},11,4)} +} diff --git a/gen/ui/timeout/stopwatch.js b/gen/ui/timeout/stopwatch.js new file mode 100644 index 0000000..27a01d0 --- /dev/null +++ b/gen/ui/timeout/stopwatch.js @@ -0,0 +1,19 @@ +// a stopwatch hand ticks round to zero as the time left shrinks away, then it rings and shakes, and winds back for another go +const{sin,cos,PI,min,max}=Math,T=2*PI +export const frames=24,delay=70 +const ease=u=>(u=min(1,max(0,u)),u<.5?2*u*u:1-2*(1-u)**2) +const ln=(c,w,f)=>{for(const[l,s]of[[w,'#111'],[w-7,'#fff']])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),f(),c.stroke();c.lineWidth=7;c.strokeStyle='#111'} +export default(c,t,i)=>{ + const X=128,Y=146,ring=t>=.5&&t<.8,f=T*(.25+.75*(min(1,t/.5)-ease((t-.8)/.18)))-PI/2 + if(ring)for(const d of[-1,1])for(const a of[-.5,0,.5])ln(c,11,()=>{const b=-PI/2+d*(.72+a*.5),r=i%2?4:0;c.moveTo(X+cos(b)*(106+r),Y+sin(b)*(106+r));c.lineTo(X+cos(b)*(122+r),Y+sin(b)*(122+r))}) + c.translate(X,Y);if(ring)c.rotate(i%2?.09:-.09),c.translate(i%2?2:-2,0);c.translate(-X,-Y) + c.save();c.translate(X,Y);c.rotate(PI/4);c.beginPath();c.roundRect(-9,-100,18,22,5);c.fill();c.stroke();c.restore() + c.beginPath();c.roundRect(X-10,48,20,24,4);c.fill();c.stroke() + c.beginPath();c.roundRect(X-28,ring&&i%2?34:28,56,20,8);c.fill();c.stroke() + c.beginPath();c.arc(X,Y,86,0,T);c.fill();c.stroke() + c.fillStyle='#ddd';c.beginPath();c.moveTo(X,Y);c.arc(X,Y,64,f,PI*1.5);c.closePath();c.fill();c.fillStyle='#fff' + c.lineWidth=5;c.beginPath();c.arc(X,Y,72,0,T);c.stroke() + for(let k=0;k<12;k++){const a=k*T/12,r=k%3?62:56;c.lineWidth=k%3?4:6;c.beginPath();c.moveTo(X+cos(a)*r,Y+sin(a)*r);c.lineTo(X+cos(a)*68,Y+sin(a)*68);c.stroke()} + c.lineWidth=8;c.beginPath();c.moveTo(X-cos(f)*12,Y-sin(f)*12);c.lineTo(X+cos(f)*60,Y+sin(f)*60);c.stroke() + c.fillStyle='#111';c.beginPath();c.arc(X,Y,9,0,T);c.fill() +} diff --git a/gen/ui/typing/bubble.js b/gen/ui/typing/bubble.js new file mode 100644 index 0000000..0273cbb --- /dev/null +++ b/gen/ui/typing/bubble.js @@ -0,0 +1,13 @@ +// chat speech bubble gently bobbing while three typing dots pulse up and darken one after another +const{sin,PI,max}=Math,T=2*PI +export const frames=18,delay=70 +export default(c,t)=>{ + c.translate(0,3*sin(T*t)) + const B=()=>{c.beginPath();c.roundRect(22,56,212,128,44)},K=()=>{c.beginPath();c.moveTo(58,168);c.quadraticCurveTo(58,204,30,218);c.quadraticCurveTo(84,214,100,176);c.closePath()} + c.lineWidth=14;B();c.stroke();K();c.stroke();B();c.fill();K();c.fill() + for(let k=0;k<3;k++){ + const u=((t-k*.16)%1+1)%1,p=u<.42?sin(PI*u/.42):0 + c.fillStyle=p>.6?'#111':p>.25?'#555':'#999' + c.beginPath();c.arc(84+k*44,120-12*p,14+4*p,0,T);c.fill() + } +} diff --git a/gen/ui/upload/cloud.js b/gen/ui/upload/cloud.js new file mode 100644 index 0000000..0f9a0fa --- /dev/null +++ b/gen/ui/upload/cloud.js @@ -0,0 +1,25 @@ +// arrows pop up, crouch and shoot one after another into a happy cloud, which puffs up each time one zips inside +const{sin,PI,min,max}=Math,T=2*PI +export const frames=24,delay=60 +const back=u=>(u=min(1,max(0,u)),1+2.7*(u-1)**3+1.7*(u-1)**2) +const ln=(c,w,f)=>{for(const[l,s]of[[w,'#111'],[w-7,'#fff']])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),f(),c.stroke();c.lineWidth=7;c.strokeStyle='#111'} +export default(c,t)=>{ + const u=t*2%1,s=1.1*back(u/.14),q=max(0,(u-.3)/.2),k=u>.14&&u<.3?sin(PI*(u-.14)/.16):0,y=196+6*k-110*q*q,pf=u>.42&&u<.82?sin(PI*(u-.42)/.4):0 + if(q<1){ + if(q>0)for(const x of[-30,0,30])ln(c,11,()=>{c.moveTo(128+x,y+(x?16:58));c.lineTo(128+x,y+(x?16:58)+56*q)}) + c.save();c.translate(128,y+40);c.scale(s*(1+.1*k),s*(1-.14*k));c.translate(0,-40) + c.beginPath();c.moveTo(0,-40);c.lineTo(36,-2);c.lineTo(15,-2);c.lineTo(15,38);c.lineTo(-15,38);c.lineTo(-15,-2);c.lineTo(-36,-2);c.closePath();c.fill();c.stroke() + c.restore() + } + if(pf>.3)for(const d of[-1,1])for(const[y,q]of[[66,-10],[100,0]])ln(c,11,()=>{c.moveTo(128+d*(102+6*pf),y);c.lineTo(128+d*(116+6*pf),y+q)}) + c.translate(128,110);c.scale(1+.08*pf,1+.06*pf);c.translate(-128,-110) + const P=[[80,96,38],[128,72,50],[178,94,40]],base=()=>c.roundRect(42,92,172,56,28) + c.lineWidth=14;for(const[x,yy,r]of P)c.beginPath(),c.arc(x,yy,r,0,T),c.stroke() + c.beginPath();base();c.stroke() + for(const[x,yy,r]of P)c.beginPath(),c.arc(x,yy,r,0,T),c.fill() + c.beginPath();base();c.fill() + c.lineWidth=6 + if(pf>.3)for(const x of[106,150])c.beginPath(),c.arc(x,114,8,PI*1.15,PI*1.85),c.stroke() + else{c.fillStyle='#111';for(const x of[106,150])c.beginPath(),c.arc(x,110,6,0,T),c.fill()} + c.beginPath();c.arc(128,120,10,PI*.15,PI*.85);c.stroke() +} diff --git a/gen/ui/verified/badge.js b/gen/ui/verified/badge.js new file mode 100644 index 0000000..4dcc865 --- /dev/null +++ b/gen/ui/verified/badge.js @@ -0,0 +1,25 @@ +// scalloped seal badge with a big check, gently wobbling, a shine sweeps across it and little sparkles twinkle +const{sin,cos,PI,abs,min,max}=Math,T=2*PI +export const frames=20,delay=80 +const cl=u=>min(1,max(0,u)) +const star=(c,x,y,r)=>{c.beginPath();for(let k=0;k<8;k++){const a=k*PI/4,q=k%2?r*.42:r;c.lineTo(x+cos(a)*q,y+sin(a)*q)}c.closePath();c.fill();c.stroke()} +export default(c,t)=>{ + const a=.1*sin(T*t),sh=cl((t-.12)/.3) + for(const d of[-1,1]){ + c.save();c.translate(128+d*26,150);c.rotate(d*.32+a*.5) + c.beginPath();c.moveTo(-20,0);c.lineTo(-20,82);c.lineTo(0,68);c.lineTo(20,82);c.lineTo(20,0);c.closePath();c.fill();c.stroke() + c.restore() + } + c.translate(128,110);c.rotate(a) + const seal=()=>{c.beginPath();for(let k=0;k<=320;k++){const th=k*T/320,r=80+11*(1-(1-abs(cos(8*th)))**2);c.lineTo(cos(th)*r,sin(th)*r)}c.closePath()} + seal();c.fill();c.stroke() + c.fillStyle='#111';c.beginPath();c.arc(0,0,62,0,T);c.fill() + if(sh>0&&sh<1){ + c.save();c.beginPath();c.arc(0,0,62,0,T);c.clip();c.rotate(.6);c.fillStyle='#666' + const x=-110+220*sh;c.fillRect(x-14,-80,22,160);c.fillRect(x+16,-80,8,160);c.restore() + } + c.strokeStyle='#fff';c.lineWidth=4;c.beginPath();c.arc(0,0,52,0,T);c.stroke() + c.lineWidth=20;c.beginPath();c.moveTo(-26,2);c.lineTo(-8,20);c.lineTo(28,-20);c.stroke() + c.setTransform(1,0,0,1,0,0);c.strokeStyle='#111';c.fillStyle='#fff';c.lineWidth=5 + for(const[x,y,o,r]of[[214,40,.42,22],[40,60,.56,18],[222,150,.7,16]]){const g=cl((t-o)/.22),s=sin(g*PI);if(s>0)star(c,x,y,r*s)} +} diff --git a/gen/ui/warning/sign.js b/gen/ui/warning/sign.js new file mode 100644 index 0000000..446a608 --- /dev/null +++ b/gen/ui/warning/sign.js @@ -0,0 +1,14 @@ +// warning triangle with a big "!" wobbling on its corner, the "!" jiggling along, alert lines flashing on both sides +const{sin,cos,PI}=Math,T=2*PI +export const frames=16,delay=70 +export default(c,t,i)=>{ + const D=(f,a=12,b=5)=>{for(const[w,s]of[[a,'#111'],[b,'#fff']])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),f(),c.stroke();c.lineWidth=7;c.strokeStyle='#111'} + const a=.1*sin(2*T*t),b=.14*sin(2*T*t-1.2),fl=i%4<2 + if(fl)for(const d of[-1,1])for(const k of[0,1,2]){const g=-PI/2+d*(.62+k*.3),r=96+(k==1?8:0);D(()=>{c.moveTo(128+cos(g)*r,130+sin(g)*r);c.lineTo(128+cos(g)*(r+20),130+sin(g)*(r+20))},12,5)} + c.translate(128,214);c.rotate(a);c.translate(-128,-214) + const tri=()=>{c.beginPath();c.moveTo(128,44);c.lineTo(222,206);c.lineTo(34,206);c.closePath()} + tri();c.lineWidth=34;c.stroke();c.lineWidth=20;c.strokeStyle='#fff';c.stroke();c.fill() + c.strokeStyle='#111';c.lineWidth=5;c.beginPath();c.moveTo(128,62);c.lineTo(207,198);c.lineTo(49,198);c.closePath();c.stroke() + c.translate(128,188);c.rotate(b);c.lineWidth=24;c.beginPath();c.moveTo(0,-90);c.lineTo(0,-46);c.stroke() + c.fillStyle='#111';c.beginPath();c.arc(0,-12,13,0,T);c.fill() +} diff --git a/gen/ui/wishlist/empty.js b/gen/ui/wishlist/empty.js new file mode 100644 index 0000000..21f4fe9 --- /dev/null +++ b/gen/ui/wishlist/empty.js @@ -0,0 +1,11 @@ +// an empty wishlist heart drawn as a chunky dashed outline, gently breathing in and out +const{sin,cos,PI,hypot}=Math,T=2*PI +export const frames=16,delay=80 +const P=[...Array(161)].map((_,k)=>{const s=k/160*T;return[16*sin(s)**3,-(13*cos(s)-5*cos(2*s)-2*cos(3*s)-cos(4*s))]}) +const L=P.reduce((a,p,k)=>k?a+hypot(p[0]-P[k-1][0],p[1]-P[k-1][1]):0,0),D=L/12 +export default(c,t)=>{ + const s=6.1*(1+.06*sin(t*T)) + c.translate(128,114);c.scale(s,s*(1-.02*sin(t*T))) + c.setLineDash([D*.46,D*.54]);c.lineDashOffset=D*.73 + for(const[w,k]of[[22,'#111'],[10,'#fff']]){c.lineWidth=w/s;c.strokeStyle=k;c.beginPath();for(const[x,y]of P)c.lineTo(x,y);c.stroke()} +} diff --git a/gen/uianime/403/batsu.js b/gen/uianime/403/batsu.js new file mode 100644 index 0000000..968a3b9 --- /dev/null +++ b/gen/uianime/403/batsu.js @@ -0,0 +1,47 @@ +// stern silver-haired student council girl slamming her white sleeves into a big batsu X, frowning as red impact lines pop +const{sin,cos,PI,max,min}=Math,T=2*PI +export const frames=12,delay=90 +const SKIN='#ffe3d1',HAIR='#e9ecef',HD='#adb5bd',EYE='#5c7cfa',ED='#364fc7',BZ='#364fc7',SL='#fff',TIE='#f03e3e',BL='#ffa8a8',RD='#ff6b6b',Z=.84 +const O=[0,0,0,0,0,0,0,0,.35,.75,.95,.55] +const eye=(c,L,x,y,d)=>{ + c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill() + c.save();c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.clip();c.fillStyle=EYE;c.fill();c.fillStyle=ED;c.beginPath();c.ellipse(x,y-8,13,10,0,0,T);c.fill();c.restore() + L(2.5);c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.stroke() + c.fillStyle='#111';c.beginPath();c.ellipse(x,y+4,5,6.5,0,0,T);c.fill() + c.fillStyle='#fff';c.beginPath();c.arc(x-4,y-1,3.5,0,T);c.fill() + c.fillStyle=SKIN;c.beginPath();c.moveTo(x-d*20,y-26);c.lineTo(x-d*20,y-6);c.lineTo(x+d*20,y-16);c.lineTo(x+d*20,y-26);c.fill() + L(6);c.beginPath();c.moveTo(x-d*18,y-6);c.lineTo(x+d*17,y-15);c.stroke() +} +export default(c,t,i)=>{ + const o=O[i],L=v=>c.lineWidth=v/Z,sh=i>1&&i<8?.04*sin(T*(i-2)/3):0 + const head=f=>{c.save();c.translate(128,104);c.rotate(sh);c.scale(Z,Z);c.translate(-128,-128);f();c.restore()} + head(()=>{L(6);c.fillStyle=HD;c.beginPath();c.moveTo(128,34);c.bezierCurveTo(200,34,214,96,206,150);c.lineTo(214,330);c.lineTo(42,330);c.lineTo(50,150);c.bezierCurveTo(42,96,56,34,128,34);c.fill();c.stroke()}) + c.save();c.translate(128,104);c.scale(Z,Z);c.translate(-128,-128) + L(6);c.fillStyle=BZ;c.beginPath();c.moveTo(100,190);c.quadraticCurveTo(56,196,44,330);c.lineTo(212,330);c.quadraticCurveTo(200,196,156,190);c.closePath();c.fill();c.stroke() + c.fillStyle='#fff';c.beginPath();c.moveTo(104,188);c.lineTo(128,250);c.lineTo(152,188);c.closePath();c.fill();c.stroke() + c.fillStyle=TIE;L(4.5);c.beginPath();c.moveTo(120,204);c.lineTo(136,204);c.lineTo(132,212);c.lineTo(138,240);c.lineTo(128,250);c.lineTo(118,240);c.lineTo(124,212);c.closePath();c.fill();c.stroke() + c.fillStyle=SKIN;L(5);c.beginPath();c.moveTo(116,166);c.lineTo(116,194);c.lineTo(128,204);c.lineTo(140,194);c.lineTo(140,166);c.fill();c.beginPath();c.moveTo(116,166);c.lineTo(116,190);c.moveTo(140,166);c.lineTo(140,190);c.stroke() + c.restore() + head(()=>{ + L(6);c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + eye(c,L,103,142,-1);eye(c,L,153,142,1) + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*42,163,11,5,0,0,T),c.fill() + L(4);c.beginPath();c.moveTo(118,174);c.quadraticCurveTo(128,166,138,174);c.stroke() + L(6);c.fillStyle=HAIR;c.beginPath();c.moveTo(64,204);c.lineTo(66,150) + c.bezierCurveTo(52,74,88,36,128,36);c.bezierCurveTo(168,36,204,74,190,150);c.lineTo(192,204);c.lineTo(174,196);c.lineTo(176,120) + c.lineTo(176,108);c.lineTo(166,114);c.lineTo(156,100);c.lineTo(146,112);c.lineTo(136,98);c.lineTo(128,112);c.lineTo(120,98);c.lineTo(110,112);c.lineTo(100,100);c.lineTo(90,114);c.lineTo(80,108) + c.lineTo(80,120);c.lineTo(82,196);c.closePath();c.fill();c.stroke() + c.strokeStyle=HD;L(5);for(const[a,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,56,PI*a,PI*e),c.stroke() + c.strokeStyle='#111';c.fillStyle='#212529';L(5);c.beginPath();c.moveTo(70,92);c.bezierCurveTo(70,40,186,40,186,92);c.lineTo(180,84);c.bezierCurveTo(170,52,86,52,76,84);c.closePath();c.fill();c.stroke() + }) + for(const d of[1,-1]){ + const ex=128-d*58,ey=226,a=(d>0?-.58:PI+.58)-d*1.05*o,fx=ex+130*cos(a),fy=ey+130*sin(a) + for(const[w,s]of[[32,'#111'],[21,SL]])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.moveTo(ex-d*10,ey+40),c.lineTo(ex,ey),c.lineTo(fx-cos(a)*16,fy-sin(a)*16),c.stroke() + c.strokeStyle='#111';c.save();c.translate(fx,fy);c.rotate(a) + c.lineWidth=5;c.fillStyle=BZ;c.beginPath();c.roundRect(-24,-14,10,28,4);c.fill();c.stroke() + c.fillStyle=SKIN;c.beginPath();c.roundRect(-14,-15,30,30,12);c.fill();c.stroke() + c.lineWidth=2.5;c.beginPath();for(const k of[-6,1,8])c.moveTo(14,k*d),c.lineTo(6,k*d);c.stroke() + c.restore() + } + if(i<3)for(const[w,s]of[[9,'#111'],[4,RD]]){c.lineWidth=w;c.strokeStyle=s;const r=i*8;for(const a of[-2.6,-2.1,-1,-.5,.5,2.6]){const x=128+cos(a)*(84+r),y=176+sin(a)*(64+r);c.beginPath();c.moveTo(x,y);c.lineTo(x+cos(a)*16,y+sin(a)*16);c.stroke()}} +} diff --git a/gen/uianime/404/flashlight.js b/gen/uianime/404/flashlight.js new file mode 100644 index 0000000..78649ed --- /dev/null +++ b/gen/uianime/404/flashlight.js @@ -0,0 +1,50 @@ +// nervous orange-haired girl in pajamas standing in a dark room, sweeping her flashlight beam back and forth and lighting up a "404" on the wall +const{sin,cos,PI,max,min}=Math,T=2*PI +export const frames=16,delay=90 +const SKIN='#ffe3d1',HAIR='#ff922b',HD='#e8590c',HL='#ffe8cc',EYE='#4dabf7',PJ='#a5d8ff',PD='#74c0fc',DARK='#232946',DIM='#2f3866',BEAM='#fff3bf',DIG='#ff8787',FL='#ff6b6b',BL='#ffa8a8',SW='#a5d8ff',Z=.74 +const eye=(c,x,y,d,lx)=>{ + c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill() + c.fillStyle=EYE;c.beginPath();c.arc(x+lx,y+2,7.5,0,T);c.fill();c.fillStyle='#111';c.beginPath();c.arc(x+lx,y+2,3.5,0,T);c.fill() + c.fillStyle='#fff';c.beginPath();c.arc(x+lx-2.5,y-1,2,0,T);c.fill() + c.lineWidth=3.5;c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.stroke() + c.lineWidth=7;c.beginPath();c.moveTo(x-16,y-8);c.quadraticCurveTo(x,y-22,x+16,y-8);c.moveTo(x+d*15,y-9);c.lineTo(x+d*21,y-14);c.stroke() +} +const four=(c,x,y)=>{c.moveTo(x+7,y-24);c.lineTo(x-15,y+6);c.lineTo(x+17,y+6);c.moveTo(x+7,y-24);c.lineTo(x+7,y+24)} +const digits=(c,col,w)=>{for(const[l,s]of[[w,'#111'],[w-12,col]]){c.lineWidth=l;c.strokeStyle=s;c.beginPath();four(c,96,64);four(c,204,64);c.moveTo(164,64);c.ellipse(150,64,14,23,0,0,T);c.stroke()}c.strokeStyle='#111'} +export default(c,t)=>{ + const a=-1.62+.6*sin(T*t),hx=150,hy=196,lx=hx+40*cos(a),ly=hy+40*sin(a),ex=4*cos(a+.6) + c.save();c.beginPath();c.roundRect(8,8,240,240,40);c.fillStyle=DARK;c.fill();c.clip() + c.globalAlpha=.6;digits(c,DIM,24);c.globalAlpha=1 + c.save();c.beginPath();c.moveTo(lx,ly);c.arc(lx,ly,300,a-.34,a+.34);c.closePath();c.fillStyle=BEAM;c.fill();c.clip() + digits(c,DIG,24);c.strokeStyle='#fff';c.lineWidth=4;c.beginPath();c.arc(150,64,9,PI*1.1,PI*1.4);c.stroke();c.strokeStyle='#111' + c.restore() + c.save();c.translate(82,262);c.scale(Z,Z);c.translate(-128,-256) + c.lineWidth=7;c.fillStyle=HD;c.beginPath();c.moveTo(128,36);c.bezierCurveTo(200,36,212,100,204,170);c.quadraticCurveTo(200,190,180,186);c.lineTo(76,186);c.quadraticCurveTo(56,190,52,170);c.bezierCurveTo(44,100,56,36,128,36);c.fill();c.stroke() + c.fillStyle=PJ;c.beginPath();c.moveTo(100,190);c.quadraticCurveTo(60,198,52,262);c.lineTo(204,262);c.quadraticCurveTo(196,198,156,190);c.closePath();c.fill();c.stroke() + c.fillStyle='#fff';for(const d of[-1,1])c.beginPath(),c.moveTo(128,212),c.lineTo(128+d*30,190),c.lineTo(128+d*34,212),c.closePath(),c.fill(),c.stroke() + c.fillStyle=PD;c.lineWidth=5;for(const y of[226,248])c.beginPath(),c.arc(128,y,5,0,T),c.fill(),c.stroke() + c.fillStyle=SKIN;c.lineWidth=7;c.beginPath();c.moveTo(116,168);c.lineTo(116,194);c.lineTo(128,210);c.lineTo(140,194);c.lineTo(140,168);c.fill();c.beginPath();c.moveTo(116,168);c.lineTo(116,192);c.moveTo(140,168);c.lineTo(140,192);c.stroke() + c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + eye(c,103,142,-1,ex);eye(c,153,142,1,ex) + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,165,12,6,0,0,T),c.fill() + c.lineWidth=4;c.beginPath();c.moveTo(116,174);for(let k=1;k<=6;k++)c.lineTo(116+k*4,174+(k%2?-3:3));c.stroke() + c.lineWidth=7;c.fillStyle=HAIR;c.beginPath();c.moveTo(62,176) + c.bezierCurveTo(44,74,88,36,128,36);c.bezierCurveTo(168,36,212,74,194,176);c.quadraticCurveTo(184,182,180,172) + c.quadraticCurveTo(186,126,176,104);c.quadraticCurveTo(168,106,164,116);c.quadraticCurveTo(158,98,146,92);c.quadraticCurveTo(140,106,130,110) + c.quadraticCurveTo(124,96,114,94);c.quadraticCurveTo(108,106,100,110);c.quadraticCurveTo(94,98,86,100);c.quadraticCurveTo(80,108,78,108) + c.quadraticCurveTo(70,130,76,172);c.quadraticCurveTo(70,182,62,176);c.closePath();c.fill();c.stroke() + c.strokeStyle=HL;c.lineWidth=6;for(const[s,e]of[[1.22,1.34],[1.42,1.5],[1.62,1.74]])c.beginPath(),c.arc(128,104,56,PI*s,PI*e),c.stroke() + c.strokeStyle='#111';c.lineWidth=5;c.beginPath();c.moveTo(88,122);c.lineTo(112,116);c.moveTo(144,116);c.lineTo(168,122);c.stroke() + c.fillStyle='#ffd43b';c.lineWidth=5;c.beginPath();c.roundRect(60,80,28,11,5);c.fill();c.stroke() + c.fillStyle=SW;c.lineWidth=5;c.beginPath();c.moveTo(196,96);c.quadraticCurveTo(208,112,196,120);c.quadraticCurveTo(184,112,196,96);c.fill();c.stroke() + c.restore() + for(const[w,s]of[[24,'#111'],[14,PJ]])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.moveTo(108,238),c.lineTo(128,222),c.lineTo(hx,hy+4),c.stroke() + c.strokeStyle='#111';c.save();c.translate(hx,hy);c.rotate(a) + c.lineWidth=5;c.fillStyle=FL;c.beginPath();c.roundRect(-14,-7,40,14,4);c.fill();c.stroke() + c.fillStyle='#ced4da';c.beginPath();c.moveTo(24,-8);c.lineTo(40,-13);c.lineTo(40,13);c.lineTo(24,8);c.closePath();c.fill();c.stroke() + c.fillStyle='#fff9db';c.beginPath();c.ellipse(40,0,4,13,0,0,T);c.fill();c.stroke() + c.restore() + c.lineWidth=5;c.fillStyle=SKIN;c.beginPath();c.ellipse(hx,hy,10,11,0,0,T);c.fill();c.stroke() + c.restore() + c.lineWidth=7;c.beginPath();c.roundRect(8,8,240,240,40);c.stroke() +} diff --git a/gen/uianime/404/lost.js b/gen/uianime/404/lost.js new file mode 100644 index 0000000..b7de9bf --- /dev/null +++ b/gen/uianime/404/lost.js @@ -0,0 +1,69 @@ +// lost explorer girl with honey pigtails and a safari hat holding her map upside down, looking left and right in confusion while question marks pop up +const{sin,PI,min,max}=Math,T=2*PI +export const frames=12,delay=120 +const SKIN='#ffe3d1',HAIR='#ffd43b',HD='#f08c00',HL='#fff9db',EYE='#a9744f',ED='#6f4518',HAT='#e9cf96',HB='#a9744f',SH='#8ce99a',SD='#40c057',MAP='#fff3bf',MP='#ffe699',MT='#91a7ff',PINE='#51cf66',BL='#ffa8a8',SW='#a5d8ff',QC=['#ff8787','#74c0fc','#b197fc'],Z=.84 +const eye=(c,x,y,d,lx)=>{ + c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill() + c.save();c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.clip();c.beginPath();c.ellipse(x+lx,y+2,11.5,15,0,0,T);c.fillStyle=EYE;c.fill();c.lineWidth=2.5;c.stroke() + c.fillStyle=ED;c.beginPath();c.ellipse(x+lx,y-8,13,10,0,0,T);c.fill() + c.fillStyle='#111';c.beginPath();c.ellipse(x+lx,y+3,5.5,7.5,0,0,T);c.fill() + c.fillStyle='#fff';c.beginPath();c.arc(x+lx-4,y-5,4.5,0,T);c.fill();c.beginPath();c.arc(x+lx+5,y+8,2,0,T);c.fill();c.restore() + c.lineWidth=7;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke() +} +const qm=(c,x,y,s,col,a)=>{ + c.save();c.translate(x,y);c.rotate(a);c.scale(s,s) + for(const[w,st]of[[14,'#111'],[6.5,col]])c.lineWidth=w,c.strokeStyle=st,c.beginPath(),c.moveTo(-9,-10),c.bezierCurveTo(-9,-24,11,-24,11,-11),c.bezierCurveTo(11,-2,0,-2,0,8),c.stroke() + c.strokeStyle='#111';c.fillStyle=col;c.lineWidth=4;c.beginPath();c.arc(0,20,5,0,T);c.fill();c.stroke();c.restore() +} +export default(c,t)=>{ + // s saturates so she holds each glance, and held frames come out identical + const s=max(-1,min(1,1.8*sin(T*t))),lx=5*s,fx=3*s + for(const[x,y,d,k]of[[26,70,-1,0],[230,70,1,1],[58,22,-1,2],[198,22,1,2]]){const sc=2*(d*s-.5);if(sc>0)qm(c,x,y,sc*(y<40?.75:1.15),QC[k],d*.25)} + c.save();c.translate(128,12);c.scale(Z,Z);c.translate(-128,-20) + const head=f=>{c.save();c.translate(128,180);c.rotate(.06*s);c.translate(-128,-180);f();c.restore()} + head(()=>{ + c.lineWidth=7;c.fillStyle=HD;c.beginPath();c.moveTo(128,36);c.bezierCurveTo(196,36,206,96,198,150);c.lineTo(58,150);c.bezierCurveTo(50,96,60,36,128,36);c.fill();c.stroke() + for(const d of[-1,1]){ + c.save();c.translate(128+d*62,126);c.scale(d,1);c.rotate(-.15-.12*d*s) + c.fillStyle=HAIR;c.beginPath();c.moveTo(0,-12);c.bezierCurveTo(40,-16,52,40,32,74);c.quadraticCurveTo(26,60,14,68);c.bezierCurveTo(22,40,12,12,0,12);c.closePath();c.fill();c.stroke() + c.strokeStyle=HL;c.lineWidth=5;c.beginPath();c.moveTo(14,-4);c.bezierCurveTo(30,4,36,26,32,44);c.stroke();c.strokeStyle='#111' + c.fillStyle='#ff8787';c.lineWidth=6;c.beginPath();c.arc(2,0,10,0,T);c.fill();c.stroke() + c.restore() + } + }) + c.lineWidth=7;c.fillStyle=SH;c.beginPath();c.moveTo(100,190);c.quadraticCurveTo(62,198,54,250);c.lineTo(202,250);c.quadraticCurveTo(194,198,156,190);c.closePath();c.fill();c.stroke() + c.fillStyle=SKIN;c.beginPath();c.moveTo(116,168);c.lineTo(116,194);c.lineTo(128,206);c.lineTo(140,194);c.lineTo(140,168);c.fill();c.lineWidth=6;c.beginPath();c.moveTo(116,168);c.lineTo(116,192);c.moveTo(140,168);c.lineTo(140,192);c.stroke() + head(()=>{ + c.lineWidth=7;c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + eye(c,103+fx,140,-1,lx);eye(c,153+fx,140,1,lx) + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+fx+d*42,162,12,6,0,0,T),c.fill() + c.lineWidth=3;for(const d of[-1,1])for(const k of[-5,0,5])c.beginPath(),c.moveTo(128+fx+d*42+k-2,165),c.lineTo(128+fx+d*42+k+2,159),c.stroke() + c.lineWidth=4;c.beginPath();c.moveTo(117+fx,171);c.quadraticCurveTo(120.5+fx,165,124+fx,171);c.quadraticCurveTo(127.5+fx,177,131+fx,171);c.quadraticCurveTo(134.5+fx,165,138+fx,171);c.stroke() + c.lineWidth=7;c.fillStyle=HAIR;c.beginPath();c.moveTo(70,146) + c.bezierCurveTo(54,74,88,36,128,36);c.bezierCurveTo(168,36,202,74,186,146) + c.quadraticCurveTo(184,116,176,102);c.quadraticCurveTo(168,104,162,112);c.quadraticCurveTo(156,98,146,92);c.quadraticCurveTo(140,104,132,110) + c.quadraticCurveTo(126,96,116,92);c.quadraticCurveTo(110,104,102,110);c.quadraticCurveTo(96,98,88,98);c.quadraticCurveTo(82,108,80,104) + c.quadraticCurveTo(72,122,70,146);c.closePath();c.fill();c.stroke() + c.strokeStyle=HL;c.lineWidth=6;for(const[a,e]of[[1.1,1.18],[1.82,1.9]])c.beginPath(),c.arc(128,110,54,PI*a,PI*e),c.stroke() + c.strokeStyle='#111';c.lineWidth=5;c.beginPath();c.moveTo(90+fx,113);c.lineTo(112+fx,119);c.moveTo(144+fx,112);c.lineTo(166+fx,103);c.stroke() + c.lineWidth=7;c.fillStyle=HAT;c.beginPath();c.ellipse(128,70,84,15,0,0,T);c.fill();c.stroke() + c.beginPath();c.moveTo(76,72);c.bezierCurveTo(74,10,182,10,180,72);c.quadraticCurveTo(128,82,76,72);c.fill();c.stroke() + c.fillStyle=HB;c.lineWidth=6;c.beginPath();c.moveTo(77,58);c.quadraticCurveTo(128,68,179,58);c.lineTo(180,70);c.quadraticCurveTo(128,80,76,70);c.closePath();c.fill();c.stroke() + c.strokeStyle='#fff';c.lineWidth=6;c.beginPath();c.arc(128,64,40,PI*1.25,PI*1.42);c.stroke();c.strokeStyle='#111' + c.fillStyle=SW;c.lineWidth=5;const sy=106;c.beginPath();c.moveTo(198,sy-14);c.quadraticCurveTo(208,sy,198,sy+7);c.quadraticCurveTo(188,sy,198,sy-14);c.fill();c.stroke() + }) + c.restore() + c.save();c.translate(128,202) + for(const[k,a,b]of[[0,-102,-34],[1,-34,34],[2,34,102]]){const u=k%2?-4:0,v=k%2?0:-4;c.fillStyle=k%2?MP:MAP;c.beginPath();c.moveTo(a,-42-u);c.lineTo(b,-42-v);c.lineTo(b,42+v);c.lineTo(a,42+u);c.closePath();c.fill();c.lineWidth=6;c.stroke()} + c.save();c.rotate(PI) + c.strokeStyle='#ff6b6b';c.lineWidth=4.5;c.setLineDash([7,7]);c.beginPath();c.moveTo(-34,26);c.bezierCurveTo(0,30,20,-6,58,-4);c.stroke();c.setLineDash([]);c.strokeStyle='#111' + c.lineWidth=4.5;for(const[x,h,w]of[[-70,34,24],[-44,26,20]]){c.fillStyle=MT;c.beginPath();c.moveTo(x-w,26);c.lineTo(x,26-h);c.lineTo(x+w,26);c.closePath();c.fill();c.stroke();c.fillStyle='#fff';c.beginPath();c.moveTo(x-w*.35,26-h*.65);c.lineTo(x,26-h);c.lineTo(x+w*.35,26-h*.65);c.lineTo(x,26-h*.55);c.closePath();c.fill();c.stroke()} + c.strokeStyle=HB;c.lineWidth=5;c.beginPath();c.moveTo(-8,30);c.lineTo(-8,22);c.stroke();c.strokeStyle='#111';c.lineWidth=4.5;c.fillStyle=PINE + for(const[y,w]of[[22,15],[10,12],[-2,9]])c.beginPath(),c.moveTo(-8-w,y),c.lineTo(-8,y-16),c.lineTo(-8+w,y),c.closePath(),c.fill(),c.stroke() + c.fillStyle='#fff';c.beginPath();c.rect(22,-24,24,18);c.fill();c.stroke();c.fillStyle='#ff8787';c.beginPath();c.moveTo(17,-22);c.lineTo(34,-38);c.lineTo(51,-22);c.closePath();c.fill();c.stroke() + for(const[w,st]of[[12,'#111'],[5.5,'#fa5252']])c.lineWidth=w,c.strokeStyle=st,c.beginPath(),c.moveTo(60,-14),c.lineTo(78,4),c.moveTo(78,-14),c.lineTo(60,4),c.stroke() + c.restore() + c.strokeStyle='#111';c.lineWidth=5;c.fillStyle=SKIN + for(const d of[-1,1]){c.beginPath();c.ellipse(d*96,-34,11,14,0,0,T);c.fill();c.stroke();c.beginPath();c.ellipse(d*87,-41,6,9,d*.6,0,T);c.fill();c.stroke()} + c.restore() +} diff --git a/gen/uianime/404/peek.js b/gen/uianime/404/peek.js new file mode 100644 index 0000000..f437338 --- /dev/null +++ b/gen/uianime/404/peek.js @@ -0,0 +1,42 @@ +// shy girl with long pink hair peeking over the top of a big "404" sign, eyes darting left and right with a nervous sweatdrop, then ducking back down +const{sin,PI}=Math,T=2*PI +export const frames=16,delay=90 +const SKIN='#ffe3d1',HAIR='#f783ac',HD='#e64980',HL='#ffdeeb',EYE='#51cf66',ED='#2b8a3e',WOOD='#e8b07a',WD='#c47f45',PANEL='#fff9db',DIG='#ff8787',BL='#ffa8a8',SW='#a5d8ff',CLIP='#ffd43b' +const ease=x=>x<=0?0:x>=1?1:x*x*(3-2*x) +const eye=(c,x,y,d,lx)=>{ + c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill() + c.save();c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.clip();c.beginPath();c.ellipse(x+lx,y+2,11.5,15,0,0,T);c.fillStyle=EYE;c.fill();c.lineWidth=2.5;c.stroke() + c.fillStyle=ED;c.beginPath();c.ellipse(x+lx,y-8,13,10,0,0,T);c.fill() + c.fillStyle='#111';c.beginPath();c.ellipse(x+lx,y+3,5.5,7.5,0,0,T);c.fill() + c.fillStyle='#fff';c.beginPath();c.arc(x+lx-4,y-5,4.5,0,T);c.fill();c.beginPath();c.arc(x+lx+5,y+8,2,0,T);c.fill();c.restore() + c.lineWidth=6;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke() +} +export default(c,t,i)=>{ + const up=ease((t-.06)/.16)-ease((t-.78)/.14),lx=t>.24&&t<.48?-5:t>=.48&&t<.76?5:0,bk=i==9 + c.save();c.beginPath();c.rect(0,0,256,200);c.clip();c.translate(128,117+40*(1-up));c.rotate(.06*up);c.scale(.88,.88);c.translate(-128,-140) + c.lineWidth=6;c.fillStyle=HD;c.beginPath();c.moveTo(128,36);c.bezierCurveTo(200,36,214,110,210,250);c.lineTo(46,250);c.bezierCurveTo(42,110,56,36,128,36);c.fill();c.stroke() + c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + if(bk){c.lineWidth=5;for(const x of[103,153])c.beginPath(),c.moveTo(x-14,142),c.quadraticCurveTo(x,149,x+14,142),c.stroke()} + else{eye(c,103,140,-1,lx);eye(c,153,140,1,lx)} + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*42,163,12,6,0,0,T),c.fill() + c.lineWidth=2.5;for(const d of[-1,1])for(const k of[-5,0,5])c.beginPath(),c.moveTo(128+d*42+k-2,166),c.lineTo(128+d*42+k+2,160),c.stroke() + c.lineWidth=6;c.fillStyle=HAIR;c.beginPath();c.moveTo(60,200);c.bezierCurveTo(44,76,86,36,128,36);c.bezierCurveTo(170,36,212,76,196,200) + c.lineTo(180,200);c.quadraticCurveTo(184,140,176,106);c.quadraticCurveTo(168,106,162,114);c.quadraticCurveTo(156,98,146,92);c.quadraticCurveTo(140,104,132,110) + c.quadraticCurveTo(126,96,116,92);c.quadraticCurveTo(110,104,102,110);c.quadraticCurveTo(96,98,88,98);c.quadraticCurveTo(84,106,80,106) + c.quadraticCurveTo(72,140,76,200);c.closePath();c.fill();c.stroke() + c.beginPath();c.moveTo(124,38);c.quadraticCurveTo(118,8,152,12);c.quadraticCurveTo(128,20,136,38);c.fill();c.stroke() + c.strokeStyle=HL;c.lineWidth=5;for(const[a,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,56,PI*a,PI*e),c.stroke() + c.strokeStyle='#111';c.lineWidth=4;c.beginPath();c.moveTo(90,118);c.lineTo(112,112);c.moveTo(144,112);c.lineTo(166,118);c.stroke() + c.fillStyle=CLIP;c.lineWidth=4;for(const y of[80,96])c.beginPath(),c.roundRect(170,y-4,22,8,4),c.fill(),c.stroke() + if(up>.9){c.fillStyle=SW;c.lineWidth=4.5;c.beginPath();c.moveTo(68,104);c.quadraticCurveTo(78,118,68,124);c.quadraticCurveTo(58,118,68,104);c.fill();c.stroke()} + c.restore() + c.lineWidth=6;c.fillStyle=WOOD;c.beginPath();c.roundRect(12,134,232,114,18);c.fill();c.stroke() + c.fillStyle=PANEL;c.lineWidth=5;c.beginPath();c.roundRect(28,149,200,84,10);c.fill();c.stroke() + c.strokeStyle=WD;c.lineWidth=4;c.beginPath();c.moveTo(34,142);c.lineTo(90,142);c.moveTo(166,241);c.lineTo(224,241);c.stroke() + for(const[w,s]of[[26,'#111'],[13,DIG]]){c.lineWidth=w;c.strokeStyle=s;c.beginPath() + for(const x of[68,188])c.moveTo(x+9,166),c.lineTo(x-18,202),c.lineTo(x+21,202),c.moveTo(x+9,166),c.lineTo(x+9,219) + c.moveTo(145,192);c.ellipse(128,192,17,26,0,0,T);c.stroke()} + c.strokeStyle='#fff';c.lineWidth=4;c.beginPath();c.arc(128,192,16,PI*1.1,PI*1.35);c.moveTo(70,172);c.lineTo(63,182);c.moveTo(190,172);c.lineTo(183,182);c.stroke() + c.strokeStyle='#111';c.fillStyle=SKIN;c.lineWidth=4.5 + for(const x of[64,192])for(const k of[-1.5,-.5,.5,1.5])c.beginPath(),c.ellipse(x+k*9,136,5,9,0,0,T),c.fill(),c.stroke() +} diff --git a/gen/uianime/404/shrug.js b/gen/uianime/404/shrug.js new file mode 100644 index 0000000..18e761a --- /dev/null +++ b/gen/uianime/404/shrug.js @@ -0,0 +1,54 @@ +// teal bob girl in a yellow hoodie giving a big "dunno" shrug: shoulders up, palms out, head tilted with half-lidded eyes while a question mark pops over her +const{sin,PI,min}=Math,T=2*PI +export const frames=12,delay=100 +const SKIN='#ffe3d1',HAIR='#3bc9db',HD='#1098ad',HL='#c5f6fa',EYE='#9775fa',ED='#6741d9',HO='#ffd43b',HOD='#f59f00',BL='#ffa8a8',Q='#ff8787',Z=.9 +const ease=x=>x<=0?0:x>=1?1:x*x*(3-2*x) +const eye=(c,x,y,d,lx)=>{ + c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill() + c.save();c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.clip();c.beginPath();c.ellipse(x+lx,y+2,11.5,15,0,0,T);c.fillStyle=EYE;c.fill();c.lineWidth=2.5;c.stroke() + c.fillStyle='#111';c.beginPath();c.ellipse(x+lx,y+4,5.5,7.5,0,0,T);c.fill() + c.fillStyle='#fff';c.beginPath();c.arc(x+lx-4,y+1,4,0,T);c.fill();c.beginPath();c.arc(x+lx+5,y+10,2,0,T);c.fill() + c.fillStyle=SKIN;c.fillRect(x-16,y-20,32,18);c.restore() + c.lineWidth=6;c.beginPath();c.moveTo(x-17,y-2);c.lineTo(x+16,y-2);c.lineTo(x+d*16+(d>0?4:-4),y-7);c.stroke() + c.lineWidth=2.5;c.beginPath();c.moveTo(x-8,y+19);c.lineTo(x+8,y+19);c.stroke() +} +export default(c,t)=>{ + const u=ease((t-.04)/.14)-ease((t-.66)/.14),sh=-8*u,lx=5*u-1 + if(u>.05){const sc=min(1,u*1.2)*(1+.25*ease(1-(t-.18)/.1)*(t>.18));c.save();c.translate(212,44);c.rotate(.2);c.scale(sc,sc) + for(const[w,s]of[[15,'#111'],[7,Q]])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.moveTo(-11,-12),c.bezierCurveTo(-11,-29,13,-29,13,-13),c.bezierCurveTo(13,-2,0,-2,0,10),c.stroke() + c.strokeStyle='#111';c.fillStyle=Q;c.lineWidth=4.5;c.beginPath();c.arc(0,24,6,0,T);c.fill();c.stroke();c.restore()} + c.translate(128,250);c.scale(Z,Z);c.translate(-128,-252) + const head=f=>{c.save();c.translate(128,190+sh*.6);c.rotate(-.12*u);c.translate(-128,-190);f();c.restore()} + head(()=>{c.lineWidth=6;c.fillStyle=HD;c.beginPath();c.moveTo(128,36);c.bezierCurveTo(200,36,214,100,204,160);c.quadraticCurveTo(200,178,184,176);c.lineTo(72,176);c.quadraticCurveTo(56,178,52,160);c.bezierCurveTo(42,100,56,36,128,36);c.fill();c.stroke()}) + c.lineWidth=6;c.fillStyle=HOD;c.beginPath();c.ellipse(128,196+sh,58,20,0,0,T);c.fill();c.stroke() + c.fillStyle=HO;c.beginPath();c.moveTo(98,190+sh);c.quadraticCurveTo(58,196+sh,50,252);c.lineTo(206,252);c.quadraticCurveTo(198,196+sh,158,190+sh);c.closePath();c.fill();c.stroke() + c.fillStyle=SKIN;c.beginPath();c.moveTo(116,168);c.lineTo(116,192+sh);c.quadraticCurveTo(128,204+sh,140,192+sh);c.lineTo(140,168);c.fill();c.lineWidth=5;c.beginPath();c.moveTo(116,168);c.lineTo(116,190+sh);c.moveTo(140,168);c.lineTo(140,190+sh);c.stroke() + c.lineWidth=5;c.beginPath();c.moveTo(104,192+sh);c.quadraticCurveTo(128,214+sh,152,192+sh);c.stroke() + c.lineWidth=4;c.fillStyle='#fff';for(const d of[-1,1])c.beginPath(),c.moveTo(128+d*14,206+sh),c.lineTo(128+d*16,232+sh),c.stroke(),c.beginPath(),c.arc(128+d*16,236+sh,4,0,T),c.fill(),c.stroke() + c.strokeStyle=HOD;c.lineWidth=4;c.beginPath();c.moveTo(96,240);c.lineTo(160,240);c.stroke();c.strokeStyle='#111' + head(()=>{ + c.lineWidth=6;c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + eye(c,103,142,-1,lx);eye(c,153,142,1,lx) + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*42,164,12,6,0,0,T),c.fill() + c.lineWidth=2.5;for(const d of[-1,1])for(const k of[-5,0,5])c.beginPath(),c.moveTo(128+d*42+k-2,167),c.lineTo(128+d*42+k+2,161),c.stroke() + c.lineWidth=3.5;c.beginPath();c.moveTo(120,171);c.quadraticCurveTo(126,168,129,171);c.quadraticCurveTo(132,174,137,169);c.stroke() + c.lineWidth=6;c.fillStyle=HAIR;c.beginPath();c.moveTo(60,170) + c.bezierCurveTo(42,74,88,36,128,36);c.bezierCurveTo(168,36,214,74,196,170);c.quadraticCurveTo(186,176,178,166) + c.quadraticCurveTo(186,124,178,104);c.lineTo(170,112);c.quadraticCurveTo(164,98,154,92);c.quadraticCurveTo(150,104,142,110) + c.quadraticCurveTo(136,96,124,90);c.quadraticCurveTo(120,102,112,110);c.quadraticCurveTo(106,98,96,96);c.quadraticCurveTo(92,104,86,110) + c.quadraticCurveTo(80,104,78,102);c.quadraticCurveTo(70,124,78,166);c.quadraticCurveTo(70,176,60,170);c.closePath();c.fill();c.stroke() + c.strokeStyle=HL;c.lineWidth=5;for(const[a,b]of[[1.22,1.34],[1.42,1.5],[1.62,1.74]])c.beginPath(),c.arc(128,104,56,PI*a,PI*b),c.stroke() + c.strokeStyle='#111';c.lineWidth=4.5;for(const d of[-1,1])c.beginPath(),c.arc(128+d*25,124-6*u,13,PI*1.2,PI*1.8),c.stroke() + c.fillStyle='#ff6b6b';c.lineWidth=4;c.beginPath();c.moveTo(70,92);c.lineTo(92,82);c.lineTo(88,96);c.closePath();c.fill();c.stroke() + }) + for(const d of[-1,1]){ + const sx=128+d*52,sy=214+sh,ex=128+d*90,ey=236+sh*.5,hx=128+d*(98+10*u),hy=222-50*u + for(const[w,s]of[[30,'#111'],[19,HO]])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.moveTo(sx,sy),c.lineTo(ex,ey),c.lineTo(hx,hy+12),c.stroke() + c.strokeStyle='#111';c.lineWidth=5;c.fillStyle=SKIN + c.save();c.translate(hx,hy);c.rotate(d*(.45+.55*u)) + const P=[[0,0,13,12,0],[-d*13,-4,4.5,9,-d*.8],...[-9,-3,3,9].map(k=>[k,-15,3.8,9,k*.02])] + for(const[l,st]of[[10,'#111'],[0,SKIN]])for(const[x,y,a,b2,r]of P){c.beginPath();c.ellipse(x,y,a,b2,r,0,T);if(l)c.lineWidth=l,c.stroke();else c.fill()} + c.lineWidth=2.5;c.beginPath();for(const k of[-6,0,6])c.moveTo(k,-20),c.lineTo(k,-9);c.stroke() + c.restore() + } +} diff --git a/gen/uianime/500/fix.js b/gen/uianime/500/fix.js new file mode 100644 index 0000000..7dc4c81 --- /dev/null +++ b/gen/uianime/500/fix.js @@ -0,0 +1,64 @@ +// red-haired mechanic girl in a bandana whacking a broken 500 server with a big wrench, sparks flying off it +const{sin,cos,PI,max,min}=Math,T=2*PI +export const frames=10,delay=80 +const SKIN='#ffe3d1',HAIR='#ff8787',HD='#e03131',EYE='#fab005',ED='#e67700',OV='#4dabf7',TS='#ffe066',BN='#ffd43b',BL='#ffa8a8',SV='#ced4da',SD='#868e96',RD='#fa5252',SP='#ffd43b',Z=.72 +const S=[0,0,.2,.45,.7,.9,1,1,.55,.15] +const eye=(c,L,x,y,d)=>{ + c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill() + c.save();c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.clip();c.fillStyle=EYE;c.fill();c.fillStyle=ED;c.beginPath();c.ellipse(x,y-8,13,10,0,0,T);c.fill();c.restore() + L(2.5);c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.stroke() + c.fillStyle='#111';c.beginPath();c.ellipse(x,y+3,5.5,7.5,0,0,T);c.fill() + c.fillStyle='#fff';c.beginPath();c.arc(x-4,y-5,4.5,0,T);c.fill();c.beginPath();c.arc(x+5,y+8,2,0,T);c.fill() + c.fillStyle=SKIN;c.beginPath();c.moveTo(x-d*20,y-26);c.lineTo(x-d*20,y-5);c.lineTo(x+d*20,y-19);c.lineTo(x+d*20,y-26);c.fill() + L(6);c.beginPath();c.moveTo(x-d*18,y-5);c.lineTo(x+d*17,y-17);c.stroke() +} +const dig=(c,x,y,n)=>{c.beginPath();if(n)c.ellipse(x,y,7,11,0,0,T);else c.moveTo(x+7,y-11),c.lineTo(x-6,y-11),c.lineTo(x-7,y-1),c.quadraticCurveTo(x+8,y-5,x+7,y+4),c.quadraticCurveTo(x+6,y+12,x-7,y+9);c.stroke()} +export default(c,t,i)=>{ + const s=S[i],hit=i<2,L=v=>c.lineWidth=v/Z,hx=100-4*s,hy=140-66*s,a=-2.55+.85*s,wx=hx+58*cos(a),wy=hy+58*sin(a) + const head=f=>{c.save();c.translate(168,108);c.scale(Z,Z);c.translate(-128,-128);f();c.restore()} + head(()=>{ + c.save();c.translate(186,74);c.rotate(.5+.12*s) + L(6);c.fillStyle=HAIR;c.beginPath();c.moveTo(-8,0);c.bezierCurveTo(40,-8,62,50,50,112);c.quadraticCurveTo(44,132,28,138);c.quadraticCurveTo(38,96,20,56);c.quadraticCurveTo(10,28,-8,14);c.closePath();c.fill();c.stroke() + c.strokeStyle=HD;L(3);c.beginPath();c.moveTo(12,12);c.bezierCurveTo(30,30,40,70,38,108);c.stroke();c.strokeStyle='#111';c.restore() + L(6);c.fillStyle=HD;c.beginPath();c.moveTo(128,34);c.bezierCurveTo(196,34,206,96,198,160);c.lineTo(58,160);c.bezierCurveTo(50,96,60,34,128,34);c.fill();c.stroke() + c.fillStyle=TS;c.beginPath();c.moveTo(100,190);c.quadraticCurveTo(58,196,46,330);c.lineTo(210,330);c.quadraticCurveTo(198,196,156,190);c.closePath();c.fill();c.stroke() + c.fillStyle=OV;c.beginPath();c.moveTo(84,236);c.lineTo(172,236);c.lineTo(180,330);c.lineTo(76,330);c.closePath();c.fill();c.stroke() + for(const d of[-1,1])c.beginPath(),c.moveTo(128+d*42,240),c.lineTo(128+d*52,196),c.lineTo(128+d*38,194),c.lineTo(128+d*28,240),c.fill(),c.stroke() + c.fillStyle=BN;for(const d of[-1,1])c.beginPath(),c.arc(128+d*36,246,6,0,T),c.fill(),c.stroke() + c.fillStyle=SKIN;c.beginPath();c.moveTo(116,166);c.lineTo(116,194);c.lineTo(128,204);c.lineTo(140,194);c.lineTo(140,166);c.fill();L(5);c.beginPath();c.moveTo(116,166);c.lineTo(116,192);c.moveTo(140,166);c.lineTo(140,192);c.stroke() + L(6);c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + eye(c,L,103,142,-1);eye(c,L,153,142,1) + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,164,11,5.5,0,0,T),c.fill() + const m=()=>{c.beginPath();c.moveTo(110,163);c.quadraticCurveTo(128,170,148,160);c.quadraticCurveTo(142,186,126,184);c.quadraticCurveTo(110,182,110,163)} + c.fillStyle='#c92a2a';m();c.fill();c.save();c.clip();c.fillStyle='#fff';c.fillRect(100,150,60,21);c.restore();L(4);m();c.stroke() + L(6);c.fillStyle=HAIR;c.beginPath();c.moveTo(70,150) + c.bezierCurveTo(54,74,88,36,128,36);c.bezierCurveTo(168,36,202,74,186,150) + c.quadraticCurveTo(186,118,178,104);c.lineTo(170,112);c.lineTo(160,96);c.lineTo(150,110);c.lineTo(138,92);c.lineTo(126,108) + c.lineTo(114,92);c.lineTo(104,108);c.lineTo(94,96);c.lineTo(84,112);c.lineTo(78,104);c.quadraticCurveTo(70,124,70,150);c.closePath();c.fill();c.stroke() + c.fillStyle=BN;c.beginPath();c.moveTo(70,92);c.bezierCurveTo(70,40,186,40,186,92);c.lineTo(182,74);c.bezierCurveTo(170,46,86,46,74,74);c.closePath();c.fill();c.stroke() + c.beginPath();c.moveTo(184,78);c.lineTo(214,62);c.lineTo(206,86);c.closePath();c.moveTo(184,80);c.lineTo(216,96);c.lineTo(194,100);c.closePath();c.fill();c.stroke() + c.fillStyle=RD;for(const[x,y]of[[100,56],[128,50],[156,56]])c.beginPath(),c.arc(x,y,4,0,T),c.fill() + c.save();c.translate(84,60);c.scale(hit?1.6:1.3,hit?1.6:1.3) + for(const[w,k]of[[11,'#111'],[5,RD]]){c.lineWidth=w;c.strokeStyle=k;c.beginPath();for(let k=0;k<4;k++){const a=k*PI/2+PI/4,ca=cos(a),sa=sin(a),q=(x,y)=>[x*ca-y*sa,x*sa+y*ca];const[a1,b1]=q(5,-11),[a2,b2]=q(5,-4),[a3,b3]=q(11,-4);c.moveTo(a1,b1);c.quadraticCurveTo(a2,b2,a3,b3)}c.stroke()} + c.restore();c.strokeStyle='#111' + }) + c.save();c.translate(hit?-3*(1-i):0,0) + c.lineWidth=6;c.fillStyle=SV;c.beginPath();c.roundRect(8,116,98,132,10);c.fill();c.stroke() + c.fillStyle='#343a40';c.beginPath();c.roundRect(17,126,80,36,6);c.fill();c.lineWidth=4;c.stroke() + for(const[w,k]of[[8,'#111'],[4,RD]])c.lineWidth=w,c.strokeStyle=k,dig(c,37,144,0),dig(c,58,144,1),dig(c,78,144,1) + c.strokeStyle='#111';c.lineWidth=4 + for(const y of[170,196,222]){c.fillStyle=SD;c.beginPath();c.roundRect(17,y,80,20,5);c.fill();c.stroke();c.fillStyle=(i+y/26)%3<1.5?RD:'#495057';c.beginPath();c.arc(85,y+10,5,0,T);c.fill();c.stroke() + c.lineWidth=3;c.beginPath();for(const x of[28,40,52])c.moveTo(x,y+5),c.lineTo(x,y+15);c.stroke();c.lineWidth=4} + c.restore() + for(const[w,k]of[[26,'#111'],[16,SKIN]])c.lineWidth=w,c.strokeStyle=k,c.beginPath(),c.moveTo(122,186),c.quadraticCurveTo(106-8*s,168-40*s,hx,hy),c.stroke() + c.strokeStyle='#111';c.fillStyle=TS;c.lineWidth=5;c.beginPath();c.ellipse(122,190,15,17,.3,0,T);c.fill();c.stroke() + c.save();c.translate(hx,hy);c.rotate(a) + c.lineWidth=5;c.fillStyle='#adb5bd';c.beginPath();c.roundRect(-14,-6,62,12,5);c.fill();c.stroke() + c.beginPath();c.moveTo(46,-6);c.lineTo(48,-18);c.quadraticCurveTo(52,-24,60,-20);c.lineTo(58,-8);c.lineTo(68,-6);c.lineTo(70,8);c.lineTo(58,10);c.lineTo(58,22);c.quadraticCurveTo(52,24,48,18);c.lineTo(46,6);c.closePath();c.fill();c.stroke() + c.restore() + c.fillStyle=SKIN;c.lineWidth=5;c.beginPath();c.ellipse(hx,hy,13,12,a,0,T);c.fill();c.stroke() + if(i<3){const q=i/3;c.fillStyle=SP;c.lineWidth=4 + c.beginPath();for(let k=0;k<16;k++){const r=k%2?10:28*(1-q*.5),b=k*PI/8;c.lineTo(wx-6+cos(b)*r,wy-4+sin(b)*r)}c.closePath();if(i<2)c.fill(),c.stroke() + for(const b of[-2.4,-1.8,-1.2,-.6,2.5]){const r=30+24*q,x=wx-6+cos(b)*r,y=wy-4+sin(b)*r;for(const[w,k]of[[9,'#111'],[4,SP]])c.lineWidth=w,c.strokeStyle=k,c.beginPath(),c.moveTo(x,y),c.lineTo(x+cos(b)*12,y+sin(b)*12),c.stroke()} + c.strokeStyle='#111'} +} diff --git a/gen/uianime/box/hide.js b/gen/uianime/box/hide.js new file mode 100644 index 0000000..5f7981f --- /dev/null +++ b/gen/uianime/box/hide.js @@ -0,0 +1,53 @@ +// white haired catgirl hiding in an empty cardboard box: ears poke out, she peeks left and right, pops up with a cat smile, then ducks back in +const{sin,cos,PI}=Math,T=2*PI +export const frames=20,delay=80 +const SKIN='#ffe3d1',HAIR='#f8f9fa',HD='#ced4da',EAR='#ffc9d6',EYE='#4dabf7',ED='#1864ab',BL='#ffa8a8',BX='#e0a96d',BXD='#c08552',BXL='#f1c48a',IN='#8d6346',TP='#ffe8cc' +const E=x=>x<=0?0:x>=1?1:x*x*(3-2*x) +const poly=(c,...p)=>{c.beginPath();for(const[x,y]of p)c.lineTo(x,y);c.closePath();c.fill();c.stroke()} +const eye=(c,x,y,d,o)=>{ + c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill() + c.save();c.clip();c.beginPath();c.ellipse(x+o,y+3,11.5,15,0,0,T);c.fillStyle=EYE;c.fill();c.lineWidth=2.5;c.stroke() + c.fillStyle=ED;c.beginPath();c.ellipse(x+o,y-7,13,9,0,0,T);c.fill() + c.fillStyle='#111';c.beginPath();c.ellipse(x+o,y+4,4,8.5,0,0,T);c.fill() + c.fillStyle='#fff';c.beginPath();c.arc(x+o-4,y-3,4.5,0,T);c.fill();c.beginPath();c.arc(x+o+5,y+9,2,0,T);c.fill();c.restore() + c.lineWidth=7;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke() +} +export default(c,t)=>{ + const pk=E((t-.12)/.1),up=E((t-.5)/.07),dn=E((t-.7)/.07),cy=236-(73*pk+23*up)*(1-dn),o=t>.24&&t<.48?-6*cos(PI*(t-.24)/.24):0,hp=up>.5&&dn<.5 + const fw=t>.76?5*sin(T*4*(t-.76))*(1-(t-.76)/.24):0,tw=(t>.04&&t<.1)||(t>.88&&t<.94)?.35:0 + // flaps behind and the dark inside + c.lineWidth=6;c.fillStyle=BXD;poly(c,[44,122],[222,122],[214,98+fw],[52,98+fw]) + c.fillStyle=BXL;poly(c,[26,140],[44,122],[20,104-fw],[8,126-fw]);poly(c,[204,140],[222,122],[242,104+fw],[236,130+fw]) + c.fillStyle=IN;poly(c,[26,140],[204,140],[222,122],[44,122]) + // the girl, only what is above the front rim shows + c.save();c.beginPath();c.rect(0,0,256,140);c.clip() + c.translate(124,cy);c.scale(.76,.76);c.translate(-128,-186) + for(const[d,r]of[[-1,-tw],[1,0]]){ + c.save();c.translate(128+d*36,62);c.rotate(r*d) + c.lineWidth=8;c.fillStyle=HAIR;c.beginPath();c.moveTo(d*-26,8);c.lineTo(d*12,-48);c.lineTo(d*24,12);c.closePath();c.fill();c.stroke() + c.fillStyle=EAR;c.beginPath();c.moveTo(d*-12,4);c.lineTo(d*11,-32);c.lineTo(d*15,6);c.closePath();c.fill() + c.restore() + } + c.lineWidth=8;c.fillStyle=HD;c.beginPath();c.moveTo(128,36);c.bezierCurveTo(198,36,212,100,204,190);c.lineTo(52,190);c.bezierCurveTo(44,100,58,36,128,36);c.fill();c.stroke() + c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + if(hp){c.lineWidth=8;for(const x of[103,153])c.beginPath(),c.arc(x,148,13,PI*1.15,PI*1.85),c.stroke()} + else eye(c,103,140,-1,o),eye(c,153,140,1,o) + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,162,13,7,0,0,T),c.fill() + c.lineWidth=3;for(const d of[-1,1])for(const k of[-5,0,5])c.beginPath(),c.moveTo(128+d*44+k-2,165),c.lineTo(128+d*44+k+2,159),c.stroke() + c.lineWidth=5;c.beginPath();c.moveTo(116,168);c.quadraticCurveTo(122,176,128,169);c.quadraticCurveTo(134,176,140,168);c.stroke() + c.lineWidth=8;c.fillStyle=HAIR;c.beginPath();c.moveTo(66,160) + c.bezierCurveTo(48,74,88,38,128,38);c.bezierCurveTo(168,38,208,74,190,160) + c.quadraticCurveTo(188,120,180,104);c.quadraticCurveTo(170,104,164,96);c.quadraticCurveTo(156,108,144,110);c.quadraticCurveTo(140,98,130,92) + c.quadraticCurveTo(122,106,108,110);c.quadraticCurveTo(104,98,96,94);c.quadraticCurveTo(88,106,78,106);c.quadraticCurveTo(68,128,66,160);c.closePath();c.fill();c.stroke() + c.strokeStyle=HD;c.lineWidth=6;for(const[a,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,56,PI*a,PI*e),c.stroke() + c.strokeStyle='#111';c.restore() + // box sides, front with a paw print, folded front flap + c.lineWidth=6;c.fillStyle=BXD;poly(c,[204,140],[222,122],[222,230],[204,248]) + c.fillStyle=BX;c.beginPath();c.rect(26,140,178,108);c.fill();c.stroke() + c.fillStyle=BXL;poly(c,[26,140],[204,140],[198,164+fw*.6],[32,164+fw*.6]) + c.fillStyle=TP;c.lineWidth=4;c.beginPath();c.rect(104,164+fw*.6,22,30);c.fill();c.stroke() + c.fillStyle=BXD;c.beginPath();c.ellipse(115,224,16,12,0,0,T);c.fill();for(const[x,y]of[[95,208],[107,199],[123,199],[135,208]])c.beginPath(),c.ellipse(x,y,5.5,7,(x-115)*.03,0,T),c.fill() + if(up>.3&&dn<.6){c.fillStyle='#fff';c.lineWidth=5;for(const d of[-1,1])c.beginPath(),c.ellipse(124+d*34,140,13,10,0,0,T),c.fill(),c.stroke() + c.lineWidth=2.5;c.beginPath();for(const d of[-1,1])for(const k of[-4,4])c.moveTo(124+d*34+k,134),c.lineTo(124+d*34+k,140);c.stroke() + c.fillStyle='#ffd43b';c.lineWidth=3.5;for(const[x,y]of[[210,40],[38,62]])c.beginPath(),c.moveTo(x,y-11),[[1,0],[0,1],[-1,0],[0,-1]].forEach(([a,b])=>c.quadraticCurveTo(x+(a+b)*2,y+(b-a)*2,x+a*11,y+b*11)),c.fill(),c.stroke()} +} diff --git a/gen/uianime/buffering/stare.js b/gen/uianime/buffering/stare.js new file mode 100644 index 0000000..70c4097 --- /dev/null +++ b/gen/uianime/buffering/stare.js @@ -0,0 +1,38 @@ +// periwinkle haired girl in round glasses staring blankly at her laptop, a buffering ring spinning in both lenses while three dots pile up above her +const{sin,cos,PI,min}=Math,T=2*PI +export const frames=12,delay=85 +const SKIN='#ffe3d1',HAIR='#748ffc',HD='#4c6ef5',HL='#dbe4ff',SWT='#ffd8a8',SWD='#ffa94d',LAP='#ced4da',LD='#868e96',LENS='#e7f5ff',RING='#4dabf7',BL='#ffc9c9' +export default(c,t,i)=>{ + c.lineWidth=6;c.fillStyle=HD;c.beginPath();c.moveTo(128,34);c.bezierCurveTo(198,34,214,100,206,160);c.quadraticCurveTo(212,190,196,200);c.lineTo(60,200);c.quadraticCurveTo(44,190,50,160);c.bezierCurveTo(42,100,58,34,128,34);c.fill();c.stroke() + c.fillStyle=SWT;c.beginPath();c.moveTo(100,190);c.quadraticCurveTo(62,198,54,250);c.lineTo(202,250);c.quadraticCurveTo(194,198,156,190);c.closePath();c.fill();c.stroke() + c.fillStyle=SKIN;c.beginPath();c.moveTo(116,168);c.lineTo(116,186);c.lineTo(140,186);c.lineTo(140,168);c.fill();c.lineWidth=5;c.beginPath();c.moveTo(116,168);c.lineTo(116,186);c.moveTo(140,168);c.lineTo(140,186);c.stroke() + c.fillStyle=SWT;c.beginPath();c.roundRect(106,182,44,20,9);c.fill();c.stroke() + c.strokeStyle=SWD;c.lineWidth=3;for(const x of[116,128,140])c.beginPath(),c.moveTo(x,187),c.lineTo(x,197),c.stroke();c.strokeStyle='#111' + c.lineWidth=6;c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,164,10,5,0,0,T),c.fill() + c.lineWidth=3.5;c.fillStyle='#fff';c.beginPath();c.roundRect(122,168,12,6,2);c.fill();c.stroke() + // glasses: opaque glare with the buffering ring reflected in each lens + const a=T*t + for(const x of[103,153]){ + c.fillStyle=LENS;c.beginPath();c.arc(x,140,21,0,T);c.fill() + c.strokeStyle='#d0ebff';c.lineWidth=6;c.beginPath();c.arc(x,140,11,0,T);c.stroke() + c.strokeStyle=RING;c.beginPath();c.arc(x,140,11,a,a+PI*1.1);c.stroke() + c.strokeStyle='#fff';c.lineWidth=3.5;c.beginPath();c.arc(x,140,17,PI*1.1,PI*1.4);c.stroke() + } + c.strokeStyle='#111';c.lineWidth=6;for(const x of[103,153])c.beginPath(),c.arc(x,140,21,0,T),c.stroke() + c.beginPath();c.moveTo(124,138);c.quadraticCurveTo(128,134,132,138);c.moveTo(82,136);c.lineTo(74,132);c.moveTo(174,136);c.lineTo(182,132);c.stroke() + c.lineWidth=6;c.fillStyle=HAIR;c.beginPath();c.moveTo(66,170) + c.bezierCurveTo(48,74,88,36,128,36);c.bezierCurveTo(168,36,208,74,190,170);c.quadraticCurveTo(184,160,180,170) + c.quadraticCurveTo(184,124,178,104);c.quadraticCurveTo(170,108,166,114);c.quadraticCurveTo(162,100,152,90);c.quadraticCurveTo(146,104,140,112) + c.quadraticCurveTo(134,98,126,90);c.quadraticCurveTo(120,104,112,110);c.quadraticCurveTo(108,98,98,92);c.quadraticCurveTo(92,106,86,112) + c.quadraticCurveTo(82,106,78,104);c.quadraticCurveTo(72,130,76,170);c.quadraticCurveTo(72,160,66,170);c.closePath();c.fill();c.stroke() + c.strokeStyle=HL;c.lineWidth=5;for(const[s,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,56,PI*s,PI*e),c.stroke() + c.strokeStyle='#111';c.fillStyle=HAIR;c.lineWidth=5;c.save();c.translate(128,38);c.rotate(1.1*(i<9?i/8:(11-i)/3));c.beginPath();c.moveTo(-6,0);c.bezierCurveTo(-12,-22,10,-32,22,-22);c.bezierCurveTo(10,-24,2,-16,6,0);c.closePath();c.fill();c.stroke();c.restore() + // laptop lid seen from behind + c.lineWidth=6;c.fillStyle=LAP;c.beginPath();c.moveTo(62,196);c.lineTo(194,196);c.quadraticCurveTo(204,196,206,206);c.lineTo(214,262);c.lineTo(42,262);c.lineTo(50,206);c.quadraticCurveTo(52,196,62,196);c.fill();c.stroke() + c.strokeStyle='#fff';c.lineWidth=4;c.beginPath();c.moveTo(62,206);c.lineTo(194,206);c.stroke();c.strokeStyle='#111' + c.fillStyle='#fff';c.lineWidth=4;c.beginPath();c.moveTo(128,240);c.bezierCurveTo(112,230,114,216,128,222);c.bezierCurveTo(142,216,144,230,128,240);c.fill();c.stroke() + c.fillStyle='#ffd43b';c.beginPath();for(let k=0;k<10;k++){const r=k%2?5.5:12,b=k*PI/5-PI/2-.3;c.lineTo(76+cos(b)*r,234+sin(b)*r)}c.closePath();c.fill();c.stroke() + // dots piling up + c.fillStyle='#fff';c.lineWidth=4;for(let k=0;kx<=0?0:x>=1?1:x*x*(3-2*x) +const ds=(c,a,b,s,f)=>{for(const[l,k]of[[a,'#111'],[b,s]])c.lineWidth=l,c.strokeStyle=k,c.beginPath(),f(),c.stroke();c.strokeStyle='#111'} +const sp=(c,x,y,r)=>{c.beginPath();c.moveTo(x,y-r);for(const[a,b]of[[1,0],[0,1],[-1,0],[0,-1]])c.quadraticCurveTo(x+(a+b)*r*.16,y+(b-a)*r*.16,x+a*r,y+b*r);c.fill();c.stroke()} +const page=c=>{c.fillStyle='#fff';c.lineWidth=5;c.beginPath();c.rect(-50,-30,100,74);c.fill();c.stroke() + c.strokeStyle=GR;c.lineWidth=3;c.beginPath();for(let k=1;k<5;k++)c.moveTo(-50+k*20,-26),c.lineTo(-50+k*20,40);for(let k=1;k<4;k++)c.moveTo(-46,-30+k*18.5),c.lineTo(46,-30+k*18.5);c.stroke();c.strokeStyle='#111'} +export default(c,t)=>{ + const hp=t<.25?abs(sin(8*PI*t)):t>=.625&&t<.875?.8*abs(sin(8*PI*t)):0,b=-10*hp,sw=t%.25<.125?.06*hp:-.06*hp,fl=(t-.4)/.2 + // side ponytail swinging behind + c.save();c.translate(0,b);c.save();c.translate(148,72);c.rotate(.25-.2*hp) + c.lineWidth=6;c.fillStyle=HAIR;c.beginPath();c.moveTo(-6,0);c.bezierCurveTo(30,-4,50,40,40,100);c.quadraticCurveTo(34,124,18,128);c.quadraticCurveTo(30,80,0,18);c.closePath();c.fill();c.stroke() + c.strokeStyle=HD;c.lineWidth=3;c.beginPath();c.moveTo(12,12);c.bezierCurveTo(30,30,38,64,32,100);c.stroke();c.strokeStyle='#111';c.restore() + c.save();c.translate(92,170);c.scale(.74,.74);c.translate(-128,-186) + c.lineWidth=8;c.fillStyle=HD;c.beginPath();c.moveTo(128,36);c.bezierCurveTo(198,36,210,100,202,164);c.lineTo(54,164);c.bezierCurveTo(46,100,58,36,128,36);c.fill();c.stroke() + c.fillStyle=TOP;c.beginPath();c.moveTo(100,190);c.quadraticCurveTo(54,198,44,300);c.lineTo(212,300);c.quadraticCurveTo(202,198,156,190);c.closePath();c.fill();c.stroke() + c.strokeStyle=TD;c.lineWidth=5;for(const y of[246,276])c.beginPath(),c.moveTo(56,y),c.lineTo(200,y),c.stroke();c.strokeStyle='#111' + c.fillStyle=SKIN;c.beginPath();c.moveTo(116,166);c.lineTo(116,194);c.lineTo(128,206);c.lineTo(140,194);c.lineTo(140,166);c.fill();c.beginPath();c.moveTo(116,166);c.lineTo(116,192);c.moveTo(140,166);c.lineTo(140,192);c.stroke() + c.fillStyle='#fff';for(const d of[-1,1])c.beginPath(),c.moveTo(128,206),c.quadraticCurveTo(128+d*34,212,128+d*30,190),c.quadraticCurveTo(128+d*16,192,128,206),c.fill(),c.stroke() + c.save();c.translate(128,186);c.rotate(sw);c.translate(-128,-186) + c.lineWidth=8;c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + for(const x of[103,153])c.beginPath(),c.arc(x,148,14,PI*1.15,PI*1.85),c.stroke() + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,160,14,8,0,0,T),c.fill() + c.lineWidth=3;for(const d of[-1,1])for(const k of[-6,0,6])c.beginPath(),c.moveTo(128+d*44+k-2,164),c.lineTo(128+d*44+k+2,157),c.stroke() + c.lineWidth=5;c.fillStyle=MO;c.beginPath();c.moveTo(110,164);c.quadraticCurveTo(128,168,146,164);c.quadraticCurveTo(144,188,128,188);c.quadraticCurveTo(112,188,110,164);c.fill();c.stroke() + c.save();c.clip();c.fillStyle=TG;c.beginPath();c.ellipse(128,190,10,7,0,0,T);c.fill();c.restore() + c.lineWidth=8;c.fillStyle=HAIR;c.beginPath();c.moveTo(66,158) + c.bezierCurveTo(48,74,88,38,128,38);c.bezierCurveTo(168,38,208,74,190,158) + c.quadraticCurveTo(188,120,180,104);c.quadraticCurveTo(172,100,166,92);c.quadraticCurveTo(158,106,146,108);c.quadraticCurveTo(140,96,132,90) + c.quadraticCurveTo(124,104,112,108);c.quadraticCurveTo(106,98,98,94);c.quadraticCurveTo(90,106,78,106);c.quadraticCurveTo(68,128,66,158);c.closePath();c.fill();c.stroke() + c.strokeStyle=HL;c.lineWidth=7;for(const[a,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,56,PI*a,PI*e),c.stroke() + c.strokeStyle='#111';c.fillStyle='#f783ac';c.lineWidth=6;c.beginPath();c.ellipse(180,62,10,15,.5,0,T);c.fill();c.stroke() + c.restore();c.restore() + // peace sign + const hx=40,hy=150 + ds(c,22,13,TOP,()=>{c.moveTo(62,200);c.quadraticCurveTo(34,196,hx,hy+14)}) + for(const[fx,fy]of[[-12,-30],[5,-33]])ds(c,14,7,SKIN,()=>{c.moveTo(hx,hy);c.lineTo(hx+fx,hy+fy)}) + c.lineWidth=5;c.fillStyle=SKIN;c.beginPath();c.ellipse(hx,hy+4,13,12,0,0,T);c.fill();c.stroke() + // calendar held up high, swaying, flipping to another blank page + c.save();c.translate(188,92);c.rotate(-sw*.8) + c.lineWidth=6;c.fillStyle=CAL;c.beginPath();c.roundRect(-54,-52,108,98,8);c.fill();c.stroke() + page(c) + if(fl>0&&fl<1){const s=cos(PI*fl*.67);c.save();c.translate(0,-30);c.scale(1,s);c.translate(0,30);if(s>0)page(c),c.restore();else{c.beginPath();c.rect(-50,-30,100,74);c.restore();c.fillStyle='#f1f3f5';c.lineWidth=5;c.fill();c.stroke()}} + c.strokeStyle=CD;c.lineWidth=4;c.beginPath();c.moveTo(-50,-38);c.lineTo(50,-38);c.stroke();c.strokeStyle='#111' + for(const x of[-30,0,30])ds(c,10,4,RG,()=>{c.moveTo(x,-58);c.lineTo(x,-44)}) + c.restore() + ds(c,22,13,TOP,()=>{c.moveTo(124,198);c.quadraticCurveTo(140,180,148,140)}) + c.fillStyle=SKIN;c.lineWidth=5;c.beginPath();c.ellipse(148,136,11,12,0,0,T);c.fill();c.stroke() + c.restore() + c.fillStyle=SP;c.lineWidth=3.5;for(const[x,y,o,r]of[[238,28,0,13],[124,30,.33,11],[240,150,.66,12],[22,94,.5,10]]){const s=.6+.4*sin(PI*min(1,hp+o));sp(c,x,y,r*s)} +} diff --git a/gen/uianime/cart/sigh.js b/gen/uianime/cart/sigh.js new file mode 100644 index 0000000..55b9365 --- /dev/null +++ b/gen/uianime/cart/sigh.js @@ -0,0 +1,55 @@ +// brown-haired girl with a side braid leaning on an empty shopping cart, peering in and letting out a long gloomy sigh +const{sin,cos,PI,max,min}=Math,T=2*PI +export const frames=16,delay=90 +const SKIN='#ffe3d1',HAIR='#b5835a',HD='#8d5a3b',HL='#f1d2b6',EYE='#3bc9db',ED='#0b7285',CD='#fab005',BL='#ffa8a8',GL='#9775fa',CW='#e7f5ff',WR='#74c0fc',HN='#fa5252',Z=.72 +const ez=(t,a,b)=>{const x=min(1,max(0,(t-a)/(b-a)));return x*x*(3-2*x)} +const puff=(c,x,y,r)=>{c.beginPath();for(const[a,b,s]of[[-.8,0,.7],[0,-.5,.8],[.8,0,.7],[0,.3,.75]])c.moveTo(x+a*r+s*r,y+b*r),c.arc(x+a*r,y+b*r,s*r,0,T);c.lineWidth=8;c.strokeStyle='#111';c.stroke();c.fillStyle='#fff';c.fill()} +export default(c,t)=>{ + const up=ez(t,.05,.3)-ez(t,.38,.55),dr=ez(t,.38,.55)-ez(t,.85,1),L=v=>c.lineWidth=v/Z,so=t>.36&&t<.8 + const head=f=>{c.save();c.translate(150,88-5*up+6*dr);c.rotate(-.1-.08*dr);c.scale(Z,Z);c.translate(-128,-128);f();c.restore()} + head(()=>{ + L(6);c.fillStyle=HD;c.beginPath();c.moveTo(128,34);c.bezierCurveTo(196,34,206,96,198,150);c.lineTo(58,150);c.bezierCurveTo(50,96,60,34,128,34);c.fill();c.stroke() + }) + c.save();c.translate(150,88-3*up+3*dr);c.scale(Z,Z);c.translate(-128,-128) + L(6);c.fillStyle=CD;c.beginPath();c.moveTo(100,190);c.quadraticCurveTo(56,196,52,270);c.lineTo(204,270);c.quadraticCurveTo(200,196,156,190);c.closePath();c.fill();c.stroke() + c.fillStyle='#fff';c.beginPath();c.moveTo(106,190);c.lineTo(128,226);c.lineTo(150,190);c.closePath();c.fill();L(5);c.stroke() + c.fillStyle=SKIN;c.beginPath();c.moveTo(116,166);c.lineTo(116,194);c.lineTo(128,206);c.lineTo(140,194);c.lineTo(140,166);c.fill();c.beginPath();c.moveTo(116,166);c.lineTo(116,192);c.moveTo(140,166);c.lineTo(140,192);c.stroke() + c.restore() + head(()=>{ + L(6);c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + for(const[x,d]of[[103,-1],[153,1]]){ + c.save();c.beginPath();c.ellipse(x,140,14,17,0,0,T);c.clip() + c.fillStyle='#fff';c.fill();c.fillStyle=EYE;c.beginPath();c.ellipse(x,150,11.5,15,0,0,T);c.fill();c.fillStyle=ED;c.beginPath();c.ellipse(x,141,13,9,0,0,T);c.fill() + c.fillStyle='#111';c.beginPath();c.ellipse(x,152,5,6.5,0,0,T);c.fill();c.fillStyle='#fff';c.beginPath();c.arc(x-4,148,3.5,0,T);c.fill() + c.fillStyle=SKIN;c.fillRect(x-16,118,32,20);c.restore() + L(6);c.beginPath();c.moveTo(x-16,137);c.quadraticCurveTo(x,132,x+16,137);c.moveTo(x+d*15,136);c.lineTo(x+d*20,140);c.stroke() + L(4);c.beginPath();c.moveTo(x-d*14,118);c.lineTo(x+d*12,126);c.stroke() + } + c.strokeStyle=GL;L(3.5);for(const x of[96,108,120,136,148,160])c.beginPath(),c.moveTo(x,106),c.lineTo(x,118+(x%24?4:0)),c.stroke() + c.strokeStyle='#111';c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*42,163,11,5,0,0,T),c.fill() + L(3.5);c.beginPath();if(so)c.ellipse(128,172,5,6.5,0,0,T);else c.moveTo(120,172),c.quadraticCurveTo(124,168,128,172),c.quadraticCurveTo(132,176,136,172);c.stroke() + L(6);c.fillStyle=HAIR;c.beginPath();c.moveTo(70,146) + c.bezierCurveTo(54,74,88,36,128,36);c.bezierCurveTo(168,36,202,74,186,146) + c.quadraticCurveTo(186,116,178,102);c.quadraticCurveTo(170,104,164,112);c.quadraticCurveTo(160,98,150,92);c.quadraticCurveTo(144,104,136,110) + c.quadraticCurveTo(132,96,124,90);c.quadraticCurveTo(118,102,110,108);c.quadraticCurveTo(106,96,96,94);c.quadraticCurveTo(90,104,86,112) + c.quadraticCurveTo(80,104,78,102);c.quadraticCurveTo(70,120,70,146);c.closePath();c.fill();c.stroke() + c.strokeStyle=HL;L(5);for(const[a,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,56,PI*a,PI*e),c.stroke() + c.strokeStyle='#111' + for(let k=0;k<4;k++){c.fillStyle=k%2?HAIR:HD;L(5);c.beginPath();c.ellipse(186+k*2,150+k*17,12,11,.2,0,T);c.fill();c.stroke()} + c.fillStyle=HN;L(4);c.beginPath();c.ellipse(194,218,9,6,0,0,T);c.fill();c.stroke() + }) + c.lineWidth=6;c.strokeStyle='#111' + for(const x of[50,178]){c.fillStyle='#868e96';c.beginPath();c.arc(x,236,10,0,T);c.fill();c.stroke();c.fillStyle='#dee2e6';c.beginPath();c.arc(x,236,3.5,0,T);c.fill()} + c.lineWidth=6;c.beginPath();c.moveTo(36,220);c.lineTo(50,236);c.moveTo(192,220);c.lineTo(178,236);c.moveTo(40,226);c.lineTo(190,226);c.stroke() + c.strokeStyle='#adb5bd';c.lineWidth=3;c.beginPath();c.moveTo(42,226);c.lineTo(188,226);c.stroke();c.strokeStyle='#111' + const bk=()=>{c.beginPath();c.moveTo(12,152);c.lineTo(214,152);c.lineTo(196,220);c.lineTo(32,220);c.closePath()} + c.fillStyle=CW;bk();c.fill() + c.save();bk();c.clip();c.strokeStyle=WR;c.lineWidth=4;c.beginPath();for(let x=20;x<214;x+=22)c.moveTo(x,150),c.lineTo(x+(x<113?6:-6),222);for(const y of[175,198])c.moveTo(0,y),c.lineTo(256,y);c.stroke();c.restore() + c.lineWidth=6;c.strokeStyle='#111';bk();c.stroke() + c.lineWidth=11;c.beginPath();c.moveTo(10,152);c.lineTo(216,152);c.stroke();c.strokeStyle='#dee2e6';c.lineWidth=4;c.stroke();c.strokeStyle='#111' + c.lineWidth=6;c.beginPath();c.moveTo(214,152);c.lineTo(230,136);c.stroke() + c.fillStyle=HN;c.save();c.translate(232,132);c.rotate(-.8);c.beginPath();c.roundRect(-16,-7,32,14,7);c.fill();c.stroke();c.restore() + c.strokeStyle='#868e96';c.lineWidth=3;c.beginPath();for(const r of[12,22])c.moveTo(18+r,156),c.arc(18,156,r,0,PI/2);for(const a of[.15,.78,1.4])c.moveTo(18,156),c.lineTo(18+30*cos(a),156+30*sin(a));c.stroke();c.strokeStyle='#111' + c.lineWidth=5;c.fillStyle=SKIN;for(const[x,y]of[[104,150],[188,150]])c.beginPath(),c.ellipse(x,y-1-3*up+3*dr,13,10,0,0,T),c.fill(),c.stroke() + if(t>.38){const p=(t-.38)/.62,x=116-62*p,y=124+18*p;puff(c,x,y,(7+13*sin(PI*min(1,p*1.3)))*min(1,(1-p)*5))} +} diff --git a/gen/uianime/comingsoon/shh.js b/gen/uianime/comingsoon/shh.js new file mode 100644 index 0000000..9b6e6c7 --- /dev/null +++ b/gen/uianime/comingsoon/shh.js @@ -0,0 +1,53 @@ +// girl with long plum hair holding a finger to her lips and winking "it's a secret", a little shh bubble puffing beside her +const{sin,PI,max,min}=Math,T=2*PI +export const frames=16,delay=85 +const SKIN='#ffe3d1',HAIR='#da77f2',HD='#ae3ec9',HL='#f8f0fc',EYE='#20c997',ED='#087f5b',CARD='#96f2d7',CD='#38d9a9',BL='#ffa8a8',STAR='#ffd43b' +const ds=(c,a,b,s,f)=>{for(const[l,k]of[[a,'#111'],[b,s]])c.lineWidth=l,c.strokeStyle=k,c.beginPath(),f(),c.stroke();c.strokeStyle='#111'} +const eye=(c,x,y,d)=>{ + c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill() + c.save();c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.clip();c.fillStyle=EYE;c.fill();c.fillStyle=ED;c.beginPath();c.ellipse(x,y-8,13,10,0,0,T);c.fill();c.restore() + c.lineWidth=2.5;c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.stroke() + c.fillStyle='#111';c.beginPath();c.ellipse(x,y+3,5.5,7.5,0,0,T);c.fill() + c.fillStyle='#fff';c.beginPath();c.arc(x-4,y-5,4.5,0,T);c.fill();c.beginPath();c.arc(x+5,y+8,2,0,T);c.fill() + c.lineWidth=6;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke() + c.lineWidth=2.5;c.beginPath();c.moveTo(x-8,y+18);c.lineTo(x+8,y+18);c.stroke() +} +const spark=(c,x,y,r)=>{c.beginPath();c.moveTo(x,y-r);for(const[a,b]of[[1,0],[0,1],[-1,0],[0,-1]])c.quadraticCurveTo(x+(a+b)*r*.15,y+(b-a)*r*.15,x+a*r,y+b*r);c.fill();c.stroke()} +export default(c,t,i)=>{ + const w=t>=.375&&t<.75,tilt=.08*min(1,max(0,min(i-4,13-i)/2)),pf=1+.1*sin(2*T*t) + const head=f=>{c.save();c.translate(128,186);c.rotate(tilt);c.translate(-128,-186);f();c.restore()} + head(()=>{c.lineWidth=6;c.fillStyle=HD;c.beginPath();c.moveTo(128,34);c.bezierCurveTo(200,34,214,96,206,150);c.quadraticCurveTo(212,200,200,228);c.lineTo(56,228);c.quadraticCurveTo(44,200,50,150);c.bezierCurveTo(42,96,56,34,128,34);c.fill();c.stroke()}) + c.lineWidth=6;c.fillStyle=CARD;c.beginPath();c.moveTo(100,190);c.quadraticCurveTo(62,198,54,250);c.lineTo(202,250);c.quadraticCurveTo(194,198,156,190);c.closePath();c.fill();c.stroke() + c.fillStyle='#fff';c.beginPath();c.moveTo(104,190);c.lineTo(128,250);c.lineTo(152,190);c.closePath();c.fill();c.lineWidth=5;c.stroke() + c.fillStyle=CD;for(const y of[226,242])c.beginPath(),c.arc(162,y,4,0,T),c.fill(),c.stroke() + c.fillStyle=SKIN;c.beginPath();c.moveTo(116,168);c.lineTo(116,192);c.quadraticCurveTo(128,204,140,192);c.lineTo(140,168);c.fill();c.beginPath();c.moveTo(116,168);c.lineTo(116,190);c.moveTo(140,168);c.lineTo(140,190);c.stroke() + head(()=>{ + c.lineWidth=6;c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + eye(c,103,140,-1) + if(w){c.lineWidth=6;c.beginPath();c.arc(153,146,13,PI*1.12,PI*1.88);c.moveTo(166,140);c.lineTo(172,135);c.stroke()}else eye(c,153,140,1) + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,162,13,7,0,0,T),c.fill() + c.lineWidth=2.5;for(const d of[-1,1])for(const k of[-5,0,5])c.beginPath(),c.moveTo(128+d*44+k-2,165),c.lineTo(128+d*44+k+2,159),c.stroke() + c.lineWidth=3.5;c.fillStyle='#e8590c';c.beginPath();c.ellipse(130,169,6,5,0,0,T);c.fill();c.stroke() + c.lineWidth=6;c.fillStyle=HAIR;c.beginPath();c.moveTo(70,150) + c.bezierCurveTo(54,74,88,36,128,36);c.bezierCurveTo(168,36,202,74,186,150) + c.quadraticCurveTo(184,118,178,104);c.quadraticCurveTo(170,106,164,112);c.quadraticCurveTo(158,98,148,92);c.quadraticCurveTo(142,104,134,110) + c.quadraticCurveTo(128,98,120,92);c.quadraticCurveTo(114,104,106,110);c.quadraticCurveTo(100,98,92,96);c.quadraticCurveTo(88,106,84,112) + c.quadraticCurveTo(80,104,78,104);c.quadraticCurveTo(72,124,70,150);c.closePath();c.fill();c.stroke() + c.strokeStyle=HL;c.lineWidth=5;for(const[a,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,56,PI*a,PI*e),c.stroke() + c.strokeStyle='#111';c.fillStyle=STAR;c.lineWidth=4;spark(c,174,70,14) + }) + if(w){const p=(t-.375)/.375;c.fillStyle=STAR;c.lineWidth=3.5;spark(c,178+40*p,124-50*p,12*sin(PI*p))} + for(const[x,y,o]of[[30,60,0],[226,190,.5]]){const s=max(0,sin(T*(t+o)));if(s>.1)c.fillStyle='#fff',c.lineWidth=3.5,spark(c,x,y,13*s)} + c.save();c.translate(212,40);c.scale(pf,pf) + c.fillStyle='#fff';c.lineWidth=5;c.beginPath();c.ellipse(0,0,34,22,0,0,T);c.fill();c.stroke() + c.beginPath();c.moveTo(-22,14);c.lineTo(-34,32);c.lineTo(-8,20);c.fill();c.stroke() + c.beginPath();c.ellipse(0,0,31.5,19.5,0,0,T);c.fill() + c.lineWidth=4.5;c.strokeStyle=HD;c.beginPath() + c.moveTo(-12,-6);c.quadraticCurveTo(-22,-8,-21,-2);c.quadraticCurveTo(-20,2,-14,3);c.quadraticCurveTo(-8,5,-11,10);c.quadraticCurveTo(-15,13,-22,9) + for(const x of[-2,14]){c.moveTo(x,-11);c.lineTo(x,10);c.moveTo(x,2);c.quadraticCurveTo(x+8,-8,x+9,3);c.lineTo(x+9,10)} + c.stroke();c.restore();c.strokeStyle='#111' + ds(c,30,19,CARD,()=>{c.moveTo(70,252);c.lineTo(92,234);c.lineTo(114,214)}) + ds(c,14,7,SKIN,()=>{c.moveTo(127,198);c.lineTo(127,162)}) + c.lineWidth=5;c.fillStyle=SKIN;c.beginPath();c.ellipse(122,208,13,12,-.3,0,T);c.fill();c.stroke() + c.lineWidth=2.5;c.beginPath();for(const y of[204,211])c.moveTo(114,y),c.lineTo(122,y-1);c.stroke() +} diff --git a/gen/uianime/construction/hardhat.js b/gen/uianime/construction/hardhat.js new file mode 100644 index 0000000..83071da --- /dev/null +++ b/gen/uianime/construction/hardhat.js @@ -0,0 +1,60 @@ +// teal braided girl in a yellow hard hat and safety vest hammering a nail into a striped under construction sign, tongue out, sparks on every bonk +const{sin,cos,PI}=Math,T=2*PI +export const frames=16,delay=75 +const SKIN='#ffe3d1',HAIR='#38d9a9',EYE='#20c997',ED='#087f5b',BL='#ffa8a8',HAT='#ffd43b',HTD='#f59f00',VS='#ff922b',SH='#74c0fc',RF='#e9ecef',WD='#c98a52',ST='#ff922b',MT='#adb5bd',TG='#ff8fab',SP='#ffd43b' +const A=[-.45,-.6,-.95,-1.35,-1.65,-1.75,-1.1,-.45] +const ds=(c,a,b,s,f)=>{for(const[l,k]of[[a,'#111'],[b,s]])c.lineWidth=l,c.strokeStyle=k,c.beginPath(),f(),c.stroke();c.strokeStyle='#111'} +const eye=(c,x,y,d)=>{ + c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,16,0,0,T);c.fill() + c.save();c.clip();c.beginPath();c.ellipse(x+5,y+3,11.5,14,0,0,T);c.fillStyle=EYE;c.fill();c.lineWidth=2.5;c.stroke() + c.fillStyle=ED;c.beginPath();c.ellipse(x+5,y-6,13,8,0,0,T);c.fill() + c.fillStyle='#111';c.beginPath();c.ellipse(x+6,y+4,5.5,7.5,0,0,T);c.fill() + c.fillStyle='#fff';c.beginPath();c.arc(x+1,y-2,4.5,0,T);c.fill();c.restore() + c.lineWidth=7;c.beginPath();c.moveTo(x-16,y-4);c.quadraticCurveTo(x,y-14,x+16,y-4);c.moveTo(x+d*15,y-5);c.lineTo(x+d*21,y-10);c.stroke() +} +export default(c,t,i)=>{ + const k=i%8,a=A[k],hit=k==7||k==0,jx=hit?3:0 + // sign on its post + c.save();c.translate(jx,0) + c.lineWidth=6;c.fillStyle=WD;c.beginPath();c.rect(190,140,18,110);c.fill();c.stroke() + c.save();c.translate(198,104);c.rotate(hit?.04:0) + const bd=()=>{c.beginPath();c.roundRect(-46,-40,92,82,6)} + c.fillStyle='#fff';bd();c.fill();c.save();bd();c.clip();c.fillStyle=ST;for(let x=-90;x<70;x+=30)c.beginPath(),c.moveTo(x,-50),c.lineTo(x+16,-50),c.lineTo(x+56,40),c.lineTo(x+40,40),c.closePath(),c.fill();c.restore() + c.lineWidth=6;bd();c.stroke() + c.fillStyle=MT;c.lineWidth=3.5;for(const[x,y]of[[-34,-28],[34,-28],[34,30],[-14,28]])c.beginPath(),c.arc(x,y,4.5,0,T),c.fill(),c.stroke() + c.restore();c.restore() + // girl + c.save();c.translate(74,170);c.scale(.72,.72);c.translate(-128,-186) + c.lineWidth=8;c.fillStyle=HAIR;for(const d of[-1,1])for(let j=4;j>=0;j--)c.beginPath(),c.ellipse(128+d*(64+j*1.5),156+j*20,14-j*.8,12,d*.4*(j%2?1:-1),0,T),c.fill(),c.stroke() + c.fillStyle=SH;c.beginPath();c.moveTo(100,190);c.quadraticCurveTo(54,198,44,300);c.lineTo(212,300);c.quadraticCurveTo(202,198,156,190);c.closePath();c.fill();c.stroke() + c.fillStyle=VS;c.beginPath();c.moveTo(94,194);c.quadraticCurveTo(58,204,52,300);c.lineTo(112,300);c.lineTo(112,232);c.lineTo(104,198);c.closePath();c.fill();c.stroke() + c.beginPath();c.moveTo(162,194);c.quadraticCurveTo(198,204,204,300);c.lineTo(144,300);c.lineTo(144,232);c.lineTo(152,198);c.closePath();c.fill();c.stroke() + c.strokeStyle=RF;c.lineWidth=9;c.beginPath();c.moveTo(56,262);c.lineTo(110,262);c.moveTo(146,262);c.lineTo(200,262);c.stroke();c.strokeStyle='#111' + c.fillStyle=SKIN;c.beginPath();c.moveTo(116,166);c.lineTo(116,194);c.quadraticCurveTo(128,204,140,194);c.lineTo(140,166);c.fill();c.beginPath();c.moveTo(116,166);c.lineTo(116,192);c.moveTo(140,166);c.lineTo(140,192);c.stroke() + c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + if(hit){c.lineWidth=7;c.beginPath();c.moveTo(92,130);c.lineTo(114,141);c.lineTo(92,151);c.moveTo(164,130);c.lineTo(142,141);c.lineTo(164,151);c.stroke()} + else eye(c,103,140,-1),eye(c,153,140,1) + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,162,13,7,0,0,T),c.fill() + c.lineWidth=3;for(const d of[-1,1])for(const j of[-5,0,5])c.beginPath(),c.moveTo(128+d*44+j-2,165),c.lineTo(128+d*44+j+2,159),c.stroke() + c.lineWidth=5;c.beginPath();c.moveTo(116,168);c.quadraticCurveTo(128,176,142,166);c.stroke() + c.fillStyle=TG;c.lineWidth=4;c.beginPath();c.ellipse(140,174,5,6,-.5,0,T);c.fill();c.stroke() + c.lineWidth=8;c.fillStyle=HAIR;c.beginPath();c.moveTo(68,154) + c.bezierCurveTo(52,90,84,60,128,60);c.bezierCurveTo(172,60,204,90,188,154) + c.quadraticCurveTo(186,120,180,106);c.quadraticCurveTo(170,108,162,98);c.quadraticCurveTo(154,110,142,110);c.quadraticCurveTo(138,100,130,94) + c.quadraticCurveTo(122,106,110,110);c.quadraticCurveTo(104,100,96,96);c.quadraticCurveTo(88,108,78,106);c.quadraticCurveTo(70,126,68,154);c.closePath();c.fill();c.stroke() + // hard hat + c.fillStyle=HAT;c.beginPath();c.moveTo(60,86);c.bezierCurveTo(56,20,200,20,196,86);c.closePath();c.fill();c.stroke() + c.beginPath();c.moveTo(44,90);c.quadraticCurveTo(128,72,212,90);c.quadraticCurveTo(216,100,206,100);c.quadraticCurveTo(128,86,50,100);c.quadraticCurveTo(40,100,44,90);c.fill();c.stroke() + c.fillStyle=HTD;c.beginPath();c.moveTo(116,34);c.quadraticCurveTo(128,28,140,34);c.lineTo(142,80);c.quadraticCurveTo(128,78,114,80);c.closePath();c.fill();c.stroke() + c.strokeStyle='#fff';c.lineWidth=7;c.beginPath();c.arc(128,90,58,PI*1.2,PI*1.34);c.stroke();c.strokeStyle='#111' + c.restore() + // arm and hammer + const hx=hit?138:134,hy=hit?166:162,ex=hx+54*cos(a),ey=hy+54*sin(a) + ds(c,20,11,SH,()=>{c.moveTo(106,196);c.quadraticCurveTo(128,204,hx,hy+4)}) + ds(c,12,6,WD,()=>{c.moveTo(hx-10*cos(a),hy-10*sin(a));c.lineTo(ex,ey)}) + c.save();c.translate(ex,ey);c.rotate(a);c.fillStyle='#868e96';c.lineWidth=5;c.beginPath();c.roundRect(-10,-22,20,38,4);c.fill();c.stroke();c.fillStyle='#ced4da';c.beginPath();c.rect(-10,10,20,6);c.fill();c.stroke();c.restore() + c.fillStyle=SKIN;c.lineWidth=5;c.beginPath();c.ellipse(hx,hy+2,11,10,0,0,T);c.fill();c.stroke() + if(k==6)for(const j of[0,1])ds(c,7,3,'#fff',()=>{c.arc(hx,hy,66+j*11,-1.7+j*.1,-.9)}) + if(hit){const s=k==7?1:.7;c.fillStyle=SP;c.lineWidth=4;c.beginPath();for(let j=0;j<16;j++){const r=j%2?8*s:20*s,b=j*PI/8;c.lineTo(174+cos(b)*r,124+sin(b)*r)}c.closePath();c.fill();c.stroke() + for(const[d,e]of[[-1.6,1],[-.6,1],[.5,1]])ds(c,7,3,'#fff',()=>{c.moveTo(174+cos(d)*24*s,124+sin(d)*24*s);c.lineTo(174+cos(d)*34*s,124+sin(d)*34*s)})} +} diff --git a/gen/uianime/construction/paint.js b/gen/uianime/construction/paint.js new file mode 100644 index 0000000..ccc6fef --- /dev/null +++ b/gen/uianime/construction/paint.js @@ -0,0 +1,59 @@ +// coral ponytail girl in a paper hat and splattered overalls rolling fresh paint up and down a wall, stripe by stripe +const{cos,PI,max,min,hypot}=Math,T=2*PI +export const frames=20,delay=85 +const SKIN='#ffe3d1',HAIR='#ff8787',HD='#f03e3e',EYE='#339af0',ED='#1864ab',BL='#ffa8a8',OV='#f8f9fa',OVD='#ced4da',TS='#ffd43b',PA='#fff3bf',PB='#a5d8ff',PBD='#74c0fc',HN='#ff922b',MT='#868e96' +const ds=(c,a,b,s,f)=>{for(const[l,k]of[[a,'#111'],[b,s]])c.lineWidth=l,c.strokeStyle=k,c.beginPath(),f(),c.stroke();c.strokeStyle='#111'} +const eye=(c,x,y,d)=>{ + c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill() + c.save();c.clip();c.beginPath();c.ellipse(x+4,y+1,11.5,15,0,0,T);c.fillStyle=EYE;c.fill();c.lineWidth=2.5;c.stroke() + c.fillStyle=ED;c.beginPath();c.ellipse(x+4,y-9,13,9,0,0,T);c.fill() + c.fillStyle='#111';c.beginPath();c.ellipse(x+5,y+2,5.5,7.5,0,0,T);c.fill() + c.fillStyle='#fff';c.beginPath();c.arc(x,y-5,4.5,0,T);c.fill();c.beginPath();c.arc(x+8,y+8,2,0,T);c.fill();c.restore() + c.lineWidth=7;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke() +} +export default(c,t,i)=>{ + // 4 strokes a loop: blue over yellow on both columns, then yellow back over blue + const j=(t*4)|0,u=t*4-j,col=j%2,nw=j<2?PB:PA,dn=u<.5,ry=36+70*(1-cos(T*u)),cx=157.5+col*59 + const pr=k=>min(1,max(0,(t*4-k)*2)) + for(const k of[0,1]){const x=128+k*59,a=pr(k),b=pr(k+2),[bs,ov,h]=b>0?[PB,PA,b]:[PA,PB,a] + c.fillStyle=bs;c.fillRect(x,10,59,194);if(h>0)c.fillStyle=ov,c.fillRect(x,10,59,h<1?ry-8:194)} + c.lineWidth=6;c.beginPath();c.rect(128,10,118,194);c.stroke() + // paint bucket + c.fillStyle='#e9ecef';c.beginPath();c.moveTo(170,214);c.lineTo(240,214);c.lineTo(232,250);c.lineTo(178,250);c.closePath();c.fill();c.stroke() + c.fillStyle=PBD;c.beginPath();c.moveTo(172,222);c.lineTo(238,222);c.lineTo(236,232);c.quadraticCurveTo(226,240,222,232);c.quadraticCurveTo(204,236,190,232);c.quadraticCurveTo(184,242,176,234);c.closePath();c.fill();c.lineWidth=4;c.stroke() + c.lineWidth=6;c.fillStyle='#ced4da';c.beginPath();c.ellipse(205,214,36,7,0,0,T);c.fill();c.stroke() + // girl + c.save();c.translate(64,168);c.scale(.72,.72);c.translate(-128,-186) + c.save();c.translate(70,70);c.rotate(-.4) + c.lineWidth=8;c.fillStyle=HAIR;c.beginPath();c.moveTo(10,0);c.bezierCurveTo(-30,-10,-70,40,-64,120);c.quadraticCurveTo(-58,140,-44,148);c.quadraticCurveTo(-48,90,-4,22);c.closePath();c.fill();c.stroke() + c.strokeStyle=HD;c.lineWidth=4;c.beginPath();c.moveTo(-12,10);c.bezierCurveTo(-40,30,-54,70,-52,118);c.stroke();c.strokeStyle='#111';c.restore() + c.lineWidth=8;c.fillStyle=HD;c.beginPath();c.moveTo(128,36);c.bezierCurveTo(198,36,210,100,202,160);c.lineTo(54,160);c.bezierCurveTo(46,100,58,36,128,36);c.fill();c.stroke() + c.fillStyle=TS;c.beginPath();c.moveTo(100,190);c.quadraticCurveTo(54,198,44,300);c.lineTo(212,300);c.quadraticCurveTo(202,198,156,190);c.closePath();c.fill();c.stroke() + c.fillStyle=OV;c.beginPath();c.moveTo(80,300);c.lineTo(84,238);c.lineTo(172,238);c.lineTo(176,300);c.closePath();c.fill();c.stroke() + for(const d of[-1,1])c.beginPath(),c.moveTo(128+d*44,240),c.lineTo(128+d*34,196),c.lineTo(128+d*22,196),c.lineTo(128+d*30,240),c.closePath(),c.fill(),c.stroke() + c.fillStyle=PBD;c.lineWidth=4;for(const[x,y,r]of[[104,262,7],[150,276,5],[160,254,4]])c.beginPath(),c.arc(x,y,r,0,T),c.fill(),c.stroke() + c.fillStyle=SKIN;c.lineWidth=8;c.beginPath();c.moveTo(116,166);c.lineTo(116,194);c.quadraticCurveTo(128,204,140,194);c.lineTo(140,166);c.fill();c.beginPath();c.moveTo(116,166);c.lineTo(116,192);c.moveTo(140,166);c.lineTo(140,192);c.stroke() + c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + eye(c,103,140,-1);eye(c,153,140,1) + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,162,13,7,0,0,T),c.fill() + c.lineWidth=3;for(const d of[-1,1])for(const k of[-5,0,5])c.beginPath(),c.moveTo(128+d*44+k-2,165),c.lineTo(128+d*44+k+2,159),c.stroke() + c.fillStyle=PBD;c.lineWidth=4;c.beginPath();c.ellipse(90,152,6,5,.3,0,T);c.fill();c.stroke() + c.lineWidth=5;c.fillStyle='#c92a2a';c.beginPath();c.moveTo(118,166);c.quadraticCurveTo(128,170,138,166);c.quadraticCurveTo(136,180,128,180);c.quadraticCurveTo(120,180,118,166);c.fill();c.stroke() + c.lineWidth=8;c.fillStyle=HAIR;c.beginPath();c.moveTo(66,156) + c.bezierCurveTo(50,80,88,46,128,46);c.bezierCurveTo(168,46,206,80,190,156) + c.quadraticCurveTo(188,120,180,104);c.quadraticCurveTo(170,104,164,96);c.quadraticCurveTo(156,108,144,110);c.quadraticCurveTo(140,98,130,92) + c.quadraticCurveTo(122,106,108,110);c.quadraticCurveTo(104,98,96,94);c.quadraticCurveTo(88,106,78,106);c.quadraticCurveTo(68,128,66,156);c.closePath();c.fill();c.stroke() + // folded newspaper hat + c.fillStyle='#fff';c.beginPath();c.moveTo(62,82);c.lineTo(128,18);c.lineTo(194,82);c.closePath();c.fill();c.stroke() + c.strokeStyle=OVD;c.lineWidth=5;c.beginPath();for(const y of[50,64])c.moveTo(128-(y-18)*.8+14,y),c.lineTo(128+(y-18)*.8-14,y);c.stroke();c.strokeStyle='#111' + c.fillStyle=HN;c.beginPath();c.moveTo(56,80);c.lineTo(200,80);c.lineTo(198,98);c.lineTo(58,98);c.closePath();c.fill();c.stroke() + c.restore() + // roller on its pole, hands on the handle + const fx=cx-18,fy=ry+24,L=hypot(124-fx,210-fy),dx=(124-fx)/L,dy=(210-fy)/L,ax=124,ay=210 + ds(c,8,3,MT,()=>{c.moveTo(cx-24,ry);c.lineTo(cx-30,ry);c.lineTo(cx-30,ry+16);c.lineTo(fx,fy)}) + ds(c,14,8,HN,()=>{c.moveTo(fx,fy);c.lineTo(fx+dx*(L+26),fy+dy*(L+26))}) + c.fillStyle=nw;c.lineWidth=5;c.beginPath();c.roundRect(cx-25,ry-12,50,24,8);c.fill();c.stroke() + c.strokeStyle='#fff';c.lineWidth=3.5;c.beginPath();c.moveTo(cx-18,ry-5);c.lineTo(cx+8,ry-5);c.stroke();c.strokeStyle='#111' + ds(c,20,11,TS,()=>{c.moveTo(98,194);c.quadraticCurveTo(114,192,ax,ay)}) + c.fillStyle=SKIN;c.lineWidth=5;c.beginPath();c.ellipse(ax,ay,11,10,0,0,T);c.fill();c.stroke() +} diff --git a/gen/uianime/download/catch.js b/gen/uianime/download/catch.js new file mode 100644 index 0000000..cfce215 --- /dev/null +++ b/gen/uianime/download/catch.js @@ -0,0 +1,61 @@ +// blonde girl with her arms up catching a falling file box with a down arrow, oof squash, a happy beam, then the box poofs into sparkles and she looks up for the next one +const{sin,cos,PI,max,min}=Math,T=2*PI +export const frames=16,delay=80 +const SKIN='#ffe3d1',HAIR='#ffe066',HD='#f59f00',HL='#fff9db',EYE='#20c997',ED='#087f5b',TEE='#b2f2bb',TD='#40c057',BL='#ffa8a8',BAND='#ff6b6b',BOX='#e8b07a',BD='#c47f45',AR='#4dabf7',SP='#ffd43b' +const ds=(c,a,b,s,f)=>{for(const[l,k]of[[a,'#111'],[b,s]])c.lineWidth=l,c.strokeStyle=k,c.beginPath(),f(),c.stroke();c.strokeStyle='#111'} +const eye=(c,x,y,d,gx,gy)=>{ + c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill() + c.save();c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.clip();c.beginPath();c.ellipse(x+gx,y+gy,11.5,15,0,0,T);c.fillStyle=EYE;c.fill();c.lineWidth=2.5;c.stroke() + c.fillStyle=ED;c.beginPath();c.ellipse(x+gx,y+gy-10,13,9,0,0,T);c.fill() + c.fillStyle='#111';c.beginPath();c.ellipse(x+gx,y+gy+1,5.5,7.5,0,0,T);c.fill() + c.fillStyle='#fff';c.beginPath();c.arc(x+gx-4,y+gy-6,4.5,0,T);c.fill();c.beginPath();c.arc(x+gx+5,y+gy+7,2,0,T);c.fill();c.restore() + c.lineWidth=6;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke() +} +const box=(c,x,y,sq)=>{c.save();c.translate(x,y);c.scale(1.2/sq,1.2*sq) + c.fillStyle=BOX;c.lineWidth=6;c.beginPath();c.roundRect(-34,-28,68,56,5);c.fill();c.stroke() + c.fillStyle=BD;c.lineWidth=4;c.beginPath();c.rect(-8,-28,16,18);c.fill();c.stroke() + c.beginPath();c.moveTo(-34,-14);c.lineTo(34,-14);c.stroke() + c.fillStyle='#fff';c.beginPath();c.roundRect(-18,-6,36,28,5);c.fill();c.stroke() + c.fillStyle=AR;c.lineWidth=3.5;c.beginPath();c.moveTo(0,19);c.lineTo(11,8);c.lineTo(4,8);c.lineTo(4,-2);c.lineTo(-4,-2);c.lineTo(-4,8);c.lineTo(-11,8);c.closePath();c.fill();c.stroke() + c.restore()} +const spark=(c,x,y,r)=>{c.beginPath();c.moveTo(x,y-r);for(const[a,b]of[[1,0],[0,1],[-1,0],[0,-1]])c.quadraticCurveTo(x+(a+b)*r*.15,y+(b-a)*r*.15,x+a*r,y+b*r);c.fill();c.stroke()} +export default(c,t)=>{ + const CY=56,u=((t+.1875)%1)/.375,fall=u<1,fy=-45+(CY+45)*(.4*u+.6*u*u) + const oof=t>=.1875&&t<.3125,imp=oof?sin(PI*(t-.1875)/.125):0,hap=t>=.3125&&t<.625,pf=t>=.625&&t<.75?(t-.625)/.125:-1 + const hop=hap?-5*max(0,sin(2*T*(t-.3125)/.3125)):0,by=CY+10*imp+hop,bob=4*imp,look=t<.1875||t>=.75 + const H=f=>{c.save();c.translate(128,200+bob);c.scale(.7,.7);c.translate(-128,-186);f();c.restore()} + H(()=>{ + c.lineWidth=8;c.fillStyle=HD;c.beginPath();c.moveTo(128,34);c.bezierCurveTo(200,34,214,96,206,150);c.quadraticCurveTo(214,200,196,236);c.lineTo(60,236);c.quadraticCurveTo(42,200,50,150);c.bezierCurveTo(42,96,56,34,128,34);c.fill();c.stroke() + c.fillStyle=TEE;c.beginPath();c.moveTo(100,190);c.quadraticCurveTo(52,198,40,330);c.lineTo(216,330);c.quadraticCurveTo(204,198,156,190);c.closePath();c.fill();c.stroke() + c.fillStyle='#fff';c.beginPath();c.moveTo(104,190);c.quadraticCurveTo(128,214,152,190);c.closePath();c.fill();c.stroke() + c.fillStyle=SKIN;c.lineWidth=8;c.beginPath();c.moveTo(114,168);c.lineTo(114,194);c.quadraticCurveTo(128,206,142,194);c.lineTo(142,168);c.fill();c.beginPath();c.moveTo(114,168);c.lineTo(114,192);c.moveTo(142,168);c.lineTo(142,192);c.stroke() + c.fillStyle='#fff';c.beginPath();c.arc(128,262,14,0,T);c.fill();c.stroke();c.fillStyle=TD;c.beginPath();c.arc(128,262,6,0,T);c.fill() + c.lineWidth=8;c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + if(oof){c.lineWidth=8;for(const d of[-1,1])c.beginPath(),c.moveTo(128+d*38,128),c.lineTo(128+d*18,140),c.lineTo(128+d*38,152),c.stroke()} + else if(hap){c.lineWidth=8;for(const x of[103,153])c.beginPath(),c.arc(x,148,15,1.15*PI,1.85*PI),c.stroke()} + else{const g=look?[5,-4]:[6,3];eye(c,103,140,-1,...g);eye(c,153,140,1,...g)} + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,162,14,8,0,0,T),c.fill() + c.lineWidth=4;for(const d of[-1,1])for(const k of[-6,0,6])c.beginPath(),c.moveTo(128+d*44+k-2,166),c.lineTo(128+d*44+k+2,158),c.stroke() + c.lineWidth=6;c.fillStyle='#c92a2a' + if(oof){c.beginPath();c.ellipse(128,170,9,6,0,0,T);c.fill();c.stroke()} + else if(look){c.beginPath();c.ellipse(128,170,6,7,0,0,T);c.fill();c.stroke()} + else{c.beginPath();c.moveTo(114,164);c.quadraticCurveTo(128,188,142,164);c.closePath();c.fill();c.stroke();c.save();c.clip();c.fillStyle='#ff8fab';c.beginPath();c.ellipse(128,180,8,6,0,0,T);c.fill();c.restore()} + c.lineWidth=8;c.fillStyle=HAIR;c.beginPath();c.moveTo(66,154) + c.bezierCurveTo(50,74,88,36,128,36);c.bezierCurveTo(168,36,206,74,190,154) + c.quadraticCurveTo(188,120,180,104);c.quadraticCurveTo(170,96,160,100);c.quadraticCurveTo(152,108,140,108);c.quadraticCurveTo(132,98,128,90) + c.quadraticCurveTo(122,100,114,108);c.quadraticCurveTo(102,108,96,100);c.quadraticCurveTo(86,96,78,104);c.quadraticCurveTo(70,124,66,154);c.closePath();c.fill();c.stroke() + c.strokeStyle=HL;c.lineWidth=7;for(const[s,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,56,PI*s,PI*e),c.stroke() + c.strokeStyle='#111';c.fillStyle=BAND;c.lineWidth=7;c.beginPath();c.moveTo(66,96);c.bezierCurveTo(70,44,186,44,190,96);c.lineTo(180,98);c.bezierCurveTo(176,58,80,58,76,98);c.closePath();c.fill();c.stroke() + if(oof){c.fillStyle='#a5d8ff';c.lineWidth=6;c.beginPath();c.moveTo(196,110);c.quadraticCurveTo(208,128,196,134);c.quadraticCurveTo(184,128,196,110);c.fill();c.stroke()} + }) + const sq=oof?1-.14*imp:1 + if(fall){box(c,128,fy,1);if(u>.2)for(const k of[-1,0,1])ds(c,8,3.5,'#fff',()=>{c.moveTo(128+k*24,fy-46+k*k*8);c.lineTo(128+k*24,fy-70+k*k*8)})} + else if(t<.625)box(c,128,by,sq) + else if(pf>=0){c.save();c.translate(128,CY);c.scale(1-pf,1-pf);box(c,0,0,1);c.restore()} + const hy=fall||pf>=0||look?CY+6:by+6 + for(const d of[-1,1])ds(c,20,11,TEE,()=>{c.moveTo(128+d*44,222+bob);c.quadraticCurveTo(128+d*66,140,128+d*48,hy+8)}) + c.fillStyle=SKIN;c.lineWidth=5;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*48,hy,11,12,0,0,T),c.fill(),c.stroke() + if(oof)for(let k=0;k<5;k++){const a=PI+k*PI/4,r=56+12*imp;ds(c,7,3,'#fff',()=>{c.moveTo(128+cos(a)*r,CY+sin(a)*r*.6);c.lineTo(128+cos(a)*(r+12),CY+sin(a)*(r+12)*.6)})} + if(pf>=0){c.fillStyle=SP;c.lineWidth=3.5;for(let k=0;k<6;k++){const a=k*PI/3+.3,r=20+48*pf;spark(c,128+cos(a)*r,CY+sin(a)*r*.8,13*sin(PI*min(1,pf*1.2+.15)))}} + if(hap){const q=(t-.375)/.3125;c.fillStyle=SP;c.lineWidth=3.5;for(const[x,y,o]of[[208,40,0],[48,62,.2],[214,104,.4]]){const r=sin(PI*min(1,max(0,q*1.4-o)));if(r>.1)spark(c,x,y,12*r)}} +} diff --git a/gen/uianime/error/cry.js b/gen/uianime/error/cry.js new file mode 100644 index 0000000..4a09511 --- /dev/null +++ b/gen/uianime/error/cry.js @@ -0,0 +1,44 @@ +// orange-haired girl bawling over her laptop as a big red X error flashes on the screen, tears gushing into puddles +const{sin,cos,PI,max,abs}=Math,T=2*PI +export const frames=8,delay=90 +const SKIN='#ffe3d1',HAIR='#ffa94d',HD='#e8590c',HL='#fff4e6',HO='#b197fc',HOD='#7950f2',BL='#ffa8a8',MO='#c92a2a',TG='#ff8fab',WA='#74c0fc',LT='#dee2e6',LD='#adb5bd',RD='#fa5252',CL='#ff6b6b',Z=.8 +export default(c,t,i)=>{ + const b=i%2*2,w=sin(2*T*t),L=v=>c.lineWidth=v/Z,fl=i%4<2 + const head=f=>{c.save();c.translate(128,96+b);c.scale(Z,Z);c.translate(-128,-128);f();c.restore()} + head(()=>{ + L(6);c.fillStyle=HD;c.beginPath();c.moveTo(128,34);c.bezierCurveTo(198,34,212,100,204,160);c.quadraticCurveTo(196,180,176,176);c.lineTo(80,176);c.quadraticCurveTo(60,180,52,160);c.bezierCurveTo(44,100,58,34,128,34);c.fill();c.stroke() + c.fillStyle=HO;c.beginPath();c.moveTo(100,190);c.quadraticCurveTo(58,196,48,262);c.lineTo(208,262);c.quadraticCurveTo(198,196,156,190);c.closePath();c.fill();c.stroke() + c.fillStyle=HOD;for(const d of[-1,1])c.beginPath(),c.moveTo(128+d*8,196),c.quadraticCurveTo(128+d*34,190,128+d*46,206),c.quadraticCurveTo(128+d*30,218,128+d*8,210),c.closePath(),c.fill(),c.stroke() + c.fillStyle=SKIN;c.beginPath();c.moveTo(116,166);c.lineTo(116,194);c.lineTo(128,204);c.lineTo(140,194);c.lineTo(140,166);c.fill();L(5);c.beginPath();c.moveTo(116,166);c.lineTo(116,192);c.moveTo(140,166);c.lineTo(140,192);c.stroke() + L(6);c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + L(6.5);for(const d of[-1,1]){const x=128+d*25;c.beginPath();c.moveTo(x-d*14,128);c.lineTo(x+d*9,140);c.lineTo(x-d*14,152);c.stroke()} + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,162,11,5.5,0,0,T),c.fill() + c.save();c.translate(128,170);c.scale(1.2,1.2);c.translate(-128,-170);c.fillStyle=MO;L(3.5);c.beginPath();c.moveTo(114,170+w);c.quadraticCurveTo(118,164-w,121,168+w);c.quadraticCurveTo(124.5,164+w,128,168-w);c.quadraticCurveTo(131.5,164+w,135,168+w);c.quadraticCurveTo(138,164-w,142,170+w);c.quadraticCurveTo(140,184,128,184);c.quadraticCurveTo(116,184,114,170+w);c.fill();c.stroke() + c.save();c.clip();c.fillStyle=TG;c.beginPath();c.ellipse(128,184,8,5,0,0,T);c.fill();c.restore();c.restore() + L(6);c.fillStyle=HAIR;c.beginPath();c.moveTo(66,160) + c.bezierCurveTo(50,74,88,36,128,36);c.bezierCurveTo(168,36,206,74,190,160);c.quadraticCurveTo(182,130,180,108) + c.quadraticCurveTo(172,104,166,112);c.quadraticCurveTo(160,98,150,94);c.quadraticCurveTo(144,104,136,108) + c.quadraticCurveTo(130,96,120,92);c.quadraticCurveTo(114,104,104,108);c.quadraticCurveTo(98,98,88,100);c.quadraticCurveTo(84,108,78,112) + c.quadraticCurveTo(74,134,66,160);c.closePath();c.fill();c.stroke() + c.strokeStyle=HL;L(5);for(const[a,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,56,PI*a,PI*e),c.stroke() + c.strokeStyle='#111';L(5);c.beginPath();c.moveTo(88,118);c.lineTo(114,110);c.moveTo(168,118);c.lineTo(142,110);c.stroke() + c.fillStyle=CL;L(4);c.save();c.translate(170,72);c.rotate(.6);c.beginPath();c.roundRect(-13,-5,26,10,5);c.fill();c.stroke();c.restore() + }) + c.fillStyle=WA;c.lineWidth=5;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*96,240,26,9,0,0,T),c.fill(),c.stroke() + c.lineWidth=6;c.fillStyle=LD;c.beginPath();c.moveTo(48,236);c.lineTo(208,236);c.lineTo(216,250);c.lineTo(40,250);c.closePath();c.fill();c.stroke() + c.fillStyle=LT;c.beginPath();c.roundRect(60,146,136,94,10);c.fill();c.stroke() + c.fillStyle=fl?'#fff5f5':'#fff';c.beginPath();c.roundRect(72,156,112,72,4);c.fill();c.lineWidth=4;c.stroke() + const s=fl?1.08:1;c.save();c.translate(128,192);c.scale(s,s) + for(const[l,k]of[[22,'#111'],[12,RD]])c.lineWidth=l,c.strokeStyle=k,c.beginPath(),c.moveTo(-22,-22),c.lineTo(22,22),c.moveTo(22,-22),c.lineTo(-22,22),c.stroke() + c.restore();c.strokeStyle='#111' + for(const d of[-1,1]){c.fillStyle=SKIN;c.lineWidth=5;c.beginPath();c.ellipse(128+d*66,150,11,14,d*.3,0,T);c.fill();c.stroke()} + head(()=>{ + for(const d of[-1,1]){ + const arc=()=>{c.beginPath();c.moveTo(128+d*40,146);c.bezierCurveTo(128+d*90,104,128+d*128,150,128+d*120,240)} + for(const[lw,s]of[[17,'#111'],[9,WA]])L(lw*Z),c.strokeStyle=s,arc(),c.stroke() + c.strokeStyle='#fff';L(3*Z);c.setLineDash([8,16]);c.lineDashOffset=-t*48;arc();c.stroke();c.setLineDash([]) + } + }) + c.strokeStyle='#111';c.fillStyle=WA;c.lineWidth=3.5 + for(const d of[-1,1])for(const o of[0,.33,.66]){const p=(t*2+o)%1,x=128+d*(96+(o>.5?-1:1)*22*p),y=234-34*p+40*p*p;c.beginPath();c.arc(x,y,5*(1-p*.5),0,T);c.fill();c.stroke()} +} diff --git a/gen/uianime/error/smoke.js b/gen/uianime/error/smoke.js new file mode 100644 index 0000000..2b003ab --- /dev/null +++ b/gen/uianime/error/smoke.js @@ -0,0 +1,39 @@ +// blue-haired girl in glasses and a lab coat coughing into her fist as gray smoke billows out of her crashed computer +const{sin,cos,PI,max,min}=Math,T=2*PI +export const frames=12,delay=90 +const SKIN='#ffe3d1',HAIR='#5c7cfa',HD='#3b5bdb',HL='#dbe4ff',CO='#fff',SH='#a5d8ff',BL='#ffa8a8',PC='#e9d8a6',PD='#c9b37e',SC='#495057',SM='#ced4da',SMD='#adb5bd',SW='#a5d8ff',SP='#ffd43b',Z=.76 +const puff=(c,x,y,r,f)=>{c.beginPath();for(const[a,b,s]of[[-.8,0,.7],[0,-.5,.8],[.8,0,.7],[0,.3,.75]])c.moveTo(x+a*r+s*r,y+b*r),c.arc(x+a*r,y+b*r,s*r,0,T);c.lineWidth=9;c.strokeStyle='#111';c.stroke();c.fillStyle=f;c.fill()} +export default(c,t,i)=>{ + const k=max(0,sin(2*T*t))**2,L=v=>c.lineWidth=v/Z,fl=i%3==0 + const head=f=>{c.save();c.translate(158,112+5*k);c.rotate(-.12*k);c.scale(Z,Z);c.translate(-128,-128);f();c.restore()} + head(()=>{ + L(6);c.fillStyle=HD;c.beginPath();c.moveTo(128,34);c.bezierCurveTo(198,34,212,96,206,150);c.lineTo(212,320);c.lineTo(44,320);c.lineTo(50,150);c.bezierCurveTo(44,96,58,34,128,34);c.fill();c.stroke() + c.fillStyle=CO;c.beginPath();c.moveTo(100,190);c.quadraticCurveTo(58,196,46,320);c.lineTo(210,320);c.quadraticCurveTo(198,196,156,190);c.closePath();c.fill();c.stroke() + c.fillStyle=SH;c.beginPath();c.moveTo(108,190);c.lineTo(128,236);c.lineTo(148,190);c.closePath();c.fill();c.stroke() + L(5);for(const d of[-1,1])c.beginPath(),c.moveTo(128+d*20,188),c.lineTo(128+d*34,214),c.lineTo(128+d*22,218),c.lineTo(128,250),c.stroke() + c.fillStyle=SKIN;c.beginPath();c.moveTo(116,166);c.lineTo(116,194);c.lineTo(128,206);c.lineTo(140,194);c.lineTo(140,166);c.fill();L(5);c.beginPath();c.moveTo(116,166);c.lineTo(116,192);c.moveTo(140,166);c.lineTo(140,192);c.stroke() + L(6);c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + L(6.5);for(const d of[-1,1]){const x=128+d*25;c.beginPath();c.moveTo(x-d*13,130);c.lineTo(x+d*9,140);c.lineTo(x-d*13,150);c.stroke()} + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,162,11,5.5,0,0,T),c.fill() + for(const[w,s]of[[8,'#111'],[3.5,'#fab005']]){c.strokeStyle=s;L(w);for(const x of[103,153])c.beginPath(),c.arc(x,140,22,0,T),c.stroke();c.beginPath();c.moveTo(123,136);c.quadraticCurveTo(128,131,133,136);c.stroke()} + c.strokeStyle='#111';L(6);c.fillStyle=HAIR;c.beginPath();c.moveTo(66,170) + c.bezierCurveTo(50,74,88,36,128,36);c.bezierCurveTo(168,36,206,74,190,170) + c.quadraticCurveTo(184,130,180,104);c.quadraticCurveTo(172,100,164,112);c.quadraticCurveTo(158,96,146,92);c.quadraticCurveTo(140,104,130,108) + c.quadraticCurveTo(124,96,112,92);c.quadraticCurveTo(106,104,96,108);c.quadraticCurveTo(90,98,82,102) + c.quadraticCurveTo(72,130,66,170);c.closePath();c.fill();c.stroke() + c.strokeStyle=HL;L(5);for(const[a,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,56,PI*a,PI*e),c.stroke() + c.strokeStyle='#111';L(4.5);c.beginPath();c.moveTo(88,112);c.lineTo(114,118);c.moveTo(168,112);c.lineTo(142,118);c.stroke() + c.fillStyle=SW;L(4);const sy=96+4*k;c.beginPath();c.moveTo(196,sy-14);c.quadraticCurveTo(206,sy,196,sy+7);c.quadraticCurveTo(186,sy,196,sy-14);c.fill();c.stroke() + }) + for(const[w,s]of[[28,'#111'],[17,CO]])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.moveTo(118,262),c.quadraticCurveTo(110,200,140,170+4*k),c.stroke() + c.strokeStyle='#111';c.lineWidth=5;c.fillStyle=SKIN;c.beginPath();c.roundRect(130,146+4*k,28,26,10);c.fill();c.stroke() + c.lineWidth=2.5;c.beginPath();for(const y of[154,161])c.moveTo(150,y+4*k),c.lineTo(158,y+4*k);c.stroke() + if(k>.2)for(const[w,s]of[[9,'#111'],[4,'#fff']]){c.lineWidth=w;c.strokeStyle=s;for(const a of[-.6,0,.6])c.beginPath(),c.moveTo(144-22*cos(a),160+4*k+22*sin(a)),c.lineTo(144-(26+16*k)*cos(a),160+4*k+(26+16*k)*sin(a)),c.stroke()} + c.strokeStyle='#111' + c.lineWidth=6;c.fillStyle=PD;c.beginPath();c.moveTo(44,226);c.lineTo(92,226);c.lineTo(104,248);c.lineTo(32,248);c.closePath();c.fill();c.stroke() + c.fillStyle=PC;c.beginPath();c.roundRect(10,122,116,106,12);c.fill();c.stroke() + c.fillStyle=fl?'#868e96':SC;c.beginPath();c.roundRect(24,136,88,70,8);c.fill();c.lineWidth=5;c.stroke() + for(const[w,s]of[[9,'#111'],[4,'#fff']])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.moveTo(44,140),c.lineTo(58,160),c.lineTo(50,172),c.lineTo(66,202),c.stroke() + c.strokeStyle='#111';c.lineWidth=4;c.fillStyle=SP;for(const[x,y]of[[96,130],[22,140]])if((i+(x>50?0:1))%2)c.beginPath(),c.moveTo(x,y-11),c.lineTo(x+4,y-3),c.lineTo(x+12,y),c.lineTo(x+4,y+3),c.lineTo(x,y+11),c.lineTo(x-4,y+3),c.lineTo(x-12,y),c.lineTo(x-4,y-3),c.closePath(),c.fill(),c.stroke() + for(let n=3;n>=0;n--){const p=(t+n/4)%1;puff(c,56+96*p+10*sin(T*p),108-90*p,(12+18*p)*min(1,(1-p)*5),n%2?SM:SMD)} +} diff --git a/gen/uianime/error/tehe.js b/gen/uianime/error/tehe.js new file mode 100644 index 0000000..df79a03 --- /dev/null +++ b/gen/uianime/error/tehe.js @@ -0,0 +1,51 @@ +// blonde girl with twin buns doing a tehepero oops: winking, tongue out, bonking her own head with her fist so little stars pop +const{sin,cos,PI,abs,max}=Math,T=2*PI +export const frames=8,delay=100 +const SKIN='#ffe3d1',HAIR='#ffe066',HD='#f59f00',HL='#fff9db',EYE='#f783ac',ED='#c2255c',UN='#fff',COL='#364fc7',RB='#fa5252',BL='#ffa8a8',TG='#ff8fab',ST='#ffd43b' +const eye=(c,x,y,d)=>{ + c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill() + c.save();c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.clip();c.fillStyle=EYE;c.fill();c.fillStyle=ED;c.beginPath();c.ellipse(x,y-8,13,10,0,0,T);c.fill();c.restore() + c.lineWidth=2.5;c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.stroke() + c.fillStyle='#111';c.beginPath();c.ellipse(x,y+3,5.5,7.5,0,0,T);c.fill() + c.fillStyle='#fff';c.beginPath();c.arc(x-4,y-5,4.5,0,T);c.fill();c.beginPath();c.arc(x+5,y+8,2,0,T);c.fill() + c.lineWidth=6;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke() +} +const star=(c,x,y,r,a)=>{c.save();c.translate(x,y);c.rotate(a);c.beginPath();for(let k=0;k<10;k++){const rr=k%2?r*.45:r,b=k*PI/5-PI/2;c.lineTo(cos(b)*rr,sin(b)*rr)}c.closePath();c.restore();c.fill();c.stroke()} +export default(c,t)=>{ + const u=abs(sin(2*PI*t)),hit=u<.5,tl=.07*(1-u) + const head=f=>{c.save();c.translate(128,186);c.rotate(-tl);c.translate(-128,-186);f();c.restore()} + head(()=>{ + c.lineWidth=6;c.fillStyle=HD;c.beginPath();c.moveTo(128,34);c.bezierCurveTo(196,34,208,100,200,156);c.quadraticCurveTo(196,178,178,176);c.lineTo(78,176);c.quadraticCurveTo(60,178,56,156);c.bezierCurveTo(48,100,60,34,128,34);c.fill();c.stroke() + c.fillStyle=HAIR;for(const d of[-1,1])c.beginPath(),c.arc(128+d*54,52,25,0,T),c.fill(),c.stroke() + c.strokeStyle=HD;c.lineWidth=3.5;for(const d of[-1,1])c.beginPath(),c.arc(128+d*54,52,14,PI*1.1,PI*1.7),c.stroke();c.strokeStyle='#111' + }) + c.lineWidth=6;c.fillStyle=UN;c.beginPath();c.moveTo(100,188);c.quadraticCurveTo(62,196,54,250);c.lineTo(202,250);c.quadraticCurveTo(194,196,156,188);c.closePath();c.fill();c.stroke() + c.fillStyle=COL;c.beginPath();c.moveTo(98,189);c.lineTo(128,228);c.lineTo(158,189);c.lineTo(172,197);c.lineTo(128,248);c.lineTo(84,197);c.closePath();c.fill();c.lineWidth=5;c.stroke() + c.strokeStyle='#fff';c.lineWidth=3;c.beginPath();c.moveTo(90,198);c.lineTo(128,240);c.lineTo(166,198);c.stroke();c.strokeStyle='#111' + c.fillStyle=SKIN;c.beginPath();c.moveTo(116,166);c.lineTo(116,192);c.lineTo(128,206);c.lineTo(140,192);c.lineTo(140,166);c.fill();c.beginPath();c.moveTo(116,166);c.lineTo(116,190);c.moveTo(140,166);c.lineTo(140,190);c.stroke() + c.fillStyle=RB;for(const d of[-1,1])c.beginPath(),c.moveTo(128,226),c.lineTo(128+d*20,216),c.lineTo(128+d*18,238),c.closePath(),c.fill(),c.stroke() + c.beginPath();c.arc(128,227,5,0,T);c.fill();c.stroke() + head(()=>{ + c.lineWidth=6;c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + eye(c,103,140,-1) + c.lineWidth=6;c.beginPath();c.moveTo(166,128);c.lineTo(144,140);c.lineTo(166,152);c.stroke() + c.lineWidth=2.5;c.beginPath();c.moveTo(128,156);c.lineTo(127,159);c.stroke() + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*42,161,12,6,0,0,T),c.fill() + c.lineWidth=2.5;for(const d of[-1,1])for(const k of[-5,0,5])c.beginPath(),c.moveTo(128+d*42+k-2,164),c.lineTo(128+d*42+k+2,158),c.stroke() + c.fillStyle=TG;c.lineWidth=3.5;c.beginPath();c.moveTo(126,168);c.lineTo(126,176+2*u);c.arc(132,176+2*u,6,PI,0,true);c.lineTo(138,168);c.fill();c.stroke() + c.lineWidth=1.8;c.beginPath();c.moveTo(132,170);c.lineTo(132,177+2*u);c.stroke() + c.lineWidth=3.5;c.beginPath();c.moveTo(116,166);c.quadraticCurveTo(128,174,142,164);c.stroke() + c.lineWidth=6;c.fillStyle=HAIR;c.beginPath();c.moveTo(70,156) + c.bezierCurveTo(54,74,88,36,128,36);c.bezierCurveTo(168,36,202,74,186,156) + c.quadraticCurveTo(184,120,178,104);c.quadraticCurveTo(170,102,164,110);c.quadraticCurveTo(160,96,148,92);c.quadraticCurveTo(142,104,132,108) + c.quadraticCurveTo(126,94,114,92);c.quadraticCurveTo(108,104,98,108);c.quadraticCurveTo(92,98,82,102) + c.quadraticCurveTo(72,124,70,156);c.closePath();c.fill();c.stroke() + c.strokeStyle=HL;c.lineWidth=5;for(const[a,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,56,PI*a,PI*e),c.stroke() + c.strokeStyle='#111';c.lineWidth=4;c.beginPath();c.moveTo(144,114);c.lineTo(166,108);c.stroke() + }) + const fx=196+14*u,fy=96-12*u + for(const[w,s]of[[30,'#111'],[19,UN]])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.moveTo(186,262),c.quadraticCurveTo(222,214,226,176),c.lineTo(fx+8,fy+14),c.stroke() + c.strokeStyle='#111';c.lineWidth=5;c.fillStyle=COL;c.save();c.translate(fx+10,fy+20);c.rotate(.9-.3*u);c.beginPath();c.roundRect(-14,-6,28,12,4);c.fill();c.stroke();c.restore() + c.fillStyle=SKIN;c.save();c.translate(fx,fy);c.rotate(.5);c.beginPath();c.roundRect(-17,-15,34,30,12);c.fill();c.stroke();c.lineWidth=2.5;c.beginPath();for(const k of[-6,1,8])c.moveTo(k,-13),c.lineTo(k,-5);c.stroke();c.restore() + if(hit){c.fillStyle=ST;c.lineWidth=4;for(const[a,r]of[[-2,15],[-1.1,12],[-.2,10]]){const q=1-u*1.6;star(c,fx-4+cos(a)*(28+14*(1-q)),fy-8+sin(a)*(28+14*(1-q)),r*q,a)}} +} diff --git a/gen/uianime/folder/dust.js b/gen/uianime/folder/dust.js new file mode 100644 index 0000000..14b609c --- /dev/null +++ b/gen/uianime/folder/dust.js @@ -0,0 +1,48 @@ +// lavender haired office girl in round glasses flips open an old folder, a cloud of dust bursts out and she squeezes her eyes shut coughing +const{sin,cos,PI,max,min}=Math,T=2*PI +export const frames=20,delay=85 +const SKIN='#ffe3d1',HAIR='#b197fc',HD='#845ef7',HL='#e5dbff',EYE='#845ef7',ED='#5f3dc4',BL='#ffa8a8',JK='#748ffc',TIE='#fa5252',FD='#ffd8a8',FDD='#e0a96d',DU='#e9ecef',MO='#c92a2a' +const E=x=>x<=0?0:x>=1?1:x*x*(3-2*x) +const ds=(c,a,b,s,f)=>{for(const[l,k]of[[a,'#111'],[b,s]])c.lineWidth=l,c.strokeStyle=k,c.beginPath(),f(),c.stroke();c.strokeStyle='#111'} +const puff=(c,x,y,s)=>{c.fillStyle=DU;c.lineWidth=4;c.beginPath();for(const[ox,oy,r]of[[-10,3,10],[2,-5,12],[13,4,9]])c.moveTo(x+(ox+r)*s,y+oy*s),c.arc(x+ox*s,y+oy*s,r*s,0,T);c.stroke();c.fill()} +const eye=(c,x,y,d)=>{ + c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill() + c.save();c.clip();c.beginPath();c.ellipse(x,y+3,11.5,15,0,0,T);c.fillStyle=EYE;c.fill();c.lineWidth=2.5;c.stroke() + c.fillStyle=ED;c.beginPath();c.ellipse(x,y-7,13,9,0,0,T);c.fill() + c.fillStyle='#111';c.beginPath();c.ellipse(x,y+4,5.5,7.5,0,0,T);c.fill() + c.fillStyle='#fff';c.beginPath();c.arc(x-4,y-3,4.5,0,T);c.fill();c.beginPath();c.arc(x+5,y+9,2,0,T);c.fill();c.restore() + c.lineWidth=7;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke() +} +export default(c,t,i)=>{ + const op=E((t-.14)/.1)-E((t-.84)/.1),du=t>.24&&t<.86,cg=t>.3&&t<.84,jl=cg&&i%3==0?1:0,dz=E((t-.24)/.2)*(1-E((t-.62)/.22)) + c.save();c.translate(128,150+3*jl);c.scale(.76,.76);c.translate(-128,-186) + c.lineWidth=8;c.fillStyle=HD;c.beginPath();c.moveTo(128,34);c.bezierCurveTo(200,34,214,104,206,180);c.quadraticCurveTo(206,214,184,212);c.lineTo(72,212);c.quadraticCurveTo(50,214,50,180);c.bezierCurveTo(42,104,56,34,128,34);c.fill();c.stroke() + c.fillStyle=JK;c.beginPath();c.moveTo(100,190);c.quadraticCurveTo(54,198,44,300);c.lineTo(212,300);c.quadraticCurveTo(202,198,156,190);c.closePath();c.fill();c.stroke() + c.fillStyle='#fff';c.beginPath();c.moveTo(104,190);c.lineTo(128,240);c.lineTo(152,190);c.closePath();c.fill();c.stroke() + c.fillStyle=SKIN;c.beginPath();c.moveTo(116,166);c.lineTo(116,192);c.lineTo(128,204);c.lineTo(140,192);c.lineTo(140,166);c.fill();c.beginPath();c.moveTo(116,166);c.lineTo(116,190);c.moveTo(140,166);c.lineTo(140,190);c.stroke() + c.fillStyle=TIE;c.lineWidth=6;c.beginPath();c.moveTo(122,206);c.lineTo(134,206);c.lineTo(138,236);c.lineTo(128,246);c.lineTo(118,236);c.closePath();c.fill();c.stroke() + c.lineWidth=8;c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + if(cg){c.lineWidth=7;c.beginPath();c.moveTo(91,130);c.lineTo(113,141);c.lineTo(91,151);c.moveTo(165,130);c.lineTo(143,141);c.lineTo(165,151);c.stroke() + c.lineWidth=5;c.fillStyle=MO;c.beginPath();c.ellipse(128,172,jl?11:8,jl?11:6,0,0,T);c.fill();c.stroke()} + else{eye(c,103,140,-1);eye(c,153,140,1);c.lineWidth=5;c.beginPath();c.moveTo(121,170);c.quadraticCurveTo(128,166,135,170);c.stroke()} + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*46,164,12,6,0,0,T),c.fill() + c.lineWidth=6;c.beginPath();for(const x of[103,153])c.moveTo(x+23,140),c.arc(x,140,23,0,T);c.moveTo(126,138);c.quadraticCurveTo(128,134,130,138);c.stroke() + c.strokeStyle='#fff';c.lineWidth=4;c.beginPath();for(const x of[103,153])c.moveTo(x+12,124),c.lineTo(x+17,129);c.stroke();c.strokeStyle='#111' + c.lineWidth=8;c.fillStyle=HAIR;c.beginPath();c.moveTo(66,160) + c.bezierCurveTo(48,74,88,38,128,38);c.bezierCurveTo(168,38,208,74,190,160) + c.quadraticCurveTo(188,124,182,108);c.quadraticCurveTo(174,110,166,100);c.quadraticCurveTo(158,110,146,112);c.quadraticCurveTo(140,100,130,96) + c.quadraticCurveTo(122,108,110,112);c.quadraticCurveTo(104,102,96,98);c.quadraticCurveTo(88,108,76,108);c.quadraticCurveTo(68,128,66,160);c.closePath();c.fill();c.stroke() + c.strokeStyle=HL;c.lineWidth=7;for(const[a,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,56,PI*a,PI*e),c.stroke() + c.strokeStyle='#111';c.restore() + // folder: back, empty inside, cover flipping up on its top edge + c.lineWidth=6;c.fillStyle=FDD;c.beginPath();c.moveTo(56,182);c.lineTo(56,250);c.lineTo(200,250);c.lineTo(200,182);c.lineTo(122,182);c.lineTo(112,166);c.lineTo(66,166);c.quadraticCurveTo(56,166,56,176);c.closePath();c.fill();c.stroke() + c.fillStyle='#f4c38a';c.lineWidth=4;c.beginPath();c.rect(62,190,132,54);c.fill() + const s=1-1.45*op + c.save();c.translate(0,190);c.scale(1,s);c.beginPath();c.rect(56,0,144,60);c.restore() + c.fillStyle=s>0?FD:'#fff0d6';c.lineWidth=6;c.fill();c.stroke() + c.fillStyle=SKIN;c.lineWidth=5;for(const x of[56,200])c.beginPath(),c.ellipse(x,224,11,13,0,0,T),c.fill(),c.stroke() + // dust bursting up into her face + if(du){for(const[x0,y0,dx,dy,o]of[[96,190,-50,-96,0],[128,196,0,-40,.12],[160,190,50,-96,.06],[104,196,-72,-40,.2],[152,196,72,-44,.16]]){const p=min(1,max(0,(t-.24-o*.4)/.4)),s2=(.4+.9*p)*(1-E((t-.62)/.22));if(s2>.08)puff(c,x0+dx*p,y0+dy*p,s2)} + c.fillStyle='#adb5bd';c.lineWidth=2.5;for(let k=0;k<8;k++){const p=(t*3+k/8)%1,x=128+cos(k*2.3)*(30+70*p),y=190-90*p+20*sin(k);if(dz>.1)c.beginPath(),c.arc(x,y,3*dz,0,T),c.fill(),c.stroke()}} + if(cg&&jl)for(const d of[-1,1])ds(c,7,3,'#fff',()=>{c.moveTo(128+d*30,128);c.lineTo(128+d*44,120)}) +} diff --git a/gen/uianime/loading/fishing.js b/gen/uianime/loading/fishing.js new file mode 100644 index 0000000..61cfa27 --- /dev/null +++ b/gen/uianime/loading/fishing.js @@ -0,0 +1,56 @@ +// patient green-haired girl in a straw hat fishing from the shore, her bobber bobbing on the pond with spreading ripples while she waits for a bite +const{sin,cos,PI,max,min,exp}=Math,T=2*PI +export const frames=16,delay=90 +const SKIN='#ffe3d1',HAIR='#69db7c',HD='#2f9e44',HL='#d3f9d8',EYE='#a9744f',ED='#6f4518',HAT='#ffe066',HTD='#e8b93c',RIB='#fa5252',TOP='#ff8fab',TD='#f06595',WAT='#a5d8ff',WD='#74c0fc',ROD='#a9744f',BL='#ffa8a8',Z=.8 +const eye=(c,x,y,d)=>{ + c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill() + c.save();c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.clip();c.beginPath();c.ellipse(x+4,y+4,11.5,15,0,0,T);c.fillStyle=EYE;c.fill();c.lineWidth=2.5;c.stroke() + c.fillStyle=ED;c.beginPath();c.ellipse(x+4,y-6,13,10,0,0,T);c.fill() + c.fillStyle='#111';c.beginPath();c.ellipse(x+5,y+6,5.5,7.5,0,0,T);c.fill() + c.fillStyle='#fff';c.beginPath();c.arc(x,y-1,4.5,0,T);c.fill();c.beginPath();c.arc(x+9,y+10,2,0,T);c.fill();c.restore() + c.lineWidth=7;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke() +} +export default(c,t,i)=>{ + const nb=i==9||i==11,by=210+4*sin(2*T*t)+(nb?10:0),bx=196,tx=234,ty=34,bk=i==4 + c.lineWidth=6;c.fillStyle=WAT;c.beginPath();c.ellipse(178,218,72,30,0,0,T);c.fill();c.stroke() + c.save();c.clip();c.fillStyle='#4dabf7';const fa=T*t,fx=184+34*cos(fa),fy=224+8*sin(fa),fd=-sin(fa)<0?-1:1;c.beginPath();c.ellipse(fx,fy,14,6,0,0,T);c.moveTo(fx-fd*12,fy);c.lineTo(fx-fd*22,fy-6);c.lineTo(fx-fd*22,fy+6);c.fill();c.restore() + c.strokeStyle=WD;c.lineWidth=4;c.beginPath();c.moveTo(126,230);c.lineTo(146,230);c.moveTo(214,238);c.lineTo(232,238);c.stroke() + c.strokeStyle='#fff';for(const o of[0,.5]){const p=(t*2+o)%1;c.lineWidth=4*(1-p)+.5;c.beginPath();c.ellipse(bx,214,14+26*p,4+9*p,0,0,T);c.stroke()} + c.strokeStyle='#111' + for(const[w,s]of[[5,'#111'],[2,'#fff']])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.moveTo(tx,ty),c.quadraticCurveTo(tx+2,ty+100,bx,by-18),c.stroke() + c.strokeStyle='#111';c.lineWidth=4;c.beginPath();c.moveTo(bx,by-18);c.lineTo(bx,by-9);c.stroke() + c.save();c.beginPath();c.arc(bx,by,13,0,T);c.clip();c.fillStyle='#fff';c.fill();c.fillStyle=RIB;c.fillRect(bx-14,by-14,28,14);c.restore() + c.lineWidth=5;c.beginPath();c.arc(bx,by,13,0,T);c.stroke();c.beginPath();c.moveTo(bx-13,by);c.lineTo(bx+13,by);c.stroke();c.strokeStyle='#fff';c.lineWidth=3.5;c.beginPath();c.arc(bx,by,7,PI*1.15,PI*1.45);c.stroke();c.strokeStyle='#111' + c.save();c.beginPath();c.rect(bx-20,by+3,40,20);c.clip();c.fillStyle=WAT;c.beginPath();c.ellipse(bx,by+12,17,8,0,0,T);c.fill();c.restore() + if(nb){c.fillStyle=WAT;c.lineWidth=3.5;for(const d of[-1,1]){c.beginPath();c.ellipse(bx+d*22,196,4,6,d*.5,0,T);c.fill();c.stroke()}} + c.save();c.translate(86,262);c.scale(Z,Z);c.translate(-128,-262) + c.lineWidth=7;c.fillStyle=HD;c.beginPath();c.moveTo(128,36);c.bezierCurveTo(196,36,206,96,198,150);c.lineTo(58,150);c.bezierCurveTo(50,96,60,36,128,36);c.fill();c.stroke() + c.fillStyle=TOP;c.beginPath();c.moveTo(100,190);c.quadraticCurveTo(62,198,54,262);c.lineTo(202,262);c.quadraticCurveTo(194,198,156,190);c.closePath();c.fill();c.stroke() + c.fillStyle='#fff';c.beginPath();c.moveTo(104,190);c.quadraticCurveTo(110,212,128,206);c.quadraticCurveTo(146,212,152,190);c.closePath();c.fill();c.lineWidth=6;c.stroke() + c.fillStyle=SKIN;c.beginPath();c.moveTo(116,168);c.lineTo(116,194);c.quadraticCurveTo(128,204,140,194);c.lineTo(140,168);c.fill();c.beginPath();c.moveTo(116,168);c.lineTo(116,192);c.moveTo(140,168);c.lineTo(140,192);c.stroke() + c.fillStyle=HAIR;c.lineWidth=7;for(let k=4;k>=0;k--)c.beginPath(),c.ellipse(64+k*2,156+k*16,12-k*.5,10,k%2?.5:-.5,0,T),c.fill(),c.stroke() + c.fillStyle=RIB;c.lineWidth=5;c.beginPath();c.ellipse(72,236,9,6,0,0,T);c.fill();c.stroke() + c.lineWidth=7;c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + if(bk){c.lineWidth=6;for(const x of[103,153])c.beginPath(),c.moveTo(x-14,144),c.quadraticCurveTo(x,151,x+14,144),c.stroke()} + else{eye(c,103,140,-1);eye(c,153,140,1)} + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*42,162,12,6,0,0,T),c.fill() + c.lineWidth=3;for(const d of[-1,1])for(const k of[-5,0,5])c.beginPath(),c.moveTo(128+d*42+k-2,165),c.lineTo(128+d*42+k+2,159),c.stroke() + c.lineWidth=4;c.beginPath();c.arc(130,164,7,.15*PI,.85*PI);c.stroke() + c.lineWidth=7;c.fillStyle=HAIR;c.beginPath();c.moveTo(70,146) + c.bezierCurveTo(54,74,88,36,128,36);c.bezierCurveTo(168,36,202,74,186,146) + c.quadraticCurveTo(186,116,178,102);c.quadraticCurveTo(170,104,164,112);c.quadraticCurveTo(160,98,150,92);c.quadraticCurveTo(144,104,136,110) + c.quadraticCurveTo(132,96,124,90);c.quadraticCurveTo(118,102,110,108);c.quadraticCurveTo(106,96,96,94);c.quadraticCurveTo(90,104,86,112) + c.quadraticCurveTo(80,104,78,102);c.quadraticCurveTo(70,120,70,146);c.closePath();c.fill();c.stroke() + c.save();c.translate(128,58);c.rotate(-.12) + c.fillStyle=HAT;c.beginPath();c.ellipse(0,8,90,19,0,0,T);c.fill();c.stroke() + c.beginPath();c.moveTo(-52,10);c.bezierCurveTo(-52,-44,52,-44,52,10);c.quadraticCurveTo(0,20,-52,10);c.fill();c.stroke() + c.fillStyle=RIB;c.beginPath();c.moveTo(-52,-2);c.quadraticCurveTo(0,8,52,-2);c.lineTo(52,10);c.quadraticCurveTo(0,20,-52,10);c.closePath();c.fill();c.stroke() + c.strokeStyle=HTD;c.lineWidth=4;c.beginPath();c.ellipse(0,8,76,13,0,.1*PI,.9*PI);c.stroke() + c.strokeStyle='#fff';c.lineWidth=6;c.beginPath();c.arc(0,4,36,PI*1.2,PI*1.42);c.stroke();c.strokeStyle='#111' + c.restore() + c.restore() + for(const[w,s]of[[13,'#111'],[6,ROD]])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.moveTo(122,236),c.lineTo(tx,ty),c.stroke() + c.strokeStyle='#111';c.fillStyle='#ced4da';c.lineWidth=4.5;c.beginPath();c.arc(140,210,9,0,T);c.fill();c.stroke() + for(const[l,s]of[[28,'#111'],[17,TOP]])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),c.moveTo(96,262),c.lineTo(124,228),c.moveTo(170,262),c.lineTo(148,204),c.stroke() + c.strokeStyle='#111';c.lineWidth=5;c.fillStyle=SKIN;for(const[x,y]of[[126,226],[148,202]])c.beginPath(),c.ellipse(x,y,11,10,-.6,0,T),c.fill(),c.stroke() +} diff --git a/gen/uianime/loading/pray.js b/gen/uianime/loading/pray.js new file mode 100644 index 0000000..0a2bb6c --- /dev/null +++ b/gen/uianime/loading/pray.js @@ -0,0 +1,37 @@ +// purple haired shrine maiden squeezing her eyes shut and praying hard while a ring of loading dots spins around her and sparkles twinkle +const{sin,cos,PI,min}=Math,T=2*PI +export const frames=12,delay=80 +const SKIN='#ffe3d1',HAIR='#9775fa',HD='#6741d9',HL='#e5dbff',RED='#fa5252',BL='#ff8fab',SW='#a5d8ff',DOT=['#fd7e14','#fcc419','#ffe066','#fff3bf'] +const ds=(c,a,b,s,f)=>{for(const[l,k]of[[a,'#111'],[b,s]])c.lineWidth=l,c.strokeStyle=k,c.beginPath(),f(),c.stroke();c.strokeStyle='#111'} +const spark=(c,x,y,r)=>{c.beginPath();c.moveTo(x,y-r);for(const[a,b]of[[1,0],[0,1],[-1,0],[0,-1]])c.quadraticCurveTo(x+(a+b)*r*.15,y+(b-a)*r*.15,x+a*r,y+b*r);c.fill();c.stroke()} +export default(c,t,i)=>{ + const n=12 + for(let k=0;k{c.lineWidth=3.5;for(const[x,y,o,f]of a){c.fillStyle=f;const s=sin(T*((t+o)%1));if(s>0)spark(c,x,y,19*s)}} + sp([[28,30,0,'#fff'],[228,32,.5,'#ffe066']]) + c.lineWidth=6;c.fillStyle=HD;c.beginPath();c.moveTo(128,34);c.bezierCurveTo(198,34,212,96,206,150);c.lineTo(212,250);c.lineTo(44,250);c.lineTo(50,150);c.bezierCurveTo(44,96,58,34,128,34);c.fill();c.stroke() + c.fillStyle='#fff';c.beginPath();c.moveTo(100,190);c.quadraticCurveTo(62,198,54,250);c.lineTo(202,250);c.quadraticCurveTo(194,198,156,190);c.closePath();c.fill();c.stroke() + ds(c,16,8,RED,()=>{c.moveTo(102,192);c.lineTo(128,236);c.lineTo(154,192)}) + c.lineWidth=5;c.beginPath();c.moveTo(94,194);c.lineTo(132,250);c.moveTo(162,194);c.lineTo(128,240);c.stroke() + c.fillStyle=SKIN;c.beginPath();c.moveTo(116,168);c.lineTo(116,192);c.quadraticCurveTo(128,204,140,192);c.lineTo(140,168);c.fill();c.beginPath();c.moveTo(116,168);c.lineTo(116,190);c.moveTo(140,168);c.lineTo(140,190);c.stroke() + c.lineWidth=6;c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + c.lineWidth=5.5;c.beginPath();c.moveTo(90,130);c.lineTo(113,140);c.lineTo(90,150);c.moveTo(166,130);c.lineTo(143,140);c.lineTo(166,150);c.stroke() + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*42,160,14,7,0,0,T),c.fill() + c.lineWidth=2.5;for(const d of[-1,1])for(const k of[-6,-1,4])c.beginPath(),c.moveTo(128+d*42+k-2,164),c.lineTo(128+d*42+k+2,156),c.stroke() + c.lineWidth=3.5;c.beginPath();c.moveTo(120,170);for(let k=1;k<=5;k++)c.lineTo(120+k*3.2,k%2?173:169);c.stroke() + c.lineWidth=6;c.fillStyle=HAIR;c.beginPath();c.moveTo(64,206);c.lineTo(68,150) + c.bezierCurveTo(52,74,88,36,128,36);c.bezierCurveTo(168,36,204,74,188,150);c.lineTo(192,206);c.quadraticCurveTo(182,200,176,206) + c.quadraticCurveTo(180,124,176,104);c.quadraticCurveTo(168,104,162,112);c.quadraticCurveTo(158,98,148,92);c.quadraticCurveTo(142,104,134,110) + c.quadraticCurveTo(130,96,122,90);c.quadraticCurveTo(116,102,108,108);c.quadraticCurveTo(104,96,94,94);c.quadraticCurveTo(88,104,82,108) + c.quadraticCurveTo(76,124,80,206);c.quadraticCurveTo(72,200,64,206);c.closePath();c.fill();c.stroke() + c.strokeStyle=HL;c.lineWidth=5;for(const[a,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,56,PI*a,PI*e),c.stroke() + c.strokeStyle='#111';c.fillStyle=RED;c.lineWidth=5 + for(const d of[-1,1])c.beginPath(),c.moveTo(168,62),c.quadraticCurveTo(168+d*10,38-d*6,168+d*28,48+d*4),c.quadraticCurveTo(168+d*24,70,168,62),c.fill(),c.stroke() + c.beginPath();c.arc(168,62,6,0,T);c.fill();c.stroke() + c.fillStyle=SW;c.lineWidth=4;const sy=104+3*sin(T*t);c.beginPath();c.moveTo(62,sy-12);c.quadraticCurveTo(70,sy,62,sy+6);c.quadraticCurveTo(54,sy,62,sy-12);c.fill();c.stroke() + for(const d of[-1,1])ds(c,34,23,'#fff',()=>{c.moveTo(128+d*82,256);c.lineTo(128+d*22,238)}) + c.lineWidth=5;c.fillStyle=SKIN + for(const d of[-1,1]){c.beginPath();c.moveTo(128,166);c.bezierCurveTo(128+d*22,176,128+d*22,208,128+d*18,236);c.lineTo(128,236);c.closePath();c.fill();c.stroke()} + c.lineWidth=3;for(const d of[-1,1])for(const y of[188,200])c.beginPath(),c.moveTo(128+d*19,y),c.quadraticCurveTo(128+d*14,y-1,128+d*11,y-5),c.stroke() + c.lineWidth=4;c.beginPath();c.ellipse(133,220,5,12,.3,0,T);c.fill();c.stroke() +} diff --git a/gen/uianime/loading/push.js b/gen/uianime/loading/push.js new file mode 100644 index 0000000..7f10da0 --- /dev/null +++ b/gen/uianime/loading/push.js @@ -0,0 +1,47 @@ +// blue-haired girl in a hard hat and overalls straining with gritted teeth to shove a long heavy progress bar along the ground, its striped fill crawling, sweat flying +const{sin,cos,PI,min,max,round}=Math,T=2*PI +export const frames=12,delay=90 +const SKIN='#ffe3d1',HAIR='#5c7cfa',HD='#3b5bdb',HL='#dbe4ff',HAT='#ffd43b',HTD='#f59f00',OV='#ff922b',OD='#e8590c',SHOE='#845ef7',BLK='#fff',FILL='#69db7c',FD='#2f9e44',BL='#ffa8a8',SW='#a5d8ff' +const dbl=(c,w,col,pts)=>{for(const[lw,s]of[[w,'#111'],[w-9,col]]){c.lineWidth=lw;c.strokeStyle=s;c.beginPath();c.moveTo(...pts[0]);for(const p of pts.slice(1))c.lineTo(...p);c.stroke()}c.strokeStyle='#111'} +export default(c,t,i)=>{ + const j=i%2 + for(const[w,st]of[[7,'#111'],[2.5,'#fff']])c.lineWidth=w,c.strokeStyle=st,c.beginPath(),c.moveTo(8,242),c.lineTo(248,242),c.stroke() + c.strokeStyle='#111' + c.lineWidth=6;c.fillStyle='#ced4da';c.beginPath();c.roundRect(92,186,154,52,26);c.fill();c.stroke() + c.fillStyle='#fff';c.beginPath();c.roundRect(92,178,154,52,26);c.fill();c.stroke() + c.save();c.beginPath();c.roundRect(104,190,130,28,14);c.clip();c.fillStyle='#e9ecef';c.fillRect(0,0,256,256);c.fillStyle=FILL;c.fillRect(100,186,82,36) + c.fillStyle=FD;const so=18*((t*2)%1);for(let k=-1;k<6;k++)c.beginPath(),c.moveTo(86+k*18+so,220),c.lineTo(96+k*18+so,220),c.lineTo(112+k*18+so,188),c.lineTo(102+k*18+so,188),c.closePath(),c.fill() + c.fillStyle='#e9ecef';c.fillRect(182,186,60,36);c.restore() + c.lineWidth=4.5;c.beginPath();c.moveTo(182,191);c.lineTo(182,217);c.stroke();c.beginPath();c.roundRect(104,190,130,28,14);c.stroke() + c.strokeStyle='#fff';c.lineWidth=4;c.beginPath();c.moveTo(118,196);c.lineTo(150,196);c.stroke() + for(const[l,s]of[[7,'#111'],[2.5,'#fff']]){c.lineWidth=l;c.strokeStyle=s;c.beginPath();for(const k of[0,1,2])c.moveTo(214+k*12,170-k*3),c.lineTo(220+k*12,154-k*3);c.stroke()} + c.strokeStyle='#111' + const sh=[80,164],hip=[48,198] + dbl(c,20,SKIN,[hip,[34,216],[24,232]]);c.fillStyle=SHOE;c.lineWidth=5;c.beginPath();c.ellipse(22,236,12,7,-.2,0,T);c.fill();c.stroke() + dbl(c,19,'#fff',[[sh[0]-2,sh[1]+4],[86,190],[96,200]]);c.lineWidth=5;c.fillStyle=SKIN;c.beginPath();c.ellipse(98,199,7,10,0,0,T);c.fill();c.stroke() + c.save();c.translate(...hip);c.rotate(.75);c.lineWidth=6;c.fillStyle=OV;c.beginPath();c.roundRect(-18,-50,36,58,12);c.fill();c.stroke() + c.fillStyle='#fff';c.beginPath();c.moveTo(-14,-48);c.lineTo(14,-48);c.lineTo(9,-34);c.lineTo(-9,-34);c.closePath();c.fill();c.stroke() + c.fillStyle=OD;c.lineWidth=4;c.beginPath();c.roundRect(-8,-26,16,12,3);c.fill();c.stroke();c.restore() + dbl(c,22,OV,[hip,[76,212],[70,232]]);c.fillStyle=SHOE;c.lineWidth=5;c.beginPath();c.ellipse(78,236,13,7,0,0,T);c.fill();c.stroke() + c.save();c.translate(94,104);c.rotate(.12);c.scale(.9,.9) + c.lineWidth=7;c.fillStyle=HAIR;c.beginPath();c.moveTo(-40,-30);c.bezierCurveTo(-64,-40,-82,-20,-86,6+3*j);c.quadraticCurveTo(-72,0,-66,6);c.quadraticCurveTo(-76,20,-72,34+3*j);c.quadraticCurveTo(-60,16,-44,6);c.closePath();c.fill();c.stroke() + c.fillStyle=HD;c.beginPath();c.moveTo(10,-62);c.bezierCurveTo(-40,-66,-62,-40,-58,0);c.quadraticCurveTo(-54,40,-30,52);c.lineTo(20,40);c.closePath();c.fill();c.stroke() + c.fillStyle=SKIN;c.beginPath();c.moveTo(-42,-6);c.bezierCurveTo(-42,40,-4,60,22,60);c.bezierCurveTo(44,58,58,30,58,-6);c.bezierCurveTo(58,-60,-42,-60,-42,-6);c.fill();c.stroke() + c.lineWidth=6;c.beginPath();c.moveTo(-6,0);c.lineTo(12,10);c.lineTo(-6,20);c.moveTo(50,2);c.lineTo(34,11);c.lineTo(50,20);c.stroke() + c.fillStyle=BL;c.beginPath();c.ellipse(-18,32,11,5.5,0,0,T);c.fill() + c.lineWidth=2.5;for(const k of[-5,0,5])c.beginPath(),c.moveTo(-18+k-2,35),c.lineTo(-18+k+2,29),c.stroke() + c.fillStyle='#fff';c.lineWidth=4;c.beginPath();c.roundRect(10,30,34,16,6);c.fill();c.stroke() + c.lineWidth=3;c.beginPath();c.moveTo(11,38);c.lineTo(43,38);for(const x of[19,27,35])c.moveTo(x,31),c.lineTo(x,45);c.stroke() + c.lineWidth=7;c.fillStyle=HAIR;c.beginPath();c.moveTo(-46,12) + c.bezierCurveTo(-56,-40,-26,-62,10,-62);c.bezierCurveTo(46,-62,68,-40,62,-8) + c.lineTo(54,-12);c.lineTo(50,-4);c.lineTo(40,-16);c.lineTo(32,-6);c.lineTo(22,-18);c.lineTo(14,-8);c.lineTo(4,-20);c.lineTo(-6,-8) + c.lineTo(-16,-20);c.lineTo(-24,-6);c.lineTo(-32,-14);c.lineTo(-38,4);c.closePath();c.fill();c.stroke() + c.fillStyle=HAT;c.beginPath();c.moveTo(-54,-22);c.bezierCurveTo(-56,-86,70,-90,66,-22);c.closePath();c.fill();c.stroke() + c.fillStyle=HTD;c.beginPath();c.roundRect(-60,-30,138,13,6);c.fill();c.stroke() + c.beginPath();c.moveTo(0,-74);c.quadraticCurveTo(6,-50,4,-30);c.lineTo(18,-30);c.quadraticCurveTo(20,-50,14,-76);c.fill();c.stroke() + c.strokeStyle='#fff';c.lineWidth=6;c.beginPath();c.arc(4,-30,40,PI*1.18,PI*1.36);c.stroke();c.strokeStyle='#111' + c.restore() + dbl(c,20,'#fff',[[sh[0]+2,sh[1]+4],[90,206],[96,218]]);c.lineWidth=5;c.fillStyle=SKIN;c.beginPath();c.ellipse(98,218,7,10,0,0,T);c.fill();c.stroke() + for(const o of[0,.5]){const p=(t*2+o)%1,x=30-18*p,y=62-24*p+40*p*p,sc=1-p*.4;c.fillStyle=SW;c.lineWidth=4;c.save();c.translate(x,y);c.rotate(-1.1+p);c.scale(sc,sc);c.beginPath();c.moveTo(0,-11);c.quadraticCurveTo(9,2,0,7);c.quadraticCurveTo(-9,2,0,-11);c.fill();c.stroke();c.restore()} + for(const o of[0,.5]){const p=(t*2+o)%1,x=18+20*(1-p),r=3+7*p;c.fillStyle='#fff';c.lineWidth=4.5;c.beginPath();c.arc(x,226-6*p,r,0,T);c.fill();c.stroke()} +} diff --git a/gen/uianime/loading/run.js b/gen/uianime/loading/run.js new file mode 100644 index 0000000..e118334 --- /dev/null +++ b/gen/uianime/loading/run.js @@ -0,0 +1,57 @@ +// chibi girl with a red ponytail and sweatband sprinting in place on a striped progress bar that rolls under her feet like a treadmill +const{sin,cos,PI,max,min,sqrt,round,abs}=Math,T=2*PI +export const frames=12,delay=60 +const SKIN='#ffe3d1',HAIR='#ff6b6b',HD='#e03131',HL='#ffc9c9',EYE='#20c997',ED='#087f5b',TEE='#fff',SHO='#4dabf7',SHD='#1c7ed6',SHOE='#f783ac',BAR='#e7f5ff',ST='#69db7c',SD='#40c057',BL='#ffa8a8',SW='#a5d8ff',Z=.8 +const knee=(hx,hy,fx,fy,l)=>{let vx=fx-hx,vy=fy-hy,d=sqrt(vx*vx+vy*vy);if(d>2*l-.5){const k=(2*l-.5)/d;vx*=k;vy*=k;d=2*l-.5}const h=sqrt(l*l-d*d/4);return[hx+vx/2+vy/d*h,hy+vy/2-vx/d*h,hx+vx,hy+vy]} +const dbl=(c,w,col,pts)=>{for(const[lw,s]of[[w,'#111'],[w-9,col]]){c.lineWidth=lw;c.strokeStyle=s;c.beginPath();c.moveTo(...pts[0]);for(const p of pts.slice(1))c.lineTo(...p);c.stroke()}c.strokeStyle='#111'} +export default(c,t)=>{ + const a=t*T,b=round(-6*abs(sin(a))),fl=k=>5*sin(2*a+k) + c.lineWidth=6;c.fillStyle=BAR;c.beginPath();c.roundRect(12,200,232,44,22);c.fill();c.stroke() + c.save();c.beginPath();c.roundRect(22,209,212,26,13);c.clip();c.fillStyle=ST;c.fillRect(0,0,256,256) + c.fillStyle=SD;const o=-(t*2%1)*28;for(let x=o;x<260;x+=28)c.beginPath(),c.moveTo(x,236),c.lineTo(x+14,236),c.lineTo(x+28,208),c.lineTo(x+14,208),c.closePath(),c.fill() + c.restore();c.lineWidth=4;c.beginPath();c.roundRect(22,209,212,26,13);c.stroke() + c.strokeStyle='#fff';c.lineWidth=4;c.beginPath();c.moveTo(34,215);c.lineTo(70,215);c.stroke();c.strokeStyle='#111' + for(const[y,o,l]of[[70,0,40],[112,.5,56],[150,.25,34]]){const p=(t*2+o)%1,x=46-50*p,w=l*min(1,(1-p)*2.5);if(w>4)dbl(c,13,'#fff',[[x,y],[x-w,y]])} + c.save();c.translate(128,200);c.scale(Z,Z);c.translate(-118,-238) + const hip=[118,192+b],sh=[122,150+b] + const leg=(ph,front)=>{const s=sin(a+ph),cc=cos(a+ph),[kx,ky,fx,fy]=knee(hip[0],hip[1],hip[0]+34*s,236-26*max(0,cc),28) + dbl(c,22,SKIN,[hip,[kx,ky],[fx,fy-4]]);dbl(c,21,'#fff',[[fx+(kx-fx)*.2,fy+(ky-fy)*.2],[fx,fy-5]]) + c.fillStyle=front?SHOE:'#e64980';c.lineWidth=5;c.beginPath();c.ellipse(fx+6,fy-3,14,8,s*.25,0,T);c.fill();c.stroke()} + const arm=ph=>{const al=-1*sin(a+ph),ex=sh[0]+22*sin(al),ey=sh[1]+22*cos(al),hx=ex+20*sin(al+1.8),hy=ey+20*cos(al+1.8) + dbl(c,22,SKIN,[[sh[0],sh[1]+6],[ex,ey],[hx,hy]]);dbl(c,24,TEE,[sh,[sh[0]+8*sin(al),sh[1]+8*cos(al)+4]]) + c.lineWidth=5;c.fillStyle=SKIN;c.beginPath();c.arc(hx,hy,9,0,T);c.fill();c.stroke()} + leg(PI,0);arm(PI) + c.save();c.translate(132,80+b);c.scale(1.02,1.02) + c.lineWidth=6;c.fillStyle=HAIR;c.beginPath();c.moveTo(-26,-50);c.bezierCurveTo(-70,-70,-96,-40,-112,-16+fl(0));c.quadraticCurveTo(-96,-24,-88,-20);c.quadraticCurveTo(-100,-4,-106,14+fl(1));c.quadraticCurveTo(-76,0,-52,-16);c.closePath();c.fill();c.stroke() + c.strokeStyle=HL;c.lineWidth=4;c.beginPath();c.moveTo(-44,-50);c.quadraticCurveTo(-70,-54,-90,-34+fl(0)*.6);c.stroke();c.strokeStyle='#111' + c.fillStyle=HD;c.lineWidth=6;c.beginPath();c.moveTo(10,-62);c.bezierCurveTo(-40,-66,-62,-40,-58,0);c.quadraticCurveTo(-54,40,-30,52);c.lineTo(20,40);c.closePath();c.fill();c.stroke() + c.fillStyle='#fff';c.lineWidth=5;c.beginPath();c.arc(-30,-48,9,0,T);c.fill();c.stroke() + c.restore() + c.lineWidth=6;c.fillStyle=SHO;c.beginPath();c.moveTo(98,174+b);c.lineTo(146,174+b);c.lineTo(150,200+b);c.lineTo(122,204+b);c.lineTo(94,200+b);c.closePath();c.fill();c.stroke() + c.strokeStyle='#fff';c.lineWidth=3.5;c.beginPath();c.moveTo(99,190+b);c.lineTo(147,190+b);c.stroke();c.strokeStyle='#111' + c.fillStyle=TEE;c.beginPath();c.moveTo(102,140+b);c.quadraticCurveTo(92,160,96,180+b);c.lineTo(148,180+b);c.quadraticCurveTo(152,158,144,140+b);c.closePath();c.fill();c.stroke() + c.fillStyle=SHD;c.lineWidth=4;c.beginPath();c.moveTo(116,152+b);c.lineTo(122,146+b);c.lineTo(128,152+b);c.lineTo(134,146+b);c.stroke() + leg(0,1) + c.save();c.translate(132,80+b);c.scale(1.02,1.02) + c.lineWidth=6;c.fillStyle=SKIN;c.beginPath();c.moveTo(-6,46);c.lineTo(-6,62);c.lineTo(10,62);c.lineTo(10,46);c.fill() + c.beginPath();c.moveTo(-42,-6);c.bezierCurveTo(-42,40,-4,60,22,60);c.bezierCurveTo(44,58,58,30,58,-6);c.bezierCurveTo(58,-60,-42,-60,-42,-6);c.fill();c.stroke() + for(const[x,rx]of[[4,12],[42,9]]){ + c.fillStyle='#fff';c.beginPath();c.ellipse(x,10,rx,15,0,0,T);c.fill() + c.save();c.beginPath();c.ellipse(x,10,rx,15,0,0,T);c.clip();c.beginPath();c.ellipse(x+rx*.3,12,rx*.8,13,0,0,T);c.fillStyle=EYE;c.fill();c.lineWidth=2.5;c.stroke();c.fillStyle=ED;c.beginPath();c.ellipse(x+2,4,rx,8,0,0,T);c.fill() + c.fillStyle='#111';c.beginPath();c.ellipse(x+rx*.35,13,rx*.38,6,0,0,T);c.fill();c.fillStyle='#fff';c.beginPath();c.arc(x-1,6,3.5,0,T);c.fill();c.restore() + c.lineWidth=5.5;c.beginPath();c.moveTo(x-rx-2,-2);c.quadraticCurveTo(x,-10,x+rx+2,-2);c.stroke() + } + c.fillStyle=BL;c.beginPath();c.ellipse(-16,32,10,5,0,0,T);c.fill() + c.fillStyle='#c92a2a';c.lineWidth=3.5;c.beginPath();c.moveTo(22,38);c.quadraticCurveTo(30,36,36,40);c.quadraticCurveTo(32,52,24,48);c.closePath();c.fill();c.stroke() + c.lineWidth=6;c.fillStyle=HAIR;c.beginPath();c.moveTo(-46,14) + c.bezierCurveTo(-56,-40,-26,-66,10,-66);c.bezierCurveTo(46,-66,68,-40,62,-4) + c.lineTo(54,-10);c.lineTo(52,-2);c.lineTo(42,-14);c.lineTo(36,-4);c.lineTo(26,-18);c.lineTo(18,-6);c.lineTo(8,-20);c.lineTo(-2,-8) + c.lineTo(-12,-20);c.lineTo(-22,-6);c.lineTo(-30,-14);c.lineTo(-36,4);c.closePath();c.fill();c.stroke() + c.strokeStyle=HL;c.lineWidth=5;for(const[s,e]of[[1.2,1.32],[1.4,1.48],[1.58,1.7]])c.beginPath(),c.arc(10,-12,46,PI*s,PI*e),c.stroke() + c.strokeStyle='#111';c.fillStyle='#fff';c.lineWidth=5;c.beginPath();c.moveTo(-50,-30);c.quadraticCurveTo(10,-56,66,-26);c.lineTo(64,-14);c.quadraticCurveTo(10,-44,-50,-18);c.closePath();c.fill();c.stroke() + c.fillStyle=HAIR;c.beginPath();c.roundRect(20,-42,12,11,3);c.fill();c.stroke() + const p=(t*2)%1;c.fillStyle=SW;c.lineWidth=3.5;c.save();c.translate(-54-30*p,-36-16*p);c.rotate(-.9);c.scale(1-p*.5,1-p*.5);c.beginPath();c.moveTo(0,-10);c.quadraticCurveTo(8,2,0,6);c.quadraticCurveTo(-8,2,0,-10);c.fill();c.stroke();c.restore() + c.restore() + arm(0) + c.restore() +} diff --git a/gen/uianime/loading/sleepy.js b/gen/uianime/loading/sleepy.js new file mode 100644 index 0000000..f4ecac0 --- /dev/null +++ b/gen/uianime/loading/sleepy.js @@ -0,0 +1,32 @@ +// sleepy lavender bedhead girl in pajamas dozing off while she waits, head nodding, a nose bubble swelling and shrinking, a loading spinner turning above her head +const{sin,cos,PI}=Math,T=2*PI +export const frames=16,delay=90 +const SKIN='#ffe3d1',HAIR='#b197fc',HD='#7950f2',HL='#e5dbff',PJ='#96f2d7',PD='#20c997',MASK='#f783ac',BL='#ffa8a8',BUB='#d0ebff',SP=['#7950f2','#845ef7','#9775fa','#b197fc','#d0bfff','#e5dbff','#f3f0ff','#fff'],Z=.8 +export default(c,t,i)=>{ + const nod=.07+.05*Math.round(2*sin(T*t))/2,r=5+12*(1-cos(T*t))/2 + for(let k=0;k<8;k++){const a=(i-k)*T/8;c.fillStyle=SP[k];c.lineWidth=4.5;c.beginPath();c.arc(128+24*sin(a),34-24*cos(a),8.5-k*.6,0,T);c.fill();c.stroke()} + c.save();c.translate(128,252);c.scale(Z,Z);c.translate(-128,-252) + const head=f=>{c.save();c.translate(128,186);c.rotate(nod);c.translate(0,8*nod);c.translate(-128,-186);f();c.restore()} + head(()=>{c.lineWidth=7;c.fillStyle=HD;c.beginPath();c.moveTo(128,40);c.bezierCurveTo(200,40,212,100,204,160);c.quadraticCurveTo(212,182,196,190);c.lineTo(60,190);c.quadraticCurveTo(44,182,52,160);c.bezierCurveTo(44,100,56,40,128,40);c.fill();c.stroke()}) + c.lineWidth=7;c.fillStyle=PJ;c.beginPath();c.moveTo(100,194);c.quadraticCurveTo(60,202,52,252);c.lineTo(204,252);c.quadraticCurveTo(196,202,156,194);c.closePath();c.fill();c.stroke() + c.fillStyle=SKIN;c.beginPath();c.moveTo(116,170);c.lineTo(116,198);c.lineTo(128,212);c.lineTo(140,198);c.lineTo(140,170);c.fill();c.lineWidth=6;c.beginPath();c.moveTo(116,170);c.lineTo(116,196);c.moveTo(140,170);c.lineTo(140,196);c.stroke() + c.fillStyle='#fff';c.lineWidth=6;for(const d of[-1,1])c.beginPath(),c.moveTo(128,214),c.lineTo(128+d*30,194),c.lineTo(128+d*36,214),c.closePath(),c.fill(),c.stroke() + c.strokeStyle=PD;c.lineWidth=4;for(const d of[-1,1])c.beginPath(),c.moveTo(128+d*8,216),c.lineTo(128+d*28,197),c.stroke();c.strokeStyle='#111' + c.fillStyle='#ffd43b';c.lineWidth=5;for(const y of[228,246])c.beginPath(),c.arc(128,y,5,0,T),c.fill(),c.stroke() + head(()=>{ + c.lineWidth=7;c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + c.lineWidth=6;for(const x of[103,153]){c.beginPath();c.arc(x,138,13,PI*.15,PI*.85);c.stroke();c.beginPath();c.moveTo(x+(x<128?-12:12),142);c.lineTo(x+(x<128?-18:18),139);c.stroke()} + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*42,162,13,6.5,0,0,T),c.fill() + c.lineWidth=4;c.fillStyle='#c92a2a';c.beginPath();c.ellipse(132,174,5,4.5,0,0,T);c.fill();c.stroke() + c.fillStyle=BUB;c.lineWidth=4;c.beginPath();c.arc(124-r*.85,157+r*.45,r,0,T);c.fill();c.stroke() + c.strokeStyle='#fff';c.lineWidth=3.5;c.beginPath();c.arc(124-r*.85,157+r*.45,r*.6,PI*1.15,PI*1.5);c.stroke();c.strokeStyle='#111' + c.lineWidth=7;c.fillStyle=HAIR;c.beginPath();c.moveTo(64,160) + c.bezierCurveTo(46,76,88,38,128,38);c.bezierCurveTo(168,38,210,76,192,160) + c.lineTo(182,150);c.quadraticCurveTo(186,124,178,106);c.lineTo(168,116);c.lineTo(162,96);c.lineTo(150,112);c.lineTo(140,90);c.lineTo(130,110) + c.lineTo(118,92);c.lineTo(108,112);c.lineTo(96,96);c.lineTo(88,114);c.lineTo(80,106);c.quadraticCurveTo(70,130,74,150);c.closePath();c.fill();c.stroke() + c.beginPath();c.moveTo(122,40);c.bezierCurveTo(112,12,82,14,74,34);c.quadraticCurveTo(100,22,134,40);c.fill();c.stroke() + c.strokeStyle=HL;c.lineWidth=6;for(const[a,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,106,56,PI*a,PI*e),c.stroke() + c.strokeStyle='#111';c.fillStyle='#ffd43b';c.lineWidth=5;c.save();c.translate(176,84);c.rotate(.3);c.beginPath();for(let k=0;k<10;k++){const rr=k%2?6:14,b=k*PI/5-PI/2;c.lineTo(cos(b)*rr,sin(b)*rr)}c.closePath();c.fill();c.stroke();c.restore() + }) + c.restore() +} diff --git a/gen/uianime/loading/tea.js b/gen/uianime/loading/tea.js new file mode 100644 index 0000000..145a74f --- /dev/null +++ b/gen/uianime/loading/tea.js @@ -0,0 +1,41 @@ +// calm sky-blue haired girl in a cardigan sipping from a steaming teacup with her eyes closed while loading dots bounce in a little thought cloud +const{sin,cos,PI,max,min}=Math,T=2*PI +export const frames=16,delay=90 +const SKIN='#ffe3d1',HAIR='#74c0fc',HD='#339af0',HL='#e7f5ff',CAR='#ffec99',CD='#fcc419',CUP='#fcc2d7',CPD='#f06595',TEA='#c77c3a',BL='#ffa8a8',RB='#b197fc',DOT=['#ff8787','#ffd43b','#69db7c'],Z=.88 +const ease=x=>x<=0?0:x>=1?1:x*x*(3-2*x) +export default(c,t)=>{ + const u=ease((t-.1)/.12)-ease((t-.46)/.12),cx=124-6*u,cy=218-26*u,ca=-.4*u + c.fillStyle='#fff';c.lineWidth=5;c.beginPath();for(const[x,y,r]of[[206,40,22],[228,46,16],[184,48,16],[208,58,16]])c.moveTo(x+r,y),c.arc(x,y,r,0,T);c.stroke();c.fill() + c.beginPath();c.arc(170,82,6,0,T);c.stroke();c.fill();c.beginPath();c.arc(160,96,4,0,T);c.stroke();c.fill() + for(let k=0;k<3;k++){const h=max(0,sin(T*(t*2-k*.15)));c.fillStyle=DOT[k];c.lineWidth=4;c.beginPath();c.arc(190+k*16,50-9*h,6,0,T);c.fill();c.stroke()} + c.save();c.translate(112,258);c.scale(Z,Z);c.translate(-128,-258) + c.lineWidth=7;c.fillStyle=HD;c.beginPath();c.moveTo(128,36);c.bezierCurveTo(200,36,214,110,210,258);c.lineTo(46,258);c.bezierCurveTo(42,110,56,36,128,36);c.fill();c.stroke() + c.fillStyle=CAR;c.beginPath();c.moveTo(100,190);c.quadraticCurveTo(60,198,52,258);c.lineTo(204,258);c.quadraticCurveTo(196,198,156,190);c.closePath();c.fill();c.stroke() + c.fillStyle='#fff';c.beginPath();c.moveTo(108,190);c.lineTo(128,240);c.lineTo(148,190);c.closePath();c.fill();c.lineWidth=6;c.stroke() + c.fillStyle=SKIN;c.beginPath();c.moveTo(116,168);c.lineTo(116,194);c.lineTo(128,206);c.lineTo(140,194);c.lineTo(140,168);c.fill();c.beginPath();c.moveTo(116,168);c.lineTo(116,192);c.moveTo(140,168);c.lineTo(140,192);c.stroke() + c.fillStyle=RB;c.lineWidth=5;for(const d of[-1,1])c.beginPath(),c.moveTo(128,212),c.lineTo(128+d*16,203),c.lineTo(128+d*14,222),c.closePath(),c.fill(),c.stroke() + c.lineWidth=7;c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + c.lineWidth=7;for(const x of[103,153])c.beginPath(),c.arc(x,146,13,PI*1.15,PI*1.85),c.stroke() + c.lineWidth=5;for(const[x,d]of[[103,-1],[153,1]])c.beginPath(),c.moveTo(x+d*12,140),c.lineTo(x+d*18,136),c.stroke() + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*42,162,14,7,0,0,T),c.fill() + c.lineWidth=3;for(const d of[-1,1])for(const k of[-6,0,6])c.beginPath(),c.moveTo(128+d*42+k-2,166),c.lineTo(128+d*42+k+2,158),c.stroke() + c.lineWidth=4.5;c.beginPath();c.moveTo(118,168);c.quadraticCurveTo(123,174,128,169);c.quadraticCurveTo(133,174,138,168);c.stroke() + c.lineWidth=7;c.fillStyle=HAIR;c.beginPath();c.moveTo(60,200);c.bezierCurveTo(44,76,86,36,128,36);c.bezierCurveTo(170,36,212,76,196,200) + c.lineTo(182,200);c.quadraticCurveTo(186,140,178,106);c.quadraticCurveTo(168,106,162,114);c.quadraticCurveTo(156,98,146,92);c.quadraticCurveTo(140,104,132,110) + c.quadraticCurveTo(126,96,116,92);c.quadraticCurveTo(110,104,102,110);c.quadraticCurveTo(96,98,88,98);c.quadraticCurveTo(84,106,80,106) + c.quadraticCurveTo(70,140,74,200);c.closePath();c.fill();c.stroke() + c.strokeStyle=HL;c.lineWidth=6;for(const[a,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,56,PI*a,PI*e),c.stroke() + c.strokeStyle='#111';c.fillStyle=RB;c.lineWidth=6;c.beginPath();c.moveTo(80,64);c.quadraticCurveTo(128,36,176,64);c.lineTo(174,76);c.quadraticCurveTo(128,50,82,76);c.closePath();c.fill();c.stroke() + c.restore() + for(const o of[0,.5]){const p=(t*2+o)%1,x=cx+14+8*sin(T*p+o*9)+30*p,y=cy-26-60*p;if(p>.05&&p<.95)for(const[w,s]of[[11,'#111'],[5,'#fff']]){c.lineWidth=w*(1-p*.4);c.strokeStyle=s;c.beginPath();c.moveTo(x,y+14);c.bezierCurveTo(x-10,y+6,x+10,y-2,x,y-12);c.stroke()}} + c.strokeStyle='#111' + c.save();c.translate(cx,cy);c.rotate(ca) + c.lineWidth=5;c.fillStyle=CUP;c.beginPath();c.arc(30,0,10,-PI/2,PI/2);c.stroke() + c.lineWidth=6;c.beginPath();c.moveTo(-28,-16);c.lineTo(28,-16);c.quadraticCurveTo(28,22,0,22);c.quadraticCurveTo(-28,22,-28,-16);c.fill();c.stroke() + c.fillStyle=TEA;c.lineWidth=4;c.beginPath();c.ellipse(0,-16,28,6,0,0,T);c.fill();c.stroke() + c.fillStyle=CPD;c.lineWidth=3.5;c.beginPath();c.moveTo(0,10);c.bezierCurveTo(-10,2,-6,-6,0,-1);c.bezierCurveTo(6,-6,10,2,0,10);c.fill();c.stroke() + c.restore() + c.fillStyle=SKIN;c.lineWidth=5;for(const d of[-1,1])c.beginPath(),c.ellipse(cx+d*26,cy+10+d*6*u,11,13,0,0,T),c.fill(),c.stroke() + for(const d of[-1,1])for(const[l,s]of[[26,'#111'],[16,CAR]])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),c.moveTo(cx+d*46,262),c.lineTo(cx+d*28,cy+22+d*6*u),c.stroke() + c.strokeStyle='#111' +} diff --git a/gen/uianime/loading/wait.js b/gen/uianime/loading/wait.js new file mode 100644 index 0000000..a93af00 --- /dev/null +++ b/gen/uianime/loading/wait.js @@ -0,0 +1,61 @@ +// impatient office girl with a brown bun tapping her foot and glaring at her ticking wristwatch, then letting out a long sigh +const{sin,PI,max,min}=Math,T=2*PI +export const frames=16,delay=90 +const SKIN='#ffe3d1',HAIR='#a9744f',HD='#7f5539',HL='#e6c9a8',EYE='#e8590c',ED='#a33c08',BZ='#748ffc',BD='#4c6ef5',SK='#364fc7',SHOE='#495057',BAND='#ff8787',BL='#ffa8a8',Z=.66 +const ease=x=>x<=0?0:x>=1?1:x*x*(3-2*x) +const eye=(c,x,y,d)=>{ + c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill() + c.save();c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.clip();c.beginPath();c.ellipse(x+5,y+5,11.5,15,0,0,T);c.fillStyle=EYE;c.fill();c.lineWidth=3;c.stroke() + c.fillStyle='#111';c.beginPath();c.ellipse(x+6,y+7,5.5,7.5,0,0,T);c.fill() + c.fillStyle='#fff';c.beginPath();c.arc(x+2,y+3,4,0,T);c.fill() + c.fillStyle=SKIN;c.fillRect(x-16,y-20,32,19);c.restore() + c.lineWidth=7;c.beginPath();c.moveTo(x-17,y-1);c.lineTo(x+16,y-1);c.lineTo(x+d*16+d*4,y-6);c.stroke() +} +export default(c,t,i)=>{ + const sg=ease((t-.56)/.08)-ease((t-.9)/.08),tap=i<8?i%2:0,dr=3*sg + for(const[w,s]of[[15,'#111'],[8,SKIN]])for(const x of[118,138])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.moveTo(x,206),c.lineTo(x,236),c.stroke() + c.strokeStyle='#111';c.lineWidth=5;c.fillStyle=SHOE;c.beginPath();c.ellipse(114,240,12,6.5,0,0,T);c.fill();c.stroke() + c.save();c.translate(132,244);c.rotate(-.6*tap);c.beginPath();c.ellipse(10,-4,12,6.5,0,0,T);c.fill();c.stroke();c.restore() + if(tap)for(const[w,s]of[[7,'#111'],[2.5,'#fff']]){c.lineWidth=w;c.strokeStyle=s;c.beginPath();c.moveTo(160,226);c.lineTo(170,220);c.moveTo(164,238);c.lineTo(176,238);c.stroke()} + c.strokeStyle='#111' + c.save();c.translate(0,dr) + c.lineWidth=6;c.fillStyle=SK;c.beginPath();c.moveTo(102,190);c.lineTo(154,190);c.lineTo(162,214);c.quadraticCurveTo(128,220,94,214);c.closePath();c.fill();c.stroke() + for(const[w,s]of[[22,'#111'],[13,BZ]])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.moveTo(102,148),c.lineTo(80,174),c.lineTo(98,192),c.stroke() + c.strokeStyle='#111';c.lineWidth=6;c.fillStyle=BZ;c.beginPath();c.moveTo(104,136);c.quadraticCurveTo(92,140,94,160);c.lineTo(96,198);c.lineTo(160,198);c.lineTo(162,160);c.quadraticCurveTo(164,140,152,136);c.closePath();c.fill();c.stroke() + c.fillStyle='#fff';c.beginPath();c.moveTo(112,136);c.lineTo(128,166);c.lineTo(144,136);c.closePath();c.fill();c.lineWidth=5;c.stroke() + c.fillStyle=BD;for(const d of[-1,1])c.beginPath(),c.moveTo(128+d*16,136),c.lineTo(128+d*8,158),c.lineTo(128+d*2,170),c.lineTo(128+d*24,150),c.closePath(),c.fill(),c.stroke() + c.fillStyle='#ffd43b';c.lineWidth=4;c.beginPath();c.arc(128,182,4,0,T);c.fill();c.stroke() + c.fillStyle=SKIN;c.lineWidth=5;c.beginPath();c.ellipse(98,192,9,8,0,0,T);c.fill();c.stroke() + c.restore() + c.fillStyle=SKIN;c.lineWidth=5;c.beginPath();c.moveTo(121,126);c.lineTo(121,138);c.lineTo(128,146);c.lineTo(135,138);c.lineTo(135,126);c.fill();c.beginPath();c.moveTo(121,126);c.lineTo(121,137);c.moveTo(135,126);c.lineTo(135,137);c.stroke() + c.save();c.translate(128,32+dr*1.5);c.rotate(-.06*sg);c.scale(Z,Z);c.translate(-128,-36) + c.lineWidth=7;c.fillStyle=HD;c.beginPath();c.moveTo(128,36);c.bezierCurveTo(196,36,206,96,198,150);c.lineTo(58,150);c.bezierCurveTo(50,96,60,36,128,36);c.fill();c.stroke() + c.fillStyle=HAIR;c.beginPath();c.arc(128,26,20,0,T);c.fill();c.stroke() + c.strokeStyle=HL;c.lineWidth=6;c.beginPath();c.arc(128,26,12,PI*1.15,PI*1.5);c.stroke();c.strokeStyle='#111' + c.fillStyle=BAND;c.beginPath();c.roundRect(104,32,48,12,6);c.fill();c.stroke() + c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + if(sg>.5){c.lineWidth=7;for(const x of[103,153])c.beginPath(),c.moveTo(x-15,140),c.quadraticCurveTo(x,150,x+15,140),c.stroke()} + else{eye(c,103,140,-1);eye(c,153,140,1)} + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,164,12,6,0,0,T),c.fill() + c.lineWidth=5;if(sg>.5){c.fillStyle='#c92a2a';c.beginPath();c.ellipse(128,172,7,6,0,0,T);c.fill();c.stroke()}else{c.beginPath();c.moveTo(118,172);c.quadraticCurveTo(128,166,138,172);c.stroke()} + c.lineWidth=7;c.fillStyle=HAIR;c.beginPath();c.moveTo(68,150) + c.bezierCurveTo(52,74,88,36,128,36);c.bezierCurveTo(168,36,204,74,188,150) + c.quadraticCurveTo(184,118,176,100);c.quadraticCurveTo(166,108,160,116);c.quadraticCurveTo(154,94,140,86);c.quadraticCurveTo(136,102,126,110) + c.quadraticCurveTo(116,92,100,88);c.quadraticCurveTo(96,104,88,112);c.quadraticCurveTo(82,104,80,102) + c.quadraticCurveTo(70,122,68,150);c.closePath();c.fill();c.stroke() + c.strokeStyle=HL;c.lineWidth=6;for(const[a,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,56,PI*a,PI*e),c.stroke() + c.strokeStyle='#111';c.lineWidth=6;if(sg<.5)c.beginPath(),c.moveTo(88,112),c.lineTo(114,120),c.moveTo(142,120),c.lineTo(168,112),c.stroke() + if(sg<.5){c.strokeStyle='#ff6b6b';c.lineWidth=5;c.save();c.translate(178,72);for(const r of[0,1,2,3]){c.rotate(PI/2);c.beginPath();c.moveTo(4,4);c.quadraticCurveTo(5,12,14,12);c.stroke()}c.restore();c.strokeStyle='#111'} + c.restore() + if(sg>.05){const p=min(1,(t-.56)/.3),x=94-46*p,y=150-40*p,r=7+11*p;c.fillStyle='#fff';c.lineWidth=5;c.beginPath();for(const[dx,dy,k]of[[-r*.7,0,.8],[0,-r*.5,1],[r*.7,0,.8]])c.moveTo(x+dx+k*r,y+dy),c.arc(x+dx,y+dy,k*r,0,T);c.stroke();c.fill() + c.lineWidth=4;c.beginPath();c.moveTo(x+r*1.4,y+r*.6);c.quadraticCurveTo(x+r*1.9,y+r*.9,108,152);c.stroke()} + const wx=182,wy=150 + for(const[w,s]of[[22,'#111'],[13,BZ]])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.moveTo(154,150+dr),c.lineTo(190,180+dr),c.lineTo(wx,wy+14),c.stroke() + c.strokeStyle='#111';c.lineWidth=5;c.fillStyle=SKIN;c.beginPath();c.ellipse(wx-1,wy-20,10,11,0,0,T);c.fill();c.stroke() + c.fillStyle=SKIN;c.beginPath();c.rect(wx-8,wy-12,16,22);c.fill();c.beginPath();c.moveTo(wx-8,wy-12);c.lineTo(wx-8,wy+10);c.moveTo(wx+8,wy-12);c.lineTo(wx+8,wy+10);c.stroke() + c.fillStyle=BAND;c.beginPath();c.roundRect(wx-10,wy-14,20,28,4);c.fill();c.stroke() + c.fillStyle='#fff';c.lineWidth=5;c.beginPath();c.arc(wx,wy,15,0,T);c.fill();c.stroke() + c.lineWidth=3;c.beginPath();c.moveTo(wx,wy);c.lineTo(wx-6,wy-4);c.stroke() + const h=i*T/16;c.strokeStyle='#f03e3e';c.lineWidth=3;c.beginPath();c.moveTo(wx,wy);c.lineTo(wx+11*sin(h),wy-11*Math.cos(h));c.stroke();c.strokeStyle='#111' + c.fillStyle='#111';c.beginPath();c.arc(wx,wy,2.5,0,T);c.fill() +} diff --git a/gen/uianime/locked/key.js b/gen/uianime/locked/key.js new file mode 100644 index 0000000..230684e --- /dev/null +++ b/gen/uianime/locked/key.js @@ -0,0 +1,56 @@ +// red haired girl straining to turn a giant gold key in a big padlock, the shackle clicks shut and she beams as sparkles pop +const{sin,cos,PI,max,min,abs}=Math,T=2*PI +export const frames=16,delay=85 +const SKIN='#ffe3d1',HAIR='#ff8787',HD='#e03131',HL='#ffe3e3',EYE='#845ef7',ED='#5f3dc4',TOP='#d0bfff',TD='#9775fa',BL='#ffa8a8',LK='#74c0fc',SH='#dee2e6',GD='#ffd43b',GDD='#f59f00',SP='#ffe066',SW='#a5d8ff' +const ds=(c,a,b,s,f)=>{for(const[l,k]of[[a,'#111'],[b,s]])c.lineWidth=l,c.strokeStyle=k,c.beginPath(),f(),c.stroke();c.strokeStyle='#111'} +const eye=(c,x,y,d)=>{ + c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill() + c.save();c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.clip();c.fillStyle=EYE;c.fill();c.fillStyle=ED;c.beginPath();c.ellipse(x,y-8,13,10,0,0,T);c.fill();c.restore() + c.lineWidth=2.5;c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.stroke() + c.fillStyle='#111';c.beginPath();c.ellipse(x,y+3,5.5,7.5,0,0,T);c.fill() + c.fillStyle='#fff';c.beginPath();c.arc(x-4,y-5,4.5,0,T);c.fill();c.beginPath();c.arc(x+5,y+8,2,0,T);c.fill() + c.lineWidth=6;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke() +} +const spark=(c,x,y,r)=>{c.beginPath();c.moveTo(x,y-r);for(const[a,b]of[[1,0],[0,1],[-1,0],[0,-1]])c.quadraticCurveTo(x+(a+b)*r*.15,y+(b-a)*r*.15,x+a*r,y+b*r);c.fill();c.stroke()} +export default(c,t)=>{ + const tw=t<.5,p=min(1,t/.5),th=PI*p*p*(3-2*p),cs=abs(cos(th)),hap=t>=.5&&t<.875 + const dy=t<.5?-24:t<.5625?4:t<.875?0:-24*min(1,(t-.875)/.0625) + const H=f=>{c.save();c.translate(188,138);c.scale(.7,.7);c.translate(-128,-186);f();c.restore()} + H(()=>{ + c.lineWidth=9;c.fillStyle=HD;c.beginPath();c.moveTo(128,34);c.bezierCurveTo(200,34,214,96,206,150);c.quadraticCurveTo(212,210,200,250);c.lineTo(56,250);c.quadraticCurveTo(44,210,50,150);c.bezierCurveTo(42,96,56,34,128,34);c.fill();c.stroke() + c.fillStyle=TOP;c.beginPath();c.moveTo(100,190);c.quadraticCurveTo(52,198,40,330);c.lineTo(216,330);c.quadraticCurveTo(204,198,156,190);c.closePath();c.fill();c.stroke() + c.fillStyle='#fff';c.beginPath();c.moveTo(102,190);c.lineTo(128,226);c.lineTo(154,190);c.closePath();c.fill();c.stroke() + c.fillStyle=SKIN;c.beginPath();c.moveTo(114,168);c.lineTo(114,194);c.quadraticCurveTo(128,208,142,194);c.lineTo(142,168);c.fill();c.beginPath();c.moveTo(114,168);c.lineTo(114,192);c.moveTo(142,168);c.lineTo(142,192);c.stroke() + c.fillStyle=TD;c.beginPath();c.moveTo(128,224);c.lineTo(112,214);c.lineTo(112,236);c.closePath();c.moveTo(128,224);c.lineTo(144,214);c.lineTo(144,236);c.closePath();c.fill();c.stroke() + c.lineWidth=9;c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + if(tw){c.lineWidth=8;for(const d of[-1,1])c.beginPath(),c.moveTo(128+d*38,128),c.lineTo(128+d*18,140),c.lineTo(128+d*38,152),c.stroke() + c.fillStyle='#fff';c.lineWidth=6;c.beginPath();c.roundRect(108,160,40,18,7);c.fill();c.stroke();c.beginPath();c.moveTo(110,169);c.lineTo(146,169);c.stroke()} + else if(hap){c.lineWidth=9;for(const x of[103,153])c.beginPath(),c.arc(x,148,15,1.15*PI,1.85*PI),c.stroke() + c.lineWidth=6;c.fillStyle='#c92a2a';c.beginPath();c.moveTo(112,164);c.quadraticCurveTo(128,190,144,164);c.closePath();c.fill();c.stroke()} + else{eye(c,103,140,-1);eye(c,153,140,1);c.lineWidth=5;c.beginPath();c.arc(128,164,8,.15*PI,.85*PI);c.stroke()} + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,162,14,8,0,0,T),c.fill() + c.lineWidth=9;c.fillStyle=HAIR;c.beginPath();c.moveTo(68,150) + c.bezierCurveTo(52,74,88,36,128,36);c.bezierCurveTo(168,36,204,74,188,150) + c.quadraticCurveTo(186,118,178,102);c.quadraticCurveTo(170,104,164,112);c.quadraticCurveTo(158,98,148,92);c.quadraticCurveTo(142,104,134,110) + c.quadraticCurveTo(128,98,120,92);c.quadraticCurveTo(114,104,106,110);c.quadraticCurveTo(100,98,92,96);c.quadraticCurveTo(88,106,84,112) + c.quadraticCurveTo(80,104,78,104);c.quadraticCurveTo(70,124,68,150);c.closePath();c.fill();c.stroke() + c.strokeStyle=HL;c.lineWidth=8;for(const[s,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,56,PI*s,PI*e),c.stroke() + c.strokeStyle='#111';c.fillStyle=GD;c.lineWidth=7;c.beginPath();c.ellipse(80,66,16,11,-.6,0,T);c.fill();c.stroke() + if(tw){c.fillStyle=SW;c.lineWidth=7;for(const[x,y]of[[196,96],[212,128]])c.beginPath(),c.moveTo(x,y-18),c.quadraticCurveTo(x+12,y,x,y+7),c.quadraticCurveTo(x-12,y,x,y-18),c.fill(),c.stroke()} + }) + ds(c,24,13,SH,()=>{c.moveTo(38,150);c.lineTo(38,84+dy);c.arc(70,84+dy,32,PI,0);c.lineTo(102,128+dy)}) + c.fillStyle=LK;c.lineWidth=6;c.beginPath();c.roundRect(12,124,116,104,24);c.fill();c.stroke() + c.strokeStyle='#fff';c.lineWidth=5;c.beginPath();c.moveTo(28,150);c.quadraticCurveTo(28,138,40,136);c.stroke();c.strokeStyle='#111' + c.fillStyle='#343a40';c.lineWidth=4;c.beginPath();c.arc(70,166,11,0,T);c.moveTo(64,170);c.lineTo(60,196);c.lineTo(80,196);c.lineTo(76,170);c.fill() + ds(c,18,9,GD,()=>{c.moveTo(70,174);c.lineTo(150,174)}) + c.fillStyle=GD;c.lineWidth=5;c.beginPath();c.roundRect(136,164,12,20,3);c.fill();c.stroke() + ds(c,22,11,GD,()=>{c.ellipse(178,174,22,max(1,28*cs),0,0,T)}) + c.strokeStyle=GDD;c.lineWidth=3;if(cs>.3){c.beginPath();c.ellipse(178,174,22,28*cs,0,PI*1.1,PI*1.45);c.stroke()}c.strokeStyle='#111' + const y1=174-30*cs,y2=174+30*cs + ds(c,22,12,TOP,()=>{c.moveTo(150,150);c.quadraticCurveTo(150,y1-16,170,y1)}) + ds(c,22,12,TOP,()=>{c.moveTo(220,156);c.quadraticCurveTo(226,y2,196,y2)}) + c.fillStyle=SKIN;c.lineWidth=5;for(const[x,y]of[[176,y1],[190,y2]])c.beginPath(),c.ellipse(x,y,12,11,0,0,T),c.fill(),c.stroke() + if(t>=.5&&t<.875){const q=(t-.5)/.375,s=sin(PI*min(1,q*1.6)) + for(let k=0;k<5;k++){const a=-PI/2+(k-2)*.5;ds(c,8,4,SP,()=>{c.moveTo(70+cos(a)*(48+8*q),66+sin(a)*(48+8*q));c.lineTo(70+cos(a)*(60+14*q),66+sin(a)*(60+14*q))})} + c.fillStyle=SP;c.lineWidth=3.5;for(const[x,y,o]of[[132,40,0],[236,30,.2],[240,104,.35]]){const r=sin(PI*min(1,max(0,q*1.4-o)));if(r>.1)spark(c,x,y,13*r)}} +} diff --git a/gen/uianime/logout/wave.js b/gen/uianime/logout/wave.js new file mode 100644 index 0000000..4c86e8a --- /dev/null +++ b/gen/uianime/logout/wave.js @@ -0,0 +1,57 @@ +// silver haired girl in a beret and red scarf by an open door, smiling and waving goodbye, a wink and little hearts as she heads out +const{sin,cos,PI}=Math,T=2*PI +export const frames=16,delay=80 +const SKIN='#ffe3d1',HAIR='#e9ecef',HD='#adb5bd',EYE='#4dabf7',ED='#1864ab',BER='#ff6b6b',BD='#c92a2a',COAT='#e8b07a',CD='#b9773f',SCF='#fa5252',BL='#ffa8a8',DR='#96f2d7',DD='#20c997',IN='#495057',HT='#ff8fab' +const ds=(c,a,b,s,f)=>{for(const[l,k]of[[a,'#111'],[b,s]])c.lineWidth=l,c.strokeStyle=k,c.beginPath(),f(),c.stroke();c.strokeStyle='#111'} +const eye=(c,x,y,d)=>{ + c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill() + c.save();c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.clip();c.fillStyle=EYE;c.fill();c.fillStyle=ED;c.beginPath();c.ellipse(x,y-8,13,10,0,0,T);c.fill();c.restore() + c.lineWidth=2.5;c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.stroke() + c.fillStyle='#111';c.beginPath();c.ellipse(x,y+3,5.5,7.5,0,0,T);c.fill() + c.fillStyle='#fff';c.beginPath();c.arc(x-4,y-5,4.5,0,T);c.fill();c.beginPath();c.arc(x+5,y+8,2,0,T);c.fill() + c.lineWidth=6;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke() +} +const heart=(c,x,y,s)=>{c.save();c.translate(x,y);c.scale(s,s);c.beginPath();c.moveTo(0,8);c.bezierCurveTo(-13,-1,-9,-12,0,-5);c.bezierCurveTo(9,-12,13,-1,0,8);c.restore();c.fill();c.stroke()} +export default(c,t)=>{ + const a=-PI/2+.32*sin(2*T*t),ex=212,ey=204,hx=ex+60*cos(a),hy=ey+60*sin(a),w=t>=.5&&t<.8125 + c.lineWidth=6;c.fillStyle=IN;c.beginPath();c.roundRect(12,40,68,212,[10,10,0,0]);c.fill();c.stroke() + c.fillStyle='#ffe066';c.beginPath();c.moveTo(18,248);c.lineTo(74,248);c.lineTo(74,46);c.closePath();c.globalAlpha=.25;c.fill();c.globalAlpha=1 + c.fillStyle=DR;c.beginPath();c.moveTo(12,40);c.lineTo(46,54);c.lineTo(46,238);c.lineTo(12,252);c.closePath();c.fill();c.stroke() + c.strokeStyle=DD;c.lineWidth=4;c.beginPath();c.moveTo(20,62);c.lineTo(38,70);c.lineTo(38,138);c.lineTo(20,136);c.closePath();c.moveTo(20,158);c.lineTo(38,158);c.lineTo(38,222);c.lineTo(20,230);c.closePath();c.stroke();c.strokeStyle='#111' + c.fillStyle='#ffd43b';c.lineWidth=4;c.beginPath();c.arc(39,150,5,0,T);c.fill();c.stroke() + const H=f=>{c.save();c.translate(140,182);c.scale(.72,.72);c.translate(-128,-186);f();c.restore()} + H(()=>{ + c.lineWidth=8;c.fillStyle=HD;c.beginPath();c.moveTo(128,34);c.bezierCurveTo(200,34,214,96,206,150);c.quadraticCurveTo(216,190,204,226);c.quadraticCurveTo(196,236,186,228);c.lineTo(70,228);c.quadraticCurveTo(60,236,52,226);c.quadraticCurveTo(40,190,50,150);c.bezierCurveTo(42,96,56,34,128,34);c.fill();c.stroke() + c.fillStyle=COAT;c.beginPath();c.moveTo(100,190);c.quadraticCurveTo(52,198,40,330);c.lineTo(216,330);c.quadraticCurveTo(204,198,156,190);c.closePath();c.fill();c.stroke() + c.lineWidth=6;c.beginPath();c.moveTo(128,214);c.lineTo(128,330);c.stroke() + c.fillStyle=CD;for(const y of[246,282])c.beginPath(),c.arc(146,y,6,0,T),c.fill(),c.stroke() + c.lineWidth=8;c.fillStyle=SKIN;c.beginPath();c.moveTo(114,168);c.lineTo(114,194);c.lineTo(142,194);c.lineTo(142,168);c.fill();c.beginPath();c.moveTo(114,168);c.lineTo(114,192);c.moveTo(142,168);c.lineTo(142,192);c.stroke() + c.fillStyle=SCF;c.beginPath();c.moveTo(94,196);c.quadraticCurveTo(128,184,162,196);c.quadraticCurveTo(168,212,160,220);c.quadraticCurveTo(128,208,96,220);c.quadraticCurveTo(88,210,94,196);c.fill();c.stroke() + c.beginPath();c.moveTo(102,214);c.lineTo(90,266);c.lineTo(114,266);c.lineTo(116,216);c.fill();c.stroke() + c.strokeStyle='#fff';c.lineWidth=4;c.beginPath();c.moveTo(96,256);c.lineTo(110,256);c.stroke();c.strokeStyle='#111' + c.lineWidth=8;c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + eye(c,103,140,-1) + if(w){c.lineWidth=8;c.beginPath();c.arc(153,148,14,1.15*PI,1.85*PI);c.stroke()}else eye(c,153,140,1) + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,162,14,8,0,0,T),c.fill() + c.lineWidth=4;for(const d of[-1,1])for(const k of[-6,0,6])c.beginPath(),c.moveTo(128+d*44+k-2,166),c.lineTo(128+d*44+k+2,158),c.stroke() + c.lineWidth=6;c.fillStyle='#c92a2a';c.beginPath();c.moveTo(114,164);c.quadraticCurveTo(128,186,142,164);c.closePath();c.fill();c.stroke() + c.save();c.clip();c.fillStyle='#ff8fab';c.beginPath();c.ellipse(128,178,8,6,0,0,T);c.fill();c.restore() + c.lineWidth=8;c.fillStyle=HAIR;c.beginPath();c.moveTo(68,150) + c.bezierCurveTo(52,74,88,36,128,36);c.bezierCurveTo(168,36,204,74,188,150) + c.quadraticCurveTo(186,118,178,102);c.quadraticCurveTo(170,104,164,112);c.quadraticCurveTo(158,98,148,92);c.quadraticCurveTo(142,104,134,110) + c.quadraticCurveTo(128,98,120,92);c.quadraticCurveTo(114,104,106,110);c.quadraticCurveTo(100,98,92,96);c.quadraticCurveTo(88,106,84,112) + c.quadraticCurveTo(80,104,78,104);c.quadraticCurveTo(70,124,68,150);c.closePath();c.fill();c.stroke() + c.strokeStyle=HD;c.lineWidth=6;for(const[s,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,56,PI*s,PI*e),c.stroke() + c.strokeStyle='#111';c.fillStyle=BER;c.lineWidth=8;c.beginPath();c.ellipse(148,48,62,24,.18,0,T);c.fill();c.stroke() + c.strokeStyle=BD;c.lineWidth=5;c.beginPath();c.ellipse(148,48,46,13,.18,.2,PI-.4);c.stroke();c.strokeStyle='#111' + c.fillStyle=BD;c.lineWidth=6;c.beginPath();c.roundRect(150,14,12,14,4);c.fill();c.stroke() + }) + ds(c,24,14,COAT,()=>{c.moveTo(168,226);c.lineTo(ex,ey);c.lineTo(ex+42*cos(a),ey+42*sin(a))}) + c.strokeStyle='#111';c.lineWidth=5;c.fillStyle=SKIN + c.save();c.translate(hx,hy);c.rotate(a+PI/2) + for(const x of[-9,-3,3,9])c.beginPath(),c.ellipse(x,-14,3.6,8,0,0,T),c.fill(),c.stroke() + c.beginPath();c.ellipse(-14,-2,4,8,-.7,0,T);c.fill();c.stroke() + c.beginPath();c.ellipse(0,-2,13,12,0,0,T);c.fill();c.stroke() + c.restore() + c.fillStyle=HT;c.lineWidth=3.5;for(const o of[0,.5]){const p=(t+o)%1,s=sin(PI*p);if(s>.15)heart(c,232+6*sin(T*p*2),100-80*p,.5+.6*s)} +} diff --git a/gen/uianime/mailbox/check.js b/gen/uianime/mailbox/check.js new file mode 100644 index 0000000..4f8079d --- /dev/null +++ b/gen/uianime/mailbox/check.js @@ -0,0 +1,73 @@ +// ginger bob girl pulls open her mailbox to find it totally empty, staring with dot eyes and a sweatdrop while a tumbleweed rolls past +const{sin,cos,PI,max,min,abs,hypot,sqrt}=Math,T=2*PI +export const frames=16,delay=85 +const SKIN='#ffe3d1',HAIR='#ff922b',HD='#e8590c',HL='#ffe8cc',EYE='#51cf66',ED='#2b8a3e',BL='#ffa8a8',TOP='#d0bfff',TD='#9775fa',MB='#74c0fc',MBD='#339af0',IN='#343a40',FL='#fa5252',WD='#c98a52',TW='#e0b46c',TWD='#a0763c',SW='#a5d8ff' +const E=x=>x<=0?0:x>=1?1:x*x*(3-2*x) +const ds=(c,a,b,s,f)=>{for(const[l,k]of[[a,'#111'],[b,s]])c.lineWidth=l,c.strokeStyle=k,c.beginPath(),f(),c.stroke();c.strokeStyle='#111'} +const arch=(c,x,y,w,h)=>{c.moveTo(x,y);c.lineTo(x,y-h+w/2);c.arc(x+w/2,y-h+w/2,w/2,PI,0);c.lineTo(x+w,y);c.closePath()} +const eye=(c,x,y,d)=>{ + c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill() + c.save();c.clip();c.beginPath();c.ellipse(x+4,y+3,11.5,15,0,0,T);c.fillStyle=EYE;c.fill();c.lineWidth=2.5;c.stroke() + c.fillStyle=ED;c.beginPath();c.ellipse(x+4,y-7,13,9,0,0,T);c.fill() + c.fillStyle='#111';c.beginPath();c.ellipse(x+5,y+4,5.5,7.5,0,0,T);c.fill() + c.fillStyle='#fff';c.beginPath();c.arc(x,y-3,4.5,0,T);c.fill();c.beginPath();c.arc(x+8,y+9,2,0,T);c.fill();c.restore() + c.lineWidth=7;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke() +} +export default(c,t)=>{ + const op=E((t-.1)/.14)-E((t-.82)/.12),ln=E((t-.22)/.1)-E((t-.8)/.1),bk=t>.3&&t<.82,sy=1-1.4*op + const p=(t-.28)/.62,tx=290-350*p,ty=228-16*abs(sin(3*PI*p)) + // post and mailbox body + c.lineWidth=6;c.fillStyle=WD;c.beginPath();c.rect(176,164,24,86);c.fill();c.stroke() + c.fillStyle=MBD;c.beginPath();c.moveTo(148,170);c.lineTo(148,134);c.arc(188,134,40,PI,PI*1.31);c.lineTo(188+40*cos(PI*1.31)+16,134+40*sin(PI*1.31)-10);c.arc(204,124,40,PI*1.31,0);c.lineTo(244,160);c.lineTo(228,170);c.closePath();c.fill();c.stroke() + ds(c,10,5,'#fff',()=>{c.moveTo(236,110);c.lineTo(236,140)}) + c.fillStyle=FL;c.lineWidth=5;c.beginPath();c.rect(230,138,12,20);c.fill();c.stroke() + // inside: dark and empty, just a cobweb + c.fillStyle=IN;c.lineWidth=6;c.beginPath();arch(c,148,170,80,76);c.fill() + c.fillStyle='#495057';c.lineWidth=3;c.beginPath();arch(c,164,160,48,54);c.fill();c.stroke() + c.strokeStyle='#868e96';c.lineWidth=3;c.beginPath();c.moveTo(154,166);c.lineTo(164,160);c.moveTo(222,166);c.lineTo(212,160);c.stroke() + c.strokeStyle='#dee2e6';c.lineWidth=2.5;c.beginPath();c.moveTo(160,136);c.lineTo(180,112);for(const r of[9,17])c.moveTo(160,136-r),c.quadraticCurveTo(165+r*.2,131-r*.2,160+r,136);c.moveTo(160,136);c.lineTo(174,118);c.stroke() + c.strokeStyle='#111';c.lineWidth=6;c.beginPath();arch(c,148,170,80,76);c.stroke() + // girl + c.save();c.translate(78,162);c.scale(.8,.8);c.translate(-128,-186) + c.save();c.translate(128,186);c.rotate(.07*ln);c.translate(-128,-186) + c.lineWidth=8;c.fillStyle=HD;c.beginPath();c.moveTo(128,34);c.bezierCurveTo(198,34,214,100,204,160);c.quadraticCurveTo(204,186,180,184);c.lineTo(76,184);c.quadraticCurveTo(52,186,52,160);c.bezierCurveTo(42,100,58,34,128,34);c.fill();c.stroke() + c.restore() + c.fillStyle=TOP;c.beginPath();c.moveTo(100,190);c.quadraticCurveTo(58,198,48,304);c.lineTo(208,304);c.quadraticCurveTo(198,198,156,190);c.closePath();c.fill();c.stroke() + c.strokeStyle=TD;c.lineWidth=5;c.beginPath();c.moveTo(128,212);c.lineTo(128,304);c.stroke();c.strokeStyle='#111' + c.fillStyle='#fff';c.lineWidth=4;for(const y of[236,266])c.beginPath(),c.arc(136,y,5,0,T),c.fill(),c.stroke() + c.fillStyle=SKIN;c.lineWidth=7;c.beginPath();c.moveTo(116,166);c.lineTo(116,194);c.lineTo(128,204);c.lineTo(140,194);c.lineTo(140,166);c.fill();c.beginPath();c.moveTo(116,166);c.lineTo(116,192);c.moveTo(140,166);c.lineTo(140,192);c.stroke() + c.fillStyle='#fff';c.lineWidth=6;for(const d of[-1,1])c.beginPath(),c.moveTo(128,206),c.quadraticCurveTo(128+d*34,212,128+d*30,190),c.quadraticCurveTo(128+d*16,192,128,206),c.fill(),c.stroke() + c.save();c.translate(128,186);c.rotate(.07*ln);c.translate(-128,-186) + c.lineWidth=8;c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + if(bk){c.fillStyle='#111';for(const x of[105,155])c.beginPath(),c.ellipse(x,140,7.5,9,0,0,T),c.fill() + c.lineWidth=5;c.beginPath();c.moveTo(121,170);c.lineTo(135,170);c.stroke()} + else{eye(c,103,140,-1);eye(c,153,140,1);c.lineWidth=5;c.beginPath();c.arc(128,164,8,.2*PI,.8*PI);c.stroke()} + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,162,13,7,0,0,T),c.fill() + c.lineWidth=3;for(const d of[-1,1])for(const k of[-5,0,5])c.beginPath(),c.moveTo(128+d*44+k-2,165),c.lineTo(128+d*44+k+2,159),c.stroke() + c.lineWidth=8;c.fillStyle=HAIR;c.beginPath();c.moveTo(66,160) + c.bezierCurveTo(48,74,88,36,128,36);c.bezierCurveTo(168,36,208,74,190,160) + c.quadraticCurveTo(188,120,180,104);c.quadraticCurveTo(170,104,164,96);c.quadraticCurveTo(156,108,144,110);c.quadraticCurveTo(140,98,130,92) + c.quadraticCurveTo(122,106,108,110);c.quadraticCurveTo(104,98,96,94);c.quadraticCurveTo(88,106,78,106);c.quadraticCurveTo(68,128,66,160);c.closePath();c.fill();c.stroke() + c.beginPath();c.moveTo(126,38);c.quadraticCurveTo(120,14,100,14);c.quadraticCurveTo(118,24,116,40);c.fill();c.stroke() + c.strokeStyle=HL;c.lineWidth=7;for(const[a,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,56,PI*a,PI*e),c.stroke() + c.strokeStyle='#111';c.fillStyle=FL;c.lineWidth=6;c.beginPath();c.roundRect(150,66,30,11,5);c.fill();c.stroke() + c.restore();c.restore() + // door swinging down on its hinge + c.save();c.translate(0,170);c.scale(1,sy);c.beginPath();arch(c,148,0,80,76);c.restore() + c.fillStyle=sy>0?MB:'#d0ebff';c.lineWidth=6;c.fill();c.stroke() + if(sy>.3){c.strokeStyle='#d0ebff';c.lineWidth=5;c.beginPath();c.arc(188,170-36*sy,30,PI*1.15,PI*1.45);c.stroke();c.strokeStyle='#111'} + const hx=188,hy=170-70*sy,sx=118,sh=186,d=hypot(hx-sx,hy-sh),h=sqrt(max(0,58*58-d*d/4)),ex=(sx+hx)/2-(hy-sh)/d*h,ey=(sh+hy)/2+(hx-sx)/d*h + ds(c,20,11,TOP,()=>{c.moveTo(sx,sh);c.lineTo(ex,ey);c.lineTo(hx,hy+4)}) + c.fillStyle=SKIN;c.lineWidth=5;c.beginPath();c.ellipse(hx,hy+4,10,9,0,0,T);c.fill();c.stroke() + // tumbleweed bouncing past + if(p>0&&p<1){ + for(const k of[1,2,3]){const q=(p*3+k/3)%1,r=7*(1-q);if(r>1){c.fillStyle='#fff';c.lineWidth=3.5;c.beginPath();c.arc(tx+18+q*34,246-q*6,r,0,T);c.fill();c.stroke()}} + c.save();c.translate(tx,ty);c.rotate(-p*14) + c.fillStyle=TW;c.lineWidth=5;c.beginPath();for(let k=0;k<12;k++){const a=k*T/12,b=a+T/24;c.quadraticCurveTo(28*cos(a),28*sin(a),22*cos(b),22*sin(b))}c.closePath();c.fill();c.stroke() + c.strokeStyle=TWD;c.lineWidth=3;for(let k=0;k<5;k++)c.beginPath(),c.ellipse(4*cos(k*2.4),4*sin(k*2.4),15,7,k*1.3,0,T),c.stroke() + c.restore() + } + // sweatdrop and silent dots + if(bk){const s=min(1,(t-.3)/.08),y=90;c.fillStyle=SW;c.lineWidth=4;c.beginPath();c.moveTo(24,y-16*s);c.quadraticCurveTo(34*s+24*(1-s),y+4,24,y+6*s);c.quadraticCurveTo(14*s+24*(1-s),y+4,24,y-16*s);c.fill();c.stroke()} + c.fillStyle='#fff';c.lineWidth=4;for(let k=0;k<3;k++)if(t>.4+k*.08&&t<.82)c.beginPath(),c.arc(134+k*16,46-k*5,6,0,T),c.fill(),c.stroke() +} diff --git a/gen/uianime/maintenance/mechanic.js b/gen/uianime/maintenance/mechanic.js new file mode 100644 index 0000000..b97272c --- /dev/null +++ b/gen/uianime/maintenance/mechanic.js @@ -0,0 +1,67 @@ +// sky blue haired mechanic girl in goggles and coveralls, wrench in hand, wiping the sweat off her brow with a phew while gears keep turning behind her +const{sin,cos,PI,max,min}=Math,T=2*PI +export const frames=12,delay=100 +const SKIN='#ffe3d1',HAIR='#74c0fc',HD='#339af0',HL='#e7f5ff',EYE='#51cf66',ED='#2b8a3e',BL='#ffa8a8',JS='#ff922b',JSD='#e8590c',GG='#ffd43b',GR='#ced4da',GD='#868e96',GY='#ffe066',WR='#dee2e6',SW='#a5d8ff',GRS='#868e96' +const E=x=>x<=0?0:x>=1?1:x*x*(3-2*x) +const ds=(c,a,b,s,f)=>{for(const[l,k]of[[a,'#111'],[b,s]])c.lineWidth=l,c.strokeStyle=k,c.beginPath(),f(),c.stroke();c.strokeStyle='#111'} +const gear=(c,x,y,n,ro,ri,a,col,h)=>{ + c.save();c.translate(x,y);c.rotate(a);c.fillStyle=col;c.lineWidth=5;c.beginPath() + for(let k=0;k{c.fillStyle=SW;c.lineWidth=4;c.beginPath();c.moveTo(x,y-10*s);c.quadraticCurveTo(x+7*s,y+2*s,x,y+5*s);c.quadraticCurveTo(x-7*s,y+2*s,x,y-10*s);c.fill();c.stroke()} +const eye=(c,x,y,d)=>{ + c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill() + c.save();c.clip();c.beginPath();c.ellipse(x,y+3,11.5,15,0,0,T);c.fillStyle=EYE;c.fill();c.lineWidth=2.5;c.stroke() + c.fillStyle=ED;c.beginPath();c.ellipse(x,y-7,13,9,0,0,T);c.fill() + c.fillStyle='#111';c.beginPath();c.ellipse(x,y+4,5.5,7.5,0,0,T);c.fill() + c.fillStyle='#fff';c.beginPath();c.arc(x-4,y-3,4.5,0,T);c.fill();c.beginPath();c.arc(x+5,y+9,2,0,T);c.fill();c.restore() + c.lineWidth=7;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke() +} +export default(c,t)=>{ + const up=E((t-.22)/.1)-E((t-.62)/.1),wp=min(1,max(0,(t-.32)/.26)),sh=t>.3&&t<.66,ph=t>=.66&&t<.92 + gear(c,204,50,12,38,30,T*t/6+.17,GR,6);gear(c,194,104,8,24,18,.57-T*t/4,GY,4) + c.save();c.translate(112,168);c.scale(.76,.76);c.translate(-128,-186) + c.lineWidth=8;c.fillStyle=HD;c.beginPath();c.moveTo(128,36);c.bezierCurveTo(198,36,212,100,206,150);c.lineTo(214,170);c.lineTo(194,166);c.lineTo(186,180);c.lineTo(70,180);c.lineTo(62,166);c.lineTo(42,170);c.lineTo(50,150);c.bezierCurveTo(44,100,58,36,128,36);c.fill();c.stroke() + c.fillStyle=JS;c.beginPath();c.moveTo(100,190);c.quadraticCurveTo(54,198,44,300);c.lineTo(212,300);c.quadraticCurveTo(202,198,156,190);c.closePath();c.fill();c.stroke() + c.fillStyle='#fff';c.beginPath();c.moveTo(106,190);c.lineTo(128,226);c.lineTo(150,190);c.closePath();c.fill();c.stroke() + c.fillStyle=JSD;for(const d of[-1,1])c.beginPath(),c.moveTo(128+d*22,190),c.lineTo(128+d*4,230),c.lineTo(128+d*30,214),c.lineTo(128+d*36,192),c.closePath(),c.fill(),c.stroke() + c.fillStyle='#fff';c.lineWidth=6;c.beginPath();c.roundRect(150,244,36,22,4);c.fill();c.stroke() + c.fillStyle=SKIN;c.lineWidth=8;c.beginPath();c.moveTo(116,166);c.lineTo(116,194);c.lineTo(128,206);c.lineTo(140,194);c.lineTo(140,166);c.fill();c.beginPath();c.moveTo(116,166);c.lineTo(116,192);c.moveTo(140,166);c.lineTo(140,192);c.stroke() + c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + if(sh||ph){c.lineWidth=8;for(const x of[103,153])c.beginPath(),c.arc(x,148,14,PI*1.15,PI*1.85),c.stroke()} + else eye(c,103,140,-1),eye(c,153,140,1) + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,162,13,7,0,0,T),c.fill() + c.lineWidth=3;for(const d of[-1,1])for(const k of[-5,0,5])c.beginPath(),c.moveTo(128+d*44+k-2,165),c.lineTo(128+d*44+k+2,159),c.stroke() + c.strokeStyle=GRS;c.lineWidth=6;c.beginPath();c.moveTo(158,164);c.lineTo(176,158);c.moveTo(162,172);c.lineTo(174,168);c.stroke();c.strokeStyle='#111' + c.lineWidth=5;if(ph){c.fillStyle='#c92a2a';c.beginPath();c.ellipse(128,172,6,7,0,0,T);c.fill();c.stroke()} + else{c.beginPath();c.moveTo(116,166);c.quadraticCurveTo(128,180,140,166);c.stroke()} + c.lineWidth=8;c.fillStyle=HAIR;c.beginPath();c.moveTo(66,158) + c.bezierCurveTo(48,74,88,38,128,38);c.bezierCurveTo(168,38,208,74,190,158) + c.lineTo(182,128);c.lineTo(178,106);c.lineTo(166,108);c.lineTo(162,94);c.lineTo(148,108);c.lineTo(138,92);c.lineTo(126,108) + c.lineTo(114,94);c.lineTo(104,108);c.lineTo(92,96);c.lineTo(88,110);c.lineTo(76,108);c.lineTo(72,128);c.closePath();c.fill();c.stroke() + c.strokeStyle=HL;c.lineWidth=7;for(const[a,e]of[[1.24,1.32],[1.6,1.7]])c.beginPath(),c.arc(128,104,56,PI*a,PI*e),c.stroke() + // goggles up on her head + c.strokeStyle='#111';ds(c,16,9,'#495057',()=>{c.moveTo(60,70);c.quadraticCurveTo(128,40,196,70)}) + for(const x of[100,156]){c.fillStyle='#868e96';c.lineWidth=7;c.beginPath();c.arc(x,58,21,0,T);c.fill();c.stroke();c.fillStyle=GG;c.lineWidth=4;c.beginPath();c.arc(x,58,13,0,T);c.fill();c.stroke() + c.strokeStyle='#fff';c.lineWidth=4;c.beginPath();c.arc(x,58,7,PI*1.1,PI*1.5);c.stroke();c.strokeStyle='#111'} + c.restore() + // sweat before the wipe, one drop flicked off after + if(t<.3){drop(c,74,104,1);drop(c,152,94,.8)} + if(t>.56&&t<.84){const p=(t-.56)/.28;drop(c,166+60*p,96-30*p+60*p*p,1.1)} + if(ph){const p=(t-.66)/.26;c.fillStyle='#fff';c.lineWidth=4;c.beginPath();for(const[ox,oy,r]of[[-8,2,8],[2,-4,10],[11,3,7]])c.moveTo(80-40*p+ox+r,150-10*p+oy),c.arc(80-40*p+ox,150-10*p+oy,r*(1-p*.4),0,T);c.stroke();c.fill()} + // wrench in her other hand + c.save();c.translate(178,212);c.rotate(-.9) + ds(c,20,11,WR,()=>{c.moveTo(0,0);c.lineTo(66,0)}) + c.fillStyle=WR;c.lineWidth=6;c.beginPath();c.arc(80,0,20,.55,T-.55);c.lineTo(84,-7);c.lineTo(84,7);c.closePath();c.fill();c.stroke() + c.restore() + ds(c,22,13,JS,()=>{c.moveTo(160,200);c.quadraticCurveTo(176,224,178,214)}) + c.fillStyle=SKIN;c.lineWidth=5;c.beginPath();c.ellipse(178,212,12,13,0,0,T);c.fill();c.stroke() + // the wiping arm + const R=[46,226,70,244],S=[32,146,68,112],F=[50,128,116,100],L=(p,q,f)=>p.map((v,k)=>v+(q[k]-v)*f),[ex,ey,hx,hy]=t<.32?L(R,S,up):t<.62?L(S,F,E(wp)):L(R,F,up) + ds(c,22,13,JS,()=>{c.moveTo(78,196);c.lineTo(ex,ey);c.lineTo(hx,hy)}) + c.fillStyle=SKIN;c.lineWidth=5;c.beginPath();c.ellipse(hx,hy,12,11,0,0,T);c.fill();c.stroke() + if(sh&&wp>0&&wp<1)for(const k of[0,1])ds(c,7,3,'#fff',()=>{c.moveTo(hx-16-k*12,hy-8+k*14);c.lineTo(hx-34-k*12,hy-8+k*14)}) +} diff --git a/gen/uianime/offline/antenna.js b/gen/uianime/offline/antenna.js new file mode 100644 index 0000000..b7bda88 --- /dev/null +++ b/gen/uianime/offline/antenna.js @@ -0,0 +1,56 @@ +// worried girl with an orange bob holding her phone up high and waving it around hunting for signal, ahoge twitching like an antenna +const{sin,cos,PI,max,min,abs}=Math,T=2*PI +export const frames=12,delay=95 +const SKIN='#ffe3d1',HAIR='#ffa94d',HD='#f76707',HL='#fff4e6',EYE='#748ffc',ED='#364fc7',HOOD='#74c0fc',HOD='#339af0',BL='#ffa8a8',PH='#ffd43b',SCR='#e3fafc',RED='#fa5252',SW='#a5d8ff' +const ds=(c,a,b,s,f)=>{for(const[l,k]of[[a,'#111'],[b,s]])c.lineWidth=l,c.strokeStyle=k,c.beginPath(),f(),c.stroke();c.strokeStyle='#111'} +const eye=(c,x,y,d,gx)=>{ + c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill() + c.save();c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.clip();c.beginPath();c.ellipse(x+gx,y,11.5,15,0,0,T);c.fillStyle=EYE;c.fill();c.lineWidth=2.5;c.stroke() + c.fillStyle=ED;c.beginPath();c.ellipse(x+gx,y-10,13,9,0,0,T);c.fill() + c.fillStyle='#111';c.beginPath();c.ellipse(x+gx,y+1,5,7,0,0,T);c.fill() + c.fillStyle='#fff';c.beginPath();c.arc(x+gx-4,y-6,4.5,0,T);c.fill();c.beginPath();c.arc(x+gx+5,y+7,2,0,T);c.fill();c.restore() + c.lineWidth=6;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke() + c.lineWidth=2.5;c.beginPath();c.moveTo(x-8,y+18);c.lineTo(x+8,y+18);c.stroke() +} +export default(c,t)=>{ + const a=-1.4+.17*sin(2*T*t),sx=150,sy=226,hx=sx+140*cos(a),hy=sy+140*sin(a),gx=4,aw=.35*sin(2*T*t+1) + const H=f=>{c.save();c.translate(112,198);c.scale(.8,.8);c.translate(-128,-186);f();c.restore()} + H(()=>{ + c.lineWidth=7;c.fillStyle=HD;c.beginPath();c.moveTo(128,34);c.bezierCurveTo(198,34,212,100,206,158);c.quadraticCurveTo(204,180,184,180);c.lineTo(72,180);c.quadraticCurveTo(52,180,50,158);c.bezierCurveTo(44,100,58,34,128,34);c.fill();c.stroke() + c.fillStyle=HOD;c.beginPath();c.ellipse(128,206,62,22,0,0,T);c.fill();c.stroke() + c.fillStyle=HOOD;c.beginPath();c.moveTo(96,196);c.quadraticCurveTo(56,206,48,262);c.lineTo(208,262);c.quadraticCurveTo(200,206,160,196);c.closePath();c.fill();c.stroke() + c.fillStyle=SKIN;c.beginPath();c.moveTo(114,168);c.lineTo(114,194);c.quadraticCurveTo(128,208,142,194);c.lineTo(142,168);c.fill();c.lineWidth=6;c.beginPath();c.moveTo(114,168);c.lineTo(114,192);c.moveTo(142,168);c.lineTo(142,192);c.stroke() + for(const d of[-1,1])ds(c,10,4,'#fff',()=>{c.moveTo(128+d*14,206);c.lineTo(128+d*16,240)}) + c.fillStyle='#fff';c.lineWidth=4;for(const d of[-1,1])c.beginPath(),c.roundRect(128+d*16-5,238,10,12,4),c.fill(),c.stroke() + c.save();c.translate(130,40);c.rotate(aw) + c.lineWidth=6;c.fillStyle=HAIR;c.beginPath();c.moveTo(-8,4);c.quadraticCurveTo(-14,-30,16,-34);c.quadraticCurveTo(-2,-24,8,4);c.closePath();c.fill();c.stroke() + c.restore() + c.lineWidth=7;c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + eye(c,103,142,-1,gx);eye(c,153,142,1,gx) + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,164,13,7,0,0,T),c.fill() + c.lineWidth=3;for(const d of[-1,1])for(const k of[-5,0,5])c.beginPath(),c.moveTo(128+d*44+k-2,167),c.lineTo(128+d*44+k+2,161),c.stroke() + c.lineWidth=4.5;c.fillStyle='#c92a2a';c.beginPath();c.ellipse(130,172,7,6,0,0,T);c.fill();c.stroke() + c.lineWidth=7;c.fillStyle=HAIR;c.beginPath();c.moveTo(66,160) + c.bezierCurveTo(50,74,88,36,128,36);c.bezierCurveTo(168,36,206,74,190,160) + c.quadraticCurveTo(188,122,180,106);c.lineTo(168,112);c.lineTo(162,96);c.lineTo(148,108);c.lineTo(140,92);c.lineTo(128,108) + c.lineTo(116,92);c.lineTo(106,108);c.lineTo(94,96);c.lineTo(88,112);c.lineTo(78,106);c.quadraticCurveTo(70,128,66,160);c.closePath();c.fill();c.stroke() + c.strokeStyle=HL;c.lineWidth=6;for(const[s,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,56,PI*s,PI*e),c.stroke() + c.strokeStyle='#111';c.lineWidth=5;c.beginPath();c.moveTo(86,124);c.lineTo(110,115);c.moveTo(146,115);c.lineTo(170,124);c.stroke() + c.fillStyle=SW;c.lineWidth=5;c.beginPath();c.moveTo(66,110);c.quadraticCurveTo(76,128,66,134);c.quadraticCurveTo(56,128,66,110);c.fill();c.stroke() + }) + const v=cos(2*T*t),g=v>0?1:-1 + if(abs(v)>.3)for(const r of[160,190])ds(c,8,3.5,'#fff',()=>{c.arc(sx,sy,r,min(a-g*.38,a-g*.2),max(a-g*.38,a-g*.2))}) + ds(c,26,15,HOOD,()=>{c.moveTo(sx,sy);c.lineTo(sx+70*cos(a+.28),sy+70*sin(a+.28));c.lineTo(hx,hy+4)}) + c.save();c.translate(hx+cos(a)*30,hy+sin(a)*30);c.rotate(a+PI/2) + c.fillStyle=PH;c.lineWidth=5;c.beginPath();c.roundRect(-22,-38,44,76,9);c.fill();c.stroke() + c.fillStyle=SCR;c.lineWidth=3.5;c.beginPath();c.roundRect(-16,-30,32,58,4);c.fill();c.stroke() + c.fillStyle='#ced4da';c.lineWidth=2.5;for(let k=0;k<4;k++)c.beginPath(),c.roundRect(-11+k*6,8-k*6,4.5,9+k*6,1.5),c.fill(),c.stroke() + ds(c,7,3.5,RED,()=>{c.moveTo(2,-24);c.lineTo(12,-14);c.moveTo(12,-24);c.lineTo(2,-14)}) + c.restore() + c.lineWidth=5;c.fillStyle=SKIN;c.beginPath();c.ellipse(hx,hy,12,13,a,0,T);c.fill();c.stroke() + const q=max(0,sin(T*t*2-1)) + c.save();c.translate(44,44-6*q);c.rotate(.2*sin(T*t*2)) + for(const[l,s]of[[13,'#111'],[6,RED]])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),c.moveTo(-10,-12),c.quadraticCurveTo(-10,-24,2,-24),c.quadraticCurveTo(14,-24,12,-12),c.quadraticCurveTo(10,-4,1,0),c.lineTo(1,6),c.stroke() + c.fillStyle=RED;c.lineWidth=4;c.strokeStyle='#111';c.beginPath();c.arc(1,19,5,0,T);c.fill();c.stroke() + c.restore() +} diff --git a/gen/uianime/offline/cable.js b/gen/uianime/offline/cable.js new file mode 100644 index 0000000..9c30b63 --- /dev/null +++ b/gen/uianime/offline/cable.js @@ -0,0 +1,64 @@ +// confused girl with mint twin buns holding up an unplugged cable that crackles with little sparks, tilting her head side to side as ? marks pop +const{sin,cos,PI,max,min}=Math,T=2*PI +export const frames=12,delay=95 +const SKIN='#ffe3d1',HAIR='#63e6be',HD='#12b886',HL='#e6fcf5',EYE='#f06595',ED='#a61e4d',OV='#ffd43b',OD='#f59f00',BL='#ffa8a8',CAB='#dee2e6',PL='#f8f9fa',PR='#adb5bd',ZAP='#ffe066',Q=['#ff8787','#748ffc'],SW='#a5d8ff' +const ds=(c,a,b,s,f)=>{for(const[l,k]of[[a,'#111'],[b,s]])c.lineWidth=l,c.strokeStyle=k,c.beginPath(),f(),c.stroke();c.strokeStyle='#111'} +const eye=(c,x,y,d,gx)=>{ + c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill() + c.save();c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.clip();c.beginPath();c.ellipse(x+gx,y+2,11.5,15,0,0,T);c.fillStyle=EYE;c.fill();c.lineWidth=2.5;c.stroke() + c.fillStyle=ED;c.beginPath();c.ellipse(x+gx,y-8,13,9,0,0,T);c.fill() + c.fillStyle='#111';c.beginPath();c.ellipse(x+gx,y+3,4.5,6.5,0,0,T);c.fill() + c.fillStyle='#fff';c.beginPath();c.arc(x+gx-4,y-5,4.5,0,T);c.fill();c.beginPath();c.arc(x+gx+5,y+8,2,0,T);c.fill();c.restore() + c.lineWidth=6;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke() + c.lineWidth=2.5;c.beginPath();c.moveTo(x-8,y+18);c.lineTo(x+8,y+18);c.stroke() +} +const qm=(c,x,y,s,col)=>{c.save();c.translate(x,y);c.scale(s,s) + for(const[l,k]of[[13,'#111'],[6,col]])c.lineWidth=l,c.strokeStyle=k,c.beginPath(),c.moveTo(-10,-12),c.quadraticCurveTo(-10,-24,2,-24),c.quadraticCurveTo(14,-24,12,-12),c.quadraticCurveTo(10,-4,1,0),c.lineTo(1,6),c.stroke() + c.fillStyle=col;c.lineWidth=4;c.strokeStyle='#111';c.beginPath();c.arc(1,19,5,0,T);c.fill();c.stroke();c.restore()} +const zap=(c,x,y,a,s)=>{c.save();c.translate(x,y);c.rotate(a);c.scale(s,s);c.fillStyle=ZAP;c.lineWidth=3;c.beginPath();for(const[u,v]of[[-2,-12],[7,-12],[2,-3],[8,-3],[-5,12],[-1,1],[-7,1]])c.lineTo(u,v);c.closePath();c.fill();c.stroke();c.restore()} +export default(c,t,i)=>{ + const k=i%6,tilt=(i<6?1:-1)*.1*min(1,k/1.5,(6-k)/1.5)*(k<1?0:1),side=i<6?1:-1 + const H=f=>{c.save();c.translate(108,198);c.scale(.82,.82);c.rotate(tilt);c.translate(-128,-186);f();c.restore()} + H(()=>{ + c.lineWidth=7;c.fillStyle=HAIR;for(const d of[-1,1])c.beginPath(),c.arc(128+d*58,58,28,0,T),c.fill(),c.stroke() + c.strokeStyle=HL;c.lineWidth=5;for(const d of[-1,1])c.beginPath(),c.arc(128+d*58,58,18,PI*1.1,PI*1.5),c.stroke();c.strokeStyle='#111' + c.lineWidth=7;c.fillStyle=HD;c.beginPath();c.moveTo(128,34);c.bezierCurveTo(198,34,212,100,206,158);c.quadraticCurveTo(204,180,184,180);c.lineTo(72,180);c.quadraticCurveTo(52,180,50,158);c.bezierCurveTo(44,100,58,34,128,34);c.fill();c.stroke() + }) + c.save();c.translate(108,198);c.scale(.82,.82);c.translate(-128,-186) + c.lineWidth=7;c.fillStyle='#fff';c.beginPath();c.moveTo(98,190);c.quadraticCurveTo(56,198,48,262);c.lineTo(208,262);c.quadraticCurveTo(200,198,158,190);c.closePath();c.fill();c.stroke() + c.fillStyle=OV;c.beginPath();c.moveTo(92,262);c.lineTo(96,222);c.lineTo(160,222);c.lineTo(164,262);c.closePath();c.fill();c.stroke() + for(const d of[-1,1])ds(c,14,6,OV,()=>{c.moveTo(128+d*30,224);c.lineTo(128+d*38,196)}) + c.fillStyle=OD;c.lineWidth=4;for(const d of[-1,1])c.beginPath(),c.arc(128+d*28,232,5,0,T),c.fill(),c.stroke() + c.fillStyle='#fff';c.lineWidth=4;c.beginPath();c.roundRect(116,236,24,16,5);c.fill();c.stroke() + c.fillStyle=SKIN;c.lineWidth=7;c.beginPath();c.moveTo(114,168);c.lineTo(114,194);c.quadraticCurveTo(128,206,142,194);c.lineTo(142,168);c.fill();c.beginPath();c.moveTo(114,168);c.lineTo(114,192);c.moveTo(142,168);c.lineTo(142,192);c.stroke() + c.restore() + H(()=>{ + c.lineWidth=7;c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + eye(c,103,142,-1,4);eye(c,153,142,1,4) + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,164,13,7,0,0,T),c.fill() + c.lineWidth=3;for(const d of[-1,1])for(const k of[-5,0,5])c.beginPath(),c.moveTo(128+d*44+k-2,167),c.lineTo(128+d*44+k+2,161),c.stroke() + c.lineWidth=4.5;c.beginPath();c.moveTo(114,172);c.quadraticCurveTo(119,166,124,172);c.quadraticCurveTo(129,178,134,172);c.quadraticCurveTo(139,166,144,172);c.stroke() + c.lineWidth=7;c.fillStyle=HAIR;c.beginPath();c.moveTo(68,156) + c.bezierCurveTo(52,74,88,36,128,36);c.bezierCurveTo(168,36,204,74,188,156) + c.quadraticCurveTo(186,120,178,104);c.quadraticCurveTo(170,106,164,112);c.quadraticCurveTo(158,98,148,92);c.quadraticCurveTo(142,104,134,110) + c.quadraticCurveTo(128,98,120,92);c.quadraticCurveTo(114,104,106,110);c.quadraticCurveTo(100,98,92,96);c.quadraticCurveTo(88,106,84,112) + c.quadraticCurveTo(80,104,78,104);c.quadraticCurveTo(70,126,68,156);c.closePath();c.fill();c.stroke() + c.strokeStyle=HL;c.lineWidth=6;for(const[s,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,56,PI*s,PI*e),c.stroke() + c.strokeStyle='#111';c.lineWidth=5;c.beginPath();c.moveTo(88,120);c.quadraticCurveTo(100,110,114,116);c.moveTo(144,120);c.lineTo(168,122);c.stroke() + c.fillStyle=SW;c.lineWidth=5;c.beginPath();c.moveTo(190,104);c.quadraticCurveTo(200,122,190,128);c.quadraticCurveTo(180,122,190,104);c.fill();c.stroke() + }) + ds(c,22,12,SKIN,()=>{c.moveTo(160,240);c.lineTo(214,214);c.lineTo(206,176)}) + ds(c,20,11,CAB,()=>{c.moveTo(206,176);c.bezierCurveTo(200,236,246,214,244,256)}) + c.save();c.translate(206,146);c.rotate(.22) + c.fillStyle=PR;c.lineWidth=4;for(const d of[-1,1])c.beginPath(),c.roundRect(d*8-3.5,-36,7,18,2),c.fill(),c.stroke() + c.fillStyle=PL;c.lineWidth=5;c.beginPath();c.roundRect(-18,-22,36,34,8);c.fill();c.stroke() + c.lineWidth=3;c.beginPath();c.moveTo(-10,-2);c.lineTo(10,-2);c.moveTo(-10,4);c.lineTo(10,4);c.stroke() + const b=i%2*.3 + for(let m=0;m<5;m++){const an=-PI/2+(m-2)*.6+b,r=24+(m+i)%2*7;ds(c,8,4,ZAP,()=>{c.moveTo(cos(an)*15,-40+sin(an)*15);c.lineTo(cos(an)*r,-40+sin(an)*r)})} + zap(c,i%2?-24:24,-52,i%2?-.4:.4,1.3) + c.restore() + c.lineWidth=5;c.fillStyle=SKIN;c.beginPath();c.ellipse(206,170,13,12,.2,0,T);c.fill();c.stroke() + c.beginPath();c.ellipse(196,164,5,8,-.6,0,T);c.fill();c.stroke() + const p=k/6,s=min(1,p*4)*(1-max(0,p-.75)*4) + if(s>.05)qm(c,side>0?42:172,62-14*p,.6+.5*s,Q[i<6?0:1]) +} diff --git a/gen/uianime/order/delivery.js b/gen/uianime/order/delivery.js new file mode 100644 index 0000000..996e87e --- /dev/null +++ b/gen/uianime/order/delivery.js @@ -0,0 +1,65 @@ +// brown haired delivery girl in a blue cap hugging a parcel under one arm and snapping a crisp salute to her brim, a twinkle popping off it +const{sin,cos,PI,max,min,atan2}=Math,T=2*PI +export const frames=16,delay=80 +const SKIN='#ffe3d1',HAIR='#8d5a3b',HD='#6b3f26',HL='#e0b08f',EYE='#fab005',ED='#e67700',CAP='#339af0',CD='#1971c2',BOX='#e8b07a',BD='#c47f45',TAPE='#fff3bf',BL='#ffa8a8',MO='#c92a2a',TG='#ff8fab' +const ds=(c,a,b,s,f)=>{for(const[l,k]of[[a,'#111'],[b,s]])c.lineWidth=l,c.strokeStyle=k,c.beginPath(),f(),c.stroke();c.strokeStyle='#111'} +const ez=(t,a,b)=>{const x=min(1,max(0,(t-a)/(b-a)));return x*x*(3-2*x)} +const eye=(c,x,y,d)=>{ + c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill() + c.save();c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.clip();c.fillStyle=EYE;c.fill();c.fillStyle=ED;c.beginPath();c.ellipse(x,y-8,13,10,0,0,T);c.fill();c.restore() + c.lineWidth=2.5;c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.stroke() + c.fillStyle='#111';c.beginPath();c.ellipse(x,y+3,5.5,7.5,0,0,T);c.fill() + c.fillStyle='#fff';c.beginPath();c.arc(x-4,y-5,4.5,0,T);c.fill();c.beginPath();c.arc(x+5,y+8,2,0,T);c.fill() + c.lineWidth=6;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke() + c.lineWidth=2.5;c.beginPath();c.moveTo(x-8,y+18);c.lineTo(x+8,y+18);c.stroke() +} +const glint=(c,x,y,r,a)=>{c.save();c.translate(x,y);c.rotate(a);c.beginPath();for(let k=0;k<8;k++){const rr=k%2?r*.28:r,b=k*PI/4;c.lineTo(cos(b)*rr,sin(b)*rr)}c.closePath();c.restore();c.fill();c.stroke()} +export default(c,t)=>{ + const u=ez(t,0,.14)-ez(t,.84,.98),g=t>=.14&&t<.5?sin(PI*(t-.14)/.36):0 + c.lineWidth=6;c.fillStyle=HD;c.beginPath();c.moveTo(128,34);c.bezierCurveTo(196,34,208,96,202,170);c.quadraticCurveTo(192,182,182,172);c.lineTo(74,172);c.quadraticCurveTo(64,182,54,170);c.bezierCurveTo(48,96,60,34,128,34);c.fill();c.stroke() + c.lineWidth=6;c.fillStyle=CAP;c.beginPath();c.moveTo(100,190);c.quadraticCurveTo(62,198,54,250);c.lineTo(202,250);c.quadraticCurveTo(194,198,156,190);c.closePath();c.fill();c.stroke() + c.fillStyle='#fff';for(const d of[-1,1])c.beginPath(),c.moveTo(128,206),c.lineTo(128+d*30,188),c.lineTo(128+d*34,204),c.closePath(),c.fill(),c.stroke() + c.strokeStyle=CD;c.lineWidth=4;c.beginPath();c.moveTo(128,208);c.lineTo(128,226);c.stroke();c.strokeStyle='#111' + c.fillStyle=SKIN;c.lineWidth=5;c.beginPath();c.moveTo(116,168);c.lineTo(116,192);c.lineTo(128,206);c.lineTo(140,192);c.lineTo(140,168);c.fill();c.beginPath();c.moveTo(116,168);c.lineTo(116,190);c.moveTo(140,168);c.lineTo(140,190);c.stroke() + c.fillStyle='#fff';c.beginPath();c.roundRect(154,214,30,20,4);c.fill();c.stroke() + c.strokeStyle=CAP;c.lineWidth=3;c.beginPath();c.moveTo(160,221);c.lineTo(178,221);c.moveTo(160,228);c.lineTo(172,228);c.stroke();c.strokeStyle='#111' + c.lineWidth=6;c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + eye(c,103,142,-1);eye(c,153,142,1) + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*42,163,12,6,0,0,T),c.fill() + c.lineWidth=2.5;for(const d of[-1,1])for(const k of[-5,0,5])c.beginPath(),c.moveTo(128+d*42+k-2,166),c.lineTo(128+d*42+k+2,160),c.stroke() + c.lineWidth=3.5;c.fillStyle=MO;c.beginPath();c.moveTo(117,167);c.quadraticCurveTo(128,172,139,167);c.quadraticCurveTo(137,182,128,182);c.quadraticCurveTo(119,182,117,167);c.fill();c.stroke() + c.save();c.clip();c.fillStyle=TG;c.beginPath();c.ellipse(128,183,7,5,0,0,T);c.fill();c.restore() + c.lineWidth=6;c.fillStyle=HAIR;c.beginPath();c.moveTo(70,150) + c.bezierCurveTo(56,96,70,80,96,80);c.lineTo(160,80);c.bezierCurveTo(186,80,200,96,186,150) + c.quadraticCurveTo(184,120,178,106);c.quadraticCurveTo(170,106,164,114);c.quadraticCurveTo(160,102,150,96);c.quadraticCurveTo(144,106,136,112) + c.quadraticCurveTo(132,100,124,94);c.quadraticCurveTo(118,104,110,110);c.quadraticCurveTo(106,100,96,98);c.quadraticCurveTo(90,106,86,114) + c.quadraticCurveTo(80,106,78,106);c.quadraticCurveTo(70,124,70,150);c.closePath();c.fill();c.stroke() + c.fillStyle=CAP;c.beginPath();c.moveTo(66,96);c.bezierCurveTo(56,30,200,30,190,96);c.closePath();c.fill();c.stroke() + c.strokeStyle='#fff';c.lineWidth=5;c.beginPath();c.arc(128,96,56,PI*1.25,PI*1.4);c.stroke();c.strokeStyle='#111' + c.fillStyle=CD;c.beginPath();c.moveTo(56,96);c.quadraticCurveTo(128,78,200,96);c.quadraticCurveTo(206,108,196,114);c.quadraticCurveTo(128,98,60,114);c.quadraticCurveTo(50,108,56,96);c.fill();c.stroke() + c.strokeStyle='#74c0fc';c.lineWidth=3;c.beginPath();c.moveTo(78,100);c.quadraticCurveTo(128,90,178,100);c.stroke();c.strokeStyle='#111' + c.fillStyle='#fff';c.lineWidth=4;c.beginPath();c.arc(128,66,12,0,T);c.fill();c.stroke() + c.fillStyle=CAP;c.lineWidth=2.5;c.beginPath();c.moveTo(121,62);c.lineTo(128,58);c.lineTo(135,62);c.lineTo(135,72);c.lineTo(121,72);c.closePath();c.fill();c.stroke() + // salute arm + const ex=200+30*u,ey=246-84*u,hx=176+22*u,hy=268-150*u,a=atan2(hy-ey,hx-ex) + ds(c,30,19,CAP,()=>{c.moveTo(176,214);c.lineTo(ex,ey);c.lineTo(ex+(hx-ex)*.7,ey+(hy-ey)*.7)}) + c.save();c.translate(hx,hy);c.rotate(a-.45*u) + c.lineWidth=5;c.fillStyle=SKIN;c.beginPath();c.roundRect(-10,-10,44,20,10);c.fill();c.stroke() + c.beginPath();c.ellipse(4,10,10,5,.3,0,T);c.fill();c.stroke() + c.lineWidth=2.5;c.beginPath();c.moveTo(14,-3);c.lineTo(32,-3);c.moveTo(14,3);c.lineTo(32,3);c.stroke() + c.restore() + if(g>0){c.fillStyle='#fff9db';c.lineWidth=3.5;glint(c,214,80,6+14*g,g*2) + ds(c,8,3.5,'#fff',()=>{for(const b of[-2.2,-1.6,-1])c.moveTo(186+36*cos(b),104+36*sin(b)),c.lineTo(186+(44+6*g)*cos(b),104+(44+6*g)*sin(b))})} + // parcel under the other arm + ds(c,30,19,CAP,()=>{c.moveTo(84,208);c.lineTo(42,230)}) + c.save();c.translate(86,224);c.rotate(-.05) + c.lineWidth=6;c.fillStyle=BOX;c.beginPath();c.rect(-50,-20,100,52);c.fill();c.stroke() + c.fillStyle=BD;c.beginPath();c.moveTo(-50,-20);c.lineTo(-38,-34);c.lineTo(62,-34);c.lineTo(50,-20);c.closePath();c.fill();c.stroke() + c.fillStyle=TAPE;c.lineWidth=4;c.beginPath();c.rect(-10,-20,20,52);c.fill();c.stroke() + c.beginPath();c.moveTo(-6,-34);c.lineTo(12,-34);c.lineTo(4,-20);c.lineTo(-14,-20);c.closePath();c.fill();c.stroke() + c.fillStyle='#fff';c.beginPath();c.roundRect(18,-10,26,22,3);c.fill();c.stroke() + c.strokeStyle=BD;c.lineWidth=3;c.beginPath();c.moveTo(31,7);c.lineTo(31,-5);c.moveTo(25,1);c.lineTo(31,-6);c.lineTo(37,1);c.stroke();c.strokeStyle='#111' + c.lineWidth=5;c.fillStyle=SKIN;c.beginPath();c.ellipse(-50,8,10,14,0,0,T);c.fill();c.stroke() + for(const y of[-2,9,20])c.beginPath(),c.ellipse(-40,y,9,5,0,0,T),c.fill(),c.stroke() + c.restore() +} diff --git a/gen/uianime/payment/tap.js b/gen/uianime/payment/tap.js new file mode 100644 index 0000000..083f442 --- /dev/null +++ b/gen/uianime/payment/tap.js @@ -0,0 +1,63 @@ +// magenta haired girl taps her card on a payment terminal, contactless waves ripple out, the screen flips green and a big check pops up as she beams +const{sin,cos,PI,max,min}=Math,T=2*PI +export const frames=16,delay=80 +const SKIN='#ffe3d1',HAIR='#da77f2',HD='#ae3ec9',HL='#f8f0fc',EYE='#51cf66',ED='#2b8a3e',SWT='#ff8787',SD='#fa5252',BAND='#ffd43b',BL='#ffa8a8',MO='#c92a2a',TG='#ff8fab',TER='#ced4da',TD='#868e96',SCR='#364fc7',OK='#51cf66',CARD='#4dabf7',CHIP='#ffd43b' +const ds=(c,a,b,s,f)=>{for(const[l,k]of[[a,'#111'],[b,s]])c.lineWidth=l,c.strokeStyle=k,c.beginPath(),f(),c.stroke();c.strokeStyle='#111'} +const ez=(t,a,b)=>{const x=min(1,max(0,(t-a)/(b-a)));return x*x*(3-2*x)} +const eye=(c,x,y,d)=>{ + c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill() + c.save();c.beginPath();c.ellipse(x+3,y+3,11.5,15,0,0,T);c.clip();c.fillStyle=EYE;c.fill();c.fillStyle=ED;c.beginPath();c.ellipse(x+3,y-7,13,10,0,0,T);c.fill();c.restore() + c.lineWidth=2.5;c.beginPath();c.ellipse(x+3,y+3,11.5,15,0,0,T);c.stroke() + c.fillStyle='#111';c.beginPath();c.ellipse(x+5,y+4,5.5,7.5,0,0,T);c.fill() + c.fillStyle='#fff';c.beginPath();c.arc(x,y-4,4.5,0,T);c.fill();c.beginPath();c.arc(x+8,y+10,2,0,T);c.fill() + c.lineWidth=6;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke() + c.lineWidth=2.5;c.beginPath();c.moveTo(x-8,y+18);c.lineTo(x+8,y+18);c.stroke() +} +const check=(c,x,y,s)=>ds(c,9*s,4.5*s,'#fff',()=>{c.moveTo(x-9*s,y);c.lineTo(x-3*s,y+7*s);c.lineTo(x+10*s,y-7*s)}) +export default(c,t)=>{ + const k=ez(t,.04,.22)-ez(t,.84,.97),ok=t>=.28&&t<.9,q=min(1,max(0,(t-.28)/.12)),bs=ok?(1+2.7*(q-1)**3+1.7*(q-1)**2)*(1-ez(t,.8,.9)):0 + c.save();c.translate(96,254);c.scale(.86,.86);c.translate(-128,-250) + c.lineWidth=6;c.fillStyle=HD;c.beginPath();c.moveTo(128,34);c.bezierCurveTo(198,34,212,96,206,150);c.quadraticCurveTo(214,200,204,250);c.lineTo(52,250);c.quadraticCurveTo(42,200,50,150);c.bezierCurveTo(44,96,58,34,128,34);c.fill();c.stroke() + c.fillStyle=SWT;c.beginPath();c.moveTo(100,190);c.quadraticCurveTo(62,198,54,250);c.lineTo(202,250);c.quadraticCurveTo(194,198,156,190);c.closePath();c.fill();c.stroke() + c.fillStyle='#fff';for(const d of[-1,1])c.beginPath(),c.moveTo(128,204),c.quadraticCurveTo(128+d*18,186,128+d*32,190),c.quadraticCurveTo(128+d*30,206,128,212),c.closePath(),c.fill(),c.stroke() + c.strokeStyle=SD;c.lineWidth=4;for(const y of[226,240])c.beginPath(),c.moveTo(70,y),c.lineTo(190,y),c.stroke();c.strokeStyle='#111' + c.lineWidth=5;c.fillStyle=SKIN;c.beginPath();c.moveTo(116,168);c.lineTo(116,194);c.quadraticCurveTo(128,204,140,194);c.lineTo(140,168);c.fill();c.beginPath();c.moveTo(116,168);c.lineTo(116,192);c.moveTo(140,168);c.lineTo(140,192);c.stroke() + c.lineWidth=6;c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + if(ok){c.lineWidth=6;for(const x of[103,153])c.beginPath(),c.arc(x,148,14,PI*1.15,PI*1.85),c.stroke()}else eye(c,103,140,-1),eye(c,153,140,1) + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*42,162,12,6,0,0,T),c.fill() + c.lineWidth=2.5;for(const d of[-1,1])for(const k of[-5,0,5])c.beginPath(),c.moveTo(128+d*42+k-2,165),c.lineTo(128+d*42+k+2,159),c.stroke() + if(ok){c.lineWidth=3.5;c.fillStyle=MO;c.beginPath();c.moveTo(116,165);c.quadraticCurveTo(128,170,140,165);c.quadraticCurveTo(138,184,128,184);c.quadraticCurveTo(118,184,116,165);c.fill();c.stroke();c.save();c.clip();c.fillStyle=TG;c.beginPath();c.ellipse(128,185,7,5,0,0,T);c.fill();c.restore()} + else{c.lineWidth=3.5;c.beginPath();c.moveTo(122,169);c.quadraticCurveTo(128,173,134,169);c.stroke()} + c.lineWidth=6;c.fillStyle=HAIR;c.beginPath();c.moveTo(66,196) + c.bezierCurveTo(48,74,88,36,128,36);c.bezierCurveTo(168,36,208,74,190,196);c.quadraticCurveTo(182,184,178,192) + c.quadraticCurveTo(184,124,178,104);c.quadraticCurveTo(170,104,164,112);c.quadraticCurveTo(160,98,150,92);c.quadraticCurveTo(144,104,136,110) + c.quadraticCurveTo(132,96,124,90);c.quadraticCurveTo(118,102,110,108);c.quadraticCurveTo(106,96,96,94);c.quadraticCurveTo(90,104,86,112) + c.quadraticCurveTo(80,104,78,104);c.quadraticCurveTo(72,124,78,192);c.quadraticCurveTo(72,184,66,196);c.closePath();c.fill();c.stroke() + c.strokeStyle=HL;c.lineWidth=5;for(const[a,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,56,PI*a,PI*e),c.stroke() + c.strokeStyle='#111';c.fillStyle=BAND;c.lineWidth=5;c.beginPath();c.moveTo(70,80);c.bezierCurveTo(90,48,166,48,186,80);c.lineTo(182,92);c.bezierCurveTo(162,64,94,64,74,92);c.closePath();c.fill();c.stroke() + c.restore() + // card arm + const cx=186+8*k,cy=104+44*k,ca=-.35+.3*k + ds(c,27,17,SWT,()=>{c.moveTo(138,228);c.lineTo(156,210);c.lineTo(cx-18,cy+22)}) + // terminal + c.lineWidth=6;c.fillStyle=TER;c.beginPath();c.roundRect(158,150,80,100,14);c.fill();c.stroke() + c.fillStyle=ok?OK:SCR;c.lineWidth=4;c.beginPath();c.roundRect(168,160,60,40,6);c.fill();c.stroke() + if(ok)check(c,198,180,1.1);else ds(c,6,2.5,'#fff',()=>{for(const r of[6,12])c.arc(190,182,r,-.7,.7)}) + c.fillStyle='#fff';c.lineWidth=3;for(let r=0;r<2;r++)for(let j=0;j<3;j++)c.beginPath(),c.roundRect(172+j*19,210+r*16,14,10,3),c.fill(),c.stroke() + // contactless ripples on the tap + if(t>=.16&&t<.36){const p=(t-.16)/.2;ds(c,7,3,'#fff',()=>{for(const r of[28,38,48]){const R=r+8*p;c.moveTo(cx+R*cos(-2.3),cy+R*sin(-2.3));c.arc(cx,cy,R,-2.3,-.84)}})} + // card + hand + c.save();c.translate(cx,cy);c.rotate(ca) + c.lineWidth=5;c.fillStyle=CARD;c.beginPath();c.roundRect(-32,-20,64,40,7);c.fill();c.stroke() + c.fillStyle='#fff';c.beginPath();c.rect(-32,-10,64,7);c.fill() + c.fillStyle=CHIP;c.lineWidth=3;c.beginPath();c.roundRect(-22,2,14,11,2);c.fill();c.stroke() + c.lineWidth=5;c.fillStyle=SKIN;c.beginPath();c.ellipse(-26,12,12,11,0,0,T);c.fill();c.stroke() + c.beginPath();c.ellipse(-16,4,9,5,-.4,0,T);c.fill();c.stroke() + c.restore() + // check badge pops up + if(bs>.02){c.save();c.translate(206,56);c.scale(bs,bs) + c.fillStyle=OK;c.lineWidth=6;c.beginPath();c.arc(0,0,30,0,T);c.fill();c.stroke() + c.strokeStyle='#fff';c.lineWidth=4;c.beginPath();c.arc(0,0,22,PI*1.1,PI*1.4);c.stroke() + check(c,1,2,1.5);c.restore() + c.fillStyle='#ffd43b';c.lineWidth=3.5;for(const[x,y,o]of[[160,30,0],[244,98,.3]]){const r=12*sin(PI*min(1,max(0,(t-.32-o*.2)/.4)));if(r>.5)c.beginPath(),c.moveTo(x,y-r),c.quadraticCurveTo(x+r*.15,y-r*.15,x+r,y),c.quadraticCurveTo(x+r*.15,y+r*.15,x,y+r),c.quadraticCurveTo(x-r*.15,y+r*.15,x-r,y),c.quadraticCurveTo(x-r*.15,y-r*.15,x,y-r),c.fill(),c.stroke()}} +} diff --git a/gen/uianime/phone/waiting.js b/gen/uianime/phone/waiting.js new file mode 100644 index 0000000..0cdad59 --- /dev/null +++ b/gen/uianime/phone/waiting.js @@ -0,0 +1,56 @@ +// indigo haired girl in a comfy hoodie staring half-lidded at her phone, pulls to refresh, still no notifications, and lets out a big sigh +const{sin,PI,min}=Math,T=2*PI +export const frames=16,delay=90 +const SKIN='#ffe3d1',HAIR='#748ffc',HD='#4c6ef5',HL='#dbe4ff',EYE='#f783ac',ED='#c2255c',BL='#ffa8a8',HO='#96f2d7',HOD='#20c997',PH='#ffd43b',SCR='#e7f5ff' +const E=x=>x<=0?0:x>=1?1:x*x*(3-2*x) +const ds=(c,a,b,s,f)=>{for(const[l,k]of[[a,'#111'],[b,s]])c.lineWidth=l,c.strokeStyle=k,c.beginPath(),f(),c.stroke();c.strokeStyle='#111'} +const eye=(c,x,y,d,l)=>{ + const ly=y-17+30*l + c.save();c.beginPath();c.moveTo(x-24,ly+3);c.quadraticCurveTo(x,ly,x+24,ly+3);c.lineTo(x+24,y+30);c.lineTo(x-24,y+30);c.clip() + c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill() + c.beginPath();c.ellipse(x+3,y+5,11.5,14,0,0,T);c.fillStyle=EYE;c.fill();c.lineWidth=2.5;c.stroke() + c.fillStyle=ED;c.beginPath();c.ellipse(x+3,y-4,12,9,0,0,T);c.fill() + c.fillStyle='#111';c.beginPath();c.ellipse(x+4,y+7,5.5,7,0,0,T);c.fill() + c.fillStyle='#fff';c.beginPath();c.arc(x,y+2,4,0,T);c.fill();c.restore() + c.lineWidth=7;c.beginPath();c.moveTo(x-16,ly+3);c.quadraticCurveTo(x,ly,x+16,ly+3);c.moveTo(x+d*15,ly+3);c.lineTo(x+d*20,ly+5);c.stroke() + c.lineWidth=2.5;c.beginPath();c.moveTo(x-8,y+18);c.lineTo(x+8,y+18);c.stroke() +} +const puff=(c,x,y,s)=>{c.fillStyle='#fff';c.lineWidth=4;c.beginPath();for(const[ox,oy,r]of[[-9,3,9],[2,-4,11],[12,4,8]])c.moveTo(x+(ox+r)*s,y+oy*s),c.arc(x+ox*s,y+oy*s,r*s,0,T);c.stroke();c.fill()} +export default(c,t,i)=>{ + const sg=E((t-.42)/.08)-E((t-.66)/.1),dr=5*sg,bk=i==13 + c.save();c.translate(128,150+dr*.6);c.scale(.76,.76);c.translate(-128,-186) + c.lineWidth=8;c.fillStyle=HD;c.beginPath();c.moveTo(128,34);c.bezierCurveTo(204,34,216,110,210,190);c.quadraticCurveTo(214,226,196,232);c.lineTo(60,232);c.quadraticCurveTo(42,226,46,190);c.bezierCurveTo(40,110,52,34,128,34);c.fill();c.stroke() + c.fillStyle=HO;c.beginPath();c.moveTo(96,188);c.quadraticCurveTo(46,196,36,310);c.lineTo(220,310);c.quadraticCurveTo(210,196,160,188);c.closePath();c.fill();c.stroke() + c.fillStyle=HOD;c.beginPath();c.moveTo(84,194);c.quadraticCurveTo(128,236,172,194);c.quadraticCurveTo(160,186,150,186);c.quadraticCurveTo(128,206,106,186);c.quadraticCurveTo(96,186,84,194);c.fill();c.stroke() + c.fillStyle=SKIN;c.beginPath();c.moveTo(116,166);c.lineTo(116,190);c.quadraticCurveTo(128,204,140,190);c.lineTo(140,166);c.fill();c.beginPath();c.moveTo(116,166);c.lineTo(116,188);c.moveTo(140,166);c.lineTo(140,188);c.stroke() + for(const d of[-1,1])ds(c,10,4,'#fff',()=>{c.moveTo(128+d*16,214);c.lineTo(128+d*18,250-d*4)}) + c.save();c.translate(0,dr);c.translate(128,186);c.rotate(.05-.04*sg);c.translate(-128,-186) + c.lineWidth=8;c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + if(sg>.5){c.lineWidth=7;for(const x of[103,153])c.beginPath(),c.moveTo(x-15,146),c.quadraticCurveTo(x,151,x+15,146),c.stroke()} + else{const l=bk?.95:.36;eye(c,103,140,-1,l);eye(c,153,140,1,l)} + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,163,12,6,0,0,T),c.fill() + c.lineWidth=5;c.fillStyle='#c92a2a';c.beginPath() + if(sg>.2)c.ellipse(124,172,6*sg+2,7*sg+2,0,0,T),c.fill(),c.stroke() + else c.moveTo(120,172),c.quadraticCurveTo(128,168,136,172),c.stroke() + c.lineWidth=8;c.fillStyle=HAIR;c.beginPath();c.moveTo(64,170) + c.bezierCurveTo(46,74,88,38,128,38);c.bezierCurveTo(168,38,210,74,192,170) + c.quadraticCurveTo(190,124,180,104);c.quadraticCurveTo(172,100,168,90);c.quadraticCurveTo(160,104,148,106);c.quadraticCurveTo(140,96,134,86) + c.quadraticCurveTo(126,102,114,106);c.quadraticCurveTo(108,94,98,90);c.quadraticCurveTo(92,102,78,104);c.quadraticCurveTo(66,130,64,170);c.closePath();c.fill();c.stroke() + c.strokeStyle=HL;c.lineWidth=7;for(const[a,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,58,PI*a,PI*e),c.stroke() + c.strokeStyle='#111';c.restore();c.restore() + // phone with an empty bell, a pull to refresh that finds nothing + c.save();c.translate(178,200+dr*.4);c.rotate(.12) + c.lineWidth=6;c.fillStyle=PH;c.beginPath();c.roundRect(-30,-50,60,96,10);c.fill();c.stroke() + c.fillStyle=SCR;c.lineWidth=3.5;c.beginPath();c.roundRect(-22,-40,44,72,4);c.fill();c.stroke() + c.fillStyle='#dee2e6';c.beginPath();c.moveTo(-13,6);c.quadraticCurveTo(-13,-20,0,-20);c.quadraticCurveTo(13,-20,13,6);c.lineTo(16,11);c.lineTo(-16,11);c.closePath();c.fill();c.stroke() + c.beginPath();c.arc(0,15,3.5,0,T);c.fill();c.stroke() + c.strokeStyle='#adb5bd';c.lineWidth=4;c.beginPath();c.moveTo(-12,24);c.lineTo(12,24);c.stroke();c.strokeStyle='#111' + if(t>.12&&t<.36){const a=t*T*5;c.strokeStyle='#4dabf7';c.lineWidth=4;c.beginPath();c.arc(0,-30,6,a,a+PI*1.5);c.stroke();c.strokeStyle='#111'} + c.restore() + ds(c,24,15,HO,()=>{c.moveTo(118,258);c.lineTo(150,232)}) + ds(c,24,15,HO,()=>{c.moveTo(240,258);c.lineTo(212,226)}) + c.fillStyle=SKIN;c.lineWidth=5;c.beginPath();c.ellipse(152,228,11,12,0,0,T);c.fill();c.stroke() + c.beginPath();c.ellipse(210,222,11,12,0,0,T);c.fill();c.stroke() + // sigh puff drifting away + if(t>.46&&t<.82){const p=(t-.46)/.36;puff(c,96-56*p,148-40*p,.8+.8*sin(PI*min(1,p*1.2)))} +} diff --git a/gen/uianime/plate/empty.js b/gen/uianime/plate/empty.js new file mode 100644 index 0000000..67ad14d --- /dev/null +++ b/gen/uianime/plate/empty.js @@ -0,0 +1,72 @@ +// pink odango girl with a napkin bib bouncing eagerly with fork and knife raised, then looking down at her empty plate and tearing up +const{PI}=Math,T=2*PI +export const frames=16,delay=85 +const SKIN='#ffe3d1',HAIR='#ff8fab',HD='#f06595',HL='#ffdeeb',EYE='#9775fa',ED='#6741d9',BL='#ffa8a8',DR='#74c0fc',TB='#ffd8a8',TBD='#e0a96d',RM='#99e9f2',SV='#dee2e6',MO='#c92a2a',TG='#ff8fab',TR='#a5d8ff' +const E=x=>x<=0?0:x>=1?1:x*x*(3-2*x) +const ds=(c,a,b,s,f)=>{for(const[l,k]of[[a,'#111'],[b,s]])c.lineWidth=l,c.strokeStyle=k,c.beginPath(),f(),c.stroke();c.strokeStyle='#111'} +const sp=(c,x,y,r)=>{c.beginPath();c.moveTo(x,y-r);for(const[a,b]of[[1,0],[0,1],[-1,0],[0,-1]])c.quadraticCurveTo(x+(a+b)*r*.16,y+(b-a)*r*.16,x+a*r,y+b*r);c.fill();c.stroke()} +const eye=(c,x,y,d,s,o)=>{ + c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill() + c.save();c.clip();c.beginPath();c.ellipse(x,y+3+o,11.5,15,0,0,T);c.fillStyle=EYE;c.fill();c.lineWidth=2.5;c.stroke() + c.fillStyle=ED;c.beginPath();c.ellipse(x,y-7+o,13,9,0,0,T);c.fill() + c.fillStyle='#111';c.beginPath();c.ellipse(x,y+4+o,5.5,7.5,0,0,T);c.fill() + c.fillStyle='#fff';if(s){c.lineWidth=2;sp(c,x-3,y-2,8);c.beginPath();c.arc(x+5,y+9,2.5,0,T);c.fill()} + else{c.beginPath();c.arc(x-4,y-4+o,5.5,0,T);c.fill();c.beginPath();c.arc(x+5,y+3+o,3,0,T);c.fill();c.fillStyle=TR;c.beginPath();c.ellipse(x,y+17,16,7,0,0,T);c.fill();c.strokeStyle='#fff';c.lineWidth=2.5;c.beginPath();c.moveTo(x-12,y+11);c.quadraticCurveTo(x-6,y+8,x,y+11);c.quadraticCurveTo(x+6,y+14,x+12,y+11);c.stroke()} + c.restore() + c.lineWidth=7;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke() +} +// fork or knife standing up in a fist +const ute=(c,x,y,a,k)=>{ + c.save();c.translate(x,y);c.rotate(a) + ds(c,13,6,SV,()=>{c.moveTo(0,0);c.lineTo(0,-44)}) + c.fillStyle=SV;c.lineWidth=4.5;c.beginPath() + if(k)c.moveTo(-6,-42),c.lineTo(-6,-92),c.quadraticCurveTo(8,-86,7,-58),c.lineTo(6,-42),c.closePath() + else{for(const[l,k]of[[10,'#111'],[4,SV]]){c.lineWidth=l;c.strokeStyle=k;c.beginPath();for(const q of[-9,0,9])c.moveTo(q,-62),c.lineTo(q,-92);c.stroke()}c.strokeStyle='#111';c.lineWidth=4.5;c.beginPath();c.moveTo(-13,-64);c.lineTo(13,-64);c.quadraticCurveTo(13,-42,0,-42);c.quadraticCurveTo(-13,-42,-13,-64);c.closePath()} + c.fill();c.stroke();c.restore() +} +export default(c,t,i)=>{ + const sd=E((t-.46)/.1)-E((t-.9)/.1),hap=sd<.5,hu=hap&&(i==1||i==5),b=hu?-10:0,wb=sd*(i%2?1:-1) + c.save();c.translate(0,b+4*sd) + c.save();c.translate(128,154);c.scale(.78,.78);c.translate(-128,-186) + c.lineWidth=8;c.fillStyle=HD;c.beginPath();c.moveTo(128,36);c.bezierCurveTo(198,36,210,100,202,164);c.lineTo(54,164);c.bezierCurveTo(46,100,58,36,128,36);c.fill();c.stroke() + c.fillStyle=HAIR;for(const d of[-1,1])c.beginPath(),c.arc(128+d*48,38,23,0,T),c.fill(),c.stroke() + c.strokeStyle=HD;c.lineWidth=5;for(const d of[-1,1])c.beginPath(),c.arc(128+d*48,38,12,d>0?PI*.9:-PI*.1,d>0?PI*2.3:PI*1.3),c.stroke() + c.strokeStyle='#111' + c.fillStyle=DR;c.beginPath();c.moveTo(100,190);c.quadraticCurveTo(54,198,44,300);c.lineTo(212,300);c.quadraticCurveTo(202,198,156,190);c.closePath();c.fill();c.stroke() + c.fillStyle=SKIN;c.beginPath();c.moveTo(116,166);c.lineTo(116,194);c.lineTo(140,194);c.lineTo(140,166);c.fill();c.beginPath();c.moveTo(116,166);c.lineTo(116,192);c.moveTo(140,166);c.lineTo(140,192);c.stroke() + c.fillStyle='#fff';c.beginPath();c.moveTo(96,192);c.quadraticCurveTo(128,204,160,192);c.lineTo(166,212);c.lineTo(150,228);c.lineTo(128,250);c.lineTo(106,228);c.lineTo(90,212);c.closePath();c.fill();c.stroke() + c.fillStyle='#fff';for(const d of[-1,1])c.beginPath(),c.moveTo(128,196),c.lineTo(128+d*16,184),c.lineTo(128+d*20,196),c.closePath(),c.fill(),c.stroke() + c.strokeStyle='#ffc9c9';c.lineWidth=5;c.beginPath();c.moveTo(102,212);c.lineTo(154,212);c.moveTo(112,228);c.lineTo(144,228);c.stroke();c.strokeStyle='#111' + c.lineWidth=8;c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + eye(c,103,140,-1,hap,hap?0:2+wb);eye(c,153,140,1,hap,hap?0:2-wb) + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,162,13,7,0,0,T),c.fill() + c.lineWidth=3;for(const d of[-1,1])for(const k of[-5,0,5])c.beginPath(),c.moveTo(128+d*44+k-2,165),c.lineTo(128+d*44+k+2,159),c.stroke() + if(hap){c.lineWidth=5;c.fillStyle=MO;c.beginPath();c.moveTo(114,164);c.quadraticCurveTo(128,166,142,164);c.quadraticCurveTo(140,184,128,184);c.quadraticCurveTo(116,184,114,164);c.fill();c.stroke() + c.save();c.clip();c.fillStyle=TG;c.beginPath();c.ellipse(128,186,9,6,0,0,T);c.fill();c.restore() + c.fillStyle=TR;c.lineWidth=4;c.beginPath();c.moveTo(142,174);c.quadraticCurveTo(150,186,145,190);c.quadraticCurveTo(138,186,142,174);c.fill();c.stroke()} + else{c.lineWidth=5;c.beginPath();c.moveTo(118,177+wb);c.quadraticCurveTo(128,166,138,177-wb);c.stroke() + c.fillStyle=TR;c.lineWidth=4;for(const d of[-1,1]){const y=156+14*((t*4+(d>0?.5:0))%1);c.beginPath();c.moveTo(128+d*36,y-9);c.quadraticCurveTo(128+d*36+7,y+3,128+d*36,y+5);c.quadraticCurveTo(128+d*36-7,y+3,128+d*36,y-9);c.fill();c.stroke()}} + c.lineWidth=8;c.fillStyle=HAIR;c.beginPath();c.moveTo(68,158) + c.bezierCurveTo(50,74,88,38,128,38);c.bezierCurveTo(168,38,206,74,188,158) + c.quadraticCurveTo(186,120,178,104);c.quadraticCurveTo(168,106,160,96);c.quadraticCurveTo(154,108,142,110);c.quadraticCurveTo(138,98,128,92) + c.quadraticCurveTo(122,106,110,110);c.quadraticCurveTo(102,100,96,96);c.quadraticCurveTo(88,106,78,104);c.quadraticCurveTo(70,126,68,158);c.closePath();c.fill();c.stroke() + c.strokeStyle=HL;c.lineWidth=7;for(const[a,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,56,PI*a,PI*e),c.stroke() + c.strokeStyle='#111';c.fillStyle='#ffd43b';c.lineWidth=6;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*36,58,13,7,-d*.75,0,T),c.fill(),c.stroke() + if(!hap){c.lineWidth=6;c.beginPath();c.moveTo(86,114);c.lineTo(112,106);c.moveTo(144,106);c.lineTo(170,114);c.stroke()} + c.restore() + // arms down to fists holding the cutlery up + const ua=hap?0:.5*sd + ds(c,22,13,DR,()=>{c.moveTo(82,190);c.quadraticCurveTo(62,196,52,206)}) + ds(c,22,13,DR,()=>{c.moveTo(174,190);c.quadraticCurveTo(194,196,204,206)}) + ute(c,48,204,-ua-.06,0);ute(c,208,204,ua+.06,1) + c.fillStyle=SKIN;c.lineWidth=5;for(const x of[48,208])c.beginPath(),c.ellipse(x,206,13,12,0,0,T),c.fill(),c.stroke() + c.restore() + if(hap){c.fillStyle='#ffd43b';c.lineWidth=3.5;for(const[x,y,o]of[[30,70,0],[226,62,.5],[218,128,.25]]){sp(c,x,y,hu?13:8+4*o)}} + // table and the empty plate + c.lineWidth=6;c.fillStyle=TB;c.beginPath();c.rect(4,214,248,40);c.fill();c.stroke() + c.strokeStyle=TBD;c.lineWidth=4;c.beginPath();c.moveTo(14,236);c.lineTo(242,236);c.stroke();c.strokeStyle='#111' + c.fillStyle='#fff';c.lineWidth=6;c.beginPath();c.ellipse(128,222,80,24,0,0,T);c.fill();c.stroke() + c.strokeStyle=RM;c.lineWidth=5;c.beginPath();c.ellipse(128,221,58,15,0,0,T);c.stroke() + c.strokeStyle='#111';c.lineWidth=3;c.beginPath();c.ellipse(128,221,52,12,0,0,T);c.stroke() + c.strokeStyle='#e9ecef';c.lineWidth=4;c.beginPath();c.ellipse(128,221,34,7,0,PI*1.1,PI*1.4);c.stroke();c.strokeStyle='#111' +} diff --git a/gen/uianime/refresh/pull.js b/gen/uianime/refresh/pull.js new file mode 100644 index 0000000..7ff14d2 --- /dev/null +++ b/gen/uianime/refresh/pull.js @@ -0,0 +1,59 @@ +// chestnut haired girl in a track jacket yanking the pull cord of a big green refresh arrow, it whirls around and the cord springs back up +const{cos,PI,exp}=Math,T=2*PI +export const frames=13,delay=95 +const SKIN='#ffe3d1',HAIR='#c0805a',HD='#8d5a3a',HL='#f3d9c7',EYE='#fab005',ED='#e67700',JK='#ffa94d',BL='#ffa8a8',GR='#51cf66',RP='#ffe8cc',HN='#ff6b6b',CLIP='#74c0fc' +const ds=(c,a,b,s,f)=>{for(const[l,k]of[[a,'#111'],[b,s]])c.lineWidth=l,c.strokeStyle=k,c.beginPath(),f(),c.stroke();c.strokeStyle='#111'} +const ease=x=>x<0?0:x>1?1:x*x*(3-2*x),L=(a,b,u)=>a+(b-a)*u +const eye=(c,x,y,d)=>{ + c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill() + c.save();c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.clip();c.beginPath();c.ellipse(x-4,y-1,11.5,15,0,0,T);c.fillStyle=EYE;c.fill();c.lineWidth=2.5;c.stroke() + c.fillStyle=ED;c.beginPath();c.ellipse(x-4,y-11,13,9,0,0,T);c.fill() + c.fillStyle='#111';c.beginPath();c.ellipse(x-4,y,5.5,7.5,0,0,T);c.fill() + c.fillStyle='#fff';c.beginPath();c.arc(x-8,y-7,4.5,0,T);c.fill();c.beginPath();c.arc(x+1,y+6,2,0,T);c.fill();c.restore() + c.lineWidth=6;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke() +} +export default(c,t)=>{ + const pu=ease((t-.125)/.3125),pull=t>=.125&&t<.4375,bd=t<.4375?pu:1-ease((t-.625)/.3125) + const f=t<.125?0:t<.4375?.6*pu:.6+.4*(1-(1-(t-.4375)/.5625)**2),th=T*f + const ry=t<.4375?L(116,196,pu):116+80*exp(-9*(t-.4375))*cos(16*(t-.4375)) + const hy=t<.4375?ry:t<.625?196:L(196,116,ease((t-.625)/.3125)),hap=t>=.5&&t<.875 + const X=84,Y=60 + ds(c,10,5,RP,()=>{c.moveTo(X,Y);c.lineTo(X,ry)}) + c.save();c.translate(X,Y);c.rotate(th) + ds(c,22,13,GR,()=>{c.arc(0,0,34,.9,T-.25)}) + c.fillStyle=GR;c.lineWidth=5;c.save();c.rotate(T-.3);c.beginPath();c.moveTo(14,-4);c.lineTo(54,-4);c.lineTo(34,22);c.closePath();c.restore();c.fill();c.stroke() + c.restore() + c.fillStyle='#adb5bd';c.lineWidth=4;c.beginPath();c.arc(X,Y,8,0,T);c.fill();c.stroke() + if(f>.05&&f<.97)for(const k of[0,1,2])ds(c,7,3,'#fff',()=>{const a=-PI/2-1+k*.75;c.arc(X,Y,52+k%2*6,a,a+.45)}) + c.fillStyle=HN;c.lineWidth=5;c.beginPath();c.roundRect(X-9,ry,18,26,8);c.fill();c.stroke() + c.strokeStyle='#fff';c.lineWidth=3;c.beginPath();c.moveTo(X-3,ry+6);c.lineTo(X-3,ry+18);c.stroke();c.strokeStyle='#111' + const H=f=>{c.save();c.translate(170,176);c.scale(.68,.68);c.translate(-128,-186);f();c.restore()} + H(()=>{ + c.lineWidth=8;c.fillStyle=HD;c.beginPath();c.moveTo(128,34);c.bezierCurveTo(200,34,214,96,206,150);c.quadraticCurveTo(212,200,200,236);c.lineTo(56,236);c.quadraticCurveTo(44,200,50,150);c.bezierCurveTo(42,96,56,34,128,34);c.fill();c.stroke() + c.fillStyle=JK;c.beginPath();c.moveTo(100,190);c.quadraticCurveTo(52,198,40,330);c.lineTo(216,330);c.quadraticCurveTo(204,198,156,190);c.closePath();c.fill();c.stroke() + c.fillStyle='#fff';c.beginPath();c.moveTo(104,188);c.lineTo(128,214);c.lineTo(152,188);c.lineTo(156,204);c.lineTo(128,226);c.lineTo(100,204);c.closePath();c.fill();c.stroke() + c.strokeStyle='#fff';c.lineWidth=5;for(const d of[-1,1])c.beginPath(),c.moveTo(128+d*62,214),c.lineTo(128+d*78,330),c.stroke();c.strokeStyle='#111' + c.lineWidth=5;c.beginPath();c.moveTo(128,226);c.lineTo(128,330);c.stroke() + c.fillStyle=SKIN;c.lineWidth=8;c.beginPath();c.moveTo(114,168);c.lineTo(114,194);c.quadraticCurveTo(128,206,142,194);c.lineTo(142,168);c.fill();c.beginPath();c.moveTo(114,168);c.lineTo(114,192);c.moveTo(142,168);c.lineTo(142,192);c.stroke() + c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + if(pull){c.lineWidth=8;for(const d of[-1,1])c.beginPath(),c.moveTo(128+d*38,128),c.lineTo(128+d*18,140),c.lineTo(128+d*38,152),c.stroke()} + else if(hap){c.lineWidth=8;for(const x of[103,153])c.beginPath(),c.arc(x,148,15,1.15*PI,1.85*PI),c.stroke()} + else eye(c,103,140,-1),eye(c,153,140,1) + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,162,14,8,0,0,T),c.fill() + c.lineWidth=4;for(const d of[-1,1])for(const k of[-6,0,6])c.beginPath(),c.moveTo(128+d*44+k-2,166),c.lineTo(128+d*44+k+2,158),c.stroke() + c.lineWidth=6;c.fillStyle='#c92a2a' + if(pull){c.beginPath();c.moveTo(112,164);c.lineTo(144,164);c.quadraticCurveTo(144,180,128,180);c.quadraticCurveTo(112,180,112,164);c.fill();c.stroke();c.fillStyle='#fff';c.beginPath();c.rect(113,164,30,6);c.fill();c.stroke()} + else{c.beginPath();c.moveTo(114,164);c.quadraticCurveTo(128,(hap?190:180),142,164);c.closePath();c.fill();c.stroke();c.save();c.clip();c.fillStyle='#ff8fab';c.beginPath();c.ellipse(128,180,8,6,0,0,T);c.fill();c.restore()} + c.lineWidth=8;c.fillStyle=HAIR;c.beginPath();c.moveTo(68,150) + c.bezierCurveTo(52,74,88,36,128,36);c.bezierCurveTo(168,36,204,74,188,150) + c.quadraticCurveTo(186,118,178,102);c.quadraticCurveTo(168,96,158,102);c.quadraticCurveTo(146,96,140,84);c.quadraticCurveTo(130,100,112,108) + c.quadraticCurveTo(104,100,100,92);c.quadraticCurveTo(92,104,82,108);c.quadraticCurveTo(72,124,68,150);c.closePath();c.fill();c.stroke() + c.strokeStyle=HL;c.lineWidth=7;for(const[s,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,56,PI*s,PI*e),c.stroke() + c.strokeStyle='#111';c.fillStyle=CLIP;c.lineWidth=6;c.beginPath();c.roundRect(152,70,30,11,5);c.fill();c.stroke() + if(pull){c.fillStyle='#a5d8ff';c.lineWidth=6;c.beginPath();c.moveTo(200,96);c.quadraticCurveTo(212,114,200,120);c.quadraticCurveTo(188,114,200,96);c.fill();c.stroke()} + }) + ds(c,20,11,JK,()=>{c.moveTo(134,210);c.quadraticCurveTo(L(100,96,bd),L(200,226,bd),X,hy+14)}) + c.fillStyle=SKIN;c.lineWidth=5;c.beginPath();c.ellipse(X,hy+12,12,12,0,0,T);c.fill();c.stroke() + ds(c,20,11,JK,()=>{c.moveTo(208,214);c.quadraticCurveTo(236,236,214,226-6*bd)}) + c.fillStyle=SKIN;c.lineWidth=5;c.beginPath();c.ellipse(212,222-6*bd,12,11,0,0,T);c.fill();c.stroke() +} diff --git a/gen/uianime/saved/hug.js b/gen/uianime/saved/hug.js new file mode 100644 index 0000000..5138cd0 --- /dev/null +++ b/gen/uianime/saved/hug.js @@ -0,0 +1,49 @@ +// pink haired girl with low pigtails squeezing a yellow folder tight to her chest, eyes shut in bliss, blush glowing as hearts float up +const{sin,cos,PI,max}=Math,T=2*PI +export const frames=16,delay=80 +const SKIN='#ffe3d1',HAIR='#faa2c1',HD='#e64980',HL='#fff0f6',TOP='#a5d8ff',TD='#4dabf7',SCR='#ffd43b',FO='#ffd43b',FD='#fab005',BL='#ff8fab',MO='#c92a2a',TG='#ff8fab',HT=['#ff6b9d','#f06595','#ff8787'] +const ds=(c,a,b,s,f)=>{for(const[l,k]of[[a,'#111'],[b,s]])c.lineWidth=l,c.strokeStyle=k,c.beginPath(),f(),c.stroke();c.strokeStyle='#111'} +const heart=(c,x,y,s)=>{c.save();c.translate(x,y);c.scale(s,s);c.beginPath();c.moveTo(0,8);c.bezierCurveTo(-13,-1,-9,-12,0,-5);c.bezierCurveTo(9,-12,13,-1,0,8);c.restore();c.fill();c.stroke()} +export default(c,t)=>{ + const sq=max(0,sin(2*T*t))**2,bl=1+.15*sq + c.lineWidth=4 + for(const[x0,o,k]of[[218,0,0],[232,.33,1],[210,.66,2]]){const p=(t+o)%1,s=1.5*sin(PI*p);if(s>.15)c.fillStyle=HT[k],heart(c,x0+8*sin(T*(p*2+o)),214-p*190,s)} + const head=f=>f() + head(()=>{ + c.lineWidth=6;c.fillStyle=HD;c.beginPath();c.moveTo(128,34);c.bezierCurveTo(196,34,206,96,198,156);c.lineTo(58,156);c.bezierCurveTo(50,96,60,34,128,34);c.fill();c.stroke() + for(const d of[-1,1]){c.save();c.translate(128+d*62,150);c.rotate(-d*.15) + c.fillStyle=HAIR;c.beginPath();c.moveTo(-8,-4);c.bezierCurveTo(d*30-6,10,d*30,60,d*16,96);c.quadraticCurveTo(d*8,110,-d*4,100);c.bezierCurveTo(d*8,60,-d*16,20,-8,-4);c.fill();c.stroke() + c.strokeStyle=HD;c.lineWidth=3;c.beginPath();c.moveTo(d*8,16);c.quadraticCurveTo(d*20,50,d*12,88);c.stroke();c.strokeStyle='#111' + c.fillStyle=SCR;c.lineWidth=5;c.beginPath();c.ellipse(0,0,13,9,d*.4,0,T);c.fill();c.stroke();c.lineWidth=6;c.restore()} + }) + c.lineWidth=6;c.fillStyle=TOP;c.beginPath();c.moveTo(100,190);c.quadraticCurveTo(62,198,54,250);c.lineTo(202,250);c.quadraticCurveTo(194,198,156,190);c.closePath();c.fill();c.stroke() + c.fillStyle='#fff';for(const d of[-1,1])c.beginPath(),c.moveTo(128,204),c.quadraticCurveTo(128+d*18,186,128+d*32,190),c.quadraticCurveTo(128+d*30,206,128,212),c.closePath(),c.fill(),c.stroke() + c.fillStyle=SKIN;c.lineWidth=5;c.beginPath();c.moveTo(116,168);c.lineTo(116,194);c.quadraticCurveTo(128,204,140,194);c.lineTo(140,168);c.fill();c.beginPath();c.moveTo(116,168);c.lineTo(116,192);c.moveTo(140,168);c.lineTo(140,192);c.stroke() + head(()=>{ + c.lineWidth=6;c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + c.lineWidth=6;for(const x of[103,153])c.beginPath(),c.arc(x,146,14,PI*1.15,PI*1.85),c.stroke() + c.lineWidth=5;for(const[x,d]of[[103,-1],[153,1]])c.beginPath(),c.moveTo(x+d*13,139),c.lineTo(x+d*19,134),c.stroke() + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*42,160,15*bl,8*bl,0,0,T),c.fill() + c.lineWidth=2.5;for(const d of[-1,1])for(const k of[-8,-3,2,7])c.beginPath(),c.moveTo(128+d*42+k-2,164),c.lineTo(128+d*42+k+2,156),c.stroke() + c.lineWidth=3.5;c.fillStyle=MO;c.beginPath();c.moveTo(118,166);c.quadraticCurveTo(128,170,138,166);c.quadraticCurveTo(136,180,128,180);c.quadraticCurveTo(120,180,118,166);c.fill();c.stroke() + c.save();c.clip();c.fillStyle=TG;c.beginPath();c.ellipse(128,181,6,5,0,0,T);c.fill();c.restore() + c.lineWidth=6;c.fillStyle=HAIR;c.beginPath();c.moveTo(70,150) + c.bezierCurveTo(54,74,88,36,128,36);c.bezierCurveTo(168,36,202,74,186,150) + c.quadraticCurveTo(184,118,178,104);c.quadraticCurveTo(172,108,164,112);c.quadraticCurveTo(160,98,150,92);c.quadraticCurveTo(144,104,136,110) + c.quadraticCurveTo(132,96,124,90);c.quadraticCurveTo(118,102,110,108);c.quadraticCurveTo(106,96,96,94);c.quadraticCurveTo(90,104,84,110) + c.quadraticCurveTo(80,104,78,104);c.quadraticCurveTo(72,124,70,150);c.closePath();c.fill();c.stroke() + c.strokeStyle=HL;c.lineWidth=5;for(const[s,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,56,PI*s,PI*e),c.stroke() + c.strokeStyle='#111';c.fillStyle=HT[0];c.lineWidth=4;heart(c,166,70,1.2) + }) + // folder squeezed to her chest + c.save();c.translate(128,226);c.rotate(-.05);c.scale(1-.05*sq,1+.02*sq) + c.lineWidth=6;c.fillStyle=FD;c.beginPath();c.moveTo(-60,-30);c.lineTo(-60,-44);c.quadraticCurveTo(-60,-50,-54,-50);c.lineTo(-18,-50);c.lineTo(-8,-38);c.lineTo(56,-38);c.quadraticCurveTo(62,-38,62,-32);c.lineTo(62,40);c.lineTo(-60,40);c.closePath();c.fill();c.stroke() + c.fillStyle='#fff';c.lineWidth=4;c.beginPath();c.rect(-46,-40,84,30);c.fill();c.stroke() + c.lineWidth=6;c.fillStyle=FO;c.beginPath();c.moveTo(-64,-24);c.lineTo(62,-24);c.lineTo(66,40);c.lineTo(-64,40);c.closePath();c.fill();c.stroke() + c.fillStyle=HT[1];c.lineWidth=4;heart(c,0,6,1.5) + c.restore() + for(const d of[-1,1]){const x=128+d*(54-3*sq);ds(c,30,19,TOP,()=>{c.moveTo(128+d*78,258);c.lineTo(x+d*8,234)}) + c.lineWidth=5;c.fillStyle=SKIN;c.beginPath();c.ellipse(x,230,12,14,d*.3,0,T);c.fill();c.stroke() + for(const y of[220,230,240])c.beginPath(),c.ellipse(x-d*10,y,8,5,0,0,T),c.fill(),c.stroke() + if(sq>.3)ds(c,8,3.5,'#fff',()=>{for(const y of[-14,0,14])c.moveTo(128+d*(76+6*sq),218+y*1.2),c.lineTo(128+d*(90+6*sq),218+y*1.6)})} +} diff --git a/gen/uianime/search/magnifier.js b/gen/uianime/search/magnifier.js new file mode 100644 index 0000000..56d82eb --- /dev/null +++ b/gen/uianime/search/magnifier.js @@ -0,0 +1,60 @@ +// honey blonde detective girl in a deerstalker sweeping a magnifying glass around, peering through it with a giant eye, then finding nothing: sweatdrop and a ? +const{sin,cos,PI,max,min,hypot,sqrt}=Math,T=2*PI +export const frames=20,delay=85 +const SKIN='#ffe3d1',HAIR='#ffd43b',HD='#f59f00',EYE='#4dabf7',ED='#1864ab',BL='#ffa8a8',CT='#e0a96d',CTD='#c08552',HAT='#a9744f',HATD='#7f5539',TIE='#fa5252',RIM='#fcc419',GL='#d0ebff',SW='#a5d8ff' +const E=x=>x<=0?0:x>=1?1:x*x*(3-2*x) +const ds=(c,a,b,s,f)=>{for(const[l,k]of[[a,'#111'],[b,s]])c.lineWidth=l,c.strokeStyle=k,c.beginPath(),f(),c.stroke();c.strokeStyle='#111'} +const eye=(c,x,y,d,o)=>{ + c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill() + c.save();c.clip();c.beginPath();c.ellipse(x+o,y+3,11.5,15,0,0,T);c.fillStyle=EYE;c.fill();c.lineWidth=2.5;c.stroke() + c.fillStyle=ED;c.beginPath();c.ellipse(x+o,y-7,13,9,0,0,T);c.fill() + c.fillStyle='#111';c.beginPath();c.ellipse(x+o,y+4,5.5,7.5,0,0,T);c.fill() + c.fillStyle='#fff';c.beginPath();c.arc(x+o-4,y-3,4.5,0,T);c.fill();c.beginPath();c.arc(x+o+5,y+9,2,0,T);c.fill();c.restore() + c.lineWidth=7;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke() +} +const G=(c,f)=>{c.save();c.translate(128,158);c.scale(.82,.82);c.translate(-128,-186);f();c.restore()} +export default(c,t)=>{ + const sw=t<.4,u=t/.4,up=E((t-.4)/.1)-E((t-.62)/.1),af=t>.72, + sx=128-60*cos(T*min(1,u)),sy=196-8*sin(2*T*min(1,u)),lx=sx+(107-sx)*up,ly=sy+(120-sy)*up,o=sw?(lx-128)/60*4:0,a=.9-.15*up + G(c,()=>{ + c.lineWidth=7;c.fillStyle=HD;c.beginPath();c.moveTo(128,34);c.bezierCurveTo(200,34,212,100,206,170);c.quadraticCurveTo(206,214,186,214);c.lineTo(70,214);c.quadraticCurveTo(50,214,50,170);c.bezierCurveTo(44,100,56,34,128,34);c.fill();c.stroke() + c.fillStyle=CT;c.beginPath();c.moveTo(100,190);c.quadraticCurveTo(56,198,46,306);c.lineTo(210,306);c.quadraticCurveTo(200,198,156,190);c.closePath();c.fill();c.stroke() + c.fillStyle=CTD;c.beginPath();c.moveTo(98,192);c.quadraticCurveTo(54,204,40,262);c.quadraticCurveTo(128,286,216,262);c.quadraticCurveTo(202,204,158,192);c.closePath();c.fill();c.stroke() + c.fillStyle='#fff';c.beginPath();c.moveTo(108,190);c.lineTo(128,216);c.lineTo(148,190);c.closePath();c.fill();c.lineWidth=6;c.stroke() + c.fillStyle=SKIN;c.beginPath();c.moveTo(116,166);c.lineTo(116,194);c.lineTo(128,206);c.lineTo(140,194);c.lineTo(140,166);c.fill();c.beginPath();c.moveTo(116,166);c.lineTo(116,192);c.moveTo(140,166);c.lineTo(140,192);c.stroke() + c.fillStyle=TIE;c.lineWidth=5;for(const d of[-1,1])c.beginPath(),c.moveTo(128,212),c.lineTo(128+d*18,203),c.lineTo(128+d*18,221),c.closePath(),c.fill(),c.stroke() + c.beginPath();c.arc(128,212,5,0,T);c.fill();c.stroke() + c.lineWidth=7;c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + if(af){eye(c,103,140,-1,0);eye(c,153,140,1,0);c.lineWidth=5;c.beginPath();c.moveTo(114,170);for(let k=1;k<=7;k++)c.lineTo(114+k*4,170+(k%2?-3:2));c.stroke()} + else{eye(c,103,140,-1,o);eye(c,153,140,1,o);c.lineWidth=5;c.fillStyle='#c92a2a';c.beginPath();c.ellipse(128+o,169,5,4,0,0,T);c.fill();c.stroke()} + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,162,13,7,0,0,T),c.fill() + c.lineWidth=3;for(const d of[-1,1])for(const k of[-5,0,5])c.beginPath(),c.moveTo(128+d*44+k-2,165),c.lineTo(128+d*44+k+2,159),c.stroke() + c.lineWidth=7;c.fillStyle=HAIR;c.beginPath();c.moveTo(66,162) + c.bezierCurveTo(48,74,88,40,128,40);c.bezierCurveTo(168,40,208,74,190,162) + c.quadraticCurveTo(188,120,180,104);c.quadraticCurveTo(170,106,162,98);c.quadraticCurveTo(154,110,142,110);c.quadraticCurveTo(138,100,128,94) + c.quadraticCurveTo(120,106,108,110);c.quadraticCurveTo(102,100,94,96);c.quadraticCurveTo(86,106,76,106);c.quadraticCurveTo(68,128,66,162);c.closePath();c.fill();c.stroke() + // deerstalker + const dome=()=>{c.beginPath();c.moveTo(60,92);c.bezierCurveTo(54,10,202,10,196,92);c.quadraticCurveTo(128,72,60,92);c.closePath()} + c.fillStyle=HAT;dome();c.fill();c.save();c.clip();c.strokeStyle=HATD;c.lineWidth=5;c.beginPath();for(let x=40;x<230;x+=22)c.moveTo(x,0),c.lineTo(x-30,100),c.moveTo(x-40,0),c.lineTo(x-10,100);c.stroke();c.restore() + c.strokeStyle='#111';c.lineWidth=7;dome();c.stroke() + c.fillStyle=HATD;c.beginPath();c.moveTo(92,84);c.quadraticCurveTo(128,74,164,84);c.quadraticCurveTo(160,104,128,100);c.quadraticCurveTo(96,104,92,84);c.fill();c.stroke() + c.fillStyle=HAT;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*14,26,14,8,d*.4,0,T),c.fill(),c.stroke() + c.beginPath();c.arc(128,28,6,0,T);c.fill();c.stroke() + }) + // magnifier: the hand holds the handle, the glass shows a giant eye when it is up at her face + const hx=lx+54*cos(a),hy=ly+54*sin(a),sx0=166,sy0=210,d=hypot(hx-sx0,hy-sy0),h=sqrt(max(0,46*46-d*d/4)),nx=-(hy-sy0)/d*h,ny=(hx-sx0)/d*h,k=nx*.5+ny>0?1:-1,ex=(sx0+hx)/2+k*nx,ey=(sy0+hy)/2+k*ny + ds(c,22,13,CT,()=>{c.moveTo(sx0,sy0);c.lineTo(ex,ey);c.lineTo(hx,hy)}) + ds(c,16,9,HATD,()=>{c.moveTo(lx+30*cos(a),ly+30*sin(a));c.lineTo(lx+68*cos(a),ly+68*sin(a))}) + c.save();c.beginPath();c.arc(lx,ly,27,0,T);c.fillStyle=GL;c.fill();c.clip() + if(up>.6){c.fillStyle=SKIN;c.fillRect(lx-30,ly-30,60,60);c.translate(107,120);c.scale(1.45,1.45);c.translate(-107,-120);G(c,()=>eye(c,103,140,-1,0))} + c.restore() + c.strokeStyle='#fff';c.lineWidth=5;c.beginPath();c.arc(lx,ly,19,PI*1.1,PI*1.45);c.stroke() + c.strokeStyle='#111';c.fillStyle=RIM;c.lineWidth=5;c.beginPath();c.arc(lx,ly,34,0,T);c.arc(lx,ly,26,0,T,true);c.fill('evenodd');c.stroke() + c.lineWidth=5;c.fillStyle=SKIN;c.beginPath();c.ellipse(hx,hy,11,10,a,0,T);c.fill();c.stroke() + // nothing found + if(af){const s=min(1,(t-.72)/.06) + c.fillStyle=SW;c.lineWidth=4;c.beginPath();c.moveTo(194,86-18*s);c.quadraticCurveTo(194+11*s,102,194,106);c.quadraticCurveTo(194-11*s,102,194,86-18*s);c.fill();c.stroke() + c.save();c.translate(220,54);c.scale(1.7*s,1.7*s);c.rotate(.2) + ds(c,15,8,'#fff',()=>{c.moveTo(-10,-8);c.quadraticCurveTo(-10,-22,2,-22);c.quadraticCurveTo(14,-22,13,-10);c.quadraticCurveTo(12,-1,2,3);c.lineTo(2,9)}) + c.fillStyle='#fff';c.lineWidth=4;c.beginPath();c.arc(2,21,5,0,T);c.fill();c.stroke();c.restore()} +} diff --git a/gen/uianime/sent/wave.js b/gen/uianime/sent/wave.js new file mode 100644 index 0000000..471d48e --- /dev/null +++ b/gen/uianime/sent/wave.js @@ -0,0 +1,64 @@ +// turquoise haired girl waving goodbye as a winged love letter flaps up and away into the corner and vanishes with a twinkle +const{sin,cos,PI,max,min}=Math,T=2*PI +export const frames=16,delay=80 +const SKIN='#ffe3d1',HAIR='#3bc9db',HD='#1098ad',HL='#e3fafc',EYE='#f783ac',ED='#a61e4d',CAR='#d0bfff',CD='#9775fa',FL='#ffd43b',BL='#ffa8a8',MO='#c92a2a',TG='#ff8fab',ENV='#fff9db',HT='#fa5252' +const ds=(c,a,b,s,f)=>{for(const[l,k]of[[a,'#111'],[b,s]])c.lineWidth=l,c.strokeStyle=k,c.beginPath(),f(),c.stroke();c.strokeStyle='#111'} +const eye=(c,x,y,d)=>{ + c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill() + c.save();c.beginPath();c.ellipse(x+3,y+1,11.5,15,0,0,T);c.clip();c.fillStyle=EYE;c.fill();c.fillStyle=ED;c.beginPath();c.ellipse(x+3,y-9,13,10,0,0,T);c.fill();c.restore() + c.lineWidth=2.5;c.beginPath();c.ellipse(x+3,y+1,11.5,15,0,0,T);c.stroke() + c.fillStyle='#111';c.beginPath();c.ellipse(x+5,y,5.5,7.5,0,0,T);c.fill() + c.fillStyle='#fff';c.beginPath();c.arc(x,y-6,4.5,0,T);c.fill();c.beginPath();c.arc(x+8,y+7,2,0,T);c.fill() + c.lineWidth=6;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke() + c.lineWidth=2.5;c.beginPath();c.moveTo(x-8,y+18);c.lineTo(x+8,y+18);c.stroke() +} +const heart=(c,x,y,s)=>{c.save();c.translate(x,y);c.scale(s,s);c.beginPath();c.moveTo(0,8);c.bezierCurveTo(-13,-1,-9,-12,0,-5);c.bezierCurveTo(9,-12,13,-1,0,8);c.restore();c.fill();c.stroke()} +const spark=(c,x,y,r)=>{c.beginPath();c.moveTo(x,y-r);for(const[a,b]of[[1,0],[0,1],[-1,0],[0,-1]])c.quadraticCurveTo(x+(a+b)*r*.15,y+(b-a)*r*.15,x+a*r,y+b*r);c.fill();c.stroke()} +const letter=(c,x,y,s,f)=>{ + c.save();c.translate(x,y);c.scale(s,s);c.rotate(-.25) + c.fillStyle='#fff';c.lineWidth=5 + for(const d of[-1,1]){c.save();c.translate(d*22,-4);c.rotate(d*f);c.beginPath();c.moveTo(0,6);c.bezierCurveTo(d*10,-26,d*36,-32,d*44,-22);c.quadraticCurveTo(d*36,-16,d*40,-9);c.quadraticCurveTo(d*30,-6,d*32,2);c.quadraticCurveTo(d*20,4,0,10);c.closePath();c.fill();c.stroke() + c.lineWidth=3;c.beginPath();c.moveTo(d*12,-6);c.quadraticCurveTo(d*22,-15,d*34,-18);c.stroke();c.lineWidth=5;c.restore()} + c.fillStyle=ENV;c.lineWidth=6;c.beginPath();c.roundRect(-30,-20,60,40,5);c.fill();c.stroke() + c.lineWidth=4;c.beginPath();c.moveTo(-26,-16);c.lineTo(0,4);c.lineTo(26,-16);c.stroke() + c.fillStyle=HT;c.lineWidth=3.5;heart(c,0,4,1.1) + c.restore() +} +export default(c,t)=>{ + const a=-1.4+.4*sin(2*T*t),p=min(1,t/.7),fl=.55*sin(8*T*t) + c.save();c.translate(102,254);c.scale(.86,.86);c.translate(-128,-250) + c.lineWidth=6;c.fillStyle=HD;c.beginPath();c.moveTo(128,34);c.bezierCurveTo(198,34,212,96,206,150);c.quadraticCurveTo(218,200,204,250);c.lineTo(52,250);c.quadraticCurveTo(38,200,50,150);c.bezierCurveTo(44,96,58,34,128,34);c.fill();c.stroke() + c.fillStyle=CAR;c.beginPath();c.moveTo(100,190);c.quadraticCurveTo(62,198,54,250);c.lineTo(202,250);c.quadraticCurveTo(194,198,156,190);c.closePath();c.fill();c.stroke() + c.fillStyle='#fff';for(const d of[-1,1])c.beginPath(),c.moveTo(128,206),c.quadraticCurveTo(128+d*16,188,128+d*30,190),c.quadraticCurveTo(128+d*34,206,128,212),c.closePath(),c.fill(),c.stroke() + c.strokeStyle=CD;c.lineWidth=4;c.beginPath();c.moveTo(128,214);c.lineTo(128,250);c.stroke();c.strokeStyle='#111' + c.fillStyle='#fff';c.lineWidth=3;for(const y of[226,242])c.beginPath(),c.arc(136,y,3.5,0,T),c.fill(),c.stroke() + c.lineWidth=5;c.fillStyle=SKIN;c.beginPath();c.moveTo(116,168);c.lineTo(116,194);c.quadraticCurveTo(128,206,140,194);c.lineTo(140,168);c.fill();c.beginPath();c.moveTo(116,168);c.lineTo(116,192);c.moveTo(140,168);c.lineTo(140,192);c.stroke() + c.lineWidth=6;c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + eye(c,103,140,-1);eye(c,153,140,1) + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*42,161,12,6,0,0,T),c.fill() + c.lineWidth=2.5;for(const d of[-1,1])for(const k of[-5,0,5])c.beginPath(),c.moveTo(128+d*42+k-2,164),c.lineTo(128+d*42+k+2,158),c.stroke() + c.lineWidth=3.5;c.fillStyle=MO;c.beginPath();c.moveTo(119,165);c.quadraticCurveTo(128,170,137,165);c.quadraticCurveTo(136,180,128,180);c.quadraticCurveTo(120,180,119,165);c.fill();c.stroke() + c.save();c.clip();c.fillStyle=TG;c.beginPath();c.ellipse(128,181,6,5,0,0,T);c.fill();c.restore() + c.lineWidth=6;c.fillStyle=HAIR;c.beginPath();c.moveTo(66,190) + c.bezierCurveTo(48,74,88,36,128,36);c.bezierCurveTo(168,36,208,74,190,190);c.quadraticCurveTo(182,176,178,186) + c.quadraticCurveTo(184,124,178,104);c.quadraticCurveTo(170,104,164,112);c.quadraticCurveTo(160,98,150,92);c.quadraticCurveTo(144,104,136,110) + c.quadraticCurveTo(132,96,124,90);c.quadraticCurveTo(118,102,110,108);c.quadraticCurveTo(106,96,96,94);c.quadraticCurveTo(90,104,86,112) + c.quadraticCurveTo(80,104,78,104);c.quadraticCurveTo(72,124,78,186);c.quadraticCurveTo(72,176,66,190);c.closePath();c.fill();c.stroke() + c.strokeStyle=HL;c.lineWidth=5;for(const[s,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,56,PI*s,PI*e),c.stroke() + c.strokeStyle='#111';c.fillStyle=FL;c.lineWidth=4;for(let k=0;k<5;k++){const b=k*T/5-PI/2;c.beginPath();c.arc(84+10*cos(b),70+10*sin(b),7,0,T);c.fill();c.stroke()} + c.fillStyle='#ff922b';c.beginPath();c.arc(84,70,5,0,T);c.fill();c.stroke() + const ex=198,ey=214,hx=ex+50*cos(a),hy=ey+50*sin(a) + ds(c,30,19,CAR,()=>{c.moveTo(166,226);c.lineTo(ex,ey);c.lineTo(ex+34*cos(a),ey+34*sin(a))}) + c.lineWidth=5;c.fillStyle=SKIN + c.save();c.translate(hx,hy);c.rotate(a+PI/2);c.scale(1.25,1.25) + for(const x of[-9,-3,3,9])c.beginPath(),c.ellipse(x,-14,3.6,8,0,0,T),c.fill(),c.stroke() + c.beginPath();c.ellipse(-14,-2,4,8,-.7,0,T);c.fill();c.stroke() + c.beginPath();c.ellipse(0,-2,13,12,0,0,T);c.fill();c.stroke() + c.restore() + for(const d of[-1,1])ds(c,7,3,'#fff',()=>{const r=60,b=a+d*.45;c.arc(ex,ey,r,b-.12,b+.12)}) + c.restore() + if(t<.7){const x=196+30*p,y=114-78*p-8*sin(PI*p),s=.9-.4*p + if(p>.12)ds(c,8,3.5,'#fff',()=>{for(const k of[0,1,2])c.moveTo(x-30*s-8-k*6,y+16*s+k*10),c.lineTo(x-30*s-20-k*6,y+24*s+k*10)}) + letter(c,x,y,s,fl)} + else{const q=(t-.7)/.3;c.fillStyle=FL;c.lineWidth=3.5;spark(c,232,36,20*sin(PI*q));c.fillStyle='#fff';spark(c,206,22,10*sin(PI*min(1,q*1.4)))} +} diff --git a/gen/uianime/success/jump.js b/gen/uianime/success/jump.js new file mode 100644 index 0000000..1b3561b --- /dev/null +++ b/gen/uianime/success/jump.js @@ -0,0 +1,45 @@ +// mint haired chibi girl in a pink dress jumping for joy with both arms up, eyes squeezed happy, while confetti rains down around her +const{sin,cos,PI,max}=Math,T=2*PI +export const frames=12,delay=80 +const SKIN='#ffe3d1',HAIR='#8ce99a',HD='#37b24d',HL='#ebfbee',DR='#ffa8c5',DD='#f06595',SH='#ff6b6b',BL='#ff8fab',MO='#c92a2a',TG='#ff8fab',RB='#ffd43b',CF=['#ff6b6b','#ffd43b','#4dabf7','#b197fc','#69db7c','#ff922b'] +const ds=(c,a,b,s,f)=>{for(const[l,k]of[[a,'#111'],[b,s]])c.lineWidth=l,c.strokeStyle=k,c.beginPath(),f(),c.stroke();c.strokeStyle='#111'} +const conf=(c,t,a)=>{for(let k=a;k<12;k+=2){const o=k*.37%1,p=(t+o)%1,x=18+k*20+8*sin(T*(p*2+o)),y=-14+p*280;c.save();c.translate(x,y);c.rotate(T*p*(k%3?1:-1)+k);c.scale(.3+.7*cos(T*p*2+k),1);c.fillStyle=CF[k%6];c.lineWidth=3;c.beginPath();c.rect(-5,-8,10,16);c.fill();c.stroke();c.restore()}} +export default(c,t)=>{ + const h=sin(PI*t),y=-26*h,Z=.62 + conf(c,t,0) + c.save();c.translate(128,242);c.scale(1.08,1.08);c.translate(-128,-242) + c.fillStyle='rgba(134,142,150,.35)';c.beginPath();c.ellipse(128,240,40-14*h,7-2*h,0,0,T);c.fill() + for(const d of[-1,1]){const fx=128+d*(11+16*h),fy=232-14*h+y + ds(c,16,9,SKIN,()=>{c.moveTo(128+d*9,206+y);c.lineTo(fx,fy-4)}) + c.lineWidth=5;c.fillStyle=SH;c.beginPath();c.ellipse(fx+d*3,fy,11,7,d*.3*h,0,T);c.fill();c.stroke()} + c.lineWidth=6;c.fillStyle=DR;c.beginPath();c.moveTo(112,164+y);c.lineTo(144,164+y);c.quadraticCurveTo(156,184,166,212+y) + for(let k=1;k<=4;k++)c.quadraticCurveTo(166-k*19+9.5,220+y,166-k*19,212+y) + c.quadraticCurveTo(100,184,112,164+y);c.closePath();c.fill();c.stroke() + c.fillStyle='#fff';c.lineWidth=4;for(const d of[-1,1])c.beginPath(),c.moveTo(128,170+y),c.quadraticCurveTo(128+d*14,164+y,128+d*16,176+y),c.quadraticCurveTo(128+d*8,182+y,128,170+y),c.fill(),c.stroke() + c.fillStyle=RB;c.beginPath();c.arc(128,172+y,4,0,T);c.fill();c.stroke() + c.save();c.translate(128,116+y);c.scale(Z,Z);c.translate(-128,-128);c.lineWidth=9 + for(const d of[-1,1]){c.save();c.translate(128+d*62,88);c.rotate(d*(-.1+.35*(1-h))) + c.fillStyle=HAIR;c.beginPath();c.moveTo(0,0);c.bezierCurveTo(d*34,2,d*46,60,d*28,104);c.quadraticCurveTo(d*22,118,d*8,114);c.bezierCurveTo(d*22,74,d*6,32,0,0);c.fill();c.stroke() + c.strokeStyle=HD;c.lineWidth=5;c.beginPath();c.moveTo(d*12,16);c.bezierCurveTo(d*26,40,d*30,70,d*22,96);c.stroke();c.strokeStyle='#111';c.lineWidth=9 + c.fillStyle=RB;c.beginPath();c.arc(0,0,13,0,T);c.fill();c.stroke();c.restore()} + c.fillStyle=HD;c.beginPath();c.moveTo(128,34);c.bezierCurveTo(196,34,206,96,198,150);c.lineTo(58,150);c.bezierCurveTo(50,96,60,34,128,34);c.fill();c.stroke() + c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + c.lineWidth=9;for(const x of[103,153])c.beginPath(),c.arc(x,148,14,PI*1.15,PI*1.85),c.stroke() + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,162,16,8,0,0,T),c.fill() + c.lineWidth=4;for(const d of[-1,1])for(const k of[-6,0,6])c.beginPath(),c.moveTo(128+d*44+k-2,166),c.lineTo(128+d*44+k+2,158),c.stroke() + c.lineWidth=6;c.fillStyle=MO;c.beginPath();c.moveTo(112,164);c.quadraticCurveTo(128,168,144,164);c.quadraticCurveTo(142,188,128,188);c.quadraticCurveTo(114,188,112,164);c.fill();c.stroke() + c.save();c.clip();c.fillStyle=TG;c.beginPath();c.ellipse(128,190,9,7,0,0,T);c.fill();c.restore() + c.lineWidth=9;c.fillStyle=HAIR;c.beginPath();c.moveTo(70,146) + c.bezierCurveTo(54,74,88,36,128,36);c.bezierCurveTo(168,36,202,74,186,146) + c.quadraticCurveTo(186,116,178,102);c.quadraticCurveTo(170,104,164,112);c.quadraticCurveTo(160,98,150,92);c.quadraticCurveTo(144,104,136,110) + c.quadraticCurveTo(132,96,124,90);c.quadraticCurveTo(118,102,110,108);c.quadraticCurveTo(106,96,96,94);c.quadraticCurveTo(90,104,86,112) + c.quadraticCurveTo(80,104,78,102);c.quadraticCurveTo(70,120,70,146);c.closePath();c.fill();c.stroke() + c.strokeStyle=HL;c.lineWidth=7;for(const[a,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,56,PI*a,PI*e),c.stroke() + c.restore() + for(const d of[-1,1]){const hx=128+d*(54-6*h),hy=150-48*h+y + ds(c,16,9,SKIN,()=>{c.moveTo(128+d*14,172+y);c.lineTo(hx,hy)}) + c.lineWidth=5;c.fillStyle=DR;c.beginPath();c.ellipse(128+d*16,170+y,10,9,0,0,T);c.fill();c.stroke() + c.fillStyle=SKIN;c.beginPath();c.arc(hx,hy,9,0,T);c.fill();c.stroke()} + c.restore() + conf(c,t,1) +} diff --git a/gen/uianime/success/thumbs.js b/gen/uianime/success/thumbs.js new file mode 100644 index 0000000..c4e33e4 --- /dev/null +++ b/gen/uianime/success/thumbs.js @@ -0,0 +1,44 @@ +// sporty blonde girl in a red headband grinning ear to ear and pumping a big thumbs up, a gleam pinging off her teeth +const{sin,cos,PI,max,min}=Math,T=2*PI +export const frames=16,delay=80 +const SKIN='#ffe3d1',HAIR='#ffd43b',HD='#f59f00',HL='#fff9db',JK='#4dabf7',JD='#1c7ed6',BAND='#fa5252',BL='#ff8fab',MO='#c92a2a',TG='#ff8fab',GL='#fff9db' +const ds=(c,a,b,s,f)=>{for(const[l,k]of[[a,'#111'],[b,s]])c.lineWidth=l,c.strokeStyle=k,c.beginPath(),f(),c.stroke();c.strokeStyle='#111'} +const glint=(c,x,y,r,a)=>{c.save();c.translate(x,y);c.rotate(a);c.beginPath();for(let k=0;k<8;k++){const rr=k%2?r*.28:r,b=k*PI/4;c.lineTo(cos(b)*rr,sin(b)*rr)}c.closePath();c.restore();c.fill();c.stroke()} +export default(c,t)=>{ + const pp=t<.2?sin(PI*t/.2):0,g=t>=.3&&t<.7?sin(PI*(t-.3)/.4):0 + c.save();c.translate(-16,4) + c.lineWidth=6;c.fillStyle=HD;c.beginPath();c.moveTo(128,34);c.bezierCurveTo(196,34,208,96,200,158);c.quadraticCurveTo(190,170,180,158);c.lineTo(76,158);c.quadraticCurveTo(66,170,56,158);c.bezierCurveTo(48,96,60,34,128,34);c.fill();c.stroke() + c.fillStyle=JK;c.beginPath();c.moveTo(100,190);c.quadraticCurveTo(62,198,54,250);c.lineTo(202,250);c.quadraticCurveTo(194,198,156,190);c.closePath();c.fill();c.stroke() + c.fillStyle='#fff';c.beginPath();c.moveTo(102,191);c.lineTo(120,252);c.lineTo(136,252);c.lineTo(154,191);c.quadraticCurveTo(128,206,102,191);c.fill();c.stroke() + c.strokeStyle=JD;c.lineWidth=4;c.beginPath();c.moveTo(128,206);c.lineTo(128,250);c.stroke();c.strokeStyle='#111' + c.strokeStyle='#fff';c.lineWidth=5;for(const d of[-1,1])c.beginPath(),c.moveTo(128+d*58,214),c.quadraticCurveTo(128+d*66,228,128+d*70,250),c.stroke() + c.strokeStyle='#111';c.fillStyle=SKIN;c.lineWidth=5;c.beginPath();c.moveTo(116,168);c.lineTo(116,190);c.quadraticCurveTo(128,200,140,190);c.lineTo(140,168);c.fill();c.beginPath();c.moveTo(116,168);c.lineTo(116,188);c.moveTo(140,168);c.lineTo(140,188);c.stroke() + c.lineWidth=6;c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + c.lineWidth=6;for(const x of[103,153])c.beginPath(),c.arc(x,146,14,PI*1.15,PI*1.85),c.stroke() + c.lineWidth=5;for(const[x,d]of[[103,-1],[153,1]])c.beginPath(),c.moveTo(x+d*13,139),c.lineTo(x+d*19,134),c.stroke() + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,158,12,6,0,0,T),c.fill() + c.lineWidth=2.5;for(const d of[-1,1])for(const k of[-5,0,5])c.beginPath(),c.moveTo(128+d*44+k-2,161),c.lineTo(128+d*44+k+2,155),c.stroke() + c.lineWidth=4;c.fillStyle=MO;c.beginPath();c.moveTo(106,160);c.quadraticCurveTo(128,166,150,160);c.quadraticCurveTo(146,186,128,186);c.quadraticCurveTo(110,186,106,160);c.fill() + c.save();c.clip();c.fillStyle=TG;c.beginPath();c.ellipse(128,188,11,7,0,0,T);c.fill();c.fillStyle='#fff';c.beginPath();c.moveTo(104,158);c.quadraticCurveTo(128,166,152,158);c.lineTo(152,170);c.quadraticCurveTo(128,176,104,170);c.fill();c.restore() + c.stroke();c.lineWidth=2.5;c.beginPath();c.moveTo(108,167);c.quadraticCurveTo(128,174,148,167);c.stroke() + c.lineWidth=6;c.fillStyle=HAIR;c.beginPath();c.moveTo(68,150) + c.bezierCurveTo(50,74,88,36,128,36);c.bezierCurveTo(168,36,206,74,188,150) + c.quadraticCurveTo(184,120,178,104);c.quadraticCurveTo(168,98,158,110);c.quadraticCurveTo(156,94,140,90) + c.quadraticCurveTo(136,104,124,110);c.quadraticCurveTo(122,96,110,90);c.quadraticCurveTo(102,100,96,112) + c.quadraticCurveTo(90,100,78,104);c.quadraticCurveTo(70,124,68,150);c.closePath();c.fill();c.stroke() + c.strokeStyle=HL;c.lineWidth=5;for(const[a,e]of[[1.42,1.5],[1.6,1.72]])c.beginPath(),c.arc(128,104,56,PI*a,PI*e),c.stroke() + c.strokeStyle='#111';c.fillStyle=BAND;c.lineWidth=5;c.beginPath();c.moveTo(70,82);c.bezierCurveTo(90,52,166,52,186,82);c.lineTo(182,96);c.bezierCurveTo(162,70,94,70,74,96);c.closePath();c.fill();c.stroke() + for(const[a,b]of[[-.3,30],[.25,24]]){c.save();c.translate(70,90);c.rotate(a);c.beginPath();c.moveTo(0,-6);c.quadraticCurveTo(-b*.6,-8,-b,-2);c.lineTo(-b+2,8);c.quadraticCurveTo(-b*.6,4,0,6);c.closePath();c.fill();c.stroke();c.restore()} + if(g>0){c.fillStyle=GL;c.lineWidth=3.5;glint(c,140,166,6+16*g,g*1.5) + ds(c,8,3.5,'#fff',()=>{for(const a of[-.9,-.4,.1])c.moveTo(156+20*cos(a),156+20*sin(a)),c.lineTo(156+(26+8*g)*cos(a),156+(26+8*g)*sin(a))})} + c.restore() + const s=1.3+.2*pp + ds(c,38,27,JK,()=>{c.moveTo(226,266);c.lineTo(204,226)}) + c.save();c.translate(196,200-6*pp);c.scale(s,s);c.rotate(-.1) + c.lineWidth=5;c.fillStyle=SKIN;c.beginPath();c.roundRect(-6,-56,22,46,11);c.fill();c.stroke() + c.beginPath();c.roundRect(-24,-18,48,44,15);c.fill();c.stroke() + c.lineWidth=3;for(const y of[-6,6,16])c.beginPath(),c.moveTo(-24,y),c.lineTo(4,y),c.stroke() + c.beginPath();c.moveTo(-2,-44);c.quadraticCurveTo(4,-49,10,-44);c.stroke() + c.restore() + if(pp>.1)ds(c,8,3.5,'#fff',()=>{for(const a of[-2.1,-1.6,-1.1])c.moveTo(196+62*cos(a),170+62*sin(a)),c.lineTo(196+(72+8*pp)*cos(a),170+(72+8*pp)*sin(a))}) +} diff --git a/gen/uianime/success/victory.js b/gen/uianime/success/victory.js new file mode 100644 index 0000000..3ac2cc8 --- /dev/null +++ b/gen/uianime/success/victory.js @@ -0,0 +1,48 @@ +// red haired girl with a side ponytail flashing a sideways V sign over her eye, winking with a big grin while sparkles pop all around +const{sin,cos,PI,max,min}=Math,T=2*PI +export const frames=16,delay=80 +const SKIN='#ffe3d1',HAIR='#ff6b6b',HD='#e03131',HL='#ffe3e3',EYE='#4dabf7',ED='#1864ab',TOP='#ffe066',TD='#fab005',SCR='#74c0fc',BL='#ff8fab',MO='#c92a2a',TG='#ff8fab',SP=['#ffd43b','#ff8fab','#74c0fc','#ffd43b','#b2f2bb'] +const ds=(c,a,b,s,f)=>{for(const[l,k]of[[a,'#111'],[b,s]])c.lineWidth=l,c.strokeStyle=k,c.beginPath(),f(),c.stroke();c.strokeStyle='#111'} +const eye=(c,x,y,d)=>{ + c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill() + c.save();c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.clip();c.fillStyle=EYE;c.fill();c.fillStyle=ED;c.beginPath();c.ellipse(x,y-8,13,10,0,0,T);c.fill();c.restore() + c.lineWidth=2.5;c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.stroke() + c.fillStyle='#111';c.beginPath();c.ellipse(x,y+3,5.5,7.5,0,0,T);c.fill() + c.fillStyle='#fff';c.beginPath();c.arc(x-4,y-5,4.5,0,T);c.fill();c.beginPath();c.arc(x+5,y+8,2,0,T);c.fill() + c.lineWidth=6;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke() + c.lineWidth=2.5;c.beginPath();c.moveTo(x-8,y+18);c.lineTo(x+8,y+18);c.stroke() +} +const spark=(c,x,y,r)=>{c.beginPath();c.moveTo(x,y-r);for(const[a,b]of[[1,0],[0,1],[-1,0],[0,-1]])c.quadraticCurveTo(x+(a+b)*r*.15,y+(b-a)*r*.15,x+a*r,y+b*r);c.fill();c.stroke()} +export default(c,t)=>{ + const w=t>=.25&&t<.94 + c.lineWidth=3.5 + for(const[k,[x,y]]of[[30,40],[220,30],[236,224],[24,104],[150,16]].entries()){const p=(t-.25-k*.1+1)%1;if(p<.4)c.fillStyle=SP[k],spark(c,x,y,19*sin(PI*p/.4))} + c.save();c.translate(178,62) + c.lineWidth=6;c.fillStyle=HAIR;c.beginPath();c.moveTo(-8,0);c.bezierCurveTo(34,-12,56,50,46,126);c.quadraticCurveTo(40,148,24,156);c.quadraticCurveTo(34,96,0,24);c.closePath();c.fill();c.stroke() + c.strokeStyle=HD;c.lineWidth=3;c.beginPath();c.moveTo(12,12);c.bezierCurveTo(34,34,42,80,36,124);c.stroke();c.strokeStyle='#111' + c.fillStyle=SCR;c.lineWidth=5;c.beginPath();c.ellipse(2,6,11,15,.5,0,T);c.fill();c.stroke() + c.restore() + c.lineWidth=6;c.fillStyle=HD;c.beginPath();c.moveTo(128,34);c.bezierCurveTo(196,34,206,96,198,156);c.lineTo(58,156);c.bezierCurveTo(50,96,60,34,128,34);c.fill();c.stroke() + c.fillStyle=TOP;c.beginPath();c.moveTo(100,190);c.quadraticCurveTo(62,198,54,250);c.lineTo(202,250);c.quadraticCurveTo(194,198,156,190);c.closePath();c.fill();c.stroke() + c.fillStyle='#fff';c.beginPath();c.moveTo(96,191);c.lineTo(128,214);c.lineTo(160,191);c.lineTo(170,200);c.lineTo(128,232);c.lineTo(86,200);c.closePath();c.fill();c.lineWidth=5;c.stroke() + c.fillStyle=SKIN;c.beginPath();c.moveTo(116,168);c.lineTo(116,194);c.quadraticCurveTo(128,208,140,194);c.lineTo(140,168);c.fill();c.beginPath();c.moveTo(116,168);c.lineTo(116,192);c.moveTo(140,168);c.lineTo(140,192);c.stroke() + c.fillStyle=TD;c.lineWidth=4;c.beginPath();for(let k=0;k<10;k++){const r=k%2?6:13,b=k*PI/5-PI/2;c.lineTo(160+cos(b)*r,230+sin(b)*r)}c.closePath();c.fill();c.stroke() + c.lineWidth=6;c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + eye(c,153,140,1) + if(w){c.lineWidth=5.5;c.beginPath();c.moveTo(91,130);c.lineTo(112,141);c.lineTo(91,151);c.stroke()}else eye(c,103,140,-1) + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*42,161,12,6,0,0,T),c.fill() + c.lineWidth=2.5;for(const d of[-1,1])for(const k of[-5,0,5])c.beginPath(),c.moveTo(128+d*42+k-2,164),c.lineTo(128+d*42+k+2,158),c.stroke() + c.lineWidth=3.5;c.fillStyle=MO;c.beginPath();c.moveTo(114,164);c.quadraticCurveTo(128,170,142,164);c.quadraticCurveTo(140,184,128,184);c.quadraticCurveTo(116,184,114,164);c.fill();c.stroke() + c.save();c.clip();c.fillStyle=TG;c.beginPath();c.ellipse(128,184,8,6,0,0,T);c.fill();c.fillStyle='#fff';c.fillRect(114,160,28,7);c.restore() + c.lineWidth=6;c.fillStyle=HAIR;c.beginPath();c.moveTo(70,146) + c.bezierCurveTo(54,74,88,36,128,36);c.bezierCurveTo(168,36,202,74,186,146) + c.quadraticCurveTo(186,116,178,102);c.quadraticCurveTo(170,104,164,112);c.quadraticCurveTo(160,98,150,92);c.quadraticCurveTo(144,104,136,110) + c.quadraticCurveTo(132,96,124,90);c.quadraticCurveTo(118,102,110,108);c.quadraticCurveTo(106,96,96,94);c.quadraticCurveTo(90,104,86,112) + c.quadraticCurveTo(80,104,78,102);c.quadraticCurveTo(70,120,70,146);c.closePath();c.fill();c.stroke() + c.strokeStyle=HL;c.lineWidth=5;for(const[a,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,56,PI*a,PI*e),c.stroke() + c.strokeStyle='#111' + ds(c,30,19,TOP,()=>{c.moveTo(74,252);c.lineTo(36,206);c.lineTo(46,166)}) + for(const[fx,fy]of[[86,120],[88,160]])ds(c,14,7,SKIN,()=>{c.moveTo(54,148+(fy-140)*.3);c.lineTo(fx,fy)}) + c.lineWidth=5;c.fillStyle=SKIN;c.beginPath();c.ellipse(50,152,13,14,0,0,T);c.fill();c.stroke() + c.beginPath();c.ellipse(56,160,8,5,-.3,0,T);c.fill();c.stroke() +} diff --git a/gen/uianime/sync/juggle.js b/gen/uianime/sync/juggle.js new file mode 100644 index 0000000..b2ce0fb --- /dev/null +++ b/gen/uianime/sync/juggle.js @@ -0,0 +1,52 @@ +// sky blue haired girl with a big bow juggling three file icons in a loop over her head, tongue out in concentration, sync arrows on her tee +const{sin,PI,max}=Math,T=2*PI +export const frames=10,delay=110 +const SKIN='#ffe3d1',HAIR='#74c0fc',HD='#1c7ed6',HL='#e7f5ff',EYE='#f76707',ED='#d9480f',TEE='#ffe066',BL='#ffa8a8',BOW='#f783ac',SY='#4dabf7',FC=[['#ffc9c9','#fa5252'],['#b2f2bb','#40c057'],['#d0bfff','#7950f2']] +const ds=(c,a,b,s,f)=>{for(const[l,k]of[[a,'#111'],[b,s]])c.lineWidth=l,c.strokeStyle=k,c.beginPath(),f(),c.stroke();c.strokeStyle='#111'} +const eye=(c,x,y,d,gx,gy)=>{ + c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill() + c.save();c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.clip();c.beginPath();c.ellipse(x+gx,y+gy,11.5,15,0,0,T);c.fillStyle=EYE;c.fill();c.lineWidth=2.5;c.stroke() + c.fillStyle=ED;c.beginPath();c.ellipse(x+gx,y+gy-10,13,9,0,0,T);c.fill() + c.fillStyle='#111';c.beginPath();c.ellipse(x+gx,y+gy+1,5.5,7.5,0,0,T);c.fill() + c.fillStyle='#fff';c.beginPath();c.arc(x+gx-4,y+gy-6,4.5,0,T);c.fill();c.beginPath();c.arc(x+gx+5,y+gy+7,2,0,T);c.fill();c.restore() + c.lineWidth=6;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke() +} +const file=(c,x,y,a,[f,l])=>{c.save();c.translate(x,y);c.rotate(a) + c.fillStyle=f;c.lineWidth=5;c.beginPath();c.moveTo(-16,-21);c.lineTo(6,-21);c.lineTo(16,-11);c.lineTo(16,21);c.lineTo(-16,21);c.closePath();c.fill();c.stroke() + c.fillStyle='#fff';c.lineWidth=4;c.beginPath();c.moveTo(6,-21);c.lineTo(6,-11);c.lineTo(16,-11);c.closePath();c.fill();c.stroke() + c.strokeStyle=l;c.lineWidth=4;c.beginPath();for(const[w,yy]of[[12,-3],[20,5],[16,13]])c.moveTo(-9,yy),c.lineTo(-9+w,yy);c.stroke();c.restore()} +const pos=p=>{if(p<2/3){const q=p*1.5;return[212-168*q,196-4*166*q*(1-q)]}const q=(p-2/3)*3;return[44+168*q,196+30*sin(PI*q)]} +export default(c,t)=>{ + const lh=196-10*max(0,sin(3*T*t+2)),rh=196-10*max(0,sin(3*T*t-.6)) + const fp=[0,1,2].map(k=>(t+k/3)%1),top=fp.reduce((a,b)=>Math.abs(b-1/3){c.save();c.translate(128,174);c.scale(.66,.66);c.translate(-128,-186);f();c.restore()} + H(()=>{ + c.lineWidth=8;c.fillStyle=HD;c.beginPath();c.moveTo(128,34);c.bezierCurveTo(198,34,212,100,206,160);c.quadraticCurveTo(208,190,190,200);c.lineTo(66,200);c.quadraticCurveTo(48,190,50,160);c.bezierCurveTo(44,100,58,34,128,34);c.fill();c.stroke() + c.fillStyle=TEE;c.beginPath();c.moveTo(100,190);c.quadraticCurveTo(52,198,40,330);c.lineTo(216,330);c.quadraticCurveTo(204,198,156,190);c.closePath();c.fill();c.stroke() + c.fillStyle='#fff';c.beginPath();c.moveTo(104,190);c.quadraticCurveTo(128,214,152,190);c.closePath();c.fill();c.stroke() + c.fillStyle=SKIN;c.beginPath();c.moveTo(114,168);c.lineTo(114,194);c.quadraticCurveTo(128,206,142,194);c.lineTo(142,168);c.fill();c.beginPath();c.moveTo(114,168);c.lineTo(114,192);c.moveTo(142,168);c.lineTo(142,192);c.stroke() + c.save();c.translate(128,260);c.rotate(-.4) + for(const d of[0,PI])ds(c,14,7,SY,()=>{c.arc(0,0,16,d+.3,d+2.5)}) + c.fillStyle=SY;c.lineWidth=4;for(const d of[0,PI]){c.save();c.rotate(d+2.5);c.beginPath();c.moveTo(16,-10);c.lineTo(28,0);c.lineTo(10,4);c.closePath();c.restore();c.fill();c.stroke()} + c.restore() + for(const d of[-1,1]){c.fillStyle=HAIR;c.beginPath();c.moveTo(128+d*60,110);c.bezierCurveTo(128+d*82,150,128+d*76,200,128+d*62,226);c.quadraticCurveTo(128+d*50,214,128+d*48,200);c.quadraticCurveTo(128+d*58,160,128+d*48,120);c.closePath();c.fill();c.stroke()} + c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + eye(c,103,140,-1,1,-4);eye(c,153,140,1,1,-4) + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,162,14,8,0,0,T),c.fill() + c.lineWidth=4;for(const d of[-1,1])for(const k of[-6,0,6])c.beginPath(),c.moveTo(128+d*44+k-2,166),c.lineTo(128+d*44+k+2,158),c.stroke() + c.lineWidth=6;c.beginPath();c.moveTo(116,168);c.quadraticCurveTo(128,174,140,168);c.stroke() + c.fillStyle='#ff8fab';c.beginPath();c.moveTo(130,171);c.quadraticCurveTo(132,184,139,182);c.quadraticCurveTo(144,176,140,169);c.fill();c.stroke() + c.lineWidth=8;c.fillStyle=HAIR;c.beginPath();c.moveTo(68,150) + c.bezierCurveTo(52,74,88,36,128,36);c.bezierCurveTo(168,36,204,74,188,150) + c.quadraticCurveTo(186,118,178,102);c.quadraticCurveTo(170,104,164,112);c.quadraticCurveTo(158,98,148,92);c.quadraticCurveTo(142,104,134,110) + c.quadraticCurveTo(128,98,120,92);c.quadraticCurveTo(114,104,106,110);c.quadraticCurveTo(100,98,92,96);c.quadraticCurveTo(88,106,84,112) + c.quadraticCurveTo(80,104,78,104);c.quadraticCurveTo(70,124,68,150);c.closePath();c.fill();c.stroke() + c.strokeStyle=HL;c.lineWidth=7;for(const[s,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,56,PI*s,PI*e),c.stroke() + c.strokeStyle='#111';c.fillStyle=BOW;c.lineWidth=7 + for(const d of[-1,1])c.beginPath(),c.moveTo(128,40),c.quadraticCurveTo(128+d*30,8,128+d*44,30),c.quadraticCurveTo(128+d*36,58,128,40),c.fill(),c.stroke() + c.beginPath();c.arc(128,40,9,0,T);c.fill();c.stroke() + }) + for(const[x,y,d]of[[44,lh,-1],[212,rh,1]])ds(c,20,11,TEE,()=>{c.moveTo(128+d*44,196);c.quadraticCurveTo(128+d*70,246,x,y+10)}) + fp.forEach((p,k)=>{const[x,y]=pos(p);file(c,x,y,p*T,FC[k])}) + c.fillStyle=SKIN;c.lineWidth=5;for(const[x,y]of[[44,lh],[212,rh]])c.beginPath(),c.ellipse(x,y+8,12,11,0,0,T),c.fill(),c.stroke() +} diff --git a/gen/uianime/thanks/heart.js b/gen/uianime/thanks/heart.js new file mode 100644 index 0000000..d4f3e0c --- /dev/null +++ b/gen/uianime/thanks/heart.js @@ -0,0 +1,47 @@ +// pink-bob girl saying thanks with a heart made of her hands, a red heart beating inside it while little hearts float up +const{sin,cos,PI,max}=Math,T=2*PI +export const frames=12,delay=90 +const SKIN='#ffe3d1',HAIR='#faa2c1',HD='#e64980',HL='#fff0f6',EYE='#9775fa',ED='#5f3dc4',SW='#a5d8ff',BL='#ff8fab',MO='#c92a2a',TG='#ff8fab',HR='#fa5252',HT=['#ff6b6b','#f06595','#ffa8a8'],CL='#ffd43b' +const eye=(c,x,y,d)=>{ + c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill() + c.save();c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.clip();c.fillStyle=EYE;c.fill();c.fillStyle=ED;c.beginPath();c.ellipse(x,y-8,13,10,0,0,T);c.fill();c.restore() + c.lineWidth=2.5;c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.stroke() + c.fillStyle='#111';c.beginPath();c.ellipse(x,y+3,5.5,7.5,0,0,T);c.fill() + c.fillStyle='#fff';c.beginPath();c.arc(x-4,y-5,4.5,0,T);c.fill();c.beginPath();c.arc(x+5,y+8,2,0,T);c.fill() + c.lineWidth=6;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke() +} +const hp=(c,x,y,s)=>{c.save();c.translate(x,y);c.scale(s,s);c.beginPath();c.moveTo(0,8);c.bezierCurveTo(-13,-1,-9,-12,0,-5);c.bezierCurveTo(9,-12,13,-1,0,8);c.restore()} +export default(c,t,i)=>{ + const pu=1+.12*max(0,sin(2*T*t))**2,bk=i==9,head=f=>f() + head(()=>{c.lineWidth=6;c.fillStyle=HD;c.beginPath();c.moveTo(128,34);c.bezierCurveTo(198,34,214,100,206,158);c.quadraticCurveTo(204,184,182,182);c.lineTo(74,182);c.quadraticCurveTo(52,184,50,158);c.bezierCurveTo(42,100,58,34,128,34);c.fill();c.stroke()}) + c.lineWidth=6;c.fillStyle=SW;c.beginPath();c.moveTo(100,190);c.quadraticCurveTo(62,198,54,252);c.lineTo(202,252);c.quadraticCurveTo(194,198,156,190);c.closePath();c.fill();c.stroke() + c.fillStyle='#fff';c.lineWidth=5;for(const d of[-1,1])c.beginPath(),c.moveTo(128,204),c.quadraticCurveTo(128+d*16,212,128+d*30,194),c.lineTo(128+d*12,188),c.closePath(),c.fill(),c.stroke() + c.fillStyle=SKIN;c.beginPath();c.moveTo(116,166);c.lineTo(116,192);c.lineTo(128,204);c.lineTo(140,192);c.lineTo(140,166);c.fill();c.beginPath();c.moveTo(116,166);c.lineTo(116,190);c.moveTo(140,166);c.lineTo(140,190);c.stroke() + head(()=>{ + c.lineWidth=6;c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + if(bk){c.lineWidth=5;for(const x of[103,153])c.beginPath(),c.arc(x,148,13,PI*1.15,PI*1.85),c.stroke()}else eye(c,103,140,-1),eye(c,153,140,1) + c.lineWidth=2.5;c.beginPath();c.moveTo(128,156);c.lineTo(127,159);c.stroke() + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*42,161,13,6.5,0,0,T),c.fill() + c.lineWidth=2.5;for(const d of[-1,1])for(const k of[-5,0,5])c.beginPath(),c.moveTo(128+d*42+k-2,164),c.lineTo(128+d*42+k+2,158),c.stroke() + c.lineWidth=3.5;c.fillStyle=MO;c.beginPath();c.moveTo(118,165);c.quadraticCurveTo(128,184,138,165);c.closePath();c.fill();c.stroke();c.save();c.clip();c.fillStyle=TG;c.beginPath();c.ellipse(128,179,7,5,0,0,T);c.fill();c.restore() + c.lineWidth=6;c.fillStyle=HAIR;c.beginPath();c.moveTo(62,172) + c.bezierCurveTo(46,74,88,36,128,36);c.bezierCurveTo(168,36,210,74,194,172);c.quadraticCurveTo(186,150,184,120) + c.lineTo(178,106);c.lineTo(168,114);c.lineTo(160,100);c.lineTo(148,112);c.lineTo(138,98);c.lineTo(128,112);c.lineTo(118,98);c.lineTo(108,112);c.lineTo(96,100);c.lineTo(88,114);c.lineTo(78,106) + c.lineTo(72,120);c.quadraticCurveTo(70,150,62,172);c.closePath();c.fill();c.stroke() + c.strokeStyle=HL;c.lineWidth=5;for(const[a,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,56,PI*a,PI*e),c.stroke() + c.strokeStyle='#111';c.fillStyle=CL;c.lineWidth=4;for(const[x,y,r]of[[80,80,-.9],[90,66,-.7]])c.save(),c.translate(x,y),c.rotate(r),c.beginPath(),c.roundRect(-11,-4,22,8,4),c.fill(),c.stroke(),c.restore() + }) + for(const d of[-1,1])for(const[w,s]of[[30,'#111'],[19,SW]])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.moveTo(128+d*86,262),c.lineTo(128+d*50,226),c.stroke() + c.save();c.translate(128,216);c.scale(pu,pu);c.translate(-128,-216) + c.fillStyle=HR;c.strokeStyle='#111';c.lineWidth=5;hp(c,128,214,2.4);c.fill();c.stroke() + c.fillStyle='#fff';c.beginPath();c.ellipse(113,202,5,3.5,-.6,0,T);c.fill() + for(const[w,s]of[[28,'#111'],[17,SKIN]])c.lineWidth=w,c.strokeStyle=s,hp(c,128,216,4),c.stroke() + c.strokeStyle='#111';c.lineWidth=5;c.fillStyle=SKIN + for(const d of[-1,1]){c.beginPath();c.ellipse(128+d*38,220,13,17,-d*.3,0,T);c.fill();c.stroke()} + c.lineWidth=3;c.beginPath() + for(const d of[-1,1])c.moveTo(128+d*30,228),c.quadraticCurveTo(128+d*22,226,128+d*16,234),c.moveTo(128+d*44,206),c.lineTo(128+d*36,201) + c.stroke() + c.restore() + c.strokeStyle='#111';c.lineWidth=4 + for(const[x0,o,k]of[[28,0,0],[228,.25,1],[36,.5,2],[220,.75,0]]){const p=(t+o)%1,s=1.4*sin(PI*p);if(s>.15)c.fillStyle=HT[k],hp(c,x0+7*sin(T*(p*2+o)),196-p*176,s),c.fill(),c.stroke()} +} diff --git a/gen/uianime/timeout/asleep.js b/gen/uianime/timeout/asleep.js new file mode 100644 index 0000000..87cddc1 --- /dev/null +++ b/gen/uianime/timeout/asleep.js @@ -0,0 +1,47 @@ +// periwinkle haired girl fast asleep with her cheek on her arms at a desk, drooling, Zzz floating up while a red alarm clock ticks its hand around +const{sin,cos,PI}=Math,T=2*PI +export const frames=12,delay=100 +const SKIN='#ffe3d1',HAIR='#91a7ff',HD='#5c7cfa',HL='#edf2ff',SWT='#ffd8a8',SD='#ffa94d',DESK='#e8b07a',DD='#c47f45',BL='#ffa8a8',CLK='#ff6b6b',CD='#e03131',BELL='#ffd43b',ZC='#91a7ff' +const ds=(c,a,b,s,f)=>{for(const[l,k]of[[a,'#111'],[b,s]])c.lineWidth=l,c.strokeStyle=k,c.beginPath(),f(),c.stroke();c.strokeStyle='#111'} +const zed=(c,x,y,s)=>{c.save();c.translate(x,y);c.scale(s,s);c.rotate(-.15);ds(c,11,5,ZC,()=>{c.moveTo(-9,-9);c.lineTo(9,-9);c.lineTo(-9,9);c.lineTo(9,9)});c.restore()} +export default(c,t,i)=>{ + const H=f=>{c.save();c.translate(96,140);c.rotate(-.32);c.scale(.8,.8);c.translate(-128,-128);f();c.restore()} + c.lineWidth=6;c.fillStyle=SWT;c.beginPath();c.moveTo(14,214);c.quadraticCurveTo(14,150,64,140);c.lineTo(132,140);c.quadraticCurveTo(178,150,178,214);c.closePath();c.fill();c.stroke() + H(()=>{c.lineWidth=7;c.fillStyle=HD;c.beginPath();c.moveTo(128,34);c.bezierCurveTo(200,34,214,100,208,160);c.quadraticCurveTo(212,200,196,218);c.lineTo(60,218);c.quadraticCurveTo(44,200,48,160);c.bezierCurveTo(42,100,56,34,128,34);c.fill();c.stroke()}) + c.lineWidth=6;c.fillStyle=DESK;c.beginPath();c.roundRect(6,208,244,34,8);c.fill();c.stroke() + c.strokeStyle=DD;c.lineWidth=4;c.beginPath();c.moveTo(18,226);c.lineTo(238,226);c.stroke();c.strokeStyle='#111' + c.lineWidth=6;c.fillStyle=SWT;c.beginPath();c.roundRect(12,180,108,32,16);c.fill();c.stroke();c.beginPath();c.roundRect(72,184,100,30,15);c.fill();c.stroke() + c.strokeStyle=SD;c.lineWidth=4;for(const x of[30,158])c.beginPath(),c.moveTo(x,186),c.lineTo(x,208),c.stroke();c.strokeStyle='#111' + H(()=>{ + c.lineWidth=7;c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + c.lineWidth=6;for(const[x,d]of[[103,-1],[153,1]]){c.beginPath();c.arc(x,134,14,PI*.15,PI*.85);c.stroke();c.beginPath();c.moveTo(x+d*13,139);c.lineTo(x+d*19,136);c.stroke()} + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,160,14,7,0,0,T),c.fill() + c.lineWidth=3;for(const d of[-1,1])for(const k of[-5,0,5])c.beginPath(),c.moveTo(128+d*44+k-2,163),c.lineTo(128+d*44+k+2,157),c.stroke() + c.lineWidth=4.5;c.fillStyle='#c92a2a';c.beginPath();c.ellipse(126,170,6,5,0,0,T);c.fill();c.stroke() + const dl=2+2*sin(T*t) + c.fillStyle='#d0ebff';c.lineWidth=3.5;c.beginPath();c.moveTo(120,173);c.quadraticCurveTo(110,184+dl,116,189+dl);c.quadraticCurveTo(124,193+dl,125,185+dl);c.quadraticCurveTo(125,179,120,173);c.fill();c.stroke() + c.lineWidth=7;c.fillStyle=HAIR;c.beginPath();c.moveTo(66,156) + c.bezierCurveTo(50,74,88,36,128,36);c.bezierCurveTo(168,36,206,74,190,156) + c.quadraticCurveTo(188,122,180,106);c.quadraticCurveTo(172,104,166,112);c.quadraticCurveTo(160,98,150,92);c.quadraticCurveTo(144,104,136,110) + c.quadraticCurveTo(130,96,120,92);c.quadraticCurveTo(114,104,106,110);c.quadraticCurveTo(100,98,92,96);c.quadraticCurveTo(88,106,84,112) + c.quadraticCurveTo(78,104,76,104);c.quadraticCurveTo(68,126,66,156);c.closePath();c.fill();c.stroke() + c.strokeStyle=HL;c.lineWidth=6;for(const[s,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,56,PI*s,PI*e),c.stroke() + c.strokeStyle='#111' + }) + const r=i%2?1:-1,X=200,Y=162 + c.save();c.translate(X,Y+48);c.rotate(.05*r);c.translate(-X,-Y-48) + c.lineWidth=6;for(const d of[-1,1])c.beginPath(),c.moveTo(X+d*20,Y+32),c.lineTo(X+d*28,Y+48),c.stroke() + ds(c,10,4,'#adb5bd',()=>{c.moveTo(X,Y-44);c.lineTo(X,Y-56)}) + c.fillStyle=BELL;c.lineWidth=5;for(const d of[-1,1])c.beginPath(),c.arc(X+d*24,Y-36,15,PI+d*.35,d*.35),c.closePath(),c.fill(),c.stroke() + c.fillStyle=CLK;c.lineWidth=6;c.beginPath();c.arc(X,Y,40,0,T);c.fill();c.stroke() + c.fillStyle='#fff';c.lineWidth=4;c.beginPath();c.arc(X,Y,30,0,T);c.fill();c.stroke() + c.fillStyle='#111';for(let k=0;k<4;k++)c.beginPath(),c.arc(X+23*cos(k*PI/2),Y+23*sin(k*PI/2),3,0,T),c.fill() + const m=T*i/12-PI/2 + c.lineWidth=6;c.beginPath();c.moveTo(X,Y);c.lineTo(X+14*cos(-2.4),Y+14*sin(-2.4));c.stroke() + c.strokeStyle=CD;c.lineWidth=4;c.beginPath();c.moveTo(X,Y);c.lineTo(X+22*cos(m),Y+22*sin(m));c.stroke();c.strokeStyle='#111' + c.fillStyle=CD;c.lineWidth=3;c.beginPath();c.arc(X,Y,4.5,0,T);c.fill();c.stroke() + c.fillStyle='#fff';c.beginPath();c.ellipse(X-20,Y-22,8,4,-.7,0,T);c.fill() + c.restore() + for(const a of[.65,1.15])ds(c,7,3,'#fff',()=>{const b=-PI/2+r*a,x=X+r*24,y=Y-36;c.moveTo(x+cos(b)*21,y+sin(b)*21);c.lineTo(x+cos(b)*30,y+sin(b)*30)}) + for(const o of[0,1/3,2/3]){const p=(t+o)%1;zed(c,146+46*p+5*sin(p*T),96-80*p,.55+.75*sin(PI*p))} +} diff --git a/gen/uianime/typing/chat.js b/gen/uianime/typing/chat.js new file mode 100644 index 0000000..f0363f4 --- /dev/null +++ b/gen/uianime/typing/chat.js @@ -0,0 +1,58 @@ +// orange bob girl in a mint hoodie typing furiously on her phone with both thumbs, tongue poking out, while a chat bubble's three dots bounce +const{sin,cos,PI,max}=Math,T=2*PI +export const frames=12,delay=75 +const SKIN='#ffe3d1',HAIR='#ffa94d',HD='#f76707',HL='#fff4e6',EYE='#20c997',ED='#087f5b',HO='#96f2d7',HOD='#20c997',PH='#b197fc',BL='#ffa8a8',TG='#ff8fab',CLIP='#f06595' +const ds=(c,a,b,s,f)=>{for(const[l,k]of[[a,'#111'],[b,s]])c.lineWidth=l,c.strokeStyle=k,c.beginPath(),f(),c.stroke();c.strokeStyle='#111'} +const eye=(c,x,y,d)=>{ + c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill() + c.save();c.beginPath();c.ellipse(x,y+3,11.5,14,0,0,T);c.clip();c.fillStyle=EYE;c.fill();c.fillStyle=ED;c.beginPath();c.ellipse(x,y-6,13,10,0,0,T);c.fill();c.restore() + c.lineWidth=2.5;c.beginPath();c.ellipse(x,y+3,11.5,14,0,0,T);c.stroke() + c.fillStyle='#111';c.beginPath();c.ellipse(x,y+6,5.5,7,0,0,T);c.fill() + c.fillStyle='#fff';c.beginPath();c.arc(x-4,y-2,4.5,0,T);c.fill();c.beginPath();c.arc(x+5,y+10,2,0,T);c.fill() + c.lineWidth=6;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-18,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke() + c.lineWidth=2.5;c.beginPath();c.moveTo(x-8,y+18);c.lineTo(x+8,y+18);c.stroke() +} +export default(c,t)=>{ + const th=[0,PI].map(o=>max(0,sin(3*T*t+o))) + c.save();c.translate(116,22);c.scale(.8,.8);c.translate(-128,0) + c.lineWidth=6;c.fillStyle=HD;c.beginPath();c.moveTo(128,34);c.bezierCurveTo(198,34,214,100,204,168);c.quadraticCurveTo(200,186,184,184);c.lineTo(72,184);c.quadraticCurveTo(56,186,52,168);c.bezierCurveTo(42,100,58,34,128,34);c.fill();c.stroke() + c.fillStyle=HOD;c.beginPath();c.moveTo(84,196);c.quadraticCurveTo(128,176,172,196);c.lineTo(166,214);c.quadraticCurveTo(128,200,90,214);c.closePath();c.fill();c.stroke() + c.fillStyle=HO;c.beginPath();c.moveTo(96,194);c.quadraticCurveTo(58,202,50,262);c.lineTo(206,262);c.quadraticCurveTo(198,202,160,194);c.quadraticCurveTo(128,214,96,194);c.fill();c.stroke() + c.fillStyle=SKIN;c.beginPath();c.moveTo(116,168);c.lineTo(116,194);c.quadraticCurveTo(128,204,140,194);c.lineTo(140,168);c.fill();c.lineWidth=5;c.beginPath();c.moveTo(116,168);c.lineTo(116,192);c.moveTo(140,168);c.lineTo(140,192);c.stroke() + c.lineWidth=6;c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + eye(c,103,140,-1);eye(c,153,140,1) + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*42,162,12,6,0,0,T),c.fill() + c.lineWidth=2.5;for(const d of[-1,1])for(const k of[-5,0,5])c.beginPath(),c.moveTo(128+d*42+k-2,165),c.lineTo(128+d*42+k+2,159),c.stroke() + c.fillStyle=TG;c.lineWidth=3;c.beginPath();c.ellipse(134,172,5,6,-.3,0,T);c.fill();c.stroke() + c.lineWidth=3.5;c.beginPath();c.moveTo(119,168);c.quadraticCurveTo(128,171,139,167);c.stroke() + c.lineWidth=6;c.fillStyle=HAIR;c.beginPath();c.moveTo(62,176) + c.bezierCurveTo(44,74,88,36,128,36);c.bezierCurveTo(168,36,212,74,194,176);c.quadraticCurveTo(186,180,178,176) + c.quadraticCurveTo(182,128,176,104);c.quadraticCurveTo(168,104,162,112);c.quadraticCurveTo(158,98,148,92);c.quadraticCurveTo(142,104,134,110) + c.quadraticCurveTo(130,96,122,90);c.quadraticCurveTo(116,102,108,108);c.quadraticCurveTo(104,96,94,94);c.quadraticCurveTo(88,104,82,108) + c.quadraticCurveTo(74,128,78,176);c.quadraticCurveTo(70,180,62,176);c.closePath();c.fill();c.stroke() + c.strokeStyle=HL;c.lineWidth=5;for(const[a,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,56,PI*a,PI*e),c.stroke() + for(const[w,s]of[[11,'#111'],[5,CLIP]]){c.lineWidth=w;c.strokeStyle=s;c.beginPath();c.moveTo(158,66);c.lineTo(176,80);c.moveTo(164,82);c.lineTo(172,62);c.stroke()} + c.strokeStyle='#111' + for(const d of[-1,1])ds(c,30,19,HO,()=>{c.moveTo(128+d*86,300);c.lineTo(128+d*40,282)}) + c.save();c.translate(128,236);c.rotate(-.05) + c.lineWidth=6;c.fillStyle=PH;c.beginPath();c.roundRect(-38,-48,76,100,13);c.fill();c.stroke() + c.fillStyle='#f8f9fa';c.lineWidth=3;c.beginPath();c.roundRect(-30,-40,60,84,6);c.fill();c.stroke() + c.fillStyle='#a5d8ff';c.beginPath();c.roundRect(-25,-35,32,10,5);c.fill() + c.fillStyle='#ffc9de';c.beginPath();c.roundRect(-6,-21,31,10,5);c.fill() + c.fillStyle='#dee2e6';c.beginPath();c.roundRect(-30,-4,60,48,[0,0,6,6]);c.fill() + c.fillStyle='#fff';for(let r=0;r<3;r++)for(let k=0;k<5;k++)c.beginPath(),c.roundRect(-27+k*11.4,r*11,9,8,2),c.fill() + for(const[k,d,tx,y]of[[0,-1,-12,8],[1,1,10,14]]){ + const l=th[k],ty=y-5*l + c.lineWidth=5;c.fillStyle=SKIN;c.beginPath();c.ellipse(d*34,40,14,16,0,0,T);c.fill();c.stroke() + ds(c,18,9,SKIN,()=>{c.moveTo(d*34,36);c.lineTo(tx,ty)}) + c.fillStyle=SKIN;c.beginPath();c.ellipse(tx,ty,6.5+1.5*l,6.5+1.5*l,0,0,T);c.fill() + } + c.restore() + for(const[k,d]of[[0,-1],[1,1]])if(th[k]<.3)ds(c,8,3.5,'#fff',()=>{for(const a of[-.5,0,.5])c.moveTo(128+d*(50+12*cos(a)),196+12*sin(a)*d),c.lineTo(128+d*(50+24*cos(a)),196+24*sin(a)*d)}) + c.restore() + // typing bubble with three bouncing dots + c.lineWidth=5;c.fillStyle='#fff' + for(const[x,y,r]of[[164,82,5],[176,70,9]])c.beginPath(),c.arc(x,y,r,0,T),c.fill(),c.stroke() + c.lineWidth=6;c.beginPath();c.roundRect(168,14,80,50,25);c.fill();c.stroke() + for(let k=0;k<3;k++){const p=(t-k*.14+1)%1,l=p<.42?sin(PI*p/.42):0;c.fillStyle=l>.3?'#495057':'#adb5bd';c.beginPath();c.arc(186+k*22,40-8*l,7,0,T);c.fill()} +} diff --git a/gen/uianime/upload/toss.js b/gen/uianime/upload/toss.js new file mode 100644 index 0000000..9d82e4c --- /dev/null +++ b/gen/uianime/upload/toss.js @@ -0,0 +1,64 @@ +// pink haired girl in a sailor top swinging a file up and tossing it into a cloud, the cloud gulps it with a bounce and she cheers, then grabs the next one +const{sin,PI,max,min}=Math,T=2*PI +export const frames=16,delay=80 +const SKIN='#ffe3d1',HAIR='#faa2c1',HD='#e64980',HL='#fff0f6',EYE='#339af0',ED='#1864ab',TOP='#e5dbff',COL='#4263eb',SCF='#fa5252',BL='#ff8fab',CL='#e7f5ff',AR='#4dabf7',FL='#ffe066',FD='#f59f00',SP='#ffd43b' +const ds=(c,a,b,s,f)=>{for(const[l,k]of[[a,'#111'],[b,s]])c.lineWidth=l,c.strokeStyle=k,c.beginPath(),f(),c.stroke();c.strokeStyle='#111'} +const ease=x=>x<0?0:x>1?1:x*x*(3-2*x),L=(a,b,u)=>a+(b-a)*u +const eye=(c,x,y,d)=>{ + c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill() + c.save();c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.clip();c.beginPath();c.ellipse(x+4,y-1,11.5,15,0,0,T);c.fillStyle=EYE;c.fill();c.lineWidth=2.5;c.stroke() + c.fillStyle=ED;c.beginPath();c.ellipse(x+4,y-11,13,9,0,0,T);c.fill() + c.fillStyle='#111';c.beginPath();c.ellipse(x+4,y,5.5,7.5,0,0,T);c.fill() + c.fillStyle='#fff';c.beginPath();c.arc(x,y-7,4.5,0,T);c.fill();c.beginPath();c.arc(x+9,y+6,2,0,T);c.fill();c.restore() + c.lineWidth=6;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke() +} +const file=(c,x,y,a,s)=>{c.save();c.translate(x,y);c.rotate(a);c.scale(s,s) + c.fillStyle=FL;c.lineWidth=5;c.beginPath();c.moveTo(-18,-23);c.lineTo(7,-23);c.lineTo(18,-12);c.lineTo(18,23);c.lineTo(-18,23);c.closePath();c.fill();c.stroke() + c.fillStyle='#fff';c.lineWidth=4;c.beginPath();c.moveTo(7,-23);c.lineTo(7,-12);c.lineTo(18,-12);c.closePath();c.fill();c.stroke() + c.strokeStyle=FD;c.lineWidth=4;c.beginPath();for(const[w,yy]of[[12,-4],[24,5],[18,14]])c.moveTo(-10,yy),c.lineTo(-10+w,yy);c.stroke();c.restore()} +const spark=(c,x,y,r)=>{c.beginPath();c.moveTo(x,y-r);for(const[a,b]of[[1,0],[0,1],[-1,0],[0,-1]])c.quadraticCurveTo(x+(a+b)*r*.15,y+(b-a)*r*.15,x+a*r,y+b*r);c.fill();c.stroke()} +export default(c,t)=>{ + const up=ease((t-.25)/.125)-ease((t-.6)/.2),dip=sin(PI*min(1,t/.25))*8,fp=(t-.3125)/.25,gulp=t>=.5625&&t<.75,cs=gulp?1+.14*sin(PI*(t-.5625)/.1875):1,hap=t>=.5625&&t<.875 + const hx=L(116,180,up),hy=L(212+dip,118,up) + const H=f=>{c.save();c.translate(104,178);c.scale(.76,.76);c.translate(-128,-186);f();c.restore()} + H(()=>{ + c.save();c.translate(196,70);c.rotate(.25) + c.lineWidth=9;c.fillStyle=HAIR;c.beginPath();c.moveTo(-6,0);c.bezierCurveTo(40,10,60,70,40,140);c.quadraticCurveTo(30,160,14,150);c.bezierCurveTo(30,90,20,30,-6,10);c.closePath();c.fill();c.stroke() + c.strokeStyle=HD;c.lineWidth=4;c.beginPath();c.moveTo(14,18);c.bezierCurveTo(36,40,42,90,32,130);c.stroke();c.strokeStyle='#111' + c.restore() + c.lineWidth=9;c.fillStyle=HD;c.beginPath();c.moveTo(128,34);c.bezierCurveTo(198,34,210,100,204,160);c.lineTo(52,160);c.bezierCurveTo(46,100,58,34,128,34);c.fill();c.stroke() + c.fillStyle=TOP;c.beginPath();c.moveTo(100,190);c.quadraticCurveTo(52,198,40,330);c.lineTo(216,330);c.quadraticCurveTo(204,198,156,190);c.closePath();c.fill();c.stroke() + c.fillStyle=COL;c.beginPath();c.moveTo(96,190);c.lineTo(128,240);c.lineTo(160,190);c.lineTo(182,200);c.lineTo(128,270);c.lineTo(74,200);c.closePath();c.fill();c.stroke() + c.strokeStyle='#fff';c.lineWidth=4;c.beginPath();c.moveTo(84,202);c.lineTo(128,258);c.lineTo(172,202);c.stroke();c.strokeStyle='#111' + c.fillStyle=SKIN;c.lineWidth=9;c.beginPath();c.moveTo(114,168);c.lineTo(114,194);c.quadraticCurveTo(128,208,142,194);c.lineTo(142,168);c.fill();c.beginPath();c.moveTo(114,168);c.lineTo(114,192);c.moveTo(142,168);c.lineTo(142,192);c.stroke() + c.fillStyle=SCF;for(const d of[-1,1])c.beginPath(),c.moveTo(128,262),c.lineTo(128+d*26,250),c.lineTo(128+d*22,276),c.closePath(),c.fill(),c.stroke() + c.lineWidth=9;c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + if(hap){c.lineWidth=9;for(const x of[103,153])c.beginPath(),c.arc(x,148,15,1.15*PI,1.85*PI),c.stroke()} + else eye(c,103,140,-1),eye(c,153,140,1) + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,162,14,8,0,0,T),c.fill() + c.lineWidth=4;for(const d of[-1,1])for(const k of[-6,0,6])c.beginPath(),c.moveTo(128+d*44+k-2,166),c.lineTo(128+d*44+k+2,158),c.stroke() + c.lineWidth=6;c.fillStyle='#c92a2a';c.beginPath();c.moveTo(114,164);c.quadraticCurveTo(128,(hap?190:180),142,164);c.closePath();c.fill();c.stroke() + c.save();c.clip();c.fillStyle='#ff8fab';c.beginPath();c.ellipse(128,180,8,6,0,0,T);c.fill();c.restore() + c.lineWidth=9;c.fillStyle=HAIR;c.beginPath();c.moveTo(68,150) + c.bezierCurveTo(52,74,88,36,128,36);c.bezierCurveTo(168,36,204,74,188,150) + c.quadraticCurveTo(186,118,178,102);c.quadraticCurveTo(170,104,164,112);c.quadraticCurveTo(158,98,148,92);c.quadraticCurveTo(142,104,134,110) + c.quadraticCurveTo(128,98,120,92);c.quadraticCurveTo(114,104,106,110);c.quadraticCurveTo(100,98,92,96);c.quadraticCurveTo(88,106,84,112) + c.quadraticCurveTo(80,104,78,104);c.quadraticCurveTo(70,124,68,150);c.closePath();c.fill();c.stroke() + c.strokeStyle=HL;c.lineWidth=8;for(const[s,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,56,PI*s,PI*e),c.stroke() + c.strokeStyle='#111';c.fillStyle=SCF;c.lineWidth=7;for(const d of[-1,1])c.beginPath(),c.moveTo(192,66),c.lineTo(192+d*16,56-d*8),c.lineTo(192+d*20,74+d*6),c.closePath(),c.fill(),c.stroke() + c.beginPath();c.arc(192,66,7,0,T);c.fill();c.stroke() + }) + c.save();c.translate(192,46);c.scale(.9*cs,.9*(2-cs)) + c.fillStyle=CL;c.lineWidth=11;c.beginPath();for(const[x,y,r]of[[-34,10,22],[-14,-8,26],[16,-12,24],[38,6,20]])c.moveTo(x+r,y),c.arc(x,y,r,0,T);c.roundRect(-56,4,112,30,15);c.stroke();c.fill() + c.fillStyle='#fff';c.beginPath();c.ellipse(-20,-16,10,6,-.4,0,T);c.fill() + const ay=gulp?-4*sin(PI*(t-.5625)/.1875):0 + c.fillStyle=AR;c.lineWidth=4.5;c.beginPath();c.moveTo(0,-14+ay*2);c.lineTo(15,2+ay);c.lineTo(6,2+ay);c.lineTo(6,20);c.lineTo(-6,20);c.lineTo(-6,2+ay);c.lineTo(-15,2+ay);c.closePath();c.fill();c.stroke() + c.restore() + if(fp>0&&fp<1){const e=1-(1-fp)**2;file(c,L(178,192,fp)+22*sin(PI*fp),L(100,52,e),fp*PI*1.5,L(1,.4,fp))} + if(gulp){const q=(t-.5625)/.1875;c.fillStyle=SP;c.lineWidth=3.5;for(const[x,y,o]of[[128,26,0],[240,104,.25],[150,100,.45]]){const r=sin(PI*min(1,max(0,q*1.4-o)));if(r>.1)spark(c,x,y,12*r)}} + const ns=t<.3125?1:t>=.75?ease((t-.75)/.15):0 + ds(c,22,12,TOP,()=>{c.moveTo(54,206);c.quadraticCurveTo(58,236,84,216)}) + ds(c,22,12,TOP,()=>{c.moveTo(154,204);c.quadraticCurveTo(L(160,196,up),L(236,190,up),hx,hy+4)}) + if(ns>0)file(c,hx-16*(1-up),hy-14,up*.4,ns) + c.fillStyle=SKIN;c.lineWidth=5;for(const[x,y]of[[84,214],[hx,hy]])c.beginPath(),c.ellipse(x,y,11,10,0,0,T),c.fill(),c.stroke() +} diff --git a/gen/uianime/wallet/shake.js b/gen/uianime/wallet/shake.js new file mode 100644 index 0000000..d01a613 --- /dev/null +++ b/gen/uianime/wallet/shake.js @@ -0,0 +1,55 @@ +// green-haired girl in a beret shaking her empty wallet upside down with teary eyes, only dust puffs and specks falling out +const{sin,cos,PI,max,min}=Math,T=2*PI +export const frames=12,delay=80 +const SKIN='#ffe3d1',HAIR='#8ce99a',HD='#2f9e44',HL='#ebfbee',EYE='#f76707',ED='#c2410c',BR='#c2255c',SW='#d0bfff',SWD='#9775fa',BL='#ffa8a8',WA='#a5d8ff',WL='#e8590c',WLD='#b35400',DU='#ced4da',Z=.8 +const puff=(c,x,y,r)=>{c.beginPath();for(const[a,b,s]of[[-.8,0,.7],[0,-.5,.8],[.8,0,.7],[0,.3,.75]])c.moveTo(x+a*r+s*r,y+b*r),c.arc(x+a*r,y+b*r,s*r,0,T);c.lineWidth=7;c.strokeStyle='#111';c.stroke();c.fillStyle=DU;c.fill()} +export default(c,t)=>{ + const w=sin(4*T*t),L=v=>c.lineWidth=v/Z,wb=sin(2*T*t) + const head=f=>{c.save();c.translate(106,124);c.scale(Z,Z);c.translate(-128,-128);f();c.restore()} + head(()=>{ + L(6);c.fillStyle=HD;c.beginPath();c.moveTo(128,34);c.bezierCurveTo(198,34,212,100,204,160);c.quadraticCurveTo(198,180,178,176);c.lineTo(78,176);c.quadraticCurveTo(58,180,52,160);c.bezierCurveTo(44,100,58,34,128,34);c.fill();c.stroke() + c.fillStyle=SW;c.beginPath();c.moveTo(100,190);c.quadraticCurveTo(56,196,44,320);c.lineTo(212,320);c.quadraticCurveTo(200,196,156,190);c.closePath();c.fill();c.stroke() + c.strokeStyle=SWD;L(4);for(let x=70;x<200;x+=20)c.beginPath(),c.moveTo(x,236),c.lineTo(x+(x-128)*.08,320),c.stroke();c.strokeStyle='#111' + c.fillStyle=SW;L(6);c.beginPath();c.roundRect(96,184,64,22,11);c.fill();c.stroke() + c.fillStyle=SKIN;c.beginPath();c.moveTo(116,166);c.lineTo(116,190);c.quadraticCurveTo(128,198,140,190);c.lineTo(140,166);c.fill();L(5);c.beginPath();c.moveTo(116,166);c.lineTo(116,188);c.moveTo(140,166);c.lineTo(140,188);c.stroke() + L(6);c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + for(const[x,d]of[[103,-1],[153,1]]){ + c.fillStyle='#fff';c.beginPath();c.ellipse(x,140,14,17,0,0,T);c.fill() + c.save();c.beginPath();c.ellipse(x,142,11.5,15,0,0,T);c.clip();c.fillStyle=EYE;c.fill();c.fillStyle=ED;c.beginPath();c.ellipse(x,132,13,10,0,0,T);c.fill() + c.fillStyle='#111';c.beginPath();c.ellipse(x+4,136,5,6.5,0,0,T);c.fill() + c.fillStyle=WA;c.beginPath();c.moveTo(x-16,150+wb);c.quadraticCurveTo(x,145-wb,x+16,150+wb);c.lineTo(x+16,160);c.lineTo(x-16,160);c.fill();c.restore() + L(2.5);c.beginPath();c.ellipse(x,142,11.5,15,0,0,T);c.stroke() + c.fillStyle='#fff';c.beginPath();c.arc(x,131,4.5,0,T);c.fill();c.beginPath();c.arc(x+7,146,2.5,0,T);c.fill();c.beginPath();c.arc(x-5,151,2,0,T);c.fill() + L(6);c.beginPath();c.moveTo(x-16,134);c.quadraticCurveTo(x,120,x+16,134);c.moveTo(x+d*15,133);c.lineTo(x+d*21,128);c.stroke() + } + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*42,163,12,6,0,0,T),c.fill() + L(2.5);for(const d of[-1,1])for(const k of[-5,0,5])c.beginPath(),c.moveTo(128+d*42+k-2,166),c.lineTo(128+d*42+k+2,160),c.stroke() + L(3.5);c.beginPath();c.moveTo(116,174);for(let k=1;k<=6;k++)c.lineTo(116+k*4,174+(k%2?-3:2));c.stroke() + L(6);c.fillStyle=HAIR;c.beginPath();c.moveTo(66,158) + c.bezierCurveTo(52,74,88,36,128,36);c.bezierCurveTo(168,36,204,74,190,158) + c.quadraticCurveTo(186,124,180,106);c.quadraticCurveTo(172,100,166,110);c.quadraticCurveTo(160,96,150,92);c.quadraticCurveTo(144,104,136,108) + c.quadraticCurveTo(130,96,118,94);c.quadraticCurveTo(112,104,102,108);c.quadraticCurveTo(96,98,86,100);c.quadraticCurveTo(70,124,66,158);c.closePath();c.fill();c.stroke() + c.strokeStyle=HL;L(5);for(const[a,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,56,PI*a,PI*e),c.stroke() + c.strokeStyle='#111';L(4.5);c.beginPath();c.moveTo(90,116);c.lineTo(114,110);c.moveTo(166,116);c.lineTo(142,110);c.stroke() + c.fillStyle=BR;L(6);c.beginPath();c.moveTo(60,72);c.bezierCurveTo(50,30,110,10,150,22);c.bezierCurveTo(196,34,210,58,196,74);c.quadraticCurveTo(128,54,60,72);c.fill();c.stroke() + c.beginPath();c.moveTo(124,16);c.lineTo(128,4);c.stroke() + c.fillStyle=SWD;L(4);c.beginPath();c.ellipse(80,86,7,7,0,0,T);c.fill();c.stroke() + c.fillStyle=WA;L(4);c.beginPath();c.moveTo(56,110);c.quadraticCurveTo(46,124,56,131);c.quadraticCurveTo(66,124,56,110);c.fill();c.stroke() + }) + const hx=178+3*w,hy=80 + for(const[l,s]of[[30,'#111'],[19,SW]])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),c.moveTo(160,262),c.quadraticCurveTo(184,180,hx-2,hy+30),c.stroke() + c.strokeStyle='#111' + c.fillStyle=DU;c.lineWidth=3 + for(let k=0;k<6;k++){const p=(t*2+k/6)%1,x=206+16*sin(k*2.1)+6*sin(T*p+k),y=116+120*p;c.beginPath();c.arc(x,y,2.5+1.5*(k%2),0,T);c.fill();c.stroke()} + for(const o of[0,.5]){const p=(t*2+o)%1;const r=13*sin(PI*p);if(r>3)puff(c,204+(o?12:-8)+8*p,116+56*p,r)} + c.save();c.translate(hx,hy);c.rotate(.2*w) + c.lineWidth=6;c.fillStyle=WLD;c.beginPath();c.roundRect(-4,-28,64,64,9);c.fill();c.stroke() + c.fillStyle='#343a40';c.beginPath();c.moveTo(0,16);c.lineTo(56,16);c.quadraticCurveTo(54,32,28,32);c.quadraticCurveTo(2,32,0,16);c.fill();c.lineWidth=4;c.stroke() + c.lineWidth=6;c.fillStyle=WL;c.beginPath();c.moveTo(-4,-19);c.quadraticCurveTo(-4,-28,5,-28);c.lineTo(51,-28);c.quadraticCurveTo(60,-28,60,-19);c.lineTo(60,10);c.quadraticCurveTo(28,24,-4,10);c.closePath();c.fill();c.stroke() + c.strokeStyle='#ffd8a8';c.lineWidth=2.5;c.setLineDash([5,5]);c.beginPath();c.moveTo(3,-21);c.lineTo(53,-21);c.lineTo(53,4);c.quadraticCurveTo(28,15,3,4);c.closePath();c.stroke();c.setLineDash([]) + c.strokeStyle='#111';c.fillStyle='#ffd43b';c.lineWidth=4;c.beginPath();c.roundRect(20,-34,16,12,4);c.fill();c.stroke() + c.restore() + c.lineWidth=5;c.fillStyle=SKIN;c.beginPath();c.ellipse(hx-2,hy+4,12,15,.2,0,T);c.fill();c.stroke() + for(const[l,s]of[[7,'#111'],[2.5,'#fff']]){c.lineWidth=l;c.strokeStyle=s;for(const d of[-1,1])c.beginPath(),c.arc(hx+28,hy,46,d<0?PI*.82:-PI*.18,d<0?PI*1.05:PI*.05),c.stroke()} + c.strokeStyle='#111' +} diff --git a/gen/uianime/warning/whistle.js b/gen/uianime/warning/whistle.js new file mode 100644 index 0000000..2d177b1 --- /dev/null +++ b/gen/uianime/warning/whistle.js @@ -0,0 +1,57 @@ +// aqua-haired crossing guard in a cap blowing her whistle with puffed cheeks and holding up a stop palm, a warning sign flashing beside her +const{sin,cos,PI,max,min}=Math,T=2*PI +export const frames=12,delay=80 +const SKIN='#ffe3d1',HAIR='#66d9e8',HD='#1098ad',EYE='#7950f2',ED='#4c2fa8',SH='#364fc7',VS='#ff922b',CAP='#364fc7',GD='#ffd43b',BL='#ffa8a8',WY='#ffd43b',WO='#ff922b',WH='#fcc419',Z=.76 +const eye=(c,L,x,y,d)=>{ + c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill() + c.save();c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.clip();c.fillStyle=EYE;c.fill();c.fillStyle=ED;c.beginPath();c.ellipse(x,y-8,13,10,0,0,T);c.fill();c.restore() + L(2.5);c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.stroke() + c.fillStyle='#111';c.beginPath();c.ellipse(x,y+3,5.5,7.5,0,0,T);c.fill() + c.fillStyle='#fff';c.beginPath();c.arc(x-4,y-5,4.5,0,T);c.fill();c.beginPath();c.arc(x+5,y+8,2,0,T);c.fill() + L(6);c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke() +} +export default(c,t,i)=>{ + const b=i%6<3,p=b?[1,1.15,1][i%6]:0,L=v=>c.lineWidth=v/Z,fl=i<6 + const head=f=>{c.save();c.translate(130,118);c.scale(Z,Z);c.translate(-128,-128);f();c.restore()} + head(()=>{ + L(6);c.fillStyle=HD;c.beginPath();c.moveTo(128,34);c.bezierCurveTo(198,34,212,100,204,160);c.quadraticCurveTo(198,180,178,176);c.lineTo(78,176);c.quadraticCurveTo(58,180,52,160);c.bezierCurveTo(44,100,58,34,128,34);c.fill();c.stroke() + c.fillStyle=SH;c.beginPath();c.moveTo(100,190);c.quadraticCurveTo(56,196,44,320);c.lineTo(212,320);c.quadraticCurveTo(200,196,156,190);c.closePath();c.fill();c.stroke() + c.fillStyle=VS;for(const d of[-1,1])c.beginPath(),c.moveTo(128+d*18,196),c.lineTo(128+d*24,320),c.lineTo(128+d*86,320),c.quadraticCurveTo(128+d*76,206,128+d*36,190),c.closePath(),c.fill(),c.stroke() + c.fillStyle='#fff';L(4);for(const d of[-1,1])c.beginPath(),c.moveTo(128+d*23,250),c.lineTo(128+d*80,250),c.lineTo(128+d*82,266),c.lineTo(128+d*24,266),c.closePath(),c.fill(),c.stroke() + c.fillStyle=SKIN;c.beginPath();c.moveTo(116,166);c.lineTo(116,194);c.lineTo(128,206);c.lineTo(140,194);c.lineTo(140,166);c.fill();L(5);c.beginPath();c.moveTo(116,166);c.lineTo(116,192);c.moveTo(140,166);c.lineTo(140,192);c.stroke() + L(6);c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + if(b)for(const d of[-1,1])c.beginPath(),c.arc(128+d*44,160,15,d<0?PI*.5:-PI*.5,d<0?PI*1.5:PI*.5),c.fill(),c.stroke() + eye(c,L,103,138,-1);eye(c,L,153,138,1) + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*42,161,b?14:11,b?7:5.5,0,0,T),c.fill() + L(2.5);for(const d of[-1,1])for(const k of[-5,0,5])c.beginPath(),c.moveTo(128+d*42+k-2,164),c.lineTo(128+d*42+k+2,158),c.stroke() + c.strokeStyle='#868e96';L(3);c.beginPath();c.moveTo(150,182);c.quadraticCurveTo(150,206,128,206);c.stroke();c.strokeStyle='#111' + c.save();c.translate(128,170);c.rotate(.35) + c.fillStyle=WH;L(4.5);c.beginPath();c.roundRect(-6,-7,30,14,4);c.fill();c.stroke();c.beginPath();c.arc(28,8,13,0,T);c.fill();c.stroke() + c.fillStyle='#111';c.beginPath();c.arc(28,8,4,0,T);c.fill() + c.restore() + L(6);c.fillStyle=HAIR;c.beginPath();c.moveTo(66,156) + c.bezierCurveTo(52,74,88,36,128,36);c.bezierCurveTo(168,36,204,74,190,156) + c.quadraticCurveTo(186,124,180,106);c.quadraticCurveTo(172,104,166,112);c.quadraticCurveTo(160,98,150,96);c.quadraticCurveTo(144,106,134,110) + c.quadraticCurveTo(128,98,116,96);c.quadraticCurveTo(110,106,100,110);c.quadraticCurveTo(94,100,84,104);c.quadraticCurveTo(70,124,66,156);c.closePath();c.fill();c.stroke() + c.strokeStyle='#111';L(5);c.beginPath();c.moveTo(88,108);c.lineTo(116,116);c.moveTo(168,108);c.lineTo(140,116);c.stroke() + c.fillStyle=CAP;L(6);c.beginPath();c.moveTo(66,86);c.bezierCurveTo(56,30,96,14,128,14);c.bezierCurveTo(160,14,200,30,190,86);c.quadraticCurveTo(128,70,66,86);c.fill();c.stroke() + c.fillStyle='#212529';c.beginPath();c.moveTo(62,88);c.quadraticCurveTo(128,66,194,88);c.quadraticCurveTo(200,100,190,100);c.quadraticCurveTo(128,82,66,100);c.quadraticCurveTo(56,100,62,88);c.fill();c.stroke() + c.strokeStyle='#fff';L(4);c.beginPath();c.moveTo(80,74);c.quadraticCurveTo(128,62,176,74);c.stroke();c.strokeStyle='#111' + c.fillStyle=GD;L(4.5);c.beginPath();for(let k=0;k<10;k++){const r=k%2?7:15,a=k*PI/5-PI/2;c.lineTo(128+cos(a)*r,46+sin(a)*r)}c.closePath();c.fill();c.stroke() + }) + if(b)for(const[w,s]of[[9,'#111'],[4,'#fff']]){c.lineWidth=w;c.strokeStyle=s;for(const a of[-.35,.15,.65]){const r0=34*p,x=150+cos(a)*r0,y=150+sin(a)*r0;c.beginPath();c.moveTo(x,y);c.lineTo(x+cos(a)*16*p,y+sin(a)*16*p);c.stroke()}} + c.strokeStyle='#111' + const hx=46,hy=120,ps=b?1.1:1 + for(const[w,s]of[[30,'#111'],[19,SH]])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.moveTo(84,230),c.quadraticCurveTo(48,214,hx+2,hy+38),c.stroke() + c.strokeStyle='#111';c.save();c.translate(hx,hy);c.scale(ps,ps) + c.lineWidth=5;c.fillStyle=SKIN + for(const[x,y,h]of[[-15,-22,15],[-5,-27,17],[5,-27,17],[15,-22,15]])c.beginPath(),c.roundRect(x-5,y-h,10,h+14,5),c.fill(),c.stroke() + c.beginPath();c.ellipse(22,8,6,12,-.7,0,T);c.fill();c.stroke() + c.beginPath();c.roundRect(-20,-14,40,36,13);c.fill();c.stroke() + c.fillStyle=SH;c.beginPath();c.roundRect(-18,22,36,14,5);c.fill();c.stroke() + c.restore() + c.save();c.translate(202,64);c.rotate(.1*sin(T*t*2));const sc=b?1.02:.94;c.scale(sc,sc) + c.lineWidth=7;c.fillStyle=fl?WY:WO;c.beginPath();c.moveTo(0,-36);c.quadraticCurveTo(4,-42,8,-34);c.lineTo(38,22);c.quadraticCurveTo(40,30,32,30);c.lineTo(-32,30);c.quadraticCurveTo(-40,30,-38,22);c.lineTo(-8,-34);c.quadraticCurveTo(-4,-42,0,-36);c.closePath();c.fill();c.stroke() + c.lineWidth=8;c.beginPath();c.moveTo(0,-14);c.lineTo(0,6);c.stroke();c.fillStyle='#111';c.beginPath();c.arc(0,18,5,0,T);c.fill() + c.restore() +} diff --git a/gen/uianime/welcome/bow.js b/gen/uianime/welcome/bow.js new file mode 100644 index 0000000..7276127 --- /dev/null +++ b/gen/uianime/welcome/bow.js @@ -0,0 +1,52 @@ +// lilac-haired shop girl in a frilly headband bowing politely in welcome, hands folded in front, sparkles twinkling around her +const{sin,cos,PI,min,max}=Math,T=2*PI +export const frames=12,delay=120 +const SKIN='#ffe3d1',HAIR='#da77f2',HD='#ae3ec9',HL='#f8f0fc',EYE='#20c997',ED='#087f5b',DR='#4c6ef5',BL='#ffa8a8',MO='#c92a2a',TG='#ff8fab',SP='#ffd43b' +const eye=(c,x,y,d)=>{ + c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill() + c.save();c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.clip();c.fillStyle=EYE;c.fill();c.fillStyle=ED;c.beginPath();c.ellipse(x,y-8,13,10,0,0,T);c.fill();c.restore() + c.lineWidth=2.5;c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.stroke() + c.fillStyle='#111';c.beginPath();c.ellipse(x,y+3,5.5,7.5,0,0,T);c.fill() + c.fillStyle='#fff';c.beginPath();c.arc(x-4,y-5,4.5,0,T);c.fill();c.beginPath();c.arc(x+5,y+8,2,0,T);c.fill() + c.lineWidth=6;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke() +} +const spark=(c,x,y,r)=>{c.beginPath();c.moveTo(x,y-r);for(const[a,b]of[[1,0],[0,1],[-1,0],[0,-1]])c.quadraticCurveTo(x+(a+b)*r*.2,y+(b-a)*r*.2,x+a*r,y+b*r);c.fill();c.stroke()} +export default(c,t)=>{ + const b=min(1,max(0,1.6*sin(PI*t)**2-.3)),dn=b>.4 + const head=(f,q=1)=>{c.save();c.translate(128,q?36+40*b:186+40*b);c.scale(1,q?1+.12*b:1-.38*b);c.translate(-128,q?-36:-186);f();c.restore()} + head(()=>{c.lineWidth=6;c.fillStyle=HD;c.beginPath();c.moveTo(128,34);c.bezierCurveTo(200,34,214,96,206,150);c.quadraticCurveTo(212,200,198,226);c.lineTo(58,226);c.quadraticCurveTo(44,200,50,150);c.bezierCurveTo(42,96,56,34,128,34);c.fill();c.stroke()}) + c.save();c.translate(0,8*b) + c.lineWidth=6;c.fillStyle=DR;c.beginPath();c.moveTo(100,190);c.quadraticCurveTo(62,198,54,252);c.lineTo(202,252);c.quadraticCurveTo(194,198,156,190);c.closePath();c.fill();c.stroke() + c.fillStyle='#fff';c.lineWidth=5;for(const d of[-1,1])c.beginPath(),c.moveTo(128,206),c.quadraticCurveTo(128+d*12,212,128+d*30,196),c.lineTo(128+d*14,188),c.closePath(),c.fill(),c.stroke() + c.fillStyle=SKIN;c.beginPath();c.moveTo(116,166);c.lineTo(116,192);c.lineTo(128,204);c.lineTo(140,192);c.lineTo(140,166);c.fill();c.beginPath();c.moveTo(116,166);c.lineTo(116,190);c.moveTo(140,166);c.lineTo(140,190);c.stroke() + c.fillStyle='#ff6b6b';c.lineWidth=4;c.beginPath();c.arc(128,204,6,0,T);c.fill();c.stroke() + for(const d of[-1,1]){ + for(const[w,s]of[[30,'#111'],[19,DR]])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.moveTo(128+d*58,206),c.quadraticCurveTo(128+d*52,236,128+d*14,238),c.stroke() + } + c.strokeStyle='#111';c.lineWidth=5;c.fillStyle=SKIN;c.beginPath();c.ellipse(120,240,15,11,.3,0,T);c.fill();c.stroke();c.beginPath();c.ellipse(136,236,15,11,-.3,0,T);c.fill();c.stroke() + c.lineWidth=2.5;c.beginPath();for(const k of[-5,1])c.moveTo(130+k,230),c.lineTo(134+k,240);c.stroke() + c.restore() + head(()=>{ + c.lineWidth=6;c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke() + if(dn){c.lineWidth=5;for(const x of[103,153])c.beginPath(),c.arc(x,132,13,PI*.15,PI*.85),c.stroke()}else eye(c,103,140,-1),eye(c,153,140,1) + c.lineWidth=2.5;c.beginPath();c.moveTo(128,156);c.lineTo(127,159);c.stroke() + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*42,161,12,6,0,0,T),c.fill() + c.lineWidth=2.5;for(const d of[-1,1])for(const k of[-5,0,5])c.beginPath(),c.moveTo(128+d*42+k-2,164),c.lineTo(128+d*42+k+2,158),c.stroke() + if(dn){c.lineWidth=3.5;c.beginPath();c.arc(128,164,7,.15*PI,.85*PI);c.stroke()} + else{c.lineWidth=3.5;c.fillStyle=MO;c.beginPath();c.moveTo(117,165);c.quadraticCurveTo(128,186,139,165);c.closePath();c.fill();c.stroke();c.save();c.clip();c.fillStyle=TG;c.beginPath();c.ellipse(128,180,7,5,0,0,T);c.fill();c.restore()} + },0) + head(()=>{ + c.lineWidth=6;c.fillStyle=HAIR;c.beginPath();c.moveTo(66,150) + c.bezierCurveTo(52,74,88,36,128,36);c.bezierCurveTo(168,36,204,74,190,150) + c.quadraticCurveTo(188,118,180,104);c.quadraticCurveTo(172,100,166,110);c.quadraticCurveTo(160,96,148,92);c.quadraticCurveTo(142,104,132,108) + c.quadraticCurveTo(126,96,114,92);c.quadraticCurveTo(108,104,98,108);c.quadraticCurveTo(92,96,82,100) + c.quadraticCurveTo(70,120,66,150);c.closePath();c.fill();c.stroke() + c.strokeStyle=HL;c.lineWidth=5;for(const[a,e]of[[1.24,1.34],[1.44,1.52],[1.66,1.76]])c.beginPath(),c.arc(128,104,56,PI*a,PI*e),c.stroke() + c.strokeStyle='#111';c.fillStyle='#fff';c.lineWidth=4 + for(let k=0;k<7;k++){const a=PI*(1.2+k*.1);c.beginPath();c.arc(128+66*cos(a),110+66*sin(a),9,0,T);c.fill();c.stroke()} + for(const[w,s]of[[16,'#111'],[9,'#fff']])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.arc(128,110,58,PI*1.2,PI*1.8),c.stroke() + c.strokeStyle='#111' + }) + c.fillStyle=SP;c.lineWidth=4 + for(const[x,y,o,r]of[[28,74,0,22],[228,96,.3,20],[34,170,.55,17],[224,184,.8,17],[206,30,.15,14]]){const s=sin(T*(t+o));if(s>0)spark(c,x,y,r*s)} +} diff --git a/gen/uicolor/403/stop.js b/gen/uicolor/403/stop.js new file mode 100644 index 0000000..c06dd2d --- /dev/null +++ b/gen/uicolor/403/stop.js @@ -0,0 +1,24 @@ +// red stop sign on a pole with a big white hand wagging no-no inside it, stern little face on the palm +const{sin,cos,PI}=Math,T=2*PI +export const frames=16,delay=80 +const RD='#ff6b6b',PL='#adb5bd',BL='#ffa8a8' +const oct=(c,r)=>{c.beginPath();for(let k=0;k<8;k++){const a=k*PI/4+PI/8;c.lineTo(128+cos(a)*r,104+sin(a)*r)}c.closePath()} +const F=[[-22.5,-128],[-7.5,-136],[7.5,-132],[22.5,-120]] +const parts=[c=>c.roundRect(-30,-82,60,76,20),c=>c.roundRect(-20,-30,40,34,10),...F.map(([x,y])=>c=>c.roundRect(x-7,y,14,-50-y,7)),c=>{c.save();c.translate(-26,-42);c.rotate(-.75);c.roundRect(-7,-44,14,48,7);c.restore()}] +export default(c,t)=>{ + const A=.26*sin(t*T*2),v=cos(t*T*2) + c.translate(128,244);c.rotate(.025*sin(t*T*2-.6));c.translate(-128,-244) + c.fillStyle=PL;c.beginPath();c.roundRect(116,176,24,66,6);c.fill();c.stroke() + oct(c,92);c.fillStyle=RD;c.fill();c.stroke() + c.strokeStyle='#fff';c.lineWidth=6;oct(c,79);c.stroke() + if(v*v>.3)for(const r of[132,114]){const a=-PI/2+A-v*.12;for(const[w,s]of[[10,'#111'],[4,'#fff']])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.arc(128,172,r*.88,a-(v>0?.2:-.05),a+(v>0?.05:.2)),c.stroke()} + c.save();c.translate(128,172);c.rotate(A);c.scale(.88,.88) + c.strokeStyle='#111';c.lineWidth=14;for(const p of parts)c.beginPath(),p(c),c.stroke() + c.fillStyle='#fff';for(const p of parts)c.beginPath(),p(c),c.fill() + c.lineWidth=4;c.beginPath();for(const x of[-15,0,15])c.moveTo(x,-82),c.lineTo(x,-70);c.stroke() + c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.arc(d*12,-50,5,0,T),c.fill() + c.lineWidth=4.5;for(const d of[-1,1])c.beginPath(),c.moveTo(d*5,-58),c.lineTo(d*20,-64),c.stroke() + c.beginPath();c.arc(0,-24,8,1.2*PI,1.8*PI);c.stroke() + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(d*21,-38,6,3.5,0,0,T),c.fill() + c.restore() +} diff --git a/gen/uicolor/404/ghost.js b/gen/uicolor/404/ghost.js new file mode 100644 index 0000000..ffff5ba --- /dev/null +++ b/gen/uicolor/404/ghost.js @@ -0,0 +1,30 @@ +// a shy little ghost rises out of a hole torn in a page, peeks left and right, then sinks back down +const{sin,cos,PI}=Math,T=2*PI +export const frames=24,delay=70 +const PG='#e7f5ff',LN='#a5d8ff',HO='#5f3dc4',HD='#3b2a8a',GH='#fff',GS='#e5dbff',BL='#ffa8a8' +const HX=128,HY=170,J=[1,.84,.97,.8,1,.88,.78,1,.86,.95,.8,1,.9,.8,.98,.84] +const hole=(c,s=1)=>{J.forEach((j,k)=>{const a=k/J.length*T;c.lineTo(HX+cos(a)*64*j*s,HY+sin(a)*32*j*s)});c.closePath()} +const ss=x=>x<=0?0:x>=1?1:x*x*(3-2*x) +export default(c,t)=>{ + const u=ss(t/.22)-ss((t-.8)/.2),lk=ss((t-.28)/.1)-2*ss((t-.48)/.1)+ss((t-.68)/.1),gy=HY+70-170*u,ln=-.16*lk + c.save();c.translate(128,150);c.rotate(-.05);c.translate(-128,-150) + c.fillStyle=PG;c.beginPath();c.moveTo(42,62);c.lineTo(184,62);c.lineTo(214,92);c.lineTo(214,238);c.lineTo(42,238);c.closePath();c.fill();c.stroke() + c.fillStyle='#fff';c.beginPath();c.moveTo(184,62);c.lineTo(184,92);c.lineTo(214,92);c.closePath();c.fill();c.lineWidth=5;c.stroke() + c.strokeStyle=LN;c.lineWidth=8;for(const[y,a,b]of[[86,62,160],[106,62,190],[126,62,140],[220,70,186]])c.beginPath(),c.moveTo(a,y),c.lineTo(b,y),c.stroke() + c.restore() + c.fillStyle='#fff';c.beginPath();hole(c,1.12);c.fill();c.lineWidth=4;c.strokeStyle='#111';c.stroke() + c.fillStyle=HO;c.beginPath();hole(c);c.fill();c.lineWidth=6;c.stroke() + c.fillStyle=HD;c.beginPath();c.ellipse(HX,HY+6,44,18,0,0,T);c.fill() + c.save();c.beginPath();c.rect(0,0,256,HY);hole(c);c.clip() + c.translate(HX,HY);c.rotate(ln);c.translate(0,gy-HY);c.scale(.92,.84) + const body=()=>{c.beginPath();c.moveTo(-40,0);c.arc(0,0,40,PI,0);c.lineTo(44,124);for(let k=0;k<4;k++){const x0=44-k*22,w=4*sin(T*t*2+k*1.6);c.quadraticCurveTo(x0-11,136+w,x0-22,124)}c.closePath()} + c.fillStyle=GH;body();c.fill();c.save();c.clip();c.fillStyle=GS;c.beginPath();c.ellipse(-12,30,50,120,0,0,T);c.rect(80,-60,-200,240);c.fill('evenodd');c.restore() + body();c.lineWidth=7;c.strokeStyle='#111';c.stroke() + for(const d of[-1,1]){c.fillStyle=GH;c.beginPath();c.ellipse(d*44,44-lk*d*8,10,14,d*.5,0,T);c.fill();c.lineWidth=5;c.stroke()} + const ex=lk*7 + c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.ellipse(d*14+ex,-2,5.5,7.5,0,0,T),c.fill() + c.fillStyle='#fff';for(const d of[-1,1])c.beginPath(),c.arc(d*14+ex-2,-5,2.2,0,T),c.fill() + c.fillStyle='#111';c.beginPath();c.ellipse(ex,14,4,5,0,0,T);c.fill() + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(d*26+ex*.6,10,7,4,0,0,T),c.fill() + c.restore() +} diff --git a/gen/uicolor/404/map.js b/gen/uicolor/404/map.js new file mode 100644 index 0000000..f40c7ef --- /dev/null +++ b/gen/uicolor/404/map.js @@ -0,0 +1,31 @@ +// a folded paper map unfolded, a dotted trail marching from a bouncing red pin to a big wobbly "?" where the road runs out +const{sin,PI}=Math,T=2*PI +export const frames=16,delay=80 +const P1='#fff4e6',P2='#ffe8cc',WA='#a5d8ff',LA='#c3fae8',TR='#69db7c',PN='#fa5252',Q='#b197fc' +const X=[16,92,166,240],TOP=[60,46,60,46],BOT=[214,228,214,228] +const map=c=>{c.beginPath();X.forEach((x,k)=>c.lineTo(x,TOP[k]));for(let k=3;k>=0;k--)c.lineTo(X[k],BOT[k]);c.closePath()} +const pnl=(c,k)=>{c.beginPath();c.moveTo(X[k],TOP[k]);c.lineTo(X[k+1],TOP[k+1]);c.lineTo(X[k+1],BOT[k+1]);c.lineTo(X[k],BOT[k]);c.closePath()} +export default(c,t)=>{ + const ph=(t*2)%1,j=4*ph*(1-ph),py=192-30*j,sq=ph<.1?1-(.1-ph)*2:1 + c.fillStyle=P1;map(c);c.fill();c.fillStyle=P2;pnl(c,1);c.fill() + c.save();map(c);c.clip() + c.fillStyle=LA;c.beginPath();c.ellipse(204,214,70,40,0,0,T);c.fill();c.beginPath();c.ellipse(30,64,50,34,0,0,T);c.fill() + c.fillStyle=WA;c.beginPath();c.ellipse(70,92,34,20,-.2,0,T);c.fill() + c.strokeStyle=WA;c.lineWidth=10;c.beginPath();c.moveTo(96,96);c.bezierCurveTo(130,110,110,150,150,160);c.bezierCurveTo(170,166,160,200,190,236);c.stroke() + c.fillStyle='rgba(200,110,20,.1)';pnl(c,1);c.fill() + c.restore() + c.lineWidth=7;c.strokeStyle='#111';map(c);c.stroke() + c.lineWidth=4;for(const k of[1,2])c.beginPath(),c.moveTo(X[k],TOP[k]),c.lineTo(X[k],BOT[k]),c.stroke() + for(const[x,y]of[[110,68],[126,78],[30,168]]){c.fillStyle=TR;c.lineWidth=4;c.beginPath();c.arc(x,y,9,0,T);c.fill();c.stroke()} + c.lineWidth=8;c.setLineDash([.1,14.9]);c.lineDashOffset=-t*30;c.beginPath();c.moveTo(56,196);c.bezierCurveTo(96,206,94,150,128,150);c.bezierCurveTo(156,150,146,198,172,194);c.stroke();c.setLineDash([]) + c.save();c.translate(182,192);c.rotate(.14*sin(T*t)) + for(const[w,s]of[[30,'#111'],[17,Q]])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.moveTo(-24,-82),c.bezierCurveTo(-24,-116,24,-116,24,-84),c.bezierCurveTo(24,-60,0,-62,0,-34),c.stroke() + c.strokeStyle='#fff';c.lineWidth=5;c.beginPath();c.moveTo(-20,-90);c.quadraticCurveTo(-16,-102,-6,-104);c.stroke() + c.strokeStyle='#111';c.lineWidth=6;c.fillStyle=Q;c.beginPath();c.arc(0,-6,12,0,T);c.fill();c.stroke() + c.restore() + c.fillStyle='rgba(0,0,0,.15)';c.beginPath();c.ellipse(56,196,14*(1-j*.4),5*(1-j*.4),0,0,T);c.fill() + c.save();c.translate(56,py);c.scale(2-sq,sq) + c.fillStyle=PN;c.lineWidth=6;c.beginPath();c.moveTo(0,0);c.bezierCurveTo(-4,-12,-20,-26,-20,-42);c.arc(0,-42,20,PI,0);c.bezierCurveTo(20,-26,4,-12,0,0);c.fill();c.stroke() + c.fillStyle='#fff';c.beginPath();c.arc(0,-42,8,0,T);c.fill();c.lineWidth=4;c.stroke() + c.restore() +} diff --git a/gen/uicolor/404/space.js b/gen/uicolor/404/space.js new file mode 100644 index 0000000..b90b51e --- /dev/null +++ b/gen/uicolor/404/space.js @@ -0,0 +1,27 @@ +// "404" adrift in outer space: the 0 is a spinning pink ringed planet with a little smile, the 4s bob gently up and down, stars twinkling all around +const{sin,cos,PI}=Math,T=2*PI +export const frames=16,delay=90 +const A='#4dabf7',B='#b197fc',PL='#f783ac',PB='#faa2c1',PD='#e64980',RG='#ffd43b',BL='#ff8787' +const dig=(c,f,col)=>{for(const[w,s]of[[32,'#111'],[19,col]])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),f(),c.stroke();c.strokeStyle='#fff';c.lineWidth=5;c.beginPath();c.moveTo(-17,-30);c.lineTo(-19,-14);c.stroke();c.lineWidth=7;c.strokeStyle='#111'} +const four=c=>()=>{c.moveTo(-14,-40);c.lineTo(-20,10);c.lineTo(24,10);c.moveTo(12,-40);c.lineTo(12,40)} +const spark=(c,x,y,s)=>{c.lineWidth=4;c.fillStyle='#fff';c.beginPath();c.moveTo(x,y-s);for(const[px,py,qx,qy]of[[s,0,s*.2,-s*.2],[0,s,s*.2,s*.2],[-s,0,-s*.2,s*.2],[0,-s,-s*.2,-s*.2]])c.quadraticCurveTo(x+qx,y+qy,x+px,y+py);c.fill();c.stroke()} +export default(c,t)=>{ + for(const[x,y,o]of[[26,34,0],[128,24,.5],[226,44,.25],[30,222,.75],[222,224,.4],[128,232,.1]])spark(c,x,y,4+6*(1+sin((t+o)*T))/2) + c.lineWidth=7 + const py=128+Math.round(4*sin(T*t+1)),tl=-.26 + for(const[x,ph,col]of[[44,0,A],[208,PI,B]]){c.save();c.translate(x,128+Math.round(9*sin(T*t+ph)));dig(c,four(c),col);c.restore()} + const ring=(a,b)=>{c.save();c.translate(128,py);c.rotate(tl);for(const[w,s]of[[22,'#111'],[10,RG]])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.ellipse(0,0,66,15,0,a,b),c.stroke();c.restore();c.strokeStyle='#111';c.lineWidth=7} + ring(PI,T) + c.fillStyle=PL;c.beginPath();c.arc(128,py,42,0,T);c.fill() + c.save();c.clip();c.translate(128,py);c.rotate(tl) + c.fillStyle=PB;c.fillRect(-46,-31,92,10);c.fillRect(-46,20,92,8) + for(const[a,y,r]of[[0,-27,5],[2.1,27,5],[4,-26,4],[5.2,24,5],[1,-37,3.5],[3.2,35,3.5]]){const q=a+t*T,x=38*sin(q);if(cos(q)>0){c.fillStyle=PD;c.beginPath();c.ellipse(x,y,r*cos(q),r,0,0,T);c.fill()}} + c.restore() + c.beginPath();c.arc(128,py,42,0,T);c.stroke() + c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.arc(128+d*15,py-2,5.5,0,T),c.fill() + c.fillStyle='#fff';for(const d of[-1,1])c.beginPath(),c.arc(128+d*15-2,py-4,2,0,T),c.fill() + c.lineWidth=4;c.beginPath();c.arc(128,py+5,7,.15*PI,.85*PI);c.stroke() + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*26,py+9,6,3.5,0,0,T),c.fill() + c.strokeStyle='#fff';c.lineWidth=5;c.beginPath();c.arc(128,py,33,PI*1.1,PI*1.35);c.stroke();c.strokeStyle='#111' + ring(0,PI) +} diff --git a/gen/uicolor/404/ufo.js b/gen/uicolor/404/ufo.js new file mode 100644 index 0000000..06f5f04 --- /dev/null +++ b/gen/uicolor/404/ufo.js @@ -0,0 +1,32 @@ +// a little ufo hovers over a colorful "404" and beams the 0 up out of it, the 0 dangling and swaying in the tractor beam before it drops back in its slot +const{sin,cos,PI,floor}=Math,T=2*PI +export const frames=16,delay=80 +const C4='#ff6b6b',C0='#ffd43b',C4b='#4dabf7',SA='#b197fc',SD='#9775fa',GL='#d0ebff',AL='#8ce99a',BM='#ffec99',LT=['#ff6b6b','#ffd43b','#69db7c'] +const dig=(c,f,col)=>{for(const[w,s]of[[32,'#111'],[19,col]])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),f(),c.stroke();c.lineWidth=7;c.strokeStyle='#111'} +const four=(c,x,y)=>()=>{c.moveTo(x-14,y-34);c.lineTo(x-20,y+8);c.lineTo(x+24,y+8);c.moveTo(x+12,y-34);c.lineTo(x+12,y+34)} +export default(c,t,i)=>{ + const h=(1-cos(T*t))/2,e=h*h*(3-2*h),uy=Math.round(2*sin(T*t)),oy=184-58*e,ox=128+6*sin(2*T*t+1)*e,sw=.2*sin(2*T*t)*e + c.fillStyle=BM;c.beginPath();c.moveTo(106,72);c.lineTo(150,72);c.lineTo(186,226);c.ellipse(128,226,58,12,0,0,PI);c.closePath();c.fill() + c.save();c.clip();c.strokeStyle='#fff';c.lineWidth=6 + for(let k=0;k<3;k++){const q=(t*2+k/3)%1,y=226-q*150,w=22+(y-74)/152*36;c.beginPath();c.ellipse(128,y,w,7,0,0,PI);c.stroke()} + c.restore();c.lineWidth=5;c.beginPath();c.moveTo(106,72);c.lineTo(150,72);c.lineTo(186,226);c.ellipse(128,226,58,12,0,0,PI);c.closePath();c.stroke() + c.lineWidth=5;c.setLineDash([9,11]);c.beginPath();c.ellipse(128,184,23,34,0,0,T);c.stroke();c.setLineDash([]) + dig(c,four(c,44,184),C4);dig(c,four(c,198,184),C4b) + c.save();c.translate(ox,oy);c.rotate(sw);dig(c,()=>c.ellipse(0,0,23,34,0,0,T),C0) + c.strokeStyle='#fff';c.lineWidth=6;c.beginPath();c.ellipse(0,0,23,34,0,PI*1.12,PI*1.38);c.stroke();c.restore() + c.strokeStyle='#fff';c.lineWidth=6;for(const x of[30,184])c.beginPath(),c.moveTo(x,160),c.lineTo(x-2,170),c.stroke() + c.strokeStyle='#111';c.lineWidth=7 + c.save();c.translate(128,uy) + c.fillStyle=GL;c.beginPath();c.arc(0,50,35,PI,0);c.closePath();c.fill() + c.fillStyle=AL;c.beginPath();c.arc(0,34,15,0,T);c.fill();c.lineWidth=4;c.stroke() + c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.ellipse(d*6,33,4,5.5,d*.3,0,T),c.fill() + c.fillStyle='#fff';for(const d of[-1,1])c.beginPath(),c.arc(d*6-1.5,31,1.6,0,T),c.fill() + c.strokeStyle='#fff';c.lineWidth=5;c.beginPath();c.arc(0,50,26,PI*1.12,PI*1.35);c.stroke();c.strokeStyle='#111' + c.lineWidth=7;c.beginPath();c.arc(0,50,35,PI,0);c.stroke() + c.fillStyle=BM;c.beginPath();c.ellipse(0,75,24,8,0,0,T);c.fill();c.lineWidth=5;c.stroke();c.lineWidth=7 + c.fillStyle=SA;c.beginPath();c.ellipse(0,61,74,17,0,0,T);c.fill();c.stroke() + c.fillStyle=SD;c.beginPath();c.ellipse(0,59,72,7,0,0,PI);c.lineTo(-72,64);c.ellipse(0,64,72,12,0,PI,0,true);c.closePath();c.fill() + c.beginPath();c.ellipse(0,61,74,17,0,0,T);c.stroke() + c.lineWidth=4;for(let k=0;k<5;k++){const x=(k-2)*26,y=64+(k==0||k==4?-4:k==2?3:1);c.fillStyle=(k+floor(t*8))%2?'#fff':LT[k%3];c.beginPath();c.arc(x,y,6,0,T);c.fill();c.stroke()} + c.restore() +} diff --git a/gen/uicolor/500/fire.js b/gen/uicolor/500/fire.js new file mode 100644 index 0000000..0e7ce1d --- /dev/null +++ b/gen/uicolor/500/fire.js @@ -0,0 +1,35 @@ +// panicking server rack on fire, cartoon flames flickering out the top, red lights blinking while an extinguisher puffs foam at it +const{sin,cos,PI,min,max}=Math,T=2*PI +export const frames=16,delay=70 +const RK='#495057',SL='#343a40',PN='#a5d8ff',FR=['#ff6b6b','#ff922b','#ffd43b'],EX='#ff6b6b',LED='#ff6b6b',BL='#ffa8a8' +const fl=(c,x,b,w,h,s)=>{c.beginPath();c.moveTo(x-w,b);c.bezierCurveTo(x-w*1.2,b-h*.45,x+s-w*.5,b-h*.62,x+s,b-h);c.bezierCurveTo(x+s+w*.55,b-h*.62,x+w*1.2,b-h*.45,x+w,b);c.closePath()} +export default(c,t,i)=>{ + for(const[k,[x,w,h,ph]]of[[54,30,58,1],[122,32,66,3],[88,44,86,0]].entries()){ + const hh=h*(1+.1*sin(2*T*t+ph)+.06*sin(4*T*t+ph*2)),s=8*sin(T*t*2+ph+k) + for(const[j,col]of FR.entries()){const f=[1,.68,.38][j];fl(c,x+s*(1-f)*.5,112,w*f,hh*f,s*f);c.fillStyle=col;c.fill();if(!j)c.lineWidth=6,c.stroke()} + } + c.lineWidth=7;c.fillStyle=RK;c.beginPath();c.roundRect(26,100,124,138,12);c.fill();c.stroke() + c.fillStyle=PN;c.lineWidth=5;c.beginPath();c.roundRect(38,112,100,52,8);c.fill();c.stroke() + c.lineWidth=4;for(const d of[-1,1])c.beginPath(),c.moveTo(88+d*31,127),c.lineTo(88+d*13,120),c.stroke() + c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.arc(88+d*21,136,5,0,T),c.fill() + c.fillStyle='#fff';for(const d of[-1,1])c.beginPath(),c.arc(88+d*21-1.5,134.5,1.8,0,T),c.fill() + c.fillStyle='#111';c.beginPath();c.ellipse(88,153,7,6+(i%2),0,0,T);c.fill() + c.fillStyle='#4dabf7';c.lineWidth=3;c.beginPath();const sy=118+(i%4);c.moveTo(130,sy);c.quadraticCurveTo(136,sy+10,130,sy+12);c.quadraticCurveTo(124,sy+10,130,sy);c.fill();c.stroke() + for(let k=0;k<3;k++){ + const y=172+k*21;c.fillStyle=SL;c.lineWidth=4;c.beginPath();c.roundRect(38,y,100,15,4);c.fill();c.stroke() + c.strokeStyle='#868e96';c.lineWidth=3;c.beginPath();for(let x=50;x<100;x+=9)c.moveTo(x,y+4),c.lineTo(x,y+11);c.stroke();c.strokeStyle='#111' + for(const[j,x]of[112,126].entries()){const on=((i>>1)+k+j)%2;c.fillStyle=on?LED:'#862e2e';c.lineWidth=2.5;c.beginPath();c.arc(x,y+7.5,4.5,0,T);c.fill();c.stroke()} + } + for(let k=0;k<3;k++){ + const p=(t+k/3)%1,x=160-60*p,y=110-58*p+10*sin(PI*p),r=(7+17*p)*min(1,(1-p)*4) + if(r>1)c.fillStyle='#fff',c.lineWidth=5,c.beginPath(),c.arc(x,y,r,0,T),c.fill(),c.stroke() + } + for(const[w,s]of[[13,'#111'],[6,SL]])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.moveTo(212,140),c.bezierCurveTo(186,150,178,138,172,124),c.stroke() + c.strokeStyle='#111';c.lineWidth=16;c.beginPath();c.moveTo(174,126);c.lineTo(164,114);c.stroke() + c.lineWidth=7;c.fillStyle='#adb5bd';c.beginPath();c.roundRect(204,128,20,18,3);c.fill();c.stroke() + for(const[w,s]of[[12,'#111'],[5,'#adb5bd']])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.moveTo(206,124),c.lineTo(236,116),c.stroke() + c.strokeStyle='#111';c.lineWidth=7;c.fillStyle=EX;c.beginPath();c.roundRect(190,144,48,94,[22,22,8,8]);c.fill();c.stroke() + c.fillStyle='#fff';c.lineWidth=4;c.beginPath();c.roundRect(196,180,36,26,4);c.fill();c.stroke() + c.strokeStyle=EX;c.lineWidth=4;c.beginPath();c.moveTo(204,189);c.lineTo(224,189);c.moveTo(204,197);c.lineTo(218,197);c.stroke() + c.strokeStyle='#fff';c.lineWidth=5;c.beginPath();c.moveTo(198,162);c.lineTo(198,172);c.stroke() +} diff --git a/gen/uicolor/achievement/star.js b/gen/uicolor/achievement/star.js new file mode 100644 index 0000000..9bffea2 --- /dev/null +++ b/gen/uicolor/achievement/star.js @@ -0,0 +1,31 @@ +// star badge levels up, a green arrow shoots up from behind it, the badge hops and its happy star flips while sparkles burst +const{sin,cos,PI,min,max}=Math,T=2*PI +export const frames=18,delay=90 +const BG='#9775fa',BI='#b197fc',ST='#ffd43b',AR='#51cf66',RB='#ff6b6b',BL='#ffa8a8' +const back=u=>{const s=1.8;return 1+(s+1)*(u-1)**3+s*(u-1)**2},io=u=>u*u*(3-2*u),cl=u=>min(1,max(0,u)) +const sp=(c,x,y,s)=>{c.lineWidth=4;c.fillStyle='#fff';c.beginPath();c.moveTo(x,y-s);for(const[px,py,qx,qy]of[[s,0,s*.18,-s*.18],[0,s,s*.18,s*.18],[-s,0,-s*.18,s*.18],[0,-s,-s*.18,-s*.18]])c.quadraticCurveTo(x+qx,y+qy,x+px,y+py);c.fill();c.stroke()} +export default(c,t)=>{ + const o=t<.05?0:t<.35?back((t-.05)/.3):t<.75?1+.03*sin(2*T*(t-.35)/.4):t<.95?1-io((t-.75)/.2):0 + const hop=10*sin(PI*cl((t-.08)/.27)),sq=t>.03&&t<.12?1-.08*sin(PI*(t-.03)/.09):1,fl=cos(T*io(cl((t-.32)/.3))),b=(t-.32)/.35 + if(b>0&&b<1)for(let k=0;k<6;k++){const a=k*T/6-PI/2+.5,r=78+34*b;sp(c,128+cos(a)*r,146+sin(a)*r*.85,13*sin(PI*b))} + for(const[x,y,ph]of[[34,40,0],[222,64,.5]]){const s=10*max(0,sin(PI*((t*2+ph)%1)));if(s>1.5)sp(c,x,y,s)} + c.lineWidth=7;c.strokeStyle='#111' + const ay=146-116*o + c.save();c.beginPath();c.rect(0,0,256,146-hop);c.clip();c.translate(128,ay);c.fillStyle=AR;c.beginPath() + for(const[x,y]of[[0,0],[40,40],[17,40],[17,110],[-17,110],[-17,40],[-40,40]])c.lineTo(x,y) + c.closePath();c.fill();c.stroke() + c.strokeStyle='#fff';c.lineWidth=5;c.beginPath();c.moveTo(-8,48);c.lineTo(-8,64);c.moveTo(-6,14);c.lineTo(-20,28);c.stroke();c.restore() + c.strokeStyle='#111';c.lineWidth=7 + c.translate(128,146-hop);c.scale(.92*(2-sq),.92*sq) + c.fillStyle=RB;for(const d of[-1,1])c.beginPath(),c.moveTo(d*10,40),c.lineTo(d*42,30),c.lineTo(d*54,98),c.lineTo(d*40,88),c.lineTo(d*26,102),c.closePath(),c.fill(),c.stroke() + c.fillStyle=BG;c.beginPath();for(let k=0;k<128;k++){const a=k*T/128,r=62+4.5*cos(16*a);c.lineTo(cos(a)*r,sin(a)*r)}c.closePath();c.fill();c.stroke() + c.fillStyle=BI;c.lineWidth=5;c.beginPath();c.arc(0,0,49,0,T);c.fill();c.stroke() + c.strokeStyle='#fff';c.lineWidth=5;c.beginPath();c.arc(0,0,42,PI*1.12,PI*1.38);c.stroke();c.strokeStyle='#111' + c.save();c.scale(fl,1);c.fillStyle=ST;c.lineWidth=5;c.beginPath();for(let k=0;k<10;k++){const r=k%2?19:43,a=k*PI/5-PI/2;c.lineTo(cos(a)*r,3+sin(a)*r)}c.closePath();c.fill();c.stroke() + if(fl>.3){ + c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.arc(d*9,4,3.8,0,T),c.fill() + c.lineWidth=3.5;c.beginPath();c.arc(0,9,5,.15*PI,.85*PI);c.stroke() + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(d*16,11,4,2.5,0,0,T),c.fill() + } + c.restore() +} diff --git a/gen/uicolor/battery/low.js b/gen/uicolor/battery/low.js new file mode 100644 index 0000000..6770fe6 --- /dev/null +++ b/gen/uicolor/battery/low.js @@ -0,0 +1,24 @@ +// red battery nearly drained, its last little bar blinking, wobbling tiredly with a worried sweaty face and drops sliding down +const{sin,PI,floor}=Math,T=2*PI +export const frames=16,delay=90 +const R='#ff6b6b',RD='#fa5252',CAP='#ced4da',DR='#a5d8ff',BL='#ffa8a8' +const drop=(c,x,y,s)=>{c.fillStyle=DR;c.lineWidth=4;c.beginPath();c.moveTo(x,y-11*s);c.quadraticCurveTo(x+9*s,y+2*s,x,y+5*s);c.quadraticCurveTo(x-9*s,y+2*s,x,y-11*s);c.fill();c.stroke();c.fillStyle='#fff';c.beginPath();c.arc(x-2*s,y,1.8*s,0,T);c.fill()} +export default(c,t,i)=>{ + const on=floor(t*4)%2==0,r=.05*sin(T*t),sq=1+.025*sin(2*T*t) + c.save();c.translate(128,236);c.rotate(r);c.scale(2-sq,sq);c.translate(-128,-236) + c.fillStyle=CAP;c.beginPath();c.roundRect(102,18,52,26,8);c.fill();c.stroke() + c.fillStyle=on?R:'#ffa8a8';c.beginPath();c.roundRect(62,38,132,198,28);c.fill();c.stroke() + c.fillStyle='#fff';c.lineWidth=6;c.beginPath();c.roundRect(80,56,96,162,16);c.fill();c.stroke() + if(on){c.fillStyle=RD;c.lineWidth=5;c.beginPath();c.roundRect(90,190,76,18,7);c.fill();c.stroke()} + else{c.strokeStyle='#ffa8a8';c.lineWidth=4;c.setLineDash([6,6]);c.beginPath();c.roundRect(90,190,76,18,7);c.stroke();c.setLineDash([]);c.strokeStyle='#111'} + c.fillStyle='#fff';c.beginPath();c.ellipse(76,74,4,12,0,0,T);c.fill() + c.lineWidth=4.5;for(const d of[-1,1])c.beginPath(),c.moveTo(128+d*12,100),c.lineTo(128+d*29,107),c.stroke() + c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*20,124,6,8,0,0,T),c.fill() + c.fillStyle='#fff';for(const d of[-1,1])c.beginPath(),c.arc(128+d*20-2,120,2.6,0,T),c.fill() + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*32,144,8,4.5,0,0,T),c.fill() + c.lineWidth=4.5;c.beginPath();c.moveTo(114,158);for(let k=1;k<=7;k++)c.lineTo(114+k*4,158+(k%2?-4:0)+(i%2?1:0));c.stroke() + for(const[x,o,z]of[[170,0,1.3],[88,.5,1]]){const p=(t*2+o)%1;drop(c,x,84+p*34,z*(.8+.3*p))} + c.restore() + for(const d of[-1,1])for(const[w,s]of[[9,'#111'],[4,'#fff']]){c.lineWidth=w;c.strokeStyle=s;const x=128+d*(86+(i%2)*3);c.beginPath();c.moveTo(x,96);c.lineTo(x+d*8,104);c.moveTo(x+2*d,118);c.lineTo(x+d*12,120);c.stroke()} + c.strokeStyle='#111' +} diff --git a/gen/uicolor/cart/sad.js b/gen/uicolor/cart/sad.js new file mode 100644 index 0000000..55c8b25 --- /dev/null +++ b/gen/uicolor/cart/sad.js @@ -0,0 +1,34 @@ +// empty shopping cart rolling back and forth with a sad face and a tear, one lonely crumb sliding around the bottom of its basket +const{sin,cos,PI}=Math,T=2*PI +export const frames=20,delay=80 +const BK='#d0ebff',GR='#74c0fc',MT='#ced4da',HD='#ff6b6b',CR='#e0a96d',CH='#8b5a3c',BL='#ffa8a8',TR='#74c0fc' +const bas=c=>{c.beginPath();c.moveTo(56,80);c.lineTo(222,80);c.lineTo(200,168);c.lineTo(78,168);c.closePath()} +export default(c,t)=>{ + const dx=10*sin(t*T),cx=140-38*sin(t*T-.9) + c.translate(dx,0) + for(const[w,s]of[[14,'#111'],[6,MT]])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.moveTo(60,84),c.lineTo(36,62),c.moveTo(84,166),c.lineTo(92,196),c.lineTo(192,196),c.lineTo(198,166),c.stroke() + c.strokeStyle='#111';c.lineWidth=6 + c.save();c.translate(34,60);c.rotate(.74);c.fillStyle=HD;c.beginPath();c.roundRect(-14,-9,24,18,9);c.fill();c.stroke();c.restore() + for(const x of[100,184]){ + c.save();c.translate(x,214);c.rotate(dx/16);c.fillStyle='#495057';c.lineWidth=6;c.beginPath();c.arc(0,0,17,0,T);c.fill();c.stroke() + c.fillStyle=MT;c.lineWidth=4;c.beginPath();c.arc(0,0,7,0,T);c.fill();c.stroke() + c.strokeStyle='#fff';c.lineWidth=4;c.beginPath();c.arc(0,0,12,-.6,.6);c.stroke();c.restore() + } + c.strokeStyle='#111';c.lineWidth=7;bas(c);c.fillStyle=BK;c.fill() + c.save();bas(c);c.clip();c.strokeStyle=GR;c.lineWidth=4;c.beginPath() + for(const y of[102,124,146])c.moveTo(40,y),c.lineTo(230,y) + for(let k=0;k<7;k++)c.moveTo(78+k*22,80),c.lineTo(86+k*19,168) + c.stroke();c.restore() + c.strokeStyle='#111';c.lineWidth=7;bas(c);c.stroke() + for(const[w,s]of[[14,'#111'],[6,MT]])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.moveTo(50,80),c.lineTo(228,80),c.stroke() + c.strokeStyle='#111' + c.save();c.translate(cx,159);c.rotate((cx-140)/8);c.fillStyle=CR;c.lineWidth=3.5;c.beginPath();for(let k=0;k<6;k++){const a=k*T/6,r=k%2?7:9.5;c.lineTo(cos(a)*r,sin(a)*r)}c.closePath();c.fill();c.stroke() + c.fillStyle=CH;c.beginPath();c.arc(2,-1,2.5,0,T);c.fill();c.restore() + c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.arc(139+d*22,112,6.5,0,T),c.fill() + c.fillStyle='#fff';for(const d of[-1,1])c.beginPath(),c.arc(137+d*22,110,2.2,0,T),c.fill() + c.lineWidth=4.5;for(const d of[-1,1])c.beginPath(),c.moveTo(139+d*12,96),c.lineTo(139+d*30,101),c.stroke() + c.lineWidth=5;c.beginPath();c.arc(139,146,11,1.15*PI,1.85*PI);c.stroke() + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(139+d*38,126,8,5,0,0,T),c.fill() + const p=(t*2)%1,ty=118+p*34 + if(p<.85){c.fillStyle=TR;c.lineWidth=3;c.beginPath();c.moveTo(117,ty);c.quadraticCurveTo(124,ty+10,117,ty+12);c.quadraticCurveTo(110,ty+10,117,ty);c.fill();c.stroke()} +} diff --git a/gen/uicolor/comingsoon/oven.js b/gen/uicolor/comingsoon/oven.js new file mode 100644 index 0000000..6dfd64a --- /dev/null +++ b/gen/uicolor/comingsoon/oven.js @@ -0,0 +1,35 @@ +// mint oven baking a happy little cake that puffs up behind the glowing window while the timer dial ticks round +const{sin,cos,PI,floor}=Math,T=2*PI +export const frames=24,delay=90 +const O='#63e6be',OD='#38d9a9',PN='#c3fae8',IN='#ffc078',CK='#fff3bf',CR='#ffd8a8',BL='#ffa8a8',HN='#dee2e6',RD='#ff6b6b',PAN='#adb5bd' +export default(c,t,i)=>{ + const s=.5-.5*cos(T*t),h=34+22*s,tk=floor(t*12),tick=i%2==0,hot=.5+.5*sin(4*T*t) + c.fillStyle='#495057';for(const x of[46,184])c.beginPath(),c.roundRect(x,222,26,18,6),c.fill(),c.stroke() + c.fillStyle=O;c.beginPath();c.roundRect(22,22,212,206,26);c.fill();c.stroke() + c.fillStyle=PN;c.lineWidth=5;c.beginPath();c.roundRect(36,34,184,52,16);c.fill();c.stroke() + for(const[x,a]of[[66,-.8],[104,.6]]){c.fillStyle='#fff';c.beginPath();c.arc(x,60,14,0,T);c.fill();c.stroke();c.lineWidth=4;c.beginPath();c.moveTo(x,60);c.lineTo(x+cos(a-PI/2)*9,60+sin(a-PI/2)*9);c.stroke();c.lineWidth=5} + c.save();c.translate(182,60);if(tick)c.rotate(.08*(tk%2?1:-1)) + c.fillStyle='#fff3bf';c.beginPath();c.arc(0,0,20,0,T);c.fill();c.stroke() + c.lineWidth=3;for(let k=0;k<4;k++){const a=k*PI/2;c.beginPath();c.moveTo(cos(a)*13,sin(a)*13);c.lineTo(cos(a)*16,sin(a)*16);c.stroke()} + const ha=-PI/2+tk*T/12;c.strokeStyle=RD;c.lineWidth=4;c.beginPath();c.moveTo(0,0);c.lineTo(cos(ha)*13,sin(ha)*13);c.stroke() + c.fillStyle='#111';c.beginPath();c.arc(0,0,3,0,T);c.fill();c.restore() + if(tick)for(const a of[-.5,0,.5].map(v=>v-PI/4))for(const[w,st]of[[8,'#111'],[3,'#fff']])c.lineWidth=w,c.strokeStyle=st,c.beginPath(),c.moveTo(182+cos(a)*27,60+sin(a)*27),c.lineTo(182+cos(a)*35,60+sin(a)*35),c.stroke() + c.strokeStyle='#111';c.lineWidth=7 + c.fillStyle=OD;c.beginPath();c.roundRect(36,98,184,118,18);c.fill();c.stroke() + c.fillStyle=HN;c.lineWidth=5;c.beginPath();c.roundRect(72,104,112,12,6);c.fill();c.stroke() + const win=()=>{c.beginPath();c.roundRect(54,124,148,84,12)} + c.fillStyle=IN;win();c.fill();c.save();win();c.clip() + c.fillStyle='#ffe8cc';c.beginPath();c.ellipse(128,210,74+6*hot,36+4*hot,0,0,T);c.fill() + for(const[w,st]of[[8,'#111'],[4,hot>.5?RD:'#ff8787']]){c.lineWidth=w;c.strokeStyle=st;c.beginPath();for(let x=66;x<=190;x+=12)c.lineTo(x,(x-66)%24?140:134);c.stroke()} + c.strokeStyle='#111';c.lineWidth=4;c.beginPath();c.moveTo(54,202);c.lineTo(202,202);c.stroke() + c.lineWidth=5;c.fillStyle=PAN;c.beginPath();c.moveTo(74,188);c.lineTo(182,188);c.lineTo(176,202);c.lineTo(80,202);c.closePath();c.fill();c.stroke() + const cake=()=>{c.beginPath();c.moveTo(84,190);c.lineTo(84,190-h*.5);c.bezierCurveTo(84,184-h,172,184-h,172,190-h*.5);c.lineTo(172,190);c.closePath()} + c.fillStyle=CK;cake();c.fill();c.save();cake();c.clip();c.fillStyle=CR;c.fillRect(70,180-h,120,h*.4);c.restore();cake();c.stroke() + const ey=198-h*.6 + c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*14,ey,4.5,6,0,0,T),c.fill() + c.fillStyle='#fff';for(const d of[-1,1])c.beginPath(),c.arc(128+d*14-1.5,ey-2.5,2,0,T),c.fill() + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*26,ey+8,7,4,0,0,T),c.fill() + c.lineWidth=4;c.beginPath();c.arc(128,ey+4,7,.15*PI,.85*PI);c.stroke() + c.strokeStyle='#fff';c.lineWidth=6;c.beginPath();c.moveTo(170,132);c.lineTo(150,152);c.moveTo(186,134);c.lineTo(178,142);c.stroke() + c.restore();c.strokeStyle='#111';c.lineWidth=5;win();c.stroke() +} diff --git a/gen/uicolor/construction/barrier.js b/gen/uicolor/construction/barrier.js new file mode 100644 index 0000000..c2b7a6f --- /dev/null +++ b/gen/uicolor/construction/barrier.js @@ -0,0 +1,35 @@ +// orange and white striped road barrier, its two warning lamps flashing in turn, the lit lamp wide awake and beaming while the other dozes +const{sin,cos,PI,floor,max}=Math,T=2*PI +export const frames=16,delay=90 +const OR='#ff922b',ON='#ffd43b',OFF='#c8962e',HS='#495057',PO='#dee2e6',BL='#ffa8a8' +const board=(c,y,h)=>{ + const r=()=>{c.beginPath();c.roundRect(14,y,228,h,10)} + c.save();r();c.fillStyle='#fff';c.fill();c.clip();c.fillStyle=OR + for(let s=-60;s<250;s+=44)c.beginPath(),c.moveTo(s,y+h),c.lineTo(s+22,y+h),c.lineTo(s+22+h,y),c.lineTo(s+h,y),c.fill() + c.restore();r();c.stroke() +} +export default(c,t)=>{ + const k=floor(t*4)%2,p=(t*4)%1,pop=1+.1*max(0,1-p*3) + c.fillStyle=PO + for(const x of[64,192])c.beginPath(),c.roundRect(x-9,70,18,156,6),c.fill(),c.stroke(),c.beginPath(),c.roundRect(x-38,222,76,16,8),c.fill(),c.stroke() + board(c,90,48);board(c,158,38) + for(const[j,x]of[[0,64],[1,192]]){ + const on=j==k + c.save();c.translate(x,54);if(on)c.scale(pop,pop) + if(on)for(let r=0;r<7;r++){const a=PI+r*PI/6;for(const[w,s]of[[9,'#111'],[4,ON]])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.moveTo(cos(a)*35,sin(a)*35),c.lineTo(cos(a)*44,sin(a)*44),c.stroke()} + c.strokeStyle='#111';c.lineWidth=7 + c.fillStyle=HS;c.beginPath();c.arc(0,0,30,0,T);c.fill();c.stroke() + c.fillStyle=on?ON:OFF;c.lineWidth=5;c.beginPath();c.arc(0,0,22,0,T);c.fill();c.stroke() + c.fillStyle='#111';c.lineWidth=3.5 + if(on){ + c.fillStyle='#fff';c.beginPath();c.ellipse(-10,-11,5,3,-.6,0,T);c.fill() + c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.ellipse(d*8,-2,3.5,4.5,0,0,T),c.fill() + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(d*14,6,4,2.5,0,0,T),c.fill() + c.beginPath();c.arc(0,4,6,.15*PI,.85*PI);c.stroke() + }else{ + for(const d of[-1,1])c.beginPath(),c.arc(d*8,-4,4,.2*PI,.8*PI),c.stroke() + c.beginPath();c.moveTo(-3,9);c.lineTo(3,9);c.stroke() + } + c.restore() + } +} diff --git a/gen/uicolor/construction/excavator.js b/gen/uicolor/construction/excavator.js new file mode 100644 index 0000000..923eb98 --- /dev/null +++ b/gen/uicolor/construction/excavator.js @@ -0,0 +1,48 @@ +// yellow excavator digging into a dirt pile, lifting a full bucket and dumping it back, exhaust puffing, smiling as it works +const{sin,cos,PI,round}=Math,T=2*PI +export const frames=20,delay=90 +const Y='#ffd43b',YD='#fab005',TR='#495057',WH='#ced4da',GL='#a5d8ff',DI='#c08552',DD='#8d6346',BL='#ffa8a8',EX='#868e96' +const arm=(c,a,b,w,col)=>{for(const[lw,s]of[[w,'#111'],[w-10,col]])c.lineWidth=lw,c.strokeStyle=s,c.beginPath(),c.moveTo(...a),c.lineTo(...b),c.stroke();c.strokeStyle='#111';c.lineWidth=7} +const pin=(c,[x,y])=>{c.fillStyle=WH;c.lineWidth=4;c.beginPath();c.arc(x,y,6,0,T);c.fill();c.stroke();c.lineWidth=7} +const pose=t=>{ + const s=.5-.5*cos(T*t),a1=-.15-.75*s,a2=1.5-.6*s,th=a2-PI/2+.5+.9*sin(T*t) + const E=[128+80*cos(a1),128+80*sin(a1)],B=[E[0]+64*cos(a2),E[1]+64*sin(a2)] + return{E,B,th,at:(x,y)=>[B[0]+x*cos(th)-y*sin(th),B[1]+x*sin(th)+y*cos(th)]} +} +const mound=c=>{c.beginPath();c.moveTo(146,240);c.bezierCurveTo(160,178,234,172,248,240);c.closePath()} +export default(c,t)=>{ + const{E,B,th}=pose(t),by=round(2*sin(2*T*t)),full=t>.03&&t<.5 + for(let k=0;k<3;k++){const p=(t*3+k/3)%1,r=4+8*sin(PI*p);c.fillStyle='#fff';c.lineWidth=4;c.beginPath();c.arc(34-8*p+4*sin(T*p),76-50*p+by,r,0,T);c.fill();c.stroke()} + c.lineWidth=7 + c.fillStyle=TR;c.beginPath();c.roundRect(10,192,132,44,22);c.fill();c.stroke() + for(const x of[32,76,120]){c.fillStyle=WH;c.lineWidth=5;c.beginPath();c.arc(x,214,11,0,T);c.fill();c.stroke();c.fillStyle='#111';c.beginPath();c.arc(x,214,3,0,T);c.fill()} + c.lineWidth=7;c.translate(0,by) + c.fillStyle='#343a40';c.beginPath();c.rect(34,180,92,14);c.fill();c.stroke() + c.fillStyle=EX;c.beginPath();c.roundRect(28,80,12,40,4);c.fill();c.stroke() + c.fillStyle=Y;c.beginPath();c.roundRect(56,50,72,76,14);c.fill();c.stroke() + c.fillStyle=GL;c.lineWidth=5;c.beginPath();c.roundRect(68,62,48,40,8);c.fill();c.stroke() + c.fillStyle='#fff';c.beginPath();c.ellipse(80,72,4,8,.5,0,T);c.fill() + c.lineWidth=7 + const body=()=>{c.beginPath();c.roundRect(14,114,124,70,14)} + c.fillStyle=Y;body();c.fill();c.save();body();c.clip();c.fillStyle=YD;c.fillRect(0,114,34,80);c.restore();body();c.stroke() + c.fillStyle='#111';for(const x of[66,100])c.beginPath(),c.ellipse(x,146,5,7,0,0,T),c.fill() + c.fillStyle='#fff';for(const x of[64,98])c.beginPath(),c.arc(x,143,2.2,0,T),c.fill() + c.fillStyle=BL;for(const x of[52,114])c.beginPath(),c.ellipse(x,160,8,4.5,0,0,T),c.fill() + c.lineWidth=5;c.beginPath();c.arc(83,152,8,.15*PI,.85*PI);c.stroke() + arm(c,[128,128],E,26,Y);arm(c,E,B,22,YD) + c.save();c.translate(...B);c.rotate(th) + if(full){c.fillStyle=DI;c.lineWidth=5;for(const[x,y,r]of[[-16,2,11],[-24,18,12],[-26,34,9],[-12,22,10]])c.beginPath(),c.arc(x,y,r,0,T),c.fill(),c.stroke()} + c.fillStyle=EX;c.lineWidth=6;c.beginPath();c.moveTo(-10,-8);c.lineTo(16,-6);c.quadraticCurveTo(32,32,-2,44);c.lineTo(-28,42);c.quadraticCurveTo(-8,30,-10,-8);c.closePath();c.fill();c.stroke() + c.fillStyle=WH;c.lineWidth=4;c.beginPath();c.moveTo(-28,42);c.lineTo(-36,46);c.lineTo(-24,48);c.lineTo(-30,52);c.lineTo(-14,48);c.closePath();c.fill();c.stroke() + c.restore();pin(c,[128,128]);pin(c,E);pin(c,B) + c.translate(0,-by);c.lineWidth=7 + c.fillStyle=DI;mound(c);c.fill();c.stroke() + c.fillStyle=DD;for(const[x,y]of[[180,214],[206,200],[222,222],[194,230]])c.beginPath(),c.ellipse(x,y,5,3,0,0,T),c.fill() + for(let k=0;k<4;k++){ + const t0=.44+k*.035,u=(t-t0)/.2 + if(u<0||u>1)continue + const P=pose(t0),[x,y]=P.at(-20,20),yy=y+by+u*u*80,xx=x+(k-1.5)*7*u + if(yy>204)continue + c.fillStyle=DI;c.lineWidth=4;c.beginPath();c.arc(xx,yy,6-k%2,0,T);c.fill();c.stroke() + } +} diff --git a/gen/uicolor/copied/clipboard.js b/gen/uicolor/copied/clipboard.js new file mode 100644 index 0000000..a60415a --- /dev/null +++ b/gen/uicolor/copied/clipboard.js @@ -0,0 +1,29 @@ +// smiling clipboard whose sheet peels off a twin copy that slides out beside it, gets a green check and sparkles, then poofs away +const{sin,cos,PI,max,min}=Math,T=2*PI +export const frames=24,delay=80 +const WD='#a9744f',CL='#ced4da',LN='#a5d8ff',CK='#51cf66',BL='#ffa8a8',SP='#ffd43b' +const ease=u=>u<0?0:u>1?1:u*u*(3-2*u) +const sheet=c=>{ + c.fillStyle='#fff';c.lineWidth=6;c.beginPath();c.roundRect(-48,-76,96,152,8);c.fill();c.stroke() + c.strokeStyle=LN;c.lineWidth=7;c.beginPath();for(const[y,w]of[[-46,60],[-28,60],[-10,40]])c.moveTo(-30,y),c.lineTo(-30+w,y);c.stroke();c.strokeStyle='#111' + c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.ellipse(d*16,26,5,6.5,0,0,T),c.fill() + c.fillStyle='#fff';for(const d of[-1,1])c.beginPath(),c.arc(d*16-2,23,2.2,0,T),c.fill() + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(d*28,38,7,4,0,0,T),c.fill() + c.lineWidth=4.5;c.beginPath();c.arc(0,33,7,.15*PI,.85*PI);c.stroke() +} +const star=(c,x,y,s)=>{c.fillStyle=SP;c.lineWidth=3.5;c.beginPath();c.moveTo(x,y-s);for(const[px,py,qx,qy]of[[s,0,s*.2,-s*.2],[0,s,s*.2,s*.2],[-s,0,-s*.2,s*.2],[0,-s,-s*.2,-s*.2]])c.quadraticCurveTo(x+qx,y+qy,x+px,y+py);c.fill();c.stroke()} +export default(c,t)=>{ + const m=ease((t-.06)/.34),dx=88*m,dy=10*m,r=.14*m,sc=t<.82?1:1-ease((t-.82)/.14),ck=t<.42?0:t<.5?1.15*ease((t-.42)/.08):t<.56?1.15-.15*ease((t-.5)/.06):1 + const lift=t<.06?0:min(1,(t-.06)/.06)*(t<.4?1:0) + c.fillStyle=WD;c.beginPath();c.roundRect(14,30,136,206,16);c.fill();c.stroke() + c.save();c.translate(80,138);sheet(c);c.restore() + c.fillStyle=CL;c.lineWidth=6;c.beginPath();c.roundRect(50,18,60,30,8);c.fill();c.stroke() + c.fillStyle=WD;c.beginPath();c.arc(80,26,5,0,T);c.fill();c.stroke() + if(sc>.02&&t>.06){ + c.save();c.translate(80+dx,138+dy-6*lift);c.rotate(r);c.scale(sc,sc);sheet(c) + if(ck>0){c.save();c.translate(36,-62);c.scale(ck,ck);c.fillStyle=CK;c.lineWidth=6;c.beginPath();c.arc(0,0,20,0,T);c.fill();c.stroke();c.strokeStyle='#fff';c.lineWidth=7;c.beginPath();c.moveTo(-10,0);c.lineTo(-3,8);c.lineTo(11,-8);c.stroke();c.restore()} + c.restore() + } + if(t>.48&&t<.82){const p=(t-.48)/.34,s=sin(PI*p)*9;for(const[x,y,o]of[[238,128,0],[152,44,.5],[236,212,.25]])star(c,x,y,max(0,s*(1-.3*o)))} + if(t>.82&&t<.98){const p=(t-.82)/.16;c.fillStyle='#fff';c.lineWidth=4;for(let k=0;k<6;k++){const a=k*PI/3+.3,d=20+46*p,s=8*(1-p)+1;c.beginPath();c.arc(168+cos(a)*d,148+sin(a)*d,s,0,T);c.fill();c.stroke()}} +} diff --git a/gen/uicolor/coupon/scissors.js b/gen/uicolor/coupon/scissors.js new file mode 100644 index 0000000..fb3a86e --- /dev/null +++ b/gen/uicolor/coupon/scissors.js @@ -0,0 +1,23 @@ +// red-handled scissors snipping their way down the dashed line of a yellow percent-off coupon, the dashes marching into the blades +const{sin,cos,PI,abs}=Math,T=2*PI +export const frames=24,delay=70 +const CP='#ffd43b',CPD='#fab005',HD='#ff6b6b',BLD='#dee2e6',X=178 +const tk=c=>{c.beginPath();c.moveTo(34,110);c.lineTo(222,110);c.arcTo(238,110,238,126,16);c.arc(238,170,15,-PI/2,PI/2,true);c.arcTo(238,232,222,232,16);c.lineTo(34,232);c.arcTo(18,232,18,216,16);c.arc(18,170,15,PI/2,-PI/2,true);c.arcTo(18,110,34,110,16);c.closePath()} +export default(c,t)=>{ + const sn=abs(sin(4*PI*t)),h=.04+.3*sn,dy=4*(1-sn) + tk(c);c.fillStyle=CP;c.fill() + c.save();tk(c);c.clip();c.fillStyle=CPD;c.fillRect(18,216,220,20);c.restore() + tk(c);c.stroke() + for(const[w,s]of[[26,'#111'],[13,'#fff']]){c.lineWidth=w;c.strokeStyle=s;c.beginPath();c.moveTo(130,138);c.lineTo(76,204);c.moveTo(94,145);c.arc(82,145,12,0,T);c.moveTo(134,198);c.arc(122,198,12,0,T);c.stroke()} + c.strokeStyle='#111';c.fillStyle='#fff';c.lineWidth=5;c.beginPath();for(let k=0;k<10;k++){const r=k%2?8:19,a=k*PI/5-PI/2;c.lineTo(209+cos(a)*r,172+sin(a)*r)}c.closePath();c.fill();c.stroke() + c.setLineDash([12,10]);c.lineDashOffset=t*66;c.lineWidth=5;c.beginPath();c.moveTo(X,116);c.lineTo(X,228);c.stroke();c.setLineDash([]) + c.translate(X,80+dy) + for(const s of[1,-1]){ + c.save();c.rotate(s*h) + for(const[w,st]of[[18,'#111'],[9,HD]])c.lineWidth=w,c.strokeStyle=st,c.beginPath(),c.moveTo(0,0),c.lineTo(s*14,-30),c.moveTo(s*20+15,-48),c.arc(s*20,-48,15,0,T),c.stroke() + c.strokeStyle='#111';c.fillStyle=BLD;c.lineWidth=5;c.beginPath();c.moveTo(-s*1,-8);c.quadraticCurveTo(-s*10,28,0,62);c.quadraticCurveTo(s*9,26,s*6,-6);c.closePath();c.fill();c.stroke() + c.strokeStyle='#fff';c.lineWidth=3;c.beginPath();c.moveTo(-s*2,6);c.quadraticCurveTo(-s*4,26,-s*1,40);c.stroke() + c.restore() + } + c.strokeStyle='#111';c.fillStyle='#ffd43b';c.lineWidth=4;c.beginPath();c.arc(0,0,6,0,T);c.fill();c.stroke() +} diff --git a/gen/uicolor/download/parachute.js b/gen/uicolor/download/parachute.js new file mode 100644 index 0000000..479f82f --- /dev/null +++ b/gen/uicolor/download/parachute.js @@ -0,0 +1,29 @@ +// smiling cardboard box drifting down under a striped parachute, swaying gently as little clouds float up past it +const{sin,PI,round}=Math,T=2*PI +export const frames=12,delay=110 +const P=['#4dabf7','#fff','#ff6b6b','#fff','#4dabf7'],BX='#e0a96d',BXD='#c08552',TP='#ffd8a8',BL='#ff8787' +const cloud=(c,x,y,s)=>{const b=[[-14*s,3*s,10*s],[2*s,-4*s,13*s],[17*s,3*s,9*s]];c.lineWidth=13;for(const[a,d,r]of b)c.beginPath(),c.arc(x+a,y+d,r,0,T),c.stroke();c.fillStyle='#fff';for(const[a,d,r]of b)c.beginPath(),c.arc(x+a,y+d,r,0,T),c.fill();c.lineWidth=7} +const can=c=>{c.beginPath();c.moveTo(-98,0);c.bezierCurveTo(-98,-74,98,-74,98,0);for(let k=0;k<5;k++){const x=98-k*39.2;c.quadraticCurveTo(x-19.6,16,x-39.2,0)}c.closePath()} +export default(c,t)=>{ + const a=.13*sin(T*t),b=round(4*sin(2*T*t)) + for(const[x,o]of[[32,0],[222,.5]]){const p=(t+o)%1,s=sin(PI*p);if(s>.08)cloud(c,x,226-p*190,.8*s)} + c.strokeStyle='#111' + c.save();c.translate(128,24+b);c.rotate(a);c.translate(0,48) + const L=[[-96,2],[-20,14],[20,14],[96,2]],K=[[-30,104],[-14,104],[14,104],[30,104]] + for(const[lw,s]of[[7,'#111'],[3,'#fff']]){c.lineWidth=lw;c.strokeStyle=s;c.beginPath();L.forEach(([x,y],k)=>{c.moveTo(x,y);c.lineTo(...K[k])});c.stroke()} + c.strokeStyle='#111';c.lineWidth=7 + c.save();can(c);c.clip() + const gx=k=>(-98+k*39.2)*1.3 + for(let k=0;k<5;k++){c.fillStyle=P[k];c.beginPath();c.moveTo(0,-110);c.lineTo(gx(k),30);c.lineTo(gx(k+1),30);c.closePath();c.fill()} + c.lineWidth=4;c.beginPath();for(let k=1;k<5;k++)c.moveTo(0,-110),c.lineTo(gx(k),30);c.stroke() + c.restore();c.lineWidth=7;can(c);c.stroke() + c.fillStyle='#fff';c.beginPath();c.ellipse(-50,-36,12,5,-.6,0,T);c.fill() + c.fillStyle=BXD;c.beginPath();c.moveTo(-40,108);c.lineTo(-30,98);c.lineTo(30,98);c.lineTo(40,108);c.closePath();c.fill();c.stroke() + c.fillStyle=BX;c.beginPath();c.roundRect(-44,104,88,60,8);c.fill();c.stroke() + c.fillStyle=TP;c.lineWidth=5;c.beginPath();c.rect(-10,104,20,22);c.fill();c.stroke() + c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.ellipse(d*17,134,5,6.5,0,0,T),c.fill() + c.fillStyle='#fff';for(const d of[-1,1])c.beginPath(),c.arc(d*17-2,131,2.2,0,T),c.fill() + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(d*28,146,7,4,0,0,T),c.fill() + c.lineWidth=4.5;c.beginPath();c.arc(0,141,7,.15*PI,.85*PI);c.stroke() + c.restore() +} diff --git a/gen/uicolor/error/cloud.js b/gen/uicolor/error/cloud.js new file mode 100644 index 0000000..de6fa0f --- /dev/null +++ b/gen/uicolor/error/cloud.js @@ -0,0 +1,27 @@ +// grumpy gray storm cloud with an anger mark, blue rain pouring down and a yellow lightning bolt cracking out as it shudders +const{sin,cos,PI,min}=Math,T=2*PI +export const frames=16,delay=80 +const CL='#ced4da',CD='#adb5bd',RN='#4dabf7',BT='#ffd43b',AN='#ff6b6b' +const PF=[[-64,8,34],[-30,-18,42],[18,-30,46],[60,-4,38],[-20,16,40],[28,14,40]] +export default(c,t,i)=>{ + const z=i==5||i==6||i==12,sh=z?(i%2?4:-4):0,y=98+3*sin(t*T) + for(let k=0;k<7;k++){ + const p=(t*2+k*.43)%1,x=56+k*24+(k%2)*4,yy=y+30+p*112,s=min(1,(1-p)*5) + if(s<=0)continue + c.save();c.translate(x-p*8,yy);c.rotate(.1);c.scale(s,s);c.fillStyle=RN;c.lineWidth=4;c.beginPath();c.moveTo(0,-14);c.quadraticCurveTo(10,3,0,8);c.quadraticCurveTo(-10,3,0,-14);c.fill();c.stroke();c.restore() + } + if(z){ + c.fillStyle=BT;c.lineWidth=5;c.beginPath();for(const[x,yy]of[[134,120],[108,180],[128,180],[108,240],[160,166],[138,166],[156,120]])c.lineTo(x+sh,yy);c.closePath();c.fill();c.stroke() + for(const[a,r]of[[-2.6,0],[-.5,1],[2.2,2]]){const x=118+cos(a)*40+sh,yy=206+sin(a)*24;for(const[w,s]of[[10,'#111'],[4,BT]])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.moveTo(x,yy),c.lineTo(x+cos(a)*14,yy+sin(a)*10),c.stroke()} + c.strokeStyle='#111' + } + c.translate(128+sh,y) + c.lineWidth=14;for(const[a,d,r]of PF)c.beginPath(),c.arc(a,d,r,0,T),c.stroke() + c.fillStyle=CL;for(const[a,d,r]of PF)c.beginPath(),c.arc(a,d,r,0,T),c.fill() + c.save();c.beginPath();for(const[a,d,r]of PF)c.moveTo(a+r,d),c.arc(a,d,r,0,T);c.clip();c.fillStyle=CD;c.beginPath();c.ellipse(0,64,120,34,0,0,T);c.fill();c.restore() + c.strokeStyle='#fff';c.lineWidth=6;c.beginPath();c.arc(18,-30,36,PI*1.15,PI*1.45);c.stroke();c.strokeStyle='#111' + c.lineWidth=6;for(const d of[-1,1])c.beginPath(),c.moveTo(d*36,-14),c.lineTo(d*14,-4),c.stroke() + c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.arc(d*24,6,z?4:6,0,T),c.fill() + c.lineWidth=5;c.beginPath();c.arc(0,34,12,PI*1.15,PI*1.85);c.stroke() + c.save();c.translate(58,-34);c.rotate(.2*sin(2*T*t));for(const[w,s]of[[11,'#111'],[5,AN]]){c.lineWidth=w;c.strokeStyle=s;c.beginPath();for(const r of[0,1,2,3]){const a=r*PI/2+PI/4;c.moveTo(cos(a)*7+cos(a+PI/4)*10,sin(a)*7+sin(a+PI/4)*10);c.quadraticCurveTo(cos(a)*7,sin(a)*7,cos(a)*7+cos(a-PI/4)*10,sin(a)*7+sin(a-PI/4)*10)}c.stroke()}c.restore() +} diff --git a/gen/uicolor/error/cookie.js b/gen/uicolor/error/cookie.js new file mode 100644 index 0000000..f3d6a45 --- /dev/null +++ b/gen/uicolor/error/cookie.js @@ -0,0 +1,38 @@ +// sad chocolate chip cookie trembles, a crack zigzags down it, it splits in two crying while crumbs tumble off, then it pulls itself back together +const{sin,cos,PI,min,max}=Math,T=2*PI +export const frames=24,delay=80 +const CK='#e0a96d',CKD='#c98c4f',CH='#5c3d2e',BL='#ffa8a8',TR='#74c0fc' +const C=[[0,-76],[-9,-56],[8,-36],[-7,-14],[9,10],[-7,34],[8,56],[0,76]] +const CH0=[[-42,-34],[30,-46],[50,6],[-52,18],[-24,50],[26,50],[-8,-60],[40,-22]] +const io=u=>u*u*(3-2*u),cl=u=>min(1,max(0,u)) +const body=c=>{c.beginPath();for(let a=0;a<=T+.01;a+=.12){const r=76+3*sin(a*7);c.lineTo(cos(a)*r,sin(a)*r)}c.closePath()} +const crack=c=>{c.beginPath();for(const[x,y]of C)c.lineTo(x,y)} +export default(c,t,i)=>{ + const tr=t>.04&&t<.32?(i%2?2:-2):0,cp=t<.3?cl((t-.1)/.2):cl(1-(t-.9)/.1),sp=t<.32?0:t<.46?1-(1-(t-.32)/.14)**3:t<.78?1:t<.9?1-io((t-.78)/.12):0 + for(const d of[-1,1]){ + c.save();c.translate(128+tr+d*14*sp,126+5*sp);c.translate(0,84);c.rotate(d*.2*sp);c.translate(0,-84) + if(sp>0){c.beginPath();for(const[x,y]of[[0,-110],...C,[0,110],[d*200,110],[d*200,-110]])c.lineTo(x,y);c.clip()} + else if(d>0){c.restore();continue} + body(c);c.fillStyle=CK;c.fill() + c.save();body(c);c.clip();c.fillStyle=CKD;c.beginPath();c.arc(0,0,82,0,T);c.arc(-10,-12,78,0,T,true);c.fill();c.restore() + c.lineWidth=7;body(c);c.stroke() + c.fillStyle=CH;for(const[x,y]of CH0)c.beginPath(),c.ellipse(x,y,7,6,x,0,T),c.fill() + c.lineWidth=4.5;for(const e of[-1,1])c.beginPath(),c.moveTo(e*38,-20),c.lineTo(e*17,-27),c.stroke() + c.fillStyle='#111';for(const e of[-1,1])c.beginPath(),c.arc(e*26,-6,6,0,T),c.fill() + c.fillStyle='#fff';for(const e of[-1,1])c.beginPath(),c.arc(e*26-2,-8,2.2,0,T),c.fill() + c.lineWidth=5;c.beginPath();c.arc(0,36,13,PI*1.2,PI*1.8);c.stroke() + c.fillStyle=BL;for(const e of[-1,1])c.beginPath(),c.ellipse(e*44,12,8,4.5,0,0,T),c.fill() + if(sp>.5)for(const o of[0,.5]){const p=(t*4+o)%1,yy=2+p*36;c.fillStyle=TR;c.lineWidth=3;c.beginPath();c.moveTo(d*30,yy-8);c.quadraticCurveTo(d*30+6,yy+3,d*30,yy+5);c.quadraticCurveTo(d*30-6,yy+3,d*30,yy-8);c.fill();c.stroke()} + if(sp>0){c.lineWidth=6;crack(c);c.stroke()} + c.restore() + } + if(sp==0&&cp>0){ + const L=C.reduce((s,[x,y],k)=>k?s+Math.hypot(x-C[k-1][0],y-C[k-1][1]):0,0) + c.save();c.translate(128+tr,126);c.lineWidth=6;c.setLineDash([L*cp,999]);c.lineDashOffset=t<.5?0:-L*(1-cp);crack(c);c.stroke();c.restore() + } + const u=(t-.33)/.5 + if(u>0&&u<1)for(let k=1;k<7;k++){ + const[cx,cy]=C[k],d=k%2?1:-1,x=128+cx+d*(18+k*7)*u*1.4,y=126+cy-(34+k*5%17)*u*1.2+280*u*u,r=(4+k%3*1.5)*min(1,(1-u)*5) + if(y<230&&r>.5){c.fillStyle=k%2?CK:CKD;c.lineWidth=3;c.beginPath();c.moveTo(x-r,y);c.lineTo(x-r*.3,y-r);c.lineTo(x+r,y-r*.4);c.lineTo(x+r*.6,y+r);c.closePath();c.fill();c.stroke()} + } +} diff --git a/gen/uicolor/error/glitch.js b/gen/uicolor/error/glitch.js new file mode 100644 index 0000000..0569be0 --- /dev/null +++ b/gen/uicolor/error/glitch.js @@ -0,0 +1,36 @@ +// computer monitor glitching out, RGB bars tearing across it and slices jumping sideways, spiral dizzy eyes and little stars circling overhead +const{sin,cos,PI,abs}=Math,T=2*PI +export const frames=16,delay=80 +const CS='#b197fc',SC='#e7f5ff',G=['#ff6b6b','#51cf66','#4dabf7','#ffd43b','#f783ac','#3bc9db'],BL='#ffa8a8',GS='0011010000111010' +const R=n=>abs(sin(n*127.1+311.7)*43758.5)%1 +const star=(c,x,y,s)=>{c.fillStyle='#ffd43b';c.lineWidth=4;c.beginPath();for(let k=0;k<10;k++){const r=k%2?s*.45:s,a=k*PI/5-PI/2;c.lineTo(x+cos(a)*r,y+sin(a)*r)}c.closePath();c.fill();c.stroke()} +const face=(c,t,col,o)=>{ + c.strokeStyle=col;c.lineWidth=5 + for(const d of[-1,1]){c.beginPath();for(let a=0;a<4.4*PI;a+=.3){const r=1+a*1.15,b=(a+t*T*2)*d;c.lineTo(128+d*32+o+cos(b)*r,118+sin(b)*r)}c.stroke()} + c.beginPath();for(let x=-22;x<=22;x+=2)c.lineTo(128+x+o,154+4*sin(x/6+t*T*2));c.stroke() +} +const M=(c,t,i,g)=>{ + c.strokeStyle='#111';c.lineWidth=7 + c.fillStyle='#868e96';c.beginPath();c.roundRect(110,194,36,26,4);c.fill();c.stroke() + c.fillStyle=CS;c.beginPath();c.roundRect(70,214,116,22,11);c.fill();c.stroke() + c.beginPath();c.roundRect(22,52,212,148,24);c.fill();c.stroke() + c.fillStyle=g?'#ff6b6b':'#51cf66';c.lineWidth=4;c.beginPath();c.arc(210,190,4.5,0,T);c.fill();c.stroke() + c.save();c.beginPath();c.roundRect(40,70,176,112,12);c.clip() + c.fillStyle=SC;c.fillRect(0,60,256,130) + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*58,140,9,5,0,0,T),c.fill() + if(g)face(c,t,'#ff6b6b',-5),face(c,t,'#4dabf7',5) + face(c,t,'#111',0) + if(g)for(let n=0;n<5;n++)c.fillStyle=G[(i+n)%6],c.fillRect(40+R(i+n*13)*90,72+R(i*9+n)*104,30+R(i*7+n)*110,4+R(i*3+n*7)*10) + c.restore() + c.strokeStyle='#111';c.lineWidth=5;c.beginPath();c.roundRect(40,70,176,112,12);c.stroke() + c.strokeStyle='#fff';c.lineWidth=6;c.beginPath();c.moveTo(54,96);c.lineTo(54,84);c.lineTo(66,84);c.stroke() +} +export default(c,t,i)=>{ + const g=GS[i]>0 + const st=b=>{for(let k=0;k<3;k++){const a=t*T+k*T/3,z=sin(a);if(z<0==b)star(c,128+cos(a)*76,30+z*10,14+3*z)}} + st(1) + if(!g)M(c,t,i,0) + else{const Y=[0,64,92,118,140,166,196,256];for(let k=0;k<7;k++){const dx=R(i*5+k)>.45?(R(i*11+k)-.5)*40:0;c.save();c.beginPath();c.rect(0,Y[k],256,Y[k+1]-Y[k]);c.clip();c.translate(dx,0);M(c,t,i,1);c.restore()}} + c.strokeStyle='#111' + st(0) +} diff --git a/gen/uicolor/expired/milk.js b/gen/uicolor/expired/milk.js new file mode 100644 index 0000000..65c080e --- /dev/null +++ b/gen/uicolor/expired/milk.js @@ -0,0 +1,35 @@ +// spoiled milk carton swaying woozily with spinning spiral eyes and a wobbly mouth, green stink lines wafting up and a fly buzzing round +const{sin,cos,PI}=Math,T=2*PI +export const frames=16,delay=90 +const BU='#74c0fc',BUD='#4dabf7',GR='#a9e34b',SB='#c0eb75',FLY='#495057',DR='#a5d8ff' +const spiral=(c,x,y,a)=>{c.beginPath();for(let k=0;k<=34;k++){const u=k*.32,r=1+u*1.15;c.lineTo(x+cos(u+a)*r,y+sin(u+a)*r)}c.stroke()} +export default(c,t,i)=>{ + const r=.07*sin(T*t),sk=.05*sin(2*T*t+1) + for(const[x,o,h]of[[36,0,70],[220,.5,70]]){ + const p=(t+o)%1,y0=150-36*p,L=h*(1-.3*p) + c.save();c.beginPath();c.rect(0,0,256,160);c.clip() + for(const[w,s]of[[12,'#111'],[5,GR]]){c.lineWidth=w;c.strokeStyle=s;c.beginPath();for(let k=0;k<=12;k++){const y=y0-k/12*L;c.lineTo(x+7*sin(y*.12+T*t*2),y)}c.stroke()} + c.restore() + } + c.strokeStyle='#111';c.lineWidth=7 + c.save();c.translate(128,238);c.rotate(r);c.transform(1,0,sk,1,0,0);c.translate(-128,-238) + c.fillStyle=BU;c.beginPath();c.roundRect(90,66,76,20,6);c.fill();c.stroke() + c.beginPath();c.moveTo(64,124);c.lineTo(88,84);c.lineTo(168,84);c.lineTo(192,124);c.closePath();c.fill();c.stroke() + c.fillStyle='#fff';c.beginPath();c.roundRect(64,122,128,114,10);c.fill();c.stroke() + c.save();c.beginPath();c.roundRect(64,122,128,114,10);c.clip() + c.fillStyle=BUD;c.beginPath();c.moveTo(60,240);c.lineTo(60,210);for(let x=60;x<=196;x+=4)c.lineTo(x,210+5*sin(x*.09+T*t));c.lineTo(196,240);c.closePath();c.fill();c.lineWidth=5;c.stroke() + c.restore();c.lineWidth=7;c.beginPath();c.roundRect(64,122,128,114,10);c.stroke() + c.fillStyle='#fff';c.lineWidth=4;c.beginPath();c.ellipse(128,104,10,8,0,0,T);c.fill();c.stroke() + c.lineWidth=4;for(const[x,d]of[[104,1],[152,-1]])spiral(c,x,152,d*T*t*2) + c.fillStyle=SB;for(const x of[88,168])c.beginPath(),c.ellipse(x,174,9,5,0,0,T),c.fill() + c.lineWidth=4.5;c.beginPath();for(let k=0;k<=8;k++){const x=110+k*4.5;c.lineTo(x,184+(k%2?-3:3)*(i%2?1:-1))}c.stroke() + c.fillStyle=SB;c.lineWidth=3.5;c.beginPath();c.moveTo(130,185);c.quadraticCurveTo(132,200,140,198);c.quadraticCurveTo(146,194,140,184);c.fill();c.stroke() + c.fillStyle=DR;c.lineWidth=3.5;const dy=(t*2%1)*14;c.beginPath();c.moveTo(178,128+dy);c.quadraticCurveTo(186,140+dy,178,144+dy);c.quadraticCurveTo(170,140+dy,178,128+dy);c.fill();c.stroke() + c.restore() + const fa=T*t,fx=128+84*cos(fa),fy=42+14*sin(2*fa),fl=-sin(fa)>0?1:-1 + c.save();c.translate(fx,fy);c.scale(fl,1) + c.fillStyle='#fff';c.lineWidth=3;for(const d of[-1,1])c.beginPath(),c.ellipse(d*3-1,-8,5,9,d*.5+(i%2?.3:-.3)*d,0,T),c.fill(),c.stroke() + c.fillStyle=FLY;c.lineWidth=3;c.beginPath();c.ellipse(0,0,9,6,0,0,T);c.fill();c.stroke() + c.fillStyle='#fff';c.beginPath();c.arc(6,-1,2.5,0,T);c.fill() + c.restore() +} diff --git a/gen/uicolor/failed/balloon.js b/gen/uicolor/failed/balloon.js new file mode 100644 index 0000000..6c4972d --- /dev/null +++ b/gen/uicolor/failed/balloon.js @@ -0,0 +1,37 @@ +// happy red balloon bobbing, panics, pops into a burst of rubber bits, the sad scrap and its droopy string flop to the ground, then it puffs back up +const{sin,cos,PI,min}=Math,T=2*PI +export const frames=24,delay=80 +const RD='#ff6b6b',BL='#ffa8a8',BY='#ffd43b',TR='#74c0fc' +const E=u=>u<0?0:u>1?1:u*u*(3-2*u) +const two=(c,w,col,f)=>{for(const[l,s]of[[w,'#111'],[w-6,col]])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),f(),c.stroke();c.strokeStyle='#111'} +export default(c,t,i)=>{ + let x=128,y=96,rx=58,ry=68,b=0,m=0,f=0,ph=0 + if(i<9){y=96+4*sin(i/9*T);ph=i/9*T;if(i>6)m=1,x+=i%2?5:-5,rx+=5,ry+=4} + else if(i<19){const q=min(1,((i-9)/4)**2);x=128-24*q;y=100+88*q;rx=52;ry=32;b=.13;m=i<11?1:2;f=q;if(i==13)rx=60,ry=24;if(i==14)rx=49,ry=35} + else{const u=E((i-18)/6);x=104+24*u;y=188-92*u;rx=52+6*u;ry=32+36*u;b=.13*(1-u);m=u<.5?2:0;f=1-u} + const k=rx/58,K=y+ry + if(i==9){c.save();c.translate(128,96);c.beginPath();for(let n=0;n<24;n++){const r=n%2?50:82,a=n*PI/12;c.lineTo(cos(a)*r,sin(a)*r)}c.closePath();c.fillStyle=BY;c.fill();c.stroke();c.restore()} + if(i==10)for(let n=0;n<12;n++){const a=n*T/12+.2;two(c,12,BY,()=>{c.moveTo(128+cos(a)*62,96+sin(a)*62);c.lineTo(128+cos(a)*84,96+sin(a)*84)})} + if(i>6&&i<9)for(const d of[-1,1])two(c,10,'#fff',()=>{for(const o of[-16,16])c.moveTo(x+d*(rx+14),y+o),c.lineTo(x+d*(rx+26),y+o)}) + two(c,9,'#fff',()=>{for(let n=0;n<=14;n++){const u=n/14,ax=x+9*sin(u*5+ph)*u,ay=K+8+u*60,gx=x+8+u*100,gy=K+8+3*sin(u*16)*u;c.lineTo(ax+(gx-ax)*f,ay+(gy-ay)*f)}}) + c.lineWidth=7;c.fillStyle=RD;c.beginPath() + for(let a=0;a14&&i<19){c.fillStyle=TR;c.lineWidth=3/k;const ty=-2+(i-15)*7;c.beginPath();c.moveTo(-18,ty);c.quadraticCurveTo(-11,ty+10,-18,ty+12);c.quadraticCurveTo(-25,ty+10,-18,ty);c.fill();c.stroke()} + c.restore() + if(i>8&&i<13)for(let n=0;n<6;n++){const a=n*T/6+.4,d=60+(i-9)*26;c.save();c.translate(128+cos(a)*d,96+sin(a)*d+(i-9)**2*5);c.rotate(a+i);two(c,10,RD,()=>{c.moveTo(-9,0);c.quadraticCurveTo(-4,-8,1,0);c.quadraticCurveTo(5,7,10,-1)});c.restore()} +} diff --git a/gen/uicolor/favorites/empty.js b/gen/uicolor/favorites/empty.js new file mode 100644 index 0000000..0183a9e --- /dev/null +++ b/gen/uicolor/favorites/empty.js @@ -0,0 +1,13 @@ +// empty dashed star outline waiting to be filled, its dashes marching round as it breathes, sparkles twinkling on and off around it +const{sin,cos,PI,max,hypot}=Math,T=2*PI +export const frames=16,delay=80 +const SY='#ffd43b',R=104,r=46,P=10*hypot(R-r*cos(PI/5),r*sin(PI/5))/20 +const sp=(c,x,y,s)=>{if(s<1.5)return;c.lineWidth=4;c.fillStyle='#fff';c.beginPath();c.moveTo(x,y-s);for(const[px,py,qx,qy]of[[s,0,s*.18,-s*.18],[0,s,s*.18,s*.18],[-s,0,-s*.18,s*.18],[0,-s,-s*.18,-s*.18]])c.quadraticCurveTo(x+qx,y+qy,x+px,y+py);c.fill();c.stroke()} +export default(c,t)=>{ + for(const[x,y,o,s]of[[46,50,0,16],[210,48,.35,14],[30,196,.6,12],[226,196,.15,13],[128,232,.8,11],[128,146,.45,15]])sp(c,x,y,s*max(0,sin(PI*((t*2+o)%1)))) + c.save();c.translate(128,138);const k=1+.04*sin(t*T*2);c.scale(k,k);c.rotate(.04*sin(t*T)) + c.beginPath();for(let n=0;n<10;n++){const q=n%2?r:R,a=n*PI/5-PI/2;c.lineTo(cos(a)*q,sin(a)*q)}c.closePath() + c.setLineDash([P*.55,P*.45]);c.lineDashOffset=-t*P*2 + for(const[w,s]of[[17,'#111'],[8,SY]])c.lineWidth=w,c.strokeStyle=s,c.stroke() + c.restore() +} diff --git a/gen/uicolor/fridge/empty.js b/gen/uicolor/fridge/empty.js new file mode 100644 index 0000000..0a7926f --- /dev/null +++ b/gen/uicolor/fridge/empty.js @@ -0,0 +1,38 @@ +// fridge door swings open to show nothing but one lonely shivering egg, the light inside flickering, then it shuts again +const{sin,cos,PI}=Math,T=2*PI +export const frames=24,delay=90 +const BD='#99e9f2',LN='#e3fafc',LIT='#fff3bf',DIM='#5c6670',SH='#d0ebff',BY='#ffd43b',BL='#ffa8a8',FL='000101110110101111010000' +const E=u=>u<0?0:u>1?1:u*u*(3-2*u) +export default(c,t,i)=>{ + const th=PI*.68*(E((t-.04)/.16)-E((t-.76)/.14)),k=cos(th),op=th>.05,on=op&&FL[i]>0,X=90,W=112 + c.fillStyle='#495057';for(const x of[100,176])c.beginPath(),c.roundRect(x,226,18,16,4),c.fill(),c.stroke() + c.fillStyle=BD;c.beginPath();c.roundRect(X,14,W,220,16);c.fill();c.stroke() + if(op){ + c.fillStyle=on?LIT:DIM;c.beginPath();c.roundRect(96,84,100,142,8);c.fill();c.lineWidth=5;c.stroke() + if(on){c.lineWidth=4;c.fillStyle=BY;c.beginPath();c.arc(146,88,9,0,PI);c.fill();c.stroke() + for(const a of[.5,1.1,PI/2,PI-1.1,PI-.5])for(const[w,s]of[[8,'#111'],[3,BY]])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.moveTo(146+cos(a)*16,88+sin(a)*16),c.lineTo(146+cos(a)*24,88+sin(a)*24),c.stroke() + c.strokeStyle='#111'} + c.lineWidth=4;c.fillStyle=SH;for(const y of[132,192])c.beginPath(),c.roundRect(96,y,100,8,3),c.fill(),c.stroke() + const j=i%2?1.5:-1.5 + c.lineWidth=5;c.fillStyle='#fff';c.beginPath();c.ellipse(146+j,170,18,23,0,0,T);c.fill();c.stroke() + c.fillStyle='#fff';c.globalAlpha=.8;c.beginPath();c.ellipse(139+j,160,4,6,-.4,0,T);c.fill();c.globalAlpha=1 + c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.arc(146+j+d*7,170,2.8,0,T),c.fill() + c.lineWidth=3;c.beginPath();c.arc(146+j,182,4.5,1.2*PI,1.8*PI);c.stroke() + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(146+j+d*12,177,3.5,2,0,0,T),c.fill() + } + c.lineWidth=7;c.strokeStyle='#111' + const fx=X+W*k,dy=6*sin(th) + c.fillStyle=k>0?BD:LN;c.beginPath();c.moveTo(X,80);c.lineTo(fx,80-dy);c.lineTo(fx,232+dy);c.lineTo(X,232);c.closePath();c.fill();c.stroke() + if(k>.25)for(const[w,s]of[[13,'#111'],[5,'#fff']])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.moveTo(X+(W-16)*k,100),c.lineTo(X+(W-16)*k,144),c.stroke() + if(k<-.2){c.lineWidth=4;c.strokeStyle='#111';c.fillStyle=SH;for(const y of[118,176])c.beginPath(),c.moveTo(X,y),c.lineTo(fx+6,y+(y>150?3:-3)*sin(th)),c.lineTo(fx+6,y+20),c.lineTo(X,y+20),c.closePath(),c.fill(),c.stroke()} + c.strokeStyle='#111';c.lineWidth=7;c.beginPath();c.moveTo(X,78);c.lineTo(X+W,78);c.stroke() + for(const[w,s]of[[13,'#111'],[5,'#fff']])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.moveTo(186,30),c.lineTo(186,62),c.stroke() + c.strokeStyle='#111';c.fillStyle='#111' + const ly=op?4:0 + for(const d of[-1,1])c.beginPath(),c.arc(146+d*20,44+ly,6,0,T),c.fill() + c.fillStyle='#fff';for(const d of[-1,1])c.beginPath(),c.arc(144+d*20,42+ly,2,0,T),c.fill() + c.lineWidth=4.5;for(const d of[-1,1])c.beginPath(),c.moveTo(146+d*11,30),c.lineTo(146+d*27,34),c.stroke() + c.lineWidth=5;c.beginPath();op?c.ellipse(146,62,5,4,0,0,T):c.arc(146,66,8,1.2*PI,1.8*PI);c.stroke() + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(146+d*36,56,7,4,0,0,T),c.fill() + if(op){c.fillStyle='#a5d8ff';c.lineWidth=3;c.beginPath();c.moveTo(106,32);c.quadraticCurveTo(113,43,106,45);c.quadraticCurveTo(99,43,106,32);c.fill();c.stroke()} +} diff --git a/gen/uicolor/inbox/zero.js b/gen/uicolor/inbox/zero.js new file mode 100644 index 0000000..b26a674 --- /dev/null +++ b/gen/uicolor/inbox/zero.js @@ -0,0 +1,29 @@ +// inbox tray at zero turned into a tiny island: palm tree swaying, a cool sun in shades, the tray smiling with relaxed closed eyes +const{sin,PI}=Math,T=2*PI +export const frames=16,delay=100 +const TY='#b197fc',TD='#7950f2',WA='#74c0fc',SA='#ffe066',TK='#c08457',LF='#51cf66',CO='#8b5a3c',SU='#ffd43b',SR='#ffa94d',BL='#ffa8a8' +export default(c,t)=>{ + c.save();c.translate(204,52+3*sin(t*T));c.save();c.rotate(t*T/8) + c.fillStyle=SR;c.lineWidth=4;for(let k=0;k<8;k++)c.save(),c.rotate(k*PI/4),c.beginPath(),c.roundRect(30,-5,13,10,5),c.fill(),c.stroke(),c.restore() + c.restore();c.fillStyle=SU;c.lineWidth=6;c.beginPath();c.arc(0,0,25,0,T);c.fill();c.stroke() + c.fillStyle='#343a40';c.lineWidth=3;for(const d of[-1,1])c.beginPath(),c.roundRect(d>0?2:-17,-8,15,10,4),c.fill(),c.stroke() + c.beginPath();c.moveTo(-2,-5);c.lineTo(2,-5);c.stroke() + c.lineWidth=3.5;c.beginPath();c.arc(0,6,7,.15*PI,.85*PI);c.stroke() + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(d*15,8,4,2.5,0,0,T),c.fill() + c.restore() + c.lineWidth=7;c.fillStyle=TD;c.beginPath();c.moveTo(54,140);c.lineTo(202,140);c.lineTo(226,172);c.lineTo(30,172);c.closePath();c.fill();c.stroke() + c.fillStyle=WA;c.beginPath();c.moveTo(62,148);c.lineTo(194,148);c.lineTo(212,172);c.lineTo(44,172);c.closePath();c.fill() + c.strokeStyle='#fff';c.lineWidth=4;for(const[x,o]of[[70,0],[184,.5]]){const w=3*sin(t*T*2+o*T);c.beginPath();c.arc(x+w,166,6,PI*1.1,PI*1.9);c.arc(x+12+w,166,6,PI*1.1,PI*1.9);c.stroke()} + c.strokeStyle='#111';c.lineWidth=6;c.fillStyle=SA;c.beginPath();c.ellipse(128,170,50,20,0,PI,T);c.fill();c.stroke() + c.save();c.translate(132,160);c.rotate(.05*sin(t*T)) + for(const[w,s]of[[20,'#111'],[11,TK]])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.moveTo(0,0),c.quadraticCurveTo(8,-44,-22,-76),c.stroke() + c.strokeStyle='#111';c.lineWidth=3;c.beginPath();for(const[x,y]of[[1,-16],[2,-34],[-4,-52]])c.moveTo(x-6,y+1),c.lineTo(x+5,y-1);c.stroke() + c.translate(-22,-78) + ;[-2.75,-2.15,-1.35,-.65,-.05].forEach((a,k)=>{c.save();c.rotate(a+.09*sin(t*T*2+k));c.fillStyle=LF;c.lineWidth=5;c.beginPath();c.moveTo(0,0);c.quadraticCurveTo(28,-20,58,4);c.quadraticCurveTo(44,0,40,10);c.quadraticCurveTo(34,0,26,6);c.quadraticCurveTo(14,-4,0,0);c.fill();c.stroke();c.restore()}) + c.fillStyle=CO;c.lineWidth=4;for(const[x,y]of[[-6,8],[7,9]])c.beginPath(),c.arc(x,y,7,0,T),c.fill(),c.stroke() + c.restore() + c.lineWidth=7;c.fillStyle=TY;c.beginPath();c.moveTo(30,172);c.lineTo(82,172);c.lineTo(94,190);c.lineTo(162,190);c.lineTo(174,172);c.lineTo(226,172);c.lineTo(212,232);c.lineTo(44,232);c.closePath();c.fill();c.stroke() + c.lineWidth=5;for(const d of[-1,1])c.beginPath(),c.arc(128+d*24,212,7,1.15*PI,1.85*PI),c.stroke() + c.beginPath();c.arc(128,214,8,.15*PI,.85*PI);c.stroke() + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,218,8,5,0,0,T),c.fill() +} diff --git a/gen/uicolor/jar/empty.js b/gen/uicolor/jar/empty.js new file mode 100644 index 0000000..daa3b7d --- /dev/null +++ b/gen/uicolor/jar/empty.js @@ -0,0 +1,26 @@ +// glass cookie jar with nothing but crumbs at the bottom, its lid rattling and hopping, the jar peering down sadly +const{sin,cos,PI,abs}=Math,T=2*PI +export const frames=16,delay=70 +const GL='#e7f5ff',GS='#a5d8ff',LD='#ff8787',LK='#ffd43b',CR='#e0a96d',CH='#8b5a3c',BL='#ffa8a8' +const CB=[[84,224,8],[104,229,6],[122,225,9],[146,229,6],[164,224,8],[182,229,5],[134,231,4],[94,231,4]] +const body=c=>{c.beginPath();c.moveTo(74,96);c.quadraticCurveTo(48,100,48,132);c.lineTo(48,208);c.quadraticCurveTo(48,236,76,236);c.lineTo(180,236);c.quadraticCurveTo(208,236,208,208);c.lineTo(208,132);c.quadraticCurveTo(208,100,182,96);c.closePath()} +export default(c,t,i)=>{ + const h=abs(sin(t*T*2)),ly=-14*h,lr=.13*sin(t*T*6)*h,sh=(i%2?1.5:-1.5)*h + c.translate(sh,0) + body(c);c.fillStyle=GL;c.fill() + CB.forEach(([x,y,r],k)=>{const dy=-4*h*abs(sin(k*1.7+t*T*4));c.save();c.translate(x,y+dy);c.rotate(k+dy/4);c.fillStyle=CR;c.lineWidth=3;c.beginPath();for(let n=0;n<6;n++){const a=n*T/6,q=r*(n%2?.75:1);c.lineTo(cos(a)*q,sin(a)*q)}c.closePath();c.fill();c.stroke();if(r>6)c.fillStyle=CH,c.beginPath(),c.arc(1,-1,2,0,T),c.fill();c.restore()}) + c.lineWidth=7;body(c);c.stroke() + c.strokeStyle='#fff';c.lineWidth=8;c.beginPath();c.moveTo(66,128);c.lineTo(66,196);c.stroke();c.lineWidth=6;c.beginPath();c.moveTo(66,210);c.lineTo(66,214);c.stroke() + c.strokeStyle='#111';c.fillStyle=GS;c.lineWidth=6;c.beginPath();c.roundRect(68,78,120,22,8);c.fill();c.stroke() + c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.arc(128+d*24,146,6.5,0,T),c.fill() + c.fillStyle='#fff';for(const d of[-1,1])c.beginPath(),c.arc(126+d*24,148,2.2,0,T),c.fill() + c.lineWidth=4.5;for(const d of[-1,1])c.beginPath(),c.moveTo(128+d*14,128),c.lineTo(128+d*32,133),c.stroke() + c.lineWidth=5;c.beginPath();c.arc(128,176,11,1.2*PI,1.8*PI);c.stroke() + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,162,8,5,0,0,T),c.fill() + c.save();c.translate(128,70+ly);c.rotate(lr) + c.fillStyle=LD;c.lineWidth=7;c.beginPath();c.roundRect(-16,-38,32,22,10);c.fill();c.stroke() + c.beginPath();c.roundRect(-70,-22,140,30,13);c.fill();c.stroke() + c.fillStyle=LK;c.lineWidth=4;c.beginPath();c.arc(0,-28,4.5,0,T);c.fill();c.stroke() + c.strokeStyle='#fff';c.lineWidth=5;c.beginPath();c.moveTo(-54,-12);c.lineTo(-30,-12);c.stroke();c.restore() + if(h>.5)for(const d of[-1,1])for(const[w,s]of[[10,'#111'],[4,'#fff']])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.moveTo(128+d*82,56+ly),c.lineTo(128+d*96,48+ly),c.moveTo(128+d*84,70+ly),c.lineTo(128+d*100,70+ly),c.stroke() +} diff --git a/gen/uicolor/loading/candy.js b/gen/uicolor/loading/candy.js new file mode 100644 index 0000000..c5ce586 --- /dev/null +++ b/gen/uicolor/loading/candy.js @@ -0,0 +1,31 @@ +// a wrapped candy as a progress bar: peppermint stripes scroll in and fill it up, a shine sweeps across when it's full, then it drains and starts again +const{sin,PI,min,max}=Math,T=2*PI +export const frames=24,delay=70 +const ST='#f06595',TK='#ffdeeb',WR='#ffd43b',WD='#fab005' +const L=58,R=198,Y=128,H=42 +const pill=c=>{c.beginPath();c.roundRect(L,Y-H,R-L,H*2,H)} +const spark=(c,x,y,s)=>{c.lineWidth=4;c.fillStyle='#fff';c.beginPath();c.moveTo(x,y-s);for(const[px,py,qx,qy]of[[s,0,s*.2,-s*.2],[0,s,s*.2,s*.2],[-s,0,-s*.2,s*.2],[0,-s,-s*.2,-s*.2]])c.quadraticCurveTo(x+qx,y+qy,x+px,y+py);c.fill();c.stroke()} +const ss=x=>x<=0?0:x>=1?1:x*x*(3-2*x) +export default(c,t)=>{ + const f=ss(t/.66),d=ss((t-.86)/.14),x0=L+(R-L)*d,x1=L+(R-L)*f,sh=(t-.68)/.14 + for(const s of[-1,1]){ + c.save();c.translate(128,Y);c.scale(s,1);c.translate(-128,-Y) + const w=3*sin(T*t*2),P=[[16,Y-46],[28,Y-30],[12,Y-14],[26,Y],[12,Y+14],[28,Y+30],[16,Y+46]].map(([x,y])=>[x-w,y]) + c.fillStyle=WR;c.beginPath();c.moveTo(L-6,Y-12);P.forEach(([x,y])=>c.lineTo(x,y));c.lineTo(L-6,Y+12);c.closePath();c.fill();c.stroke() + c.strokeStyle=WD;c.lineWidth=4;for(const k of[0,2,4,6])c.beginPath(),c.moveTo(L-14,Y+(k-3)*3),c.lineTo(P[k][0]+8,P[k][1]+(3-k)*1.5),c.stroke() + c.strokeStyle='#111';c.fillStyle=WD;c.lineWidth=6;c.beginPath();c.roundRect(L-16,Y-15,22,30,9);c.fill();c.stroke() + c.restore();c.lineWidth=7 + } + c.fillStyle=TK;pill(c);c.fill() + c.save();pill(c);c.clip() + if(x1>x0+.5){ + c.beginPath();c.rect(x0,0,x1-x0,256);c.clip();c.fillStyle='#fff';c.fillRect(0,0,256,256) + c.fillStyle=ST;const o=t*2*40;for(let x=L-80+o%40;x0&&sh<1){const gx=L-30+(R-L+60)*sh;c.fillStyle='#fff';c.beginPath();c.moveTo(gx,Y-H);c.lineTo(gx+22,Y-H);c.lineTo(gx-2,Y+H);c.lineTo(gx-24,Y+H);c.closePath();c.fill()} + c.restore() + c.strokeStyle='#fff';c.lineWidth=7;c.beginPath();c.moveTo(L+28,Y-26);c.lineTo(R-34,Y-26);c.stroke() + c.strokeStyle='#111';c.lineWidth=7;pill(c);c.stroke() + if(t>.66&&t<.88)for(const[x,y,o]of[[84,56,0],[178,54,.4],[124,206,.2],[206,198,.6]]){const s=12*sin(PI*min(1,max(0,(t-.66)/.22*1.4-o*.4)));if(s>1.5)spark(c,x,y,s)} +} diff --git a/gen/uicolor/loading/cat.js b/gen/uicolor/loading/cat.js new file mode 100644 index 0000000..a55cc1b --- /dev/null +++ b/gen/uicolor/loading/cat.js @@ -0,0 +1,26 @@ +// orange tabby curled in a ring chasing its own tail round and round like a spinner, paws scrabbling, eyes locked on the tail tip +const{sin,cos,PI,atan2}=Math,T=2*PI +export const frames=16,delay=60 +const OR='#ffa94d',OD='#f08c00',PK='#ffc9c9',BL='#ff8787',X=128,Y=134,R=58 +const at=(a,r=R)=>[X+cos(a)*r,Y+sin(a)*r] +export default(c,t,i)=>{ + const h=t*T,tail=[];for(let s=0;s<=1.001;s+=.1){const a=h-3.3-s*1.9,r=R+8*sin(s*PI)+6*s*sin(T*t*4+s*3);tail.push(at(a,r))} + const line=(pts,w,col)=>{c.lineWidth=w;c.strokeStyle=col;c.beginPath();pts.forEach(([x,y])=>c.lineTo(x,y));c.stroke()} + const tp=tail.at(-1) + line(tail,34,'#111');line(tail,20,OR);line(tail.slice(-3),20,'#fff') + for(const[a,ph]of[[h-.75,0],[h-3.1,PI]])for(const s of[-1,1]){const q=a+.22*sin(T*t*4+ph+(s>0?0:PI)),[x,y]=at(q,R+s*26);c.fillStyle='#fff';c.lineWidth=5;c.strokeStyle='#111';c.beginPath();c.ellipse(x,y,11,8,q,0,T);c.fill();c.stroke()} + c.strokeStyle='#111';c.lineWidth=54;c.beginPath();c.arc(X,Y,R,h-3.3,h-.2);c.stroke() + c.lineWidth=40;c.strokeStyle=OR;c.beginPath();c.arc(X,Y,R,h-3.3,h-.2);c.stroke() + c.lineWidth=6;c.strokeStyle=OD;for(let k=0;k<4;k++){const a=h-1.3-k*.52;c.beginPath();c.moveTo(...at(a-.08,R-14));c.lineTo(...at(a,R+14));c.stroke()} + const[hx,hy]=at(h,R+2),d=atan2(tp[1]-hy,tp[0]-hx),ex=4*cos(d),ey=4*sin(d) + c.strokeStyle='#111';c.lineWidth=7 + for(const s of[-1,1]){c.fillStyle=OR;c.beginPath();c.moveTo(hx+s*28,hy-6);c.lineTo(hx+s*24,hy-44);c.lineTo(hx+s*4,hy-26);c.closePath();c.fill();c.stroke();c.fillStyle=PK;c.beginPath();c.moveTo(hx+s*22,hy-14);c.lineTo(hx+s*22,hy-34);c.lineTo(hx+s*12,hy-24);c.closePath();c.fill()} + c.fillStyle=OR;c.beginPath();c.ellipse(hx,hy,34,29,0,0,T);c.fill();c.stroke() + c.lineWidth=4;c.strokeStyle=OD;for(const s of[-1,0,1])c.beginPath(),c.moveTo(hx+s*9,hy-27),c.lineTo(hx+s*7,hy-17),c.stroke() + c.fillStyle='#fff';c.beginPath();c.ellipse(hx,hy+12,14,10,0,0,T);c.fill() + c.fillStyle='#111';for(const s of[-1,1])c.beginPath(),c.arc(hx+s*14+ex,hy-1+ey,5.5,0,T),c.fill() + c.fillStyle='#fff';for(const s of[-1,1])c.beginPath(),c.arc(hx+s*14+ex-2,hy-3+ey,2,0,T),c.fill() + c.fillStyle='#ff8fab';c.beginPath();c.moveTo(hx-4,hy+6);c.lineTo(hx+4,hy+6);c.lineTo(hx,hy+10);c.closePath();c.fill() + c.strokeStyle='#111';c.lineWidth=3;c.beginPath();c.moveTo(hx-7,hy+13);c.quadraticCurveTo(hx-3.5,hy+17,hx,hy+12);c.quadraticCurveTo(hx+3.5,hy+17,hx+7,hy+13);c.stroke() + c.fillStyle=BL;for(const s of[-1,1])c.beginPath(),c.ellipse(hx+s*24,hy+9,6,3.5,0,0,T),c.fill() +} diff --git a/gen/uicolor/loading/coffee.js b/gen/uicolor/loading/coffee.js new file mode 100644 index 0000000..aa90e2b --- /dev/null +++ b/gen/uicolor/loading/coffee.js @@ -0,0 +1,33 @@ +// smiling coffee machine drips coffee into a glass mug that fills up bit by bit, steams when full, then empties to brew again +const{sin,PI,min}=Math,T=2*PI +export const frames=24,delay=80 +const BO='#ff8787',BD='#fa5252',RC='#495057',GL='#d0ebff',CO='#a9744f',CR='#e8b27a',BL='#ffc9c9',ME='#ced4da' +const ss=x=>x<=0?0:x>=1?1:x*x*(3-2*x) +export default(c,t)=>{ + const f=ss(t/.74)-ss((t-.88)/.12),lv=204-8-62*f,brew=t<.76 + c.fillStyle=BO;c.beginPath();c.roundRect(34,14,188,226,24);c.fill();c.stroke() + c.fillStyle=RC;c.beginPath();c.roundRect(56,88,144,124,[10,10,4,4]);c.fill();c.lineWidth=5;c.stroke() + c.fillStyle=ME;c.beginPath();c.moveTo(112,86);c.lineTo(144,86);c.lineTo(136,104);c.lineTo(120,104);c.closePath();c.fill();c.stroke() + c.fillStyle=ME;c.beginPath();c.roundRect(48,208,160,16,6);c.fill();c.stroke() + c.lineWidth=3;for(let x=64;x<200;x+=16)c.beginPath(),c.moveTo(x,212),c.lineTo(x,220),c.stroke() + c.lineWidth=7 + for(const[w,s]of[[22,'#111'],[10,GL]])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.moveTo(166,146),c.bezierCurveTo(194,144,194,190,164,188),c.stroke() + c.strokeStyle='#111';c.lineWidth=7 + const mug=()=>{c.beginPath();c.roundRect(86,128,82,78,[4,4,16,16])} + c.fillStyle=GL;mug();c.fill() + c.save();mug();c.clip() + if(f>.01){c.fillStyle=CO;c.fillRect(80,lv,96,90);c.fillStyle=CR;c.beginPath();c.ellipse(127,lv,46,4+2*sin(T*t*4),0,0,T);c.fill()} + c.strokeStyle='#fff';c.lineWidth=7;c.beginPath();c.moveTo(100,142);c.lineTo(100,174);c.stroke() + c.restore();mug();c.stroke() + if(brew)for(let k=0;k<4;k++){const p=(t*8+k/4)%1,y=106+p*(lv-106);if(y.76&&t<.92 + if(t>.7&&t<.94)for(let k=0;k<2;k++){const a=min(1,(t-.7)/.08)*min(1,(.94-t)/.06),pts=[];for(let s=0;s<=1;s+=.125)pts.push([116+k*24+5*sin(T*(s-t*2)+k*2),122-26*s*a]);c.strokeStyle='#fff';c.lineWidth=5;c.beginPath();pts.forEach(([x,y])=>c.lineTo(x,y));c.stroke()} + c.strokeStyle='#111' + if(happy){c.lineWidth=5;for(const d of[-1,1])c.beginPath(),c.arc(128+d*26,54,7,PI*1.15,PI*1.85),c.stroke()} + else{c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.arc(128+d*26,50,6.5,0,T),c.fill();c.fillStyle='#fff';for(const d of[-1,1])c.beginPath(),c.arc(128+d*26-2,48,2.3,0,T),c.fill()} + c.lineWidth=5;c.beginPath();c.arc(128,58,happy?11:8,.15*PI,.85*PI);c.stroke() + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*48,62,9,5,0,0,T),c.fill() + c.lineWidth=4;c.fillStyle=brew&&Math.floor(t*12)%2?'#ffd43b':'#69db7c';c.beginPath();c.arc(196,36,7,0,T);c.fill();c.stroke() + c.fillStyle='#fff';c.beginPath();c.arc(60,36,7,0,T);c.fill();c.stroke() +} diff --git a/gen/uicolor/loading/gummies.js b/gen/uicolor/loading/gummies.js new file mode 100644 index 0000000..268963d --- /dev/null +++ b/gen/uicolor/loading/gummies.js @@ -0,0 +1,24 @@ +// three gummy bears, red, yellow and green, hopping one after another in a wave like a loading dots row +const{sin,PI,max}=Math,T=2*PI +export const frames=16,delay=70 +const B=[['#ff6b6b','#ffa8a8'],['#ffd43b','#fff3bf'],['#69db7c','#b2f2bb']],BL='#ff8787' +const shapes=c=>[()=>c.ellipse(-14,-12,12,13,0,0,T),()=>c.ellipse(14,-12,12,13,0,0,T),()=>c.ellipse(-25,-44,10,14,.5,0,T),()=>c.ellipse(25,-44,10,14,-.5,0,T),()=>c.ellipse(0,-36,26,29,0,0,T),()=>c.arc(-18,-96,10,0,T),()=>c.arc(18,-96,10,0,T),()=>c.arc(0,-76,25,0,T)] +export default(c,t)=>{ + B.forEach(([col,lt],k)=>{ + const h=max(0,sin(T*(t-k*.16))),y=-50*h**.8,sq=h<.15?1-(.15-h)*.8:1+.06*h*(1-h)*4 + c.save();c.translate(48+k*80,214);c.scale(2-sq,sq);c.translate(0,y/sq);c.scale(1.04,1.04) + const S=shapes(c) + c.fillStyle='#111';for(const f of S)c.beginPath(),f(),c.lineWidth=14,c.strokeStyle='#111',c.stroke() + c.fillStyle=col;for(const f of S)c.beginPath(),f(),c.fill() + c.fillStyle=lt;c.beginPath();c.ellipse(0,-32,15,17,0,0,T);c.fill();c.beginPath();c.ellipse(0,-68,12,8,0,0,T);c.fill() + for(const d of[-1,1])c.beginPath(),c.arc(d*18,-96,4.5,0,T),c.fill() + c.strokeStyle='#111';c.lineWidth=3;c.beginPath();c.moveTo(-6,-22);c.quadraticCurveTo(-8,-12,-14,-6);c.moveTo(6,-22);c.quadraticCurveTo(8,-12,14,-6);c.stroke() + c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.arc(d*10,-80,4,0,T),c.fill() + c.fillStyle='#fff';for(const d of[-1,1])c.beginPath(),c.arc(d*10-1.5,-81.5,1.5,0,T),c.fill() + c.fillStyle='#111';c.beginPath();c.ellipse(0,-71,4,3,0,0,T);c.fill() + c.lineWidth=3;c.beginPath();c.moveTo(-5,-65);c.quadraticCurveTo(-2.5,-62,0,-66);c.quadraticCurveTo(2.5,-62,5,-65);c.stroke() + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(d*17,-70,4.5,2.8,0,0,T),c.fill() + c.strokeStyle='#fff';c.lineWidth=5;c.beginPath();c.arc(0,-76,18,PI*1.15,PI*1.4);c.stroke();c.beginPath();c.arc(0,-36,20,PI*1.05,PI*1.3);c.stroke() + c.restore() + }) +} diff --git a/gen/uicolor/loading/microwave.js b/gen/uicolor/loading/microwave.js new file mode 100644 index 0000000..0635997 --- /dev/null +++ b/gen/uicolor/loading/microwave.js @@ -0,0 +1,39 @@ +// mint microwave humming away: light on inside, a smiling soup bowl turning round on the spinning plate, the green timer glowing and counting down +const{sin,cos,PI,floor}=Math,T=2*PI +export const frames=20,delay=90 +const BO='#63e6be',BD='#20c997',IN='#fff3bf',BW='#ff8787',SO='#ffd43b',DS='#343a40',GG='#2f9e44',GB='#b2f2bb',BL='#ffa8a8' +const SEG=[63,6,91,79,102,109,125,7,127,111] +const digit=(c,n,x,y,w=11,h=20)=>{const P=[[0,0,w,0],[w,0,w,h/2],[w,h/2,w,h],[0,h,w,h],[0,h/2,0,h],[0,0,0,h/2],[0,h/2,w,h/2]];c.beginPath();P.forEach(([a,b,e,f],k)=>{if(SEG[n]>>k&1)c.moveTo(x+a,y+b),c.lineTo(x+e,y+f)})} +export default(c,t,i)=>{ + const th=t*T,PX=98,PY=162 + c.fillStyle=BD;for(const x of[44,196])c.beginPath(),c.roundRect(x-14,200,28,22,8),c.fill(),c.stroke() + c.fillStyle=BO;c.beginPath();c.roundRect(14,44,228,166,24);c.fill();c.stroke() + c.fillStyle=BD;c.beginPath();c.roundRect(28,58,144,138,16);c.fill();c.lineWidth=5;c.stroke() + const win=()=>{c.beginPath();c.roundRect(40,70,118,114,10)} + c.fillStyle=IN;win();c.fill() + c.save();win();c.clip() + c.fillStyle='#ffe066';c.beginPath();c.ellipse(99,70,44,16,0,0,T);c.fill() + c.fillStyle='#fff';c.beginPath();c.ellipse(PX,PY,46,12,0,0,T);c.fill();c.lineWidth=5;c.stroke() + c.fillStyle='#dee2e6';for(let k=0;k<6;k++){const a=th+k*T/6;if(sin(a)>0)continue;c.beginPath();c.arc(PX+cos(a)*36,PY+sin(a)*8,2.6,0,T);c.fill()} + const by=PY-6 + c.fillStyle=BW;c.lineWidth=6;c.beginPath();c.ellipse(PX,by-32,32,8,0,0,PI,true);c.ellipse(PX,by-32,32,34,0,0,PI);c.fill();c.stroke() + c.save();c.beginPath();c.ellipse(PX,by-32,32,34,0,0,PI);c.clip() + for(const[o,face]of[[0,1],[PI,0]]){const a=th+o,cx=PX+22*sin(a),k=cos(a);if(k<.05)continue + c.save();c.translate(cx,by-11);c.scale(k,1) + if(face){c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.arc(d*9,-4,3.5,0,T),c.fill();c.fillStyle='#fff';for(const d of[-1,1])c.beginPath(),c.arc(d*9-1.2,-5.2,1.3,0,T),c.fill();c.strokeStyle='#111';c.lineWidth=3;c.beginPath();c.arc(0,0,4.5,.15*PI,.85*PI);c.stroke();c.fillStyle='#ffc9c9';for(const d of[-1,1])c.beginPath(),c.ellipse(d*16,1,4,2.5,0,0,T),c.fill()} + else{c.fillStyle='#fff';c.beginPath();c.moveTo(0,6);c.bezierCurveTo(-12,-2,-7,-11,0,-5);c.bezierCurveTo(7,-11,12,-2,0,6);c.fill()} + c.restore()} + c.restore() + c.fillStyle=SO;c.beginPath();c.ellipse(PX,by-32,27,6,0,0,T);c.fill();c.lineWidth=4;c.stroke() + c.lineWidth=6;c.beginPath();c.ellipse(PX,by-32,32,8,0,0,T);c.stroke() + for(let k=0;k<2;k++){const pts=[];for(let s=0;s<=1;s+=.125)pts.push([PX-10+k*20+4*sin(T*(s-t*2)+k*2),by-46-30*s]);for(const[w,st]of[[9,'#111'],[4,'#fff']]){c.lineWidth=w;c.strokeStyle=st;c.beginPath();pts.forEach(([x,y])=>c.lineTo(x,y));c.stroke()}} + c.strokeStyle='#fff';c.lineWidth=7;c.beginPath();c.moveTo(52,92);c.lineTo(62,82);c.moveTo(52,108);c.lineTo(76,84);c.stroke() + c.restore();c.strokeStyle='#111';c.lineWidth=6;win();c.stroke() + c.lineWidth=7;c.fillStyle=DS;c.beginPath();c.roundRect(180,64,50,34,8);c.fill();c.stroke() + const n=20-i;for(const[w,col]of[[7,GG],[3.5,GB]]){c.lineWidth=w;c.strokeStyle=col;digit(c,floor(n/10),189,71);c.stroke();digit(c,n%10,210,71);c.stroke()} + c.strokeStyle='#111';c.lineWidth=4 + for(let r=0;r<2;r++)for(let q=0;q<3;q++){c.fillStyle=['#fff','#ffd43b','#ff8787'][q];c.beginPath();c.roundRect(182+q*16,110+r*18,12,12,4);c.fill();c.stroke()} + c.lineWidth=6;c.fillStyle='#fff';c.beginPath();c.arc(205,170,16,0,T);c.fill();c.stroke() + c.save();c.translate(205,170);c.rotate(-th);c.lineWidth=5;c.beginPath();c.moveTo(0,0);c.lineTo(0,-10);c.stroke();c.restore() + c.fillStyle='#fff';c.lineWidth=5;c.beginPath();c.roundRect(160,84,10,90,5);c.fill();c.stroke() +} diff --git a/gen/uicolor/loading/pinwheel.js b/gen/uicolor/loading/pinwheel.js new file mode 100644 index 0000000..f4e67d5 --- /dev/null +++ b/gen/uicolor/loading/pinwheel.js @@ -0,0 +1,21 @@ +// four-color paper pinwheel whirling round on its stick in the breeze, little wind swooshes blowing past +const{sin,cos,PI}=Math,T=2*PI +export const frames=16,delay=60 +const C=['#ff6b6b','#ffd43b','#4dabf7','#69db7c'],L=['#ffa8a8','#fff3bf','#a5d8ff','#b2f2bb'],X=128,Y=106,R=88,BL='#ffa8a8' +const p=(a,r)=>[cos(a)*r,sin(a)*r] +export default(c,t)=>{ + for(const[y,o,w]of[[178,0,50],[206,.5,58]]){const q=(t+o)%1,x=16+q*40,a=sin(PI*q) + if(a>.15)for(const[lw,st]of[[11,'#111'],[5,'#fff']]){c.lineWidth=lw;c.strokeStyle=st;c.beginPath();c.moveTo(x,y);c.quadraticCurveTo(x+w*a*.5,y-6*a,x+w*a,y);c.stroke()}} + c.strokeStyle='#111' + for(const[w,s]of[[22,'#111'],[10,'#e8a15a']])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.moveTo(X,Y),c.lineTo(X,240),c.stroke() + c.strokeStyle='#111';c.lineWidth=7 + c.save();c.translate(X,Y);const rot=-t*T + for(let k=0;k<4;k++){const a=rot+k*PI/2 + c.fillStyle=C[k];c.beginPath();c.moveTo(0,0);c.lineTo(...p(a,R));c.quadraticCurveTo(...p(a+1.2,R*1.02),...p(a+PI/2,R*.4));c.closePath();c.fill();c.stroke() + c.fillStyle=L[k];c.lineWidth=5;c.beginPath();c.moveTo(0,0);c.lineTo(...p(a,R-6));c.quadraticCurveTo(...p(a+.55,R*.62),...p(a+.85,R*.26));c.closePath();c.fill();c.stroke();c.lineWidth=7} + c.restore() + c.fillStyle='#fff';c.beginPath();c.arc(X,Y,20,0,T);c.fill();c.stroke() + c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.arc(X+d*7,Y-2,3.5,0,T),c.fill() + c.lineWidth=3.5;c.beginPath();c.arc(X,Y+3,4.5,.15*PI,.85*PI);c.stroke() + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(X+d*12,Y+5,3.5,2.2,0,0,T),c.fill() +} diff --git a/gen/uicolor/loading/pizza.js b/gen/uicolor/loading/pizza.js new file mode 100644 index 0000000..c76cd86 --- /dev/null +++ b/gen/uicolor/loading/pizza.js @@ -0,0 +1,29 @@ +// pizza progress circle: slices pop onto the plate one by one clockwise until the pie is whole and smiling with sparkles, then all the slices shrink away to load again +const{sin,cos,PI,min,max}=Math,T=2*PI +export const frames=24,delay=80 +const CR='#e8a15a',CH='#ffd43b',PP='#fa5252',PR='#a5d8ff',X=128,Y=128,R=92 +const ss=x=>x<=0?0:x>=1?1:x*x*(3-2*x) +const back=p=>p<=0?0:p>=1?1:1+2.7*(p-1)**3+1.7*(p-1)**2 +export default(c,t)=>{ + const out=1-ss((t-.86)/.1) + c.fillStyle=PR;c.beginPath();c.arc(X,Y,112,0,T);c.fill();c.stroke() + c.fillStyle='#fff';c.beginPath();c.arc(X,Y,100,0,T);c.fill();c.lineWidth=4;c.stroke() + c.strokeStyle='#ced4da';c.lineWidth=4;c.setLineDash([6,8]);for(let k=0;k<8;k++){const a=-PI/2+k*PI/4;c.beginPath();c.moveTo(X+cos(a)*14,Y+sin(a)*14);c.lineTo(X+cos(a)*R,Y+sin(a)*R);c.stroke()} + c.beginPath();c.arc(X,Y,R-2,0,T);c.stroke();c.setLineDash([]);c.strokeStyle='#111' + for(let k=0;k<8;k++){ + const s=back((t-k/12)/.08)*out;if(s<.02)continue + const a0=-PI/2+k*PI/4,a1=a0+PI/4,m=(a0+a1)/2,cx=X+cos(m)*(48+3),cy=Y+sin(m)*(48+3) + c.save();c.translate(cx,cy);c.scale(s,s);c.translate(-cx,-cy);c.translate(cos(m)*3,sin(m)*3) + c.lineWidth=6;c.fillStyle=CR;c.beginPath();c.moveTo(X,Y);c.arc(X,Y,R,a0,a1);c.closePath();c.fill();c.stroke() + c.fillStyle=CH;c.beginPath();c.moveTo(X,Y);c.arc(X,Y,R-16,a0+.03,a1-.03);c.closePath();c.fill() + c.lineWidth=4;c.fillStyle=PP;for(const[r,o]of[[62,-.13],[40,.12]]){const a=m+o;c.beginPath();c.arc(X+cos(a)*r,Y+sin(a)*r,8,0,T);c.fill();c.stroke()} + c.restore() + } + const f=t>.72&&t<.86 + if(f){c.fillStyle=CH;c.beginPath();c.arc(X,Y,27,0,T);c.fill() + c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.arc(X+d*11,Y-4,5,0,T),c.fill() + c.fillStyle='#fff';for(const d of[-1,1])c.beginPath(),c.arc(X+d*11-1.6,Y-5.6,1.8,0,T),c.fill() + c.lineWidth=4;c.beginPath();c.arc(X,Y+3,7,.15*PI,.85*PI);c.stroke() + c.fillStyle='#ff8787';for(const d of[-1,1])c.beginPath(),c.ellipse(X+d*19,Y+5,5,3,0,0,T),c.fill()} + if(t>.68&&t<.9)for(const[x,y,o]of[[26,30,0],[230,30,.3],[22,66,.45],[234,66,.15]]){const q=(t-.68)/.22*1.5-o,z=12*sin(PI*min(1,max(0,q)));if(z>1.5){c.lineWidth=4;c.fillStyle='#fff';c.beginPath();c.moveTo(x,y-z);for(const[px,py,qx,qy]of[[z,0,z*.2,-z*.2],[0,z,z*.2,z*.2],[-z,0,-z*.2,z*.2],[0,-z,-z*.2,-z*.2]])c.quadraticCurveTo(x+qx,y+qy,x+px,y+py);c.fill();c.stroke()}} +} diff --git a/gen/uicolor/loading/rainbow.js b/gen/uicolor/loading/rainbow.js new file mode 100644 index 0000000..8d5a78b --- /dev/null +++ b/gen/uicolor/loading/rainbow.js @@ -0,0 +1,25 @@ +// rainbow loader between two smiling clouds: the empty arch fills in band by band from red to violet, sparkles when complete, then wipes clear to start over +const{sin,PI,min,max}=Math,T=2*PI +export const frames=24,delay=80 +const C=['#ff6b6b','#ffa94d','#ffd43b','#69db7c','#4dabf7','#b197fc'],X=128,Y=182,RO=114,RI=42,BW=(RO-RI)/6 +const cloud=(c,x,y)=>{ + const P=[[x-20,y+2,16],[x+2,y-10,21],[x+22,y+2,15]],base=()=>c.roundRect(x-36,y,72,24,12) + c.lineWidth=14;c.strokeStyle='#111';for(const[a,b,r]of P)c.beginPath(),c.arc(a,b,r,0,T),c.stroke();c.beginPath();base();c.stroke() + c.fillStyle='#fff';for(const[a,b,r]of P)c.beginPath(),c.arc(a,b,r,0,T),c.fill();c.beginPath();base();c.fill() + c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.arc(x+2+d*9,y+6,3,0,T),c.fill() + c.lineWidth=3;c.beginPath();c.arc(x+2,y+10,4.5,.15*PI,.85*PI);c.stroke() + c.fillStyle='#ffc9c9';for(const d of[-1,1])c.beginPath(),c.ellipse(x+2+d*18,y+11,4,2.5,0,0,T),c.fill();c.lineWidth=7 +} +const spark=(c,x,y,s)=>{c.lineWidth=4;c.fillStyle='#fff';c.beginPath();c.moveTo(x,y-s);for(const[px,py,qx,qy]of[[s,0,s*.2,-s*.2],[0,s,s*.2,s*.2],[-s,0,-s*.2,s*.2],[0,-s,-s*.2,-s*.2]])c.quadraticCurveTo(x+qx,y+qy,x+px,y+py);c.fill();c.stroke()} +export default(c,t)=>{ + const q=max(0,min(1,(t-.8)/.14)) + c.fillStyle='#fff';c.beginPath();c.arc(X,Y,RO,PI,0);c.arc(X,Y,RI,0,PI,true);c.closePath();c.fill() + c.lineCap='butt' + C.forEach((col,k)=>{const p=max(0,min(1,(t-k*.1)/.12)),a0=PI+PI*q,a1=PI+PI*p;if(a1>a0+.01){c.strokeStyle=col;c.lineWidth=BW+.8;c.beginPath();c.arc(X,Y,RO-BW*(k+.5),a0,a1);c.stroke()}}) + c.lineCap='round';c.strokeStyle='#111';c.lineWidth=7 + c.beginPath();c.arc(X,Y,RO,PI,0);c.arc(X,Y,RI,0,PI,true);c.closePath();c.stroke() + const h0=PI*max(1.1,1+q),h1=PI*min(1.3,1+min(1,t/.12));c.strokeStyle='#fff';c.lineWidth=5;if(h1>h0+.05)c.beginPath(),c.arc(X,Y,RO-7,h0,h1),c.stroke() + c.strokeStyle='#111' + if(t>.68&&t<.84)for(const[x,y,o]of[[128,40,0],[40,72,.33],[216,72,.66]]){const s=13*sin(PI*((t-.68)/.16));if(s>1.5)spark(c,x,y,s*1.2*(1-o*.3))} + cloud(c,X-(RO+RI)/2,Y+4+Math.round(2*sin(T*t)));cloud(c,X+(RO+RI)/2,Y+4+Math.round(2*sin(T*t+PI))) +} diff --git a/gen/uicolor/loading/snail.js b/gen/uicolor/loading/snail.js new file mode 100644 index 0000000..b99f2e3 --- /dev/null +++ b/gen/uicolor/loading/snail.js @@ -0,0 +1,39 @@ +// a snail slowly crawls along a progress bar dragging the slimy fill along behind it, at the end it ducks into its shell and rolls back to the start +const{sin,cos,PI,min,max}=Math,T=2*PI +export const frames=24,delay=90 +const SH='#b197fc',SD='#7950f2',BD='#ffd8a8',FL='#63e6be',BL='#ff8787' +const GY=170,L=14,R=242,K=1.34,XA=L+56*K,XB=R-66*K +const ss=x=>x<=0?0:x>=1?1:x*x*(3-2*x) +const bar=c=>{c.beginPath();c.roundRect(L,GY,R-L,36,18)} +export default(c,t)=>{ + const u=min(1,t/.66),rb=ss((t-.74)/.18),e=t<.66?1:1-ss((t-.66)/.07)+ss((t-.92)/.08),x=t<.74?XA+(XB-XA)*u:XB-(XB-XA)*rb + const F=t<.74?L+(R-L)*u:t<.92?L+(R-L)*(x-XA)/(XB-XA):L,st=t<.66?4*sin(T*t*6):0,rot=-T*rb + c.fillStyle='#fff';bar(c);c.fill() + c.save();bar(c);c.clip();if(F>L+1){c.fillStyle=FL;c.fillRect(L,GY,F-L,40);c.strokeStyle='#fff';c.lineWidth=5;c.beginPath();c.moveTo(L+14,GY+9);c.lineTo(max(L+14,F-12),GY+9);c.stroke()}c.restore() + c.strokeStyle='#111';c.lineWidth=7;bar(c);c.stroke() + c.save();c.translate(x,GY);c.scale(K,K) + if(e>.02){ + c.save();c.translate(0,-30);c.scale(e,e);c.translate(0,30) + const hx=44+st,hy=-36+st*.3,parts=(o,f)=>{ + c.lineWidth=8+o;c.beginPath();c.moveTo(hx-8,hy-12);c.lineTo(hx-16,hy-36);c.moveTo(hx+6,hy-14);c.lineTo(hx+10,hy-38);c.stroke() + c.beginPath();c.arc(hx-16,hy-36,5+o/2,0,T);c.arc(hx+10,hy-38,5+o/2,0,T);f() + c.beginPath();c.roundRect(-50-o/2,-20-o/2,90+st+o,20+o,10+o/2);f() + c.lineWidth=26+o;c.beginPath();c.moveTo(hx-16,-10);c.lineTo(hx-2,hy+6);c.stroke() + c.beginPath();c.arc(hx,hy,19+o/2,0,T);f()} + c.strokeStyle=c.fillStyle='#111';parts(12,()=>c.fill()) + c.strokeStyle=c.fillStyle=BD;parts(0,()=>c.fill()) + c.strokeStyle='#111' + c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.arc(hx+2+d*8,hy-3,3.8,0,T),c.fill() + c.fillStyle='#fff';for(const d of[-1,1])c.beginPath(),c.arc(hx+.8+d*8,hy-4.5,1.4,0,T),c.fill() + c.lineWidth=3.5;c.beginPath();c.arc(hx+2,hy+3,5,.15*PI,.85*PI);c.stroke() + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(hx+2+d*13,hy+5,4,2.5,0,0,T),c.fill() + c.restore() + } + const sy=-34-10*e + c.save();c.translate(-4,sy);c.rotate(rot+.04*st) + c.fillStyle=SH;c.lineWidth=7;c.beginPath();c.arc(0,0,34,0,T);c.fill();c.stroke() + c.strokeStyle=SD;c.lineWidth=6;c.beginPath();for(let a=0;a<4.4*PI;a+=.2){const r=3+a*1.75;c.lineTo(cos(a)*r,sin(a)*r)}c.stroke() + c.strokeStyle='#fff';c.lineWidth=5;c.beginPath();c.arc(0,0,26,PI*1.1,PI*1.4);c.stroke() + c.restore() + c.restore() +} diff --git a/gen/uicolor/locked/vault.js b/gen/uicolor/locked/vault.js new file mode 100644 index 0000000..12c4422 --- /dev/null +++ b/gen/uicolor/locked/vault.js @@ -0,0 +1,41 @@ +// blue vault with its gold wheel spun hard by a straining face, then jammed and rattling, locked tight as a padlock badge pops up +const{sin,cos,PI}=Math,T=2*PI +export const frames=16,delay=85 +const BX='#4dabf7',DR='#ced4da',DRD='#adb5bd',G='#ffd43b',GD='#fab005',BL='#ffa8a8',SH='#868e96' +const ease=u=>u*u*(3-2*u) +export default(c,t)=>{ + const sp=t<.5,u=sp?ease(t/.5):1,rt=(t-.5)*2,rat=sp?0:.14*sin(T*rt*4)*(1-rt),ang=u*T/3+rat,sh=sp?0:2.5*sin(T*rt*8)*(1-rt) + const pop=t<.5?0:t<.6?ease((t-.5)/.1)*1.2:t<.68?1.2-.2*ease((t-.6)/.08):t<.9?1:1-ease((t-.9)/.1) + c.fillStyle=SH;for(const x of[38,182])c.beginPath(),c.roundRect(x,220,36,18,6),c.fill(),c.stroke() + c.fillStyle=BX;c.beginPath();c.roundRect(16,16,224,208,28);c.fill();c.stroke() + c.fillStyle=SH;for(const y of[64,170])c.beginPath(),c.roundRect(28,y-14,20,28,6),c.fill(),c.stroke() + c.translate(sh,0) + c.fillStyle=DRD;for(const a of[-.35,.35])c.beginPath(),c.roundRect(200,118+a*90-7,30,14,5),c.fill(),c.stroke() + c.fillStyle=DR;c.beginPath();c.arc(128,120,90,0,T);c.fill();c.stroke() + c.lineWidth=5;c.fillStyle=DRD;c.beginPath();c.arc(128,120,72,0,T);c.fill();c.stroke() + c.fillStyle=DR;for(let k=0;k<8;k++){const a=k*PI/4+PI/8;c.beginPath();c.arc(128+cos(a)*81,120+sin(a)*81,4.5,0,T);c.fill();c.lineWidth=3;c.stroke()} + c.save();c.translate(128,120);c.rotate(ang) + for(const[w,s]of[[14,'#111'],[6,GD]])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.arc(0,0,46,0,T),c.stroke() + for(let k=0;k<6;k++){c.rotate(PI/3);for(const[w,s]of[[13,'#111'],[5,GD]])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.moveTo(24,0),c.lineTo(58,0),c.stroke();c.strokeStyle='#111';c.lineWidth=5;c.fillStyle=G;c.beginPath();c.arc(62,0,9,0,T);c.fill();c.stroke()} + c.restore() + c.lineWidth=6;c.fillStyle=G;c.beginPath();c.arc(128,120,28,0,T);c.fill();c.stroke() + c.fillStyle='#fff';c.beginPath();c.ellipse(116,108,5,3,-.6,0,T);c.fill() + c.lineWidth=3.5;c.fillStyle='#111' + if(sp){ + for(const d of[-1,1])c.beginPath(),c.moveTo(128+d*15,114),c.lineTo(128+d*7,118),c.lineTo(128+d*15,122),c.stroke() + c.beginPath();c.moveTo(119,130);for(let k=1;k<=6;k++)c.lineTo(119+k*3,130+(k%2?-2.5:0));c.stroke() + }else{ + for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*10,117,3.5,4.5,0,0,T),c.fill() + c.lineWidth=3.5;for(const d of[-1,1])c.beginPath(),c.moveTo(128+d*15,108),c.lineTo(128+d*5,111),c.stroke() + c.beginPath();c.moveTo(120,128);c.quadraticCurveTo(128,132,137,125);c.stroke() + } + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*17,127,4.5,2.5,0,0,T),c.fill() + c.translate(-sh,0) + if(pop>.02){ + c.save();c.translate(206,52);c.scale(pop,pop);c.rotate(.15*sin(T*rt*2)) + for(const[w,s]of[[16,'#111'],[7,DR]])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.arc(0,-8,14,PI,0),c.lineTo(14,4),c.moveTo(-14,4),c.lineTo(-14,-8),c.stroke() + c.strokeStyle='#111';c.lineWidth=6;c.fillStyle=G;c.beginPath();c.roundRect(-24,-2,48,38,9);c.fill();c.stroke() + c.fillStyle='#111';c.beginPath();c.arc(0,12,5,0,T);c.fill();c.beginPath();c.moveTo(-3,13);c.lineTo(3,13);c.lineTo(4,26);c.lineTo(-4,26);c.closePath();c.fill() + c.restore() + } +} diff --git a/gen/uicolor/mailbox/empty.js b/gen/uicolor/mailbox/empty.js new file mode 100644 index 0000000..81a2932 --- /dev/null +++ b/gen/uicolor/mailbox/empty.js @@ -0,0 +1,44 @@ +// mailbox with its flag down, the door drops open with a puff of dust and a lonely moth flutters out, loops around and leaves, then the door shuts +const{sin,cos,PI,max,min,abs,floor}=Math,T=2*PI +export const frames=24,delay=80 +const MB='#4dabf7',DR='#74c0fc',DI='#d0ebff',IN='#343a40',FL='#ff6b6b',PO='#a9744f',MW='#ffe8cc',MS='#e0a96d',MG='#ced4da',BL='#ffa8a8',DU='#e9ecef' +const E=u=>u<0?0:u>1?1:u*u*(3-2*u) +const KP=[[66,118],[66,118],[46,64],[100,34],[164,58],[200,30],[250,-70],[250,-70]] +const cr=u=>{const s=min(4.999,max(0,u)*5),k=floor(s),f=s-k,[a,b,d,e]=KP.slice(k,k+4);return[0,1].map(j=>.5*(2*b[j]+(d[j]-a[j])*f+(2*a[j]-5*b[j]+4*d[j]-e[j])*f*f+(3*b[j]-a[j]-3*d[j]+e[j])*f**3))} +const arch=(c,x,k)=>{c.beginPath();c.moveTo(x-32,148);for(let a=PI;a<=T+.01;a+=PI/16)c.lineTo(x+32*cos(a),148-(40-32*sin(a))*k);c.lineTo(x+32,148);c.closePath()} +const moth=(c,x,y,s,f,r)=>{ + c.save();c.translate(x,y);c.rotate(r);c.scale(s,s);c.strokeStyle='#111' + for(const d of[-1,1]){c.save();c.scale(d*f,1);c.fillStyle=MW;c.lineWidth=5 + c.beginPath();c.moveTo(0,4);c.bezierCurveTo(24,4,34,22,24,32);c.bezierCurveTo(14,40,4,26,0,10);c.fill();c.stroke() + c.beginPath();c.moveTo(0,-4);c.bezierCurveTo(18,-32,50,-30,46,-8);c.bezierCurveTo(44,8,16,10,0,4);c.fill();c.stroke() + c.fillStyle=MS;c.beginPath();c.arc(30,-10,6,0,T);c.fill();c.beginPath();c.arc(16,20,4,0,T);c.fill();c.restore()} + for(const d of[-1,1])for(const[w,st]of[[7,'#111'],[3,MW]])c.lineWidth=w,c.strokeStyle=st,c.beginPath(),c.moveTo(d*3,-16),c.quadraticCurveTo(d*6,-30,d*16,-34),c.stroke() + c.strokeStyle='#111';c.lineWidth=4.5;c.fillStyle=MG;c.beginPath();c.ellipse(0,8,8,20,0,0,T);c.fill();c.stroke() + c.beginPath();c.arc(0,-13,9,0,T);c.fill();c.stroke() + c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.arc(d*3.5,-14,2,0,T),c.fill() + c.restore() +} +export default(c,t)=>{ + const th=PI*.66*(E((t-.06)/.12)-E((t-.82)/.12)),k=cos(th),op=th>.05,u=(t-.2)/.66,[mx,my]=cr(u),mv=u>0&&u<1 + c.save();c.translate(128,120);c.scale(1.12,1.12);c.translate(-128,-120) + c.fillStyle=PO;c.beginPath();c.roundRect(126,140,26,88,4);c.fill();c.stroke() + c.fillStyle=MB;c.beginPath();c.moveTo(72,76);c.lineTo(192,76);c.arc(192,108,32,-PI/2,0);c.lineTo(224,148);c.lineTo(72,148);c.closePath();c.fill();c.stroke() + c.strokeStyle='#fff';c.lineWidth=6;c.beginPath();c.moveTo(110,88);c.lineTo(176,88);c.stroke();c.strokeStyle='#111' + arch(c,72,1);c.fillStyle=op?IN:DR;c.fill();c.lineWidth=7;c.stroke() + if(op){arch(c,72,k);c.fillStyle=k>0?DR:DI;c.fill();c.stroke()} + c.fillStyle=MG;c.lineWidth=4;c.beginPath();c.roundRect(64,op?148-(k>0?66:60)*k-4:78,16,8,4);c.fill();c.stroke() + c.save();c.translate(204,104);c.rotate(.06*sin(t*T*2)) + for(const[w,s]of[[11,'#111'],[5,FL]])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.moveTo(0,0),c.lineTo(-34,0),c.stroke() + c.strokeStyle='#111';c.lineWidth=5;c.fillStyle=FL;c.beginPath();c.roundRect(-44,-4,18,30,4);c.fill();c.stroke() + c.fillStyle=MG;c.beginPath();c.arc(0,0,6,0,T);c.fill();c.stroke();c.restore() + const lx=mv?max(-3,min(3,(mx-136)/14)):0,ly=mv?max(-3,min(2,(my-116)/14)):2 + c.fillStyle='#111';for(const x of[118,146])c.beginPath(),c.arc(x+lx,106+ly,6,0,T),c.fill() + c.fillStyle='#fff';for(const x of[118,146])c.beginPath(),c.arc(x+lx-2,104+ly,2,0,T),c.fill() + c.lineWidth=4.5;c.beginPath();c.moveTo(110,92);c.lineTo(124,88);c.moveTo(154,92);c.lineTo(140,88);c.stroke() + c.lineWidth=5;c.beginPath();c.arc(132,132,8,1.2*PI,1.8*PI);c.stroke() + c.fillStyle=BL;for(const x of[106,158])c.beginPath(),c.ellipse(x,120,7,4,0,0,T),c.fill() + c.restore() + const p=(t-.14)/.3 + if(p>0&&p<1)for(const[a,o]of[[-2.4,0],[-1.9,.15],[-2.9,.1]]){const q=min(1,max(0,p-o)/.8),r=13*sin(PI*q);if(r>1)c.fillStyle=DU,c.lineWidth=4,c.beginPath(),c.arc(66+cos(a)*(30+40*q),118+sin(a)*(20+40*q),r,0,T),c.fill(),c.stroke()} + if(mv)moth(c,mx,my,.4+.75*E(u*5),.25+.75*abs(cos(6*PI*t)),.3*sin(u*T*2)) +} diff --git a/gen/uicolor/maintenance/robot.js b/gen/uicolor/maintenance/robot.js new file mode 100644 index 0000000..0587b2d --- /dev/null +++ b/gen/uicolor/maintenance/robot.js @@ -0,0 +1,43 @@ +// little robot cranking a bolt on its own chest with a big wrench, tongue out in concentration, sparks popping, gears turning on its head +const{sin,cos,PI}=Math,T=2*PI +export const frames=16,delay=90 +const M='#ced4da',MD='#adb5bd',SC='#e7f5ff',G='#ffd43b',G2='#ffa94d',WR='#868e96',BL='#ffa8a8',RD='#ff6b6b',GN='#51cf66' +const gear=(c,x,y,r,n,a,col)=>{ + c.fillStyle=col;c.lineWidth=5;c.beginPath() + for(let k=0;k{c.fillStyle=G;c.lineWidth=3.5;c.beginPath();c.moveTo(x,y-s);for(const[px,py,qx,qy]of[[s,0,s*.2,-s*.2],[0,s,s*.2,s*.2],[-s,0,-s*.2,s*.2],[0,-s,-s*.2,-s*.2]])c.quadraticCurveTo(x+qx,y+qy,x+px,y+py);c.fill();c.stroke()} +export default(c,t,i)=>{ + const ph=(t*2)%1,q=ph<.6?ph/.6:1-(ph-.6)/.4,th=.15+.7*(q*q*(3-2*q)),ga=t*T/2,bx=156,by=184 + const hx=bx+68*cos(th),hy=by+68*sin(th) + c.fillStyle=MD;c.beginPath();c.roundRect(122,48,12,20,4);c.fill();c.stroke() + gear(c,128,38,17,10,ga,G);gear(c,165,22,10,6,-ga*10/6+.3,G2) + c.lineWidth=7;c.fillStyle=M + for(const x of[100,140]){c.beginPath();c.roundRect(x,206,18,26,6);c.fill();c.stroke()} + for(const x of[90,134]){c.beginPath();c.roundRect(x,226,34,14,7);c.fill();c.stroke()} + for(const[lw,s]of[[20,'#111'],[10,M]])c.lineWidth=lw,c.strokeStyle=s,c.beginPath(),c.moveTo(84,166),c.quadraticCurveTo(56,176,62,204),c.stroke() + c.strokeStyle='#111';c.lineWidth=6;c.fillStyle=M;c.beginPath();c.arc(62,206,11,0,T);c.fill();c.stroke() + c.lineWidth=7;c.fillStyle=M;c.beginPath();c.roundRect(78,150,100,64,16);c.fill();c.stroke() + c.fillStyle=MD;c.lineWidth=5;c.beginPath();c.roundRect(90,162,40,40,8);c.fill();c.stroke() + for(const[x,y,col,on]of[[102,174,RD,i%4<2],[118,174,GN,i%4>=2],[102,190,G,i%8<4],[118,190,'#4dabf7',i%8>=4]]){c.fillStyle=on?col:'#868e96';c.lineWidth=3;c.beginPath();c.arc(x,y,5,0,T);c.fill();c.stroke()} + c.lineWidth=7;c.fillStyle=MD;c.beginPath();c.rect(114,140,28,14);c.fill();c.stroke() + c.fillStyle=M;for(const x of[58,198]){c.beginPath();c.roundRect(x-8,88,16,30,6);c.fill();c.stroke()} + c.beginPath();c.roundRect(62,62,132,82,22);c.fill();c.stroke() + c.fillStyle=SC;c.lineWidth=5;c.beginPath();c.roundRect(78,76,100,56,14);c.fill();c.stroke() + c.fillStyle='#111';c.beginPath();c.ellipse(144,100,5,7,0,0,T);c.fill() + c.fillStyle='#fff';c.beginPath();c.arc(142,97,2.2,0,T);c.fill() + c.lineWidth=4;c.beginPath();c.moveTo(105,94);c.lineTo(115,101);c.lineTo(105,108);c.stroke() + c.fillStyle=BL;for(const x of[96,160])c.beginPath(),c.ellipse(x,116,7,4,0,0,T),c.fill() + c.beginPath();c.moveTo(118,116);c.quadraticCurveTo(128,121,140,114);c.stroke() + c.fillStyle='#ff8787';c.lineWidth=3.5;c.beginPath();c.ellipse(136,121,5,6,-.4,0,PI);c.fill();c.stroke() + c.save();c.translate(bx,by);c.rotate(th) + c.fillStyle=WR;c.lineWidth=6;c.beginPath();c.roundRect(10,-8,62,16,8);c.fill();c.stroke();c.fillStyle=RD;c.beginPath();c.roundRect(34,-9,40,18,9);c.fill();c.stroke();c.fillStyle=WR + c.beginPath();c.arc(0,0,17,0,T);c.fill();c.stroke() + c.fillStyle=G;c.lineWidth=4;c.beginPath();for(let k=0;k<6;k++)c.lineTo(cos(k*PI/3)*9,sin(k*PI/3)*9);c.closePath();c.fill();c.stroke() + c.restore() + for(const[lw,s]of[[20,'#111'],[10,M]])c.lineWidth=lw,c.strokeStyle=s,c.beginPath(),c.moveTo(174,166),c.quadraticCurveTo(212,160,hx,hy),c.stroke() + c.strokeStyle='#111';c.lineWidth=6;c.fillStyle=M;c.beginPath();c.arc(hx,hy,12,0,T);c.fill();c.stroke() + const sp=ph>.6?(ph-.6)/.4:ph<.1?1+ph/.1:0 + if(sp>0&&sp<2){const s=sp<1?sp:2-sp;for(const[a,d]of[[-2.4,30],[-1.6,34],[-.8,28]])star(c,bx+cos(a)*d,by-6+sin(a)*d,3+6*s)} +} diff --git a/gen/uicolor/offline/satellite.js b/gen/uicolor/offline/satellite.js new file mode 100644 index 0000000..8c009eb --- /dev/null +++ b/gen/uicolor/offline/satellite.js @@ -0,0 +1,31 @@ +// worried satellite dish sweeping back and forth hunting for a signal, its little signal waves breaking up into dots and fizzling out +const{sin,cos,PI,max}=Math,T=2*PI +export const frames=16,delay=100 +const DS='#74c0fc',DI='#e7f5ff',ST='#adb5bd',BA='#868e96',FE='#ff6b6b',WV='#ffd43b',BL='#ffa8a8' +export default(c,t)=>{ + const a=.42*sin(T*t),lk=3.5*cos(T*t) + c.fillStyle=BA;c.beginPath();c.roundRect(68,214,120,26,10);c.fill();c.stroke() + c.fillStyle=ST;c.beginPath();c.roundRect(116,176,24,42,6);c.fill();c.stroke() + c.save();c.translate(128,190);c.rotate(a) + for(let k=0;k<3;k++){ + const p=(t*3+k/3)%1,r=18+40*p,d=max(1,14-15*p) + c.setLineDash([d,6+20*p*p]) + for(const[w,s]of[[13,'#111'],[6,WV]])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.arc(0,-122,r,-PI/2-.62,-PI/2+.62),c.stroke() + } + c.setLineDash([]);c.strokeStyle='#111' + c.fillStyle=ST;c.lineWidth=7;c.beginPath();c.roundRect(-16,-20,32,22,6);c.fill();c.stroke() + for(const[w,s]of[[12,'#111'],[5,ST]])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.moveTo(-74,-74),c.lineTo(0,-118),c.lineTo(74,-74),c.stroke() + c.strokeStyle='#111';c.lineWidth=7 + c.fillStyle=DS;c.beginPath();c.ellipse(0,-60,92,58,0,0,PI);c.ellipse(0,-60,92,34,0,PI,0,true);c.fill();c.stroke() + c.fillStyle=DI;c.beginPath();c.ellipse(0,-60,92,34,0,0,T);c.fill();c.stroke() + for(const[w,s]of[[12,'#111'],[5,ST]])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.moveTo(-74,-74),c.lineTo(-60,-82),c.moveTo(74,-74),c.lineTo(60,-82),c.stroke() + c.strokeStyle='#111';c.lineWidth=6;c.fillStyle=FE;c.beginPath();c.arc(0,-122,11,0,T);c.fill();c.stroke() + c.fillStyle='#fff';c.beginPath();c.arc(-3,-125,3,0,T);c.fill() + c.fillStyle='#fff';c.beginPath();c.ellipse(-56,-30,10,4,.3,0,T);c.fill() + c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.ellipse(d*22+lk,-60,6,7.5,0,0,T),c.fill() + c.fillStyle='#fff';for(const d of[-1,1])c.beginPath(),c.arc(d*22+lk-2,-63,2.4,0,T),c.fill() + c.lineWidth=4;for(const d of[-1,1])c.beginPath(),c.moveTo(d*14+lk,-76),c.lineTo(d*30+lk,-71),c.stroke() + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(d*42,-50,8,4.5,0,0,T),c.fill() + c.beginPath();c.moveTo(-10+lk,-45);c.quadraticCurveTo(-5+lk,-50,0+lk,-45);c.quadraticCurveTo(5+lk,-40,10+lk,-45);c.stroke() + c.restore() +} diff --git a/gen/uicolor/order/shipped.js b/gen/uicolor/order/shipped.js new file mode 100644 index 0000000..70ef0ea --- /dev/null +++ b/gen/uicolor/order/shipped.js @@ -0,0 +1,41 @@ +// delivery truck driving along with a smiling parcel hopping on its flatbed, wheels turning, road dashes and speed lines rushing past +const{sin,cos,PI,abs,round,max}=Math,T=2*PI +export const frames=16,delay=60 +const CAB='#4dabf7',CABD='#339af0',WIN='#e7f5ff',TIRE='#343a40',HUB='#ced4da',BED='#868e96',BX='#f0b878',BXD='#d99a5a',TAPE='#ffe8cc',BL='#ffa8a8' +export default(c,t)=>{ + const b=-round(3*abs(sin(2*T*t))),h=-round(7*max(0,sin(2*T*t-.8))),tl=.05*max(0,sin(2*T*t-.8)),rot=t*T + c.fillStyle='#868e96';c.beginPath();c.roundRect(8,214,240,22,11);c.fill();c.stroke() + c.save();c.beginPath();c.rect(14,214,228,22);c.clip() + for(let k=-1;k<5;k++){const x=k*64-((t*128)%64)+20;c.fillStyle='#fff';c.beginPath();c.roundRect(x,222,30,6,3);c.fill()} + c.restore() + for(const[y,o,l]of[[92,0,30],[122,.5,22],[150,.25,28]]){const p=(t*2+o)%1,x=40-p*28;if(p<.85)for(const[w,s]of[[9,'#111'],[4,'#fff']])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.moveTo(x,y),c.lineTo(x-l*(1-p),y),c.stroke()} + c.strokeStyle='#111';c.lineWidth=7 + c.translate(0,b) + c.fillStyle=BED;c.beginPath();c.roundRect(34,166,136,22,6);c.fill();c.stroke() + c.save();c.translate(104,166+h);c.rotate(-tl) + c.fillStyle=BX;c.beginPath();c.roundRect(-58,-92,116,92,6);c.fill() + c.fillStyle=BXD;c.fillRect(-58,-92,116,14) + c.fillStyle=TAPE;c.fillRect(-14,-92,28,36) + c.lineWidth=4;c.beginPath();c.moveTo(-14,-92);c.lineTo(-14,-56);c.lineTo(14,-56);c.lineTo(14,-92);c.moveTo(-58,-78);c.lineTo(-14,-78);c.moveTo(14,-78);c.lineTo(58,-78);c.stroke() + c.lineWidth=7;c.beginPath();c.roundRect(-58,-92,116,92,6);c.stroke() + c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.arc(d*20,-36,5,0,T),c.fill() + c.fillStyle='#fff';for(const d of[-1,1])c.beginPath(),c.arc(d*20-2,-38,1.8,0,T),c.fill() + c.lineWidth=4;c.beginPath();c.arc(0,-30,8,.15*PI,.85*PI);c.stroke() + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(d*36,-24,7,4,0,0,T),c.fill() + c.restore() + c.lineWidth=7;c.fillStyle=CAB;c.beginPath();c.moveTo(164,188);c.lineTo(164,98);c.quadraticCurveTo(164,88,174,88);c.lineTo(202,88);c.quadraticCurveTo(212,88,218,98);c.lineTo(232,130);c.lineTo(232,188);c.closePath();c.fill();c.stroke() + c.fillStyle=WIN;c.lineWidth=5;c.beginPath();c.moveTo(178,100);c.lineTo(204,100);c.lineTo(218,128);c.lineTo(178,128);c.closePath();c.fill();c.stroke() + c.fillStyle='#fff';c.beginPath();c.ellipse(188,110,3,7,.4,0,T);c.fill() + c.fillStyle=CABD;c.beginPath();c.rect(164,160,68,10);c.fill();c.beginPath();c.moveTo(164,160);c.lineTo(232,160);c.moveTo(164,170);c.lineTo(232,170);c.stroke() + c.lineWidth=4;c.beginPath();c.moveTo(184,140);c.lineTo(196,140);c.stroke() + c.fillStyle='#ffd43b';c.lineWidth=5;c.beginPath();c.roundRect(222,134,14,14,4);c.fill();c.stroke() + c.fillStyle='#111';c.beginPath();c.arc(210,144,4,0,T);c.fill() + c.fillStyle=BL;c.beginPath();c.ellipse(202,178,6,3.5,0,0,T);c.fill() + c.lineWidth=4;c.beginPath();c.arc(216,174,6,.2*PI,.8*PI);c.stroke() + c.translate(0,-b) + for(const x of[78,196]){ + c.lineWidth=7;c.fillStyle=TIRE;c.beginPath();c.arc(x,194,22,0,T);c.fill();c.stroke() + c.fillStyle=HUB;c.beginPath();c.arc(x,194,10,0,T);c.fill();c.lineWidth=4;c.stroke() + for(let k=0;k<4;k++){const a=rot+k*PI/2;c.beginPath();c.moveTo(x+cos(a)*4,194+sin(a)*4);c.lineTo(x+cos(a)*9,194+sin(a)*9);c.stroke()} + } +} diff --git a/gen/uicolor/payment/coins.js b/gen/uicolor/payment/coins.js new file mode 100644 index 0000000..ed20555 --- /dev/null +++ b/gen/uicolor/payment/coins.js @@ -0,0 +1,33 @@ +// spinning gold coins dropping one after another into a happy purple wallet that gulps and bounces with each one +const{sin,cos,PI,abs,max,min}=Math,T=2*PI +export const frames=24,delay=60 +const G='#ffd43b',GD='#f59f00',WF='#b197fc',WB='#7950f2',WT='#9775fa',BILL='#8ce99a',BL='#ffa8a8' +const C=[[100,0],[148,1/3],[122,2/3]] +const sp=(c,x,y,s)=>{c.lineWidth=4;c.fillStyle='#fff';c.beginPath();c.moveTo(x,y-s);for(const[px,py,qx,qy]of[[s,0,s*.18,-s*.18],[0,s,s*.18,s*.18],[-s,0,-s*.18,s*.18],[0,-s,-s*.18,-s*.18]])c.quadraticCurveTo(x+qx,y+qy,x+px,y+py);c.fill();c.stroke()} +export default(c,t)=>{ + let bump=0 + for(const[x,o]of C){const p=(t+o)%1,q=(p-.42)/.2;if(q>0&&q<1)bump=max(bump,sin(PI*q))} + c.translate(128,234);c.scale(1+.05*bump,1-.07*bump);c.translate(-128,-234) + c.fillStyle=WB;c.beginPath();c.roundRect(42,104,172,122,18);c.fill();c.stroke() + c.save();c.translate(150,96);c.rotate(.12);c.fillStyle=BILL;c.beginPath();c.roundRect(-34,-26,68,60,4);c.fill();c.stroke() + c.lineWidth=4;c.beginPath();c.arc(0,-2,9,0,T);c.stroke();c.restore();c.lineWidth=7 + for(const[x,o]of C){ + const p=(t+o)%1;if(p>.44)continue + const u=p/.44,y=34+114*u*u,w=max(6,28*abs(cos(u*PI*1.5))),xx=x+8*sin(u*PI) + c.save();c.translate(xx,y);c.scale(min(1,u*5),min(1,u*5)) + c.fillStyle=GD;c.lineWidth=5;c.beginPath();c.ellipse(0,0,w,28,0,0,T);c.fill();c.stroke() + c.fillStyle=G;c.beginPath();c.ellipse(0,0,w*.78,22,0,0,T);c.fill() + if(w>12){c.scale(w/28,1);c.lineWidth=4.5/(w/28);c.beginPath();c.moveTo(7,-8);c.bezierCurveTo(4,-14,-10,-13,-9,-5);c.bezierCurveTo(-8,2,9,-1,9,6);c.bezierCurveTo(9,14,-6,15,-9,8);c.moveTo(0,-17);c.lineTo(0,17);c.stroke()} + c.restore() + } + c.lineWidth=7;c.fillStyle=WF;c.beginPath();c.roundRect(32,128,192,104,20);c.fill();c.stroke() + c.fillStyle=WT;c.beginPath();c.roundRect(176,150,56,46,12);c.fill();c.stroke() + c.fillStyle=G;c.lineWidth=5;c.beginPath();c.arc(214,173,8,0,T);c.fill();c.stroke() + c.strokeStyle='#fff';c.lineWidth=6;c.beginPath();c.moveTo(48,148);c.lineTo(48,168);c.stroke();c.strokeStyle='#111' + c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.arc(110+d*26,170-3*bump,6,0,T),c.fill() + c.fillStyle='#fff';for(const d of[-1,1])c.beginPath(),c.arc(108+d*26,167-3*bump,2.2,0,T),c.fill() + c.fillStyle='#111';c.beginPath();c.arc(110,184,10+3*bump,0,PI);c.closePath();c.fill() + c.fillStyle='#ff8787';c.beginPath();c.ellipse(110,190+2*bump,5,3,0,0,T);c.fill() + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(110+d*44,186,8,4.5,0,0,T),c.fill() + for(const[x,o]of C){const p=(t+o)%1,q=(p-.42)/.2;if(q>0&&q<1)sp(c,x+(x<128?-34:34),112,14*sin(PI*q))} +} diff --git a/gen/uicolor/search/sad.js b/gen/uicolor/search/sad.js new file mode 100644 index 0000000..2ddf468 --- /dev/null +++ b/gen/uicolor/search/sad.js @@ -0,0 +1,24 @@ +// sad magnifying glass swaying side to side, big eyes peeking left and right for results, a little question mark bobbing beside it +const{sin,PI}=Math,T=2*PI +export const frames=14,delay=100 +const RG='#9775fa',LN='#d0ebff',HN='#ffa94d',BL='#ffa8a8',QM='#ffd43b',SW='#74c0fc' +export default(c,t)=>{ + const a=.14*sin(t*T),x=112+10*sin(t*T),y=100+3*sin(2*T*t),lk=sin(t*T+.7),qs=1+.08*sin(2*T*t) + c.save();c.translate(210,56+5*sin(2*T*t+1));c.scale(qs,qs);c.rotate(.15*sin(t*T)) + for(const[w,s]of[[17,'#111'],[8,QM]])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.arc(0,-14,13,PI*1.05,PI*2.45),c.lineTo(0,6),c.stroke() + c.strokeStyle='#111';c.fillStyle=QM;c.lineWidth=4;c.beginPath();c.arc(0,22,6.5,0,T);c.fill();c.stroke();c.restore() + c.save();c.translate(x,y);c.rotate(a) + c.save();c.rotate(PI/4);c.fillStyle=HN;c.beginPath();c.roundRect(76,-15,68,30,15);c.fill();c.stroke() + c.fillStyle=RG;c.beginPath();c.roundRect(66,-19,22,38,6);c.fill();c.stroke();c.restore() + c.fillStyle=RG;c.beginPath();c.arc(0,0,72,0,T);c.fill();c.stroke() + c.fillStyle=LN;c.beginPath();c.arc(0,0,56,0,T);c.fill();c.lineWidth=5;c.stroke() + c.strokeStyle='#fff';c.lineWidth=7;c.beginPath();c.arc(0,0,44,PI*1.08,PI*1.38);c.stroke();c.strokeStyle='#111' + c.lineWidth=4;c.fillStyle='#fff';for(const d of[-1,1])c.beginPath(),c.arc(d*21,-4,13,0,T),c.fill(),c.stroke() + c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.arc(d*21+lk*5,-2,6.5,0,T),c.fill() + c.fillStyle='#fff';for(const d of[-1,1])c.beginPath(),c.arc(d*21+lk*5-2,-4,2,0,T),c.fill() + c.lineWidth=4.5;for(const d of[-1,1])c.beginPath(),c.moveTo(d*10,-26),c.lineTo(d*30,-21),c.stroke() + c.lineWidth=5;c.beginPath();c.arc(0,32,10,1.2*PI,1.8*PI);c.stroke() + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(d*36,16,7,4,0,0,T),c.fill() + c.fillStyle=SW;c.lineWidth=3;c.beginPath();c.moveTo(40,-34);c.quadraticCurveTo(47,-23,40,-21);c.quadraticCurveTo(33,-23,40,-34);c.fill();c.stroke() + c.restore() +} diff --git a/gen/uicolor/sent/envelope.js b/gen/uicolor/sent/envelope.js new file mode 100644 index 0000000..59895ab --- /dev/null +++ b/gen/uicolor/sent/envelope.js @@ -0,0 +1,21 @@ +// blue envelope with a heart seal flapping its little white wings as it flies off, a trail of puffs streaming out behind it +const{sin,cos,PI,min}=Math,T=2*PI +export const frames=18,delay=70 +const EN='#a5d8ff',FL='#74c0fc',HT='#ff6b6b',BL='#ffa8a8' +const wing=c=>{c.beginPath();c.moveTo(-6,8);c.quadraticCurveTo(8,-40,54,-46);c.quadraticCurveTo(60,-30,44,-27);c.quadraticCurveTo(48,-13,30,-12);c.quadraticCurveTo(30,1,12,0);c.quadraticCurveTo(8,10,-6,8);c.fill();c.stroke()} +export default(c,t)=>{ + const f=sin(3*T*t),y=126+5*f,B=(u,p,q,r,v)=>(1-u)**3*p+3*(1-u)**2*u*q+3*(1-u)*u*u*r+u**3*v + c.fillStyle='#fff';c.lineWidth=4 + for(let k=0;k<8;k++){const u=((k+t*2)%8)/8,x=B(u,132,66,86,16),yy=B(u,y,y+10,214,226),r=10*(1-u)+2.5;c.beginPath();c.arc(x,yy,r,0,T);c.fill();c.stroke()} + c.translate(136,y);c.rotate(-.16+.04*sin(t*T)) + c.lineWidth=6;c.fillStyle='#fff' + for(const d of[-1,1]){c.save();c.translate(d*50,-24);c.scale(d,1);c.rotate(.45*f-.15);wing(c);c.lineWidth=4;c.beginPath();c.moveTo(8,-14);c.quadraticCurveTo(24,-28,40,-34);c.stroke();c.restore()} + c.lineWidth=7;c.fillStyle=EN;c.beginPath();c.roundRect(-58,-40,116,80,10);c.fill();c.stroke() + c.fillStyle=FL;c.lineWidth=5;c.beginPath();c.moveTo(-55,-37);c.lineTo(0,4);c.lineTo(55,-37);c.closePath();c.fill();c.stroke() + c.fillStyle=HT;c.beginPath();c.moveTo(0,16);c.bezierCurveTo(-16,6,-12,-8,0,-1);c.bezierCurveTo(12,-8,16,6,0,16);c.fill();c.lineWidth=4;c.stroke() + c.fillStyle='#fff';c.beginPath();c.ellipse(-5,2,2.5,1.6,-.6,0,T);c.fill() + c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.arc(d*30,14,5.5,0,T),c.fill() + c.fillStyle='#fff';for(const d of[-1,1])c.beginPath(),c.arc(d*30-2,12,2,0,T),c.fill() + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(d*40,25,7,4,0,0,T),c.fill() + c.lineWidth=4;c.beginPath();c.arc(0,22,6,.2*PI,.8*PI);c.stroke() +} diff --git a/gen/uicolor/success/balloons.js b/gen/uicolor/success/balloons.js new file mode 100644 index 0000000..0f5581f --- /dev/null +++ b/gen/uicolor/success/balloons.js @@ -0,0 +1,31 @@ +// bunch of smiling balloons bobbing up on wavy strings tied with a bow, confetti fluttering down around them +const{sin,cos,PI,min}=Math,T=2*PI +export const frames=14,delay=100 +const B=[[128,74,'#ffd43b',.2,36],[70,108,'#ff6b6b',0,33],[186,108,'#4dabf7',.55,33]],BL='#ffa8a8' +const CF=['#ff6b6b','#ffd43b','#4dabf7','#69db7c','#b197fc','#f783ac','#ffa94d'] +export default(c,t)=>{ + for(let k=0;k<9;k++){ + const p=(t*(1+k%2)+k*.37)%1,x=(k*71+20)%200+28+10*sin(p*T*2+k),y=6+p*236,s=min(1,4*sin(PI*p)) + if(s<.1)continue + c.save();c.translate(x,y);c.rotate(p*T*(1+k%3));c.scale(s,s);c.fillStyle=CF[k%7];c.lineWidth=3;c.beginPath() + if(k%3==0)c.rect(-7,-4,14,8);else if(k%3==1)c.arc(0,0,5,0,T);else c.moveTo(0,-7),c.lineTo(6,5),c.lineTo(-6,5),c.closePath() + c.fill();c.stroke();c.restore() + } + const b=-6*sin(t*T),K=[128,222+b*.4],P=B.map(([x,y,,o,r])=>[x+6*sin(t*T+o*T),y+b+4*sin(2*T*t+o*T),r]) + for(const[w,st]of[[7,'#111'],[3,'#fff']]){c.lineWidth=w;c.strokeStyle=st;c.beginPath();for(const[x,y,r]of P){const w2=10*sin(2*T*t+x);c.moveTo(x,y+r*1.2+8);c.quadraticCurveTo((x+K[0])/2+w2,(y+K[1])/2+20,K[0],K[1])}c.stroke()} + c.strokeStyle='#111' + for(const[k,[x,y,r]]of P.entries()){ + const col=B[k][2] + c.save();c.translate(x,y);c.rotate((x-128)/500) + c.lineWidth=5;c.fillStyle=col;c.beginPath();c.moveTo(0,r*1.12);c.lineTo(-7,r*1.2+9);c.lineTo(7,r*1.2+9);c.closePath();c.fill();c.stroke() + c.lineWidth=7;c.beginPath();c.ellipse(0,0,r,r*1.18,0,0,T);c.fill();c.stroke() + c.fillStyle='#fff';c.beginPath();c.ellipse(-r*.45,-r*.5,r*.14,r*.26,.5,0,T);c.fill();c.beginPath();c.arc(-r*.2,-r*.82,r*.07,0,T);c.fill() + c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.arc(d*r*.3,r*.06,4.5,0,T),c.fill() + c.lineWidth=4;c.beginPath();c.arc(0,r*.2,r*.2,.15*PI,.85*PI);c.stroke() + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(d*r*.56,r*.3,6,3.5,0,0,T),c.fill() + c.restore() + } + c.save();c.translate(...K);c.fillStyle='#f783ac';c.lineWidth=4 + for(const d of[-1,1])c.beginPath(),c.moveTo(0,0),c.lineTo(d*16,-9),c.lineTo(d*16,9),c.closePath(),c.fill(),c.stroke() + c.beginPath();c.arc(0,0,5,0,T);c.fill();c.stroke();c.restore() +} diff --git a/gen/uicolor/success/check.js b/gen/uicolor/success/check.js new file mode 100644 index 0000000..6768f7c --- /dev/null +++ b/gen/uicolor/success/check.js @@ -0,0 +1,25 @@ +// green badge pops in, a white check mark draws itself, a burst of colorful rays and sparkles goes off, then it shrinks away +const{sin,cos,PI,min,max,hypot}=Math,T=2*PI +export const frames=24,delay=60 +const GR='#51cf66',GD='#37b24d',CF=['#ffd43b','#ff6b6b','#4dabf7','#f783ac'] +const back=u=>{const s=2;return 1+(s+1)*(u-1)**3+s*(u-1)**2} +const P=[[90,132],[116,158],[168,100]],L=hypot(26,26)+hypot(52,58) +const sp=(c,x,y,s)=>{c.lineWidth=4;c.fillStyle='#fff';c.beginPath();c.moveTo(x,y-s);for(const[px,py,qx,qy]of[[s,0,s*.18,-s*.18],[0,s,s*.18,s*.18],[-s,0,-s*.18,s*.18],[0,-s,-s*.18,-s*.18]])c.quadraticCurveTo(x+qx,y+qy,x+px,y+py);c.fill();c.stroke()} +export default(c,t)=>{ + const s=t<.15?back(t/.15):t>.85?1-((t-.85)/.15)**2:1,p=min(1,max(0,(t-.15)/.25)),b=(t-.38)/.32 + if(b>0&&b<1){ + for(let k=0;k<8;k++){ + const a=k*T/8+PI/8,r1=88+30*b,r2=r1+22*(1-b) + for(const[w,st]of[[13,'#111'],[6,CF[k%4]]])c.lineWidth=w,c.strokeStyle=st,c.beginPath(),c.moveTo(128+cos(a)*r1,128+sin(a)*r1),c.lineTo(128+cos(a)*r2,128+sin(a)*r2),c.stroke() + } + c.strokeStyle='#111' + for(let k=0;k<4;k++){const a=k*T/4-PI/2,r=92+16*b;sp(c,128+cos(a)*r,128+sin(a)*r,14*sin(PI*b))} + } + c.strokeStyle='#111' + if(s<=.01)return + c.translate(128,128);c.scale(s,s);c.translate(-128,-128);c.lineWidth=7/s + c.fillStyle=GR;c.beginPath();c.arc(128,128,76,0,T);c.fill();c.stroke() + c.strokeStyle=GD;c.lineWidth=6;c.beginPath();c.arc(128,128,62,0,T);c.stroke() + c.strokeStyle='#fff';c.beginPath();c.arc(128,128,66,PI*1.1,PI*1.38);c.stroke() + if(p>0)for(const[w,st]of[[28,'#111'],[16,'#fff']]){c.lineWidth=w;c.strokeStyle=st;c.setLineDash([L*p,999]);c.beginPath();for(const[x,y]of P)c.lineTo(x,y);c.stroke()} +} diff --git a/gen/uicolor/success/medal.js b/gen/uicolor/success/medal.js new file mode 100644 index 0000000..5376f9c --- /dev/null +++ b/gen/uicolor/success/medal.js @@ -0,0 +1,27 @@ +// gold medal with a star swinging on its red and blue ribbon, a glint sliding across it and sparkles popping around +const{sin,cos,PI,max}=Math,T=2*PI +export const frames=14,delay=90 +const G='#ffd43b',GD='#fab005',GE='#f59f00',RB=['#ff6b6b','#4dabf7'] +const sp=(c,x,y,s)=>{c.lineWidth=4;c.fillStyle='#fff';c.beginPath();c.moveTo(x,y-s);for(const[px,py,qx,qy]of[[s,0,s*.18,-s*.18],[0,s,s*.18,s*.18],[-s,0,-s*.18,s*.18],[0,-s,-s*.18,-s*.18]])c.quadraticCurveTo(x+qx,y+qy,x+px,y+py);c.fill();c.stroke()} +const disc=(c,r)=>{c.beginPath();c.arc(0,170,r,0,T)} +export default(c,t)=>{ + const a=.13*sin(t*T) + for(const[x,y,o]of[[38,120,0],[220,104,.33],[214,216,.66],[46,224,.5]]){const s=12*max(0,sin(PI*((t*2+o)%1)));if(s>1.5)sp(c,x,y,s)} + c.lineWidth=7;c.translate(128,20);c.rotate(a);c.scale(.94,.94) + for(const[k,d]of[[0,1],[1,-1]]){ + const q=()=>{c.beginPath();c.moveTo(d*58,0);c.lineTo(d*22,0);c.lineTo(-d*16,112);c.lineTo(d*18,112);c.closePath()} + q();c.fillStyle=RB[k];c.fill() + c.save();q();c.clip();c.strokeStyle='#fff';c.lineWidth=9;c.beginPath();c.moveTo(d*40,0);c.lineTo(d*1,112);c.stroke();c.restore() + q();c.stroke() + } + c.fillStyle=GD;c.beginPath();c.roundRect(-20,100,40,22,7);c.fill();c.stroke() + disc(c,62);c.fillStyle=GD;c.fill();c.stroke() + disc(c,48);c.fillStyle=G;c.fill() + c.save();disc(c,48);c.clip() + c.fillStyle=GD;c.beginPath();c.arc(0,170,48,0,T);c.arc(-12,157,48,0,T,true);c.fill() + const g=t*360-120;c.strokeStyle='#fff';c.lineWidth=14;c.beginPath();c.moveTo(g-40,240);c.lineTo(g+30,100);c.stroke();c.lineWidth=5;c.beginPath();c.moveTo(g-16,240);c.lineTo(g+54,100);c.stroke() + c.restore() + c.lineWidth=5;disc(c,48);c.stroke() + c.fillStyle=GE;c.beginPath();for(let k=0;k<10;k++){const r=k%2?14:31,b=k*PI/5-PI/2;c.lineTo(cos(b)*r,172+sin(b)*r)}c.closePath();c.fill();c.lineWidth=4;c.stroke() + c.strokeStyle='#fff';c.lineWidth=6;c.beginPath();c.arc(0,170,54,PI*1.12,PI*1.36);c.stroke() +} diff --git a/gen/uicolor/sync/phones.js b/gen/uicolor/sync/phones.js new file mode 100644 index 0000000..7e2f1d1 --- /dev/null +++ b/gen/uicolor/sync/phones.js @@ -0,0 +1,37 @@ +// two smiling phones tossing a file back and forth in a high arc, each one hopping as it catches, sync arrows spinning between them +const{sin,cos,PI,max}=Math,T=2*PI +export const frames=20,delay=80 +const PL='#9775fa',PR='#ff8787',SC='#e7f5ff',FL='#fff',FC='#ffd43b',AR='#51cf66',BL='#ffa8a8' +const ease=u=>u*u*(3-2*u) +const phone=(c,x,col,tilt,hop,open)=>{ + c.save();c.translate(x,236-hop);c.rotate(tilt) + c.fillStyle=col;c.beginPath();c.roundRect(-38,-148,76,148,18);c.fill();c.stroke() + c.fillStyle=SC;c.lineWidth=5;c.beginPath();c.roundRect(-28,-132,56,116,9);c.fill();c.stroke() + c.fillStyle='#111';c.beginPath();c.roundRect(-10,-144,20,5,2.5);c.fill() + c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.ellipse(d*12,-50,4.5,6,0,0,T),c.fill() + c.fillStyle='#fff';for(const d of[-1,1])c.beginPath(),c.arc(d*12-1.5,-52.5,1.8,0,T),c.fill() + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(d*20,-38,5.5,3.5,0,0,T),c.fill() + c.lineWidth=4;c.beginPath() + if(open)c.fillStyle='#ff8787',c.moveTo(-6,-40),c.quadraticCurveTo(0,-26,6,-40),c.closePath(),c.fill() + else c.arc(0,-42,6,.15*PI,.85*PI) + c.stroke();c.restore();c.lineWidth=7 +} +const file=(c,x,y,r)=>{ + c.save();c.translate(x,y);c.rotate(r);c.lineWidth=5 + c.fillStyle=FL;c.beginPath();c.moveTo(-18,-24);c.lineTo(8,-24);c.lineTo(18,-14);c.lineTo(18,24);c.lineTo(-18,24);c.closePath();c.fill();c.stroke() + c.fillStyle=FC;c.beginPath();c.moveTo(8,-24);c.lineTo(8,-14);c.lineTo(18,-14);c.closePath();c.fill();c.stroke() + c.strokeStyle='#4dabf7';c.lineWidth=4;c.beginPath();for(const y of[-8,2,12])c.moveTo(-9,y),c.lineTo(9,y);c.stroke() + c.restore();c.strokeStyle='#111';c.lineWidth=7 +} +export default(c,t)=>{ + const h=t<.5?0:1,u=((t*2)%1),fly=u<.72,f=fly?ease(u/.72):1,dir=h?-1:1 + const x0=h?198:58,x1=h?58:198,fx=x0+(x1-x0)*f,fy=148-110*sin(PI*f),land=fly?0:(u-.72)/.28 + const ca=fly?0:sin(PI*land) + phone(c,58,PL,-.1,h?ca*10:0,h&&!fly) + phone(c,198,PR,.1,h?0:ca*10,!h&&!fly) + c.save();c.translate(128,186);c.rotate(-T*t*2) + for(let k=0;k<2;k++){c.rotate(PI);for(const[w,s]of[[12,'#111'],[5,AR]])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.arc(0,0,20,.25,PI-.5),c.stroke();c.strokeStyle='#111';c.lineWidth=4;c.fillStyle=AR;c.beginPath();const ex=cos(PI-.5)*20,ey=sin(PI-.5)*20;c.moveTo(ex-9,ey-4);c.lineTo(ex+3,ey-9);c.lineTo(ex+3,ey+5);c.closePath();c.fill();c.stroke()} + c.restore();c.lineWidth=7 + if(fly&&f>.06&&f<.94)for(let k=1;k<=3;k++){const g=max(0,f-k*.07),gx=x0+(x1-x0)*g,gy=148-110*sin(PI*g);c.fillStyle='#fff';c.lineWidth=3;c.beginPath();c.arc(gx,gy,5-k,0,T);c.fill();c.stroke()} + file(c,fx+(fly?0:dir*ca*1),fy-ca*10,dir*.5*sin(PI*f)*(fly?1:0)) +} diff --git a/gen/uicolor/trash/empty.js b/gen/uicolor/trash/empty.js new file mode 100644 index 0000000..0f12854 --- /dev/null +++ b/gen/uicolor/trash/empty.js @@ -0,0 +1,30 @@ +// clean empty trash bin flipping its lid open and shut with a big grin, sparkles popping out of it and twinkling all around +const{sin,PI,max}=Math,T=2*PI +export const frames=20,delay=80 +const BN='#63e6be',BD='#20c997',RM='#38d9a9',IN='#c3fae8',BL='#ffa8a8',TG='#ff8787' +const E=u=>u<0?0:u>1?1:u*u*(3-2*u) +const sp=(c,x,y,s)=>{if(s<1.5)return;c.lineWidth=4;c.fillStyle='#fff';c.beginPath();c.moveTo(x,y-s);for(const[px,py,qx,qy]of[[s,0,s*.18,-s*.18],[0,s,s*.18,s*.18],[-s,0,-s*.18,s*.18],[0,-s,-s*.18,-s*.18]])c.quadraticCurveTo(x+qx,y+qy,x+px,y+py);c.fill();c.stroke()} +const bod=c=>{c.beginPath();c.moveTo(70,112);c.lineTo(186,112);c.lineTo(176,236);c.lineTo(80,236);c.closePath()} +export default(c,t)=>{ + const o=E((t-.08)/.14)-E((t-.56)/.08),b=t>.64&&t<.76?sin(PI*(t-.64)/.12):0,th=.55*o+.12*b,q=t>.62&&t<.8?sin(PI*(t-.62)/.18):0 + for(const[x,y,f,s]of[[34,150,0,13],[222,140,.3,12],[28,222,.55,11],[228,214,.8,14]])sp(c,x,y,s*max(0,sin(PI*((t*2+f)%1)))) + c.save();c.translate(128,236);c.scale(1+.04*q,1-.06*q);c.translate(-128,-236) + c.fillStyle=BN;bod(c);c.fill();c.stroke() + c.strokeStyle='#fff';c.lineWidth=7;c.beginPath();c.moveTo(86,128);c.lineTo(91,184);c.stroke() + c.strokeStyle=BD;c.lineWidth=6;c.beginPath();for(const x of[104,128,152])c.moveTo(x,198),c.lineTo(x+(x-128)*.06,222);c.stroke() + c.strokeStyle='#111';c.fillStyle='#111' + if(th>.15)c.lineWidth=5,[-1,1].forEach(d=>{c.beginPath();c.arc(128+d*20,156,7,1.15*PI,1.85*PI);c.stroke()}) + else[-1,1].forEach(d=>{c.beginPath();c.arc(128+d*20,152,6.5,0,T);c.fill()}),c.fillStyle='#fff',[-1,1].forEach(d=>{c.beginPath();c.arc(126+d*20,150,2.2,0,T);c.fill()}) + c.fillStyle='#111';c.lineWidth=4;c.beginPath();c.moveTo(112,170);c.quadraticCurveTo(128,196,144,170);c.closePath();c.fill();c.stroke() + c.fillStyle=TG;c.beginPath();c.ellipse(128,184,7,4,0,0,T);c.fill() + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*38,172,8,5,0,0,T),c.fill() + c.lineWidth=7;c.fillStyle=RM;c.beginPath();c.roundRect(62,104,132,16,8);c.fill();c.stroke() + if(th>.05){c.fillStyle=IN;c.lineWidth=5;c.beginPath();c.ellipse(128,108,56,7,0,0,T);c.fill();c.stroke()} + c.restore() + const u=(t-.18)/.42 + if(u>0&&u<1)for(const[x,f,s]of[[104,0,13],[150,.2,11],[126,.4,15]]){const v=(u-f)/.6;if(v>0&&v<1)sp(c,x+8*sin(v*T),104-80*v,s*sin(PI*v))} + c.save();c.translate(198,104-4*q);c.rotate(th);c.fillStyle=RM;c.lineWidth=7 + c.beginPath();c.roundRect(-92,-28,32,16,7);c.fill();c.stroke() + c.beginPath();c.roundRect(-150,-18,156,20,9);c.fill();c.stroke() + c.strokeStyle='#fff';c.lineWidth=5;c.beginPath();c.moveTo(-136,-10);c.lineTo(-112,-10);c.stroke();c.restore() +} diff --git a/gen/uicolor/upload/rocket.js b/gen/uicolor/upload/rocket.js new file mode 100644 index 0000000..24c848a --- /dev/null +++ b/gen/uicolor/upload/rocket.js @@ -0,0 +1,35 @@ +// happy rocket blasting up and away with a file strapped to its nose, flame flickering, speed streaks and little clouds rushing past +const{sin,PI,round}=Math,T=2*PI +export const frames=16,delay=70 +const RD='#ff6b6b',NZ='#adb5bd',FO='#ff922b',FY='#ffd43b',AR='#4dabf7',LN='#d0ebff',BL='#ffa8a8' +const cloud=(c,x,y,s)=>{const b=[[-14*s,3*s,10*s],[2*s,-4*s,13*s],[17*s,3*s,9*s]];c.lineWidth=13;for(const[a,d,r]of b)c.beginPath(),c.arc(x+a,y+d,r,0,T),c.stroke();c.fillStyle='#fff';for(const[a,d,r]of b)c.beginPath(),c.arc(x+a,y+d,r,0,T),c.fill();c.lineWidth=7} +export default(c,t,i)=>{ + const b=round(4*sin(T*t)),w=.04*sin(2*T*t),fh=26+(i%2?10:0)+4*sin(4*T*t) + c.translate(128,128);c.rotate(.6) + for(const[x,o,L]of[[-56,0,40],[58,.5,40],[-70,.3,30],[72,.8,30]]){ + const p=(t*2+o)%1,y=-50+p*120,l=L*sin(PI*p) + for(const[lw,s]of[[11,'#111'],[5,'#fff']])c.lineWidth=lw,c.strokeStyle=s,c.beginPath(),c.moveTo(x,y-l/2),c.lineTo(x,y+l/2),c.stroke() + } + c.strokeStyle='#111' + for(const[x,o]of[[-88,.1],[90,.6]]){const p=(t+o)%1,s=sin(PI*p);if(s>.15)cloud(c,x,-46+p*92,.85*s)} + c.translate(0,8+b);c.rotate(w);c.scale(.94,.94) + c.fillStyle=FO;c.lineWidth=5;c.beginPath();c.moveTo(-18,66);c.quadraticCurveTo(-20,66+fh*.6,0,66+fh);c.quadraticCurveTo(20,66+fh*.6,18,66);c.closePath();c.fill();c.stroke() + c.fillStyle=FY;c.beginPath();c.moveTo(-10,66);c.quadraticCurveTo(-10,66+fh*.45,0,66+fh*.7);c.quadraticCurveTo(10,66+fh*.45,10,66);c.closePath();c.fill() + c.lineWidth=7;c.fillStyle=NZ;c.beginPath();c.roundRect(-20,54,40,16,5);c.fill();c.stroke() + c.fillStyle=RD;for(const d of[-1,1]){c.beginPath();c.moveTo(d*24,18);c.quadraticCurveTo(d*50,30,d*50,64);c.lineTo(d*24,52);c.closePath();c.fill();c.stroke()} + const bd=()=>{c.beginPath();c.moveTo(0,-56);c.bezierCurveTo(34,-40,34,0,30,58);c.lineTo(-30,58);c.bezierCurveTo(-34,0,-34,-40,0,-56);c.closePath()} + c.fillStyle='#fff';bd();c.fill();c.save();bd();c.clip();c.fillStyle=RD;c.fillRect(-40,-70,80,34);c.fillRect(-40,44,80,20);c.restore();bd();c.stroke() + c.lineWidth=4;c.beginPath();c.moveTo(-31,-36);c.lineTo(31,-36);c.moveTo(-31,44);c.lineTo(31,44);c.stroke() + c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.ellipse(d*12,2,5,7,0,0,T),c.fill() + c.fillStyle='#fff';for(const d of[-1,1])c.beginPath(),c.arc(d*12-2,-1,2.2,0,T),c.fill() + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(d*20,15,6,3.5,0,0,T),c.fill() + c.lineWidth=4.5;c.fillStyle='#ff8787';c.beginPath();c.moveTo(-7,11);c.quadraticCurveTo(0,23,7,11);c.closePath();c.fill();c.stroke() + c.fillStyle='#fff';c.beginPath();c.ellipse(-20,-14,3.5,9,.15,0,T);c.fill() + c.save();c.translate(0,-86);c.rotate(-1.4*w) + for(const[lw,s]of[[9,'#111'],[4,'#ffd8a8']])c.lineWidth=lw,c.strokeStyle=s,c.beginPath(),c.moveTo(-20,28),c.lineTo(-4,36),c.moveTo(20,28),c.lineTo(4,36),c.stroke() + c.strokeStyle='#111';c.lineWidth=6;c.fillStyle='#fff' + c.beginPath();c.moveTo(-26,-38);c.lineTo(12,-38);c.lineTo(26,-24);c.lineTo(26,30);c.lineTo(-26,30);c.closePath();c.fill();c.stroke() + c.fillStyle=LN;c.lineWidth=5;c.beginPath();c.moveTo(12,-38);c.lineTo(12,-24);c.lineTo(26,-24);c.closePath();c.fill();c.stroke() + for(const[lw,s]of[[13,'#111'],[6,AR]])c.lineWidth=lw,c.strokeStyle=s,c.beginPath(),c.moveTo(0,16),c.lineTo(0,-18),c.moveTo(-12,-6),c.lineTo(0,-20),c.lineTo(12,-6),c.stroke() + c.restore() +} diff --git a/gen/uicolor/wallet/moth.js b/gen/uicolor/wallet/moth.js new file mode 100644 index 0000000..38df2d6 --- /dev/null +++ b/gen/uicolor/wallet/moth.js @@ -0,0 +1,36 @@ +// open wallet with nothing in it, a dusty moth flutters up out of the money pocket while the wallet sweats nervously +const{sin,cos,PI,abs,min}=Math,T=2*PI +export const frames=24,delay=80 +const WB='#c08457',WF='#e0a96d',WI='#5c3d2e',ST='#ffe8cc',MW='#ffe8cc',MS='#e0a96d',MB='#ced4da',BL='#ffa8a8',DU='#e9ecef',SW='#74c0fc' +const moth=(c,x,y,s,f,r)=>{ + c.save();c.translate(x,y);c.rotate(r);c.scale(s,s);c.strokeStyle='#111' + for(const d of[-1,1]){c.save();c.scale(d*f,1);c.fillStyle=MW;c.lineWidth=5 + c.beginPath();c.moveTo(0,4);c.bezierCurveTo(24,4,34,22,24,32);c.bezierCurveTo(14,40,4,26,0,10);c.fill();c.stroke() + c.beginPath();c.moveTo(0,-4);c.bezierCurveTo(18,-32,50,-30,46,-8);c.bezierCurveTo(44,8,16,10,0,4);c.fill();c.stroke() + c.fillStyle=MS;c.beginPath();c.arc(30,-10,6,0,T);c.fill();c.beginPath();c.arc(16,20,4,0,T);c.fill();c.restore()} + for(const d of[-1,1])for(const[w,st]of[[7,'#111'],[3,MW]])c.lineWidth=w,c.strokeStyle=st,c.beginPath(),c.moveTo(d*3,-16),c.quadraticCurveTo(d*6,-30,d*16,-34),c.stroke() + c.strokeStyle='#111';c.lineWidth=4.5;c.fillStyle=MB;c.beginPath();c.ellipse(0,8,8,20,0,0,T);c.fill();c.stroke() + c.beginPath();c.arc(0,-13,9,0,T);c.fill();c.stroke() + c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.arc(d*3.5,-14,2,0,T),c.fill() + c.restore() +} +const pos=u=>[128+30*sin(u*T*1.5)*min(1,u*3),184-240*u] +export default(c,t)=>{ + const u=t/.8 + c.fillStyle=WB;c.beginPath();c.roundRect(42,86,172,70,18);c.fill();c.stroke() + c.setLineDash([7,6]);c.strokeStyle=ST;c.lineWidth=3;c.beginPath();c.moveTo(60,100);c.lineTo(196,100);c.stroke();c.setLineDash([]) + c.strokeStyle='#111';c.fillStyle=WI;c.lineWidth=6;c.beginPath();c.roundRect(50,116,156,28,12);c.fill();c.stroke() + if(u<1){const[x,y]=pos(u);moth(c,x,y,1.15,.25+.75*abs(cos(5*PI*t)),.25*cos(u*T*1.5)) + for(let k=1;k<4;k++){const[dx,dy]=pos(u-k*.05),r=7-k*1.5;if(dy<120&&u-k*.05>0)c.fillStyle=DU,c.lineWidth=3,c.beginPath(),c.arc(dx+(k%2?10:-10),dy+40,r,0,T),c.fill(),c.stroke()}} + c.lineWidth=7;c.fillStyle=WF;c.beginPath();c.roundRect(30,130,188,104,22);c.fill();c.stroke() + c.setLineDash([8,7]);c.strokeStyle=ST;c.lineWidth=3;c.beginPath();c.roundRect(42,142,164,80,14);c.stroke();c.setLineDash([]) + c.strokeStyle='#111';c.fillStyle=WB;c.lineWidth=6;c.beginPath();c.roundRect(164,158,68,48,16);c.fill();c.stroke() + c.fillStyle='#ffd43b';c.lineWidth=4;c.beginPath();c.arc(210,182,7,0,T);c.fill();c.stroke() + const bl=(t*3)%1<.06,X=104 + c.fillStyle='#111';for(const d of[-1,1])bl?(c.lineWidth=4.5,c.beginPath(),c.moveTo(X+d*24-6,180),c.lineTo(X+d*24+6,180),c.stroke()):(c.beginPath(),c.arc(X+d*24,180,6.5,0,T),c.fill()) + if(!bl){c.fillStyle='#fff';for(const d of[-1,1])c.beginPath(),c.arc(X-2+d*24,178,2.2,0,T),c.fill()} + c.lineWidth=4.5;for(const d of[-1,1])c.beginPath(),c.moveTo(X+d*14,162),c.lineTo(X+d*32,167),c.stroke() + c.beginPath();for(let x=-12;x<=12;x+=2)c.lineTo(X+x,202+2.5*sin(x/2.5));c.stroke() + c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(X+d*44,194,8,5,0,0,T),c.fill() + const sy=(t*2)%1*8;c.fillStyle=SW;c.lineWidth=3;c.beginPath();c.moveTo(148,150+sy);c.quadraticCurveTo(155,161+sy,148,163+sy);c.quadraticCurveTo(141,161+sy,148,150+sy);c.fill();c.stroke() +} diff --git a/gen/uicolor/warning/siren.js b/gen/uicolor/warning/siren.js new file mode 100644 index 0000000..26a1bd5 --- /dev/null +++ b/gen/uicolor/warning/siren.js @@ -0,0 +1,25 @@ +// alarmed red siren on a hazard-striped base, its light spinning inside the dome, sweeping beams side to side and flashing bright when it faces you +const{sin,cos,PI,max,abs,sign}=Math,T=2*PI +export const frames=20,delay=50 +const RD='#fa5252',RB='#ff8787',GL='#fff3bf',BM='#ffc9c9',HZ='#ffd43b',KN='#868e96' +const dome=c=>{c.beginPath();c.moveTo(66,186);c.lineTo(66,124);c.arc(128,124,62,PI,0);c.lineTo(190,186);c.closePath()} +export default(c,t)=>{ + const a=2*T*t,s=sin(a),k=cos(a),I=max(0,abs(s)-.25)/.75,fr=k>.55 + if(I>0){const d=sign(s);c.fillStyle=BM;c.lineWidth=5;c.beginPath();c.moveTo(128+d*48,112);c.lineTo(128+d*112,124-60*I);c.lineTo(128+d*112,124+60*I);c.lineTo(128+d*48,140);c.closePath();c.fill();c.stroke()} + if(fr)for(const r of[-.84,-.67,-.5,-.33,-.16]){const b=r*PI,l=14+10*(k-.55)/.45;for(const[w,st]of[[11,'#111'],[5,HZ]])c.lineWidth=w,c.strokeStyle=st,c.beginPath(),c.moveTo(128+cos(b)*80,124+sin(b)*80),c.lineTo(128+cos(b)*(80+l),124+sin(b)*(80+l)),c.stroke()} + c.strokeStyle='#111';c.lineWidth=7 + c.fillStyle=KN;c.beginPath();c.roundRect(114,50,28,16,6);c.fill();c.stroke() + dome(c);c.fillStyle=fr?RB:RD;c.fill() + c.save();dome(c);c.clip() + if(k>0){const x=128+46*s,w=34*max(.18,k);c.fillStyle=GL;c.beginPath();c.ellipse(x,128,w,52,0,0,T);c.fill();c.fillStyle='#fff';c.beginPath();c.ellipse(x,128,w*.45,30,0,0,T);c.fill()} + c.restore() + dome(c);c.stroke() + c.strokeStyle='#fff';c.lineWidth=7;c.beginPath();c.arc(128,124,48,PI*1.1,PI*1.36);c.stroke();c.beginPath();c.moveTo(80,128);c.lineTo(80,150);c.stroke();c.strokeStyle='#111' + c.lineWidth=5;c.fillStyle='#fff';for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*22,136,11,13,0,0,T),c.fill(),c.stroke() + c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.arc(128+d*22,138,5,0,T),c.fill() + c.lineWidth=4.5;for(const d of[-1,1])c.beginPath(),c.arc(128+d*22,120,11,PI*1.25,PI*1.75),c.stroke() + c.fillStyle='#111';c.beginPath();c.ellipse(128,166,8,9,0,0,T);c.fill() + c.lineWidth=7;c.fillStyle=HZ;c.beginPath();c.roundRect(44,182,168,44,10);c.fill() + c.save();c.clip();c.strokeStyle='#111';c.lineWidth=12;c.beginPath();for(let x=30;x<240;x+=32)c.moveTo(x,230),c.lineTo(x+36,178);c.stroke();c.restore() + c.beginPath();c.roundRect(44,182,168,44,10);c.stroke() +} diff --git a/gen/uicolor/welcome/door.js b/gen/uicolor/welcome/door.js new file mode 100644 index 0000000..c3fc1ae --- /dev/null +++ b/gen/uicolor/welcome/door.js @@ -0,0 +1,34 @@ +// blue front door swings open toward you, warm golden light pours out with sparkles over a heart welcome mat, then it eases shut +const{sin,cos,PI,min,max}=Math,T=2*PI +export const frames=20,delay=80 +const FR='#a9744f',FRD='#8d6346',DR='#4dabf7',DRD='#339af0',IN='#ffd43b',GLOW='#fff3bf',MAT='#ff6b6b',MATL='#ffa8a8',KN='#ffd43b' +const back=u=>{const s=1.4;return 1+(s+1)*(u-1)**3+s*(u-1)**2},io=u=>u*u*(3-2*u) +const sp=(c,x,y,s)=>{c.lineWidth=4;c.fillStyle='#fff';c.beginPath();c.moveTo(x,y-s);for(const[px,py,qx,qy]of[[s,0,s*.18,-s*.18],[0,s,s*.18,s*.18],[-s,0,-s*.18,s*.18],[0,-s,-s*.18,-s*.18]])c.quadraticCurveTo(x+qx,y+qy,x+px,y+py);c.fill();c.stroke()} +const X0=76,X1=180,Y0=36,Y1=208 +export default(c,t)=>{ + const o=t<.08?0:t<.36?back((t-.08)/.28):t<.78?1:t<.94?1-io((t-.78)/.16):0,th=o*1.2,fx=X0+(X1-X0)*cos(th),d=18*sin(th) + const m=(u,v)=>[X0+u*(fx-X0),(Y0-d*u)+v*((Y1+d*u)-(Y0-d*u))],q=(u0,v0,u1,v1)=>{c.beginPath();for(const[u,v]of[[u0,v0],[u1,v0],[u1,v1],[u0,v1]])c.lineTo(...m(u,v));c.closePath()} + const L=min(1,o*1.5) + if(L>.05)for(let k=0;k<6;k++){ + const e=k%3-1,a=k<3?e*.5:PI-e*.5,tw=.75+.25*sin(2*T*t+k*2),x=128+(k<3?78:-78),y=118+e*64,l=24*L*tw + for(const[w,s]of[[11,'#111'],[5,IN]])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.moveTo(x,y),c.lineTo(x+cos(a)*l,y+sin(a)*l),c.stroke() + } + c.strokeStyle='#111';c.lineWidth=7 + c.fillStyle=FR;c.beginPath();c.roundRect(60,20,136,196,[18,18,4,4]);c.fill();c.stroke() + c.fillStyle=FRD;c.fillRect(64,24,8,188) + c.fillStyle=IN;c.beginPath();c.rect(X0,Y0,X1-X0,Y1-Y0);c.fill() + c.save();c.clip();c.fillStyle=GLOW;c.beginPath();c.ellipse(140,120,40*L+4,70*L+4,0,0,T);c.fill();c.restore() + c.lineWidth=5;c.beginPath();c.rect(X0,Y0,X1-X0,Y1-Y0);c.stroke() + c.lineWidth=7;c.fillStyle=MAT;c.beginPath();c.roundRect(46,212,164,30,8);c.fill();c.stroke() + c.strokeStyle=MATL;c.lineWidth=4;c.beginPath();c.roundRect(56,219,144,16,4);c.stroke();c.strokeStyle='#111' + c.fillStyle='#fff';c.lineWidth=4;c.beginPath();c.moveTo(128,234);c.bezierCurveTo(112,226,116,214,128,221);c.bezierCurveTo(140,214,144,226,128,234);c.fill();c.stroke() + if(L>.3)for(const[x0,y0,ph]of[[150,150,0],[118,96,.33],[160,70,.66]]){const p=(t*2+ph)%1,s=11*sin(PI*p)*min(1,(L-.3)*3);if(s>1.5)sp(c,x0+30*p,y0-26*p,s)} + c.lineWidth=7;q(0,0,1,1);c.fillStyle=DR;c.fill();c.stroke() + if(th<1.45){ + c.fillStyle=DRD;c.lineWidth=5 + for(const[u0,v0,u1,v1]of[[.18,.5,.82,.68],[.18,.74,.82,.9]])q(u0,v0,u1,v1),c.fill(),c.stroke() + c.fillStyle=IN;c.beginPath();for(let k=0;k<24;k++){const a=k*T/24;c.lineTo(...m(.5+.26*cos(a),.25+.15*sin(a)))}c.closePath();c.fill();c.stroke() + c.strokeStyle='#fff';c.lineWidth=4;c.beginPath();for(let k=0;k<6;k++){const a=PI*1.1+k*.08;c.lineTo(...m(.5+.19*cos(a),.25+.11*sin(a)))}c.stroke();c.strokeStyle='#111' + const[kx,ky]=m(.86,.46);c.fillStyle=KN;c.lineWidth=4;c.beginPath();c.ellipse(kx,ky,7*max(.35,cos(th)),7,0,0,T);c.fill();c.stroke() + } +} diff --git a/public/403/batsu.gif b/public/403/batsu.gif new file mode 100644 index 0000000..47eb7f9 Binary files /dev/null and b/public/403/batsu.gif differ diff --git a/public/403/batsu.webp b/public/403/batsu.webp new file mode 100644 index 0000000..46dac4c Binary files /dev/null and b/public/403/batsu.webp differ diff --git a/public/403/door.gif b/public/403/door.gif new file mode 100644 index 0000000..1604e68 Binary files /dev/null and b/public/403/door.gif differ diff --git a/public/403/door.webp b/public/403/door.webp new file mode 100644 index 0000000..12d1538 Binary files /dev/null and b/public/403/door.webp differ diff --git a/public/403/stop.gif b/public/403/stop.gif new file mode 100644 index 0000000..b4b1603 Binary files /dev/null and b/public/403/stop.gif differ diff --git a/public/403/stop.webp b/public/403/stop.webp new file mode 100644 index 0000000..61cd857 Binary files /dev/null and b/public/403/stop.webp differ diff --git a/public/404/flashlight.gif b/public/404/flashlight.gif new file mode 100644 index 0000000..571246d Binary files /dev/null and b/public/404/flashlight.gif differ diff --git a/public/404/flashlight.webp b/public/404/flashlight.webp new file mode 100644 index 0000000..ef5fd68 Binary files /dev/null and b/public/404/flashlight.webp differ diff --git a/public/404/ghost.gif b/public/404/ghost.gif new file mode 100644 index 0000000..3492bb7 Binary files /dev/null and b/public/404/ghost.gif differ diff --git a/public/404/ghost.webp b/public/404/ghost.webp new file mode 100644 index 0000000..d56166b Binary files /dev/null and b/public/404/ghost.webp differ diff --git a/public/404/hole.gif b/public/404/hole.gif new file mode 100644 index 0000000..4b99dec Binary files /dev/null and b/public/404/hole.gif differ diff --git a/public/404/hole.webp b/public/404/hole.webp new file mode 100644 index 0000000..62fbdc8 Binary files /dev/null and b/public/404/hole.webp differ diff --git a/public/404/lost.gif b/public/404/lost.gif new file mode 100644 index 0000000..4f064dd Binary files /dev/null and b/public/404/lost.gif differ diff --git a/public/404/lost.webp b/public/404/lost.webp new file mode 100644 index 0000000..126e0f4 Binary files /dev/null and b/public/404/lost.webp differ diff --git a/public/404/magnifier.gif b/public/404/magnifier.gif new file mode 100644 index 0000000..5f8811b Binary files /dev/null and b/public/404/magnifier.gif differ diff --git a/public/404/magnifier.webp b/public/404/magnifier.webp new file mode 100644 index 0000000..5b1fdd3 Binary files /dev/null and b/public/404/magnifier.webp differ diff --git a/public/404/map.gif b/public/404/map.gif new file mode 100644 index 0000000..794414d Binary files /dev/null and b/public/404/map.gif differ diff --git a/public/404/map.webp b/public/404/map.webp new file mode 100644 index 0000000..d517cde Binary files /dev/null and b/public/404/map.webp differ diff --git a/public/404/peek.gif b/public/404/peek.gif new file mode 100644 index 0000000..d0ade27 Binary files /dev/null and b/public/404/peek.gif differ diff --git a/public/404/peek.webp b/public/404/peek.webp new file mode 100644 index 0000000..b1b4390 Binary files /dev/null and b/public/404/peek.webp differ diff --git a/public/404/shrug.gif b/public/404/shrug.gif new file mode 100644 index 0000000..a0ba288 Binary files /dev/null and b/public/404/shrug.gif differ diff --git a/public/404/shrug.webp b/public/404/shrug.webp new file mode 100644 index 0000000..088b4ce Binary files /dev/null and b/public/404/shrug.webp differ diff --git a/public/404/signpost.gif b/public/404/signpost.gif new file mode 100644 index 0000000..5616b72 Binary files /dev/null and b/public/404/signpost.gif differ diff --git a/public/404/signpost.webp b/public/404/signpost.webp new file mode 100644 index 0000000..228008a Binary files /dev/null and b/public/404/signpost.webp differ diff --git a/public/404/space.gif b/public/404/space.gif new file mode 100644 index 0000000..cc1a4dd Binary files /dev/null and b/public/404/space.gif differ diff --git a/public/404/space.webp b/public/404/space.webp new file mode 100644 index 0000000..630e4b0 Binary files /dev/null and b/public/404/space.webp differ diff --git a/public/404/tumbleweed.gif b/public/404/tumbleweed.gif new file mode 100644 index 0000000..8400493 Binary files /dev/null and b/public/404/tumbleweed.gif differ diff --git a/public/404/tumbleweed.webp b/public/404/tumbleweed.webp new file mode 100644 index 0000000..a35768a Binary files /dev/null and b/public/404/tumbleweed.webp differ diff --git a/public/404/ufo.gif b/public/404/ufo.gif new file mode 100644 index 0000000..d64bf85 Binary files /dev/null and b/public/404/ufo.gif differ diff --git a/public/404/ufo.webp b/public/404/ufo.webp new file mode 100644 index 0000000..bd82fe1 Binary files /dev/null and b/public/404/ufo.webp differ diff --git a/public/500/fire.gif b/public/500/fire.gif new file mode 100644 index 0000000..b7e5266 Binary files /dev/null and b/public/500/fire.gif differ diff --git a/public/500/fire.webp b/public/500/fire.webp new file mode 100644 index 0000000..98a67fe Binary files /dev/null and b/public/500/fire.webp differ diff --git a/public/500/fix.gif b/public/500/fix.gif new file mode 100644 index 0000000..b8cfdad Binary files /dev/null and b/public/500/fix.gif differ diff --git a/public/500/fix.webp b/public/500/fix.webp new file mode 100644 index 0000000..80f99d4 Binary files /dev/null and b/public/500/fix.webp differ diff --git a/public/500/server.gif b/public/500/server.gif new file mode 100644 index 0000000..c14a28b Binary files /dev/null and b/public/500/server.gif differ diff --git a/public/500/server.webp b/public/500/server.webp new file mode 100644 index 0000000..ee9e9da Binary files /dev/null and b/public/500/server.webp differ diff --git a/public/achievement/star.gif b/public/achievement/star.gif new file mode 100644 index 0000000..9e4ec6f Binary files /dev/null and b/public/achievement/star.gif differ diff --git a/public/achievement/star.webp b/public/achievement/star.webp new file mode 100644 index 0000000..db3dcf0 Binary files /dev/null and b/public/achievement/star.webp differ diff --git a/public/battery/low.gif b/public/battery/low.gif new file mode 100644 index 0000000..06660aa Binary files /dev/null and b/public/battery/low.gif differ diff --git a/public/battery/low.webp b/public/battery/low.webp new file mode 100644 index 0000000..c9c8d4c Binary files /dev/null and b/public/battery/low.webp differ diff --git a/public/bell/quiet.gif b/public/bell/quiet.gif new file mode 100644 index 0000000..2f0b4e4 Binary files /dev/null and b/public/bell/quiet.gif differ diff --git a/public/bell/quiet.webp b/public/bell/quiet.webp new file mode 100644 index 0000000..6b18d15 Binary files /dev/null and b/public/bell/quiet.webp differ diff --git a/public/box/empty.gif b/public/box/empty.gif new file mode 100644 index 0000000..4b3a8b5 Binary files /dev/null and b/public/box/empty.gif differ diff --git a/public/box/empty.webp b/public/box/empty.webp new file mode 100644 index 0000000..24532fa Binary files /dev/null and b/public/box/empty.webp differ diff --git a/public/box/hide.gif b/public/box/hide.gif new file mode 100644 index 0000000..4200f2e Binary files /dev/null and b/public/box/hide.gif differ diff --git a/public/box/hide.webp b/public/box/hide.webp new file mode 100644 index 0000000..93e6e1e Binary files /dev/null and b/public/box/hide.webp differ diff --git a/public/buffering/stare.gif b/public/buffering/stare.gif new file mode 100644 index 0000000..4c30494 Binary files /dev/null and b/public/buffering/stare.gif differ diff --git a/public/buffering/stare.webp b/public/buffering/stare.webp new file mode 100644 index 0000000..5335933 Binary files /dev/null and b/public/buffering/stare.webp differ diff --git a/public/buffering/video.gif b/public/buffering/video.gif new file mode 100644 index 0000000..7eb7fd4 Binary files /dev/null and b/public/buffering/video.gif differ diff --git a/public/buffering/video.webp b/public/buffering/video.webp new file mode 100644 index 0000000..11b3a9c Binary files /dev/null and b/public/buffering/video.webp differ diff --git a/public/calendar/empty.gif b/public/calendar/empty.gif new file mode 100644 index 0000000..dbc4d48 Binary files /dev/null and b/public/calendar/empty.gif differ diff --git a/public/calendar/empty.webp b/public/calendar/empty.webp new file mode 100644 index 0000000..05112cc Binary files /dev/null and b/public/calendar/empty.webp differ diff --git a/public/calendar/free.gif b/public/calendar/free.gif new file mode 100644 index 0000000..550b89b Binary files /dev/null and b/public/calendar/free.gif differ diff --git a/public/calendar/free.webp b/public/calendar/free.webp new file mode 100644 index 0000000..a8032a7 Binary files /dev/null and b/public/calendar/free.webp differ diff --git a/public/cart/empty.gif b/public/cart/empty.gif new file mode 100644 index 0000000..8bd8436 Binary files /dev/null and b/public/cart/empty.gif differ diff --git a/public/cart/empty.webp b/public/cart/empty.webp new file mode 100644 index 0000000..b1094ff Binary files /dev/null and b/public/cart/empty.webp differ diff --git a/public/cart/sad.gif b/public/cart/sad.gif new file mode 100644 index 0000000..2df0044 Binary files /dev/null and b/public/cart/sad.gif differ diff --git a/public/cart/sad.webp b/public/cart/sad.webp new file mode 100644 index 0000000..2160984 Binary files /dev/null and b/public/cart/sad.webp differ diff --git a/public/cart/sigh.gif b/public/cart/sigh.gif new file mode 100644 index 0000000..dee3741 Binary files /dev/null and b/public/cart/sigh.gif differ diff --git a/public/cart/sigh.webp b/public/cart/sigh.webp new file mode 100644 index 0000000..88376f8 Binary files /dev/null and b/public/cart/sigh.webp differ diff --git a/public/chat/crickets.gif b/public/chat/crickets.gif new file mode 100644 index 0000000..cb783ce Binary files /dev/null and b/public/chat/crickets.gif differ diff --git a/public/chat/crickets.webp b/public/chat/crickets.webp new file mode 100644 index 0000000..6c9c61f Binary files /dev/null and b/public/chat/crickets.webp differ diff --git a/public/comingsoon/curtain.gif b/public/comingsoon/curtain.gif new file mode 100644 index 0000000..7b4bd52 Binary files /dev/null and b/public/comingsoon/curtain.gif differ diff --git a/public/comingsoon/curtain.webp b/public/comingsoon/curtain.webp new file mode 100644 index 0000000..fd8c1e4 Binary files /dev/null and b/public/comingsoon/curtain.webp differ diff --git a/public/comingsoon/oven.gif b/public/comingsoon/oven.gif new file mode 100644 index 0000000..4b2beb5 Binary files /dev/null and b/public/comingsoon/oven.gif differ diff --git a/public/comingsoon/oven.webp b/public/comingsoon/oven.webp new file mode 100644 index 0000000..ed8e246 Binary files /dev/null and b/public/comingsoon/oven.webp differ diff --git a/public/comingsoon/shh.gif b/public/comingsoon/shh.gif new file mode 100644 index 0000000..d4556da Binary files /dev/null and b/public/comingsoon/shh.gif differ diff --git a/public/comingsoon/shh.webp b/public/comingsoon/shh.webp new file mode 100644 index 0000000..c5a2b60 Binary files /dev/null and b/public/comingsoon/shh.webp differ diff --git a/public/confirmed/handshake.gif b/public/confirmed/handshake.gif new file mode 100644 index 0000000..97cf759 Binary files /dev/null and b/public/confirmed/handshake.gif differ diff --git a/public/confirmed/handshake.webp b/public/confirmed/handshake.webp new file mode 100644 index 0000000..5cce597 Binary files /dev/null and b/public/confirmed/handshake.webp differ diff --git a/public/construction/barrier.gif b/public/construction/barrier.gif new file mode 100644 index 0000000..605c71d Binary files /dev/null and b/public/construction/barrier.gif differ diff --git a/public/construction/barrier.webp b/public/construction/barrier.webp new file mode 100644 index 0000000..682b023 Binary files /dev/null and b/public/construction/barrier.webp differ diff --git a/public/construction/cone.gif b/public/construction/cone.gif new file mode 100644 index 0000000..47d68f4 Binary files /dev/null and b/public/construction/cone.gif differ diff --git a/public/construction/cone.webp b/public/construction/cone.webp new file mode 100644 index 0000000..9e343bf Binary files /dev/null and b/public/construction/cone.webp differ diff --git a/public/construction/crane.gif b/public/construction/crane.gif new file mode 100644 index 0000000..2bbf8db Binary files /dev/null and b/public/construction/crane.gif differ diff --git a/public/construction/crane.webp b/public/construction/crane.webp new file mode 100644 index 0000000..16e6a90 Binary files /dev/null and b/public/construction/crane.webp differ diff --git a/public/construction/excavator.gif b/public/construction/excavator.gif new file mode 100644 index 0000000..87e99c5 Binary files /dev/null and b/public/construction/excavator.gif differ diff --git a/public/construction/excavator.webp b/public/construction/excavator.webp new file mode 100644 index 0000000..c9fb5a2 Binary files /dev/null and b/public/construction/excavator.webp differ diff --git a/public/construction/hardhat.gif b/public/construction/hardhat.gif new file mode 100644 index 0000000..4a018bb Binary files /dev/null and b/public/construction/hardhat.gif differ diff --git a/public/construction/hardhat.webp b/public/construction/hardhat.webp new file mode 100644 index 0000000..62be056 Binary files /dev/null and b/public/construction/hardhat.webp differ diff --git a/public/construction/paint.gif b/public/construction/paint.gif new file mode 100644 index 0000000..124edfa Binary files /dev/null and b/public/construction/paint.gif differ diff --git a/public/construction/paint.webp b/public/construction/paint.webp new file mode 100644 index 0000000..3afefba Binary files /dev/null and b/public/construction/paint.webp differ diff --git a/public/copied/clipboard.gif b/public/copied/clipboard.gif new file mode 100644 index 0000000..6d61b07 Binary files /dev/null and b/public/copied/clipboard.gif differ diff --git a/public/copied/clipboard.webp b/public/copied/clipboard.webp new file mode 100644 index 0000000..891c829 Binary files /dev/null and b/public/copied/clipboard.webp differ diff --git a/public/coupon/scissors.gif b/public/coupon/scissors.gif new file mode 100644 index 0000000..9e5cabe Binary files /dev/null and b/public/coupon/scissors.gif differ diff --git a/public/coupon/scissors.webp b/public/coupon/scissors.webp new file mode 100644 index 0000000..f2fc28b Binary files /dev/null and b/public/coupon/scissors.webp differ diff --git a/public/crash/browser.gif b/public/crash/browser.gif new file mode 100644 index 0000000..192cc0f Binary files /dev/null and b/public/crash/browser.gif differ diff --git a/public/crash/browser.webp b/public/crash/browser.webp new file mode 100644 index 0000000..7bac081 Binary files /dev/null and b/public/crash/browser.webp differ diff --git a/public/deleted/shredder.gif b/public/deleted/shredder.gif new file mode 100644 index 0000000..09e4530 Binary files /dev/null and b/public/deleted/shredder.gif differ diff --git a/public/deleted/shredder.webp b/public/deleted/shredder.webp new file mode 100644 index 0000000..b6ce5c9 Binary files /dev/null and b/public/deleted/shredder.webp differ diff --git a/public/done/checklist.gif b/public/done/checklist.gif new file mode 100644 index 0000000..207eed5 Binary files /dev/null and b/public/done/checklist.gif differ diff --git a/public/done/checklist.webp b/public/done/checklist.webp new file mode 100644 index 0000000..8993c9b Binary files /dev/null and b/public/done/checklist.webp differ diff --git a/public/download/catch.gif b/public/download/catch.gif new file mode 100644 index 0000000..d90c842 Binary files /dev/null and b/public/download/catch.gif differ diff --git a/public/download/catch.webp b/public/download/catch.webp new file mode 100644 index 0000000..8cd4a8f Binary files /dev/null and b/public/download/catch.webp differ diff --git a/public/download/parachute.gif b/public/download/parachute.gif new file mode 100644 index 0000000..42351bd Binary files /dev/null and b/public/download/parachute.gif differ diff --git a/public/download/parachute.webp b/public/download/parachute.webp new file mode 100644 index 0000000..d827e67 Binary files /dev/null and b/public/download/parachute.webp differ diff --git a/public/download/tray.gif b/public/download/tray.gif new file mode 100644 index 0000000..7f43fa1 Binary files /dev/null and b/public/download/tray.gif differ diff --git a/public/download/tray.webp b/public/download/tray.webp new file mode 100644 index 0000000..58047c1 Binary files /dev/null and b/public/download/tray.webp differ diff --git a/public/error/bug.gif b/public/error/bug.gif new file mode 100644 index 0000000..5070a66 Binary files /dev/null and b/public/error/bug.gif differ diff --git a/public/error/bug.webp b/public/error/bug.webp new file mode 100644 index 0000000..0558bc3 Binary files /dev/null and b/public/error/bug.webp differ diff --git a/public/error/cloud.gif b/public/error/cloud.gif new file mode 100644 index 0000000..58dd160 Binary files /dev/null and b/public/error/cloud.gif differ diff --git a/public/error/cloud.webp b/public/error/cloud.webp new file mode 100644 index 0000000..6d088c2 Binary files /dev/null and b/public/error/cloud.webp differ diff --git a/public/error/cookie.gif b/public/error/cookie.gif new file mode 100644 index 0000000..67196d3 Binary files /dev/null and b/public/error/cookie.gif differ diff --git a/public/error/cookie.webp b/public/error/cookie.webp new file mode 100644 index 0000000..128bc99 Binary files /dev/null and b/public/error/cookie.webp differ diff --git a/public/error/cross.gif b/public/error/cross.gif new file mode 100644 index 0000000..51a266e Binary files /dev/null and b/public/error/cross.gif differ diff --git a/public/error/cross.webp b/public/error/cross.webp new file mode 100644 index 0000000..1aca09c Binary files /dev/null and b/public/error/cross.webp differ diff --git a/public/error/cry.gif b/public/error/cry.gif new file mode 100644 index 0000000..786d2da Binary files /dev/null and b/public/error/cry.gif differ diff --git a/public/error/cry.webp b/public/error/cry.webp new file mode 100644 index 0000000..c9aba20 Binary files /dev/null and b/public/error/cry.webp differ diff --git a/public/error/glitch.gif b/public/error/glitch.gif new file mode 100644 index 0000000..329a85d Binary files /dev/null and b/public/error/glitch.gif differ diff --git a/public/error/glitch.webp b/public/error/glitch.webp new file mode 100644 index 0000000..e65f2d5 Binary files /dev/null and b/public/error/glitch.webp differ diff --git a/public/error/robot.gif b/public/error/robot.gif new file mode 100644 index 0000000..6e18b69 Binary files /dev/null and b/public/error/robot.gif differ diff --git a/public/error/robot.webp b/public/error/robot.webp new file mode 100644 index 0000000..dc534c3 Binary files /dev/null and b/public/error/robot.webp differ diff --git a/public/error/smoke.gif b/public/error/smoke.gif new file mode 100644 index 0000000..78e0b22 Binary files /dev/null and b/public/error/smoke.gif differ diff --git a/public/error/smoke.webp b/public/error/smoke.webp new file mode 100644 index 0000000..9f135ad Binary files /dev/null and b/public/error/smoke.webp differ diff --git a/public/error/tehe.gif b/public/error/tehe.gif new file mode 100644 index 0000000..9f6533f Binary files /dev/null and b/public/error/tehe.gif differ diff --git a/public/error/tehe.webp b/public/error/tehe.webp new file mode 100644 index 0000000..a520f09 Binary files /dev/null and b/public/error/tehe.webp differ diff --git a/public/expired/milk.gif b/public/expired/milk.gif new file mode 100644 index 0000000..dee6b58 Binary files /dev/null and b/public/expired/milk.gif differ diff --git a/public/expired/milk.webp b/public/expired/milk.webp new file mode 100644 index 0000000..62fc420 Binary files /dev/null and b/public/expired/milk.webp differ diff --git a/public/failed/balloon.gif b/public/failed/balloon.gif new file mode 100644 index 0000000..4feb1ba Binary files /dev/null and b/public/failed/balloon.gif differ diff --git a/public/failed/balloon.webp b/public/failed/balloon.webp new file mode 100644 index 0000000..a38ae68 Binary files /dev/null and b/public/failed/balloon.webp differ diff --git a/public/favorites/empty.gif b/public/favorites/empty.gif new file mode 100644 index 0000000..ff6991d Binary files /dev/null and b/public/favorites/empty.gif differ diff --git a/public/favorites/empty.webp b/public/favorites/empty.webp new file mode 100644 index 0000000..b44e39e Binary files /dev/null and b/public/favorites/empty.webp differ diff --git a/public/folder/dust.gif b/public/folder/dust.gif new file mode 100644 index 0000000..b95b844 Binary files /dev/null and b/public/folder/dust.gif differ diff --git a/public/folder/dust.webp b/public/folder/dust.webp new file mode 100644 index 0000000..0868024 Binary files /dev/null and b/public/folder/dust.webp differ diff --git a/public/folder/empty.gif b/public/folder/empty.gif new file mode 100644 index 0000000..f753fb8 Binary files /dev/null and b/public/folder/empty.gif differ diff --git a/public/folder/empty.webp b/public/folder/empty.webp new file mode 100644 index 0000000..9fe84f1 Binary files /dev/null and b/public/folder/empty.webp differ diff --git a/public/fridge/empty.gif b/public/fridge/empty.gif new file mode 100644 index 0000000..82ddbe6 Binary files /dev/null and b/public/fridge/empty.gif differ diff --git a/public/fridge/empty.webp b/public/fridge/empty.webp new file mode 100644 index 0000000..312232a Binary files /dev/null and b/public/fridge/empty.webp differ diff --git a/public/inbox/empty.gif b/public/inbox/empty.gif new file mode 100644 index 0000000..4cfe510 Binary files /dev/null and b/public/inbox/empty.gif differ diff --git a/public/inbox/empty.webp b/public/inbox/empty.webp new file mode 100644 index 0000000..9a89949 Binary files /dev/null and b/public/inbox/empty.webp differ diff --git a/public/inbox/zero.gif b/public/inbox/zero.gif new file mode 100644 index 0000000..2d2416a Binary files /dev/null and b/public/inbox/zero.gif differ diff --git a/public/inbox/zero.webp b/public/inbox/zero.webp new file mode 100644 index 0000000..c6c2a2e Binary files /dev/null and b/public/inbox/zero.webp differ diff --git a/public/jar/empty.gif b/public/jar/empty.gif new file mode 100644 index 0000000..8807dae Binary files /dev/null and b/public/jar/empty.gif differ diff --git a/public/jar/empty.webp b/public/jar/empty.webp new file mode 100644 index 0000000..9874e0b Binary files /dev/null and b/public/jar/empty.webp differ diff --git a/public/loading/bar.gif b/public/loading/bar.gif new file mode 100644 index 0000000..723498d Binary files /dev/null and b/public/loading/bar.gif differ diff --git a/public/loading/bar.webp b/public/loading/bar.webp new file mode 100644 index 0000000..156f7ee Binary files /dev/null and b/public/loading/bar.webp differ diff --git a/public/loading/blocks.gif b/public/loading/blocks.gif new file mode 100644 index 0000000..697ea9c Binary files /dev/null and b/public/loading/blocks.gif differ diff --git a/public/loading/blocks.webp b/public/loading/blocks.webp new file mode 100644 index 0000000..8e2d28e Binary files /dev/null and b/public/loading/blocks.webp differ diff --git a/public/loading/candy.gif b/public/loading/candy.gif new file mode 100644 index 0000000..78cc9f2 Binary files /dev/null and b/public/loading/candy.gif differ diff --git a/public/loading/candy.webp b/public/loading/candy.webp new file mode 100644 index 0000000..9da404a Binary files /dev/null and b/public/loading/candy.webp differ diff --git a/public/loading/cat.gif b/public/loading/cat.gif new file mode 100644 index 0000000..1931766 Binary files /dev/null and b/public/loading/cat.gif differ diff --git a/public/loading/cat.webp b/public/loading/cat.webp new file mode 100644 index 0000000..14adf04 Binary files /dev/null and b/public/loading/cat.webp differ diff --git a/public/loading/coffee.gif b/public/loading/coffee.gif new file mode 100644 index 0000000..6cbb757 Binary files /dev/null and b/public/loading/coffee.gif differ diff --git a/public/loading/coffee.webp b/public/loading/coffee.webp new file mode 100644 index 0000000..1b7e11d Binary files /dev/null and b/public/loading/coffee.webp differ diff --git a/public/loading/dots.gif b/public/loading/dots.gif new file mode 100644 index 0000000..3d8e2f0 Binary files /dev/null and b/public/loading/dots.gif differ diff --git a/public/loading/dots.webp b/public/loading/dots.webp new file mode 100644 index 0000000..5747180 Binary files /dev/null and b/public/loading/dots.webp differ diff --git a/public/loading/fishing.gif b/public/loading/fishing.gif new file mode 100644 index 0000000..762ab1d Binary files /dev/null and b/public/loading/fishing.gif differ diff --git a/public/loading/fishing.webp b/public/loading/fishing.webp new file mode 100644 index 0000000..67e33c8 Binary files /dev/null and b/public/loading/fishing.webp differ diff --git a/public/loading/gummies.gif b/public/loading/gummies.gif new file mode 100644 index 0000000..0dd7b99 Binary files /dev/null and b/public/loading/gummies.gif differ diff --git a/public/loading/gummies.webp b/public/loading/gummies.webp new file mode 100644 index 0000000..114516f Binary files /dev/null and b/public/loading/gummies.webp differ diff --git a/public/loading/microwave.gif b/public/loading/microwave.gif new file mode 100644 index 0000000..b4c5dc8 Binary files /dev/null and b/public/loading/microwave.gif differ diff --git a/public/loading/microwave.webp b/public/loading/microwave.webp new file mode 100644 index 0000000..79cd378 Binary files /dev/null and b/public/loading/microwave.webp differ diff --git a/public/loading/orbit.gif b/public/loading/orbit.gif new file mode 100644 index 0000000..02f0e4f Binary files /dev/null and b/public/loading/orbit.gif differ diff --git a/public/loading/orbit.webp b/public/loading/orbit.webp new file mode 100644 index 0000000..ee63a54 Binary files /dev/null and b/public/loading/orbit.webp differ diff --git a/public/loading/pinwheel.gif b/public/loading/pinwheel.gif new file mode 100644 index 0000000..63bb8b4 Binary files /dev/null and b/public/loading/pinwheel.gif differ diff --git a/public/loading/pinwheel.webp b/public/loading/pinwheel.webp new file mode 100644 index 0000000..9105ce8 Binary files /dev/null and b/public/loading/pinwheel.webp differ diff --git a/public/loading/pizza.gif b/public/loading/pizza.gif new file mode 100644 index 0000000..8b9418d Binary files /dev/null and b/public/loading/pizza.gif differ diff --git a/public/loading/pizza.webp b/public/loading/pizza.webp new file mode 100644 index 0000000..85dd76a Binary files /dev/null and b/public/loading/pizza.webp differ diff --git a/public/loading/pray.gif b/public/loading/pray.gif new file mode 100644 index 0000000..6d5572e Binary files /dev/null and b/public/loading/pray.gif differ diff --git a/public/loading/pray.webp b/public/loading/pray.webp new file mode 100644 index 0000000..dbc9349 Binary files /dev/null and b/public/loading/pray.webp differ diff --git a/public/loading/pulse.gif b/public/loading/pulse.gif new file mode 100644 index 0000000..b9a1b65 Binary files /dev/null and b/public/loading/pulse.gif differ diff --git a/public/loading/pulse.webp b/public/loading/pulse.webp new file mode 100644 index 0000000..1bd48e6 Binary files /dev/null and b/public/loading/pulse.webp differ diff --git a/public/loading/push.gif b/public/loading/push.gif new file mode 100644 index 0000000..64efa1d Binary files /dev/null and b/public/loading/push.gif differ diff --git a/public/loading/push.webp b/public/loading/push.webp new file mode 100644 index 0000000..f4d0000 Binary files /dev/null and b/public/loading/push.webp differ diff --git a/public/loading/rainbow.gif b/public/loading/rainbow.gif new file mode 100644 index 0000000..a9f8f8a Binary files /dev/null and b/public/loading/rainbow.gif differ diff --git a/public/loading/rainbow.webp b/public/loading/rainbow.webp new file mode 100644 index 0000000..046355a Binary files /dev/null and b/public/loading/rainbow.webp differ diff --git a/public/loading/ring.gif b/public/loading/ring.gif new file mode 100644 index 0000000..3e0c0de Binary files /dev/null and b/public/loading/ring.gif differ diff --git a/public/loading/ring.webp b/public/loading/ring.webp new file mode 100644 index 0000000..7f19673 Binary files /dev/null and b/public/loading/ring.webp differ diff --git a/public/loading/run.gif b/public/loading/run.gif new file mode 100644 index 0000000..c1ca5ae Binary files /dev/null and b/public/loading/run.gif differ diff --git a/public/loading/run.webp b/public/loading/run.webp new file mode 100644 index 0000000..1e2ca18 Binary files /dev/null and b/public/loading/run.webp differ diff --git a/public/loading/skeleton.gif b/public/loading/skeleton.gif new file mode 100644 index 0000000..f2c1372 Binary files /dev/null and b/public/loading/skeleton.gif differ diff --git a/public/loading/skeleton.webp b/public/loading/skeleton.webp new file mode 100644 index 0000000..b3a8f35 Binary files /dev/null and b/public/loading/skeleton.webp differ diff --git a/public/loading/sleepy.gif b/public/loading/sleepy.gif new file mode 100644 index 0000000..271883c Binary files /dev/null and b/public/loading/sleepy.gif differ diff --git a/public/loading/sleepy.webp b/public/loading/sleepy.webp new file mode 100644 index 0000000..909384d Binary files /dev/null and b/public/loading/sleepy.webp differ diff --git a/public/loading/snail.gif b/public/loading/snail.gif new file mode 100644 index 0000000..b8d1d81 Binary files /dev/null and b/public/loading/snail.gif differ diff --git a/public/loading/snail.webp b/public/loading/snail.webp new file mode 100644 index 0000000..536cc85 Binary files /dev/null and b/public/loading/snail.webp differ diff --git a/public/loading/tea.gif b/public/loading/tea.gif new file mode 100644 index 0000000..a8a6f5d Binary files /dev/null and b/public/loading/tea.gif differ diff --git a/public/loading/tea.webp b/public/loading/tea.webp new file mode 100644 index 0000000..c207b2e Binary files /dev/null and b/public/loading/tea.webp differ diff --git a/public/loading/wait.gif b/public/loading/wait.gif new file mode 100644 index 0000000..0918e2b Binary files /dev/null and b/public/loading/wait.gif differ diff --git a/public/loading/wait.webp b/public/loading/wait.webp new file mode 100644 index 0000000..2fefb54 Binary files /dev/null and b/public/loading/wait.webp differ diff --git a/public/locked/key.gif b/public/locked/key.gif new file mode 100644 index 0000000..f5349f8 Binary files /dev/null and b/public/locked/key.gif differ diff --git a/public/locked/key.webp b/public/locked/key.webp new file mode 100644 index 0000000..3d976cf Binary files /dev/null and b/public/locked/key.webp differ diff --git a/public/locked/vault.gif b/public/locked/vault.gif new file mode 100644 index 0000000..008132d Binary files /dev/null and b/public/locked/vault.gif differ diff --git a/public/locked/vault.webp b/public/locked/vault.webp new file mode 100644 index 0000000..e8c24fd Binary files /dev/null and b/public/locked/vault.webp differ diff --git a/public/logout/wave.gif b/public/logout/wave.gif new file mode 100644 index 0000000..0c529dd Binary files /dev/null and b/public/logout/wave.gif differ diff --git a/public/logout/wave.webp b/public/logout/wave.webp new file mode 100644 index 0000000..02f8007 Binary files /dev/null and b/public/logout/wave.webp differ diff --git a/public/mailbox/check.gif b/public/mailbox/check.gif new file mode 100644 index 0000000..d4c2551 Binary files /dev/null and b/public/mailbox/check.gif differ diff --git a/public/mailbox/check.webp b/public/mailbox/check.webp new file mode 100644 index 0000000..b642494 Binary files /dev/null and b/public/mailbox/check.webp differ diff --git a/public/mailbox/empty.gif b/public/mailbox/empty.gif new file mode 100644 index 0000000..391fb38 Binary files /dev/null and b/public/mailbox/empty.gif differ diff --git a/public/mailbox/empty.webp b/public/mailbox/empty.webp new file mode 100644 index 0000000..f6126d6 Binary files /dev/null and b/public/mailbox/empty.webp differ diff --git a/public/maintenance/mechanic.gif b/public/maintenance/mechanic.gif new file mode 100644 index 0000000..fde78ad Binary files /dev/null and b/public/maintenance/mechanic.gif differ diff --git a/public/maintenance/mechanic.webp b/public/maintenance/mechanic.webp new file mode 100644 index 0000000..2736023 Binary files /dev/null and b/public/maintenance/mechanic.webp differ diff --git a/public/maintenance/robot.gif b/public/maintenance/robot.gif new file mode 100644 index 0000000..1b5be6d Binary files /dev/null and b/public/maintenance/robot.gif differ diff --git a/public/maintenance/robot.webp b/public/maintenance/robot.webp new file mode 100644 index 0000000..39c47fa Binary files /dev/null and b/public/maintenance/robot.webp differ diff --git a/public/maintenance/wrench.gif b/public/maintenance/wrench.gif new file mode 100644 index 0000000..cac2a46 Binary files /dev/null and b/public/maintenance/wrench.gif differ diff --git a/public/maintenance/wrench.webp b/public/maintenance/wrench.webp new file mode 100644 index 0000000..6babc61 Binary files /dev/null and b/public/maintenance/wrench.webp differ diff --git a/public/offline/antenna.gif b/public/offline/antenna.gif new file mode 100644 index 0000000..8677128 Binary files /dev/null and b/public/offline/antenna.gif differ diff --git a/public/offline/antenna.webp b/public/offline/antenna.webp new file mode 100644 index 0000000..346b141 Binary files /dev/null and b/public/offline/antenna.webp differ diff --git a/public/offline/cable.gif b/public/offline/cable.gif new file mode 100644 index 0000000..34289cd Binary files /dev/null and b/public/offline/cable.gif differ diff --git a/public/offline/cable.webp b/public/offline/cable.webp new file mode 100644 index 0000000..8ecbeca Binary files /dev/null and b/public/offline/cable.webp differ diff --git a/public/offline/plug.gif b/public/offline/plug.gif new file mode 100644 index 0000000..327c04f Binary files /dev/null and b/public/offline/plug.gif differ diff --git a/public/offline/plug.webp b/public/offline/plug.webp new file mode 100644 index 0000000..0e60ffd Binary files /dev/null and b/public/offline/plug.webp differ diff --git a/public/offline/satellite.gif b/public/offline/satellite.gif new file mode 100644 index 0000000..0e5b85b Binary files /dev/null and b/public/offline/satellite.gif differ diff --git a/public/offline/satellite.webp b/public/offline/satellite.webp new file mode 100644 index 0000000..84619fe Binary files /dev/null and b/public/offline/satellite.webp differ diff --git a/public/offline/wifi.gif b/public/offline/wifi.gif new file mode 100644 index 0000000..bbdf9fa Binary files /dev/null and b/public/offline/wifi.gif differ diff --git a/public/offline/wifi.webp b/public/offline/wifi.webp new file mode 100644 index 0000000..ddb6826 Binary files /dev/null and b/public/offline/wifi.webp differ diff --git a/public/order/delivery.gif b/public/order/delivery.gif new file mode 100644 index 0000000..5af23af Binary files /dev/null and b/public/order/delivery.gif differ diff --git a/public/order/delivery.webp b/public/order/delivery.webp new file mode 100644 index 0000000..c0825d9 Binary files /dev/null and b/public/order/delivery.webp differ diff --git a/public/order/shipped.gif b/public/order/shipped.gif new file mode 100644 index 0000000..33f37b4 Binary files /dev/null and b/public/order/shipped.gif differ diff --git a/public/order/shipped.webp b/public/order/shipped.webp new file mode 100644 index 0000000..5f0eb93 Binary files /dev/null and b/public/order/shipped.webp differ diff --git a/public/payment/card.gif b/public/payment/card.gif new file mode 100644 index 0000000..a3990a9 Binary files /dev/null and b/public/payment/card.gif differ diff --git a/public/payment/card.webp b/public/payment/card.webp new file mode 100644 index 0000000..1586886 Binary files /dev/null and b/public/payment/card.webp differ diff --git a/public/payment/coins.gif b/public/payment/coins.gif new file mode 100644 index 0000000..1958b63 Binary files /dev/null and b/public/payment/coins.gif differ diff --git a/public/payment/coins.webp b/public/payment/coins.webp new file mode 100644 index 0000000..2dc55c8 Binary files /dev/null and b/public/payment/coins.webp differ diff --git a/public/payment/tap.gif b/public/payment/tap.gif new file mode 100644 index 0000000..e5ae021 Binary files /dev/null and b/public/payment/tap.gif differ diff --git a/public/payment/tap.webp b/public/payment/tap.webp new file mode 100644 index 0000000..bf04b3e Binary files /dev/null and b/public/payment/tap.webp differ diff --git a/public/phone/waiting.gif b/public/phone/waiting.gif new file mode 100644 index 0000000..c744603 Binary files /dev/null and b/public/phone/waiting.gif differ diff --git a/public/phone/waiting.webp b/public/phone/waiting.webp new file mode 100644 index 0000000..b29647e Binary files /dev/null and b/public/phone/waiting.webp differ diff --git a/public/plate/empty.gif b/public/plate/empty.gif new file mode 100644 index 0000000..295f94a Binary files /dev/null and b/public/plate/empty.gif differ diff --git a/public/plate/empty.webp b/public/plate/empty.webp new file mode 100644 index 0000000..e134af8 Binary files /dev/null and b/public/plate/empty.webp differ diff --git a/public/refresh/pull.gif b/public/refresh/pull.gif new file mode 100644 index 0000000..f6e8573 Binary files /dev/null and b/public/refresh/pull.gif differ diff --git a/public/refresh/pull.webp b/public/refresh/pull.webp new file mode 100644 index 0000000..3b1b778 Binary files /dev/null and b/public/refresh/pull.webp differ diff --git a/public/saved/floppy.gif b/public/saved/floppy.gif new file mode 100644 index 0000000..c7c95f0 Binary files /dev/null and b/public/saved/floppy.gif differ diff --git a/public/saved/floppy.webp b/public/saved/floppy.webp new file mode 100644 index 0000000..e4d3ea0 Binary files /dev/null and b/public/saved/floppy.webp differ diff --git a/public/saved/hug.gif b/public/saved/hug.gif new file mode 100644 index 0000000..b027d01 Binary files /dev/null and b/public/saved/hug.gif differ diff --git a/public/saved/hug.webp b/public/saved/hug.webp new file mode 100644 index 0000000..29e15a5 Binary files /dev/null and b/public/saved/hug.webp differ diff --git a/public/search/magnifier.gif b/public/search/magnifier.gif new file mode 100644 index 0000000..d4f1b66 Binary files /dev/null and b/public/search/magnifier.gif differ diff --git a/public/search/magnifier.webp b/public/search/magnifier.webp new file mode 100644 index 0000000..d9531df Binary files /dev/null and b/public/search/magnifier.webp differ diff --git a/public/search/none.gif b/public/search/none.gif new file mode 100644 index 0000000..ba1a016 Binary files /dev/null and b/public/search/none.gif differ diff --git a/public/search/none.webp b/public/search/none.webp new file mode 100644 index 0000000..63a563d Binary files /dev/null and b/public/search/none.webp differ diff --git a/public/search/sad.gif b/public/search/sad.gif new file mode 100644 index 0000000..3aa66c3 Binary files /dev/null and b/public/search/sad.gif differ diff --git a/public/search/sad.webp b/public/search/sad.webp new file mode 100644 index 0000000..6419242 Binary files /dev/null and b/public/search/sad.webp differ diff --git a/public/sent/envelope.gif b/public/sent/envelope.gif new file mode 100644 index 0000000..6ea2420 Binary files /dev/null and b/public/sent/envelope.gif differ diff --git a/public/sent/envelope.webp b/public/sent/envelope.webp new file mode 100644 index 0000000..3a1b056 Binary files /dev/null and b/public/sent/envelope.webp differ diff --git a/public/sent/plane.gif b/public/sent/plane.gif new file mode 100644 index 0000000..548ef4a Binary files /dev/null and b/public/sent/plane.gif differ diff --git a/public/sent/plane.webp b/public/sent/plane.webp new file mode 100644 index 0000000..c12f5c7 Binary files /dev/null and b/public/sent/plane.webp differ diff --git a/public/sent/wave.gif b/public/sent/wave.gif new file mode 100644 index 0000000..4c7a1cd Binary files /dev/null and b/public/sent/wave.gif differ diff --git a/public/sent/wave.webp b/public/sent/wave.webp new file mode 100644 index 0000000..aaf9420 Binary files /dev/null and b/public/sent/wave.webp differ diff --git a/public/signal/none.gif b/public/signal/none.gif new file mode 100644 index 0000000..d59dcd6 Binary files /dev/null and b/public/signal/none.gif differ diff --git a/public/signal/none.webp b/public/signal/none.webp new file mode 100644 index 0000000..6c985bc Binary files /dev/null and b/public/signal/none.webp differ diff --git a/public/success/balloons.gif b/public/success/balloons.gif new file mode 100644 index 0000000..964911a Binary files /dev/null and b/public/success/balloons.gif differ diff --git a/public/success/balloons.webp b/public/success/balloons.webp new file mode 100644 index 0000000..2b04ea5 Binary files /dev/null and b/public/success/balloons.webp differ diff --git a/public/success/check.gif b/public/success/check.gif new file mode 100644 index 0000000..6b4c841 Binary files /dev/null and b/public/success/check.gif differ diff --git a/public/success/check.webp b/public/success/check.webp new file mode 100644 index 0000000..762f11b Binary files /dev/null and b/public/success/check.webp differ diff --git a/public/success/confetti.gif b/public/success/confetti.gif new file mode 100644 index 0000000..de01582 Binary files /dev/null and b/public/success/confetti.gif differ diff --git a/public/success/confetti.webp b/public/success/confetti.webp new file mode 100644 index 0000000..f0e3b04 Binary files /dev/null and b/public/success/confetti.webp differ diff --git a/public/success/jump.gif b/public/success/jump.gif new file mode 100644 index 0000000..fc4e356 Binary files /dev/null and b/public/success/jump.gif differ diff --git a/public/success/jump.webp b/public/success/jump.webp new file mode 100644 index 0000000..1ba8dd7 Binary files /dev/null and b/public/success/jump.webp differ diff --git a/public/success/medal.gif b/public/success/medal.gif new file mode 100644 index 0000000..ef32d6c Binary files /dev/null and b/public/success/medal.gif differ diff --git a/public/success/medal.webp b/public/success/medal.webp new file mode 100644 index 0000000..b84637e Binary files /dev/null and b/public/success/medal.webp differ diff --git a/public/success/stamp.gif b/public/success/stamp.gif new file mode 100644 index 0000000..148a77d Binary files /dev/null and b/public/success/stamp.gif differ diff --git a/public/success/stamp.webp b/public/success/stamp.webp new file mode 100644 index 0000000..fe81fd7 Binary files /dev/null and b/public/success/stamp.webp differ diff --git a/public/success/thumbs.gif b/public/success/thumbs.gif new file mode 100644 index 0000000..e67f4bf Binary files /dev/null and b/public/success/thumbs.gif differ diff --git a/public/success/thumbs.webp b/public/success/thumbs.webp new file mode 100644 index 0000000..a6ab894 Binary files /dev/null and b/public/success/thumbs.webp differ diff --git a/public/success/victory.gif b/public/success/victory.gif new file mode 100644 index 0000000..0630c89 Binary files /dev/null and b/public/success/victory.gif differ diff --git a/public/success/victory.webp b/public/success/victory.webp new file mode 100644 index 0000000..ea96534 Binary files /dev/null and b/public/success/victory.webp differ diff --git a/public/sync/arrows.gif b/public/sync/arrows.gif new file mode 100644 index 0000000..9ae7cce Binary files /dev/null and b/public/sync/arrows.gif differ diff --git a/public/sync/arrows.webp b/public/sync/arrows.webp new file mode 100644 index 0000000..e89f28a Binary files /dev/null and b/public/sync/arrows.webp differ diff --git a/public/sync/juggle.gif b/public/sync/juggle.gif new file mode 100644 index 0000000..72b6664 Binary files /dev/null and b/public/sync/juggle.gif differ diff --git a/public/sync/juggle.webp b/public/sync/juggle.webp new file mode 100644 index 0000000..16182e9 Binary files /dev/null and b/public/sync/juggle.webp differ diff --git a/public/sync/phones.gif b/public/sync/phones.gif new file mode 100644 index 0000000..30f1185 Binary files /dev/null and b/public/sync/phones.gif differ diff --git a/public/sync/phones.webp b/public/sync/phones.webp new file mode 100644 index 0000000..8ab67ce Binary files /dev/null and b/public/sync/phones.webp differ diff --git a/public/thanks/card.gif b/public/thanks/card.gif new file mode 100644 index 0000000..bc73781 Binary files /dev/null and b/public/thanks/card.gif differ diff --git a/public/thanks/card.webp b/public/thanks/card.webp new file mode 100644 index 0000000..864fc6d Binary files /dev/null and b/public/thanks/card.webp differ diff --git a/public/thanks/heart.gif b/public/thanks/heart.gif new file mode 100644 index 0000000..0464c48 Binary files /dev/null and b/public/thanks/heart.gif differ diff --git a/public/thanks/heart.webp b/public/thanks/heart.webp new file mode 100644 index 0000000..0565a1f Binary files /dev/null and b/public/thanks/heart.webp differ diff --git a/public/timeout/asleep.gif b/public/timeout/asleep.gif new file mode 100644 index 0000000..bb40377 Binary files /dev/null and b/public/timeout/asleep.gif differ diff --git a/public/timeout/asleep.webp b/public/timeout/asleep.webp new file mode 100644 index 0000000..3ad59bb Binary files /dev/null and b/public/timeout/asleep.webp differ diff --git a/public/timeout/stopwatch.gif b/public/timeout/stopwatch.gif new file mode 100644 index 0000000..7938ada Binary files /dev/null and b/public/timeout/stopwatch.gif differ diff --git a/public/timeout/stopwatch.webp b/public/timeout/stopwatch.webp new file mode 100644 index 0000000..2e90ac9 Binary files /dev/null and b/public/timeout/stopwatch.webp differ diff --git a/public/trash/empty.gif b/public/trash/empty.gif new file mode 100644 index 0000000..0eb881c Binary files /dev/null and b/public/trash/empty.gif differ diff --git a/public/trash/empty.webp b/public/trash/empty.webp new file mode 100644 index 0000000..26a36e1 Binary files /dev/null and b/public/trash/empty.webp differ diff --git a/public/typing/bubble.gif b/public/typing/bubble.gif new file mode 100644 index 0000000..bfd329e Binary files /dev/null and b/public/typing/bubble.gif differ diff --git a/public/typing/bubble.webp b/public/typing/bubble.webp new file mode 100644 index 0000000..ef3e9dd Binary files /dev/null and b/public/typing/bubble.webp differ diff --git a/public/typing/chat.gif b/public/typing/chat.gif new file mode 100644 index 0000000..4d13ab3 Binary files /dev/null and b/public/typing/chat.gif differ diff --git a/public/typing/chat.webp b/public/typing/chat.webp new file mode 100644 index 0000000..e2f2080 Binary files /dev/null and b/public/typing/chat.webp differ diff --git a/public/upload/cloud.gif b/public/upload/cloud.gif new file mode 100644 index 0000000..f8e648d Binary files /dev/null and b/public/upload/cloud.gif differ diff --git a/public/upload/cloud.webp b/public/upload/cloud.webp new file mode 100644 index 0000000..8c431d2 Binary files /dev/null and b/public/upload/cloud.webp differ diff --git a/public/upload/rocket.gif b/public/upload/rocket.gif new file mode 100644 index 0000000..73fd527 Binary files /dev/null and b/public/upload/rocket.gif differ diff --git a/public/upload/rocket.webp b/public/upload/rocket.webp new file mode 100644 index 0000000..27f3d37 Binary files /dev/null and b/public/upload/rocket.webp differ diff --git a/public/upload/toss.gif b/public/upload/toss.gif new file mode 100644 index 0000000..ec9c861 Binary files /dev/null and b/public/upload/toss.gif differ diff --git a/public/upload/toss.webp b/public/upload/toss.webp new file mode 100644 index 0000000..baa5856 Binary files /dev/null and b/public/upload/toss.webp differ diff --git a/public/verified/badge.gif b/public/verified/badge.gif new file mode 100644 index 0000000..a8ba6b8 Binary files /dev/null and b/public/verified/badge.gif differ diff --git a/public/verified/badge.webp b/public/verified/badge.webp new file mode 100644 index 0000000..43d8f13 Binary files /dev/null and b/public/verified/badge.webp differ diff --git a/public/wallet/moth.gif b/public/wallet/moth.gif new file mode 100644 index 0000000..b68a82d Binary files /dev/null and b/public/wallet/moth.gif differ diff --git a/public/wallet/moth.webp b/public/wallet/moth.webp new file mode 100644 index 0000000..5e75b95 Binary files /dev/null and b/public/wallet/moth.webp differ diff --git a/public/wallet/shake.gif b/public/wallet/shake.gif new file mode 100644 index 0000000..15216b9 Binary files /dev/null and b/public/wallet/shake.gif differ diff --git a/public/wallet/shake.webp b/public/wallet/shake.webp new file mode 100644 index 0000000..572a182 Binary files /dev/null and b/public/wallet/shake.webp differ diff --git a/public/warning/sign.gif b/public/warning/sign.gif new file mode 100644 index 0000000..a16875d Binary files /dev/null and b/public/warning/sign.gif differ diff --git a/public/warning/sign.webp b/public/warning/sign.webp new file mode 100644 index 0000000..f33898e Binary files /dev/null and b/public/warning/sign.webp differ diff --git a/public/warning/siren.gif b/public/warning/siren.gif new file mode 100644 index 0000000..5d70ec9 Binary files /dev/null and b/public/warning/siren.gif differ diff --git a/public/warning/siren.webp b/public/warning/siren.webp new file mode 100644 index 0000000..0c0904b Binary files /dev/null and b/public/warning/siren.webp differ diff --git a/public/warning/whistle.gif b/public/warning/whistle.gif new file mode 100644 index 0000000..21bb5cd Binary files /dev/null and b/public/warning/whistle.gif differ diff --git a/public/warning/whistle.webp b/public/warning/whistle.webp new file mode 100644 index 0000000..1a44239 Binary files /dev/null and b/public/warning/whistle.webp differ diff --git a/public/welcome/bow.gif b/public/welcome/bow.gif new file mode 100644 index 0000000..3837ef0 Binary files /dev/null and b/public/welcome/bow.gif differ diff --git a/public/welcome/bow.webp b/public/welcome/bow.webp new file mode 100644 index 0000000..f271b7a Binary files /dev/null and b/public/welcome/bow.webp differ diff --git a/public/welcome/door.gif b/public/welcome/door.gif new file mode 100644 index 0000000..a3b3ffc Binary files /dev/null and b/public/welcome/door.gif differ diff --git a/public/welcome/door.webp b/public/welcome/door.webp new file mode 100644 index 0000000..f7c623d Binary files /dev/null and b/public/welcome/door.webp differ diff --git a/public/wishlist/empty.gif b/public/wishlist/empty.gif new file mode 100644 index 0000000..84115fd Binary files /dev/null and b/public/wishlist/empty.gif differ diff --git a/public/wishlist/empty.webp b/public/wishlist/empty.webp new file mode 100644 index 0000000..3fb719d Binary files /dev/null and b/public/wishlist/empty.webp differ