mirror of
https://github.com/direct-img/vibegif.direct-img.link.git
synced 2026-10-29 03:34:51 +00:00
Add minimalist creature sections, 50 black-and-white and 50 colored
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
// baku asleep: slow breaths, a dream bubble above it with a star slowly turning and twinkling inside
|
||||
const{sin,cos,PI}=Math,T=2*PI
|
||||
export const frames=24,delay=90
|
||||
const B='#b48cff',L='#dac6ff',S='#4ea8de',Y='#f4c03e',D='#2b2633'
|
||||
export default(c,t)=>{
|
||||
const br=sin(T*t),ry=38*(1+.04*br)
|
||||
const fill=(col,g)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();g();c.fill();c.stroke()}
|
||||
for(const[x,y,r]of[[100,104,5],[114,84,8]])fill(S,()=>c.arc(x,y,r*(1+.08*br),0,T))
|
||||
const R=32*(1+.05*br)
|
||||
fill(S,()=>c.arc(150,56,R,0,T))
|
||||
c.save();c.translate(150,56);c.rotate(T*t/5);const k=.85+.15*sin(2*T*t)
|
||||
fill(Y,()=>{for(let i=0;i<10;i++){const a=i*PI/5-PI/2,r=(i%2?7:16)*k;c.lineTo(r*cos(a),r*sin(a))}c.closePath()});c.restore()
|
||||
for(const x of[96,176])fill(B,()=>c.ellipse(x,194,12,7,0,0,T))
|
||||
fill(B,()=>c.ellipse(142,162,66,ry,0,0,T))
|
||||
c.save();c.beginPath();c.ellipse(142,162,66,ry,0,0,T);c.clip()
|
||||
fill(L,()=>c.ellipse(186,154,44,60,0,0,T));c.restore()
|
||||
c.strokeStyle=B;c.lineWidth=18;c.beginPath();c.moveTo(60,152+2*br);c.quadraticCurveTo(38,154+2*br,38,176+3*br);c.stroke()
|
||||
fill(B,()=>c.arc(76,156+2*br,30,0,T))
|
||||
fill(B,()=>c.ellipse(88,128+2*br,9,12,.4,0,T))
|
||||
c.strokeStyle=D;c.lineWidth=3.5;c.beginPath();c.arc(78,150+2*br,6,.15*PI,.85*PI);c.stroke()
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// bee-cat hovering: a striped cat body with buzzing wings, its tail curling and swaying, blinking
|
||||
const{sin,cos,PI}=Math,T=2*PI
|
||||
export const frames=24,delay=70
|
||||
const B='#f4c03e',L='#f9e09e',A='#5b4a3f',W='#a7d4ef',D='#2b2633'
|
||||
export default(c,t)=>{
|
||||
const fill=(col,f)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();f();c.fill();c.stroke()}
|
||||
const wing=(r,s)=>{c.save();c.translate(118,104);c.rotate(r);fill(W,()=>c.ellipse(-4,-30,15*s,30,0,0,T));c.restore()}
|
||||
const bl=t>.5&&t<.56,bz=sin(T*t*6)
|
||||
c.translate(128,134+7*sin(T*t));c.rotate(.04*sin(T*t+1));c.translate(-128,-128)
|
||||
c.lineCap='round';c.strokeStyle=B;c.lineWidth=13;c.beginPath();c.moveTo(70,150)
|
||||
c.bezierCurveTo(38,160,26,128,40+5*sin(T*t-1),104+4*cos(T*t-1));c.stroke()
|
||||
wing(-.75+.35*bz,.9)
|
||||
fill(B,()=>c.ellipse(104,142,56,42,-.1,0,T))
|
||||
c.save();c.beginPath();c.ellipse(104,142,50,36,-.1,0,T);c.clip();c.translate(104,142);c.rotate(-.1)
|
||||
c.fillStyle=A;c.fillRect(-26,-50,14,100);c.fillRect(4,-50,14,100);c.restore()
|
||||
for(const[x,r]of[[150,-.35],[190,.35]]){
|
||||
c.save();c.translate(x,88);c.rotate(r);fill(B,()=>{c.moveTo(-14,8);c.lineTo(0,-22);c.lineTo(14,8)})
|
||||
fill(L,()=>{c.moveTo(-5,5);c.lineTo(0,-8);c.lineTo(5,5)});c.restore()
|
||||
}
|
||||
fill(B,()=>c.arc(170,120,38,0,T))
|
||||
wing(-.35+.35*bz,1)
|
||||
c.fillStyle=c.strokeStyle=D
|
||||
for(const x of[157,183])if(bl)c.lineWidth=4,c.beginPath(),c.arc(x,114,6,.15*PI,.85*PI),c.stroke()
|
||||
else c.beginPath(),c.arc(x,116,5.5,0,T),c.fill()
|
||||
c.lineWidth=3.5;for(const d of[-1,1])c.beginPath(),c.arc(170+d*4.5,126,4.5,.1*PI,.9*PI),c.stroke()
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// beluga bobbing: pale grey-blue whale with a bulging melon head that squishes, smiling, tail and flipper paddling
|
||||
const{sin,cos,PI}=Math,T=2*PI
|
||||
export const frames=24,delay=85
|
||||
const B='#9fb8d6',L='#d3dfed',D='#2b2633'
|
||||
export default(c,t)=>{
|
||||
const s=sin(T*t),m=4*sin(T*t*2),bl=t>.8&&t<.87,fill=(col,f)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();f();c.fill();c.stroke()}
|
||||
c.translate(128,130+6*s);c.rotate(.05*cos(T*t));c.translate(-132,-128)
|
||||
c.save();c.translate(58,130);c.rotate(.3*sin(T*t-1.3))
|
||||
fill(B,()=>{c.moveTo(6,-8);c.quadraticCurveTo(-12,-12,-30,-32);c.quadraticCurveTo(-22,-10,-24,0);c.quadraticCurveTo(-22,10,-30,32);c.quadraticCurveTo(-12,12,6,8)})
|
||||
c.restore()
|
||||
c.save();c.translate(150,150);c.rotate(-.4-.35*sin(T*t*2));fill(B,()=>c.ellipse(-14,10,20,9,.4,0,T));c.restore()
|
||||
fill(B,()=>{c.moveTo(56,124);c.bezierCurveTo(88,90,136,78,166,82);c.bezierCurveTo(196+m,82,214+m,104,208,124)
|
||||
c.quadraticCurveTo(220,128,218,134);c.quadraticCurveTo(206,146,196,144);c.bezierCurveTo(180,166,126,172,96,156);c.quadraticCurveTo(72,144,56,136)})
|
||||
fill(L,()=>c.ellipse(140,152,40,9,-.05,0,T))
|
||||
c.fillStyle=c.strokeStyle=D
|
||||
if(bl)c.lineWidth=3.5,c.beginPath(),c.arc(180,112,5,.15*PI,.85*PI),c.stroke()
|
||||
else c.beginPath(),c.arc(180,114,5,0,T),c.fill()
|
||||
c.lineWidth=3;c.lineCap='round';c.beginPath();c.moveTo(214,137);c.quadraticCurveTo(204,145,192,138);c.stroke()
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// betta fish swishing: small red body trailing big pink fins whose wavy edges ripple
|
||||
const{sin,cos,PI}=Math,T=2*PI
|
||||
export const frames=24,delay=80
|
||||
const B='#ee5a5a',A='#ff85a8',L='#ffc2d4',D='#2b2633'
|
||||
export default(c,t)=>{
|
||||
const s=sin(T*t),sw=.12*sin(T*t-1),fill=(col,f)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();f();c.fill();c.stroke()}
|
||||
c.translate(128,128+6*s);c.rotate(.04*cos(T*t));c.translate(-120,-128)
|
||||
const rim=i=>{const a=PI+1.15-2.3*i/32+sw,r=78+8*sin(i/32*T*1.5-T*t*2);return[114+r*cos(a),128+r*sin(a)]}
|
||||
fill(A,()=>{c.moveTo(118,112);for(let i=0;i<=32;i++)c.lineTo(...rim(i));c.lineTo(118,144)})
|
||||
c.strokeStyle=L;c.lineWidth=3;c.lineCap='round'
|
||||
for(const i of[7,16,25]){const[x,y]=rim(i);c.beginPath();c.moveTo(114+(x-114)*.25,128+(y-128)*.25);c.lineTo(114+(x-114)*.75,128+(y-128)*.75);c.stroke()}
|
||||
fill(A,()=>{c.moveTo(176,104);c.quadraticCurveTo(160,56,112+4*s,58+6*sin(T*t*2));c.quadraticCurveTo(124,92,130,106)})
|
||||
fill(A,()=>{c.moveTo(172,142);c.quadraticCurveTo(162,196,110+4*s,196+5*sin(T*t*2+1));c.quadraticCurveTo(122,160,128,140)})
|
||||
fill(B,()=>c.ellipse(152,124,44,26,0,0,T))
|
||||
c.save();c.translate(156,136);c.rotate(2.3+.4*sin(T*t*2));fill(A,()=>c.ellipse(10,0,12,6,0,0,T));c.restore()
|
||||
c.fillStyle=D;c.beginPath();c.arc(182,116,5,0,T);c.fill()
|
||||
c.strokeStyle=D;c.lineWidth=3;c.beginPath();c.arc(190,126,5,.4*PI,.85*PI);c.stroke()
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
// bread-loaf corgi standing and wiggling its butt: nub tail wagging, back feet stepping, scored crust on its back
|
||||
const{sin,cos,PI,max}=Math,T=2*PI
|
||||
export const frames=24,delay=70
|
||||
const B='#c9a27e',L='#ead7c3',D='#2b2633'
|
||||
export default(c,t)=>{
|
||||
const fill=(col,f)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();f();c.fill();c.stroke()}
|
||||
const bl=t>.3&&t<.36
|
||||
c.translate(-12,4)
|
||||
for(const x of[158,180])fill(B,()=>c.roundRect(x,180,14,26,6))
|
||||
c.save();c.translate(186,196);c.rotate(.085*sin(T*t*2));c.translate(-186,-196)
|
||||
for(const[x,d]of[[66,0],[90,PI]])fill(B,()=>c.roundRect(x,180-5*max(0,sin(T*t*2+d)),14,26,6))
|
||||
c.save();c.translate(54,124);c.rotate(.6*sin(T*t*4));fill(B,()=>c.ellipse(-8,-4,13,9,-.5,0,T));c.restore()
|
||||
fill(B,()=>{c.moveTo(60,194);c.lineTo(58,148);c.quadraticCurveTo(46,146,48,130);c.bezierCurveTo(52,96,96,92,126,92)
|
||||
c.bezierCurveTo(156,92,198,96,202,130);c.quadraticCurveTo(204,146,192,148);c.lineTo(190,194);c.closePath()})
|
||||
c.strokeStyle=L;c.lineWidth=8;c.lineCap='round'
|
||||
for(const x of[82,114,146])c.beginPath(),c.moveTo(x,110),c.lineTo(x+16,124),c.stroke()
|
||||
c.restore()
|
||||
c.translate(210,150);c.rotate(.04*sin(T*t*2+1));c.translate(-210,-150)
|
||||
fill(L,()=>c.ellipse(194,164,14,22,.2,0,T))
|
||||
for(const[x,r]of[[194,-.28],[228,.32]]){
|
||||
c.save();c.translate(x,94);c.rotate(r);fill(B,()=>{c.moveTo(-15,8);c.lineTo(-3,-34);c.lineTo(15,6)})
|
||||
fill(L,()=>{c.moveTo(-5,4);c.lineTo(-1,-14);c.lineTo(5,3)});c.restore()
|
||||
}
|
||||
fill(B,()=>c.arc(211,122,34,0,T))
|
||||
fill(L,()=>c.ellipse(229,136,18,13,0,0,T))
|
||||
c.fillStyle=c.strokeStyle=D
|
||||
c.beginPath();c.arc(244,130,5.5,0,T);c.fill()
|
||||
if(bl)c.lineWidth=4,c.beginPath(),c.arc(214,114,6,.15*PI,.85*PI),c.stroke()
|
||||
else c.beginPath(),c.arc(214,116,5.5,0,T),c.fill()
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// bunny-bird hopping: round flat-color body, long ears that lag behind the hop, wings flapping in the air, blinks while resting
|
||||
const{sin,cos,PI,max}=Math,T=2*PI
|
||||
export const frames=24,delay=70
|
||||
const B='#7b8cff',L='#c3cbff',A='#f4c03e',D='#2b2633'
|
||||
export default(c,t)=>{
|
||||
const air=t<.5,h=air?50*sin(PI*t/.5):0,v=air?cos(PI*t/.5):0,sq=t>.5&&t<.68?.13*sin(PI*(t-.5)/.18):0
|
||||
const rx=50*(1+sq),ry=50*(1-sq),cx=128,cy=206-ry-h,bl=t>.82&&t<.88
|
||||
const fill=(col,f)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();f();c.fill();c.stroke()}
|
||||
for(const d of[-1,1])fill(A,()=>c.ellipse(cx+d*16,cy+ry+4+(air?4*v:0),10,6,0,0,T))
|
||||
for(const d of[-1,1]){
|
||||
c.save();c.translate(cx+d*16,cy-ry+14);c.rotate(d*(.2+.35*v+.4*sq))
|
||||
fill(B,()=>c.ellipse(0,-30,16,32,0,0,T));fill(L,()=>c.ellipse(0,-28,6,20,0,0,T));c.restore()
|
||||
}
|
||||
for(const d of[-1,1]){
|
||||
c.save();c.translate(cx+d*(rx-6),cy+2);c.rotate(d*(air?.5+.5*sin(T*t*4):.15))
|
||||
fill(B,()=>c.ellipse(d*12,6,10,20,-d*.5,0,T));c.restore()
|
||||
}
|
||||
fill(B,()=>c.ellipse(cx,cy,rx,ry,0,0,T))
|
||||
fill(L,()=>c.ellipse(cx,cy+20*(1-sq),30*(1+sq),24*(1-sq),0,0,T))
|
||||
c.fillStyle=c.strokeStyle=D
|
||||
for(const d of[-1,1])if(bl)c.lineWidth=4,c.beginPath(),c.arc(cx+d*18,cy-12,6,.15*PI,.85*PI),c.stroke()
|
||||
else c.beginPath(),c.arc(cx+d*18,cy-10,5.5,0,T),c.fill()
|
||||
fill(A,()=>{c.moveTo(cx-7,cy-3);c.lineTo(cx+7,cy-3);c.lineTo(cx,cy+6);c.closePath()})
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// three-headed puppy sitting, the heads pant one after another with tongues out, tail wagging
|
||||
const{sin,PI}=Math,T=2*PI
|
||||
export const frames=24,delay=80
|
||||
const B='#8a94a6',L='#c5cad3',A='#ff85a8',D='#2b2633'
|
||||
export default(c,t)=>{
|
||||
const fill=(col,g)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();g();c.fill();c.stroke()}
|
||||
c.translate(0,-12)
|
||||
c.save();c.translate(168,200);c.rotate(.35*sin(3*T*t))
|
||||
c.strokeStyle=B;c.lineWidth=14;c.beginPath();c.moveTo(0,0);c.quadraticCurveTo(28,-6,30,-40);c.stroke();c.restore()
|
||||
fill(B,()=>c.ellipse(128,184,56,36,0,0,T))
|
||||
fill(L,()=>c.ellipse(128,192,26,22,0,0,T))
|
||||
for(const d of[-1,1])fill(L,()=>c.ellipse(128+d*26,218,14,8,0,0,T))
|
||||
for(const[i,x,y,r,a]of[[0,70,140,28,-.26],[2,186,140,28,.26],[1,128,106,31,0]]){
|
||||
const p=sin(T*(3*t-i/3)),bl=i==1&&t>.6&&t<.66
|
||||
c.save();c.translate(x,y+2.5*p);c.rotate(a)
|
||||
for(const d of[-1,1])fill(B,()=>{c.moveTo(d*r*.3,-r*.8);c.lineTo(d*r*.82,-r*1.25);c.lineTo(d*r*.95,-r*.3)})
|
||||
fill(B,()=>c.arc(0,0,r,0,T))
|
||||
for(const d of[-1,1])fill(L,()=>{c.moveTo(d*r*.55,-r*.78);c.lineTo(d*r*.8,-r*1.05);c.lineTo(d*r*.82,-r*.62)})
|
||||
fill(L,()=>c.ellipse(0,r*.36,r*.5,r*.36,0,0,T))
|
||||
fill(D,()=>c.ellipse(0,r*.5,r*.16,r*.14+1.5*(p+1),0,0,PI))
|
||||
fill(A,()=>c.roundRect(-r*.15,r*.52,r*.3,r*.34+4*(p+1),r*.15))
|
||||
fill(D,()=>c.ellipse(0,r*.2,5.5,4,0,0,T))
|
||||
c.fillStyle=c.strokeStyle=D
|
||||
for(const d of[-1,1])if(bl)c.lineWidth=3.5,c.beginPath(),c.arc(d*r*.38,-r*.16,5,.15*PI,.85*PI),c.stroke()
|
||||
else c.beginPath(),c.arc(d*r*.38,-r*.12,4.5,0,T),c.fill()
|
||||
c.restore()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// chipmunk sitting up with an acorn, stuffs it in its mouth and its cheeks balloon out, blinks, then grabs another
|
||||
const{sin,cos,PI,max,min}=Math,T=2*PI
|
||||
export const frames=32,delay=70
|
||||
const B='#e8955a',L='#f8d1b0',A='#8c4f2c',N='#f4c03e',D='#2b2633'
|
||||
const cl=x=>max(0,min(1,x)),ease=x=>(x=cl(x),x*x*(3-2*x))
|
||||
export default(c,t)=>{
|
||||
const lift=ease((t-.26)/.16)-ease((t-.86)/.14)*0,eat=t>.42&&t<.86,ns=t<.42?1:t>.86?ease((t-.86)/.12):0
|
||||
const puff=ease((t-.42)/.08)*(1+.12*sin(PI*cl((t-.42)/.16)))-ease((t-.86)/.1)
|
||||
const cr=14+13*puff,nb=t<.26?1.5*sin(T*t*8):0,bl=t>.68&&t<.73
|
||||
const nx=128,ny=150-30*lift+nb
|
||||
const fill=(col,f)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();f();c.fill();c.stroke()}
|
||||
c.strokeStyle=B;c.lineWidth=26;c.beginPath();c.moveTo(150,200);c.bezierCurveTo(196,204,200,150,186,108+3*sin(T*t));c.stroke()
|
||||
c.strokeStyle=A;c.lineWidth=7;c.beginPath();c.moveTo(166,200);c.bezierCurveTo(194,196,192,150,184,116+3*sin(T*t));c.stroke()
|
||||
for(const d of[-1,1])fill(B,()=>c.ellipse(128+d*20,212,16,7,0,0,T))
|
||||
fill(B,()=>c.ellipse(128,172,42,44,0,0,T))
|
||||
fill(L,()=>c.ellipse(128,180,25,32,0,0,T))
|
||||
for(const d of[-1,1])fill(B,()=>c.arc(128+d*29,70,11,0,T)),fill(L,()=>c.arc(128+d*29,70,5,0,T))
|
||||
fill(B,()=>c.arc(128,102,36,0,T))
|
||||
for(const x of[-14,0,14])c.strokeStyle=A,c.lineWidth=6,c.beginPath(),c.moveTo(128+x,70+abs(x)*.25),c.lineTo(128+x*.9,88),c.stroke()
|
||||
for(const d of[-1,1])fill(L,()=>c.arc(128+d*(18+cr*.55),118,cr,0,T))
|
||||
fill(L,()=>c.ellipse(128,120,10,8,0,0,T))
|
||||
c.fillStyle=c.strokeStyle=D
|
||||
for(const d of[-1,1])if(bl)c.lineWidth=4,c.beginPath(),c.arc(128+d*15,98,5,.15*PI,.85*PI),c.stroke()
|
||||
else c.beginPath(),c.arc(128+d*15,100,5,0,T),c.fill()
|
||||
c.beginPath();c.ellipse(128,114,4.5,3.5,0,0,T);c.fill()
|
||||
if(ns>0){
|
||||
c.save();c.translate(nx,ny);c.scale(ns,ns)
|
||||
fill(N,()=>c.ellipse(0,5,11,13,0,0,T));fill(A,()=>c.ellipse(0,-7,13,7,0,0,T))
|
||||
c.strokeStyle=A;c.lineWidth=3;c.beginPath();c.moveTo(0,-11);c.lineTo(2,-16);c.stroke();c.restore()
|
||||
}
|
||||
const hy=eat?150:ny+6
|
||||
for(const d of[-1,1])fill(B,()=>c.ellipse(128+d*(eat?11:17),hy,7,9,d*.3,0,T))
|
||||
}
|
||||
const abs=Math.abs
|
||||
@@ -0,0 +1,20 @@
|
||||
// clownfish wiggle-swimming: orange body with white bands kept inside an orange edge, tail and fins fluttering
|
||||
const{sin,PI}=Math,T=2*PI
|
||||
export const frames=24,delay=70
|
||||
const B='#ff9f43',L='#ffcfa1',W='#fff',D='#2b2633'
|
||||
export default(c,t)=>{
|
||||
const w=sin(T*t*2),fill=(col,f)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();f();c.fill();c.stroke()}
|
||||
c.translate(140,128+5*sin(T*t));c.rotate(.05*sin(T*t*2+1));c.scale(1.08,1.08);c.translate(-128,-128)
|
||||
fill(B,()=>{c.moveTo(92,104);c.quadraticCurveTo(102,70+4*w,130,72);c.quadraticCurveTo(158,74,166,100)})
|
||||
fill(B,()=>c.ellipse(116,164,22,12,-.3+.1*w,0,T))
|
||||
c.save();c.translate(70,128);c.rotate(.3*w)
|
||||
fill(B,()=>{c.moveTo(8,0);c.quadraticCurveTo(-12,-16,-40,-34);c.quadraticCurveTo(-28,0,-40,34);c.quadraticCurveTo(-12,16,8,0)})
|
||||
c.restore()
|
||||
fill(B,()=>c.ellipse(130,128,66,44,0,0,T))
|
||||
c.save();c.beginPath();c.ellipse(130,128,57,35,0,0,T);c.clip()
|
||||
c.fillStyle=W;for(const[x,r]of[[170,9],[124,12],[80,8]])c.beginPath(),c.ellipse(x,128,r,50,0,0,T),c.fill()
|
||||
c.restore()
|
||||
c.save();c.translate(144,142);c.rotate(.5+.4*sin(T*t*2+2));fill(L,()=>c.ellipse(12,0,14,8,0,0,T));c.restore()
|
||||
c.fillStyle=D;c.beginPath();c.arc(184,118,6,0,T);c.fill()
|
||||
c.strokeStyle=D;c.lineWidth=3;c.lineCap='round';c.beginPath();c.arc(190,134,6,.35*PI,.8*PI);c.stroke()
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// cockatiel bobbing its crest: grey body, yellow head with orange cheeks, head tilting side to side, blinks
|
||||
const{sin,PI}=Math,T=2*PI
|
||||
export const frames=24,delay=80
|
||||
const B='#8a94a6',L='#c5cad3',Y='#f4c03e',O='#ff9f43',D='#2b2633'
|
||||
export default(c,t)=>{
|
||||
const s=sin(T*t),tl=.12*s,cr=.22*sin(T*t-1.3)+.12*sin(2*T*t),br=1+.02*sin(2*T*t),bl=t>.42&&t<.48
|
||||
const fill=(col,f)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();f();c.fill();c.stroke()}
|
||||
fill(B,()=>{c.moveTo(116,196);c.lineTo(140,196);c.lineTo(134,238);c.lineTo(122,238);c.closePath()})
|
||||
for(const d of[-1,1])fill(L,()=>c.ellipse(128+d*18,220,11,6,0,0,T))
|
||||
fill(B,()=>c.ellipse(128,162,50*br,56,0,0,T))
|
||||
for(const d of[-1,1])fill(L,()=>c.ellipse(128+d*36,150,8,22,d*.2,0,T))
|
||||
c.save();c.translate(128,124);c.rotate(tl)
|
||||
c.strokeStyle=Y;c.lineCap='round'
|
||||
for(const[a,l,w]of[[-.3,30,8],[0,42,10],[.3,34,8]]){
|
||||
c.save();c.translate(a*20,-58);c.rotate(a+cr*(1+a));c.lineWidth=w
|
||||
c.beginPath();c.moveTo(0,4);c.quadraticCurveTo(-8,-l*.7,6,-l);c.stroke();c.restore()
|
||||
}
|
||||
fill(Y,()=>c.arc(0,-28,36,0,T))
|
||||
for(const d of[-1,1])fill(O,()=>c.arc(d*21,-16,9,0,T))
|
||||
c.fillStyle=c.strokeStyle=D
|
||||
for(const d of[-1,1])if(bl)c.lineWidth=4,c.beginPath(),c.arc(d*14,-34,5.5,.15*PI,.85*PI),c.stroke()
|
||||
else c.beginPath(),c.arc(d*14,-32,5.5,0,T),c.fill()
|
||||
fill(L,()=>{c.moveTo(-7,-22);c.lineTo(7,-22);c.lineTo(0,-11);c.closePath()})
|
||||
c.restore()
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// crocodile lying low: knobbly back, eyes on top of its head, jaws creak open then snap shut, tail swaying
|
||||
const{sin,cos,PI,min,max}=Math,T=2*PI
|
||||
export const frames=32,delay=70
|
||||
const B='#8cc084',L='#c5e0c1',W='#fff',A='#ff85a8',D='#2b2633'
|
||||
const e=x=>(x=min(1,max(0,x)),x*x*(3-2*x))
|
||||
export default(c,t)=>{
|
||||
const j=.42*e((t-.1)/.3)*(1-e((t-.46)/.05))+.2*e((t-.62)/.06)*(1-e((t-.72)/.04)),bl=t>.85&&t<.91
|
||||
const fill=(col,f)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();f();c.fill();c.stroke()}
|
||||
c.translate(128,128+2*sin(T*t));c.scale(.92,.92);c.translate(-121,-150)
|
||||
c.save();c.translate(70,150);c.rotate(.1*sin(T*t))
|
||||
fill(B,()=>{c.moveTo(6,-18);c.quadraticCurveTo(-30,-14,-56,-2);c.lineTo(-58,2);c.quadraticCurveTo(-30,6,6,14)})
|
||||
for(const x of[-12,-28,-42])fill(B,()=>c.arc(x,-12+(x+42)*-.12+2,4.5,0,T))
|
||||
c.restore()
|
||||
for(const x of[92,146])fill(B,()=>{c.moveTo(x-9,160);c.lineTo(x-10,184);c.lineTo(x+8,186);c.lineTo(x+9,160)})
|
||||
fill(B,()=>c.ellipse(112,150,56,22,0,0,T))
|
||||
for(const x of[78,96,114,132])fill(B,()=>c.arc(x,130,7,0,T))
|
||||
fill(L,()=>c.ellipse(114,162,40,6,0,0,T))
|
||||
const r=(l,a)=>[156+l*cos(a),150+l*sin(a)]
|
||||
if(j>.01)fill(A,()=>{c.moveTo(158,150);c.lineTo(...r(58,-j*.35));c.lineTo(...r(56,j));c.closePath()})
|
||||
c.save();c.translate(156,150);c.rotate(j)
|
||||
fill(B,()=>{c.moveTo(-8,-2);c.lineTo(66,-2);c.quadraticCurveTo(74,2,66,8);c.lineTo(-8,12)})
|
||||
c.fillStyle=c.strokeStyle=W;c.lineWidth=2;c.lineJoin='round'
|
||||
for(const x of[18,32,46,58])c.beginPath(),c.moveTo(x-4,-1),c.lineTo(x,-8),c.lineTo(x+4,-1),c.closePath(),c.fill(),c.stroke()
|
||||
c.restore()
|
||||
c.save();c.translate(156,150);c.rotate(-j*.35)
|
||||
fill(B,()=>{c.moveTo(-14,4);c.lineTo(-14,-20);c.quadraticCurveTo(0,-30,20,-24);c.lineTo(66,-12);c.quadraticCurveTo(78,-8,74,0);c.lineTo(-14,2)})
|
||||
fill(B,()=>c.arc(10,-26,11,0,T));fill(B,()=>c.arc(66,-14,6,0,T))
|
||||
c.fillStyle=c.strokeStyle=W;c.lineWidth=2
|
||||
for(const x of[24,38,52,64])c.beginPath(),c.moveTo(x-4,1),c.lineTo(x,8),c.lineTo(x+4,1),c.closePath(),c.fill(),c.stroke()
|
||||
c.fillStyle=c.strokeStyle=D
|
||||
if(bl)c.lineWidth=3,c.beginPath(),c.moveTo(6,-28),c.lineTo(16,-28),c.stroke()
|
||||
else c.beginPath(),c.arc(12,-28,4.5,0,T),c.fill()
|
||||
c.beginPath();c.arc(68,-17,2,0,T);c.fill()
|
||||
c.restore()
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// dolphin leaping in a big arc out of a little rolling wave and diving back in, slowest at the top, quick under water
|
||||
const{sin,cos,PI}=Math,T=2*PI
|
||||
export const frames=32,delay=60
|
||||
const B='#4ea8de',L='#a7d4ef',A='#2ec4b6',AL='#96e1da',D='#2b2633'
|
||||
export default(c,t)=>{
|
||||
const u=(t+.5)%1-.5,v=Math.abs(u)*2,th=Math.sign(u)*PI*(.525*v+.475*v**8)-PI/2,R=74,fill=(col,f)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();f();c.fill();c.stroke()}
|
||||
c.save();c.beginPath();c.rect(0,0,256,194);c.clip()
|
||||
c.translate(128+R*cos(th),182+R*sin(th));c.rotate(th+PI/2)
|
||||
c.save();c.translate(-60,0);c.rotate(.2*sin(T*t*2))
|
||||
fill(B,()=>{c.moveTo(6,-4);c.quadraticCurveTo(-6,-6,-16,-18);c.quadraticCurveTo(-10,-4,-12,0);c.quadraticCurveTo(-10,4,-16,18);c.quadraticCurveTo(-6,6,6,4)})
|
||||
c.restore()
|
||||
fill(B,()=>{c.moveTo(6,-22);c.quadraticCurveTo(-2,-44,-16,-46);c.quadraticCurveTo(-12,-30,-20,-17)})
|
||||
fill(B,()=>c.ellipse(14,17,14,6,.6,0,T))
|
||||
fill(B,()=>{c.moveTo(60,4);c.quadraticCurveTo(58,-4,46,-6);c.bezierCurveTo(36,-24,0,-26,-22,-17);c.bezierCurveTo(-40,-10,-52,-5,-60,-3)
|
||||
c.lineTo(-60,3);c.bezierCurveTo(-46,8,-4,22,26,15);c.quadraticCurveTo(44,10,60,4)})
|
||||
fill(L,()=>c.ellipse(8,9,28,6,.05,0,T))
|
||||
c.fillStyle=D;c.beginPath();c.arc(36,-7,3.5,0,T);c.fill()
|
||||
c.restore()
|
||||
c.fillStyle=c.strokeStyle=A;c.lineWidth=6;c.beginPath();c.moveTo(30,206)
|
||||
for(let x=30;x<=226;x+=4)c.lineTo(x,182+5*sin(x*T/66-T*t))
|
||||
c.lineTo(226,206);c.closePath();c.fill();c.stroke()
|
||||
c.strokeStyle=AL;c.lineWidth=4;c.lineCap='round';c.beginPath()
|
||||
for(let x=48;x<=208;x+=4)c.lineTo(x,194+3*sin(x*T/66-T*t+1.5))
|
||||
c.stroke()
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// fennec fox sitting with its tail wrapped round its feet, huge ears swivelling to listen, blinks
|
||||
const{sin,cos,PI}=Math,T=2*PI
|
||||
export const frames=24,delay=80
|
||||
const B='#efb36a',L='#fadcb8',A='#8c5a36',D='#2b2633'
|
||||
export default(c,t)=>{
|
||||
const tw=t>.56&&t<.62?.22:0,el=-.55+.14*sin(T*t),er=.55+.14*sin(T*t+1.9)+tw,bl=t>.3&&t<.36,hr=.04*sin(T*t+.6)
|
||||
const fill=(col,f)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();f();c.fill();c.stroke()}
|
||||
c.translate(0,7)
|
||||
fill(B,()=>c.ellipse(128,172,38,44,0,0,T))
|
||||
fill(L,()=>c.ellipse(128,174,22,32,0,0,T))
|
||||
c.save();c.translate(128,128);c.rotate(hr);c.translate(-128,-128)
|
||||
for(const[x,r]of[[110,el],[146,er]]){
|
||||
c.save();c.translate(x,92);c.rotate(r)
|
||||
fill(B,()=>{c.moveTo(-19,4);c.quadraticCurveTo(-24,-52,0,-86);c.quadraticCurveTo(24,-52,19,4);c.closePath()})
|
||||
fill(L,()=>{c.moveTo(-9,-2);c.quadraticCurveTo(-12,-44,0,-68);c.quadraticCurveTo(12,-44,9,-2);c.closePath()});c.restore()
|
||||
}
|
||||
fill(B,()=>c.arc(128,108,32,0,T))
|
||||
fill(B,()=>{c.moveTo(98,112);c.quadraticCurveTo(110,134,128,142);c.quadraticCurveTo(146,134,158,112);c.closePath()})
|
||||
fill(L,()=>{c.moveTo(108,122);c.quadraticCurveTo(116,136,128,140);c.quadraticCurveTo(140,136,148,122);c.quadraticCurveTo(128,114,108,122)})
|
||||
c.fillStyle=c.strokeStyle=D
|
||||
for(const d of[-1,1])if(bl)c.lineWidth=4,c.beginPath(),c.arc(128+d*14,104,5.5,.15*PI,.85*PI),c.stroke()
|
||||
else c.beginPath(),c.ellipse(128+d*14,107,5,6,0,0,T),c.fill()
|
||||
c.beginPath();c.ellipse(128,138,5,3.5,0,0,T);c.fill()
|
||||
c.restore()
|
||||
fill(B,()=>c.ellipse(140,210,52,13,0,0,T))
|
||||
fill(A,()=>c.ellipse(88,208,15,11,0,0,T))
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// fire-fox sitting still while it burns: ears, chest and tail are flames that flicker, embers drift off the tail tip
|
||||
const{sin,cos,PI}=Math,T=2*PI
|
||||
export const frames=24,delay=80
|
||||
const B='#ff9f43',A='#f4c03e',D='#2b2633'
|
||||
export default(c,t)=>{
|
||||
const fill=(col,f)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();f();c.fill();c.stroke()}
|
||||
// teardrop flame standing on (x,y): round base of radius w, tip h up and leaning by lean
|
||||
const fl=(x,y,w,h,lean)=>{c.moveTo(x+lean,y-h);c.quadraticCurveTo(x+w*1.15,y-h*.45,x+w,y-w);c.arc(x,y-w,w,0,PI);c.quadraticCurveTo(x-w*1.15,y-h*.45,x+lean,y-h)}
|
||||
c.translate(-12,0)
|
||||
const f=k=>sin(T*t*2+k)*.7+sin(T*t*3+k*1.7)*.3,bl=t>.4&&t<.46
|
||||
for(let k=0;k<2;k++){const q=(t+k/2)%1;fill(A,()=>c.arc(206+10*sin(T*q+k*2)+q*8,78-56*q,4.5*(1-q),0,T))}
|
||||
fill(B,()=>fl(170,212,30,130+7*f(1),44+9*f(2)))
|
||||
fill(A,()=>fl(172,206,15,84+6*f(2.5),26+8*f(3)))
|
||||
for(const d of[-1,1])fill(B,()=>fl(118+d*22,84,13,52+5*f(d*2),d*12+5*f(d+4)))
|
||||
for(const d of[-1,1])fill(A,()=>fl(118+d*22,82,6,34+3*f(d*2),d*9+4*f(d+4)))
|
||||
fill(B,()=>fl(118,212,42,116,0))
|
||||
fill(A,()=>fl(118,208,19,62+5*f(4),4*f(5)))
|
||||
fill(B,()=>c.arc(118,106,36,0,T))
|
||||
for(const d of[-1,1])fill(B,()=>{c.moveTo(118+d*30,98);c.lineTo(118+d*48,122+3*f(d*3));c.lineTo(118+d*24,122)})
|
||||
fill(A,()=>c.ellipse(118,124,15,10,0,0,T))
|
||||
c.fillStyle=c.strokeStyle=D
|
||||
for(const d of[-1,1])if(bl)c.lineWidth=4,c.beginPath(),c.arc(118+d*15,102,6,.15*PI,.85*PI),c.stroke()
|
||||
else c.beginPath(),c.arc(118+d*15,104,5.5,0,T),c.fill()
|
||||
c.beginPath();c.ellipse(118,119,5,3.5,0,0,T);c.fill()
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// goose honking: long neck stretches up and forward, beak honks twice, tail wags while it waits
|
||||
const{sin,cos,PI,max}=Math,T=2*PI
|
||||
export const frames=24,delay=80
|
||||
const B='#4ea8de',L='#a7d4ef',O='#ff9f43',D='#2b2633'
|
||||
export default(c,t)=>{
|
||||
const u=(t-.25)/.5,on=u>0&&u<1,e=on?sin(PI*u)**2:0,op=on?.42*max(0,sin(4*PI*u))*e:0,bl=t>.86&&t<.92
|
||||
const hx=168+18*e,hy=80-30*e,tw=on?0:.12*sin(4*PI*t)
|
||||
const fill=(col,f)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();f();c.fill();c.stroke()}
|
||||
c.strokeStyle=O;c.lineWidth=6
|
||||
for(const x of[98,124])c.beginPath(),c.moveTo(x,200),c.lineTo(x,226),c.stroke(),fill(O,()=>c.ellipse(x+6,228,10,4,0,0,T))
|
||||
c.save();c.translate(52,160);c.rotate(tw);fill(B,()=>{c.moveTo(14,-14);c.lineTo(-30,-26);c.lineTo(-24,-12);c.lineTo(14,12);c.closePath()});c.restore()
|
||||
fill(B,()=>c.ellipse(108,168,66,40,-.06,0,T))
|
||||
fill(L,()=>c.ellipse(100,160,44,22,-.16,0,T))
|
||||
c.strokeStyle=B;c.lineWidth=26;c.lineCap='round'
|
||||
c.beginPath();c.moveTo(150,158);c.quadraticCurveTo(160+6*e,120-12*e,hx,hy);c.stroke()
|
||||
fill(B,()=>c.arc(hx,hy,20,0,T))
|
||||
for(const d of[-1,1]){
|
||||
c.save();c.translate(hx+16,hy+3);c.rotate(d*op)
|
||||
fill(O,()=>{c.moveTo(0,-7*(d<0)-1);c.lineTo(22,d*2);c.lineTo(0,d>0?7:1);c.closePath()});c.restore()
|
||||
}
|
||||
c.fillStyle=c.strokeStyle=D
|
||||
if(bl)c.lineWidth=3.5,c.beginPath(),c.arc(hx+4,hy-7,4.5,.15*PI,.85*PI),c.stroke()
|
||||
else c.beginPath(),c.arc(hx+4,hy-5,4.5,0,T),c.fill()
|
||||
if(op>.15){
|
||||
c.strokeStyle=O;c.lineWidth=4;c.lineCap='round'
|
||||
for(const[a,r]of[[-.5,14],[0,18],[.5,14]])c.beginPath(),c.moveTo(hx+44+8*cos(a),hy+2+8*sin(a)),c.lineTo(hx+44+r*cos(a)+6,hy+2+r*sin(a)),c.stroke()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// hermit crab: eyes peek out of its shell, it climbs half out waving both claws, ducks back in and the shell wobbles
|
||||
const{sin,cos,PI,min,max}=Math,T=2*PI
|
||||
export const frames=32,delay=70
|
||||
const B='#f4c03e',L='#f9e0a0',A='#ee5a5a',D='#2b2633'
|
||||
const e=x=>(x=min(1,max(0,x)),x*x*(3-2*x))
|
||||
export default(c,t)=>{
|
||||
const o=e((t-.1)/.16)*(1-e((t-.7)/.14)),pe=e((t-.02)/.1)*(1-e((t-.8)/.08)),wob=.06*sin(PI*e((t-.84)/.16))*sin(T*t*8)
|
||||
const fill=(col,f)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();f();c.fill();c.stroke()},ox=146,oy=166
|
||||
c.translate(110,198);c.rotate(wob);c.translate(-110,-198)
|
||||
c.strokeStyle=A;c.lineCap='round';c.lineJoin='round'
|
||||
for(let i=0;i<3;i++){c.lineWidth=7;c.beginPath();c.moveTo(ox-4+8*i,oy+8);c.lineTo(ox+o*(18+8*i),oy+8-o*4);c.lineTo(ox+o*(28+10*i),oy+30*o+4);c.stroke()}
|
||||
fill(A,()=>c.ellipse(ox+o*16,oy-o*6,22,18,0,0,T))
|
||||
for(const d of[-1,1]){c.strokeStyle=A;c.lineWidth=5;c.beginPath();c.moveTo(ox+4+d*4,oy-6);c.lineTo(ox+8+pe*10+d*7,oy-12-pe*30);c.stroke()
|
||||
const ex=ox+8+pe*10+d*7,ey=oy-14-pe*30;c.fillStyle=A;c.beginPath();c.arc(ex,ey,7.5,0,T);c.fill();c.fillStyle=D;c.beginPath();c.arc(ex+1,ey,4.5,0,T);c.fill()}
|
||||
for(const[dy,sz,p]of[[-22,1,0],[6,.75,1.3]]){
|
||||
const px=ox+o*(52*sz+4),py=oy+o*(dy-18*sz+6*sin(T*t*4+p)),g=.35+.25*sin(T*t*8+p)
|
||||
c.strokeStyle=A;c.lineWidth=9;c.beginPath();c.moveTo(ox+o*16,oy-o*6);c.lineTo(px,py);c.stroke()
|
||||
c.save();c.translate(px,py);c.rotate(-.5+.25*sin(T*t*4+p));c.scale(sz*(.4+.6*o),sz*(.4+.6*o))
|
||||
fill(A,()=>c.ellipse(12,-6,14,8,-g,0,T));fill(A,()=>c.ellipse(12,6,13,7,g,0,T));fill(A,()=>c.arc(0,0,10,0,T));c.restore()
|
||||
}
|
||||
for(const[x,y,r]of[[37,60,12],[50,76,20],[72,100,32],[108,140,56]])fill(B,()=>c.arc(x,y,r,0,T))
|
||||
c.strokeStyle=L;c.lineWidth=4
|
||||
for(const[x,y,r]of[[37,60,12],[50,76,20],[72,100,32]])c.beginPath(),c.arc(x,y,r,-.3,2.1),c.stroke()
|
||||
fill(A,()=>c.ellipse(ox,oy,20,26,-.6,0,T))
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
// little imp giggling: quick bounces with squeezed eyes and a wide grin, then catches its breath, tail swishing
|
||||
const{sin,abs,PI}=Math,T=2*PI
|
||||
export const frames=24,delay=75
|
||||
const B='#ff85a8',L='#ffc2d4',A='#f4c03e',D='#2b2633'
|
||||
export default(c,t)=>{
|
||||
const gg=t<.6,g=gg?abs(sin(4*PI*t/.6)):0,sq=gg?.06*(1-g):0,y=gg?-12*g:-2*sin(PI*(t-.6)/.4)
|
||||
const fill=(col,f)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();f();c.fill();c.stroke()}
|
||||
c.translate(128,190+y);c.scale(1+sq,1-sq)
|
||||
c.save();c.translate(36,-18);c.rotate(.3*sin(T*t))
|
||||
c.strokeStyle=B;c.lineWidth=8;c.beginPath();c.moveTo(0,0);c.quadraticCurveTo(40,8,54,-16);c.stroke()
|
||||
fill(B,()=>{c.moveTo(54,-12);c.lineTo(44,-24);c.lineTo(58,-38);c.lineTo(66,-20);c.closePath()});c.restore()
|
||||
for(const d of[-1,1])fill(B,()=>c.ellipse(d*20,-4,12,8,0,0,T))
|
||||
for(const d of[-1,1])fill(A,()=>{c.moveTo(d*22,-104);c.quadraticCurveTo(d*30,-130,d*44,-136);c.quadraticCurveTo(d*44,-118,d*40,-100)})
|
||||
for(const d of[-1,1])fill(B,()=>{c.moveTo(d*48,-74);c.lineTo(d*76,-92);c.lineTo(d*54,-56)})
|
||||
fill(B,()=>c.ellipse(0,-58,56,52,0,0,T))
|
||||
fill(L,()=>c.ellipse(0,-30,28,20,0,0,T))
|
||||
for(const d of[-1,1])fill(B,()=>c.ellipse(d*(50+(gg?3*g:0)),-30-(gg?6*g:0),9,14,d*.5,0,T))
|
||||
c.fillStyle=c.strokeStyle=D;c.lineWidth=4.5
|
||||
if(gg){
|
||||
for(const d of[-1,1])c.beginPath(),c.moveTo(d*28,-70),c.lineTo(d*18,-78),c.lineTo(d*8,-70),c.stroke()
|
||||
c.beginPath();c.moveTo(-18,-56);c.quadraticCurveTo(0,-56,18,-56);c.quadraticCurveTo(14,-36,0,-36);c.quadraticCurveTo(-14,-36,-18,-56);c.fill()
|
||||
c.fillStyle=L;c.beginPath();c.moveTo(-12,-56);c.lineTo(-8,-50);c.lineTo(-4,-56);c.fill()
|
||||
c.strokeStyle=B;c.lineWidth=4;for(const d of[-1,1])c.beginPath(),c.arc(d*84,-84,10+3*g,d>0?-.6:PI-.4+0,d>0?.4:PI+.6),c.stroke()
|
||||
}else{
|
||||
const bl=t>.86&&t<.92
|
||||
for(const d of[-1,1])if(bl)c.lineWidth=3.5,c.beginPath(),c.arc(d*18,-74,5,.15*PI,.85*PI),c.stroke()
|
||||
else c.beginPath(),c.arc(d*18,-72,5,0,T),c.fill()
|
||||
c.lineWidth=3.5;c.beginPath();c.moveTo(-10,-54);c.quadraticCurveTo(2,-46,12,-56);c.stroke()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// jackalope hopping in place: little antlers, ears trailing the hop, stretched in the air, squashed on landing
|
||||
const{sin,cos,PI}=Math,T=2*PI
|
||||
export const frames=24,delay=75
|
||||
const B='#c9a27e',L='#ead8c4',A='#8f6b4c',D='#2b2633'
|
||||
export default(c,t)=>{
|
||||
const air=t<.5,u=t/.5,h=air?38*sin(PI*u):0,v=air?cos(PI*u):0,sq=t>.5&&t<.66?sin(PI*(t-.5)/.16):0,bl=t>.84&&t<.9
|
||||
const fill=(col,g)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();g();c.fill();c.stroke()}
|
||||
const line=(col,lw,g)=>{c.strokeStyle=col;c.lineWidth=lw;c.beginPath();g();c.stroke()}
|
||||
c.translate(126,214-h);c.scale(1.15*(1+.07*sq),1.15*(1-.09*sq));c.rotate(air?-.22*v:0)
|
||||
const ear=(x,col,lag)=>{c.save();c.translate(x,-92);c.rotate(-.95-.3*v+.2*sq+lag);fill(col,()=>c.ellipse(0,-24,10,26,0,0,T))
|
||||
if(col==B)fill(L,()=>c.ellipse(0,-22,4,17,0,0,T));c.restore()}
|
||||
ear(30,A,.12)
|
||||
for(const x of[36,46])line(A,5,()=>{c.moveTo(x,-92);c.quadraticCurveTo(x+6,-108,x+2,-122);c.moveTo(x+3,-106);c.lineTo(x+13,-114)})
|
||||
fill(B,()=>c.ellipse(-36,air?-12+6*v:-6,air?18:22,8,air?.5*v:0,0,T))
|
||||
fill(B,()=>c.arc(-28,-32,24,0,T))
|
||||
fill(B,()=>c.ellipse(-6,-42,48,30,-.1,0,T))
|
||||
fill(L,()=>c.arc(-56,-50,10,0,T))
|
||||
const px=air?38+3*v:30,py=air?-18:-8
|
||||
line(B,12,()=>{c.moveTo(22,-32);c.lineTo(px-2,py)});fill(B,()=>c.ellipse(px,py,10,7,0,0,T))
|
||||
fill(B,()=>c.arc(40,-70,26,0,T))
|
||||
ear(38,B,0)
|
||||
c.fillStyle=c.strokeStyle=D
|
||||
if(bl)c.lineWidth=3.5,c.beginPath(),c.arc(48,-74,5,.15*PI,.85*PI),c.stroke()
|
||||
else c.beginPath(),c.arc(48,-72,4.5,0,T),c.fill()
|
||||
c.beginPath();c.arc(65,-62,3,0,T);c.fill()
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// jelly-cat drifting: a cat-eared jellyfish bell that pulses as it bobs, tentacles waving behind
|
||||
const{sin,cos,PI}=Math,T=2*PI
|
||||
export const frames=24,delay=80
|
||||
const B='#ff85a8',L='#ffc2d3',D='#2b2633'
|
||||
export default(c,t)=>{
|
||||
const s=sin(T*t),rx=62*(1-.07*s),ry=56*(1+.06*s),cx=128,cy=96-8*sin(T*t-1),bl=t>.72&&t<.78
|
||||
const fill=(col,f)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();f();c.fill();c.stroke()}
|
||||
for(const[k,col,w,len]of[[-1.5,B,7,112],[-.5,L,10,84],[.5,L,10,84],[1.5,B,7,112]]){
|
||||
c.strokeStyle=col;c.lineWidth=w;c.beginPath()
|
||||
for(let j=0;j<=14;j++){const q=j/14;c.lineTo(cx+k*rx*.4+q*k*6+12*q*sin(T*t-q*4+k),cy+10+q*len*(1+.06*s))}
|
||||
c.stroke()
|
||||
}
|
||||
for(const d of[-1,1]){
|
||||
const a=-PI/2+d*.74
|
||||
c.save();c.translate(cx+rx*cos(a),cy+ry*sin(a)+4);c.rotate(d*(.5+.06*s))
|
||||
fill(B,()=>{c.moveTo(-16,10);c.lineTo(0,-24);c.lineTo(16,10)});fill(L,()=>{c.moveTo(-6,6);c.lineTo(0,-10);c.lineTo(6,6)});c.restore()
|
||||
}
|
||||
fill(B,()=>{c.ellipse(cx,cy,rx,ry,0,PI,T);for(let i=0;i<4;i++){const x0=cx+rx-i*rx/2;c.quadraticCurveTo(x0-rx/4,cy+18,x0-rx/2,cy)}})
|
||||
c.fillStyle=c.strokeStyle=D
|
||||
for(const d of[-1,1])if(bl)c.lineWidth=4,c.beginPath(),c.arc(cx+d*21,cy-14,6,.15*PI,.85*PI),c.stroke()
|
||||
else c.beginPath(),c.arc(cx+d*21,cy-12,5.5,0,T),c.fill()
|
||||
c.lineWidth=3.5;for(const d of[-1,1])c.beginPath(),c.arc(cx+d*4.5,cy-3,4.5,.1*PI,.9*PI),c.stroke()
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// karakasa umbrella yokai hopping on its one leg: big single eye, long tongue flapping behind the hop
|
||||
const{sin,cos,PI}=Math,T=2*PI
|
||||
export const frames=24,delay=75
|
||||
const B='#ff9f43',L='#ffcfa1',A='#ff85a8',G='#c9a27e',D='#2b2633'
|
||||
export default(c,t)=>{
|
||||
const air=t<.5,u=t/.5,h=air?28*sin(PI*u):0,v=air?cos(PI*u):0,sq=t>.5&&t<.66?sin(PI*(t-.5)/.16):0,bl=t>.8&&t<.86
|
||||
const fill=(col,g)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();g();c.fill();c.stroke()}
|
||||
c.translate(128,212-h);c.scale(1+.08*sq,1-.08*sq);c.rotate(.07*sin(T*t))
|
||||
fill(G,()=>c.roundRect(-22,-12,44,9,4));for(const x of[-14,8])fill(G,()=>c.rect(x,-4,6,4))
|
||||
c.strokeStyle=B;c.lineWidth=9;c.beginPath();c.moveTo(0,-14);c.lineTo(0,-48-(air?6*v:0));c.stroke()
|
||||
const hy=-56-(air?6*v:0)
|
||||
fill(B,()=>{c.moveTo(0,hy-112);c.quadraticCurveTo(26,hy-72,56,hy-4)
|
||||
for(const x of[28,0,-28,-56])c.quadraticCurveTo(x+14,hy+12,x,hy-4)
|
||||
c.quadraticCurveTo(-26,hy-72,0,hy-112)})
|
||||
c.strokeStyle=L;c.lineWidth=4;for(const x of[-28,28])c.beginPath(),c.moveTo(0,hy-106),c.quadraticCurveTo(x*.45,hy-60,x,hy-4),c.stroke()
|
||||
// tongue: hangs out of the mouth and lags behind the hop
|
||||
c.strokeStyle=A;c.lineWidth=12;c.beginPath();c.moveTo(0,hy-30);c.bezierCurveTo(4,hy-10,20+10*v,hy+4-10*v,30+8*sin(T*t*2),hy+20-16*v);c.stroke()
|
||||
fill(D,()=>c.ellipse(0,hy-30,11,7,0,0,PI))
|
||||
if(bl){c.strokeStyle=D;c.lineWidth=4;c.beginPath();c.arc(0,hy-64,13,.15*PI,.85*PI);c.stroke()}
|
||||
else{fill('#fff',()=>c.arc(0,hy-62,14,0,T));c.fillStyle=D;c.beginPath();c.arc(3*sin(T*t),hy-60,7,0,T);c.fill()}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
// kingfisher on a branch: bobs, tips forward and darts beak-first into the water, then pops back up to its perch
|
||||
const{sin,PI,min,abs,atan2}=Math,T=2*PI
|
||||
export const frames=32,delay=70
|
||||
const B='#2ec4b6',L='#97e2da',O='#ff9f43',W='#c9a27e',K='#8a94a6',D='#2b2633'
|
||||
const sm=x=>x<=0?0:x>=1?1:x*x*(3-2*x),lerp=(a,b,k)=>a+(b-a)*k
|
||||
export default(c,t)=>{
|
||||
const fill=(col,f)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();f();c.fill();c.stroke()}
|
||||
// pose: x, y, rotation, and whether it's stretched out into a dart
|
||||
let x=96,y=100,r=0,dart=0,hide=0
|
||||
const dn=(t-.4)/.14,uw=(t-.54)/.1,upk=(t-.64)/.16,st=(t-.8)/.08
|
||||
if(dn>0&&dn<=.3)r=dn/.3*.7
|
||||
else if(dn>.3&&dn<=1){const k=(dn-.3)/.7;x=lerp(110,160,k*k);y=lerp(118,290,k*k);r=atan2(172,50);dart=1}
|
||||
else if(uw>0&&uw<=1)hide=1
|
||||
else if(upk>0&&upk<=1){const k=sm(upk);x=lerp(156,96,k);y=lerp(206,100,k)-50*sin(PI*k);r=lerp(-.6,0,k)}
|
||||
if(st>0&&st<1)y+=6*sin(PI*st)
|
||||
const bl=t>.2&&t<.25,bob=dn<0?2*sin(4*T*t):0
|
||||
c.strokeStyle=W;c.lineWidth=11;c.lineCap='round'
|
||||
c.beginPath();c.moveTo(16,138);c.quadraticCurveTo(70,132,136,140);c.stroke()
|
||||
c.lineWidth=6;c.beginPath();c.moveTo(40,136);c.lineTo(28,118);c.stroke()
|
||||
if(!hide){
|
||||
c.save();c.beginPath();c.rect(0,0,256,212);c.clip()
|
||||
c.translate(x,y+bob);c.rotate(r);c.scale(1.2,1.2)
|
||||
if(dart){
|
||||
// stretched out along +x: tail, body, orange underside, head, beak
|
||||
fill(B,()=>{c.moveTo(-30,0);c.lineTo(-56,-10);c.lineTo(-56,10);c.closePath()})
|
||||
fill(B,()=>c.ellipse(-4,0,36,17,0,0,T))
|
||||
c.save();c.beginPath();c.ellipse(-4,0,36,17,0,0,T);c.clip();fill(O,()=>c.ellipse(-4,16,36,12,0,0,T));c.restore()
|
||||
fill(B,()=>c.arc(24,-2,18,0,T))
|
||||
fill(K,()=>{c.moveTo(36,-8);c.lineTo(80,0);c.lineTo(36,6);c.closePath()})
|
||||
fill(D,()=>c.arc(26,-8,3.5,0,T))
|
||||
}else{
|
||||
fill(B,()=>{c.moveTo(-14,24);c.lineTo(-30,50);c.lineTo(-18,54);c.lineTo(0,30);c.closePath()})
|
||||
for(const d of[-6,8])fill(O,()=>c.ellipse(d,34,6,4,0,0,T))
|
||||
fill(B,()=>c.ellipse(0,6,27,32,-.2,0,T))
|
||||
c.save();c.beginPath();c.ellipse(0,6,27,32,-.2,0,T);c.clip();fill(O,()=>c.ellipse(16,18,22,28,0,0,T));c.restore()
|
||||
fill(B,()=>c.arc(10,-28,24,0,T))
|
||||
fill(L,()=>c.ellipse(22,-16,12,8,0,0,T))
|
||||
fill(K,()=>{c.moveTo(28,-34);c.lineTo(78,-22);c.lineTo(30,-18);c.closePath()})
|
||||
c.fillStyle=c.strokeStyle=D
|
||||
if(bl)c.lineWidth=3.5,c.beginPath(),c.arc(16,-34,4.5,.15*PI,.85*PI),c.stroke()
|
||||
else c.beginPath(),c.arc(16,-32,4.5,0,T),c.fill()
|
||||
}
|
||||
c.restore()
|
||||
}
|
||||
// water line, splash and ripple
|
||||
c.strokeStyle=c.fillStyle=L;c.lineWidth=5;c.lineCap='round'
|
||||
const sp=(t-.5)/.3
|
||||
for(const[a,b]of[[40,96],[124,232]]){c.beginPath();for(let i=a;i<=b;i+=4)c.lineTo(i,214+3*sin(i/9+T*t*2));c.stroke()}
|
||||
if(sp>0&&sp<1){
|
||||
c.beginPath();c.ellipse(158,214,14+40*sp,4+6*sp,0,0,T);c.stroke()
|
||||
for(const d of[-1,-.4,.4,1]){const q=min(1,sp*1.6),h=212-40*q*(1-abs(d)*.3)+50*q*q;if(h<208)c.beginPath(),c.arc(158+d*30*q,h,5*(1-q*.6),0,T),c.fill()}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// koi-dragon swimming in place, seen from above: its body waves in an S, whiskers and fins trail, little horns on its head
|
||||
const{sin,cos,PI,hypot,atan2}=Math,T=2*PI
|
||||
export const frames=24,delay=80
|
||||
const B='#ff7a5c',L='#ffbcad',A='#f4c03e',D='#2b2633'
|
||||
export default(c,t)=>{
|
||||
const fill=(col,f)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();f();c.fill();c.stroke()}
|
||||
const N=40,P=[],Nr=[],hw=s=>s<.16?30*Math.sqrt(1-((.16-s)/.16)**2):30*(1-.84*((s-.16)/.84)**1.15)
|
||||
for(let j=0;j<=N;j++){const s=j/N;P.push([214-150*s,128+(3+24*s**1.4)*sin(T*t-3.4*s)])}
|
||||
for(let j=0;j<=N;j++){const a=P[Math.max(0,j-1)],b=P[Math.min(N,j+1)],dx=b[0]-a[0],dy=b[1]-a[1],l=hypot(dx,dy);Nr.push([-dy/l,dx/l])}
|
||||
const at=(s,o=0)=>{const j=Math.round(s*N);return[P[j][0]+Nr[j][0]*o,P[j][1]+Nr[j][1]*o]}
|
||||
const ang=s=>{const j=Math.round(s*N);return atan2(Nr[j][0],-Nr[j][1])}
|
||||
// tail fan at the end, trailing the body's last bend
|
||||
const[ex,ey]=P[N],ta=ang(1)
|
||||
c.save();c.translate(ex,ey);c.rotate(ta)
|
||||
fill(L,()=>{c.moveTo(0,0);c.quadraticCurveTo(-14,-30,-36,-30+6*sin(T*t-4));c.quadraticCurveTo(-26,-6,-30,0);c.quadraticCurveTo(-26,6,-36,30+6*sin(T*t-4));c.quadraticCurveTo(-14,30,0,0)})
|
||||
c.restore()
|
||||
for(const d of[-1,1]){const[x,y]=at(.3,d*hw(.3)*.8);c.save();c.translate(x,y);c.rotate(ang(.3)+PI+d*(.7+.3*sin(T*t*2+d)))
|
||||
fill(L,()=>c.ellipse(14,0,18,8,0,0,T));c.restore()}
|
||||
// dragon whiskers: flow from the snout out and back along the body, rippling
|
||||
const[hx,hy]=P[0],fx=P[0][0]-P[4][0],fy=P[0][1]-P[4][1],fl=hypot(fx,fy),ux=fx/fl,uy=fy/fl
|
||||
c.strokeStyle=A;c.lineCap='round';c.lineWidth=4
|
||||
for(const d of[-1,1]){c.beginPath();for(let k=0;k<=16;k++){const q=k/16,al=2-80*q,la=d*(13+30*q**.6+8*q*sin(T*t*2-q*5+d))
|
||||
c.lineTo(hx+ux*al-uy*la,hy+uy*al+ux*la)}c.stroke()}
|
||||
fill(B,()=>{for(let j=0;j<=N;j++){const[x,y]=at(j/N,hw(j/N));c.lineTo(x,y)}for(let j=N;j>=0;j--){const[x,y]=at(j/N,-hw(j/N));c.lineTo(x,y)}c.closePath()})
|
||||
for(const[s,rx,ry]of[[.46,17,11],[.68,10,7]]){const[x,y]=at(s);c.save();c.translate(x,y);c.rotate(ang(s));fill(L,()=>c.ellipse(0,0,rx,ry,0,0,T));c.restore()}
|
||||
c.strokeStyle=A;c.lineWidth=7
|
||||
for(const d of[-1,1]){const[x,y]=at(.13,d*12),[x2,y2]=at(.25,d*38);c.beginPath();c.moveTo(x,y);c.lineTo(x2,y2);c.stroke()}
|
||||
c.fillStyle=D;for(const d of[-1,1]){const[x,y]=at(.06,d*hw(.06)*.72);c.beginPath();c.arc(x,y,4.5,0,T);c.fill()}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// lemon-duck floating: a lemon-shaped duck bobbing and rocking over two ripples, the leaf on its head twitching
|
||||
const{sin,cos,PI}=Math,T=2*PI
|
||||
export const frames=24,delay=85
|
||||
const B='#f4c03e',L='#f9e09e',O='#ff9f43',G='#8cc084',W='#4ea8de',D='#2b2633'
|
||||
export default(c,t)=>{
|
||||
const fill=(col,f)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();f();c.fill();c.stroke()}
|
||||
const bl=t>.6&&t<.66
|
||||
c.save();c.translate(122,150+5*sin(T*t));c.rotate(.05*sin(T*t+1.2));c.translate(-122,-150)
|
||||
c.save();c.translate(166,74);c.rotate(.25*sin(T*t*2));fill(G,()=>c.ellipse(13,-6,15,7,-.4,0,T))
|
||||
c.lineWidth=5;c.lineCap='round';c.beginPath();c.moveTo(0,4);c.lineTo(2,-4);c.stroke();c.restore()
|
||||
fill(B,()=>{c.moveTo(60,134);c.lineTo(34,124);c.lineTo(56,158)})
|
||||
fill(B,()=>c.ellipse(122,152,72,42,0,0,T))
|
||||
fill(B,()=>c.arc(166,106,33,0,T))
|
||||
// wing is a lemon slice: pale half-wheel with segment lines
|
||||
c.save();c.translate(112,140);c.rotate(-.12+.1*sin(T*t*2));fill(L,()=>{c.arc(0,0,27,0,PI);c.closePath()})
|
||||
c.strokeStyle=B;c.lineWidth=4;c.lineCap='round';c.beginPath();c.arc(0,0,19,.04*PI,.96*PI);c.stroke()
|
||||
for(const a of[.25,.5,.75])c.beginPath(),c.moveTo(0,2),c.lineTo(19*cos(a*PI),19*sin(a*PI)),c.stroke()
|
||||
c.restore()
|
||||
fill(O,()=>c.ellipse(199,114,15,8,.12,0,T))
|
||||
c.fillStyle=c.strokeStyle=D
|
||||
if(bl)c.lineWidth=4,c.beginPath(),c.arc(174,98,6,.15*PI,.85*PI),c.stroke()
|
||||
else c.beginPath(),c.arc(174,100,5.5,0,T),c.fill()
|
||||
c.restore()
|
||||
c.strokeStyle=W;c.lineWidth=5;c.lineCap='round'
|
||||
for(const[x0,x1,y,k]of[[44,204,198,0],[84,170,212,2]]){
|
||||
c.beginPath();for(let x=x0;x<=x1;x+=4)c.lineTo(x,y+3*sin(x/10-T*t+k));c.stroke()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// ring-tailed lemur sitting with big amber eyes, its long striped tail curling and uncurling over its head, blinks
|
||||
const{sin,cos,PI}=Math,T=2*PI
|
||||
export const frames=24,delay=85
|
||||
const B='#8a94a6',L='#e2e6ed',A='#3d4352',Y='#f4c03e',D='#2b2633'
|
||||
export default(c,t)=>{
|
||||
const s=sin(T*t),bl=t>.62&&t<.68
|
||||
const fill=(col,f)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();f();c.fill();c.stroke()}
|
||||
let x=140,y=200,a=0;const K=3.7+.55*s,n=40,Ls=215,pts=[[x,y]]
|
||||
for(let i=1;i<=n;i++){const u=i/n;a=-.3+.08*s-K*u**1.6;x+=Ls/n*cos(a);y+=Ls/n*sin(a);pts.push([x,y])}
|
||||
const tail=()=>{c.moveTo(...pts[0]);for(const p of pts)c.lineTo(...p)}
|
||||
c.strokeStyle=L;c.lineWidth=20;c.beginPath();tail();c.stroke()
|
||||
c.lineCap='butt';c.setLineDash([12,12]);c.lineDashOffset=-14;c.strokeStyle=A;c.beginPath();tail();c.stroke();c.setLineDash([]);c.lineCap='round'
|
||||
for(const d of[-1,1])fill(B,()=>c.ellipse(108+d*16,212,14,7,0,0,T))
|
||||
fill(B,()=>c.ellipse(108,170,36,42,0,0,T))
|
||||
fill(L,()=>c.ellipse(108,178,20,28,0,0,T))
|
||||
for(const d of[-1,1])fill(B,()=>c.ellipse(108+d*20,190,8,14,-d*.3,0,T))
|
||||
for(const d of[-1,1])fill(B,()=>{c.moveTo(108+d*14,80);c.lineTo(108+d*32,52);c.lineTo(108+d*36,84);c.closePath()})
|
||||
fill(B,()=>c.arc(108,100,30,0,T))
|
||||
fill(L,()=>{c.moveTo(80,98);c.quadraticCurveTo(108,82,136,98);c.quadraticCurveTo(128,128,108,142);c.quadraticCurveTo(88,128,80,98)})
|
||||
fill(A,()=>c.ellipse(108,140,6,5,0,0,T))
|
||||
for(const d of[-1,1]){
|
||||
fill(A,()=>{c.moveTo(108+d*4,94);c.quadraticCurveTo(108+d*22,82,108+d*24,104);c.quadraticCurveTo(108+d*14,114,108+d*6,108);c.closePath()})
|
||||
if(bl)c.strokeStyle=Y,c.lineWidth=3.5,c.beginPath(),c.arc(108+d*14,98,6,.15*PI,.85*PI),c.stroke()
|
||||
else fill(Y,()=>c.arc(108+d*14,100,5.5,0,T)),c.fillStyle=D,c.beginPath(),c.arc(108+d*14,100,3,0,T),c.fill()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// fluffy llama standing side-on in a little blanket, chewing away, one ear twitches, blinks
|
||||
const{sin,cos,PI}=Math,T=2*PI
|
||||
export const frames=24,delay=80
|
||||
const B='#d6a77a',L='#efd5bd',A='#2ec4b6',D='#2b2633'
|
||||
export default(c,t)=>{
|
||||
const j=sin(T*t*4),s=sin(T*t),tw=t>.46&&t<.56?-.45:0,bl=t>.8&&t<.86,hy=1.5*s
|
||||
const fill=(col,f)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();f();c.fill();c.stroke()}
|
||||
const line=(col,lw,f)=>{c.strokeStyle=col;c.lineWidth=lw;c.beginPath();f();c.stroke()}
|
||||
for(const[x,o]of[[76,4],[94,0],[132,4],[150,0]])line(B,14,()=>{c.moveTo(x,160);c.lineTo(x+o*.5,222)})
|
||||
fill(B,()=>c.arc(48,134,12,0,T))
|
||||
fill(B,()=>c.ellipse(108,150,58,30,0,0,T))
|
||||
for(let x=62;x<=156;x+=16)fill(B,()=>c.arc(x,126+(x%32?2:0),13,0,T))
|
||||
for(let y=164;y<=178;y+=14)fill(B,()=>c.arc(56+(y-164)*.4,y,11,0,T))
|
||||
line(B,30,()=>{c.moveTo(150,140);c.lineTo(166,72+hy)})
|
||||
for(let y=86;y<=130;y+=15)fill(B,()=>c.arc(178-(y-86)*.25,y+hy*(130-y)/44,10,0,T))
|
||||
fill(A,()=>c.roundRect(84,114,50,34,8))
|
||||
for(const[x,r]of[[166,-.35+tw],[180,.05]])fill(B,()=>c.ellipse(x,34+hy,6,16,r,0,T))
|
||||
fill(B,()=>c.ellipse(180,64+hy,24,17,0,0,T))
|
||||
fill(B,()=>c.ellipse(200,72+hy,15,11,0,0,T))
|
||||
fill(L,()=>c.ellipse(199+2*cos(T*t*4),80+hy+1.5*j,12,6,0,0,T))
|
||||
fill(L,()=>{c.arc(170,50+hy,9,0,T);c.arc(182,46+hy,9,0,T)})
|
||||
c.fillStyle=c.strokeStyle=D
|
||||
if(bl)c.lineWidth=3.5,c.beginPath(),c.arc(186,60+hy,4.5,.15*PI,.85*PI),c.stroke()
|
||||
else c.beginPath(),c.arc(186,62+hy,4.5,0,T),c.fill()
|
||||
c.beginPath();c.ellipse(209,68+hy,2.5,3,0,0,T);c.fill()
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
// two lovebirds on a branch leaning in to nuzzle, eyes closing happily, a little heart floats up between them
|
||||
const{sin,PI,max,min}=Math,T=2*PI
|
||||
export const frames=24,delay=85
|
||||
const B='#8cc084',L='#c6e0c1',F='#ff7a5c',W='#c9a27e',D='#2b2633'
|
||||
const bump=(t,a,w)=>{const x=(t-a)/w;return x>0&&x<1?sin(PI*x)**2:0}
|
||||
export default(c,t)=>{
|
||||
const n=bump(t,.1,.36)+bump(t,.56,.36),wig=.05*sin(6*T*t)*n,hp=(t-.22)/.5
|
||||
const fill=(col,f)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();f();c.fill();c.stroke()}
|
||||
c.strokeStyle=W;c.lineWidth=12;c.lineCap='round'
|
||||
c.beginPath();c.moveTo(18,172);c.quadraticCurveTo(128,180,238,168);c.stroke()
|
||||
c.lineWidth=6;c.beginPath();c.moveTo(210,170);c.lineTo(226,152);c.stroke()
|
||||
for(const d of[1,-1]){
|
||||
const x=128-d*56,a=d*(.2*n+wig)+(d>0?.02:-.02)*sin(T*t)
|
||||
c.save();c.translate(x,170);c.scale(d,1);c.rotate(a*d)
|
||||
fill(B,()=>{c.moveTo(-14,-14);c.lineTo(-32,26);c.lineTo(-18,30);c.lineTo(0,-6);c.closePath()})
|
||||
fill(B,()=>c.ellipse(0,-36,30,38,0,0,T))
|
||||
fill(L,()=>c.ellipse(8,-28,18,24,0,0,T))
|
||||
fill(B,()=>c.arc(6,-82,26,0,T))
|
||||
c.save();c.beginPath();c.arc(6,-82,29,0,T);c.clip();fill(F,()=>c.ellipse(28,-84,30,30,0,0,T));c.restore()
|
||||
fill(W,()=>{c.moveTo(28,-90);c.quadraticCurveTo(44,-86,40,-74);c.lineTo(28,-76);c.closePath()})
|
||||
c.fillStyle=c.strokeStyle=D
|
||||
if(n>.5)c.lineWidth=3.5,c.beginPath(),c.arc(16,-90,5,1.15*PI,1.85*PI),c.stroke()
|
||||
else c.beginPath(),c.arc(16,-88,5,0,T),c.fill()
|
||||
c.restore()
|
||||
}
|
||||
for(const k of[0,1]){
|
||||
const q=hp-k*.46;if(q<0||q>.5)continue
|
||||
const z=min(1,6*min(q,.5-q)),y=72-60*q
|
||||
c.save();c.translate(128,y);c.scale(z,z);c.fillStyle=c.strokeStyle=F;c.lineWidth=4
|
||||
c.beginPath();c.moveTo(0,8);c.bezierCurveTo(-16,-4,-8,-16,0,-7);c.bezierCurveTo(8,-16,16,-4,0,8);c.fill();c.stroke();c.restore()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// macaw standing tall: long red tail, spreads blue-and-yellow wings and flaps twice, head bobbing
|
||||
const{sin,cos,PI,max}=Math,T=2*PI
|
||||
export const frames=24,delay=80
|
||||
const B='#ee5a5a',L='#f6adad',S='#4ea8de',Y='#f4c03e',D='#2b2633'
|
||||
export default(c,t)=>{
|
||||
const u=(t-.18)/.6,on=u>0&&u<1,env=on?sin(PI*u)**.6:0,a=.14+env*(1.35+.45*sin(4*T*u)),hb=.08*sin(T*t*2),bl=t>.86&&t<.92
|
||||
const fill=(col,f)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();f();c.fill();c.stroke()}
|
||||
fill(B,()=>{c.moveTo(118,170);c.lineTo(138,170);c.lineTo(134,240);c.lineTo(122,240);c.closePath()})
|
||||
fill(S,()=>{c.moveTo(124,214);c.lineTo(132,214);c.lineTo(134,240);c.lineTo(122,240);c.closePath()})
|
||||
for(const d of[-1,1])fill(L,()=>c.ellipse(128+d*13,186,10,6,0,0,T))
|
||||
fill(B,()=>c.ellipse(128,134,34,52,0,0,T))
|
||||
for(const d of[-1,1]){
|
||||
c.save();c.translate(128+d*26,104);c.rotate(-d*a)
|
||||
fill(S,()=>c.ellipse(0,40,19,42,0,0,T))
|
||||
fill(Y,()=>c.ellipse(0,18,17,10,0,0,T))
|
||||
fill(B,()=>c.ellipse(0,4,15,10,0,0,T))
|
||||
c.restore()
|
||||
}
|
||||
c.save();c.translate(128,96);c.rotate(hb)
|
||||
fill(B,()=>c.arc(0,-24,30,0,T))
|
||||
for(const d of[-1,1])fill(L,()=>c.ellipse(d*14,-24,11,13,0,0,T))
|
||||
c.fillStyle=c.strokeStyle=D
|
||||
for(const d of[-1,1])if(bl)c.lineWidth=3.5,c.beginPath(),c.arc(d*14,-27,4.5,.15*PI,.85*PI),c.stroke()
|
||||
else c.beginPath(),c.arc(d*14,-25,4.5,0,T),c.fill()
|
||||
fill(L,()=>{c.moveTo(-9,-14);c.quadraticCurveTo(0,-22,9,-14);c.quadraticCurveTo(8,0,0,6);c.quadraticCurveTo(-8,0,-9,-14)})
|
||||
c.restore()
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// moon-cat sleeping: a crescent moon curled like a cat, rocking and breathing, its tail swaying and z's floating up
|
||||
const{sin,cos,PI,atan2,sqrt,hypot}=Math,T=2*PI
|
||||
export const frames=24,delay=90
|
||||
const B='#f4c03e',L='#f9e09e',A='#b48cff',D='#2b2633'
|
||||
export default(c,t)=>{
|
||||
const fill=(col,f)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();f();c.fill();c.stroke()}
|
||||
// crescent: outer circle minus inner circle, horns pointing up
|
||||
const[x1,y1,R,x2,y2,r]=[128,100,84,136,60,80],d=hypot(x2-x1,y2-y1),a=(R*R-r*r+d*d)/(2*d),h=sqrt(R*R-a*a)
|
||||
const ux=(x2-x1)/d,uy=(y2-y1)/d,px=x1+a*ux,py=y1+a*uy,I=[[px+h*uy,py-h*ux],[px-h*uy,py+h*ux]].sort((p,q)=>p[0]-q[0])
|
||||
const[l,rr]=I
|
||||
c.translate(0,22);c.translate(128,120);c.rotate(.07*sin(T*t));c.scale(1+.02*sin(T*t*2),1+.02*sin(T*t*2));c.translate(-128,-120)
|
||||
for(let k=0;k<3;k++){const q=(t+k/3)%1,s=8*sin(PI*q),x=88+26*q+6*sin(T*q),y=34-40*q
|
||||
if(s<3)continue
|
||||
c.strokeStyle=A;c.lineWidth=4.5;c.lineCap=c.lineJoin='round';c.beginPath();c.moveTo(x-s,y-s);c.lineTo(x+s,y-s);c.lineTo(x-s,y+s);c.lineTo(x+s,y+s);c.stroke()}
|
||||
c.strokeStyle=B;c.lineWidth=13;c.lineCap='round';c.beginPath();c.moveTo(rr[0]-4,rr[1]+4)
|
||||
c.bezierCurveTo(rr[0]+14,rr[1]-10,rr[0]+22,rr[1]-26,rr[0]+12+6*sin(T*t-1),rr[1]-44+3*cos(T*t-1));c.stroke()
|
||||
for(const[x,rt]of[[50,-.5],[76,.25]]){c.save();c.translate(x,64);c.rotate(rt);fill(B,()=>{c.moveTo(-12,8);c.lineTo(0,-20);c.lineTo(12,8)})
|
||||
fill(L,()=>{c.moveTo(-5,5);c.lineTo(0,-8);c.lineTo(5,5)});c.restore()}
|
||||
fill(B,()=>{c.arc(x1,y1,R,atan2(l[1]-y1,l[0]-x1),atan2(rr[1]-y1,rr[0]-x1),true);c.arc(x2,y2,r,atan2(rr[1]-y2,rr[0]-x2),atan2(l[1]-y2,l[0]-x2),false);c.closePath()})
|
||||
fill(B,()=>c.arc(64,86,28,0,T))
|
||||
c.fillStyle=L;for(const[x,y,s]of[[128,166,8],[96,158,6],[162,160,5.5]])c.beginPath(),c.arc(x,y,s,0,T),c.fill()
|
||||
c.strokeStyle=D;c.lineWidth=4;c.lineCap='round'
|
||||
for(const x of[54,76])c.beginPath(),c.arc(x,84,6,.15*PI,.85*PI),c.stroke()
|
||||
c.lineWidth=3.5;for(const d of[-1,1])c.beginPath(),c.arc(65+d*4,97,4,.1*PI,.9*PI),c.stroke()
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// moose facing you with big flat antlers, slowly nodding, an ear flick and a blink
|
||||
const{sin,cos,PI}=Math,T=2*PI
|
||||
export const frames=24,delay=90
|
||||
const B='#b07d55',L='#d9b38c',A='#ecd3a5',D='#2b2633'
|
||||
export default(c,t)=>{
|
||||
const n=(1-cos(T*t))/2,fl=t>.6&&t<.66?.4:0,bl=t>.82&&t<.88
|
||||
const fill=(col,f)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();f();c.fill();c.stroke()}
|
||||
const line=(col,lw,f)=>{c.strokeStyle=col;c.lineWidth=lw;c.beginPath();f();c.stroke()}
|
||||
for(const x of[100,156])line(B,13,()=>{c.moveTo(x,170);c.lineTo(x,218)})
|
||||
fill(B,()=>c.ellipse(128,166,60,34,0,0,T))
|
||||
for(const x of[108,148])line(B,15,()=>{c.moveTo(x,180);c.lineTo(x,222)})
|
||||
c.save();c.translate(128,140);c.scale(1,1-.05*n);c.translate(-128,-140+9*n)
|
||||
for(const d of[-1,1]){
|
||||
c.save();c.translate(128,0);c.scale(d,1);c.translate(-128,0)
|
||||
line(A,11,()=>{c.moveTo(146,88);c.quadraticCurveTo(160,86,170,78)})
|
||||
fill(A,()=>c.ellipse(190,64,32,17,-.45,0,T))
|
||||
for(const[x,y]of[[170,48],[184,38],[199,32],[214,32],[224,44]])fill(A,()=>c.arc(x,y,6.5,0,T))
|
||||
c.save();c.translate(156,100);c.rotate(.3+(d>0?fl:0))
|
||||
fill(B,()=>c.ellipse(14,0,16,7,0,0,T));c.restore();c.restore()
|
||||
}
|
||||
fill(B,()=>c.ellipse(128,100,26,24,0,0,T))
|
||||
fill(L,()=>c.ellipse(128,142,22,25,0,0,T))
|
||||
c.fillStyle=c.strokeStyle=D
|
||||
for(const d of[-1,1])if(bl)c.lineWidth=4,c.beginPath(),c.arc(128+d*15,96,4.5,.15*PI,.85*PI),c.stroke()
|
||||
else c.beginPath(),c.arc(128+d*15,98,4.5,0,T),c.fill()
|
||||
for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*8,154,3.5,5,d*.3,0,T),c.fill()
|
||||
c.restore()
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// ostrich running in place: long pink legs cycling, fluffy body bouncing, neck bobbing with each stride
|
||||
const{sin,cos,PI,sqrt,max,min,hypot}=Math,T=2*PI
|
||||
export const frames=24,delay=60
|
||||
const B='#b48cff',L='#dac6ff',P='#ff85a8',Q='#ffc2d4',D='#2b2633'
|
||||
export default(c,t)=>{
|
||||
const f=2*T*t,bob=4*cos(2*f),hx=126,hy=136+bob
|
||||
const fill=(col,g)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();g();c.fill();c.stroke()}
|
||||
const leg=(ph,col)=>{
|
||||
const fx=hx+28*cos(ph),fy=224-16*max(0,sin(ph)),dx=fx-hx,dy=fy-hy,d=min(hypot(dx,dy),92),h=sqrt(max(0,46*46-(d/2)**2))
|
||||
const ux=dx/hypot(dx,dy),uy=dy/hypot(dx,dy),kx=hx+ux*d/2-uy*h,ky=hy+uy*d/2+ux*h
|
||||
c.strokeStyle=col;c.lineWidth=9;c.lineCap=c.lineJoin='round'
|
||||
c.beginPath();c.moveTo(hx,hy);c.lineTo(kx,ky);c.lineTo(fx,fy);c.lineTo(fx+14,fy);c.stroke()
|
||||
}
|
||||
leg(f+PI,Q);leg(f,P)
|
||||
c.translate(0,bob)
|
||||
for(const[x,y,r]of[[58,96,16],[50,116,14],[64,124,13]])fill(L,()=>c.arc(x,y,r,0,T))
|
||||
fill(B,()=>{c.ellipse(118,112,54,34,-.08,0,T);for(let x=78;x<=158;x+=16)c.moveTo(x+13,138-(x-118)*.08),c.arc(x,138-(x-118)*.08,13,0,T)})
|
||||
fill(L,()=>c.ellipse(112,108,30,16,-.15,0,T))
|
||||
const nx=176+5*sin(2*f),ny=40
|
||||
c.strokeStyle=P;c.lineWidth=12;c.lineCap='round'
|
||||
c.beginPath();c.moveTo(152,100);c.quadraticCurveTo(170,70,nx,ny+12);c.stroke()
|
||||
fill(P,()=>c.ellipse(nx,ny,15,12,0,0,T))
|
||||
fill(P,()=>{c.moveTo(nx+10,ny-2);c.lineTo(nx+26,ny+3);c.lineTo(nx+10,ny+7);c.closePath()})
|
||||
c.fillStyle=D;c.beginPath();c.arc(nx+3,ny-3,4.5,0,T);c.fill()
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
// pangolin trundling, then curling up into a scaly ball that rocks, then unrolling again
|
||||
const{sin,cos,PI,max,min,atan2}=Math,T=2*PI
|
||||
export const frames=32,delay=70
|
||||
const B='#c9a27e',A='#97734f',D='#2b2633'
|
||||
const cl=x=>max(0,min(1,x)),ease=x=>(x=cl(x),x*x*(3-2*x))
|
||||
const N=56,Ls=208,W=s=>s<.32?6+25*(s/.32)**.6:31-23*(s-.32)/.68
|
||||
export default(c,t)=>{
|
||||
const r=ease((t-.06)/.26)-ease((t-.62)/.26),rock=.22*sin(T*cl((t-.3)/.34))*r
|
||||
const turn=.9+r*(T*1.06-.9),a0=PI+.42+rock+.6*r
|
||||
let x=0,y=0;const P=[[0,0,a0]]
|
||||
for(let i=1;i<=N;i++){const a=a0-turn*i/N;x+=Ls/N*cos(a);y+=Ls/N*sin(a);P.push([x,y,a])}
|
||||
let x0=1e9,x1=-1e9,y1=-1e9
|
||||
P.forEach(([px,py],i)=>{const w=W(i/N);x0=min(x0,px-w);x1=max(x1,px+w);y1=max(y1,py+w)})
|
||||
const ox=128-(x0+x1)/2,oy=(1-r)*(196-y1)+r*(206-y1),wk=(1-r)*sin(T*t*3)
|
||||
c.translate(ox,oy)
|
||||
c.fillStyle=c.strokeStyle=B
|
||||
if(r<.45)for(const[k,f]of[[.3,1],[.66,-1]]){
|
||||
const[px,py]=P[Math.round(k*N)],l=(1-r/.45)*(18+2*f*wk)
|
||||
c.lineWidth=12;c.beginPath();c.moveTo(px,py);c.lineTo(px+f*2*wk,py+W(k)+l-4);c.stroke()
|
||||
}
|
||||
P.forEach(([px,py],i)=>{c.beginPath();c.arc(px,py,W(i/N),0,T);c.fill()})
|
||||
const f=ease((r-.7)/.3);if(f>0){let mx=0,my=0;for(const[px,py]of P)mx+=px/P.length,my+=py/P.length;c.beginPath();c.arc(mx,my,Ls/turn*f,0,T);c.fill()}
|
||||
c.strokeStyle=A;c.lineWidth=3.5
|
||||
for(let s=.13;s<.96;s+=.07)for(const j of[0,1]){
|
||||
const q=s+j*.035,i=Math.round(q*N),[px,py,a]=P[i],w=W(q),dx=cos(a),dy=sin(a),nx=-dy,ny=dx,o=w*(.62-.5*j),rr=w*.42
|
||||
const cx=px+nx*o-dx*rr*.3,cy=py+ny*o-dy*rr*.3
|
||||
c.beginPath();c.arc(cx,cy,rr,a-1.25,a+1.25);c.stroke()
|
||||
}
|
||||
if(r<.6){const[px,py,a]=P[Math.round(.07*N)];c.fillStyle=D;c.beginPath();c.arc(px-sin(a)*3,py+cos(a)*3-4,3.5,0,T);c.fill()}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
// pegasus flying in place: two slow wing beats per loop, legs tucked, mane and tail streaming, blinks
|
||||
const{sin,PI}=Math,T=2*PI
|
||||
export const frames=24,delay=80
|
||||
const B='#4ea8de',L='#a7d4ef',A='#ff85a8',D='#2b2633'
|
||||
export default(c,t)=>{
|
||||
const f=sin(2*T*t),w=-.52+.66*f,bl=t>.7&&t<.76
|
||||
const fill=(col,g)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();g();c.fill();c.stroke()}
|
||||
const line=(col,lw,g)=>{c.strokeStyle=col;c.lineWidth=lw;c.beginPath();g();c.stroke()}
|
||||
const wing=(x,y,r,col)=>{c.save();c.translate(x,y);c.rotate(r);c.scale(.82,.82);fill(col,()=>{
|
||||
c.moveTo(14,4);c.quadraticCurveTo(24,-46,-12,-86);c.quadraticCurveTo(-30,-80,-30,-64)
|
||||
c.quadraticCurveTo(-44,-56,-38,-40);c.quadraticCurveTo(-46,-26,-34,-14);c.quadraticCurveTo(-30,4,-14,4)});c.restore()}
|
||||
c.translate(8,-7*sin(2*T*t+1.2))
|
||||
wing(116,110,w-.14,B)
|
||||
// tail: a tube along a curve that ripples, fuller toward the end
|
||||
const ty=152+8*sin(2*T*t-1)
|
||||
for(let s=0;s<=1;s+=.02){const u=1-s,x=u*u*u*76+3*u*u*s*56+3*u*s*s*44+s*s*s*24,y=u*u*u*134+3*u*u*s*(124+5*f)+3*u*s*s*(150-6*f)+s*s*s*ty
|
||||
c.fillStyle=A;c.beginPath();c.arc(x,y,5+5*sin(PI*s*.8),0,T);c.fill()}
|
||||
for(const[x,k]of[[138,0],[156,1]])line(B,11,()=>{c.moveTo(x,150);c.quadraticCurveTo(x+16+6*k,166+3*f,x+4+8*k,186+2*f-6*k)})
|
||||
for(const x of[84,94])line(B,11,()=>{c.moveTo(x,150);c.quadraticCurveTo(x-10,172,x-26,178-3*f)})
|
||||
// mane scallops peek out along the back of the neck
|
||||
for(let i=0;i<5;i++){const s=.15+.22*i,o=14+3*sin(2*T*t-i*.9);fill(A,()=>c.arc(146+30*s-.81*o,138-42*s-.58*o,9,0,T))}
|
||||
line(B,32,()=>{c.moveTo(146,138);c.lineTo(176,96)})
|
||||
fill(B,()=>c.ellipse(118,140,50,27,0,0,T))
|
||||
fill(B,()=>c.ellipse(190,98,24,15,.55,0,T))
|
||||
fill(B,()=>{c.moveTo(174,86);c.lineTo(178,62);c.lineTo(188,82)})
|
||||
wing(126,114,w,L)
|
||||
c.fillStyle=c.strokeStyle=D
|
||||
if(bl)c.lineWidth=3.5,c.beginPath(),c.arc(187,90,5,.15*PI,.85*PI),c.stroke()
|
||||
else c.beginPath(),c.arc(187,92,4.5,0,T),c.fill()
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// pelican scooping: dips its long bill, comes up with a full pouch, tips back and gulps (a lump slides down the neck)
|
||||
const{sin,PI,max,min}=Math,T=2*PI
|
||||
export const frames=24,delay=85
|
||||
const B='#7b8cff',L='#c3cbff',Y='#f4c03e',D='#2b2633'
|
||||
const sm=x=>x<=0?0:x>=1?1:x*x*(3-2*x)
|
||||
export default(c,t)=>{
|
||||
const dip=sm(t/.18)-sm((t-.24)/.16),up=sm((t-.42)/.1)-sm((t-.66)/.14),r=.55*dip-.3*up
|
||||
const p=sm((t-.2)/.1)*(1-sm((t-.5)/.12)),lump=(t-.5)/.22,bl=t>.84&&t<.9
|
||||
const fill=(col,f)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();f();c.fill();c.stroke()}
|
||||
for(const x of[92,114])fill(Y,()=>{c.moveTo(x,196);c.lineTo(x+2,222);c.lineTo(x+14,224)})
|
||||
fill(B,()=>{c.moveTo(56,150);c.lineTo(28,140);c.lineTo(40,166);c.closePath()})
|
||||
// neck goes behind the body, head and bill on top
|
||||
const head=()=>{c.translate(124,138);c.rotate(r)}
|
||||
c.save();head();c.strokeStyle=B;c.lineWidth=28;c.lineCap='round'
|
||||
c.beginPath();c.moveTo(-6,28);c.quadraticCurveTo(-10,-24,20,-62);c.stroke();c.restore()
|
||||
fill(B,()=>c.ellipse(100,164,60,44,-.05,0,T))
|
||||
fill(L,()=>c.ellipse(92,156,40,22,-.12,0,T))
|
||||
c.save();head()
|
||||
if(lump>0&&lump<1){const q=1-lump;fill(B,()=>c.arc(-4+24*q*q,-6-52*q,19,0,T))}
|
||||
fill(B,()=>c.arc(22,-66,22,0,T))
|
||||
fill(Y,()=>{c.moveTo(38,-74);c.lineTo(100,-56);c.quadraticCurveTo(108,-52,102,-46);c.lineTo(38,-60);c.closePath()})
|
||||
fill(Y,()=>{c.moveTo(40,-58);c.lineTo(98,-46);c.quadraticCurveTo(76,-40+46*p,42,-40+12*p);c.closePath()})
|
||||
c.fillStyle=c.strokeStyle=D
|
||||
if(bl)c.lineWidth=3.5,c.beginPath(),c.arc(26,-72,4.5,.15*PI,.85*PI),c.stroke()
|
||||
else c.beginPath(),c.arc(26,-70,4.5,0,T),c.fill()
|
||||
c.restore()
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// platypus swimming along: duck bill, flat beaver tail beating up and down, webbed feet paddling in turn
|
||||
const{sin,cos,PI}=Math,T=2*PI
|
||||
export const frames=24,delay=80
|
||||
const B='#b5835a',L='#dcc0a6',A='#8a94a6',D='#2b2633'
|
||||
export default(c,t)=>{
|
||||
const s=sin(T*t),bl=t>.55&&t<.62,fill=(col,f)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();f();c.fill();c.stroke()}
|
||||
c.translate(128,124+5*s);c.rotate(.04*sin(T*t+1));c.translate(-124,-128)
|
||||
for(const[x,ph]of[[92,0],[150,PI]]){c.save();c.translate(x,150);c.rotate(.5*sin(T*t*2+ph))
|
||||
fill(A,()=>{c.moveTo(-4,0);c.lineTo(-14,26);c.quadraticCurveTo(0,34,14,26);c.lineTo(4,0)});c.restore()}
|
||||
c.save();c.translate(66,130);c.rotate(.25*sin(T*t*2-1));fill(B,()=>c.ellipse(-22,0,26,14,0,0,T));c.restore()
|
||||
fill(B,()=>c.ellipse(122,128,64,34,0,0,T))
|
||||
fill(L,()=>c.ellipse(126,150,40,9,0,0,T))
|
||||
fill(A,()=>c.ellipse(204,134,26,11,.08,0,T))
|
||||
c.fillStyle=c.strokeStyle=D;c.beginPath();c.arc(218,129,2,0,T);c.fill()
|
||||
if(bl)c.lineWidth=3.5,c.beginPath(),c.arc(174,114,5,.15*PI,.85*PI),c.stroke()
|
||||
else c.beginPath(),c.arc(174,116,5,0,T),c.fill()
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// round quokka doing a small happy hop on its long feet, then beaming with its big smile and squinting
|
||||
const{sin,cos,PI,max,min}=Math,T=2*PI
|
||||
export const frames=24,delay=80
|
||||
const B='#b88a64',L='#ddc3ab',P='#ff85a8',D='#2b2633'
|
||||
export default(c,t)=>{
|
||||
const h=t<.32?20*sin(PI*t/.32):0,sq=t>.32&&t<.46?.08*sin(PI*(t-.32)/.14):0,g=max(0,min(1,(t-.42)/.12))*max(0,min(1,(.96-t)/.12))
|
||||
const y=-h
|
||||
const fill=(col,f)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();f();c.fill();c.stroke()}
|
||||
c.translate(128,214);c.scale(1+sq,1-sq);c.translate(-128,-214)
|
||||
c.strokeStyle=B;c.lineWidth=15;c.beginPath();c.moveTo(150,196+y);c.quadraticCurveTo(178,204,196,212+y*.6);c.stroke()
|
||||
for(const d of[-1,1])fill(B,()=>c.ellipse(128+d*22,211+y*.7,21,7,0,0,T))
|
||||
fill(B,()=>{c.moveTo(128,120+y);c.bezierCurveTo(166,120+y,178,170+y,172,190+y);c.bezierCurveTo(166,210+y,90,210+y,84,190+y);c.bezierCurveTo(78,170+y,90,120+y,128,120+y)})
|
||||
fill(L,()=>c.ellipse(128,180+y,26,26,0,0,T))
|
||||
for(const d of[-1,1])fill(B,()=>c.ellipse(128+d*11,144+y,6,10,d*.4,0,T))
|
||||
for(const d of[-1,1])fill(B,()=>c.arc(128+d*33,76+y,10,0,T)),fill(L,()=>c.arc(128+d*33,76+y,4.5,0,T))
|
||||
fill(B,()=>{c.moveTo(128,62+y);c.bezierCurveTo(158,62+y,170,82+y,168,98+y);c.bezierCurveTo(166,114+y,140,128+y,128,128+y);c.bezierCurveTo(116,128+y,90,114+y,88,98+y);c.bezierCurveTo(86,82+y,98,62+y,128,62+y)})
|
||||
c.fillStyle=c.strokeStyle=D
|
||||
for(const d of[-1,1])if(g>.5)c.lineWidth=4,c.beginPath(),c.arc(128+d*18,95+y,5,1.15*PI,1.85*PI),c.stroke()
|
||||
else c.beginPath(),c.arc(128+d*18,91+y,4.5,0,T),c.fill()
|
||||
c.beginPath();c.ellipse(128,104+y,6.5,4.5,0,0,T);c.fill()
|
||||
const w=8+5*g,m=3+4*g
|
||||
c.beginPath();c.moveTo(128-w,113+y);c.quadraticCurveTo(128,113+y+m*2,128+w,113+y);c.quadraticCurveTo(128,115+y,128-w,113+y);c.fill()
|
||||
c.lineWidth=3;c.beginPath();c.moveTo(128-w,113+y);c.lineTo(128-w-3,110+y);c.moveTo(128+w,113+y);c.lineTo(128+w+3,110+y);c.stroke()
|
||||
if(g>.3)c.fillStyle=P,c.beginPath(),c.ellipse(128,114+y+m,4*g,2.5*g,0,0,T),c.fill()
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// red panda sitting up and waving a paw, ringed tail swishing behind it, blinks
|
||||
const{sin,cos,PI}=Math,T=2*PI
|
||||
export const frames=24,delay=80
|
||||
const B='#ff7a5c',L='#ffc4b5',A='#b84a32',D='#2b2633'
|
||||
export default(c,t)=>{
|
||||
const s=sin(T*t),w=sin(T*t*2),y=1.5*s,bl=t>.7&&t<.76,tx=204+10*s
|
||||
const fill=(col,f)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();f();c.fill();c.stroke()}
|
||||
const line=(col,lw,f)=>{c.strokeStyle=col;c.lineWidth=lw;c.beginPath();f();c.stroke()}
|
||||
const tail=()=>{c.moveTo(150,198);c.bezierCurveTo(208,204,226,168,tx,124)}
|
||||
line(B,30,tail)
|
||||
c.lineCap='butt';c.setLineDash([11,13]);c.lineDashOffset=-8;line(A,30,tail);c.setLineDash([]);c.lineCap='round'
|
||||
for(const d of[-1,1])fill(A,()=>c.ellipse(128+d*18,212,15,9,0,0,T))
|
||||
fill(B,()=>c.ellipse(128,166+y,44,46,0,0,T))
|
||||
fill(A,()=>c.ellipse(128,176+y,26,30,0,0,T))
|
||||
line(A,17,()=>{c.moveTo(150,150+y);c.quadraticCurveTo(158,172,142,184+y)})
|
||||
const a=-2.15+.38*w,hx=102+46*cos(a),hy=150+y+46*sin(a)
|
||||
line(A,17,()=>{c.moveTo(104,152+y);c.lineTo(hx,hy)});fill(A,()=>c.arc(hx,hy,9,0,T))
|
||||
for(const d of[-1,1]){
|
||||
c.save();c.translate(128+d*34,70+y);c.rotate(d*.35)
|
||||
fill(B,()=>{c.moveTo(-16,12);c.quadraticCurveTo(-14,-18,0,-20);c.quadraticCurveTo(14,-18,16,12);c.closePath()})
|
||||
fill(L,()=>{c.moveTo(-8,8);c.quadraticCurveTo(-6,-10,0,-11);c.quadraticCurveTo(6,-10,8,8);c.closePath()});c.restore()
|
||||
}
|
||||
fill(B,()=>c.ellipse(128,100+y,50,40,0,0,T))
|
||||
fill(L,()=>c.ellipse(128,118+y,22,15,0,0,T))
|
||||
for(const d of[-1,1])fill(L,()=>c.ellipse(128+d*20,80+y,8,5,d*.2,0,T))
|
||||
c.fillStyle=c.strokeStyle=D
|
||||
for(const d of[-1,1])if(bl)c.lineWidth=4,c.beginPath(),c.arc(128+d*20,93+y,5.5,.15*PI,.85*PI),c.stroke()
|
||||
else c.beginPath(),c.arc(128+d*20,96+y,5.5,0,T),c.fill()
|
||||
c.beginPath();c.ellipse(128,112+y,5,3.5,0,0,T);c.fill()
|
||||
c.lineWidth=3;c.beginPath();c.moveTo(121,120+y);c.quadraticCurveTo(124.5,124+y,128,120+y);c.quadraticCurveTo(131.5,124+y,135,120+y);c.stroke()
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// robin singing: red breast puffs out, head tips up, beak chirps three times and little notes float off
|
||||
const{sin,PI,abs,max,min}=Math,T=2*PI
|
||||
export const frames=24,delay=80
|
||||
const B='#c9a27e',R='#ff7a5c',Y='#f4c03e',D='#2b2633'
|
||||
export default(c,t)=>{
|
||||
const u=(t-.05)/.6,on=u>0&&u<1,e=on?sin(PI*u):0,op=on?.32*abs(sin(3*PI*u)):0,bl=t>.8&&t<.86
|
||||
const fill=(col,f)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();f();c.fill();c.stroke()}
|
||||
c.translate(0,3*sin(T*t))
|
||||
c.strokeStyle=B;c.lineWidth=5
|
||||
for(const[x,y]of[[112,196],[136,196]])c.beginPath(),c.moveTo(x,y),c.lineTo(x-2,224),c.moveTo(x-12,226),c.lineTo(x+8,226),c.stroke()
|
||||
fill(B,()=>{c.moveTo(74,150);c.lineTo(24,120);c.lineTo(32,102);c.lineTo(86,128);c.closePath()})
|
||||
c.save();c.translate(150,130);c.rotate(-.18*e);c.translate(-150,-130)
|
||||
const body=()=>{c.moveTo(184,150);c.ellipse(122,150,62*(1+.05*e),52,0,0,T);c.moveTo(206,104);c.arc(170,104,36,0,T)}
|
||||
fill(B,body)
|
||||
c.save();c.beginPath();body();c.clip();c.fillStyle=R;c.beginPath();c.ellipse(170,146,40*(1+.15*e),48*(1+.1*e),0,0,T);c.fill();c.restore()
|
||||
c.fillStyle=c.strokeStyle=D
|
||||
if(bl)c.lineWidth=4,c.beginPath(),c.arc(180,94,5,.15*PI,.85*PI),c.stroke()
|
||||
else c.beginPath(),c.arc(180,96,5,0,T),c.fill()
|
||||
for(const d of[-1,1]){
|
||||
c.save();c.translate(202,104);c.rotate(d*op);c.fillStyle=c.strokeStyle=Y;c.beginPath()
|
||||
c.moveTo(0,0);c.lineTo(0,d*6);c.lineTo(22,d*1.5);c.closePath();c.lineWidth=3;c.fill();c.stroke();c.restore()
|
||||
}
|
||||
c.restore()
|
||||
for(const k of[0,1]){
|
||||
const q=(t-.12-k*.22)/.4;if(q<0||q>1)continue
|
||||
const x=214-10*q+k*8,y=78-56*q,z=min(1,4*min(q,1-q))
|
||||
c.save();c.translate(x,y);c.scale(z,z);c.fillStyle=c.strokeStyle=R;c.lineWidth=3
|
||||
c.beginPath();c.ellipse(0,0,6,4.5,-.4,0,T);c.fill()
|
||||
c.beginPath();c.moveTo(5,-2);c.lineTo(5,-20);c.quadraticCurveTo(12,-16,13,-10);c.stroke();c.restore()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// rooster crowing: puffs its chest out, throws its head back and opens its beak, tail feathers swaying
|
||||
const{sin,cos,PI}=Math,T=2*PI
|
||||
export const frames=24,delay=85
|
||||
const B='#ff9f43',L='#ffcfa1',R='#ee5a5a',G='#2ec4b6',Y='#f4c03e',D='#2b2633'
|
||||
const bump=(t,a,w)=>{const x=(t-a)/w;return x>0&&x<1?sin(PI*x)**2:0}
|
||||
export default(c,t)=>{
|
||||
const e=bump(t,.2,.56),op=.42*bump(t,.3,.36),sw=.06*sin(T*t),bl=t>.86&&t<.92
|
||||
const fill=(col,f)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();f();c.fill();c.stroke()}
|
||||
c.strokeStyle=Y;c.lineWidth=6;c.lineCap='round'
|
||||
for(const x of[104,128])c.beginPath(),c.moveTo(x,190),c.lineTo(x-2,224),c.moveTo(x-14,226),c.lineTo(x+10,226),c.stroke()
|
||||
c.save();c.translate(70,140);c.rotate(sw-.1*e)
|
||||
c.strokeStyle=G;c.lineCap='round'
|
||||
for(const[w,a,b,x,y]of[[14,-20,-90,-48,-30],[12,-34,-70,-56,-6],[11,-40,-40,-50,14]])c.lineWidth=w,c.beginPath(),c.moveTo(0,0),c.quadraticCurveTo(a,b,x,y),c.stroke()
|
||||
c.restore()
|
||||
fill(B,()=>c.ellipse(108,152,58,44,.1,0,T))
|
||||
fill(B,()=>c.arc(150+6*e,144-4*e,36*(1+.14*e),0,T))
|
||||
fill(L,()=>c.ellipse(100,148,38,22,.25-.2*e,0,T))
|
||||
c.save();c.translate(150,140);c.rotate(-.42*e)
|
||||
c.strokeStyle=B;c.lineWidth=40;c.lineCap='round';c.beginPath();c.moveTo(0,0);c.lineTo(14,-46);c.stroke()
|
||||
fill(B,()=>c.arc(18,-56,24,0,T))
|
||||
for(const[x,y]of[[4,-80],[17,-84],[30,-78]])fill(R,()=>c.arc(x,y,9,0,T))
|
||||
fill(R,()=>c.ellipse(38,-30,7,11,0,0,T))
|
||||
for(const d of[-1,1]){c.save();c.translate(38,-54);c.rotate(d*op);fill(Y,()=>{c.moveTo(0,d*7*(d>0)-(d<0)*7);c.lineTo(18,d*2);c.lineTo(0,0);c.closePath()});c.restore()}
|
||||
c.fillStyle=c.strokeStyle=D
|
||||
if(bl)c.lineWidth=3.5,c.beginPath(),c.arc(26,-62,4.5,.15*PI,.85*PI),c.stroke()
|
||||
else c.beginPath(),c.arc(26,-60,4.5,0,T),c.fill()
|
||||
if(op>.15){c.strokeStyle=B;c.lineWidth=4;for(const a of[-.6,-.15,.3])c.beginPath(),c.moveTo(62+10*cos(a),-54+10*sin(a)),c.lineTo(62+24*cos(a),-54+24*sin(a)),c.stroke()}
|
||||
c.restore()
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// fire salamander resting: little flames flicker along its back, tail sways, slow breaths, blinks
|
||||
const{sin,PI,sqrt}=Math,T=2*PI
|
||||
export const frames=24,delay=80
|
||||
const B='#ee5a5a',A='#ff9f43',Y='#f4c03e',D='#2b2633'
|
||||
export default(c,t)=>{
|
||||
const br=1+.03*sin(T*t),bl=t>.62&&t<.68,sw=10*sin(T*t)
|
||||
c.translate(10,-14)
|
||||
const fill=(col,g)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();g();c.fill();c.stroke()}
|
||||
const flame=(x,y,h,s,k)=>fill(k?Y:A,()=>{const w=k?5:10;c.moveTo(x-w,y+4);c.quadraticCurveTo(x-w-2,y-h*.5,x+s,y-h);c.quadraticCurveTo(x+w+2,y-h*.5,x+w,y+4)})
|
||||
for(const[i,x]of[92,112,132,152,170].entries()){
|
||||
const y=152-20*br*sqrt(1-((x-126)/52)**2)+4,h=26+7*sin(2*T*t+i*1.9)+4*sin(3*T*t+i),s=3*sin(2*T*t+i*2.3)
|
||||
flame(x,y,h,s,0);flame(x,y,h*.55,s*.6,1)
|
||||
}
|
||||
// tail: tapering tube from the hips to a tip that curls up and sways
|
||||
for(let s=0;s<=1;s+=.015){const u=1-s,x=u*u*84+2*u*s*44+s*s*20,y=u*u*154+2*u*s*(176+sw*.3)+s*s*(130+sw);c.fillStyle=B;c.beginPath();c.arc(x,y,15-12*s,0,T);c.fill()}
|
||||
for(const[x,d]of[[96,-1],[106,-1],[150,1],[160,1]])fill(B,()=>{c.ellipse(x+d*6,178,6,14,d*.4,0,T)}),fill(B,()=>c.ellipse(x+d*12,190,9,5,0,0,T))
|
||||
fill(B,()=>c.ellipse(126,152,52,20*br,0,0,T))
|
||||
fill(B,()=>c.ellipse(186,146,28,18,-.08,0,T))
|
||||
c.fillStyle=c.strokeStyle=D
|
||||
if(bl)c.lineWidth=3.5,c.beginPath(),c.arc(192,138,5,.15*PI,.85*PI),c.stroke()
|
||||
else c.beginPath(),c.arc(192,140,4.5,0,T),c.fill()
|
||||
c.lineWidth=3;c.beginPath();c.moveTo(212,152);c.quadraticCurveTo(204,156,196,154);c.stroke()
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// sea serpent: its humps roll up out of the water line and back under, tail fin flicks, head bobs
|
||||
const{sin,PI}=Math,T=2*PI
|
||||
export const frames=24,delay=80
|
||||
const B='#2ec4b6',L='#97e2da',W='#4ea8de',D='#2b2633'
|
||||
export default(c,t)=>{
|
||||
const wy=188,hb=4*sin(T*t),bl=t>.3&&t<.36
|
||||
const fill=(col,g)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();g();c.fill();c.stroke()}
|
||||
const dot=(x,y,r)=>{c.fillStyle=B;c.beginPath();c.arc(x,y,r,0,T);c.fill()}
|
||||
c.save();c.beginPath();c.rect(0,0,256,wy);c.clip()
|
||||
// humps: a wave travelling along the body, both ends stay under water
|
||||
for(let x=54;x<=182;x+=1.5)dot(x,wy+16-64*sin(PI*(x-54)/128)**.6*sin(T*(x/104-t)),15)
|
||||
// tail fin flicking up out of the water on the left
|
||||
c.save();c.translate(42,wy+4);c.rotate(-.3+.2*sin(T*t+1));fill(B,()=>{c.moveTo(-8,0);c.quadraticCurveTo(-22,-36,-8,-52);c.quadraticCurveTo(8,-30,10,0)});c.restore()
|
||||
// neck rising from the water, head looking left
|
||||
for(let s=0;s<=1;s+=.02){
|
||||
const u=1-s,x=u*u*u*208+3*u*u*s*222+3*u*s*s*180+s*s*s*194,y=u*u*u*(wy+18)+3*u*u*s*(wy-36)+3*u*s*s*(128+hb)+s*s*s*(104+hb)
|
||||
dot(x,y,16-3*s)
|
||||
}
|
||||
c.restore()
|
||||
for(let i=0;i<3;i++)fill(L,()=>{c.moveTo(204,88+hb+i*10);c.lineTo(234,76+hb+i*14);c.lineTo(208,100+hb+i*10)})
|
||||
fill(B,()=>c.ellipse(186,96+hb,31,21,-.12,0,T))
|
||||
c.fillStyle=c.strokeStyle=D
|
||||
if(bl)c.lineWidth=3.5,c.beginPath(),c.arc(178,87+hb,5.5,.15*PI,.85*PI),c.stroke()
|
||||
else c.beginPath(),c.arc(178,89+hb,5,0,T),c.fill()
|
||||
c.strokeStyle=W;c.lineWidth=8;c.beginPath()
|
||||
for(let x=18;x<=238;x+=2)c.lineTo(x,wy+3.5*sin(T*(x/44-2*t)))
|
||||
c.stroke()
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// sea turtle seen from above, gliding: front flippers sweep together, back flippers steer, head sways
|
||||
const{sin,cos,PI}=Math,T=2*PI
|
||||
export const frames=24,delay=85
|
||||
const B='#2ec4b6',L='#96e1da',A='#8cc084',D='#2b2633'
|
||||
export default(c,t)=>{
|
||||
const s=sin(T*t),fill=(col,f)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();f();c.fill();c.stroke()}
|
||||
c.translate(128,130+4*sin(T*t*2));c.rotate(.08*sin(T*t-.5));c.scale(.94,.94);c.translate(-128,-128)
|
||||
for(const d of[-1,1]){c.save();c.translate(128+d*36,100);c.rotate(d*(-.2+.5*s))
|
||||
fill(A,()=>{c.moveTo(0,-10);c.quadraticCurveTo(d*44,-24,d*76,14);c.quadraticCurveTo(d*38,6,0,12)});c.restore()}
|
||||
for(const d of[-1,1]){c.save();c.translate(128+d*30,176);c.rotate(d*.3*sin(T*t+1));fill(A,()=>c.ellipse(d*14,10,18,9,d*.6,0,T));c.restore()}
|
||||
fill(A,()=>{c.moveTo(122,186);c.lineTo(134,186);c.lineTo(128,204);c.closePath()})
|
||||
c.save();c.translate(128,82);c.rotate(.12*sin(T*t*2-1));fill(A,()=>c.ellipse(0,-16,17,22,0,0,T))
|
||||
c.fillStyle=D;for(const d of[-1,1])c.beginPath(),c.arc(d*10,-20,3.5,0,T),c.fill();c.restore()
|
||||
fill(B,()=>c.ellipse(128,134,52,62,0,0,T))
|
||||
const hex=k=>[128+20*cos(k*PI/3+PI/6),132+20*sin(k*PI/3+PI/6)]
|
||||
fill(L,()=>{for(let k=0;k<6;k++)c.lineTo(...hex(k));c.closePath()})
|
||||
c.strokeStyle=L;c.lineWidth=4;c.lineCap='round'
|
||||
for(let k=0;k<6;k++){const a=k*PI/3+PI/6,[x,y]=hex(k);c.beginPath();c.moveTo(x,y);c.lineTo(128+40*cos(a),132+50*sin(a));c.stroke()}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// shrimp curled in a c, flicking its long antennae and snapping its tail fan, little legs pedalling
|
||||
const{sin,cos,PI,max,atan2}=Math,T=2*PI
|
||||
export const frames=24,delay=75
|
||||
const B='#ff7a5c',L='#ffbcad',D='#2b2633'
|
||||
export default(c,t)=>{
|
||||
const fl=max(0,sin(T*t*2))**3,cx=116,cy=130,R=48,n=7,a0=-.45,span=4+.3*fl
|
||||
const fill=(col,f)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();f();c.fill();c.stroke()}
|
||||
const seg=k=>{const a=a0-span*k/n;return[cx+R*cos(a),cy+R*sin(a),a,26-12*k/n]}
|
||||
c.translate(0,4*sin(T*t))
|
||||
const[hx,hy]=seg(0),ax=hx+40,ay=hy-12
|
||||
c.strokeStyle=B;c.lineWidth=3;c.lineCap='round'
|
||||
for(const[ex,ey,qx,qy,p]of[[124,22,214,40,0],[176,16,236,60,1.5]]){const w=sin(T*t*2+p);c.beginPath();c.moveTo(ax-6,ay);c.quadraticCurveTo(qx,qy,ex+10*w,ey+4*w);c.stroke()}
|
||||
c.lineWidth=4
|
||||
for(let k=1;k<5;k++){const[x,y,a]=seg(k),b=a+PI+.35*sin(T*t*2-k);c.beginPath();c.moveTo(x,y);c.lineTo(x+32*cos(b),y+32*sin(b));c.stroke()}
|
||||
const[tx,ty,ta]=seg(n);c.save();c.translate(tx,ty);c.rotate(atan2(-cos(ta),sin(ta))+.5*fl)
|
||||
for(const a of[-.65,0,.65])fill(B,()=>c.ellipse(18*cos(a),18*sin(a),17,7,a,0,T))
|
||||
c.restore()
|
||||
for(let k=n;k>=0;k--){const[x,y,,r]=seg(k);fill(B,()=>c.arc(x,y,r,0,T))}
|
||||
c.strokeStyle=L;c.lineWidth=3
|
||||
for(let k=1;k<n;k++){const[x,y,a,r]=seg(k);c.beginPath();c.arc(x,y,r-6,a-.7,a+.7);c.stroke()}
|
||||
fill(B,()=>{c.moveTo(hx-12,hy-20);c.quadraticCurveTo(hx+30,hy-30,hx+44,hy-10);c.quadraticCurveTo(hx+30,hy+16,hx-6,hy+18)})
|
||||
c.strokeStyle=B;c.lineWidth=5;c.beginPath();c.moveTo(ax-8,ay+2);c.lineTo(ax+12,ay-6);c.stroke()
|
||||
c.fillStyle=D;c.beginPath();c.arc(hx+24,hy-14,5,0,T);c.fill()
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// cupcake-shell snail sliding along: its foot stretches and gathers, eye stalks wobble, the cherry on top jiggles
|
||||
const{sin,cos,PI}=Math,T=2*PI
|
||||
export const frames=24,delay=80
|
||||
const B='#c9a27e',L='#ead7c3',P='#ff85a8',R='#ee5a5a',D='#2b2633'
|
||||
export default(c,t)=>{
|
||||
const fill=(col,f)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();f();c.fill();c.stroke()}
|
||||
const e=sin(T*t),hx=196+8*e,bl=t>.55&&t<.61
|
||||
c.translate(-4,0)
|
||||
fill(B,()=>c.roundRect(40,184,hx-22,22,11))
|
||||
c.strokeStyle=B;c.lineCap='round'
|
||||
for(const[x,y,k]of[[-8,98,0],[14,100,1.5]])c.lineWidth=6,c.beginPath(),c.moveTo(hx,134),c.lineTo(hx+x+4*sin(T*t*2+k),y+3*cos(T*t*2+k)),c.stroke()
|
||||
c.lineWidth=36;c.beginPath();c.moveTo(hx-22,190);c.lineTo(hx,144);c.stroke()
|
||||
c.fillStyle=c.strokeStyle=D
|
||||
for(const[x,y,k]of[[-8,98,0],[14,100,1.5]]){const ex=hx+x+4*sin(T*t*2+k),ey=y+3*cos(T*t*2+k)
|
||||
if(bl)c.lineWidth=3.5,c.beginPath(),c.moveTo(ex-5,ey),c.lineTo(ex+5,ey),c.stroke()
|
||||
else c.beginPath(),c.arc(ex,ey,5.5,0,T),c.fill()}
|
||||
c.lineWidth=3.5;c.beginPath();c.arc(hx+6,150,6,.1*PI,.7*PI);c.stroke()
|
||||
const sy=2*sin(T*t-.8),j=k=>2.5*sin(T*t*2-k)
|
||||
c.translate(0,sy)
|
||||
fill(L,()=>{c.moveTo(78,186);c.lineTo(140,186);c.lineTo(152,138);c.lineTo(66,138);c.closePath()})
|
||||
c.strokeStyle=B;c.lineWidth=4
|
||||
for(const[a,b]of[[92,84],[109,109],[126,134]])c.beginPath(),c.moveTo(a,182),c.lineTo(b,142),c.stroke()
|
||||
fill(P,()=>c.ellipse(109,132,50,15,0,0,T))
|
||||
fill(P,()=>c.ellipse(109+j(1),113,38,14,0,0,T))
|
||||
fill(P,()=>c.ellipse(109+j(2),96,25,12,0,0,T))
|
||||
fill(P,()=>{c.moveTo(97+j(3),90);c.quadraticCurveTo(108+j(3),68,120+j(3),88)})
|
||||
c.strokeStyle=B;c.lineWidth=4;c.beginPath();c.moveTo(111+j(4),58);c.quadraticCurveTo(114+j(4),46,124+j(4),40);c.stroke()
|
||||
fill(R,()=>c.arc(110+j(4),66,10,0,T))
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// strawberry frog hopping in place: crouch, leap with legs stretched, land with a squash, then its throat puffs
|
||||
const{sin,cos,PI,max,min}=Math,T=2*PI
|
||||
export const frames=24,delay=70
|
||||
const B='#ee5a5a',L='#f7adad',S='#f4c03e',G='#8cc084',D='#2b2633'
|
||||
export default(c,t)=>{
|
||||
const fill=(col,f)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();f();c.fill();c.stroke()}
|
||||
const air=t>.12&&t<.56,ap=air?(t-.12)/.44:0,h=air?56*sin(PI*ap):0,ext=air?sin(PI*min(1,ap*1.6)):0
|
||||
const sq=t<.12?.12*sin(PI*t/.12):t>.56&&t<.7?.14*sin(PI*(t-.56)/.14):0,g=t>.7?sin(PI*(t-.7)/.3):0
|
||||
const cx=128,base=214-h,W=64*(1+sq),H=96*(1-sq)+10*ext,y0=base-H,bl=t>.9&&t<.96
|
||||
for(const d of[-1,1]){
|
||||
fill(B,()=>c.ellipse(cx+d*W*.78,base-14+8*ext,22-6*ext,15+10*ext,d*(.5-.5*ext),0,T))
|
||||
fill(B,()=>c.ellipse(cx+d*(W*.98-14*ext),base+18*ext,17,6,d*.2,0,T))
|
||||
}
|
||||
fill(B,()=>{c.moveTo(cx,y0+4);c.bezierCurveTo(cx+W*.9,y0-4,cx+W*1.12,y0+H*.4,cx+W*.72,y0+H*.72)
|
||||
c.bezierCurveTo(cx+W*.44,y0+H*1.02,cx+W*.14,base,cx,base);c.bezierCurveTo(cx-W*.14,base,cx-W*.44,y0+H*1.02,cx-W*.72,y0+H*.72)
|
||||
c.bezierCurveTo(cx-W*1.12,y0+H*.4,cx-W*.9,y0-4,cx,y0+4)})
|
||||
for(const d of[-1,1])fill(B,()=>c.arc(cx+d*32,y0+8,19,0,T))
|
||||
for(const a of[-2.6,-2,-1.15,-.5])fill(G,()=>c.ellipse(cx+15*cos(a),y0+4+10*sin(a),14,6,a,0,T))
|
||||
c.strokeStyle=G;c.lineWidth=5;c.lineCap='round';c.beginPath();c.moveTo(cx,y0);c.lineTo(cx+3,y0-14);c.stroke()
|
||||
fill(S,()=>{for(const[x,y]of[[-30,.5],[30,.5],[-14,.64],[14,.64],[0,.78],[-24,.74],[24,.74]])c.moveTo(cx+x*W/64+2.5,y0+H*y),c.ellipse(cx+x*W/64,y0+H*y,2.5,4,0,0,T)})
|
||||
if(g>0)fill(L,()=>c.ellipse(cx,y0+H*.46+6*g,14*g+4,11*g+3,0,0,T))
|
||||
for(const d of[-1,1])fill(B,()=>c.ellipse(cx+d*16,base-2+6*ext,11,6,0,0,T))
|
||||
c.fillStyle=c.strokeStyle=D
|
||||
for(const d of[-1,1])if(bl)c.lineWidth=4,c.beginPath(),c.moveTo(cx+d*32-7,y0+8),c.lineTo(cx+d*32+7,y0+8),c.stroke()
|
||||
else c.beginPath(),c.arc(cx+d*32,y0+8,7,0,T),c.fill()
|
||||
c.lineWidth=4;c.beginPath();c.arc(cx,y0+H*.2,22,.2*PI,.8*PI);c.stroke()
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// thunderbird hovering: lightning-bolt wings beat twice a loop and little sparks crackle off the tips at the top of each beat
|
||||
const{sin,cos,PI,max}=Math,T=2*PI
|
||||
export const frames=24,delay=80
|
||||
const B='#ff7a5c',L='#ffbdad',A='#f4c03e',D='#2b2633'
|
||||
export default(c,t)=>{
|
||||
const f=sin(2*T*t-PI/2),bl=t>.66&&t<.72
|
||||
const fill=(col,g)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();g();c.fill();c.stroke()}
|
||||
const bolt=()=>{for(const[x,y]of[[-14,0],[14,0],[0,32],[18,32],[-18,84],[-8,44],[-26,44]])c.lineTo(x,y);c.closePath()}
|
||||
c.translate(0,5*sin(2*T*t+1.4))
|
||||
for(const d of[-1,1]){c.save();c.translate(128+d*20,128);c.scale(d,1);c.rotate(-2.3+.32*f);fill(A,bolt);c.restore()}
|
||||
c.save();c.translate(128,176);c.scale(.55,.55);fill(A,bolt);c.restore()
|
||||
fill(B,()=>c.ellipse(128,144,30,38,0,0,T))
|
||||
fill(L,()=>c.ellipse(128,152,18,24,0,0,T))
|
||||
fill(A,()=>{for(const[x,y]of[[112,82],[116,60],[124,74],[130,50],[136,72],[144,58],[144,82]])c.lineTo(x,y);c.closePath()})
|
||||
fill(B,()=>c.arc(128,98,26,0,T))
|
||||
fill(A,()=>{c.moveTo(122,102);c.lineTo(134,102);c.lineTo(128,112);c.closePath()})
|
||||
c.fillStyle=c.strokeStyle=D
|
||||
for(const d of[-1,1])if(bl)c.lineWidth=3.5,c.beginPath(),c.arc(128+d*12,92,5,.15*PI,.85*PI),c.stroke()
|
||||
else c.beginPath(),c.arc(128+d*12,94,4.5,0,T),c.fill()
|
||||
// sparks: little four-point stars popping near each wing tip while the wings are up
|
||||
const z=max(0,-f)**3
|
||||
if(z>.05)for(const d of[-1,1])for(const[x,y,s]of[[92,40,1],[78,74,.7],[104,22,.6]]){
|
||||
const r=10*s*z,cx=128+d*x,cy=y+6
|
||||
fill(A,()=>{c.moveTo(cx,cy-r);c.quadraticCurveTo(cx,cy,cx+r,cy);c.quadraticCurveTo(cx,cy,cx,cy+r);c.quadraticCurveTo(cx,cy,cx-r,cy);c.quadraticCurveTo(cx,cy,cx,cy-r)})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// striped tiger doing a big cat stretch, rump up and front paws out, eyes shut and a little yawn, then back to standing
|
||||
const{sin,cos,PI,hypot}=Math,T=2*PI
|
||||
export const frames=24,delay=85
|
||||
const B='#ff9f43',L='#ffd2a6',A='#b5531c',D='#2b2633'
|
||||
const mix=(a,b,k)=>a+(b-a)*k
|
||||
export default(c,t)=>{
|
||||
const s=(1-cos(T*t))/2,k=s*s*(3-2*s)
|
||||
const fill=(col,f)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();f();c.fill();c.stroke()}
|
||||
const line=(col,lw,f)=>{c.strokeStyle=col;c.lineWidth=lw;c.beginPath();f();c.stroke()}
|
||||
const hx=mix(80,78,k),hy=mix(134,108,k),sx=mix(166,160,k),sy=mix(136,176,k),px=mix(170,214,k)
|
||||
const tail=()=>{c.moveTo(hx-12,hy-6);c.quadraticCurveTo(mix(36,52,k),mix(132,90,k),mix(44,72,k),mix(88,46,k))}
|
||||
line(B,13,tail);c.lineCap='butt';c.setLineDash([9,11]);line(A,13,tail);c.setLineDash([]);c.lineCap='round'
|
||||
for(const[x,o]of[[hx+12,0],[hx-6,8]])line(B,19,()=>{c.moveTo(x,hy+10);c.lineTo(x+o-2,214)})
|
||||
for(const o of[12,-4])line(B,19,()=>{c.moveTo(sx+o*.4,sy+6);c.lineTo(px+o,214)})
|
||||
line(B,62,()=>{c.moveTo(hx,hy);c.lineTo(sx,sy)})
|
||||
const dx=sx-hx,dy=sy-hy,l=hypot(dx,dy),ux=dx/l,uy=dy/l
|
||||
for(const f of[.18,.38,.58,.78]){
|
||||
const x=hx+dx*f,y=hy+dy*f
|
||||
line(A,7,()=>{c.moveTo(x+uy*30,y-ux*30);c.lineTo(x+uy*12+ux*4,y-ux*12+uy*4)})
|
||||
}
|
||||
const ex=mix(196,204,k),ey=mix(104,166,k),r=mix(0,.25,k)
|
||||
c.save();c.translate(ex,ey);c.rotate(r)
|
||||
for(const d of[-1,1])fill(B,()=>{c.moveTo(d*8-9,-22);c.lineTo(d*20,-36);c.lineTo(d*28+(d>0?-2:2),-14);c.closePath()})
|
||||
fill(B,()=>c.arc(0,0,30,0,T))
|
||||
fill(L,()=>c.ellipse(10,12,18,12,0,0,T))
|
||||
for(const y of[-2,8])line(A,5,()=>{c.moveTo(-28,y);c.lineTo(-16,y+2)})
|
||||
line(A,5,()=>{c.moveTo(4,-30);c.lineTo(4,-20)})
|
||||
c.fillStyle=c.strokeStyle=D
|
||||
if(k>.55)c.lineWidth=4,c.beginPath(),c.arc(10,-4,5.5,.15*PI,.85*PI),c.stroke()
|
||||
else c.beginPath(),c.arc(10,-4,5,0,T),c.fill()
|
||||
c.beginPath();c.ellipse(22,6,4.5,3.5,0,0,T);c.fill()
|
||||
if(k>.7)c.beginPath(),c.ellipse(14,18,6,7*(k-.7)/.3+1,0,0,T),c.fill()
|
||||
c.restore()
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// walrus sitting up: tusks and a whiskery muzzle, flopping both front flippers, head bobbing, a slow blink
|
||||
const{sin,PI}=Math,T=2*PI
|
||||
export const frames=24,delay=80
|
||||
const B='#c9a27e',L='#e6d3bf',W='#fff',D='#2b2633'
|
||||
export default(c,t)=>{
|
||||
const f=sin(T*t*2),h=3*sin(T*t*2-1),bl=t>.7&&t<.78,fill=(col,g)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();g();c.fill();c.stroke()}
|
||||
for(const d of[-1,1])fill(B,()=>c.ellipse(128+d*40,212,26,9,d*.15,0,T))
|
||||
for(const d of[-1,1]){c.save();c.translate(128+d*60,170);c.rotate(-d*(.35+.4*f));fill(B,()=>c.ellipse(d*22,8,14,30,-d*.7,0,T));c.restore()}
|
||||
fill(B,()=>c.ellipse(128,162,70,52,0,0,T))
|
||||
c.translate(0,h)
|
||||
fill(B,()=>c.ellipse(128,108,52,44,0,0,T))
|
||||
for(const d of[-1,1])fill(W,()=>{c.moveTo(128+d*8,132);c.quadraticCurveTo(128+d*12,160,128+d*16,178);c.quadraticCurveTo(128+d*22,156,128+d*22,130)})
|
||||
for(const d of[-1,1])fill(L,()=>c.arc(128+d*15,124,17,0,T))
|
||||
c.fillStyle=c.strokeStyle=D;c.beginPath();c.ellipse(128,109,7,5,0,0,T);c.fill()
|
||||
for(const d of[-1,1])for(const[x,y]of[[9,123],[17,129],[22,120]])c.beginPath(),c.arc(128+d*x,y,2,0,T),c.fill()
|
||||
for(const d of[-1,1])if(bl)c.lineWidth=3.5,c.beginPath(),c.arc(128+d*22,90,5,.15*PI,.85*PI),c.stroke()
|
||||
else c.beginPath(),c.arc(128+d*22,92,5,0,T),c.fill()
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
// whale carrying a tiny island: it bobs, its palm leaves sway, its tail flicks and it puffs a spout now and then
|
||||
const{sin,cos,PI,min,max}=Math,T=2*PI
|
||||
export const frames=24,delay=85
|
||||
const B='#4ea8de',L='#a7d4ef',S='#f4c03e',G='#8cc084',D='#2b2633'
|
||||
export default(c,t)=>{
|
||||
const fill=(col,f)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();f();c.fill();c.stroke()}
|
||||
const shape=(x,y,r,col,f)=>{c.save();c.translate(x,y);c.rotate(r);fill(col,f);c.restore()}
|
||||
const k=sin(T*t-1.4),tx=210-4*k,ty=94-5*k,bl=t>.8&&t<.86,p=(t-.1)/.45,sw=.08*sin(T*t*2)
|
||||
c.translate(128,134+6*sin(T*t));c.rotate(-.03*cos(T*t));c.scale(.86,.86);c.translate(-132,-128)
|
||||
const body=()=>{c.moveTo(106,88);c.bezierCurveTo(60,86,30,114,32,148);c.bezierCurveTo(34,184,66,200,108,200)
|
||||
c.bezierCurveTo(158,200,204,180,212,136);c.quadraticCurveTo(tx+10,116,tx+7,ty);c.lineTo(tx-7,ty)
|
||||
c.quadraticCurveTo(tx-8,120,184,124);c.bezierCurveTo(172,100,144,88,106,88)}
|
||||
shape(tx,ty,.12-.2*k,B,()=>{c.moveTo(0,6);c.quadraticCurveTo(16,0,36,-22);c.quadraticCurveTo(16,-22,0,-8)
|
||||
c.quadraticCurveTo(-12,-20,-26,-20);c.quadraticCurveTo(-12,0,0,6)})
|
||||
fill(B,body)
|
||||
c.save();c.beginPath();body();c.clip();c.fillStyle=L;c.beginPath();c.ellipse(104,204,92,30,0,0,T);c.fill();c.restore()
|
||||
shape(110,192,.6+.35*sin(T*t-2),B,()=>c.ellipse(20,0,24,9,0,0,T))
|
||||
fill(S,()=>c.ellipse(126,94,36,15,0,PI,T))
|
||||
c.strokeStyle=S;c.lineWidth=8;c.lineCap='round';c.beginPath();c.moveTo(130,86);c.quadraticCurveTo(126+30*sw,58,142+60*sw,34);c.stroke()
|
||||
// palm crown: crescent fronds arching out and drooping
|
||||
c.save();c.translate(142+60*sw,34);c.rotate(sw*1.5)
|
||||
for(const[ex,ey]of[[-48,18],[-34,-12],[0,-24],[34,-12],[48,18]])fill(G,()=>{c.moveTo(0,0);c.quadraticCurveTo(ex*.5,ey*.5-(ey<0?6:18),ex,ey);c.quadraticCurveTo(ex*.5,ey*.5+(ey<0?6:-4),0,0)})
|
||||
c.restore()
|
||||
if(p>0&&p<1){
|
||||
const g=sin(PI*p),x=66,y=96,h=46*g,q=max(0,(p-.25)/.75)
|
||||
c.strokeStyle=L;c.lineWidth=10*g+2;c.beginPath();c.moveTo(x,y);c.lineTo(x,y-h);c.stroke()
|
||||
c.fillStyle=L;for(const d of[-1,1])c.beginPath(),c.arc(x+d*24*q,y-h-8+30*q*q,6*(1-.4*q),0,T),c.fill()
|
||||
}
|
||||
c.fillStyle=c.strokeStyle=D
|
||||
if(bl)c.lineWidth=4,c.beginPath(),c.arc(66,128,6,.15*PI,.85*PI),c.stroke()
|
||||
else c.beginPath(),c.arc(66,130,6,0,T),c.fill()
|
||||
c.lineWidth=3.5;c.beginPath();c.moveTo(40,160);c.quadraticCurveTo(50,168,62,166);c.stroke()
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// chunky wombat digging nose-down into a dirt mound, paws scooping, clods flying back over its back
|
||||
const{sin,cos,PI,max}=Math,T=2*PI
|
||||
export const frames=24,delay=70
|
||||
const B='#8a94a6',L='#c5cad3',A='#b5835a',D='#2b2633'
|
||||
export default(c,t)=>{
|
||||
const rk=.035*sin(T*t*2)
|
||||
const fill=(col,f)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();f();c.fill();c.stroke()}
|
||||
c.translate(0,-14)
|
||||
for(let k=0;k<3;k++){
|
||||
const u=(t*2+k/3)%1,x=190-160*u,y=196-4*124*u*(1-u)+20*u,r=7-2*u
|
||||
fill(A,()=>c.arc(x,y,r,0,T))
|
||||
}
|
||||
fill(A,()=>c.ellipse(46,212,28,10,0,0,T))
|
||||
fill(A,()=>{c.moveTo(186,216);c.quadraticCurveTo(212,184,238,216);c.closePath()})
|
||||
c.save();c.translate(160,210);c.rotate(rk);c.translate(-160,-210)
|
||||
for(const[x,y]of[[70,206],[96,210]])fill(B,()=>c.ellipse(x,y,15,9,0,0,T))
|
||||
for(const[k,o]of[[0,0],[1,PI]]){
|
||||
const a=.7*sin(T*t*2+o)
|
||||
c.save();c.translate(170+k*8,194);c.rotate(a);fill(B,()=>c.ellipse(10,12,9,15,-.4,0,T));c.restore()
|
||||
}
|
||||
fill(B,()=>c.ellipse(112,166,62,44,-.1,0,T))
|
||||
fill(B,()=>c.arc(56,150,8,0,T))
|
||||
for(const[x,r]of[[162,-.3],[176,.2]])fill(B,()=>c.ellipse(x,140,7,10,r,0,T))
|
||||
fill(B,()=>c.ellipse(178,172,32,27,.25,0,T))
|
||||
fill(L,()=>c.ellipse(198,182,14,12,.25,0,T))
|
||||
c.fillStyle=D;c.beginPath();c.ellipse(205,180,9,7,.25,0,T);c.fill()
|
||||
c.beginPath();c.arc(182,160,4.5,0,T);c.fill()
|
||||
c.restore()
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
// little wyvern hovering: bat wings beating twice a loop, tail curling below, tiny horns, blinks
|
||||
const{sin,PI}=Math,T=2*PI
|
||||
export const frames=24,delay=80
|
||||
const B='#8cc084',L='#c6e0c2',A='#f4c03e',D='#2b2633'
|
||||
export default(c,t)=>{
|
||||
const f=sin(2*T*t),bl=t>.42&&t<.48
|
||||
const fill=(col,g)=>{c.fillStyle=c.strokeStyle=col;c.lineWidth=6;c.beginPath();g();c.fill();c.stroke()}
|
||||
const line=(col,lw,g)=>{c.strokeStyle=col;c.lineWidth=lw;c.beginPath();g();c.stroke()}
|
||||
c.translate(0,6*sin(2*T*t+1.3))
|
||||
// tail curling down and to the side, tapering, with a spade tip
|
||||
const sw=6*sin(T*t)
|
||||
for(let s=0;s<=1;s+=.02){const u=1-s,x=u*u*128+2*u*s*(140+sw)+s*s*(176+sw),y=u*u*168+2*u*s*222+s*s*(196);c.fillStyle=B;c.beginPath();c.arc(x,y,9-5*s,0,T);c.fill()}
|
||||
fill(B,()=>{c.moveTo(174+sw,198);c.lineTo(186+sw,178);c.lineTo(192+sw,200);c.closePath()})
|
||||
for(const d of[-1,1]){
|
||||
c.save();c.translate(128+d*16,122);c.scale(d*.92,.92);c.rotate(-.35*f)
|
||||
fill(L,()=>{c.moveTo(0,12);c.lineTo(46,-40);c.lineTo(92,-30);c.quadraticCurveTo(76,-18,84,6);c.quadraticCurveTo(64,4,58,28);c.quadraticCurveTo(34,14,8,28)})
|
||||
line(B,6,()=>{c.moveTo(0,0);c.lineTo(46,-40);c.lineTo(92,-30);c.moveTo(46,-40);c.lineTo(84,6);c.moveTo(46,-40);c.lineTo(58,28)})
|
||||
c.restore()
|
||||
}
|
||||
for(const d of[-1,1])fill(B,()=>c.ellipse(128+d*14,174,8,10,0,0,T))
|
||||
fill(B,()=>c.ellipse(128,140,30,36,0,0,T))
|
||||
fill(L,()=>c.ellipse(128,148,17,23,0,0,T))
|
||||
for(const d of[-1,1])fill(A,()=>{c.moveTo(128+d*10,72);c.quadraticCurveTo(128+d*16,52,128+d*28,48);c.quadraticCurveTo(128+d*24,62,128+d*24,76)})
|
||||
fill(B,()=>c.arc(128,94,30,0,T))
|
||||
fill(L,()=>c.ellipse(128,108,16,10,0,0,T))
|
||||
c.fillStyle=c.strokeStyle=D
|
||||
for(const d of[-1,1]){
|
||||
c.beginPath();c.arc(128+d*5,106,2.2,0,T);c.fill()
|
||||
if(bl)c.lineWidth=3.5,c.beginPath(),c.arc(128+d*14,86,5,.15*PI,.85*PI),c.stroke()
|
||||
else c.beginPath(),c.arc(128+d*14,88,4.5,0,T),c.fill()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user