diff --git a/gen/face/laugh.js b/gen/face/laugh.js new file mode 100644 index 0000000..34a581e --- /dev/null +++ b/gen/face/laugh.js @@ -0,0 +1,18 @@ +// face laughing so hard it shakes, with tears of joy squirting out both sides +const{sin,cos,PI,abs}=Math,T=2*PI +export const frames=18,delay=60 +export default(c,t)=>{ + const r=.1*sin(3*T*t),b=-5*abs(sin(3*PI*t)),m=38+5*sin(6*T*t) + for(const d of[-1,1])for(let k=0;k<3;k++){ + const p=(t*2+k/3)%1,x=128+d*(56+p*58),y=112+b-34*p+70*p*p,s=7*sin(PI*p)+2,vx=d*58,vy=-34+140*p,a=Math.atan2(vy,vx) + c.save();c.translate(x,y);c.rotate(a-PI/2);c.beginPath();c.moveTo(0,-s*1.8);c.quadraticCurveTo(s,-s*.2,s,s*.3);c.arc(0,s*.3,s,0,PI);c.quadraticCurveTo(-s,-s*.2,0,-s*1.8);c.restore();c.lineWidth=4;c.fill();c.stroke() + } + c.lineWidth=7 + c.translate(128,132+b);c.rotate(r);c.translate(-128,-132) + c.beginPath();c.arc(128,132,76,0,T);c.fill();c.stroke() + for(const d of[-1,1])c.beginPath(),c.moveTo(128+d*44,104),c.lineTo(128+d*24,112),c.lineTo(128+d*44,120),c.stroke() + c.save();c.beginPath();c.moveTo(128-m,140);c.arc(128,140,m,0,PI);c.closePath();c.fillStyle='#111';c.fill();c.clip() + c.fillStyle='#fff';c.fillRect(80,136,96,12);c.beginPath();c.ellipse(128,140+m,m*.55,m*.42,0,0,T);c.fill();c.lineWidth=5;c.stroke();c.restore() + c.beginPath();c.moveTo(128-m,140);c.arc(128,140,m,0,PI);c.closePath();c.stroke() + c.lineWidth=3;for(const d of[-1,1])for(const k of[-5,0,5])c.beginPath(),c.moveTo(128+d*58+k-2,140),c.lineTo(128+d*58+k+2,133),c.stroke() +} diff --git a/gen/fire/burn.js b/gen/fire/burn.js new file mode 100644 index 0000000..1936316 --- /dev/null +++ b/gen/fire/burn.js @@ -0,0 +1,28 @@ +// campfire: three flame tongues flickering on two crossed logs, little face in the flame, sparks floating up +// the black flame gets a white rim so it still shows on dark backgrounds +const{sin,PI}=Math,T=2*PI +export const frames=20,delay=70 +const tongue=(c,x,by,h,w,b)=>{ + c.moveTo(x+b,by-h) + c.bezierCurveTo(x+w*.2+b*.5,by-h*.55,x+w,by-h*.5,x+w,by-w) + c.arc(x,by-w,w,0,PI) + c.bezierCurveTo(x-w,by-h*.5,x-w*.2+b*.5,by-h*.55,x+b,by-h) +} +export default(c,t)=>{ + const s=k=>sin(T*t*k) + c.lineWidth=4 + for(const[x0,o]of[[98,0],[152,.4],[126,.75]]){const p=(t+o)%1;c.beginPath();c.arc(x0+10*sin(p*T*2+o*5),120-p*110,4*(1-p)+1.5,0,T);c.fill();c.stroke()} + c.beginPath() + tongue(c,128,214,156+8*s(2),54,14*s(2)) + tongue(c,96,214,100+8*s(3),34,-16+8*s(2)) + tongue(c,160,214,112+8*s(2),36,16-8*s(3)) + c.lineWidth=16;c.strokeStyle='#fff';c.stroke();c.fillStyle='#111';c.fill();c.lineWidth=7;c.strokeStyle='#111';c.stroke() + c.beginPath();tongue(c,128,212,92+6*s(3),30,8*s(2));c.fillStyle='#fff';c.fill() + c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.arc(128+d*10,180,4,0,T),c.fill() + c.lineWidth=4;c.beginPath();c.arc(128,187,6,.15*PI,.85*PI);c.stroke() + c.fillStyle='#fff';c.lineWidth=7 + for(const d of[-1,1]){ + c.save();c.translate(128,222);c.rotate(d*.22);c.beginPath();c.roundRect(-78,-13,156,26,13);c.fill();c.stroke() + c.lineWidth=4;c.beginPath();c.ellipse(d*68,0,6,9,0,0,T);c.stroke();c.lineWidth=7;c.restore() + } +} diff --git a/gen/hands/clap.js b/gen/hands/clap.js new file mode 100644 index 0000000..d446e67 --- /dev/null +++ b/gen/hands/clap.js @@ -0,0 +1,19 @@ +// two mitten hands clapping twice per loop with a burst of lines each time they meet +const{sin,cos,PI}=Math,T=2*PI +export const delay=60 +export default(c,t)=>{ + const k=(1+cos(2*T*t))/2,g=8+44*k + if(k<.12)for(const d of[-1,1])for(const a of[-.5,0,.5]){ + const ang=-PI/2+d*(.55+a*.5) + for(const[w,s]of[[11,'#111'],[4,'#fff']])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.moveTo(128+cos(ang)*58,104+sin(ang)*58),c.lineTo(128+cos(ang)*84,104+sin(ang)*84),c.stroke() + } + c.lineWidth=7;c.strokeStyle='#111' + for(const d of[-1,1]){ + c.save();c.translate(128+d*g,212);c.scale(d,1);c.rotate(-.22-.12*k) + c.beginPath();c.ellipse(-2,-74,12,24,-.5,0,T);c.fill();c.stroke() + c.beginPath();c.roundRect(0,-150,46,118,23);c.fill();c.stroke() + c.lineWidth=4;c.beginPath();for(const x of[12,23,34])c.moveTo(x,-150+8),c.lineTo(x,-126);c.stroke();c.lineWidth=7 + c.beginPath();c.roundRect(-3,-40,52,22,5);c.fill();c.stroke() + c.restore() + } +} diff --git a/gen/leaf/fall.js b/gen/leaf/fall.js new file mode 100644 index 0000000..3a513f2 --- /dev/null +++ b/gen/leaf/fall.js @@ -0,0 +1,14 @@ +// leaf rocking down through the air like a pendulum while two small leaves tumble past behind it +const{sin,cos,PI}=Math,T=2*PI +export const frames=24,delay=70 +const leaf=(c,x,y,r,s)=>{ + c.save();c.translate(x,y);c.rotate(r);c.scale(s,s);c.lineWidth=7/s + for(const[l,st]of[[10,'#111'],[4,'#fff']])c.lineWidth=l/s,c.strokeStyle=st,c.beginPath(),c.moveTo(-44,0),c.lineTo(-62,6),c.stroke() + c.lineWidth=7/s;c.strokeStyle='#111';c.beginPath();c.moveTo(-46,0);c.quadraticCurveTo(0,-36,46,0);c.quadraticCurveTo(0,36,-46,0);c.fill();c.stroke() + c.lineWidth=4/s;c.beginPath();c.moveTo(-44,0);c.lineTo(38,0);for(const v of[-22,-2,18])c.moveTo(v,0),c.lineTo(v+12,-13),c.moveTo(v,0),c.lineTo(v+12,13);c.stroke() + c.restore() +} +export default(c,t)=>{ + for(const[x0,o,s]of[[56,0,.68],[200,.5,.58]]){const p=(t+o)%1;leaf(c,x0+24*sin(p*T*2),-40+p*336,p*T*2,s)} + leaf(c,128+46*sin(t*T),122+22*cos(2*t*T),.5*sin(t*T)+.15,1.45) +} diff --git a/gen/lightning/flash.js b/gen/lightning/flash.js new file mode 100644 index 0000000..ee9c92b --- /dev/null +++ b/gen/lightning/flash.js @@ -0,0 +1,21 @@ +// grumpy storm cloud that zaps a lightning bolt twice and shakes when it does +const{sin,cos,PI}=Math,T=2*PI +export const frames=20,delay=80 +export default(c,t,i)=>{ + const z=i==2||i==3||i==6,sx=z?(i%2?3:-3):0 + if(z){ + c.beginPath();for(const[x,y]of[[146,136],[100,192],[132,192],[96,242],[172,170],[140,170],[168,136]])c.lineTo(x+sx,y);c.closePath();c.fill();c.stroke() + for(const[a,l]of[[-2.7,18],[-2.1,22],[-.4,18],[-1,22]]) + for(const[w,s]of[[11,'#111'],[4,'#fff']])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.moveTo(96+sx+cos(a)*16,240+sin(a)*16),c.lineTo(96+sx+cos(a)*(16+l),240+sin(a)*(16+l)),c.stroke() + c.lineWidth=7;c.strokeStyle='#111' + } + const P=[[76,112,34],[122,84,46],[176,104,38]],base=()=>c.roundRect(40+sx,104,176,50,25) + c.lineWidth=14;for(const[x,y,r]of P)c.beginPath(),c.arc(x+sx,y,r,0,T),c.stroke() + c.beginPath();base();c.stroke() + for(const[x,y,r]of P)c.beginPath(),c.arc(x+sx,y,r,0,T),c.fill() + c.beginPath();base();c.fill() + c.lineWidth=6;for(const d of[-1,1])c.beginPath(),c.moveTo(128+sx+d*36,110+(z?-2:0)),c.lineTo(128+sx+d*14,118),c.stroke() + c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.arc(128+sx+d*24,126,5,0,T),c.fill() + c.beginPath();if(z)c.ellipse(128+sx,144,8,6,0,0,T),c.fill();else c.arc(128+sx,148,9,PI*1.2,PI*1.8),c.stroke() + c.fillStyle='#fff' +} diff --git a/gen/snow/fall.js b/gen/snow/fall.js new file mode 100644 index 0000000..774ddc8 --- /dev/null +++ b/gen/snow/fall.js @@ -0,0 +1,18 @@ +// snowflakes of different sizes drifting down and slowly spinning +const{sin,cos,PI}=Math,T=2*PI +export const frames=20,delay=90 +const F=[[46,0,20,1],[112,.3,30,1],[186,.62,24,1],[228,.15,16,1],[150,.82,38,1],[70,.55,26,1],[206,.42,32,1]] +export default(c,t)=>{ + for(const[x0,o,r,n]of F){ + const p=(t*n+o)%1,x=x0+12*sin(p*T+o*7),y=-r-6+p*(256+2*r+12),a=t*T/6*(n%2?1:-1) + for(const[l,s]of[[10,'#111'],[4,'#fff']]){ + c.lineWidth=l;c.strokeStyle=s;c.beginPath() + for(let k=0;k<6;k++){ + const b=a+k*PI/3,ux=cos(b),uy=sin(b),m=r*.55,q=r*.28 + c.moveTo(x,y);c.lineTo(x+ux*r,y+uy*r) + for(const d of[-1,1])c.moveTo(x+ux*m,y+uy*m),c.lineTo(x+ux*m+cos(b+d*.9)*q,y+uy*m+sin(b+d*.9)*q) + } + c.stroke() + } + } +} diff --git a/gen/sprout/grow.js b/gen/sprout/grow.js new file mode 100644 index 0000000..5c911c9 --- /dev/null +++ b/gen/sprout/grow.js @@ -0,0 +1,20 @@ +// sprout boings up out of the dirt, opens its leaves, wiggles happily, then ducks back down +const{sin,cos,PI,min,max}=Math,T=2*PI +export const frames=24,delay=70 +const back=u=>{const s=1.9;return 1+(s+1)*(u-1)**3+s*(u-1)**2} +export default(c,t)=>{ + const g=t<.3?back(t/.3):t<.8?1:1-((t-.8)/.2)**2,H=112*g + const o=min(1,max(0,(t-.18)/.22))*(t>.8?1-(t-.8)/.2:1),sw=t>.3&&t<.8?.22*sin((t-.3)/.5*2*T*2):0 + const tx=128+sw*H*.5,ty=214-H + if(H>2){ + for(const[l,s]of[[16,'#111'],[4,'#fff']])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),c.moveTo(128,226),c.quadraticCurveTo(128,214-H*.5,tx,ty),c.stroke() + c.lineWidth=7;c.strokeStyle='#111' + for(const d of[-1,1]){ + c.save();c.translate(tx,ty);c.rotate(d*(.15+1.05*o)+sw);c.scale(.5+.8*g,.5+.8*g) + c.beginPath();c.moveTo(0,0);c.bezierCurveTo(d*10,-30,d*44,-40,d*40,-16);c.bezierCurveTo(d*38,-4,d*16,4,0,0);c.restore();c.fill();c.stroke() + c.lineWidth=4;c.save();c.translate(tx,ty);c.rotate(d*(.15+1.05*o)+sw);c.scale(.5+.8*g,.5+.8*g);c.beginPath();c.moveTo(d*4,-4);c.quadraticCurveTo(d*20,-20,d*32,-18);c.restore();c.stroke();c.lineWidth=7 + } + } + c.lineWidth=7;c.beginPath();c.ellipse(128,232,76,26,0,PI,T);c.closePath();c.fill();c.stroke() + c.fillStyle='#111';for(const[x,y]of[[96,224],[112,216],[150,220],[166,226],[132,224]])c.beginPath(),c.arc(x,y,3,0,T),c.fill() +} diff --git a/gen/thumbs/up.js b/gen/thumbs/up.js new file mode 100644 index 0000000..68d5c03 --- /dev/null +++ b/gen/thumbs/up.js @@ -0,0 +1,16 @@ +// thumbs up bouncing on the beat while little sparkles pop around it +const{sin,cos,PI,max}=Math,T=2*PI +export const delay=70 +const star=(c,x,y,s)=>{c.beginPath();for(let k=0;k<8;k++){const r=k%2?s*.32:s,a=k*PI/4;c.lineTo(x+r*cos(a),y+r*sin(a))}c.closePath();c.fill();c.stroke()} +export default(c,t)=>{ + const b=max(0,sin(2*T*t)),y=-14*b,r=-.06+.1*sin(2*T*t-.6) + c.lineWidth=5;for(const[x,yy,p]of[[48,70,0],[208,92,.33],[196,30,.66]]){const s=16*max(0,sin(((t+p)%1)*T*2));if(s>1)star(c,x,yy,s)} + c.lineWidth=7 + c.translate(128,226+y);c.rotate(r);c.translate(-128,-226) + c.save();c.translate(104,128);c.rotate(-.12);c.beginPath();c.roundRect(-17,-82,34,96,17);c.restore();c.fill();c.stroke() + c.lineWidth=4;c.save();c.translate(104,128);c.rotate(-.12);c.beginPath();c.arc(0,-62,10,PI*1.1,PI*1.9);c.stroke();c.restore();c.lineWidth=7 + c.beginPath();c.roundRect(74,112,56,100,20);c.fill();c.stroke() + for(let k=0;k<4;k++)c.beginPath(),c.roundRect(100,114+k*24,74,26,13),c.fill(),c.stroke() + c.beginPath();c.roundRect(76,204,82,26,6);c.fill();c.stroke() + c.lineWidth=4;c.beginPath();c.moveTo(86,212);c.lineTo(148,212);c.moveTo(86,222);c.lineTo(148,222);c.stroke() +} diff --git a/public/face/laugh.gif b/public/face/laugh.gif new file mode 100644 index 0000000..3ecc241 Binary files /dev/null and b/public/face/laugh.gif differ diff --git a/public/face/laugh.webp b/public/face/laugh.webp new file mode 100644 index 0000000..71ef0ca Binary files /dev/null and b/public/face/laugh.webp differ diff --git a/public/fire/burn.gif b/public/fire/burn.gif new file mode 100644 index 0000000..c48e3ba Binary files /dev/null and b/public/fire/burn.gif differ diff --git a/public/fire/burn.webp b/public/fire/burn.webp new file mode 100644 index 0000000..f36ebed Binary files /dev/null and b/public/fire/burn.webp differ diff --git a/public/hands/clap.gif b/public/hands/clap.gif new file mode 100644 index 0000000..66dbcad Binary files /dev/null and b/public/hands/clap.gif differ diff --git a/public/hands/clap.webp b/public/hands/clap.webp new file mode 100644 index 0000000..2306e13 Binary files /dev/null and b/public/hands/clap.webp differ diff --git a/public/leaf/fall.gif b/public/leaf/fall.gif new file mode 100644 index 0000000..07b1618 Binary files /dev/null and b/public/leaf/fall.gif differ diff --git a/public/leaf/fall.webp b/public/leaf/fall.webp new file mode 100644 index 0000000..f486cda Binary files /dev/null and b/public/leaf/fall.webp differ diff --git a/public/lightning/flash.gif b/public/lightning/flash.gif new file mode 100644 index 0000000..9fb1049 Binary files /dev/null and b/public/lightning/flash.gif differ diff --git a/public/lightning/flash.webp b/public/lightning/flash.webp new file mode 100644 index 0000000..db1b781 Binary files /dev/null and b/public/lightning/flash.webp differ diff --git a/public/snow/fall.gif b/public/snow/fall.gif new file mode 100644 index 0000000..92f2ebc Binary files /dev/null and b/public/snow/fall.gif differ diff --git a/public/snow/fall.webp b/public/snow/fall.webp new file mode 100644 index 0000000..2914846 Binary files /dev/null and b/public/snow/fall.webp differ diff --git a/public/sprout/grow.gif b/public/sprout/grow.gif new file mode 100644 index 0000000..ab94410 Binary files /dev/null and b/public/sprout/grow.gif differ diff --git a/public/sprout/grow.webp b/public/sprout/grow.webp new file mode 100644 index 0000000..7f72719 Binary files /dev/null and b/public/sprout/grow.webp differ diff --git a/public/thumbs/up.gif b/public/thumbs/up.gif new file mode 100644 index 0000000..01378ac Binary files /dev/null and b/public/thumbs/up.gif differ diff --git a/public/thumbs/up.webp b/public/thumbs/up.webp new file mode 100644 index 0000000..fc1fb04 Binary files /dev/null and b/public/thumbs/up.webp differ