diff --git a/gen/cake/candle.js b/gen/cake/candle.js new file mode 100644 index 0000000..c4e501e --- /dev/null +++ b/gen/cake/candle.js @@ -0,0 +1,21 @@ +// two-tier birthday cake, candle flame flickering, sparkles popping around it +const{sin,cos,PI,max}=Math,T=2*PI +export const frames=20,delay=80 +const star=(c,x,y,r)=>{const k=r*.18;c.beginPath();c.moveTo(x,y-r);for(const[px,py,qx,qy]of[[r,0,k,-k],[0,r,k,k],[-r,0,-k,k],[0,-r,-k,-k]])c.quadraticCurveTo(x+qx,y+qy,x+px,y+py);c.fill();c.stroke()} +const tier=(c,x,y,w,h)=>{ + c.beginPath();c.roundRect(x,y,w,h,10);c.fill();c.stroke() + c.beginPath();c.moveTo(x,y+12);const n=Math.round(w/22);for(let k=0;k{ + c.lineWidth=4;for(const[x,y,o]of[[42,70,0],[214,56,.33],[206,128,.66]]){const r=13*max(0,sin(PI*((t*2+o)%1)));if(r>1.5)star(c,x,y,r)} + c.lineWidth=7 + c.beginPath();c.ellipse(128,230,100,12,0,0,T);c.fill();c.stroke() + tier(c,48,152,160,76);tier(c,74,98,108,58) + c.lineWidth=4;for(const[x,y,a]of[[70,196,.4],[100,212,-.5],[140,200,.8],[176,210,-.2],[188,184,.3],[96,136,-.6],[124,144,.5],[160,132,-.3]])c.beginPath(),c.moveTo(x-cos(a)*5,y-sin(a)*5),c.lineTo(x+cos(a)*5,y+sin(a)*5),c.stroke() + c.lineWidth=7;c.beginPath();c.roundRect(119,50,18,50,4);c.fill();c.stroke() + c.save();c.beginPath();c.rect(119,50,18,50);c.clip();c.lineWidth=4;for(const y of[56,72,88])c.beginPath(),c.moveTo(118,y+8),c.lineTo(138,y),c.stroke();c.restore() + c.beginPath();c.moveTo(128,50);c.lineTo(128,42);c.lineWidth=4;c.stroke() + const h=26+5*sin(2*T*t)+3*sin(5*T*t),b=4*sin(3*T*t) + c.lineWidth=6;c.beginPath();c.moveTo(128+b,40-h);c.quadraticCurveTo(142,32,138,22+0);c.arc(128,24,10,0,PI);c.quadraticCurveTo(114,32,128+b,40-h);c.fill();c.stroke() + c.fillStyle='#111';c.beginPath();c.ellipse(128,28,4,6,0,0,T);c.fill() +} diff --git a/gen/clock/tick.js b/gen/clock/tick.js new file mode 100644 index 0000000..2a58063 --- /dev/null +++ b/gen/clock/tick.js @@ -0,0 +1,19 @@ +// alarm clock rocking tick-tock while the second hand steps once a frame around the dial +const{sin,cos,PI}=Math,T=2*PI +export const frames=12,delay=160 +export default(c,t,i)=>{ + c.translate(128,232);c.rotate(i%2?.045:-.045);c.translate(-128,-232) + for(const d of[-1,1]){ + c.beginPath();c.moveTo(128+d*40,212);c.lineTo(128+d*56,236);c.lineWidth=12;c.stroke();c.lineWidth=7 + c.save();c.translate(128+d*50,66);c.rotate(d*.6);c.beginPath();c.arc(0,0,24,PI,0);c.closePath();c.fill();c.stroke();c.restore() + } + for(const[w,s]of[[14,'#111'],[4,'#fff']])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.arc(128,64,30,PI*1.15,PI*1.85),c.stroke() + c.lineWidth=7;c.strokeStyle='#111' + c.beginPath();c.arc(128,140,82,0,T);c.fill();c.stroke() + c.lineWidth=5;c.beginPath();c.arc(128,140,70,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(128+cos(a)*r,140+sin(a)*r);c.lineTo(128+cos(a)*66,140+sin(a)*66);c.stroke()} + c.lineWidth=8;for(const[a,r]of[[-PI*.83,34],[-PI*.17,48]])c.beginPath(),c.moveTo(128,140),c.lineTo(128+cos(a)*r,140+sin(a)*r),c.stroke() + const s=i/12*T-PI/2 + c.lineWidth=3;c.beginPath();c.moveTo(128-cos(s)*12,140-sin(s)*12);c.lineTo(128+cos(s)*58,140+sin(s)*58);c.stroke() + c.fillStyle='#111';c.beginPath();c.arc(128,140,7,0,T);c.fill() +} diff --git a/gen/gift/open.js b/gen/gift/open.js new file mode 100644 index 0000000..ae216a3 --- /dev/null +++ b/gen/gift/open.js @@ -0,0 +1,23 @@ +// gift box rattles, the lid pops off and confetti bursts out, then the lid drops back on +const{sin,cos,PI,min,max}=Math,T=2*PI +export const frames=24,delay=70 +const C=[[-90,-150,0],[-50,-190,1],[-10,-200,2],[40,-185,0],[85,-140,1],[-120,-90,2],[115,-100,0],[20,-150,1],[-70,-120,1],[60,-210,2]] +export default(c,t)=>{ + const sh=t<.3?.07*sin(t*T*10):0,up=t<.32?0:t<.45?(t-.32)/.13:t<.62?1:t<.78?1-((t-.62)/.16)**2:0,ly=-70*up,lr=-.35*up + const u=(t-.36)/.44 + if(u>0&&u<1)for(const[vx,vy,k]of C){ + const x=128+vx*u,y=120+vy*u+260*u*u + c.save();c.translate(x,y);c.rotate(u*T*(k+1));c.lineWidth=4;c.beginPath() + if(k==0)c.rect(-6,-4,12,8);else if(k==1)c.arc(0,0,6,0,T);else c.moveTo(0,-7),c.lineTo(7,5),c.lineTo(-7,5),c.closePath() + c.restore();c.fill();c.stroke() + } + c.lineWidth=7 + c.translate(128,226);c.rotate(sh);c.translate(-128,-226) + c.beginPath();c.roundRect(64,128,128,96,6);c.fill();c.stroke() + c.beginPath();c.rect(116,128,24,96);c.fill();c.stroke() + c.translate(128,116+ly);c.rotate(lr);c.translate(-128,-116) + for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*20,88,22,13,d*.5,0,T),c.fill(),c.stroke() + c.beginPath();c.roundRect(56,100,144,32,6);c.fill();c.stroke() + c.beginPath();c.rect(116,100,24,32);c.fill();c.stroke() + c.beginPath();c.arc(128,96,9,0,T);c.fill();c.stroke() +} diff --git a/gen/icecream/melt.js b/gen/icecream/melt.js new file mode 100644 index 0000000..737c854 --- /dev/null +++ b/gen/icecream/melt.js @@ -0,0 +1,23 @@ +// ice cream cone melting: drips stretch down the cone and drops fall off, the scoop looks worried +const{sin,cos,PI,min}=Math,T=2*PI +export const frames=24,delay=80 +export default(c,t)=>{ + c.beginPath();c.moveTo(80,146);c.lineTo(176,146);c.lineTo(128,246);c.closePath();c.fill() + c.save();c.clip();c.lineWidth=4;for(let k=-6;k<8;k++)c.beginPath(),c.moveTo(60+k*18,140),c.lineTo(160+k*18,250),c.moveTo(196-k*18,140),c.lineTo(96-k*18,250),c.stroke();c.restore() + c.lineWidth=7;c.beginPath();c.moveTo(80,146);c.lineTo(176,146);c.lineTo(128,246);c.closePath();c.stroke() + for(const[x,o]of[[108,0],[150,.5]]){ + const p=(t+o)%1,L=p<.7?10+40*(p/.7)**1.5:10+40*(1-(p-.7)/.3)**3,dy=p>=.7?150+50+(p-.7)/.3*90:0 + c.beginPath();c.roundRect(x-8,140,16,L+10,[0,0,8,8]);c.fill();c.stroke() + if(dy){c.beginPath();c.arc(x,dy,7,0,T);c.fill();c.stroke()} + } + c.beginPath();c.arc(128,102,56,PI*.92,PI*.08) + for(let k=0;k<=6;k++){const x=184-k*18.7;c.arc(x-9.3,148,9.4,0,PI)} + c.closePath();c.fill();c.stroke() + c.beginPath();c.moveTo(128,46);c.quadraticCurveTo(132,24,148,20);c.lineWidth=5;c.stroke() + c.lineWidth=7;c.beginPath();c.arc(128,48,13,0,T);c.fill();c.stroke() + c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.arc(128+d*18,104,5,0,T),c.fill() + c.lineWidth=4;for(const d of[-1,1])c.beginPath(),c.moveTo(128+d*12,90),c.lineTo(128+d*24,94),c.stroke() + c.beginPath();c.moveTo(118,124);c.quadraticCurveTo(123,118,128,124);c.quadraticCurveTo(133,130,138,124);c.stroke() + const sw=(t*2)%1 + c.save();c.translate(178,72+sw*20);c.fillStyle='#fff';c.beginPath();c.moveTo(0,-9);c.quadraticCurveTo(6,0,0,6);c.quadraticCurveTo(-6,0,0,-9);c.fill();c.lineWidth=4;c.stroke();c.restore() +} diff --git a/gen/lol/bounce.js b/gen/lol/bounce.js new file mode 100644 index 0000000..7f206a7 --- /dev/null +++ b/gen/lol/bounce.js @@ -0,0 +1,12 @@ +// chunky bubble letters "lol" hopping one after another like a wave +const{sin,max}=Math,T=2*Math.PI +export const frames=20,delay=60 +export default(c,t)=>{ + const L=[[x=>{c.moveTo(x,70);c.lineTo(x,180)},48],[x=>{c.moveTo(x+32,148);c.arc(x,148,32,0,T)},128],[x=>{c.moveTo(x,70);c.lineTo(x,180)},208]] + L.forEach(([f,x],k)=>{ + const h=max(0,sin(T*(t-k*.14))),y=-38*h**.8,sq=h<.15?1-(.15-h)*.6:1 + c.save();c.translate(x,212);c.scale(2-sq,sq);c.translate(-x,-212+y/sq) + for(const[w,s]of[[44,'#111'],[28,'#fff']])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),f(x),c.stroke() + c.restore() + }) +} diff --git a/gen/note/bounce.js b/gen/note/bounce.js new file mode 100644 index 0000000..2bfaa4b --- /dev/null +++ b/gen/note/bounce.js @@ -0,0 +1,19 @@ +// pair of music notes bouncing on the beat while little notes float up on either side +const{sin,cos,PI,abs}=Math,T=2*PI +export const frames=20,delay=70 +const D=(c,f,a=18,b=6)=>{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'} +const head=(c,x,y,s=1)=>{c.beginPath();c.ellipse(x,y,22*s,15*s,-.35,0,T);c.fill();c.stroke()} +export default(c,t)=>{ + for(const[x0,o,d]of[[40,0,1],[216,.5,-1]]){ + const p=(t+o)%1,s=.55*sin(PI*p),x=x0+10*sin(p*T),y=230-p*170 + if(s<.08)continue + c.save();c.translate(x,y);c.scale(s,s) + D(c,()=>{c.moveTo(18,-6);c.lineTo(18,-80);c.quadraticCurveTo(26,-56,44,-50)},16,6) + c.lineWidth=7/s;head(c,0,0);c.restore() + } + const b=abs(sin(2*PI*t)),y=-26*b,sq=1+.08*(1-b) + c.translate(128,200);c.scale(sq,2-sq);c.translate(-128,-200+y) + D(c,()=>{c.moveTo(110,176);c.lineTo(110,74);c.moveTo(182,156);c.lineTo(182,54)}) + c.beginPath();c.moveTo(104,64);c.lineTo(188,40);c.lineTo(188,68);c.lineTo(104,92);c.closePath();c.fill();c.stroke() + head(c,90,182);head(c,162,162) +} diff --git a/gen/popcorn/pop.js b/gen/popcorn/pop.js new file mode 100644 index 0000000..86bc682 --- /dev/null +++ b/gen/popcorn/pop.js @@ -0,0 +1,25 @@ +// striped popcorn bucket with kernels popping up out of the pile and dropping back in +const{sin,cos,PI}=Math,T=2*PI +export const frames=20,delay=60 +const kernel=(c,x,y,a,s=1)=>{ + const B=[[0,0,11],[10,-6,9],[-9,-7,9],[2,-14,8]] + c.save();c.translate(x,y);c.rotate(a);c.scale(s,s) + c.lineWidth=12/s;for(const[bx,by,r]of B)c.beginPath(),c.arc(bx,by,r,0,T),c.stroke() + for(const[bx,by,r]of B)c.beginPath(),c.arc(bx,by,r,0,T),c.fill() + c.restore() +} +export default(c,t)=>{ + const pile=[[84,120],[106,108],[130,104],[154,110],[174,122],[96,128],[120,124],[146,126],[164,130]] + for(const[x,y]of pile)kernel(c,x,y,x*.1) + for(const[x0,vx,h,o]of[[100,-50,80,0],[150,46,70,.35],[124,10,88,.7]]){ + const p=(t*1.5+o)%1,x=x0+vx*sin(PI*p),y=112-h*4*p*(1-p) + kernel(c,x,y,p*T*(vx>0?1:-1),1.1) + } + c.lineWidth=7 + const bucket=()=>{c.beginPath();c.moveTo(68,132);c.lineTo(188,132);c.lineTo(172,238);c.lineTo(84,238);c.closePath()} + bucket();c.fill() + c.save();bucket();c.clip();c.fillStyle='#111' + for(const k of[-1,1])c.beginPath(),c.moveTo(128+k*30-10,132),c.lineTo(128+k*30+10,132),c.lineTo(128+k*25+8,238),c.lineTo(128+k*25-8,238),c.fill() + c.restore();bucket();c.stroke() + c.beginPath();c.roundRect(62,126,132,14,5);c.fill();c.stroke() +} diff --git a/gen/rocket/launch.js b/gen/rocket/launch.js new file mode 100644 index 0000000..652d1a4 --- /dev/null +++ b/gen/rocket/launch.js @@ -0,0 +1,21 @@ +// rocket blasting along with its flame flickering, body rattling and speed lines streaking past +const{sin,PI}=Math,T=2*PI +export const frames=16,delay=50 +export default(c,t,i)=>{ + for(const[x,len,o]of[[34,46,0],[66,30,.5],[196,38,.25],[226,52,.75]]){ + const y=((t*2+o)%1)*(256+len*2)-len*2 + for(const[w,s]of[[11,'#111'],[4,'#fff']])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.moveTo(x,y),c.lineTo(x,y+len),c.stroke() + } + c.lineWidth=7;c.strokeStyle='#111' + c.translate(i%2?2:-2,0) + const h=44+10*sin(2*T*t)+6*sin(5*T*t) + c.beginPath();c.moveTo(108,178);c.quadraticCurveTo(110,178+h*.7,128,178+h);c.quadraticCurveTo(146,178+h*.7,148,178);c.closePath();c.fill();c.stroke() + c.fillStyle='#111';c.beginPath();c.moveTo(118,182);c.quadraticCurveTo(120,180+h*.45,128,180+h*.6);c.quadraticCurveTo(136,180+h*.45,138,182);c.closePath();c.fill();c.fillStyle='#fff' + for(const d of[-1,1])c.beginPath(),c.moveTo(128+d*30,128),c.quadraticCurveTo(128+d*56,150,128+d*58,186),c.lineTo(128+d*30,172),c.closePath(),c.fill(),c.stroke() + c.beginPath();c.roundRect(110,166,36,16,4);c.fill();c.stroke() + c.beginPath();c.moveTo(128,28);c.bezierCurveTo(162,52,162,96,160,170);c.lineTo(96,170);c.bezierCurveTo(94,96,94,52,128,28);c.closePath();c.fill();c.stroke() + c.lineWidth=5;c.beginPath();c.moveTo(106,62);c.quadraticCurveTo(128,70,150,62);c.stroke() + c.lineWidth=7;c.beginPath();c.arc(128,106,19,0,T);c.fill();c.stroke() + c.lineWidth=4;c.beginPath();c.arc(128,106,11,PI*1.1,PI*1.6);c.stroke() + c.lineWidth=7;c.beginPath();c.moveTo(128,140);c.lineTo(128,166);c.stroke() +} diff --git a/public/cake/candle.gif b/public/cake/candle.gif new file mode 100644 index 0000000..37796f9 Binary files /dev/null and b/public/cake/candle.gif differ diff --git a/public/cake/candle.webp b/public/cake/candle.webp new file mode 100644 index 0000000..1728299 Binary files /dev/null and b/public/cake/candle.webp differ diff --git a/public/clock/tick.gif b/public/clock/tick.gif new file mode 100644 index 0000000..6f24af5 Binary files /dev/null and b/public/clock/tick.gif differ diff --git a/public/clock/tick.webp b/public/clock/tick.webp new file mode 100644 index 0000000..e2b444d Binary files /dev/null and b/public/clock/tick.webp differ diff --git a/public/gift/open.gif b/public/gift/open.gif new file mode 100644 index 0000000..f9030c1 Binary files /dev/null and b/public/gift/open.gif differ diff --git a/public/gift/open.webp b/public/gift/open.webp new file mode 100644 index 0000000..75840f2 Binary files /dev/null and b/public/gift/open.webp differ diff --git a/public/icecream/melt.gif b/public/icecream/melt.gif new file mode 100644 index 0000000..843dda3 Binary files /dev/null and b/public/icecream/melt.gif differ diff --git a/public/icecream/melt.webp b/public/icecream/melt.webp new file mode 100644 index 0000000..f1bfc0e Binary files /dev/null and b/public/icecream/melt.webp differ diff --git a/public/lol/bounce.gif b/public/lol/bounce.gif new file mode 100644 index 0000000..bd79274 Binary files /dev/null and b/public/lol/bounce.gif differ diff --git a/public/lol/bounce.webp b/public/lol/bounce.webp new file mode 100644 index 0000000..cff4c64 Binary files /dev/null and b/public/lol/bounce.webp differ diff --git a/public/note/bounce.gif b/public/note/bounce.gif new file mode 100644 index 0000000..1707bb6 Binary files /dev/null and b/public/note/bounce.gif differ diff --git a/public/note/bounce.webp b/public/note/bounce.webp new file mode 100644 index 0000000..f35a707 Binary files /dev/null and b/public/note/bounce.webp differ diff --git a/public/popcorn/pop.gif b/public/popcorn/pop.gif new file mode 100644 index 0000000..a905f4a Binary files /dev/null and b/public/popcorn/pop.gif differ diff --git a/public/popcorn/pop.webp b/public/popcorn/pop.webp new file mode 100644 index 0000000..13b28f5 Binary files /dev/null and b/public/popcorn/pop.webp differ diff --git a/public/rocket/launch.gif b/public/rocket/launch.gif new file mode 100644 index 0000000..78d071c Binary files /dev/null and b/public/rocket/launch.gif differ diff --git a/public/rocket/launch.webp b/public/rocket/launch.webp new file mode 100644 index 0000000..3f74f74 Binary files /dev/null and b/public/rocket/launch.webp differ