Double the anime and manga sections to 100 each

Anime, 50 more colored girls: daily moments (yawn, hiccup, toothbrush, hair
dryer, blanket burrito, pocky), hobbies (baker, barista, DJ, piano, violin,
polaroid, knitting, origami, pottery), sports (swimming, tennis, badminton,
skating, ballet, jump rope, hula hoop, bicycle, campfire, surfing), holidays
(halloween, christmas, valentine, mochi, birthday, easter, tsukimi,
suikawari, taiko, teru teru bozu) and fantasy (fairy, bunny hood, slime,
cyber, magical girl, alien, jiangshi, tanuki, yuki-onna, little devil).

Manga, 50 more black-and-white girls: reactions (doki, stare, ufufu,
denial, fired up, panic, sigh, confused, shiver, poka poka), sports and
martial arts (boxing, fencing, volleyball, sprint, gymnast, baseball,
naginata, nunchaku, parkour, motorbike), school (library, flute,
calligraphy, science, hanko, transfer student, tug of war, sweeping, note
passing, yakisoba bread), home and town (claw machine, cooking, ironing,
bus stop, matcha, sewing, boxes, stray cat, foggy window, piggy bank) and
yokai and fantasy (tengu, kappa, rokurokubi, temari, alchemist, mummy, wolf
girl, medusa, genie, bard).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-23 11:39:30 +00:00
co-authored by Claude Opus 5.5
parent 56666ba0e3
commit c4dd37f62c
300 changed files with 6009 additions and 0 deletions
+55
View File
@@ -0,0 +1,55 @@
// lilac-skinned alien girl with bobbling antennae waving hello, a soft UFO plushie tucked under her arm, stars twinkling
const{sin,cos,PI,round,max}=Math,T=2*PI
export const frames=12,delay=80
const SKIN='#e5dbff',SK2='#d0bfff',HAIR='#22b8cf',HD='#0c8599',HL='#c5f6fa',EYE='#ff6b6b',ED='#c92a2a',SUIT='#e9ecef',SD='#adb5bd',GO='#ffd43b',UF='#91a7ff',UD='#5c7cfa',DOME='#faa2c1',BL='#f783ac'
const eye=(c,x,y,d)=>{
c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,15,18,0,0,T);c.fill()
c.save();c.beginPath();c.ellipse(x,y+2,12.5,16,0,0,T);c.clip();c.fillStyle=EYE;c.fill();c.fillStyle=ED;c.beginPath();c.ellipse(x,y-8,14,10,0,0,T);c.fill();c.restore()
c.lineWidth=2.5;c.beginPath();c.ellipse(x,y+2,12.5,16,0,0,T);c.stroke()
c.fillStyle='#111';c.beginPath();c.ellipse(x,y+3,6,8,0,0,T);c.fill()
c.fillStyle='#fff';c.beginPath();c.arc(x-4,y-5,5,0,T);c.fill();c.beginPath();c.arc(x+5,y+8,2.5,0,T);c.fill();c.beginPath();c.arc(x+6,y-3,1.5,0,T);c.fill()
c.lineWidth=6;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke()
}
const spark=(c,x,y,r)=>{const q=r*.2;c.beginPath();c.moveTo(x,y-r);c.quadraticCurveTo(x+q,y-q,x+r,y);c.quadraticCurveTo(x+q,y+q,x,y+r);c.quadraticCurveTo(x-q,y+q,x-r,y);c.quadraticCurveTo(x-q,y-q,x,y-r);c.fill();c.stroke()}
const line=(c,pts,w,col)=>{for(const[lw,s]of[[w+8,'#111'],[w,col]]){c.lineWidth=lw;c.strokeStyle=s;c.beginPath();pts.forEach(([x,y],k)=>k?c.lineTo(x,y):c.moveTo(x,y));c.stroke()}c.strokeStyle='#111'}
export default(c,t)=>{
const wv=sin(2*T*t),bob=sin(T*t)
for(const[x,y,o]of[[54,40,0],[202,40,.5]]){const r=round(9*max(0,sin(T*(t+o))));if(r>2){c.fillStyle=GO;c.lineWidth=3;spark(c,x,y,r)}}
c.save();c.translate(128,262);c.scale(.82,.82);c.translate(-128,-262)
for(const d of[-1,1]){const a=d*.32+.16*sin(T*t*2+d)+.06*bob,L=70,bx=128+d*24,by=50,ex=bx+L*sin(a),ey=by-L*cos(a)
line(c,[[bx,by],[(bx+ex)/2+d*8,(by+ey)/2],[ex,ey]],4,SK2)
c.fillStyle=d<0?GO:DOME;c.lineWidth=6;c.beginPath();c.arc(ex,ey,13,0,T);c.fill();c.stroke();c.fillStyle='#fff';c.beginPath();c.arc(ex-4,ey-4,4,0,T);c.fill()}
c.lineWidth=6;c.fillStyle=HD;c.beginPath();c.moveTo(128,36);c.bezierCurveTo(198,36,212,98,202,150);c.quadraticCurveTo(218,170,214,180);c.quadraticCurveTo(196,176,184,170);c.lineTo(72,170);c.quadraticCurveTo(60,176,42,180);c.quadraticCurveTo(38,170,54,150);c.bezierCurveTo(44,98,58,36,128,36);c.fill();c.stroke()
c.fillStyle=SUIT;c.beginPath();c.moveTo(98,190);c.quadraticCurveTo(56,198,46,262);c.lineTo(210,262);c.quadraticCurveTo(200,198,158,190);c.closePath();c.fill();c.stroke()
c.fillStyle=UF;c.beginPath();c.ellipse(128,192,36,12,0,0,T);c.fill();c.stroke()
c.fillStyle=GO;c.lineWidth=5;c.beginPath();for(let k=0;k<10;k++){const r=k%2?6:14,a=k*PI/5-PI/2;c.lineTo(150+cos(a)*r,226+sin(a)*r)}c.closePath();c.fill();c.stroke()
c.strokeStyle=SD;c.lineWidth=4;c.beginPath();c.moveTo(70,226);c.quadraticCurveTo(80,240,76,262);c.stroke();c.strokeStyle='#111'
c.fillStyle=SKIN;c.lineWidth=6;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke()
eye(c,103,140,-1);eye(c,153,140,1)
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*42,163,12,6,0,0,T),c.fill()
c.lineWidth=4;c.fillStyle='#c92a2a';c.beginPath();c.moveTo(116,164);c.quadraticCurveTo(128,182,140,164);c.closePath();c.fill();c.stroke()
c.lineWidth=6;c.fillStyle=HAIR;c.beginPath();c.moveTo(60,150)
c.bezierCurveTo(46,74,88,36,128,36);c.bezierCurveTo(168,36,210,74,196,150)
c.quadraticCurveTo(192,120,182,106);c.quadraticCurveTo(172,96,166,108);c.quadraticCurveTo(156,90,146,92);c.quadraticCurveTo(140,106,130,110)
c.quadraticCurveTo(124,94,112,90);c.quadraticCurveTo(108,106,98,110);c.quadraticCurveTo(92,96,84,98);c.quadraticCurveTo(80,110,76,114)
c.quadraticCurveTo(66,122,60,150);c.closePath();c.fill();c.stroke()
c.strokeStyle=HL;c.lineWidth=5;for(const[a,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,56,PI*a,PI*e),c.stroke();c.strokeStyle='#111'
c.save();c.translate(76,236);c.scale(.8,.8);c.rotate(-.12+.04*bob)
c.fillStyle=DOME;c.lineWidth=5;c.beginPath();c.ellipse(0,-14,24,22,0,PI,T);c.fill();c.stroke()
c.fillStyle='#fff';c.beginPath();c.ellipse(-9,-24,6,4,-.5,0,T);c.fill()
c.fillStyle=UF;c.beginPath();c.ellipse(0,-6,52,18,0,0,T);c.fill();c.stroke()
c.fillStyle=UD;c.beginPath();c.ellipse(0,4,32,8,0,0,T);c.fill();c.stroke()
c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.arc(d*13,-8,3.5,0,T),c.fill()
c.lineWidth=3;c.beginPath();c.arc(0,-7,5,.15*PI,.85*PI);c.stroke()
c.fillStyle=GO;c.lineWidth=3;for(const x of[-38,38])c.beginPath(),c.arc(x,-6,5,0,T),c.fill(),c.stroke()
c.restore()
c.lineWidth=5;c.fillStyle=SKIN;c.beginPath();c.ellipse(100,224,11,9,-.4,0,T);c.fill();c.stroke()
const sx=176,sy=214,ea=-.7,ex=sx+40*cos(ea),ey=sy+40*sin(ea),fa=-1.5+.45*wv,hx=ex+36*cos(fa),hy=ey+36*sin(fa)
line(c,[[sx,sy],[ex,ey],[hx,hy]],11,SUIT)
c.save();c.translate(hx,hy);c.rotate(fa+PI/2);c.fillStyle=SKIN;c.lineWidth=5
c.beginPath();c.moveTo(-11,4);c.quadraticCurveTo(-14,-22,-6,-26);c.quadraticCurveTo(0,-30,6,-26);c.quadraticCurveTo(14,-22,11,4);c.closePath();c.fill();c.stroke()
c.lineWidth=3;c.beginPath();for(const k of[-4,2])c.moveTo(k,-25),c.lineTo(k+.5,-15);c.stroke()
c.lineWidth=5;c.beginPath();c.ellipse(-13,-6,4.5,8,-.7,0,T);c.fill();c.stroke();c.restore()
c.lineWidth=4;for(const s of[1,-1])c.beginPath(),c.arc(hx,hy,26,fa+s*.6-.2,fa+s*.6+.2),c.stroke()
c.restore()
}
+70
View File
@@ -0,0 +1,70 @@
// girl with a scarlet bob and sweatband leaps and smashes a falling shuttlecock, which rockets off with speed lines
const{sin,cos,PI,max,min,hypot,sqrt,atan2}=Math,T=2*PI
export const frames=16,delay=70
const SKIN='#ffe3d1',HAIR='#f03e3e',HD='#c92a2a',HL='#ffc9c9',EYE='#fab005',ED='#e67700',JER='#9775fa',JD='#7048e8',SH='#364fc7',BAND='#fff',RQ='#fcc419',BL='#ffa8a8'
const eye=(c,x,y,d,lx,ly)=>{
c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill()
c.save();c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.clip();const X=x+lx,Y=y+ly
c.beginPath();c.ellipse(X,Y+2,11.5,15,0,0,T);c.fillStyle=EYE;c.fill();c.save();c.clip();c.fillStyle=ED;c.beginPath();c.ellipse(X,Y-8,13,10,0,0,T);c.fill();c.restore()
c.lineWidth=2.5;c.beginPath();c.ellipse(X,Y+2,11.5,15,0,0,T);c.stroke()
c.fillStyle='#111';c.beginPath();c.ellipse(X+1,Y+3,5.5,7.5,0,0,T);c.fill()
c.fillStyle='#fff';c.beginPath();c.arc(X-3,Y-5,4.5,0,T);c.fill();c.beginPath();c.arc(X+6,Y+8,2,0,T);c.fill();c.restore()
c.lineWidth=8;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke()
}
const line=(c,pts,w,col)=>{for(const[lw,s]of[[w+8,'#111'],[w,col]]){c.lineWidth=lw;c.strokeStyle=s;c.beginPath();pts.forEach(([x,y],k)=>k?c.lineTo(x,y):c.moveTo(x,y));c.stroke()}c.strokeStyle='#111'}
const ik=(hx,hy,fx,fy,L,s=1)=>{const dx=fx-hx,dy=fy-hy,d=hypot(dx,dy),k=sqrt(max(0,L*L-d*d/4));return[hx+dx/2+s*dy/d*k,hy+dy/2-s*dx/d*k]}
const ss=u=>u*u*(3-2*u)
const key=(K,t)=>{let k=0;while(k<K.length-2&&t>=K[k+1][0])k++;const[t0,...a]=K[k],[t1,...b]=K[k+1],u=ss(min(1,max(0,(t-t0)/(t1-t0))));return a.map((v,j)=>v+(b[j]-v)*u)}
const RK=[[0,24,22,-.9],[.14,24,22,-.9],[.36,-8,-26,1.9],[.44,-4,-36,3.6],[.48,30,-34,5.35],[.6,30,24,7.1],[.82,24,22,5.38],[1,24,22,5.38]]
const cock=(c,x,y,a,s=1)=>{c.save();c.translate(x,y);c.rotate(a);c.scale(s,s);c.fillStyle='#fff';c.lineWidth=4;c.beginPath();c.moveTo(-4,-6);c.lineTo(-24,-13);c.quadraticCurveTo(-28,0,-24,13);c.lineTo(-4,6);c.closePath();c.fill();c.stroke()
c.lineWidth=2;for(const k of[-7,0,7])c.beginPath(),c.moveTo(-5,k*.5),c.lineTo(-25,k*1.4),c.stroke();c.lineWidth=3;c.beginPath();c.moveTo(-15,-9);c.quadraticCurveTo(-17,0,-15,9);c.stroke()
c.fillStyle='#ff6b6b';c.lineWidth=4;c.beginPath();c.arc(0,0,7,-PI/2,PI/2);c.closePath();c.fill();c.stroke();c.restore()}
export default(c,t,i)=>{
const h=t>.28&&t<.7?32*sin(PI*(t-.28)/.42):0,cr=t>.16&&t<.28?7*sin(PI*(t-.16)/.12):t>.7&&t<.84?8*sin(PI*(t-.7)/.14):0,oy=cr-h
const sh=[112,138+oy],[rdx,rdy,ra]=key(RK,t),hd=[sh[0]+rdx,sh[1]+rdy],air=h>6
const up=t>.18&&t<.5,hit=t>.46&&t<.56
c.translate(128,244);c.scale(.9,.9);c.translate(-128,-244)
c.fillStyle='#dee2e6';c.beginPath();c.ellipse(108,234,40*(1-h/90),6*(1-h/90),0,0,T);c.fill()
const oa=up?[sh[0]+38,sh[1]-6]:[sh[0]+18,sh[1]+24]
line(c,[[sh[0]-4,sh[1]+2],[(sh[0]+oa[0])/2+4,(sh[1]+oa[1])/2+6],oa],7,SKIN)
c.fillStyle=SKIN;c.lineWidth=4;c.beginPath();c.arc(...oa,6,0,T);c.fill();c.stroke()
const hip=[104,180+oy]
for(const[d,s]of[[-1,1],[1,-1]]){const f=air?[hip[0]+(d<0?-22:10),hip[1]+(d<0?30:38)]:[hip[0]+d*14,224],k=ik(...hip,f[0],f[1]-4,27,d<0?-1:1);line(c,[hip,k,[f[0],f[1]-4]],8,SKIN)
c.fillStyle='#fff';c.lineWidth=5;c.beginPath();c.ellipse(f[0]+4,f[1],12,7,air&&d<0?.5:0,0,T);c.fill();c.stroke();c.strokeStyle='#ff6b6b';c.lineWidth=3;c.beginPath();c.moveTo(f[0]-2,f[1]-2);c.lineTo(f[0]+10,f[1]-2);c.stroke();c.strokeStyle='#111'}
c.fillStyle=SH;c.lineWidth=5;c.beginPath();c.moveTo(90,168+oy);c.lineTo(120,168+oy);c.lineTo(124,190+oy);c.lineTo(86,190+oy);c.closePath();c.fill();c.stroke()
c.fillStyle=SKIN;c.beginPath();c.rect(106,124+oy,12,10);c.fill()
c.fillStyle=JER;c.lineWidth=5;c.beginPath();c.moveTo(98,130+oy);c.lineTo(124,130+oy);c.lineTo(132,142+oy);c.lineTo(126,172+oy);c.lineTo(88,172+oy);c.lineTo(90,140+oy);c.closePath();c.fill();c.stroke()
c.strokeStyle='#fff';c.lineWidth=4;c.beginPath();c.moveTo(92,156+oy);c.lineTo(128,152+oy);c.stroke();c.strokeStyle='#111'
const bk=t>.2&&t<.47,arm=()=>{
c.save();c.translate(...hd);c.rotate(ra)
line(c,[[0,0],[40,0]],3,'#e9ecef');c.fillStyle='#fff';c.beginPath();c.ellipse(58,0,18,13,0,0,T);c.fill();c.save();c.clip();c.strokeStyle='#ced4da';c.lineWidth=1.5;for(let k=-18;k<=18;k+=5)c.beginPath(),c.moveTo(40,k),c.lineTo(76,k),c.moveTo(58+k,-14),c.lineTo(58+k,14),c.stroke();c.restore()
c.strokeStyle='#111';c.lineWidth=9;c.beginPath();c.ellipse(58,0,18,13,0,0,T);c.stroke();c.strokeStyle=RQ;c.lineWidth=4;c.stroke();c.strokeStyle='#111'
c.fillStyle=JD;c.lineWidth=4;c.beginPath();c.roundRect(-8,-4,16,8,3);c.fill();c.stroke();c.restore()
line(c,[sh,[(sh[0]+hd[0])/2+(rdy<0?-10:8),(sh[1]+hd[1])/2+(rdy<0?2:6)],hd],8,SKIN)
c.fillStyle=SKIN;c.lineWidth=4;c.beginPath();c.arc(...hd,6.5,0,T);c.fill();c.stroke()
}
if(bk)arm()
const head=g=>{c.save();c.translate(114,92+oy);c.rotate(up?-.12:0);c.scale(.56,.56);c.translate(-128,-120);g();c.restore()}
head(()=>{
c.lineWidth=9;c.fillStyle=HAIR;c.beginPath();c.moveTo(126,34);c.bezierCurveTo(196,34,210,96,196,170);c.quadraticCurveTo(178,178,166,166);c.lineTo(70,166);c.quadraticCurveTo(54,178,46,160);c.bezierCurveTo(40,96,56,34,126,34);c.fill();c.stroke()
c.fillStyle=SKIN;c.beginPath();c.moveTo(78,96);c.bezierCurveTo(74,152,104,184,132,186);c.bezierCurveTo(160,184,190,152,186,96);c.bezierCurveTo(186,44,78,44,78,96);c.fill();c.stroke()
if(hit){c.lineWidth=8;for(const[x,d]of[[108,1],[158,-1]])c.beginPath(),c.moveTo(x-12*d,128),c.lineTo(x+10*d,140),c.lineTo(x-12*d,152),c.stroke()}else eye(c,108,140,-1,4,up?-5:0),eye(c,158,140,1,4,up?-5:0)
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(134+d*42,162,12,6,0,0,T),c.fill()
c.fillStyle='#c92a2a';c.lineWidth=6;c.beginPath()
if(hit||air)c.moveTo(120,164),c.quadraticCurveTo(138,190,152,164),c.closePath(),c.fill();else c.moveTo(126,168),c.quadraticCurveTo(136,174,146,166)
c.stroke()
c.fillStyle=HAIR;c.lineWidth=9;c.beginPath();c.moveTo(70,150);c.bezierCurveTo(56,74,92,40,132,40);c.bezierCurveTo(176,40,206,78,192,150)
c.lineTo(184,112);c.lineTo(174,118);c.lineTo(166,104);c.lineTo(156,116);c.lineTo(146,100);c.lineTo(136,116);c.lineTo(124,100);c.lineTo(114,116);c.lineTo(102,102);c.lineTo(92,118);c.lineTo(80,112);c.closePath();c.fill();c.stroke()
c.strokeStyle=HL;c.lineWidth=8;for(const[a0,a1]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(132,104,56,PI*a0,PI*a1),c.stroke();c.strokeStyle='#111'
c.fillStyle=BAND;c.lineWidth=8;c.beginPath();c.moveTo(64,80);c.quadraticCurveTo(132,50,200,80);c.lineTo(200,96);c.quadraticCurveTo(132,66,64,96);c.closePath();c.fill();c.stroke()
c.strokeStyle='#ff6b6b';c.lineWidth=5;c.beginPath();c.moveTo(70,86);c.quadraticCurveTo(132,60,194,86);c.stroke();c.strokeStyle='#111'
for(const k of[0,1]){c.save();c.translate(62,90);c.rotate(2.4+k*.5+.25*sin(T*t+k));c.fillStyle=BAND;c.lineWidth=7;c.beginPath();c.moveTo(0,-7);c.quadraticCurveTo(24,-10,40,0);c.quadraticCurveTo(24,10,0,7);c.closePath();c.fill();c.stroke();c.restore()}
})
if(!bk)arm()
const C=[176,28]
if(t<.47||t>=.84){const u=((t+.16)%1)/.63,x=226+(C[0]-226)*u+6*sin(u*PI*3),y=4+(C[1]-4)*u;cock(c,x,y,PI/2+.25*sin(u*PI*3),t>=.84?min(1,(t-.84)/.06):1)}
else if(t<.66){const u=(t-.47)/.19,x=C[0]+u*130,y=C[1]+u*230,a=atan2(230,130)
for(const[k,l]of[[-9,40],[0,64],[9,40]])line(c,[[x-l*cos(a)+k*sin(a),y-l*sin(a)-k*cos(a)],[x-16*cos(a)+k*sin(a),y-16*sin(a)-k*cos(a)]],3,'#fff')
cock(c,x,y,a)}
if(hit){c.fillStyle='#fff3bf';c.lineWidth=4;c.beginPath();for(let k=0;k<16;k++){const r=k%2?9:22,b=k*PI/8+.2;c.lineTo(C[0]+4+r*cos(b),C[1]+4+r*sin(b))}c.closePath();c.fill();c.stroke()}
}
+56
View File
@@ -0,0 +1,56 @@
// baker girl in a polka-dot kerchief kneading a ball of dough on a floured board, pushing it flat and rolling it back, flour puffing up
const{sin,cos,PI,max}=Math,T=2*PI
export const frames=16,delay=80
const SKIN='#ffe3d1',HAIR='#e0a458',HD='#b8782e',HL='#f7dcae',EYE='#82c91e',ED='#5c940d',BL='#ffa8a8',KER='#ff6b6b',APR='#a5d8ff',WOOD='#e0a96d',WD='#b5803f',DOUGH='#ffe8cc',DS='#f5d0a0'
const ds=(c,a,b,s,f)=>{for(const[l,k]of[[a,'#111'],[b,s]])c.lineWidth=l,c.strokeStyle=k,c.beginPath(),f(),c.stroke();c.strokeStyle='#111'}
const eye=(c,x,y,d,ly)=>{
c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill()
c.save();c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.clip()
c.beginPath();c.ellipse(x,y+2+ly,11.5,15,0,0,T);c.fillStyle=EYE;c.fill();c.lineWidth=2.5;c.stroke()
c.save();c.clip();c.fillStyle=ED;c.beginPath();c.ellipse(x,y-8+ly,13,10,0,0,T);c.fill();c.restore()
c.fillStyle='#111';c.beginPath();c.ellipse(x,y+3+ly,5.5,7.5,0,0,T);c.fill()
c.fillStyle='#fff';c.beginPath();c.arc(x-4,y-5+ly,4.5,0,T);c.fill();c.beginPath();c.arc(x+5,y+8+ly,2,0,T);c.fill();c.restore()
c.lineWidth=7;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke()
}
const puff=(c,x,y,r)=>{c.fillStyle='#fff';c.lineWidth=3.5;c.beginPath();for(const[a,b,q]of[[-.7,.2,.7],[0,-.4,.9],[.7,.1,.75]])c.moveTo(x+a*r+q*r,y+b*r),c.arc(x+a*r,y+b*r,q*r,0,T);c.fill();c.stroke()}
export default(c,t)=>{
const k=(1-cos(2*T*t))/2,u=(2*t)%1
c.lineWidth=7;c.fillStyle='#fff';c.beginPath();c.moveTo(102,150);c.quadraticCurveTo(62,160,52,240);c.lineTo(204,240);c.quadraticCurveTo(194,160,154,150);c.closePath();c.fill();c.stroke()
c.fillStyle=APR;c.lineWidth=5;c.beginPath();c.moveTo(106,172);c.lineTo(150,172);c.lineTo(156,240);c.lineTo(100,240);c.closePath();c.fill();c.stroke()
c.beginPath();c.moveTo(108,172);c.lineTo(114,154);c.moveTo(148,172);c.lineTo(142,154);c.stroke()
c.fillStyle=SKIN;c.beginPath();c.moveTo(118,138);c.lineTo(118,156);c.quadraticCurveTo(128,164,138,156);c.lineTo(138,138);c.fill();c.beginPath();c.moveTo(118,138);c.lineTo(118,154);c.moveTo(138,138);c.lineTo(138,154);c.stroke()
c.save();c.translate(128,100);c.scale(.72,.72);c.translate(-128,-120)
c.lineWidth=7;c.fillStyle=HD;c.beginPath();c.moveTo(128,38);c.bezierCurveTo(198,38,212,110,202,196);c.quadraticCurveTo(190,212,176,202);c.lineTo(80,202);c.quadraticCurveTo(66,212,54,196);c.bezierCurveTo(44,110,58,38,128,38);c.fill();c.stroke()
c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke()
eye(c,103,140,-1,4);eye(c,153,140,1,4)
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,163,13,7,0,0,T),c.fill()
c.lineWidth=2.5;for(const d of[-1,1])for(const x of[-5,0,5])c.beginPath(),c.moveTo(128+d*44+x-2,166),c.lineTo(128+d*44+x+2,160),c.stroke()
c.lineWidth=5;c.fillStyle='#c92a2a';c.beginPath();c.moveTo(118,166);c.quadraticCurveTo(128,180,138,166);c.closePath();c.fill();c.stroke()
c.fillStyle='#ff8fab';c.lineWidth=3;c.beginPath();c.ellipse(134,170,4,3,0,0,T);c.fill();c.stroke()
c.lineWidth=7;c.fillStyle=HAIR;c.beginPath();c.moveTo(68,150)
c.bezierCurveTo(54,90,80,60,128,60);c.bezierCurveTo(176,60,202,90,188,150)
c.quadraticCurveTo(186,122,178,106);c.quadraticCurveTo(170,110,162,116);c.quadraticCurveTo(160,100,148,92)
c.quadraticCurveTo(138,108,124,112);c.quadraticCurveTo(126,100,120,92);c.quadraticCurveTo(108,106,92,112)
c.quadraticCurveTo(92,102,86,98);c.quadraticCurveTo(70,118,68,150);c.closePath();c.fill();c.stroke()
for(const d of[-1,1]){c.beginPath();c.moveTo(128+d*58,108);c.quadraticCurveTo(128+d*72,160,128+d*62,200);c.quadraticCurveTo(128+d*52,196,128+d*50,176);c.quadraticCurveTo(128+d*52,140,128+d*46,112);c.closePath();c.fill();c.stroke()}
c.strokeStyle=HL;c.lineWidth=5;c.beginPath();c.arc(128,110,52,PI*1.3,PI*1.42);c.stroke();c.beginPath();c.arc(128,110,52,PI*1.58,PI*1.7);c.stroke();c.strokeStyle='#111'
const ker=()=>{c.moveTo(56,96);c.bezierCurveTo(50,22,206,22,200,96);c.quadraticCurveTo(128,70,56,96);c.closePath()}
c.lineWidth=7;c.fillStyle=KER;c.beginPath();ker();c.fill();c.save();c.clip();c.fillStyle='#fff';for(const[x,y]of[[84,58],[112,44],[146,46],[176,60],[98,78],[130,66],[162,80],[70,82],[190,84]])c.beginPath(),c.arc(x,y,6,0,T),c.fill();c.restore();c.beginPath();ker();c.stroke()
c.fillStyle=KER;for(const a of[-.5,.7])c.beginPath(),c.ellipse(204+cos(a)*12,92+sin(a)*12,13,8,a,0,T),c.fill(),c.stroke()
c.beginPath();c.arc(202,94,7,0,T);c.fill();c.stroke()
c.restore()
c.lineWidth=6;c.fillStyle=WOOD;c.beginPath();c.roundRect(12,212,232,36,12);c.fill();c.stroke()
c.fillStyle=WD;c.beginPath();c.roundRect(12,236,232,12,6);c.fill();c.stroke()
c.fillStyle='#fff';for(const[x,y]of[[40,222],[52,228],[66,220],[192,224],[206,219],[218,228],[180,230]])c.beginPath(),c.arc(x,y,2.5,0,T),c.fill()
const rx=36+18*k,ry=22-8*k,cy=230-ry
c.fillStyle=DOUGH;c.lineWidth=6;c.beginPath();c.ellipse(128,cy,rx,ry,0,0,T);c.fill();c.stroke()
c.strokeStyle=DS;c.lineWidth=4;c.beginPath();c.ellipse(128,cy+ry*.2,rx*.6,ry*.45,0,.15*PI,.85*PI);c.stroke();c.strokeStyle='#111'
c.lineWidth=3;c.beginPath();c.moveTo(128-rx*.35,cy-ry*.25);c.quadraticCurveTo(128,cy-ry*(.5-.4*k),128+rx*.35,cy-ry*.25);c.stroke()
if(u>.25&&u<.8){const p=(u-.25)/.55,r=11*sin(PI*p);for(const d of[-1,1])puff(c,128+d*(rx+10+26*p),cy-4-26*p,r)}
for(const d of[-1,1]){
const hx=128+d*(16+14*k),hy=cy-ry+6+4*k
ds(c,20,11,'#fff',()=>{c.moveTo(128+d*30,166);c.lineTo(128+d*54,190)})
ds(c,18,9,SKIN,()=>{c.moveTo(128+d*54,190);c.lineTo(hx+d*6,hy+2)})
c.lineWidth=5;c.fillStyle=SKIN;c.beginPath();c.ellipse(hx,hy,13,10,d*.3,0,T);c.fill();c.stroke()
}
}
+64
View File
@@ -0,0 +1,64 @@
// ballerina with a coral bun rises on pointe and pirouettes twice, spotting her head front, tutu bouncing, then lands in plié
const{sin,cos,PI,max,min,abs,round}=Math,T=2*PI
export const frames=20,delay=75
const SKIN='#ffe3d1',HAIR='#ff7f6e',HD='#f0564a',HL='#ffd6cf',EYE='#40c057',ED='#2b8a3e',LEO='#b197fc',LD='#7950f2',TU='#e5dbff',TD='#b197fc',SHOE='#faa2c1',FL='#ffd43b',BL='#ffa8a8',WOOD='#e0a96d',WD='#b07d4f',SPOT='#fff3bf'
const eye=(c,x,y,d)=>{
c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill()
c.save();c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.clip();c.fillStyle=EYE;c.fill();c.fillStyle=ED;c.beginPath();c.ellipse(x,y-8,13,10,0,0,T);c.fill();c.restore()
c.lineWidth=2.5;c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.stroke()
c.fillStyle='#111';c.beginPath();c.ellipse(x,y+3,5.5,7.5,0,0,T);c.fill()
c.fillStyle='#fff';c.beginPath();c.arc(x-4,y-5,4.5,0,T);c.fill();c.beginPath();c.arc(x+5,y+8,2,0,T);c.fill()
c.lineWidth=8;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke()
}
const line=(c,pts,w,col)=>{for(const[lw,s]of[[w+8,'#111'],[w,col]]){c.lineWidth=lw;c.strokeStyle=s;c.beginPath();pts.forEach(([x,y],k)=>k?c.lineTo(x,y):c.moveTo(x,y));c.stroke()}c.strokeStyle='#111'}
const ss=u=>u*u*(3-2*u),cl=u=>min(1,max(0,u))
export default(c,t,i)=>{
const up=ss(cl((t-.18)/.08))*(1-ss(cl((t-.78)/.07))),pl=t<.18?4*sin(PI*t/.18):t>.85?4*sin(PI*(t-.85)/.15):0
const q=4*PI*ss(cl((t-.26)/.52)),cq=cos(q),sq=sin(q),m=q%T,hq=m<4.4?0:(m-4.4)/(T-4.4)*T,ch=cos(hq),sh=sin(hq)
const oy=pl-9*up,bounce=2.5*sin(T*t*5)*up
c.fillStyle=WOOD;c.lineWidth=6;c.beginPath();c.ellipse(128,226,94,20,0,0,T);c.fill();c.stroke()
c.strokeStyle=WD;c.lineWidth=3;for(const x of[78,112,146,180])c.beginPath(),c.moveTo(x,209+abs(x-128)*.06),c.lineTo(x-6,243-abs(x-128)*.06),c.stroke();c.strokeStyle='#111'
c.fillStyle=SPOT;c.beginPath();c.ellipse(128,226,50,10,0,0,T);c.fill()
c.lineWidth=3.5;for(const[x,y,p]of[[50,64,0],[206,84,.4],[40,150,.7],[218,170,.2]]){const s=5+4*sin(T*(t+p)*2);if(s>2){c.fillStyle=FL;c.beginPath();for(let k=0;k<8;k++){const r=k%2?s*.4:s,b=k*PI/4;c.lineTo(x+r*cos(b),y+r*sin(b))}c.closePath();c.fill();c.stroke()}}
const pk=up*(1)
const lx=128+3*cq
line(c,[[lx-2,184+oy],[lx-1,206+oy+pl*.5],[lx,218+oy*.15-2]],8,SKIN)
if(pk>.3){const kx=128+20*cq,ky=192+oy;line(c,[[134,184+oy],[kx,ky],[128+2*cq,206+oy]],8,SKIN);c.fillStyle=SHOE;c.lineWidth=4;c.beginPath();c.ellipse(128+3*cq,208+oy,6,8,0,0,T);c.fill();c.stroke()}
else line(c,[[136,184+oy],[140,206+oy],[142,220]],8,SKIN)
const shoe=(x,y,pt)=>{c.fillStyle=SHOE;c.lineWidth=4;c.beginPath();pt?c.ellipse(x,y,6,9,0,0,T):c.ellipse(x+3,y,11,6,0,0,T);c.fill();c.stroke();c.strokeStyle='#f06595';c.lineWidth=2.5;c.beginPath();c.moveTo(x-5,y-12);c.lineTo(x+5,y-6);c.moveTo(x+5,y-12);c.lineTo(x-5,y-6);c.stroke();c.strokeStyle='#111'}
shoe(lx,222+oy*.15-(up>.5?6:0),up>.5);if(pk<=.3)shoe(142,222,0)
const tut=(back)=>{const ry=17+2*bounce,rx=60,y=172+oy;c.save();c.beginPath();back?c.rect(0,0,256,y):c.rect(0,y,256,256);c.clip()
for(const[r,dy,col]of[[1,5,'#fff'],[.94,0,TU]]){c.fillStyle=col;c.lineWidth=4;c.beginPath();for(let k=0;k<=32;k++){const a=k*T/32+q*.15,rr=(k%2?.95:1)*r;c.lineTo(128+rx*rr*cos(a),y+dy+ry*rr*sin(a))}c.closePath();c.fill();c.stroke()}
c.strokeStyle='#fff';c.lineWidth=3;c.beginPath();c.ellipse(128,y,rx*.7,ry*.62,0,0,T);c.stroke();c.strokeStyle='#111'
c.fillStyle=TD;for(let k=0;k<6;k++){const a=q+k*T/6;c.beginPath();c.arc(128+42*cos(a),y+11*sin(a),3,0,T);c.fill()}c.restore()}
tut(1)
c.fillStyle=LEO;c.lineWidth=5;c.beginPath();c.moveTo(114,128+oy);c.lineTo(142,128+oy);c.quadraticCurveTo(148,150,144,174+oy);c.lineTo(112,174+oy);c.quadraticCurveTo(108,150,114,128+oy);c.closePath();c.fill();c.stroke()
c.strokeStyle=LD;c.lineWidth=3;c.beginPath();c.moveTo(118,140+oy);c.quadraticCurveTo(128+6*sq,150+oy,138,140+oy);c.stroke();c.strokeStyle='#111'
c.fillStyle=FL;c.lineWidth=3.5;c.beginPath();c.arc(128+10*sq,134+oy,4,0,T);c.fill();c.stroke()
tut(0)
c.fillStyle=SKIN;c.beginPath();c.rect(122,120+oy,12,10);c.fill()
const head=g=>{c.save();c.translate(128,90+oy);c.scale(.56,.56);c.translate(-128,-120);g();c.restore()}
const front=ch>-.2,ex=34*sh,es=25*ch
head(()=>{
c.lineWidth=9;c.fillStyle=HAIR;c.beginPath();c.moveTo(128,38);c.bezierCurveTo(194,38,200,96,190,138);c.lineTo(66,138);c.bezierCurveTo(56,96,62,38,128,38);c.fill();c.stroke()
c.beginPath();c.ellipse(128+6*sh,28,30,24,0,0,T);c.fill();c.stroke();c.strokeStyle=HD;c.lineWidth=5;c.beginPath();c.ellipse(128+6*sh,28,18,13,0,PI,T);c.stroke();c.strokeStyle='#111'
if(front){
c.fillStyle=SKIN;c.lineWidth=9;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke()
if(ch>.9&&up<.5){eye(c,103,140,-1);eye(c,153,140,1)}
else{c.lineWidth=8;for(const d of[-1,1]){const x=128+ex+d*es;if(abs(es)>8||d*sh>0)c.beginPath(),c.arc(x,146,13,PI*1.15,PI*1.85),c.stroke(),c.beginPath(),c.moveTo(x+d*12,138),c.lineTo(x+d*19,133),c.stroke()}}
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+ex+d*42*ch,162,11*max(.4,abs(ch)),6,0,0,T),c.fill()
c.lineWidth=5;c.beginPath();c.arc(128+ex,164,7,.15*PI,.85*PI);c.stroke()
c.fillStyle=HAIR;c.lineWidth=9;c.beginPath();c.moveTo(70,130);c.bezierCurveTo(56,70,92,42,128,42);c.bezierCurveTo(166,42,200,70,186,130)
c.quadraticCurveTo(180,104,162,92);c.quadraticCurveTo(146,88,132,96);c.quadraticCurveTo(128,84,124,96);c.quadraticCurveTo(110,88,94,92);c.quadraticCurveTo(76,104,70,130);c.closePath();c.fill();c.stroke()
}else{
c.fillStyle=HAIR;c.lineWidth=9;c.beginPath();c.moveTo(72,100);c.bezierCurveTo(68,160,100,186,128,186);c.bezierCurveTo(156,186,188,160,184,100);c.bezierCurveTo(184,44,72,44,72,100);c.fill();c.stroke()
c.strokeStyle=HD;c.lineWidth=5;for(const d of[-1,1])c.beginPath(),c.moveTo(128+d*14,60),c.quadraticCurveTo(128+d*34,120,128+d*14,170),c.stroke();c.strokeStyle='#111'
}
c.strokeStyle=HL;c.lineWidth=8;c.beginPath();c.arc(128,104,56,PI*1.3,PI*1.44);c.stroke();c.strokeStyle='#111'
c.save();c.translate(128+46*sh+30*ch*(front?1:-1),36);c.fillStyle=FL;c.lineWidth=6;for(let k=0;k<5;k++){const b=k*T/5;c.beginPath();c.arc(12*cos(b),12*sin(b),9,0,T);c.fill();c.stroke()}c.fillStyle='#ff6b6b';c.beginPath();c.arc(0,0,7,0,T);c.fill();c.stroke();c.restore()
})
const op=1-up
for(const d of[-1,1]){const s=[128+d*14,136+oy],e=[128+d*(22+30*op),148+oy-24*op],h=[128+d*(8+50*op),158+oy-34*op];line(c,[s,e,h],7,SKIN);c.fillStyle=SKIN;c.lineWidth=4;c.beginPath();c.arc(...h,5.5,0,T);c.fill();c.stroke()}
if(up>.8)for(const[y,r]of[[176,72],[112,56]])for(const d of[-1,1]){const a0=d>0?.15:PI+.15;for(const[lw,s]of[[9,'#111'],[3.5,'#fff']])c.lineWidth=lw,c.strokeStyle=s,c.beginPath(),c.ellipse(128,y+oy,r,r*.2,0,a0,a0+.8),c.stroke()}
c.strokeStyle='#111'
}
+66
View File
@@ -0,0 +1,66 @@
// barista girl with an espresso-brown bob pouring steamed milk from a steel pitcher into a latte, wiggling the pour, ripples and steam
// the dark back hair gets a white rim so it doesn't vanish on black
const{sin,cos,PI,max}=Math,T=2*PI
export const frames=16,delay=80
const SKIN='#ffe3d1',HAIR='#6b4a3a',HD='#4a3329',HL='#b0907e',EYE='#f59f00',ED='#d9480f',BL='#ffa8a8',APR='#2f9e44',APD='#2b8a3e',CNT='#c08552',CND='#8d5a33',STEEL='#ced4da',STD='#868e96',COF='#c08552',FOAM='#fff4e6',CUP='#fff'
const ds=(c,a,b,s,f)=>{for(const[l,k]of[[a,'#111'],[b,s]])c.lineWidth=l,c.strokeStyle=k,c.beginPath(),f(),c.stroke();c.strokeStyle='#111'}
const eye=(c,x,y,d)=>{
c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill()
c.save();c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.clip()
c.beginPath();c.ellipse(x+4,y+6,11.5,15,0,0,T);c.fillStyle=EYE;c.fill();c.lineWidth=2.5;c.stroke()
c.save();c.clip();c.fillStyle=ED;c.beginPath();c.ellipse(x+4,y-4,13,10,0,0,T);c.fill();c.restore()
c.fillStyle='#111';c.beginPath();c.ellipse(x+4,y+7,5.5,7.5,0,0,T);c.fill()
c.fillStyle='#fff';c.beginPath();c.arc(x,y,4.5,0,T);c.fill();c.beginPath();c.arc(x+9,y+12,2,0,T);c.fill();c.restore()
c.lineWidth=7;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke()
}
export default(c,t)=>{
const w=sin(4*T*t),blink=t>=.55&&t<.65
c.save();c.translate(-18,0)
c.lineWidth=7;c.fillStyle='#fff';c.beginPath();c.moveTo(90,152);c.quadraticCurveTo(52,160,42,236);c.lineTo(178,236);c.quadraticCurveTo(168,160,130,152);c.closePath();c.fill();c.stroke()
c.fillStyle=APR;c.lineWidth=6;c.beginPath();c.moveTo(84,176);c.lineTo(136,176);c.lineTo(146,236);c.lineTo(74,236);c.closePath();c.fill();c.stroke()
c.lineWidth=5;c.beginPath();c.moveTo(86,176);c.lineTo(94,156);c.moveTo(134,176);c.lineTo(126,156);c.stroke()
c.fillStyle='#fff';c.lineWidth=4;c.beginPath();c.arc(110,200,11,0,T);c.fill();c.stroke()
c.fillStyle=COF;c.beginPath();c.ellipse(110,200,4.5,7,.5,0,T);c.fill();c.stroke()
c.fillStyle=SKIN;c.lineWidth=6;c.beginPath();c.moveTo(100,140);c.lineTo(100,158);c.quadraticCurveTo(110,166,120,158);c.lineTo(120,140);c.fill();c.beginPath();c.moveTo(100,140);c.lineTo(100,156);c.moveTo(120,140);c.lineTo(120,156);c.stroke()
c.save();c.translate(110,100);c.scale(.72,.72);c.translate(-128,-120)
const back=()=>{c.moveTo(128,36);c.bezierCurveTo(200,36,214,104,204,178);c.quadraticCurveTo(196,188,184,182);c.lineTo(72,182);c.quadraticCurveTo(60,188,52,178);c.bezierCurveTo(42,104,56,36,128,36)}
c.strokeStyle='#fff';c.lineWidth=20;c.beginPath();back();c.stroke();c.strokeStyle='#111'
c.lineWidth=7;c.fillStyle=HD;c.beginPath();back();c.fill();c.stroke()
c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke()
if(blink){c.lineWidth=6;for(const x of[103,153])c.beginPath(),c.arc(x,138,14,.15*PI,.85*PI),c.stroke()}else eye(c,103,140,-1),eye(c,153,140,1)
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,164,13,7,0,0,T),c.fill()
c.lineWidth=5;c.beginPath();c.moveTo(118,169);c.quadraticCurveTo(128,176,138,168);c.stroke()
c.fillStyle='#ff8fab';c.lineWidth=3.5;c.beginPath();c.moveTo(130,172);c.quadraticCurveTo(138,180,140,170);c.fill();c.stroke()
c.lineWidth=7;c.fillStyle=HAIR;c.beginPath();c.moveTo(62,176)
c.bezierCurveTo(44,80,84,40,128,40);c.bezierCurveTo(172,40,212,80,194,176)
c.quadraticCurveTo(186,182,180,174);c.quadraticCurveTo(186,130,176,104);c.quadraticCurveTo(160,96,150,86)
c.quadraticCurveTo(140,110,104,118);c.quadraticCurveTo(116,108,118,94);c.quadraticCurveTo(100,112,78,116)
c.quadraticCurveTo(70,150,76,174);c.quadraticCurveTo(70,182,62,176);c.closePath();c.fill();c.stroke()
c.strokeStyle=HL;c.lineWidth=6;for(const[s,e]of[[1.28,1.4],[1.5,1.58],[1.66,1.76]])c.beginPath(),c.arc(128,108,58,PI*s,PI*e),c.stroke();c.strokeStyle='#111'
c.fillStyle=COF;c.lineWidth=5;c.save();c.translate(170,84);c.rotate(.6);c.beginPath();c.ellipse(0,0,11,15,0,0,T);c.fill();c.stroke();c.beginPath();c.moveTo(0,-14);c.quadraticCurveTo(-5,0,0,14);c.stroke();c.restore()
c.restore();c.restore()
c.lineWidth=6;c.fillStyle=CNT;c.beginPath();c.roundRect(6,214,244,38,10);c.fill();c.stroke()
c.fillStyle=CND;c.beginPath();c.roundRect(6,214,244,12,6);c.fill();c.stroke()
c.fillStyle=SKIN;c.lineWidth=5;c.beginPath();c.ellipse(52,212,14,10,-.2,0,T);c.fill();c.stroke()
c.fillStyle=CUP;c.lineWidth=6;c.beginPath();c.ellipse(200,215,40,8,0,0,T);c.fill();c.stroke()
c.lineWidth=7;c.beginPath();c.moveTo(228,194);c.bezierCurveTo(250,192,250,214,226,210);c.stroke()
c.lineWidth=6;c.beginPath();c.moveTo(170,189);c.lineTo(174,208);c.quadraticCurveTo(200,218,226,208);c.lineTo(230,189);c.closePath();c.fill();c.stroke()
c.fillStyle=COF;c.beginPath();c.ellipse(200,189,30,8,0,0,T);c.fill();c.stroke()
c.save();c.beginPath();c.ellipse(200,189,30,8,0,0,T);c.clip()
c.fillStyle=FOAM;c.beginPath();c.ellipse(198+2*w,190,18,5,0,0,T);c.fill()
c.strokeStyle=COF;c.lineWidth=2.5;for(const o of[0,.5]){const p=(2*t+o)%1;c.beginPath();c.ellipse(198+2*w,190,6+16*p,2+4*p,0,0,T);c.stroke()}
c.restore();c.strokeStyle='#111'
for(const[x,o]of[[222,0],[238,.5]]){const p=(t+o)%1,s=sin(PI*p);if(s>.15)ds(c,7,3,'#fff',()=>{const y=176-34*p;c.moveTo(x,y+10);c.bezierCurveTo(x-7*s,y+4,x+7*s,y-4,x+2,y-12)})}
const sx=194+2*w,sy=172,a=.8+.05*w,Z=.85
c.save();c.beginPath();c.rect(0,0,256,189);c.clip()
ds(c,13,7,FOAM,()=>{c.moveTo(sx,sy);c.quadraticCurveTo(sx+3+2*w,sy+10,198+2*w,190)})
c.restore()
const hx=sx+Z*(-70*cos(a)-16*sin(a)),hy=sy+Z*(-70*sin(a)+16*cos(a))
ds(c,20,11,'#fff',()=>{c.moveTo(110,168);c.lineTo(128,196);c.lineTo(hx,hy+6)})
c.save();c.translate(sx,sy);c.rotate(a);c.scale(Z,Z)
c.fillStyle=STEEL;c.lineWidth=7;c.beginPath();c.moveTo(-6,-6);c.lineTo(-46,-14);c.quadraticCurveTo(-56,-8,-56,0);c.lineTo(-56,30);c.quadraticCurveTo(-56,40,-46,40);c.lineTo(-14,40);c.quadraticCurveTo(-4,40,-4,30);c.lineTo(-4,4);c.closePath();c.fill();c.stroke()
c.strokeStyle='#fff';c.lineWidth=5;c.beginPath();c.moveTo(-46,-2);c.lineTo(-46,30);c.stroke();c.strokeStyle=STD;c.beginPath();c.moveTo(-14,4);c.lineTo(-14,32);c.stroke();c.strokeStyle='#111'
c.lineWidth=8;c.beginPath();c.moveTo(-56,4);c.bezierCurveTo(-78,4,-78,30,-56,30);c.stroke()
c.restore()
c.fillStyle=SKIN;c.lineWidth=5;c.beginPath();c.ellipse(hx,hy,11,12,0,0,T);c.fill();c.stroke()
}
+64
View File
@@ -0,0 +1,64 @@
// girl with a tangerine bob pedals a bicycle with a puppy riding in the front basket, wheels spinning, scarf streaming behind
const{sin,cos,PI,max,min,hypot,sqrt}=Math,T=2*PI
export const frames=12,delay=80
const SKIN='#ffe3d1',HAIR='#fd7e14',HD='#e8590c',HL='#ffe8cc',EYE='#339af0',ED='#1864ab',TOP='#fff',STR='#20c997',DEN='#4dabf7',DD='#1c7ed6',SCARF='#20c997',SCD='#0ca678',BIKE='#ff6b6b',BD='#e03131',BAS='#e0a96d',BSD='#b07d4f',PUP='#fff4e6',EAR='#a9744f',SHOE='#fa5252',BL='#ffa8a8'
const eye=(c,x,y,d)=>{
c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill()
c.save();c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.clip()
c.beginPath();c.ellipse(x+3,y+2,11.5,15,0,0,T);c.fillStyle=EYE;c.fill();c.save();c.clip();c.fillStyle=ED;c.beginPath();c.ellipse(x+3,y-8,13,10,0,0,T);c.fill();c.restore()
c.lineWidth=2.5;c.beginPath();c.ellipse(x+3,y+2,11.5,15,0,0,T);c.stroke()
c.fillStyle='#111';c.beginPath();c.ellipse(x+5,y+3,5.5,7.5,0,0,T);c.fill()
c.fillStyle='#fff';c.beginPath();c.arc(x,y-5,4.5,0,T);c.fill();c.beginPath();c.arc(x+9,y+8,2,0,T);c.fill();c.restore()
c.lineWidth=8;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke()
}
const line=(c,pts,w,col)=>{for(const[lw,s]of[[w+8,'#111'],[w,col]]){c.lineWidth=lw;c.strokeStyle=s;c.beginPath();pts.forEach(([x,y],k)=>k?c.lineTo(x,y):c.moveTo(x,y));c.stroke()}c.strokeStyle='#111'}
const ik=(hx,hy,fx,fy,L)=>{const dx=fx-hx,dy=fy-hy,d=hypot(dx,dy),k=sqrt(max(0,L*L-d*d/4));return[hx+dx/2-dy/d*k,hy+dy/2+dx/d*k]}
export default(c,t,i)=>{
const f=T*t,bob=1.2*sin(2*f),RH=[70,198],FH=[192,198],BB=[128,200],R=33
c.fillStyle='#ced4da';c.lineWidth=5;c.beginPath();c.roundRect(14,226,228,16,8);c.fill();c.stroke()
c.save();c.beginPath();c.roundRect(14,226,228,16,8);c.clip();c.strokeStyle='#fff';c.lineWidth=4;for(let k=0;k<4;k++){const x=((k*64-t*256)%256+256)%256;c.beginPath();c.moveTo(x,234);c.lineTo(x+28,234);c.stroke()}c.restore()
for(const[k,y]of[[0,132],[1,164]]){const x=((k*20-t*48)%48+48)%48-6;line(c,[[x,y],[x+20,y]],3,'#fff')}
const pd=k=>[BB[0]+15*cos(f+k*PI),BB[1]+15*sin(f+k*PI)],hip=[112,146+bob]
const leg=(k,col)=>{const p=pd(k),kn=ik(...hip,p[0],p[1]-3,37);line(c,[hip,kn,[p[0],p[1]-3]],9,col);line(c,[kn,[(kn[0]+p[0])/2,(kn[1]+p[1])/2]],9,SKIN);c.fillStyle=SHOE;c.lineWidth=5;c.beginPath();c.ellipse(p[0]+4,p[1]-1,11,6,0,0,T);c.fill();c.stroke()}
leg(1,DD)
const wheel=([x,y])=>{c.strokeStyle='#fff';c.lineWidth=16;c.beginPath();c.arc(x,y,R,0,T);c.stroke();c.strokeStyle='#343a40';c.lineWidth=9;c.stroke();c.strokeStyle='#111';c.lineWidth=2.5;c.beginPath();c.arc(x,y,R+5,0,T);c.stroke();c.beginPath();c.arc(x,y,R-5,0,T);c.stroke()
c.strokeStyle='#adb5bd';c.lineWidth=2.5;for(let k=0;k<6;k++){const a=f+k*PI/3;c.beginPath();c.moveTo(x,y);c.lineTo(x+(R-5)*cos(a),y+(R-5)*sin(a));c.stroke()}c.strokeStyle='#111';c.fillStyle='#e9ecef';c.lineWidth=4;c.beginPath();c.arc(x,y,5,0,T);c.fill();c.stroke()}
wheel(RH);wheel(FH)
const seat=[112,152],ht=[172,150]
line(c,[RH,BB,seat,RH],6,BIKE);line(c,[seat,ht],6,BIKE);line(c,[BB,[170,162]],6,BIKE);line(c,[[176,140],FH],6,BD);line(c,[[176,140],[176,126],[162,124]],5,'#adb5bd')
c.fillStyle='#495057';c.lineWidth=5;c.beginPath();c.ellipse(108,148,16,6,0,0,T);c.fill();c.strokeStyle='#fff';c.lineWidth=9;c.stroke();c.strokeStyle='#111';c.lineWidth=5;c.stroke()
c.fillStyle=BIKE;c.lineWidth=4;c.beginPath();c.arc(...BB,8,0,T);c.fill();c.stroke()
const scarf=Array.from({length:7},(_,k)=>[128-15*k,112+6*sin(k*.9-T*t*2)*k/6+k*2.5+bob])
line(c,scarf,10,SCARF);c.strokeStyle=SCD;c.lineWidth=3;const e=scarf[6];for(const d of[-5,0,5])c.beginPath(),c.moveTo(e[0],e[1]+d),c.lineTo(e[0]-9,e[1]+d+2),c.stroke();c.strokeStyle='#111'
c.fillStyle=DEN;c.lineWidth=5;c.beginPath();c.moveTo(100,150+bob);c.lineTo(108,124+bob);c.lineTo(132,122+bob);c.lineTo(132,152+bob);c.quadraticCurveTo(116,160,100,150+bob);c.closePath();c.fill();c.stroke()
leg(0,DEN)
c.fillStyle=TOP;c.lineWidth=5;c.beginPath();c.moveTo(112,104+bob);c.lineTo(134,100+bob);c.lineTo(140,128+bob);c.lineTo(110,132+bob);c.closePath();c.fill();c.save();c.clip();c.strokeStyle=STR;c.lineWidth=4;for(const y of[108,116,124])c.beginPath(),c.moveTo(100,y+bob+2),c.lineTo(150,y+bob-3),c.stroke();c.restore();c.stroke()
c.fillStyle=DEN;c.lineWidth=4;c.beginPath();c.moveTo(116,118+bob);c.lineTo(134,114+bob);c.lineTo(136,128+bob);c.lineTo(114,132+bob);c.closePath();c.fill();c.stroke()
const sh=[130,108+bob],gp=[164,124]
line(c,[sh,[148,122+bob/2],gp],8,SKIN);c.fillStyle=SKIN;c.lineWidth=4;c.beginPath();c.arc(...gp,6.5,0,T);c.fill();c.stroke()
c.fillStyle=SCARF;c.lineWidth=5;c.beginPath();c.ellipse(128,104+bob,16,8,-.2,0,T);c.fill();c.stroke()
c.save();c.translate(132,72+bob);c.rotate(.05);c.scale(.54,.54);c.translate(-128,-120)
c.lineWidth=9;c.fillStyle=HAIR;c.beginPath();c.moveTo(124,34);c.bezierCurveTo(192,34,206,96,196,160);c.quadraticCurveTo(180,170,168,160);c.lineTo(70,160);c.quadraticCurveTo(46,168,44,140);c.bezierCurveTo(26,124,30,104,46,110);c.bezierCurveTo(46,60,70,34,124,34);c.fill();c.stroke()
c.fillStyle=SKIN;c.beginPath();c.moveTo(78,96);c.bezierCurveTo(74,152,104,184,132,186);c.bezierCurveTo(160,184,190,152,186,96);c.bezierCurveTo(186,44,78,44,78,96);c.fill();c.stroke()
eye(c,110,140,-1);eye(c,160,140,1)
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(136+d*42,162,12,6,0,0,T),c.fill()
c.fillStyle='#c92a2a';c.lineWidth=6;c.beginPath();c.moveTo(126,164);c.quadraticCurveTo(140,184,154,164);c.closePath();c.fill();c.stroke()
c.fillStyle=HAIR;c.lineWidth=9;c.beginPath();c.moveTo(72,148);c.bezierCurveTo(56,74,94,40,134,40);c.bezierCurveTo(178,40,208,78,192,148)
c.quadraticCurveTo(186,118,178,104);c.quadraticCurveTo(170,102,164,112);c.quadraticCurveTo(158,98,148,94);c.quadraticCurveTo(142,106,134,112)
c.quadraticCurveTo(128,98,120,94);c.quadraticCurveTo(114,106,106,112);c.quadraticCurveTo(100,98,92,98);c.quadraticCurveTo(86,106,82,112);c.quadraticCurveTo(74,124,72,148);c.closePath();c.fill();c.stroke()
c.strokeStyle=HL;c.lineWidth=8;for(const[a0,a1]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(132,104,56,PI*a0,PI*a1),c.stroke();c.strokeStyle='#111'
c.fillStyle='#ffd43b';c.lineWidth=7;c.beginPath();c.roundRect(150,70,34,13,6);c.fill();c.stroke()
c.restore()
const bx=178,by=118
c.save();c.translate(bx+19,by-6+bob*.5);c.scale(1.25,1.25)
for(const d of[-1,1]){c.save();c.translate(d*11,-8);c.rotate(d*(.5+.35*sin(T*t*3+d)));c.fillStyle=EAR;c.lineWidth=4;c.beginPath();c.ellipse(0,9,6,11,0,0,T);c.fill();c.stroke();c.restore()}
c.fillStyle=PUP;c.lineWidth=5;c.beginPath();c.ellipse(0,0,15,13,0,0,T);c.fill();c.stroke()
c.fillStyle=EAR;c.beginPath();c.ellipse(-6,-6,6,5,0,0,T);c.fill()
c.fillStyle='#111';for(const x of[-5,6])c.beginPath(),c.arc(x,-1,2.6,0,T),c.fill()
c.beginPath();c.ellipse(1,4,3.5,2.5,0,0,T);c.fill()
c.fillStyle='#ff8fab';c.lineWidth=2.5;c.beginPath();c.moveTo(-2,8);c.quadraticCurveTo(1,16+2*sin(T*t*3),5,8);c.closePath();c.fill();c.stroke();c.restore()
c.fillStyle=BAS;c.lineWidth=5;c.beginPath();c.moveTo(bx,by+8);c.lineTo(bx+38,by+8);c.lineTo(bx+34,by+32);c.lineTo(bx+4,by+32);c.closePath();c.fill();c.stroke()
c.strokeStyle=BSD;c.lineWidth=3;for(const y of[16,24])c.beginPath(),c.moveTo(bx+2,by+y),c.lineTo(bx+36,by+y),c.stroke();for(const x of[10,19,28])c.beginPath(),c.moveTo(bx+x,by+10),c.lineTo(bx+x-1,by+30),c.stroke();c.strokeStyle='#111'
c.fillStyle=PUP;c.lineWidth=3.5;for(const x of[8,28])c.beginPath(),c.ellipse(bx+x,by+8,5,4,0,0,T),c.fill(),c.stroke()
c.fillStyle='#ffd43b';c.lineWidth=3.5;c.beginPath();for(let k=0;k<10;k++){const r=k%2?3:7,b=k*PI/5-PI/2;c.lineTo(bx+19+r*cos(b),by+21+r*sin(b))}c.closePath();c.fill();c.stroke()
}
+72
View File
@@ -0,0 +1,72 @@
// birthday girl in a party hat behind her cake: makes a wish, puffs her cheeks and blows the candles out one by one, confetti pops, the candles spark back on
const{sin,cos,PI,max,min}=Math,T=2*PI
export const frames=16,delay=90
const SKIN='#ffe3d1',HAIR='#8f1d4a',HD='#6a1236',HL='#f3a6c4',EYE='#4dabf7',ED='#1864ab',DRESS='#ffd43b',DD='#fab005',HAT='#4dabf7',HS='#fff',POM='#ff6b6b',CAKE='#fff4e6',CR='#f783ac',CRD='#e64980',BERRY='#fa5252',CAN=['#69db7c','#b197fc','#ffa94d'],FL='#ffd43b',FO='#ff922b',BL='#ffa8a8',MO='#c92a2a',CONF=['#ff6b6b','#4dabf7','#ffd43b','#69db7c','#b197fc']
const cl=x=>max(0,min(1,x))
const eye=(c,x,y,d)=>{
c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill()
c.save();c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.clip();c.fillStyle=EYE;c.fill();c.fillStyle=ED;c.beginPath();c.ellipse(x,y-8,13,10,0,0,T);c.fill();c.restore()
c.lineWidth=2.5;c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.stroke()
c.fillStyle='#111';c.beginPath();c.ellipse(x,y+3,5.5,7.5,0,0,T);c.fill()
c.fillStyle='#fff';c.beginPath();c.arc(x-4,y-5,4.5,0,T);c.fill();c.beginPath();c.arc(x+5,y+8,2,0,T);c.fill()
c.lineWidth=6;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke()
}
export default(c,t)=>{
const wish=t<.16,puff=t>=.16&&t<.26,blow=t>=.26&&t<.56,happy=t>=.56&&t<.84,out=[.32,.4,.48],relit=t>=.84
c.save();c.translate(128,-12);c.scale(.86,.86);c.translate(-128,0)
// braid over her shoulder, then back hair
c.lineWidth=6;c.fillStyle=HAIR;for(let k=0;k<5;k++){const y=150+k*18;c.beginPath();c.ellipse(186+k*2,y,13-k,11,.2,0,T);c.fill();c.stroke()}
c.fillStyle='#69db7c';c.beginPath();c.arc(196,240,7,0,T);c.fill();c.stroke()
c.fillStyle=HD;c.beginPath();c.moveTo(128,40);c.bezierCurveTo(196,40,206,100,196,156);c.lineTo(60,156);c.bezierCurveTo(50,100,60,40,128,40);c.fill();c.stroke()
// dress shoulders
c.fillStyle=DRESS;c.beginPath();c.moveTo(100,190);c.quadraticCurveTo(60,198,50,262);c.lineTo(206,262);c.quadraticCurveTo(196,198,156,190);c.closePath();c.fill();c.stroke()
c.fillStyle='#fff';c.lineWidth=5;for(const d of[-1,1])c.beginPath(),c.moveTo(128,206),c.quadraticCurveTo(128+d*22,190,128+d*30,194),c.quadraticCurveTo(128+d*24,210,128,206),c.fill(),c.stroke()
c.fillStyle=SKIN;c.lineWidth=6;c.beginPath();c.rect(116,170,24,26);c.fill();c.beginPath();c.moveTo(116,170);c.lineTo(116,192);c.moveTo(140,170);c.lineTo(140,192);c.stroke()
// face
c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke()
if(puff||blow){const pf=puff?1.25:1.1;c.fillStyle=SKIN;for(const d of[-1,1])c.beginPath(),c.arc(128+d*42,158,14*pf,d<0?PI*.5:-PI*.5,d<0?PI*1.5:PI*.5),c.fill(),c.stroke()}
if(wish||happy||puff){c.lineWidth=6;for(const x of[103,153])c.beginPath(),wish||puff?c.arc(x,140,12,PI*.15,PI*.85):c.arc(x,146,13,PI*1.15,PI*1.85),c.stroke()}
else{eye(c,103,140,-1);eye(c,153,140,1)}
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*42,161,13,7,0,0,T),c.fill()
c.lineWidth=3.5;c.fillStyle=MO;c.beginPath()
if(blow)c.ellipse(128,170,5,6,0,0,T),c.fill(),c.stroke()
else if(puff)c.moveTo(122,170),c.lineTo(134,170),c.stroke()
else if(happy)c.moveTo(114,164),c.quadraticCurveTo(128,186,142,164),c.closePath(),c.fill(),c.stroke()
else c.arc(128,166,7,.15*PI,.85*PI),c.stroke()
// bangs
c.lineWidth=6;c.fillStyle=HAIR;c.beginPath();c.moveTo(66,146);c.bezierCurveTo(50,74,88,40,128,40);c.bezierCurveTo(168,40,206,74,190,146)
c.quadraticCurveTo(186,118,178,104);c.quadraticCurveTo(170,102,164,110);c.quadraticCurveTo(160,96,150,92);c.quadraticCurveTo(144,104,136,110)
c.quadraticCurveTo(132,96,122,90);c.quadraticCurveTo(116,104,106,108);c.quadraticCurveTo(102,96,92,96);c.quadraticCurveTo(86,106,80,112);c.quadraticCurveTo(70,124,66,146);c.closePath();c.fill();c.stroke()
c.strokeStyle=HL;c.lineWidth=5;for(const[a,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,56,PI*a,PI*e),c.stroke();c.strokeStyle='#111'
// party hat
c.save();c.translate(82,74);c.rotate(-.55)
c.lineWidth=6;c.fillStyle=HAT;c.beginPath();c.moveTo(-24,6);c.lineTo(0,-52);c.lineTo(24,6);c.closePath();c.fill();c.stroke()
c.save();c.clip();c.strokeStyle=HS;c.lineWidth=7;for(const y of[-36,-14])c.beginPath(),c.moveTo(-30,y+12),c.lineTo(30,y-4),c.stroke();c.restore()
c.beginPath();c.moveTo(-24,6);c.lineTo(0,-52);c.lineTo(24,6);c.closePath();c.stroke()
c.fillStyle=POM;c.beginPath();c.arc(0,-54,9,0,T);c.fill();c.stroke()
c.restore()
c.restore()
// wind lines while blowing
if(blow)for(const[dx,o]of[[-14,0],[0,.33],[14,.66]]){const p=(t*8+o)%1;for(const[w,s]of[[7,'#111'],[3,'#fff']])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.moveTo(128+dx*.6,142+10*p),c.lineTo(128+dx*(1+.5*p),152+10*p),c.stroke()}
c.strokeStyle='#111'
// cake
c.lineWidth=6;c.fillStyle=CAKE;c.beginPath();c.moveTo(52,206);c.lineTo(52,246);c.quadraticCurveTo(128,262,204,246);c.lineTo(204,206);c.closePath();c.fill();c.stroke()
c.strokeStyle=CR;c.lineWidth=5;c.beginPath();c.moveTo(56,230);c.quadraticCurveTo(128,244,200,230);c.stroke();c.strokeStyle='#111'
c.fillStyle=CR;c.beginPath();c.moveTo(50,206);for(let k=0;k<=8;k++){const x=50+k*19.5;c.quadraticCurveTo(x-10,222+(k%2)*6,x,210)}c.lineTo(206,206);c.closePath();c.fill();c.stroke()
c.beginPath();c.ellipse(128,204,78,16,0,0,T);c.fill();c.stroke()
c.fillStyle=BERRY;c.lineWidth=4;for(const x of[78,178])c.beginPath(),c.moveTo(x,190),c.quadraticCurveTo(x+11,196,x,212),c.quadraticCurveTo(x-11,196,x,190),c.fill(),c.stroke()
// candles and flames
for(const[k,x]of[[0,100],[1,128],[2,156]]){
c.fillStyle=CAN[k];c.lineWidth=5;c.beginPath();c.roundRect(x-6,178,12,24,3);c.fill();c.stroke()
c.strokeStyle='#fff';c.lineWidth=3;for(const y of[186,196])c.beginPath(),c.moveTo(x-5,y+3),c.lineTo(x+5,y-3),c.stroke();c.strokeStyle='#111'
c.lineWidth=3;c.beginPath();c.moveTo(x,178);c.lineTo(x,172);c.stroke()
const lit=t<out[k]||relit,lean=blow&&lit?6*cl((t-.26)/.06):0
if(lit){const f=1+.12*sin(4*T*t+k*2),pop=relit?cl((t-.84)/.06):1
c.save();c.translate(x,171);c.scale(pop,pop);c.fillStyle=FO;c.lineWidth=4;c.beginPath();c.moveTo(0,0);c.bezierCurveTo(-9,-2,-6,-14,lean,-22*f);c.bezierCurveTo(6,-14,9,-2,0,0);c.fill();c.stroke()
c.fillStyle=FL;c.beginPath();c.moveTo(0,-3);c.quadraticCurveTo(-4,-8,lean*.6,-14*f);c.quadraticCurveTo(4,-8,0,-3);c.fill();c.restore()
if(relit&&t<.92){c.lineWidth=3;for(let a=0;a<4;a++)c.beginPath(),c.moveTo(x+12*cos(a*PI/2+.7),160+12*sin(a*PI/2+.7)),c.lineTo(x+18*cos(a*PI/2+.7),160+18*sin(a*PI/2+.7)),c.stroke()}}
else{const p=cl((t-out[k])/.3);if(p<1){c.globalAlpha=1-p;for(const[w,s]of[[7,'#111'],[3,'#dee2e6']])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.moveTo(x,170),c.bezierCurveTo(x-8,158-20*p,x+8,148-20*p,x,136-20*p),c.stroke();c.globalAlpha=1;c.strokeStyle='#111'}}
}
// confetti burst
if(happy){const p=cl((t-.56)/.28);for(let k=0;k<10;k++){const a=-PI/2+(k-4.5)*.3,r=40+70*p,x=128+r*cos(a)*1.4,y=130+r*sin(a)+90*p*p;c.save();c.translate(x,y);c.rotate(k+p*6);c.fillStyle=CONF[k%5];c.lineWidth=3;c.beginPath();c.rect(-5,-3,10,6);c.fill();c.stroke();c.restore()}}
}
+55
View File
@@ -0,0 +1,55 @@
// peach-haired girl rolled up in a starry blanket burrito, only her sleepy face peeking out, wobbling side to side with a slow blink and a drifting z
const{sin,cos,PI}=Math,T=2*PI
export const frames=12,delay=110
const SKIN='#ffe3d1',HAIR='#ffcfa8',HD='#f2a26b',HL='#fff0e4',EYE='#51cf66',ED='#2b8a3e',BLK='#91a7ff',BKD='#5c7cfa',LIN='#fcc2d7',SOCK='#fff',SKS='#ff8787',BL='#ffa8a8',MO='#c92a2a',ZC='#d0bfff'
const eye=(c,x,y,d,shut)=>{
if(shut){c.lineWidth=6;c.beginPath();c.arc(x,y-2,13,PI*.15,PI*.85);c.stroke();return}
c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill()
c.save();c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.clip();c.fillStyle=EYE;c.fill();c.fillStyle=ED;c.beginPath();c.ellipse(x,y-8,13,10,0,0,T);c.fill()
c.fillStyle='#111';c.beginPath();c.ellipse(x,y+4,5.5,7.5,0,0,T);c.fill();c.fillStyle='#fff';c.beginPath();c.arc(x-4,y+6,3,0,T);c.fill();c.restore()
c.lineWidth=2.5;c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.stroke()
c.fillStyle=SKIN;c.beginPath();c.moveTo(x-19,y+3);c.quadraticCurveTo(x,y-10,x+19,y+3);c.lineTo(x+19,y-24);c.lineTo(x-19,y-24);c.fill()
c.lineWidth=6;c.beginPath();c.moveTo(x-16,y+3);c.quadraticCurveTo(x,y-9,x+16,y+3);c.moveTo(x+d*15,y+2);c.lineTo(x+d*20,y-2);c.stroke()
}
const star=(c,x,y,r)=>{c.beginPath();for(let k=0;k<10;k++){const rr=k%2?r*.45:r,a=k*PI/5-PI/2;c.lineTo(x+cos(a)*rr,y+sin(a)*rr)}c.closePath();c.fill();c.stroke()}
export default(c,t,i)=>{
const a=.12*sin(T*t),shut=i==7||i==8
c.fillStyle='rgba(17,17,17,.15)';c.beginPath();c.ellipse(128,246,56,6,0,0,T);c.fill()
c.save();c.translate(128,244);c.rotate(a);c.translate(-128,-244)
// socks peeking out the bottom
c.lineWidth=5;for(const d of[-1,1]){c.fillStyle=SOCK;c.beginPath();c.ellipse(128+d*18,238,13,8,0,0,T);c.fill();c.stroke();c.strokeStyle=SKS;c.lineWidth=3;c.beginPath();c.moveTo(128+d*18-10,236);c.lineTo(128+d*18+10,236);c.stroke();c.strokeStyle='#111';c.lineWidth=5}
// the burrito
const body=()=>{c.beginPath();c.moveTo(128,32);c.bezierCurveTo(206,32,214,120,204,190);c.quadraticCurveTo(196,236,128,236);c.quadraticCurveTo(60,236,52,190);c.bezierCurveTo(42,120,50,32,128,32);c.closePath()}
c.lineWidth=6;c.fillStyle=BLK;body();c.fill()
c.save();body();c.clip()
c.fillStyle='#fff';c.lineWidth=2.5;for(const[x,y]of[[70,170],[176,150],[110,214],[160,206],[66,96],[192,90],[92,140]])star(c,x,y,6)
// wrapped edge spiralling round the front, with the lining showing
c.lineWidth=6;c.fillStyle=LIN;c.beginPath();c.moveTo(40,180);c.quadraticCurveTo(140,176,220,226);c.lineTo(220,240);c.quadraticCurveTo(140,192,40,196);c.closePath();c.fill();c.stroke()
c.fillStyle=BLK;c.beginPath();c.moveTo(40,196);c.quadraticCurveTo(140,192,220,240);c.lineTo(220,260);c.lineTo(40,260);c.closePath();c.fill()
c.fillStyle='#fff';c.lineWidth=2.5;for(const[x,y]of[[82,216],[140,224]])star(c,x,y,6)
c.lineWidth=6;c.beginPath();c.moveTo(40,196);c.quadraticCurveTo(140,192,220,240);c.stroke()
c.restore()
c.lineWidth=6;body();c.stroke()
// face peeking out of the opening, under a folded hood of blanket
c.fillStyle=LIN;c.beginPath();c.ellipse(128,108,70,62,0,0,T);c.fill();c.stroke()
c.save();c.beginPath();c.ellipse(128,110,60,53,0,0,T);c.clip()
c.fillStyle=HD;c.fillRect(60,50,140,130)
c.translate(128,118);c.scale(.82,.82);c.translate(-128,-132)
c.lineWidth=7;c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke()
eye(c,103,142,-1,shut);eye(c,153,142,1,shut)
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,164,14,7,0,0,T),c.fill()
c.lineWidth=2.5;for(const d of[-1,1])for(const k of[-5,0,5])c.beginPath(),c.moveTo(128+d*44+k-2,167),c.lineTo(128+d*44+k+2,161),c.stroke()
c.lineWidth=4;c.beginPath();c.moveTo(120,172);c.quadraticCurveTo(124,176,128,173);c.quadraticCurveTo(132,176,136,172);c.stroke()
c.lineWidth=7;c.fillStyle=HAIR;c.beginPath();c.moveTo(60,160);c.bezierCurveTo(46,74,88,36,128,36);c.bezierCurveTo(168,36,210,74,196,160)
c.quadraticCurveTo(186,124,180,108);c.quadraticCurveTo(170,100,162,114);c.quadraticCurveTo(154,96,140,94);c.quadraticCurveTo(136,108,128,114)
c.quadraticCurveTo(120,98,106,96);c.quadraticCurveTo(102,108,94,114);c.quadraticCurveTo(86,100,76,108);c.quadraticCurveTo(68,128,60,160);c.closePath();c.fill();c.stroke()
c.strokeStyle=HL;c.lineWidth=6;for(const[a0,e]of[[1.3,1.4],[1.46,1.56],[1.62,1.7]])c.beginPath(),c.arc(128,110,56,PI*a0,PI*e),c.stroke()
c.restore()
c.strokeStyle='#111';c.lineWidth=6;c.beginPath();c.ellipse(128,110,60,53,0,0,T);c.stroke()
c.restore()
// z drifting up and fading
const p=(t*2)%1,s=.6+.6*p
c.save();c.globalAlpha=p<.8?1:1-(p-.8)/.2;c.translate(214+8*p,44-28*p);c.scale(s,s);c.rotate(-.2)
for(const[l,st]of[[9,'#111'],[4,ZC]])c.lineWidth=l,c.strokeStyle=st,c.beginPath(),c.moveTo(-8,-8),c.lineTo(8,-8),c.lineTo(-8,8),c.lineTo(8,8),c.stroke()
c.restore()
}
+61
View File
@@ -0,0 +1,61 @@
// close-up of a girl with long wavy ash-blonde hair breathing in a bouquet with her eyes shut, then sighing dreamily, petals drifting by
const{sin,cos,PI,max,min}=Math,T=2*PI
export const frames=16,delay=90
const SKIN='#ffe3d1',HAIR='#d8cbb0',HD='#a99c80',HL='#f4efe3',EYE='#b197fc',ED='#7048e8',BL='#ffa8a8',DR='#b2d8a8',WR='#faa2c1',WRD='#f06595',ROSE='#ff8787',RD='#e03131',DAI='#fff',YEL='#ffd43b',LEAF='#69db7c',PET='#ffc9de'
const ds=(c,a,b,s,f)=>{for(const[l,k]of[[a,'#111'],[b,s]])c.lineWidth=l,c.strokeStyle=k,c.beginPath(),f(),c.stroke();c.strokeStyle='#111'}
const eye=(c,x,y,d,lid)=>{
const u=-lid*.7
c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill()
c.save();c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.clip()
c.beginPath();c.ellipse(x+1,y+2+u,11.5,15,0,0,T);c.fillStyle=EYE;c.fill();c.lineWidth=2.5;c.stroke()
c.save();c.clip();c.fillStyle=ED;c.beginPath();c.ellipse(x+1,y-8+u,13,10,0,0,T);c.fill();c.restore()
c.fillStyle='#111';c.beginPath();c.ellipse(x+1,y+3+u,5.5,7.5,0,0,T);c.fill()
c.fillStyle='#fff';c.beginPath();c.arc(x-3,y-2+u,5.5,0,T);c.fill();c.beginPath();c.arc(x+6,y+8+u,2.5,0,T);c.fill()
c.lineWidth=1.5;c.beginPath();for(let k=0;k<8;k++){const a=k*PI/4,q=k%2?1.6:4.5;c.lineTo(x+5+cos(a)*q,y+2+u+sin(a)*q)}c.closePath();c.fill();c.restore()
c.lineWidth=7;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke()
}
const shut=(c,x,y,d)=>{c.lineWidth=6;c.beginPath();c.arc(x,y-6,15,.12*PI,.88*PI);c.stroke();c.lineWidth=4;c.beginPath();for(const a of[.25,.5,.75])c.moveTo(x+15*cos(a*PI)*.9,y-6+15*sin(a*PI)),c.lineTo(x+19*cos(a*PI)*.9,y-6+19*sin(a*PI)+2);c.moveTo(x+d*14,y-1);c.lineTo(x+d*21,y+2);c.stroke()}
const petal=(c,x,y,a)=>{c.save();c.translate(x,y);c.rotate(a);c.fillStyle=PET;c.lineWidth=3.5;c.beginPath();c.moveTo(0,-9);c.quadraticCurveTo(9,-2,0,9);c.quadraticCurveTo(-9,-2,0,-9);c.fill();c.stroke();c.restore()}
const rose=(c,x,y,r)=>{c.fillStyle=ROSE;c.lineWidth=5;c.beginPath();c.arc(x,y,r,0,T);c.fill();c.stroke();c.strokeStyle=RD;c.lineWidth=3;c.beginPath();for(let a=0;a<3*T;a+=.2){const q=r*.75*(1-a/(3*T));a?c.lineTo(x+q*cos(a),y+q*sin(a)):c.moveTo(x+q,y)}c.stroke();c.strokeStyle='#111'}
const daisy=(c,x,y,r)=>{c.fillStyle=DAI;c.lineWidth=3.5;for(let k=0;k<8;k++){const a=k*PI/4;c.beginPath();c.ellipse(x+cos(a)*r*.62,y+sin(a)*r*.62,r*.42,r*.22,a,0,T);c.fill();c.stroke()}c.fillStyle=YEL;c.beginPath();c.arc(x,y,r*.32,0,T);c.fill();c.stroke()}
export default(c,t)=>{
const sn=t<.5,b=sn?sin(PI*t/.5):0,lid=sn?0:6+2*sin(2*T*t),g=sn?0:sin(PI*(t-.5)/.5)
c.lineWidth=7;c.fillStyle=HD;c.beginPath();c.moveTo(128,30)
c.bezierCurveTo(214,30,228,110,222,178);for(let k=0;k<4;k++)c.quadraticCurveTo(236-(k%2)*20,190+k*16,226-(k%2)*8,204+k*16)
c.lineTo(30,254);for(let k=3;k>=0;k--)c.quadraticCurveTo(20+(k%2)*20,198+k*16,30+(k%2)*8,186+k*16)
c.bezierCurveTo(28,110,42,30,128,30);c.fill();c.stroke()
c.fillStyle=DR;c.beginPath();c.moveTo(100,196);c.quadraticCurveTo(64,204,58,256);c.lineTo(198,256);c.quadraticCurveTo(192,204,156,196);c.closePath();c.fill();c.stroke()
c.fillStyle='#fff';c.lineWidth=5;for(const d of[-1,1])c.beginPath(),c.moveTo(128,210),c.quadraticCurveTo(128+d*16,196,128+d*30,198),c.quadraticCurveTo(128+d*26,214,128,214),c.fill(),c.stroke()
c.fillStyle=SKIN;c.lineWidth=6;c.beginPath();c.moveTo(114,170);c.lineTo(114,198);c.quadraticCurveTo(128,212,142,198);c.lineTo(142,170);c.fill();c.beginPath();c.moveTo(114,170);c.lineTo(114,196);c.moveTo(142,170);c.lineTo(142,196);c.stroke()
c.save();c.translate(128,110);c.scale(.92,.92);c.translate(-128,-120)
c.lineWidth=7;c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke()
if(t>.06&&sn)shut(c,103,140,-1),shut(c,153,140,1);else eye(c,103,140,-1,lid),eye(c,153,140,1,lid)
const bl=1+.25*g
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,163,13*bl,7*bl,0,0,T),c.fill()
c.lineWidth=2.5;for(const d of[-1,1])for(const x of[-6,0,6])c.beginPath(),c.moveTo(128+d*44+x-2,167),c.lineTo(128+d*44+x+2,159),c.stroke()
c.beginPath();c.moveTo(129,152);c.lineTo(127,157);c.stroke()
c.lineWidth=4.5;c.beginPath()
if(sn)c.moveTo(121,168),c.quadraticCurveTo(128,173,135,168),c.stroke();else c.fillStyle='#c92a2a',c.moveTo(121,167),c.quadraticCurveTo(129,176+4*g,137,167),c.closePath(),c.fill(),c.stroke()
c.lineWidth=7;c.fillStyle=HAIR;c.beginPath();c.moveTo(66,170)
c.bezierCurveTo(46,80,86,40,128,40);c.bezierCurveTo(170,40,212,80,190,170)
c.quadraticCurveTo(190,130,182,108);c.quadraticCurveTo(170,96,152,92);c.quadraticCurveTo(150,104,144,110)
c.quadraticCurveTo(128,96,108,90);c.quadraticCurveTo(112,104,106,112);c.quadraticCurveTo(92,104,84,96)
c.quadraticCurveTo(86,108,80,118);c.quadraticCurveTo(70,140,66,170);c.closePath();c.fill();c.stroke()
for(const d of[-1,1]){c.beginPath();c.moveTo(128+d*56,110);c.bezierCurveTo(128+d*70,140,128+d*58,170,128+d*70,210);c.quadraticCurveTo(128+d*56,206,128+d*50,186);c.bezierCurveTo(128+d*44,160,128+d*54,140,128+d*46,116);c.closePath();c.fill();c.stroke()}
c.strokeStyle=HL;c.lineWidth=6;for(const[s,e]of[[1.26,1.38],[1.46,1.54],[1.62,1.72]])c.beginPath(),c.arc(128,108,58,PI*s,PI*e),c.stroke();c.strokeStyle='#111'
c.fillStyle=YEL;c.lineWidth=5;c.save();c.translate(170,74);c.rotate(.4);c.beginPath();c.roundRect(-14,-5,28,10,5);c.fill();c.stroke();c.restore()
c.restore()
if(sn&&b>.4)for(const k of[0,1,2])ds(c,6,2.5,'#fff',()=>{const x=146+k*8,y=150-k*3;c.moveTo(x,y);c.quadraticCurveTo(x+4,y-4,x+8,y)})
if(g>.05){const s=g,x=170+36*(t-.5),y=168-40*(t-.5);c.fillStyle='#fff';c.lineWidth=3.5;c.beginPath();for(const[a,q,r]of[[0,0,9],[10,-5,7],[18,2,6]])c.moveTo(x+a*s+r*s,y+q*s),c.arc(x+a*s,y+q*s,r*s,0,T);c.fill();c.stroke()
c.fillStyle='#f06595';c.lineWidth=3.5;for(const[x0,o]of[[204,0],[222,.25]]){const p=min(1,max(0,(t-.5-o*.4)/.4)),h=sin(PI*p);if(h>.1){const x=x0+4*sin(p*T),y=130-50*p;c.save();c.translate(x,y);c.scale(h,h);c.beginPath();c.moveTo(0,8);c.bezierCurveTo(-13,-1,-9,-12,0,-5);c.bezierCurveTo(9,-12,13,-1,0,8);c.restore();c.fill();c.stroke()}}}
const bx=82+8*b,by=208-10*b,Z=.86
c.save();c.translate(bx,by);c.rotate(-.35);c.scale(Z,Z)
c.fillStyle=LEAF;c.lineWidth=5;for(const[a,l]of[[-1.2,30],[-2,30],[-.3,28]])c.beginPath(),c.ellipse(cos(a)*l,sin(a)*l,14,7,a,0,T),c.fill(),c.stroke()
rose(c,-14,-22,15);daisy(c,16,-24,15);rose(c,4,-42,13);daisy(c,-30,-44,12);c.fillStyle=YEL;c.lineWidth=4;c.beginPath();c.arc(28,-50,8,0,T);c.fill();c.stroke()
c.fillStyle=WR;c.lineWidth=6;c.beginPath();c.moveTo(-34,-14);c.lineTo(34,-14);c.lineTo(6,60);c.lineTo(-6,60);c.closePath();c.fill();c.stroke()
c.strokeStyle=WRD;c.lineWidth=3;c.beginPath();c.moveTo(-14,-10);c.lineTo(0,52);c.moveTo(14,-10);c.lineTo(2,52);c.stroke();c.strokeStyle='#111'
c.fillStyle=YEL;c.lineWidth=4;for(const d of[-1,1])c.beginPath(),c.ellipse(d*10,18,10,6,d*.5,0,T),c.fill(),c.stroke()
c.restore()
c.fillStyle=SKIN;c.lineWidth=5;for(const[x,y]of[[-10,22],[12,30]]){const a=-.35,X=bx+Z*(x*cos(a)-y*sin(a)),Y=by+Z*(x*sin(a)+y*cos(a));c.beginPath();c.ellipse(X,Y,13,11,0,0,T);c.fill();c.stroke()}
for(const[o,y0]of[[0,40],[.5,70]]){const p=(t+o)%1;petal(c,250-200*p,y0+80*p+10*sin(p*T*2),p*T*1.5+o*4)}
}
+68
View File
@@ -0,0 +1,68 @@
// lilac-haired girl with two braids blowing soap bubbles through a wand, rainbow-sheen bubbles growing, drifting up and popping
const{sin,cos,PI,min,max}=Math,T=2*PI
export const frames=16,delay=80
const SKIN='#ffe3d1',HAIR='#d0bfff',HD='#9775fa',HL='#f3f0ff',EYE='#4c6ef5',ED='#364fc7',DR='#ffc9c9',DD='#ff8787',COL='#fff',BOW='#69db7c',WAND='#ffd43b',BUB='#f8f9fa',BL='#ffa8a8',MO='#c92a2a'
const ease=x=>x<=0?0:x>=1?1:x*x*(3-2*x)
const eye=(c,x,y,d)=>{
c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill()
c.save();c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.clip();c.fillStyle=EYE;c.fill();c.fillStyle=ED;c.beginPath();c.ellipse(x,y-8,13,10,0,0,T);c.fill()
c.fillStyle='#111';c.beginPath();c.ellipse(x+4,y+1,5.5,7.5,0,0,T);c.fill();c.fillStyle='#fff';c.beginPath();c.arc(x,y-6,4.5,0,T);c.fill();c.beginPath();c.arc(x+8,y+6,2,0,T);c.fill();c.restore()
c.lineWidth=2.5;c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.stroke()
c.lineWidth=6;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke()
}
// soap bubble with a rainbow sheen and a shine
const bubble=(c,x,y,r)=>{
c.fillStyle=BUB;c.lineWidth=3.5;c.beginPath();c.arc(x,y,r,0,T);c.fill();c.stroke()
c.lineWidth=max(2,r*.16);for(const[a,col]of[[0,'#faa2c1'],[1,'#a5d8ff'],[2,'#b2f2bb']]){c.strokeStyle=col;c.beginPath();c.arc(x,y,r*(.72-a*.13),PI*.15,PI*.6);c.stroke()}
c.strokeStyle='#111';c.fillStyle='#fff';c.beginPath();c.ellipse(x-r*.4,y-r*.4,r*.2,r*.13,-.7,0,T);c.fill()
}
const pop=(c,x,y,r)=>{for(const[l,s]of[[6,'#111'],[2.5,'#fff']]){c.lineWidth=l;c.strokeStyle=s;c.beginPath();for(let k=0;k<8;k++){const a=k*T/8;c.moveTo(x+cos(a)*r*.55,y+sin(a)*r*.55);c.lineTo(x+cos(a)*r,y+sin(a)*r)}c.stroke()}c.strokeStyle='#111'}
export default(c,t)=>{
const blow=sin(PI*((t*2)%1)),puff=blow>.3
c.lineWidth=6
c.save();c.translate(100,256);c.scale(.94,.94);c.translate(-128,-256)
// braids hang down either side, a tapered plait with chevrons
for(const d of[-1,1]){
const x=128+d*64
c.fillStyle=HAIR;c.beginPath();c.moveTo(x-14,138);c.quadraticCurveTo(x-16,190,x-8,228);c.lineTo(x+8,228);c.quadraticCurveTo(x+16,190,x+14,138);c.closePath();c.fill();c.stroke()
c.lineWidth=4;c.beginPath();for(let y=150;y<224;y+=14)c.moveTo(x-12+(y-150)/14,y),c.quadraticCurveTo(x,y+9,x+12-(y-150)/14,y);c.stroke();c.lineWidth=6
c.fillStyle=BOW;c.beginPath();c.moveTo(x,232);c.lineTo(x-12,222);c.lineTo(x-12,242);c.closePath();c.moveTo(x,232);c.lineTo(x+12,222);c.lineTo(x+12,242);c.closePath();c.fill();c.stroke()
c.beginPath();c.arc(x,232,4,0,T);c.fill();c.stroke()
c.fillStyle=HAIR;c.beginPath();c.moveTo(x-8,236);c.lineTo(x+8,236);c.lineTo(x,254);c.closePath();c.fill();c.stroke()
}
c.fillStyle=DR;c.beginPath();c.moveTo(100,190);c.quadraticCurveTo(62,198,54,256);c.lineTo(202,256);c.quadraticCurveTo(194,198,156,190);c.closePath();c.fill();c.stroke()
c.fillStyle=COL;for(const d of[-1,1])c.beginPath(),c.moveTo(128,200),c.quadraticCurveTo(128+d*30,186,128+d*36,204),c.quadraticCurveTo(128+d*20,214,128,204),c.closePath(),c.fill(),c.stroke()
c.fillStyle=DD;for(const[x,y]of[[86,236],[170,232],[128,246]])c.beginPath(),c.arc(x,y,5,0,T),c.fill()
c.fillStyle=SKIN;c.beginPath();c.moveTo(116,168);c.lineTo(116,194);c.quadraticCurveTo(128,204,140,194);c.lineTo(140,168);c.fill();c.beginPath();c.moveTo(116,168);c.lineTo(116,192);c.moveTo(140,168);c.lineTo(140,192);c.stroke()
c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke()
eye(c,103,140,-1);eye(c,153,140,1)
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,160,13+3*blow*(d>0),6,0,0,T),c.fill()
// pursed lips blowing, cheeks puffing
c.lineWidth=3.5;c.fillStyle=MO;c.beginPath();c.ellipse(140,170,4+2*blow,4+2*blow,0,0,T);c.fill();c.stroke()
if(puff){c.lineWidth=5;c.fillStyle=SKIN;c.beginPath();c.arc(166,164,8+5*blow,-PI*.5,PI*.5);c.fill();c.stroke()}
c.lineWidth=6;c.fillStyle=HAIR;c.beginPath();c.moveTo(68,150)
c.bezierCurveTo(52,74,88,36,128,36);c.bezierCurveTo(168,36,204,74,188,150)
c.quadraticCurveTo(184,124,180,108);c.quadraticCurveTo(160,90,150,112);c.quadraticCurveTo(146,92,126,90);c.quadraticCurveTo(120,104,112,110)
c.quadraticCurveTo(108,94,94,96);c.quadraticCurveTo(86,108,78,112);c.quadraticCurveTo(70,128,68,150);c.closePath();c.fill();c.stroke()
c.strokeStyle=HL;c.lineWidth=5;for(const[a,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,102,56,PI*a,PI*e),c.stroke()
c.strokeStyle='#111'
// wand held up to her lips
for(const[l,s]of[[24,'#111'],[15,SKIN]])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),c.moveTo(196,262),c.lineTo(186,214),c.stroke()
c.strokeStyle='#111'
for(const[l,s]of[[11,'#111'],[5,WAND]])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),c.moveTo(186,214),c.lineTo(166,180),c.stroke()
c.strokeStyle='#111';c.lineWidth=5;c.fillStyle=SKIN;c.beginPath();c.ellipse(188,214,12,13,0,0,T);c.fill();c.stroke()
c.lineWidth=3;c.beginPath();c.moveTo(178,210);c.lineTo(192,210);c.moveTo(178,218);c.lineTo(192,218);c.stroke()
for(const[l,s]of[[11,'#111'],[5,WAND]])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),c.arc(160,170,11,0,T),c.stroke()
c.strokeStyle='#111'
c.restore()
// ring position in screen space after the girl's transform
const rx=100+(160-128)*.94,ry=256+(170-256)*.94
// a bubble swelling on the wand, then the stream of released bubbles drifting up and popping
const g=(t*2)%1
if(g<.5)bubble(c,rx+ease(g/.5)*8,ry-ease(g/.5)*4,3+11*ease(g/.5))
for(const[o,dx,r]of[[0,4,15],[.25,-14,11],[.5,0,19],[.75,-22,10]]){
const p=(t+o)%1,x=rx+16+80*min(1,p*1.6)+dx*p+6*sin(T*p*2+o*7),y=ry-4-118*p
if(p<.86)bubble(c,x,y,r*min(1,.4+p*3))
else pop(c,x,y,r*1.4)
}
}
+51
View File
@@ -0,0 +1,51 @@
// chibi in a bunny-ear hoodie crouching and hopping, the floppy ears trailing behind the jump and flopping on landing
const{sin,cos,PI,max,round}=Math,T=2*PI
export const frames=16,delay=60
const SKIN='#ffe3d1',HAIR='#f8f0e3',HD='#d8c8a8',HL='#fff',EYE='#e64980',ED='#a61e4d',HOOD='#fff',HP='#faa2c1',HPD='#f06595',LEG='#b197fc',BL='#ffa8a8'
const eye=(c,x,y,d)=>{
c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill()
c.save();c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.clip();c.fillStyle=EYE;c.fill();c.fillStyle=ED;c.beginPath();c.ellipse(x,y-8,13,10,0,0,T);c.fill();c.restore()
c.lineWidth=3;c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.stroke()
c.fillStyle='#111';c.beginPath();c.ellipse(x,y+3,5.5,7.5,0,0,T);c.fill()
c.fillStyle='#fff';c.beginPath();c.arc(x-4,y-5,4.5,0,T);c.fill();c.beginPath();c.arc(x+5,y+8,2,0,T);c.fill()
c.lineWidth=8;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke()
}
const line=(c,pts,w,col)=>{for(const[lw,s]of[[w+8,'#111'],[w,col]]){c.lineWidth=lw;c.strokeStyle=s;c.beginPath();pts.forEach(([x,y],k)=>k?c.lineTo(x,y):c.moveTo(x,y));c.stroke()}c.strokeStyle='#111'}
const ear=(c,x,y,a,b)=>{
c.save();c.translate(x,y);c.rotate(a)
const p=(s,o)=>{c.beginPath();c.moveTo(-15*s,o);c.bezierCurveTo(-26*s,-44*s+o,(-14+b)*s,-76*s+o,b*s,-88*s+o);c.bezierCurveTo((16+b)*s,-76*s+o,26*s,-44*s+o,15*s,o);c.closePath()}
c.lineWidth=9;c.fillStyle=HOOD;p(1,0);c.fill();c.stroke()
c.fillStyle=HP;p(.55,-14);c.fill();c.restore()
}
export default(c,t)=>{
let sq=0,h=0,v=0
if(t<.2)sq=.8*sin(PI*t/.2)
else if(t<.8){const p=(t-.2)/.6;h=round(32*sin(PI*p));v=cos(PI*p);sq=-.25*v*v}
else sq=.6*sin(PI*(t-.8)/.2)
const happy=sq>.3,arm=t>=.2&&t<.8?1:0
c.fillStyle='#e9ecef';c.beginPath();c.ellipse(128,237,46-h*.4,7-h*.06,0,0,T);c.fill()
c.save();c.translate(128,233-h);c.scale(.86*(1+sq*.14),.86*(1-sq*.16));c.translate(-128,-230)
for(const x of[116,140]){line(c,[[x,196],[x,222]],9,LEG);c.lineWidth=5;c.fillStyle=HP;c.beginPath();c.ellipse(x+(x<128?-3:3),226,11,7,0,0,T);c.fill();c.stroke()}
for(const d of[-1,1]){const a=arm?2.3+.3*v:.4+.3*sq,sx=128+d*20,sy=146,hx=sx+d*26*sin(a),hy=sy+26*cos(a)
line(c,[[sx,sy],[hx,hy]],9,HOOD);c.lineWidth=5;c.fillStyle=SKIN;c.beginPath();c.arc(hx,hy,7,0,T);c.fill();c.stroke()}
c.fillStyle=HOOD;c.lineWidth=5;c.beginPath();c.moveTo(110,136);c.lineTo(146,136);c.quadraticCurveTo(156,166,154,198);c.lineTo(102,198);c.quadraticCurveTo(100,166,110,136);c.closePath();c.fill();c.stroke()
c.fillStyle=HP;c.beginPath();c.roundRect(112,172,32,16,6);c.fill();c.stroke()
c.lineWidth=3;c.beginPath();c.moveTo(122,140);c.lineTo(120,160);c.moveTo(134,140);c.lineTo(136,160);c.stroke()
c.fillStyle=HP;c.lineWidth=3;for(const x of[120,136])c.beginPath(),c.arc(x,162,4,0,T),c.fill(),c.stroke()
c.save();c.translate(128,96);c.scale(.62,.62);c.translate(-128,-128)
for(const d of[-1,1])ear(c,128+d*36,46,d*(arm?.95+.3*max(0,v):.28+.5*sq),d*(arm?10+24*v:14-20*sq))
c.lineWidth=9;c.fillStyle=HOOD;c.beginPath();c.moveTo(128,26);c.bezierCurveTo(214,26,226,110,212,170);c.quadraticCurveTo(206,200,176,204);c.lineTo(80,204);c.quadraticCurveTo(50,200,44,170);c.bezierCurveTo(30,110,42,26,128,26);c.fill();c.stroke()
c.fillStyle=HD;c.beginPath();c.moveTo(70,170);c.bezierCurveTo(56,90,90,52,128,52);c.bezierCurveTo(166,52,200,90,186,170);c.closePath();c.fill()
c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke()
if(happy){c.lineWidth=8;for(const x of[103,153])c.beginPath(),c.moveTo(x-15,144),c.quadraticCurveTo(x,128,x+15,144),c.stroke()}else eye(c,103,140,-1),eye(c,153,140,1)
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*42,162,13,7,0,0,T),c.fill()
c.lineWidth=6;if(arm||happy){c.fillStyle='#c92a2a';c.beginPath();c.moveTo(116,164);c.quadraticCurveTo(128,184,140,164);c.closePath();c.fill();c.stroke()}else{c.beginPath();c.moveTo(118,166);c.quadraticCurveTo(123,172,128,166);c.quadraticCurveTo(133,172,138,166);c.stroke()}
c.lineWidth=9;c.fillStyle=HAIR;c.beginPath();c.moveTo(72,136)
c.bezierCurveTo(64,84,94,58,128,58);c.bezierCurveTo(162,58,192,84,184,136)
c.quadraticCurveTo(180,112,172,102);c.quadraticCurveTo(164,108,158,114);c.quadraticCurveTo(152,98,142,94);c.quadraticCurveTo(136,106,128,110)
c.quadraticCurveTo(120,98,110,94);c.quadraticCurveTo(104,108,96,112);c.quadraticCurveTo(90,104,84,104);c.quadraticCurveTo(76,114,72,136);c.closePath();c.fill();c.stroke()
c.strokeStyle=HD;c.lineWidth=5;c.beginPath();for(const x of[110,146])c.moveTo(x,72),c.quadraticCurveTo(x+(x<128?-6:6),86,x+(x<128?-4:4),100);c.stroke();c.strokeStyle='#111'
for(const[lw,col]of[[30,'#111'],[18,HOOD]])c.lineWidth=lw,c.strokeStyle=col,c.beginPath(),c.moveTo(56,196),c.bezierCurveTo(40,100,80,46,128,46),c.bezierCurveTo(176,46,216,100,200,196),c.stroke()
c.strokeStyle='#111';c.restore()
c.restore()
}
+54
View File
@@ -0,0 +1,54 @@
// girl with emerald braids and a knit beanie roasts a marshmallow on a stick over a crackling campfire, it puffs up golden
const{sin,cos,PI,max,min}=Math,T=2*PI
export const frames=16,delay=80
const SKIN='#ffe3d1',HAIR='#12b886',HD='#087f5b',HL='#c3fae8',EYE='#a9744f',ED='#5c3d2e',BEAN='#ff922b',BND='#e8590c',JK='#e64980',JD='#a61e4d',LOG='#a9744f',LD='#7c5236',F1='#ff6b6b',F2='#ffa94d',F3='#ffe066',ST='#ced4da',MAL='#fff',TOAST='#f4b860',BL='#ff8787'
const line=(c,pts,w,col)=>{for(const[lw,s]of[[w+8,'#111'],[w,col]]){c.lineWidth=lw;c.strokeStyle=s;c.beginPath();pts.forEach(([x,y],k)=>k?c.lineTo(x,y):c.moveTo(x,y));c.stroke()}c.strokeStyle='#111'}
const flame=(c,x,y,w,h,col,lw)=>{c.fillStyle=col;c.lineWidth=lw;c.beginPath();c.moveTo(x-w,y);c.bezierCurveTo(x-w*1.1,y-h*.5,x-w*.2,y-h*.6,x+w*.1,y-h);c.bezierCurveTo(x+w*.3,y-h*.55,x+w*1.2,y-h*.45,x+w,y);c.quadraticCurveTo(x,y+w*.5,x-w,y);c.closePath();c.fill();c.stroke()}
export default(c,t,i)=>{
const p=T*t,glow=.5+.5*sin(p*4),puff=t<.6?min(1,t/.6):1-(t-.6)/.4*0,ms=1+.35*min(1,t/.7)*(t<.85?1:1-(t-.85)/.15),gold=min(1,t/.75)*(t<.9?1:1-(t-.9)/.1)
const fx=172,fy=208
c.fillStyle='#fff3bf';c.globalAlpha=.6+.2*glow;c.beginPath();c.ellipse(fx,fy+4,64,14,0,0,T);c.fill();c.globalAlpha=1
for(const[x,a]of[[-30,.28],[30,-.28]]){c.save();c.translate(fx+x*.4,fy+2);c.rotate(a);c.fillStyle=LOG;c.lineWidth=5;c.beginPath();c.roundRect(-34,-8,68,16,8);c.fill();c.stroke();c.fillStyle='#ffd8a8';c.beginPath();c.ellipse(x>0?30:-30,0,6,8,0,0,T);c.fill();c.stroke();c.strokeStyle=LD;c.lineWidth=3;c.beginPath();c.moveTo(-18,-2);c.lineTo(10,-2);c.stroke();c.strokeStyle='#111';c.restore()}
for(const[k,x]of[[0,-50],[1,-30],[2,32],[3,52]]){c.fillStyle=ST;c.lineWidth=4;c.beginPath();c.ellipse(fx+x,fy+12-(k%3)*2,11,7,0,0,T);c.fill();c.stroke()}
const fl=[[-14,26,58,F1,1.3],[12,22,52,F1,2.1],[0,30,74,F1,0]]
for(const[x,w,h,col,o]of fl)flame(c,fx+x+3*sin(p*3+o),fy,w,h*(1+.12*sin(p*4+o)),col,5)
for(const[x,w,h,o]of[[-6,18,48,.7],[8,16,42,2.4],[0,20,56,1.5]])flame(c,fx+x+2*sin(p*3+o),fy-2,w,h*(1+.14*sin(p*4+o)),F2,0)
flame(c,fx+2*sin(p*4),fy-4,12,34*(1+.12*sin(p*4+.3)),F3,0)
c.lineWidth=3.5;for(let k=0;k<3;k++){const u=(t*2+k/3)%1,x=fx-20+k*20+10*sin(u*PI*2+k),y=fy-70-u*70,r=4*(1-u);if(r>.8){c.fillStyle=k%2?F3:F2;c.beginPath();c.arc(x,y,r,0,T);c.fill();c.stroke()}}
const head=g=>{c.save();c.translate(76,94);c.rotate(-.05);c.scale(.56,.56);c.translate(-128,-120);g();c.restore()}
head(()=>{
for(const d of[-1,1]){c.save();c.translate(128+d*56,148);c.rotate(-d*.08);c.fillStyle=HAIR;c.lineWidth=9;for(let k=0;k<4;k++){c.beginPath();c.ellipse(0,k*24,15-k*1.5,16,0,0,T);c.fill();c.stroke()}c.fillStyle=BEAN;c.beginPath();c.ellipse(0,92,10,7,0,0,T);c.fill();c.stroke();c.restore()}
c.lineWidth=9;c.fillStyle=HD;c.beginPath();c.moveTo(128,40);c.bezierCurveTo(194,40,200,96,192,150);c.lineTo(64,150);c.bezierCurveTo(56,96,62,40,128,40);c.fill();c.stroke()
})
c.fillStyle=JK;c.lineWidth=5;c.beginPath();c.moveTo(56,132);c.lineTo(96,132);c.quadraticCurveTo(116,160,112,200);c.lineTo(40,200);c.quadraticCurveTo(36,160,56,132);c.closePath();c.fill();c.stroke()
c.strokeStyle=JD;c.lineWidth=4;c.beginPath();c.moveTo(76,138);c.lineTo(76,198);c.stroke();c.strokeStyle='#111'
c.fillStyle='#fff';c.lineWidth=5;c.beginPath();c.moveTo(60,132);c.quadraticCurveTo(76,146,92,132);c.quadraticCurveTo(76,126,60,132);c.fill();c.stroke()
c.fillStyle=LOG;c.lineWidth=5;c.beginPath();c.roundRect(24,196,104,22,10);c.fill();c.stroke();c.fillStyle='#ffd8a8';c.beginPath();c.ellipse(28,207,7,10,0,0,T);c.fill();c.stroke();c.strokeStyle=LD;c.lineWidth=3;c.beginPath();c.moveTo(50,204);c.lineTo(110,204);c.moveTo(64,212);c.lineTo(100,212);c.stroke();c.strokeStyle='#111'
for(const x of[56,90]){c.fillStyle=JD;c.lineWidth=5;c.beginPath();c.roundRect(x-10,192,26,16,8);c.fill();c.stroke()}
for(const x of[64,96]){c.fillStyle='#868e96';c.lineWidth=5;c.beginPath();c.roundRect(x-4,214,16,20,6);c.fill();c.stroke();c.fillStyle=BND;c.beginPath();c.ellipse(x+6,236,13,7,0,0,T);c.fill();c.stroke()}
const tip=[fx-6+3*sin(p),fy-86+2*cos(p)],hand=[110,164]
line(c,[hand,tip],4,'#d4a373')
line(c,[[92,144],[106,154],hand],8,JK);c.fillStyle=SKIN;c.lineWidth=4;c.beginPath();c.arc(...hand,7,0,T);c.fill();c.stroke()
c.save();c.translate(...tip);c.rotate(-.5);c.scale(ms,ms)
c.fillStyle=MAL;c.lineWidth=4;c.beginPath();c.roundRect(-11,-9,22,18,8);c.fill()
c.save();c.clip();c.globalAlpha=gold;c.fillStyle=TOAST;c.beginPath();c.ellipse(4,6,16,9,0,0,T);c.fill();c.globalAlpha=1;c.restore()
c.beginPath();c.roundRect(-11,-9,22,18,8);c.stroke()
if(gold>.6){c.fillStyle='#111';for(const x of[-4,4])c.beginPath(),c.arc(x,-1,1.6,0,T),c.fill();c.lineWidth=2;c.beginPath();c.arc(0,2,2.5,.2*PI,.8*PI);c.stroke()}
c.restore()
if(gold>.85){c.fillStyle=F3;c.lineWidth=3;for(const[dx,dy,s]of[[-20,-16,5],[18,-20,4]]){const x=tip[0]+dx,y=tip[1]+dy;c.beginPath();for(let k=0;k<8;k++){const r=k%2?s*.4:s,b=k*PI/4;c.lineTo(x+r*cos(b),y+r*sin(b))}c.closePath();c.fill();c.stroke()}}
head(()=>{
c.lineWidth=9;c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke()
for(const x of[108,158]){c.fillStyle='#fff';c.beginPath();c.ellipse(x,140,14,17,0,0,T);c.fill();c.save();c.clip();c.beginPath();c.ellipse(x+5,142,11.5,15,0,0,T);c.fillStyle=EYE;c.fill();c.save();c.clip();c.fillStyle=ED;c.beginPath();c.ellipse(x+5,132,13,10,0,0,T);c.fill();c.restore();c.lineWidth=2.5;c.beginPath();c.ellipse(x+5,142,11.5,15,0,0,T);c.stroke()
c.fillStyle='#111';c.beginPath();c.ellipse(x+7,143,5.5,7.5,0,0,T);c.fill();c.fillStyle='#fff';c.beginPath();c.arc(x+2,135,4.5,0,T);c.fill();c.fillStyle=F3;c.globalAlpha=.5+.5*glow;c.beginPath();c.arc(x+10,148,3,0,T);c.fill();c.globalAlpha=1;c.restore()
c.lineWidth=8;c.beginPath();c.moveTo(x-16,134);c.quadraticCurveTo(x,120,x+16,134);c.stroke()}
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(133+d*42,162,13,7,0,0,T),c.fill()
c.fillStyle='#c92a2a';c.lineWidth=6;c.beginPath();c.moveTo(124,164);c.quadraticCurveTo(138,182,152,164);c.closePath();c.fill();c.stroke()
c.fillStyle=HAIR;c.lineWidth=9;c.beginPath();c.moveTo(70,140);c.bezierCurveTo(54,90,80,70,128,70);c.bezierCurveTo(176,70,202,90,186,140)
c.quadraticCurveTo(184,118,176,106);c.quadraticCurveTo(168,104,162,112);c.quadraticCurveTo(156,100,146,98);c.quadraticCurveTo(140,108,132,112)
c.quadraticCurveTo(126,100,118,98);c.quadraticCurveTo(112,108,104,112);c.quadraticCurveTo(98,100,90,100);c.quadraticCurveTo(84,108,80,112);c.quadraticCurveTo(72,120,70,140);c.closePath();c.fill();c.stroke()
c.fillStyle=BEAN;c.beginPath();c.moveTo(62,92);c.bezierCurveTo(56,20,200,20,194,92);c.closePath();c.fill();c.stroke()
c.strokeStyle=BND;c.lineWidth=5;for(const x of[96,128,160])c.beginPath(),c.moveTo(x,36+(x==128?-6:0)),c.lineTo(x+(x-128)*.1,88),c.stroke();c.strokeStyle='#111'
c.fillStyle=BND;c.lineWidth=9;c.beginPath();c.roundRect(56,80,144,22,11);c.fill();c.stroke()
c.fillStyle='#fff';c.beginPath();c.arc(128,22,16,0,T);c.fill();c.stroke()
})
}
+51
View File
@@ -0,0 +1,51 @@
// girl peeking over a huge heart chocolate box she thrusts toward you, eyes squeezed shut, blushing hard, box trembling, hearts rising
const{sin,cos,PI}=Math,T=2*PI
export const frames=12,delay=80
const SKIN='#ffe3d1',HAIR='#ffc9de',HD='#f783ac',HL='#fff0f6',SLV='#9775fa',SD='#7048e8',BOX='#e03131',BXD='#a61e1e',BXL='#ff8787',RIB='#faa2c1',RD='#e64980',BOW='#e64980',BL='#ff6b81',HT='#f06595'
const heart=(c,x,y,s)=>{c.save();c.translate(x,y);c.scale(s,s);c.beginPath();c.moveTo(0,8);c.bezierCurveTo(-13,-1,-9,-12,0,-5);c.bezierCurveTo(9,-12,13,-1,0,8);c.restore()}
export default(c,t)=>{
const tr=1.8*sin(6*T*t),pu=1+.05*Math.max(0,sin(2*T*t)),bp=1+.15*sin(2*T*t)
c.save();c.translate(0,-28)
// long hair behind
c.lineWidth=7;c.fillStyle=HD;c.beginPath();c.moveTo(128,40);c.bezierCurveTo(206,40,216,120,216,200);c.quadraticCurveTo(222,250,200,272);c.lineTo(56,272);c.quadraticCurveTo(34,250,40,200);c.bezierCurveTo(40,120,50,40,128,40);c.fill();c.stroke()
// big bow on top
c.fillStyle=BOW;c.lineWidth=6;for(const d of[-1,1])c.beginPath(),c.moveTo(184,62),c.quadraticCurveTo(184+d*30,30,184+d*30,70),c.closePath(),c.fill(),c.stroke()
c.beginPath();c.arc(184,62,8,0,T);c.fill();c.stroke()
// face
c.fillStyle=SKIN;c.lineWidth=7;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke()
c.lineWidth=7;for(const d of[-1,1]){const x=128+d*25;c.beginPath();c.moveTo(x+d*12,128);c.lineTo(x-d*8,138);c.lineTo(x+d*12,148);c.stroke()}
c.lineWidth=5;for(const d of[-1,1])c.beginPath(),c.moveTo(128+d*14,112),c.quadraticCurveTo(128+d*26,104,128+d*38,112),c.stroke()
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*38,160,18*bp,9*bp,0,0,T),c.fill()
c.lineWidth=3;for(const d of[-1,1])for(const k of[-9,-3,3,9])c.beginPath(),c.moveTo(128+d*38+k-2,165),c.lineTo(128+d*38+k+2,155),c.stroke()
// bangs
c.lineWidth=7;c.fillStyle=HAIR;c.beginPath();c.moveTo(66,150)
c.bezierCurveTo(50,74,88,38,128,38);c.bezierCurveTo(168,38,206,74,190,150)
c.quadraticCurveTo(186,120,178,106);c.quadraticCurveTo(170,104,164,112);c.quadraticCurveTo(160,96,150,94);c.quadraticCurveTo(144,104,136,110)
c.quadraticCurveTo(132,96,122,92);c.quadraticCurveTo(116,104,106,108);c.quadraticCurveTo(102,96,92,98);c.quadraticCurveTo(86,106,80,112)
c.quadraticCurveTo(70,126,66,150);c.closePath();c.fill();c.stroke()
c.strokeStyle=HL;c.lineWidth=6;for(const[a,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,58,PI*a,PI*e),c.stroke();c.strokeStyle='#111'
c.restore()
// tremble lines and a sweat drop by her head
c.lineWidth=4;for(const d of[-1,1])for(const y of[78,94])c.beginPath(),c.moveTo(128+d*(92+tr),y),c.lineTo(128+d*(102+tr),y-4),c.stroke()
c.fillStyle='#a5d8ff';c.beginPath();c.moveTo(190,64);c.quadraticCurveTo(198,78,190,84);c.quadraticCurveTo(182,78,190,64);c.fill();c.stroke()
// sleeves from the bottom corners
for(const d of[-1,1])for(const[l,s]of[[38,'#111'],[27,SLV]])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),c.moveTo(128+d*112,262),c.quadraticCurveTo(128+d*96,222,128+d*(84+tr),198),c.stroke()
c.strokeStyle='#111'
// the big heart box, pushed forward
c.save();c.translate(128+tr,196);c.scale(pu,pu)
c.fillStyle=BXD;c.lineWidth=7;heart(c,0,3,7);c.fill();c.stroke()
c.fillStyle=BOX;heart(c,0,-2,6.8);c.fill();c.stroke()
c.strokeStyle=BXL;c.lineWidth=6;c.beginPath();c.arc(-38,-36,16,PI*1.1,PI*1.6);c.stroke();c.strokeStyle='#111'
c.save();heart(c,0,-2,6.8);c.clip()
for(const[l,s]of[[22,'#111'],[13,RIB]])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),c.moveTo(-90,-40),c.lineTo(90,40),c.stroke()
c.restore();c.strokeStyle='#111'
c.fillStyle=RIB;c.lineWidth=5;for(const d of[-1,1])c.beginPath(),c.moveTo(6,4),c.quadraticCurveTo(6+d*30,-22,6+d*26,16),c.closePath(),c.fill(),c.stroke()
for(const d of[-1,1])c.beginPath(),c.moveTo(6,8),c.lineTo(6+d*14,34),c.lineTo(6+d*4,30),c.closePath(),c.fill(),c.stroke()
c.fillStyle=RD;c.beginPath();c.arc(6,6,7,0,T);c.fill();c.stroke()
c.restore()
// hands gripping the sides
c.fillStyle=SKIN;c.lineWidth=5;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*(78+tr*d),196,13,15,d*.3,0,T),c.fill(),c.stroke()
// hearts rising beside her
c.fillStyle=HT;c.lineWidth=4
for(const[x0,o]of[[30,0],[226,.5]]){const p=(t+o)%1,s=1.4*sin(PI*p);if(s>.15)heart(c,x0+6*sin(2*T*p),150-p*120,s),c.fill(),c.stroke()}
}
+58
View File
@@ -0,0 +1,58 @@
// cyber girl with split cyan and pink hair and a glowing visor tapping holographic screens that pop up and slide around her
const{sin,cos,PI,max,min,round}=Math,T=2*PI
export const frames=16,delay=80
const SKIN='#ffe3d1',HC='#66d9e8',HCD='#1098ad',HP='#f783ac',HPD='#c2255c',EYE='#9775fa',ED='#5f3dc4',JK='#f8f9fa',JD='#495057',CY='#3bc9db',GL='#c5f6fa',BL='#ffa8a8'
const eye=(c,x,y,d)=>{
c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill()
c.save();c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.clip();c.fillStyle=EYE;c.fill();c.fillStyle=ED;c.beginPath();c.ellipse(x,y-8,13,10,0,0,T);c.fill();c.restore()
c.lineWidth=2.5;c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.stroke()
c.fillStyle='#111';c.beginPath();c.ellipse(x,y+3,5.5,7.5,0,0,T);c.fill()
c.fillStyle='#fff';c.beginPath();c.arc(x-4,y-5,4.5,0,T);c.fill();c.beginPath();c.arc(x+5,y+8,2,0,T);c.fill()
c.lineWidth=6;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke()
}
const glow=(c,f,w=3)=>{for(const[lw,s]of[[w+5,CY],[w,'#fff']]){c.lineWidth=lw;c.strokeStyle=s;f();c.stroke()}c.strokeStyle='#111'}
const panel=(c,x,y,w,h,s,k,flash)=>{
if(s<=.02)return
c.save();c.translate(x,y);c.scale(s,s)
const r=()=>{c.beginPath();c.roundRect(-w/2,-h/2,w,h,6)}
c.globalAlpha=.85;c.fillStyle=flash?'#fff':GL;r();c.fill();c.globalAlpha=1;glow(c,r)
c.strokeStyle=HCD;c.lineWidth=3;c.beginPath()
if(k==0)for(let j=0;j<3;j++)c.moveTo(-w/2+8,-h/2+10+j*9),c.lineTo(-w/2+8+(w-16)*[.9,.6,.75][j],-h/2+10+j*9)
else if(k==1){c.moveTo(-w/2+8,h/2-8);for(let j=0;j<5;j++)c.lineTo(-w/2+8+j*(w-16)/4,h/2-10-[6,14,9,18,12][j]*h/40)}
else{c.arc(0,0,min(w,h)*.28,0,T);c.moveTo(0,0);c.lineTo(min(w,h)*.28,0)}
c.stroke();c.strokeStyle='#111';c.restore()
}
export default(c,t)=>{
const tap=(t*2)%1,push=tap<.25?sin(PI*tap/.25):0,fl=tap<.12&&tap>.0
const sA=min(1,max(0,(t<.5?t:1-t)*6)),yA=round(4*sin(T*t)),sC=min(1,max(0,sin(T*(t+.25))*3))
const g=(a,b)=>{const q=c.createLinearGradient(60,0,196,0);q.addColorStop(.5,a);q.addColorStop(.5,b);return q}
c.lineWidth=6;c.fillStyle=g(HCD,HPD);c.beginPath();c.moveTo(128,36);c.bezierCurveTo(198,36,212,98,204,150);c.lineTo(210,208);c.lineTo(192,198);c.lineTo(184,212);c.lineTo(72,212);c.lineTo(64,198);c.lineTo(46,208);c.lineTo(52,150);c.bezierCurveTo(44,98,58,36,128,36);c.fill();c.stroke()
panel(c,46,70+yA,58,42,1,0,false)
c.fillStyle=JK;c.beginPath();c.moveTo(98,186);c.quadraticCurveTo(58,194,50,256);c.lineTo(206,256);c.quadraticCurveTo(198,194,158,186);c.closePath();c.fill();c.stroke()
c.fillStyle=JD;c.beginPath();c.moveTo(104,188);c.lineTo(128,214);c.lineTo(152,188);c.lineTo(150,176);c.lineTo(106,176);c.closePath();c.fill();c.stroke()
glow(c,()=>{c.beginPath();c.moveTo(96,210);c.lineTo(84,256);c.moveTo(160,210);c.lineTo(172,256)},2)
c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke()
eye(c,103,140,-1);eye(c,153,140,1)
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*42,163,12,6,0,0,T),c.fill()
c.lineWidth=4;c.beginPath();c.moveTo(118,167);c.quadraticCurveTo(128,174,140,165);c.stroke()
const vz=()=>{c.beginPath();c.moveTo(68,124);c.quadraticCurveTo(128,112,188,124);c.lineTo(184,152);c.quadraticCurveTo(128,162,72,152);c.closePath()}
c.globalAlpha=.55;c.fillStyle=CY;vz();c.fill();c.globalAlpha=1;c.lineWidth=5;vz();c.stroke()
c.strokeStyle='#fff';c.lineWidth=4;c.beginPath();c.moveTo(82,128);c.lineTo(110,123);c.moveTo(150,124);c.lineTo(160,126);c.stroke()
c.strokeStyle='#111';c.lineWidth=6
c.fillStyle=g(HC,HP);c.beginPath();c.moveTo(62,150)
c.bezierCurveTo(48,74,88,36,128,36);c.bezierCurveTo(168,36,208,74,194,150)
c.quadraticCurveTo(190,118,180,104);c.quadraticCurveTo(170,104,164,114);c.quadraticCurveTo(158,98,146,92);c.quadraticCurveTo(140,104,132,112)
c.quadraticCurveTo(126,96,114,88);c.quadraticCurveTo(108,104,98,110);c.quadraticCurveTo(94,98,86,98);c.quadraticCurveTo(80,108,78,116)
c.quadraticCurveTo(68,124,62,150);c.closePath();c.fill();c.stroke()
c.strokeStyle='#fff';c.lineWidth=5;c.beginPath();c.arc(128,104,56,PI*1.25,PI*1.36);c.moveTo(150,52);c.arc(128,104,56,PI*1.6,PI*1.72);c.stroke();c.strokeStyle='#111'
for(const d of[-1,1]){c.fillStyle=JD;c.lineWidth=5;c.beginPath();c.roundRect(128+d*58-10,108,20,30,8);c.fill();c.stroke();c.fillStyle=(t*4|0)%2&&d>0?'#fff':CY;c.beginPath();c.arc(128+d*58,123,4,0,T);c.fill()}
panel(c,214,80,52,40,sC,2,false)
const px=196,py=168
panel(c,px,py,74,56,1,1,fl)
if(tap<.4){const r=8+tap*90;c.globalAlpha=max(0,1-tap/.4);glow(c,()=>{c.beginPath();c.arc(px-14,py+4,r,0,T)},2);c.globalAlpha=1}
const hx=px-14-6*push,hy=py+4+10*(1-push)
for(const[lw,s]of[[17,'#111'],[9,JK]])c.lineWidth=lw,c.strokeStyle=s,c.beginPath(),c.moveTo(184,256),c.quadraticCurveTo(186,214,hx+6,hy+18),c.stroke()
c.strokeStyle='#111';c.lineWidth=4;c.fillStyle=SKIN;c.beginPath();c.ellipse(hx+6,hy+16,10,9,0,0,T);c.fill();c.stroke()
for(const[lw,s]of[[11,'#111'],[5,SKIN]])c.lineWidth=lw,c.strokeStyle=s,c.beginPath(),c.moveTo(hx+4,hy+10),c.lineTo(hx,hy),c.stroke()
c.strokeStyle='#111'
}
+59
View File
@@ -0,0 +1,59 @@
// little devil with crimson hair and tiny horns hovering on flapping bat wings, spade tail swishing, poking her toy trident with a sly fanged grin
const{sin,cos,PI,round,max}=Math,T=2*PI
export const frames=12,delay=80
const SKIN='#ffe3d1',HAIR='#e03131',HD='#a51111',HL='#ffc9c9',EYE='#ff922b',ED='#d9480f',HORN='#495057',WG='#9c36b5',WL='#e599f7',DR='#862e9c',DD='#5f3dc4',GO='#ffd43b',GD='#f59f00',TL='#c92a2a',BL='#ffa8a8'
const line=(c,pts,w,col)=>{for(const[lw,s]of[[w+8,'#111'],[w,col]]){c.lineWidth=lw;c.strokeStyle=s;c.beginPath();pts.forEach(([x,y],k)=>k?c.lineTo(x,y):c.moveTo(x,y));c.stroke()}c.strokeStyle='#111'}
const sly=(c,x,y,d)=>{
c.fillStyle='#fff';c.beginPath();c.ellipse(x,y+4,14,12,0,0,T);c.fill()
c.save();c.beginPath();c.ellipse(x,y+4,14,12,0,0,T);c.clip();c.fillStyle=EYE;c.beginPath();c.ellipse(x-d*3,y+8,11,13,0,0,T);c.fill();c.fillStyle=ED;c.beginPath();c.ellipse(x-d*3,y,12,8,0,0,T);c.fill()
c.fillStyle='#111';c.beginPath();c.ellipse(x-d*3,y+8,3,7,0,0,T);c.fill();c.fillStyle='#fff';c.beginPath();c.arc(x-d*3-4,y+3,3.5,0,T);c.fill();c.restore()
c.lineWidth=8;c.beginPath();c.moveTo(x-17,y-6+d*3);c.lineTo(x+17,y-6-d*3);c.moveTo(x+d*16,y-6-d*3);c.lineTo(x+d*22,y-11-d*3);c.stroke()
c.lineWidth=6;c.beginPath();c.moveTo(x-12,y-22+d*6);c.lineTo(x+12,y-22-d*2);c.stroke()
}
const wing=(c,x,y,d,a)=>{
c.save();c.translate(x,y);c.scale(d,1);c.rotate(-a)
const p=()=>{c.beginPath();c.moveTo(0,0);c.lineTo(30,-34);c.lineTo(76,-46);c.quadraticCurveTo(70,-24,82,-8);c.quadraticCurveTo(62,-12,56,6);c.quadraticCurveTo(40,-2,30,16);c.quadraticCurveTo(18,4,0,14);c.closePath()}
c.lineWidth=14;c.strokeStyle='#fff';p();c.stroke();c.fillStyle=WG;p();c.fill();c.strokeStyle=WL;c.lineWidth=3;c.beginPath();for(const[ex,ey]of[[76,-46],[56,6],[30,16]])c.moveTo(30,-34),c.lineTo(ex,ey);c.stroke()
c.strokeStyle='#111';c.lineWidth=5;p();c.stroke();c.restore()
}
export default(c,t)=>{
const by=round(4*sin(T*t)),a=.34*sin(2*T*t),sw=sin(T*t+1),pk=max(0,sin(2*T*t-1))
c.translate(0,by)
const tp=[[124,190]];for(let k=1;k<=10;k++){const s=k/10;tp.push([124-60*s+10*sin(s*PI*2+sw),196+28*sin(s*PI)-34*s*s+14*sw*s])}
line(c,tp,4,TL)
const[tx,ty]=tp[10],ta=.6+.5*sw
c.save();c.translate(tx,ty);c.rotate(ta);c.fillStyle=TL;c.lineWidth=5;c.beginPath();c.moveTo(0,4);c.bezierCurveTo(-18,-2,-14,-22,0,-26);c.bezierCurveTo(14,-22,18,-2,0,4);c.closePath();c.fill();c.stroke();c.restore()
for(const d of[-1,1])wing(c,128+d*14,138,d,a)
for(const[x,s]of[[118,-1],[138,1]]){line(c,[[x,196],[x+s*3,218]],7,SKIN);c.lineWidth=5;c.fillStyle=DD;c.beginPath();c.ellipse(x+s*5,222,9,7,s*.3,0,T);c.fill();c.stroke()}
c.fillStyle=DR;c.lineWidth=5;c.beginPath();c.moveTo(112,136);c.lineTo(144,136);c.bezierCurveTo(156,160,164,180,170,200);c.lineTo(158,194);c.lineTo(148,204);c.lineTo(138,196);c.lineTo(128,206);c.lineTo(118,196);c.lineTo(108,204);c.lineTo(98,194);c.lineTo(86,200);c.bezierCurveTo(92,180,100,160,112,136);c.closePath();c.fill();c.stroke()
c.fillStyle='#fff';for(const d of[-1,1])c.beginPath(),c.moveTo(128,148),c.lineTo(128+d*16,136),c.lineTo(128+d*18,146),c.closePath(),c.fill(),c.stroke()
c.fillStyle=GO;c.lineWidth=4;c.beginPath();c.moveTo(128,154);c.bezierCurveTo(118,146,120,138,128,144);c.bezierCurveTo(136,138,138,146,128,154);c.fill();c.stroke()
line(c,[[114,142],[98,160],[104,172]],7,SKIN)
const hx=168+6*pk,hy=156-8*pk,ang=.45
c.save();c.translate(hx,hy);c.rotate(ang)
for(const[lw,col]of[[11,'#111'],[5,GO]])c.lineWidth=lw,c.strokeStyle=col,c.beginPath(),c.moveTo(0,30),c.lineTo(0,-64),c.stroke()
c.strokeStyle='#111';c.fillStyle=GO;c.lineWidth=5;c.beginPath();c.moveTo(-20,-62);c.quadraticCurveTo(-20,-74,-22,-88);c.lineTo(-14,-80);c.quadraticCurveTo(-12,-70,-6,-66);c.lineTo(-5,-86);c.lineTo(0,-100);c.lineTo(5,-86);c.lineTo(6,-66);c.quadraticCurveTo(12,-70,14,-80);c.lineTo(22,-88);c.quadraticCurveTo(20,-74,20,-62);c.quadraticCurveTo(0,-54,-20,-62);c.closePath();c.fill();c.stroke()
c.fillStyle='#ff6b6b';c.beginPath();c.arc(0,-60,5,0,T);c.fill();c.stroke()
c.restore()
line(c,[[142,142],[158,152],[hx,hy]],7,SKIN)
c.lineWidth=4;c.fillStyle=SKIN;c.beginPath();c.arc(hx,hy,7,0,T);c.fill();c.stroke()
if(pk>.6){c.lineWidth=4;const ex=hx+cos(ang-PI/2)*104,ey=hy+sin(ang-PI/2)*104;for(const b of[-.7,0,.7]){const q=ang-PI/2+b;c.beginPath();c.moveTo(ex+cos(q)*12,ey+sin(q)*12);c.lineTo(ex+cos(q)*22,ey+sin(q)*22);c.stroke()}}
c.save();c.translate(128,92);c.scale(.6,.6);c.translate(-128,-128)
c.lineWidth=9;c.fillStyle=HD;c.beginPath();c.moveTo(128,36);c.bezierCurveTo(200,36,212,98,202,150);c.quadraticCurveTo(190,166,176,160);c.lineTo(80,160);c.quadraticCurveTo(66,166,54,150);c.bezierCurveTo(44,98,56,36,128,36);c.fill();c.stroke()
c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke()
sly(c,103,140,-1);sly(c,153,140,1)
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,164,13,7,0,0,T),c.fill()
c.lineWidth=6;c.fillStyle='#c92a2a';c.beginPath();c.moveTo(108,162);c.quadraticCurveTo(128,186,150,160);c.quadraticCurveTo(128,170,108,162);c.closePath();c.fill();c.stroke()
c.fillStyle='#fff';c.lineWidth=4;c.beginPath();c.moveTo(134,167);c.lineTo(138,176);c.lineTo(142,165);c.fill();c.stroke()
c.lineWidth=9;c.fillStyle=HAIR;c.beginPath();c.moveTo(66,142)
c.bezierCurveTo(52,70,90,36,128,36);c.bezierCurveTo(166,36,204,70,190,142)
c.quadraticCurveTo(186,112,176,100);c.quadraticCurveTo(168,104,162,114);c.quadraticCurveTo(156,96,146,90);c.quadraticCurveTo(140,104,132,110)
c.quadraticCurveTo(126,96,116,90);c.quadraticCurveTo(110,104,100,112);c.quadraticCurveTo(96,98,88,96);c.quadraticCurveTo(82,108,80,114)
c.quadraticCurveTo(70,114,66,142);c.closePath();c.fill();c.stroke()
c.strokeStyle=HL;c.lineWidth=7;for(const[a0,e]of[[1.26,1.38],[1.46,1.54],[1.62,1.72]])c.beginPath(),c.arc(128,104,56,PI*a0,PI*e),c.stroke();c.strokeStyle='#111'
for(const d of[-1,1]){c.fillStyle=HAIR;c.lineWidth=9;c.beginPath();c.arc(128+d*56,52,22,0,T);c.fill();c.stroke()
const hp=()=>{c.beginPath();c.moveTo(128+d*24,52);c.quadraticCurveTo(128+d*22,22,128+d*38,6);c.quadraticCurveTo(128+d*36,30,128+d*44,48);c.closePath()}
c.lineWidth=20;c.strokeStyle='#fff';hp();c.stroke();c.fillStyle=HORN;hp();c.fill();c.lineWidth=8;c.strokeStyle='#111';hp();c.stroke()
c.strokeStyle='#adb5bd';c.lineWidth=4;c.beginPath();c.moveTo(128+d*29,40);c.quadraticCurveTo(128+d*29,26,128+d*35,16);c.stroke();c.strokeStyle='#111'}
c.restore()
}
+57
View File
@@ -0,0 +1,57 @@
// dj girl with copper hair and big headphones scratching a record back and forth, nodding to the beat, light beams behind her
const{sin,cos,PI,abs}=Math,T=2*PI
export const frames=12,delay=80
const SKIN='#ffe3d1',HAIR='#e07a3a',HD='#b0561e',HL='#f8c9a0',EYE='#15aabf',ED='#0b7285',BL='#ffa8a8',HOOD='#9775fa',HOD='#7048e8',PH='#38d9a9',PHD='#0ca678',LED='#f783ac',DECK='#e9ecef',DKD='#adb5bd',REC='#495057',LAB='#ffd43b',B1='#faa2c1',B2='#74c0fc'
const ds=(c,a,b,s,f)=>{for(const[l,k]of[[a,'#111'],[b,s]])c.lineWidth=l,c.strokeStyle=k,c.beginPath(),f(),c.stroke();c.strokeStyle='#111'}
const note=(c,x,y,s,col)=>{ds(c,8,3,col,()=>{c.moveTo(x+6*s,y);c.lineTo(x+6*s,y-22*s);c.lineTo(x+16*s,y-18*s)});c.fillStyle=col;c.lineWidth=3.5;c.beginPath();c.ellipse(x,y,7*s,5*s,-.4,0,T);c.fill();c.stroke()}
const eye=(c,x,y,d)=>{
c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill()
c.save();c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.clip()
c.beginPath();c.ellipse(x-2,y+6,11.5,15,0,0,T);c.fillStyle=EYE;c.fill();c.lineWidth=2.5;c.stroke()
c.save();c.clip();c.fillStyle=ED;c.beginPath();c.ellipse(x-2,y-4,13,10,0,0,T);c.fill();c.restore()
c.fillStyle='#111';c.beginPath();c.ellipse(x-2,y+7,5.5,7.5,0,0,T);c.fill()
c.fillStyle='#fff';c.beginPath();c.arc(x-6,y,4.5,0,T);c.fill();c.beginPath();c.arc(x+3,y+12,2,0,T);c.fill()
c.fillStyle=SKIN;c.fillRect(x-16,y-20,32,9);c.restore()
c.lineWidth=7;c.beginPath();c.moveTo(x-16,y-9);c.quadraticCurveTo(x,y-16,x+16,y-9);c.moveTo(x+d*15,y-9);c.lineTo(x+d*21,y-14);c.stroke()
}
export default(c,t)=>{
const nod=abs(sin(2*PI*t)),th=1.1*sin(2*T*t),cf=10*sin(2*T*t)
for(const[x,d,col]of[[50,-1,B1],[206,1,B2]]){c.save();c.translate(x,206);c.rotate(d*.45);c.fillStyle=col;c.lineWidth=5;c.beginPath();c.moveTo(-6,0);c.lineTo(-30,-190);c.lineTo(30,-190);c.lineTo(6,0);c.closePath();c.fill();c.stroke();c.restore()}
for(const[x,o,col]of[[40,0,'#ffd43b'],[212,.5,'#f783ac']]){const p=(t+o)%1,s=sin(PI*p);if(s>.2)note(c,x+5*sin(p*T),120-60*p,.5+.4*s,col)}
c.lineWidth=7;c.fillStyle=HOOD;c.beginPath();c.moveTo(100,150);c.quadraticCurveTo(58,160,50,230);c.lineTo(206,230);c.quadraticCurveTo(198,160,156,150);c.closePath();c.fill();c.stroke()
c.fillStyle=HOD;c.lineWidth=5;c.beginPath();c.moveTo(102,152);c.quadraticCurveTo(128,176,154,152);c.quadraticCurveTo(150,168,128,170);c.quadraticCurveTo(106,168,102,152);c.fill();c.stroke()
ds(c,7,3,'#fff',()=>{c.moveTo(118,166);c.lineTo(116,190);c.moveTo(138,166);c.lineTo(140,190)})
c.fillStyle=SKIN;c.lineWidth=6;c.beginPath();c.moveTo(118,136);c.lineTo(118,154);c.quadraticCurveTo(128,162,138,154);c.lineTo(138,136);c.fill();c.beginPath();c.moveTo(118,136);c.lineTo(118,152);c.moveTo(138,136);c.lineTo(138,152);c.stroke()
c.save();c.translate(128,96+Math.round(3*nod));c.scale(.7,.7);c.translate(-128,-120)
c.lineWidth=7;c.fillStyle=HD;c.beginPath();c.moveTo(128,36);c.bezierCurveTo(198,36,210,100,200,166);c.lineTo(56,166);c.bezierCurveTo(46,100,58,36,128,36);c.fill();c.stroke()
c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke()
eye(c,103,140,-1);eye(c,153,140,1)
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,164,13,7,0,0,T),c.fill()
c.lineWidth=5;c.fillStyle='#c92a2a';c.beginPath();c.moveTo(112,164);c.quadraticCurveTo(128,184,144,164);c.closePath();c.fill();c.stroke()
c.fillStyle='#fff';c.lineWidth=2.5;c.beginPath();c.moveTo(114,165);c.lineTo(142,165);c.lineTo(140,170);c.lineTo(116,170);c.closePath();c.fill();c.stroke()
c.lineWidth=7;c.fillStyle=HAIR;c.beginPath();c.moveTo(64,150)
c.bezierCurveTo(48,76,86,38,128,38);c.bezierCurveTo(170,38,208,76,192,150)
c.lineTo(186,120);c.lineTo(178,126);c.lineTo(174,102);c.lineTo(160,110);c.quadraticCurveTo(150,94,134,86)
c.quadraticCurveTo(120,106,90,118);c.quadraticCurveTo(100,104,98,94);c.lineTo(80,110);c.lineTo(76,126);c.lineTo(70,122);c.closePath();c.fill();c.stroke()
c.strokeStyle=HL;c.lineWidth=6;for(const[s,e]of[[1.3,1.42],[1.52,1.6],[1.68,1.78]])c.beginPath(),c.arc(128,108,58,PI*s,PI*e),c.stroke();c.strokeStyle='#111'
ds(c,24,14,PH,()=>{c.arc(128,118,78,PI*1.04,PI*1.96)})
for(const d of[-1,1]){c.fillStyle=PH;c.lineWidth=7;c.beginPath();c.ellipse(128+d*76,130,22,32,0,0,T);c.fill();c.stroke();c.fillStyle=PHD;c.beginPath();c.ellipse(128+d*82,130,10,20,0,0,T);c.fill();c.stroke()
c.strokeStyle=nod>.5?LED:'#fff';c.lineWidth=5;c.beginPath();c.ellipse(128+d*76,130,15,24,0,0,T);c.stroke();c.strokeStyle='#111'}
c.restore()
c.lineWidth=7;c.fillStyle=DECK;c.beginPath();c.moveTo(18,192);c.lineTo(238,192);c.lineTo(250,250);c.lineTo(6,250);c.closePath();c.fill();c.stroke()
c.fillStyle=DKD;c.lineWidth=6;c.beginPath();c.moveTo(6,238);c.lineTo(250,238);c.lineTo(250,250);c.lineTo(6,250);c.closePath();c.fill();c.stroke()
c.fillStyle='#fff';c.lineWidth=14;c.strokeStyle='#fff';c.beginPath();c.ellipse(82,216,56,20,0,0,T);c.stroke();c.strokeStyle='#111'
c.fillStyle=REC;c.lineWidth=6;c.beginPath();c.ellipse(82,216,56,20,0,0,T);c.fill();c.stroke()
c.strokeStyle=DKD;c.lineWidth=2;for(const r of[.5,.72,.9])c.beginPath(),c.ellipse(82,216,56*r,20*r,0,0,T),c.stroke();c.strokeStyle='#111'
c.fillStyle=LAB;c.lineWidth=4;c.beginPath();c.ellipse(82,216,18,7,0,0,T);c.fill();c.stroke()
c.lineWidth=4;c.beginPath();c.moveTo(82,216);c.lineTo(82+16*cos(th),216+6*sin(th));c.stroke()
c.fillStyle='#fff';c.beginPath();c.arc(82,216,3,0,T);c.fill();c.stroke()
c.fillStyle='#fff';c.lineWidth=5;for(const[x,y]of[[164,206],[182,206],[220,206]])c.beginPath(),c.arc(x,y,6,0,T),c.fill(),c.stroke()
c.fillStyle=DKD;c.lineWidth=4;c.beginPath();c.roundRect(160,222,64,8,4);c.fill();c.stroke()
const fx=192+cf,a=th+2.4,rx=82+44*cos(a),ry=216+15*sin(a)
ds(c,20,11,HOOD,()=>{c.moveTo(104,172);c.lineTo(rx+6,ry-10)})
ds(c,20,11,HOOD,()=>{c.moveTo(152,172);c.lineTo(fx-4,212)})
c.fillStyle='#fff';c.lineWidth=4;c.beginPath();c.roundRect(fx-7,218,14,16,4);c.fill();c.stroke()
c.fillStyle=SKIN;c.lineWidth=5;for(const[x,y]of[[rx,ry],[fx,218]])c.beginPath(),c.ellipse(x,y,12,10,0,0,T),c.fill(),c.stroke()
for(const d of[-1,1])if(abs(cos(2*T*t))<.6)ds(c,6,2.5,'#fff',()=>{c.moveTo(rx+d*18,ry-6);c.lineTo(rx+d*26,ry-10)})
}
+69
View File
@@ -0,0 +1,69 @@
// easter chibi with bunny-ear headband and a basket: spots a painted egg in the grass, pulls it out, holds it up sparkling, drops it in her basket
const{sin,cos,PI,max,min}=Math,T=2*PI
export const frames=20,delay=80
const SKIN='#ffe3d1',HAIR='#ffe066',HD='#f59f00',HL='#fff9db',EYE='#f06595',ED='#a61e4d',DRESS='#a5d8ff',DD='#4dabf7',EAR='#fff',PINK='#faa2c1',BASK='#c08a5e',BD='#8d6346',GRASS='#69db7c',GD='#2f9e44',SHOE='#f783ac',BL='#ffa8a8',MO='#c92a2a',EGG=[['#b197fc','#fff'],['#f783ac','#ffd43b'],['#4dabf7','#fff'],['#ffd43b','#69db7c']]
const cl=x=>max(0,min(1,x)),ease=x=>x*x*(3-2*x),lerp=(a,b,k)=>[a[0]+(b[0]-a[0])*k,a[1]+(b[1]-a[1])*k]
const eye=(c,x,y,d,dx,dy)=>{
c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill()
c.save();c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.clip()
c.fillStyle=EYE;c.beginPath();c.ellipse(x+dx,y+2+dy,11.5,15,0,0,T);c.fill();c.fillStyle=ED;c.beginPath();c.ellipse(x+dx,y-8+dy,13,10,0,0,T);c.fill()
c.fillStyle='#111';c.beginPath();c.ellipse(x+dx,y+3+dy,5.5,7.5,0,0,T);c.fill()
c.fillStyle='#fff';c.beginPath();c.arc(x-4+dx,y-5+dy,4.5,0,T);c.fill();c.beginPath();c.arc(x+5+dx,y+8+dy,2,0,T);c.fill();c.restore()
c.lineWidth=3.5;c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.stroke()
c.lineWidth=8;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke()
}
const egg=(c,x,y,s,k,a=0)=>{const[f,p]=EGG[k];c.save();c.translate(x,y);c.rotate(a);c.scale(s,s)
const sh=()=>{c.beginPath();c.moveTo(0,-15);c.bezierCurveTo(11,-15,13,4,12,7);c.bezierCurveTo(10,15,-10,15,-12,7);c.bezierCurveTo(-13,4,-11,-15,0,-15)}
sh();c.fillStyle=f;c.lineWidth=4/s;c.fill();c.save();c.clip();c.strokeStyle=p;c.lineWidth=3.5/s;c.beginPath();for(let i=0;i<=6;i++)c.lineTo(-14+i*4.7,(i%2?-1:3));c.stroke()
c.fillStyle=p;for(const[px,py]of[[-5,-8],[5,-8],[0,9]])c.beginPath(),c.arc(px,py,2.2,0,T),c.fill();c.restore();sh();c.stroke();c.restore()}
const spark=(c,x,y,r)=>{c.beginPath();c.moveTo(x,y-r);for(const[px,py,qx,qy]of[[r,0,r*.18,-r*.18],[0,r,r*.18,r*.18],[-r,0,-r*.18,r*.18],[0,-r,-r*.18,-r*.18]])c.quadraticCurveTo(x+qx,y+qy,x+px,y+py);c.fill();c.stroke()}
export default(c,t)=>{
const BK=[78,198],GR=[192,222],UP=[170,64]
const H=t<.15?lerp(BK,GR,ease(t/.15)):t<.3?GR:t<.5?lerp(GR,UP,ease((t-.3)/.2)):t<.78?UP:t<.86?lerp(UP,[150,192],ease((t-.78)/.08)):t<.95?lerp([150,192],BK,ease((t-.86)/.09)):BK
const held=t>=.3&&t<.95,inGrass=t<.3||t>=.9,up=t>=.5&&t<.78,Z=.62,look=t<.3?[4,6]:t<.5?[3,-2]:t<.78?[3,-6]:[-3,4],pop=t>=.9?ease(cl((t-.9)/.06)):1
// grass tuft with an egg peeking out
const blades=(x0,y0,n,hs,sw)=>{c.fillStyle=GRASS;c.lineWidth=4;for(let k=0;k<n;k++){const x=x0+k*13,h=hs[k%hs.length],b=sw*sin(T*t+k);c.beginPath();c.moveTo(x-8,y0);c.quadraticCurveTo(x-2,y0-h*.6,x+b,y0-h);c.quadraticCurveTo(x+3,y0-h*.5,x+8,y0);c.closePath();c.fill();c.stroke()}}
blades(162,242,6,[30,38,26],3)
if(inGrass)egg(c,GR[0],228,.95*pop,0,-.2)
blades(168,248,6,[18,24,14],1.5)
if(t>=.9&&t<.98){c.fillStyle='#ffd43b';c.lineWidth=3;spark(c,GR[0]+18,206,8*sin(PI*(t-.9)/.08))}
// legs and shoes
for(const d of[-1,1])for(const[l,s]of[[15,'#111'],[8,SKIN]])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),c.moveTo(112+d*12,212),c.lineTo(112+d*12,234),c.stroke()
c.strokeStyle='#111';c.lineWidth=5;c.fillStyle=SHOE;for(const d of[-1,1])c.beginPath(),c.ellipse(112+d*14,240,11,6.5,0,0,T),c.fill(),c.stroke()
// dress
c.lineWidth=5;c.fillStyle=DRESS;c.beginPath();c.moveTo(96,166);c.quadraticCurveTo(86,170,84,184);c.lineTo(72,220);c.quadraticCurveTo(112,230,152,220);c.lineTo(140,184);c.quadraticCurveTo(138,170,128,166);c.closePath();c.fill();c.stroke()
c.strokeStyle=DD;c.lineWidth=3;c.beginPath();c.moveTo(76,214);c.quadraticCurveTo(112,222,148,214);c.stroke();c.strokeStyle='#111'
c.fillStyle='#fff';c.lineWidth=4;for(const d of[-1,1])c.beginPath(),c.moveTo(112,170),c.quadraticCurveTo(112+d*14,166,112+d*16,176),c.quadraticCurveTo(112+d*8,184,112,176),c.fill(),c.stroke()
// basket arm and basket
for(const[l,s]of[[15,'#111'],[8,SKIN]])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),c.moveTo(94,178),c.lineTo(70,196),c.stroke()
c.strokeStyle='#111';c.lineWidth=9;c.beginPath();c.arc(60,206,22,PI*1.05,PI*1.95);c.stroke();c.strokeStyle=BASK;c.lineWidth=4;c.stroke();c.strokeStyle='#111'
egg(c,50,200,.75,1,-.3);egg(c,68,198,.75,2,.25);egg(c,59,195,.7,3,0)
c.lineWidth=5;c.fillStyle=BASK;c.beginPath();c.moveTo(34,204);c.lineTo(86,204);c.lineTo(80,230);c.quadraticCurveTo(60,236,40,230);c.closePath();c.fill();c.stroke()
c.strokeStyle=BD;c.lineWidth=3;for(const y of[212,220])c.beginPath(),c.moveTo(38,y),c.lineTo(83,y),c.stroke();for(const x of[48,60,72])c.beginPath(),c.moveTo(x,206),c.lineTo(x,230),c.stroke();c.strokeStyle='#111'
c.fillStyle=SKIN;c.lineWidth=5;c.beginPath();c.arc(70,198,7,0,T);c.fill();c.stroke()
// head
c.save();c.translate(112,72);c.scale(Z,Z);c.translate(-128,-40)
c.lineWidth=8;c.fillStyle=HD;c.beginPath();c.moveTo(128,36);c.bezierCurveTo(196,36,206,96,198,150);c.quadraticCurveTo(186,162,170,152);c.lineTo(86,152);c.quadraticCurveTo(70,162,58,150);c.bezierCurveTo(50,96,60,36,128,36);c.fill();c.stroke()
// bunny-ear headband
for(const d of[-1,1]){c.save();c.translate(128+d*30,44);c.rotate(d*(.18+(d>0?.5+.12*sin(2*T*t):0)))
c.fillStyle=EAR;c.lineWidth=8;c.beginPath();c.ellipse(0,-44,15,44,0,0,T);c.fill();c.stroke();c.fillStyle=PINK;c.beginPath();c.ellipse(0,-42,7,32,0,0,T);c.fill();c.restore()}
c.fillStyle=SKIN;c.lineWidth=8;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke()
if(up){c.lineWidth=8;for(const x of[103,153])c.beginPath(),c.arc(x,146,13,PI*1.15,PI*1.85),c.stroke()}
else eye(c,103,140,-1,...look),eye(c,153,140,1,...look)
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,162,14,7,0,0,T),c.fill()
c.lineWidth=4.5;c.fillStyle=MO;c.beginPath()
if(up||t>=.3&&t<.5)c.moveTo(114,164),c.quadraticCurveTo(128,186,142,164),c.closePath(),c.fill(),c.stroke();else c.ellipse(128,170,6,7,0,0,T),c.fill(),c.stroke()
c.lineWidth=8;c.fillStyle=HAIR;c.beginPath();c.moveTo(66,146);c.bezierCurveTo(50,74,88,38,128,38);c.bezierCurveTo(168,38,206,74,190,146)
c.quadraticCurveTo(186,118,178,104);c.quadraticCurveTo(170,102,164,110);c.quadraticCurveTo(160,96,150,92);c.quadraticCurveTo(144,104,136,110)
c.quadraticCurveTo(132,96,122,90);c.quadraticCurveTo(116,104,106,108);c.quadraticCurveTo(102,96,92,96);c.quadraticCurveTo(86,106,80,112);c.quadraticCurveTo(70,124,66,146);c.closePath();c.fill();c.stroke()
c.strokeStyle=HL;c.lineWidth=6;for(const[a,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,58,PI*a,PI*e),c.stroke();c.strokeStyle='#111'
c.fillStyle=PINK;c.lineWidth=8;c.beginPath();c.roundRect(76,52,104,12,6);c.fill();c.stroke()
c.restore()
// reaching arm with the egg
const E=[150+.3*(H[0]-150),Math.min(176,H[1]+40)]
for(const[l,s]of[[15,'#111'],[8,SKIN]])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),c.moveTo(130,178),c.quadraticCurveTo(E[0]+14,E[1],H[0],H[1]),c.stroke()
c.strokeStyle='#111'
if(held)egg(c,H[0],H[1]-12,1.05,0,0)
c.fillStyle=SKIN;c.lineWidth=5;c.beginPath();c.arc(H[0],H[1],8,0,T);c.fill();c.stroke()
if(up){c.fillStyle='#ffd43b';c.lineWidth=3;for(const[dx,dy,o]of[[-22,-26,0],[24,-30,.5],[26,4,.25]]){const s=10*sin(PI*((((t-.5)/.28)*2+o)%1));if(s>1.5)spark(c,H[0]+dx,H[1]+dy-12,s)}}
}
+52
View File
@@ -0,0 +1,52 @@
// tiny emerald-haired fairy hovering on buzzing dragonfly wings, waving her star wand so glitter sprinkles down
const{sin,cos,PI,round,abs}=Math,T=2*PI
export const frames=12,delay=80
const SKIN='#ffe3d1',HAIR='#12b886',HD='#087f5b',HL='#c3fae8',EYE='#fab005',ED='#e67700',DR='#faa2c1',DD='#f06595',WG='#e3fafc',WV='#66d9e8',BL='#ffa8a8',FL='#fff3bf',GL=['#ffd43b','#f783ac','#66d9e8','#b197fc']
const eye=(c,x,y,d)=>{
c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill()
c.save();c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.clip();c.fillStyle=EYE;c.fill();c.fillStyle=ED;c.beginPath();c.ellipse(x,y-8,13,10,0,0,T);c.fill();c.restore()
c.lineWidth=3;c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.stroke()
c.fillStyle='#111';c.beginPath();c.ellipse(x,y+3,5.5,7.5,0,0,T);c.fill()
c.fillStyle='#fff';c.beginPath();c.arc(x-4,y-5,4.5,0,T);c.fill();c.beginPath();c.arc(x+5,y+8,2,0,T);c.fill()
c.lineWidth=8;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke()
}
const line=(c,pts,w,col)=>{for(const[lw,s]of[[w+8,'#111'],[w,col]]){c.lineWidth=lw;c.strokeStyle=s;c.beginPath();pts.forEach(([x,y],k)=>k?c.lineTo(x,y):c.moveTo(x,y));c.stroke()}c.strokeStyle='#111'}
const spark=(c,x,y,r)=>{const q=r*.2;c.beginPath();c.moveTo(x,y-r);c.quadraticCurveTo(x+q,y-q,x+r,y);c.quadraticCurveTo(x+q,y+q,x,y+r);c.quadraticCurveTo(x-q,y+q,x-r,y);c.quadraticCurveTo(x-q,y-q,x,y-r);c.fill();c.stroke()}
const star=(c,x,y,r,a)=>{c.save();c.translate(x,y);c.rotate(a);c.beginPath();for(let k=0;k<10;k++){const q=k%2?r*.45:r,b=k*PI/5-PI/2;c.lineTo(cos(b)*q,sin(b)*q)}c.closePath();c.restore();c.fill();c.stroke()}
const wing=(c,a,len,w)=>{c.save();c.rotate(a);c.fillStyle=WG;c.lineWidth=4;c.beginPath();c.ellipse(len/2+4,0,len/2,w,0,0,T);c.fill();c.stroke();c.strokeStyle=WV;c.lineWidth=2.5;c.beginPath();c.moveTo(10,0);c.lineTo(len-6,0);for(const k of[.35,.6,.82])c.moveTo(len*k,0),c.lineTo(len*k+8,-w*.6),c.moveTo(len*k,0),c.lineTo(len*k+8,w*.6);c.stroke();c.restore()}
export default(c,t)=>{
const by=round(5*sin(T*t)),fl=abs(sin(3*T*t)),wa=.3*sin(2*T*t)
for(let k=0;k<5;k++){const p=(t*2+k/5)%1,x=204+18*p+7*sin(T*(p+k*.3)),y=92+by+70*p*p+50*p,r=12*(1-p)+3
c.fillStyle=GL[k%4];c.lineWidth=3;spark(c,x,y,r)}
c.translate(0,by)
c.save();c.translate(128,142)
for(const d of[-1,1]){c.save();c.scale(d,1);wing(c,-.55-.18*fl,74,14+5*fl);wing(c,.35+.12*fl,56,11+4*fl);c.restore()}
c.restore()
for(const x of[118,138]){line(c,[[x,186],[x+(x<128?-2:2),212]],6,SKIN);c.lineWidth=4;c.fillStyle=DD;c.beginPath();c.moveTo(x-7,210);c.quadraticCurveTo(x+(x<128?-14:14),214,x+(x<128?-16:16),206);c.quadraticCurveTo(x+(x<128?-8:8),220,x-6,218);c.closePath();c.fill();c.stroke()}
line(c,[[112,140],[98,162],[104,176]],6,SKIN)
c.fillStyle=DR;c.lineWidth=5;c.beginPath();c.moveTo(114,128);c.lineTo(142,128);c.bezierCurveTo(150,150,158,170,168,186);for(let k=0;k<5;k++)c.quadraticCurveTo(160-k*16,198-(k%2)*4,152-k*16,190);c.bezierCurveTo(98,170,106,150,114,128);c.closePath();c.fill();c.stroke()
c.strokeStyle=DD;c.lineWidth=3;c.beginPath();for(const x of[120,136])c.moveTo(x,150),c.quadraticCurveTo(x+(x-128)*.6,168,x+(x-128),186);c.stroke();c.strokeStyle='#111'
c.fillStyle=HAIR;c.lineWidth=4;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*8,132,8,5,d*.5,0,T),c.fill(),c.stroke()
const sx=146,sy=134,ex=184+6*cos(wa),ey=116-10*sin(wa)
c.save();c.translate(ex,ey);c.rotate(.5+wa)
for(const[lw,col]of[[9,'#111'],[4,FL]])c.lineWidth=lw,c.strokeStyle=col,c.beginPath(),c.moveTo(0,4),c.lineTo(0,-34),c.stroke()
c.strokeStyle='#111';c.fillStyle=GL[0];c.lineWidth=4;star(c,0,-42,13,wa*2);c.restore()
line(c,[[sx,sy],[164,132],[ex,ey]],6,SKIN)
c.lineWidth=4;c.fillStyle=SKIN;c.beginPath();c.arc(ex,ey,6,0,T);c.fill();c.stroke()
c.save();c.translate(128,92);c.scale(.55,.55);c.translate(-128,-128)
c.lineWidth=9;c.fillStyle=HD;c.beginPath();c.moveTo(128,36);c.bezierCurveTo(198,36,210,100,198,156);c.quadraticCurveTo(184,170,170,156);c.lineTo(86,156);c.quadraticCurveTo(72,170,58,156);c.bezierCurveTo(46,100,58,36,128,36);c.fill();c.stroke()
c.fillStyle=SKIN;for(const d of[-1,1])c.beginPath(),c.moveTo(128+d*50,108),c.quadraticCurveTo(128+d*86,82,128+d*96,70),c.quadraticCurveTo(128+d*84,118,128+d*54,138),c.closePath(),c.fill(),c.stroke()
c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke()
eye(c,103,140,-1);eye(c,153,140,1)
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*42,162,13,7,0,0,T),c.fill()
c.lineWidth=6;c.fillStyle='#c92a2a';c.beginPath();c.moveTo(116,164);c.quadraticCurveTo(128,182,140,164);c.closePath();c.fill();c.stroke()
c.lineWidth=9;c.fillStyle=HAIR;c.beginPath();c.moveTo(64,140)
c.bezierCurveTo(52,70,90,38,128,38);c.bezierCurveTo(166,38,204,70,192,140)
c.quadraticCurveTo(186,112,176,100);c.quadraticCurveTo(168,106,162,114);c.quadraticCurveTo(156,98,146,92);c.quadraticCurveTo(140,104,132,110)
c.quadraticCurveTo(126,96,116,92);c.quadraticCurveTo(110,106,100,110);c.quadraticCurveTo(96,98,88,98);c.quadraticCurveTo(82,108,80,114)
c.quadraticCurveTo(70,110,64,140);c.closePath();c.fill();c.stroke()
c.strokeStyle=HL;c.lineWidth=7;for(const[a,e]of[[1.26,1.38],[1.46,1.54],[1.62,1.72]])c.beginPath(),c.arc(128,104,56,PI*a,PI*e),c.stroke()
c.strokeStyle='#111';c.lineWidth=6;c.fillStyle=DR;for(let k=0;k<5;k++){const a=k*T/5-PI/2;c.beginPath();c.ellipse(78+16*cos(a),66+16*sin(a),11,9,a,0,T);c.fill();c.stroke()}
c.fillStyle='#ffd43b';c.beginPath();c.arc(78,66,8,0,T);c.fill();c.stroke()
c.restore()
}
+56
View File
@@ -0,0 +1,56 @@
// butter-blonde girl in a bathrobe blow-drying her hair, long locks whooshing and fluttering in the air stream, eyes squinting, droplets flying off
const{sin,cos,PI,max}=Math,T=2*PI
export const frames=12,delay=90
const SKIN='#ffe3d1',HAIR='#ffe066',HD='#f2b705',HL='#fff9db',ROBE='#ffa8a8',RD='#fa5252',DRY='#9775fa',DD='#7048e8',BL='#ff8fab',MO='#c92a2a',DROP='#a5d8ff'
// a tapered lock streaming left from (x,y), rippling with phase o
const lock=(c,x,y,len,w0,o,t)=>{
const P=[...Array(11)].map((_,k)=>{const f=k/10;return[x-len*f,y+f*f*10+9*f*sin(T*t*2-f*5+o)]}),L=[],R=[]
P.forEach(([px,py],k)=>{
const[ax,ay]=P[max(0,k-1)],[bx,by]=P[Math.min(10,k+1)],dx=bx-ax,dy=by-ay,n=Math.hypot(dx,dy),w=w0*(1-k/10*.9)/2
L.push([px-dy/n*w,py+dx/n*w]);R.push([px+dy/n*w,py-dx/n*w])
})
c.beginPath();c.moveTo(...L[0]);for(const p of L)c.lineTo(...p);for(const p of R.reverse())c.lineTo(...p);c.closePath();c.fill();c.stroke()
}
export default(c,t)=>{
c.lineWidth=6
// air stream: dashes rushing left past her head
c.save();c.setLineDash([20,14]);c.lineDashOffset=-68*t
for(const[l,s]of[[9,'#111'],[3.5,'#fff']]){c.lineWidth=l;c.strokeStyle=s;for(const[y,o]of[[42,0],[60,17],[30,9]])c.beginPath(),c.moveTo(196,y+40),c.bezierCurveTo(160,y,90,y+4,10,y+14+o/4),c.stroke()}
c.restore();c.strokeStyle='#111';c.lineWidth=6
// streaming locks behind the head
c.fillStyle=HD;for(const[x,y,len,w,o]of[[86,74,92,30,0],[78,108,104,34,1.3],[76,144,100,32,2.6],[84,178,86,28,3.9]])lock(c,x,y,len,w,o,t)
c.fillStyle=HAIR;for(const[x,y,len,w,o]of[[96,92,78,26,.7],[90,128,94,30,2],[90,162,86,26,3.3]])lock(c,x,y,len,w,o,t)
c.fillStyle=HD;c.beginPath();c.moveTo(128,36);c.bezierCurveTo(196,36,200,90,194,150);c.quadraticCurveTo(190,178,176,188);c.lineTo(80,188);c.bezierCurveTo(60,150,56,36,128,36);c.fill();c.stroke()
// robe with a wide white collar
c.fillStyle=ROBE;c.beginPath();c.moveTo(100,190);c.quadraticCurveTo(62,198,54,256);c.lineTo(202,256);c.quadraticCurveTo(194,198,156,190);c.closePath();c.fill();c.stroke()
c.fillStyle='#fff';c.beginPath();c.moveTo(102,190);c.lineTo(128,240);c.lineTo(154,190);c.lineTo(166,196);c.lineTo(132,256);c.lineTo(122,256);c.lineTo(90,196);c.closePath();c.fill();c.stroke()
c.fillStyle=SKIN;c.beginPath();c.moveTo(116,168);c.lineTo(116,194);c.lineTo(128,226);c.lineTo(140,194);c.lineTo(140,168);c.fill();c.beginPath();c.moveTo(116,168);c.lineTo(116,194);c.moveTo(140,168);c.lineTo(140,194);c.stroke()
// face, squinting against the wind
c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke()
c.lineWidth=6;for(const d of[-1,1]){const x=128+d*25;c.beginPath();c.moveTo(x+d*13,130);c.lineTo(x-d*9,141);c.lineTo(x+d*13,151);c.stroke()}
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,162,13,6,0,0,T),c.fill()
c.lineWidth=2.5;for(const d of[-1,1])for(const k of[-5,0,5])c.beginPath(),c.moveTo(128+d*44+k-2,165),c.lineTo(128+d*44+k+2,159),c.stroke()
c.lineWidth=3.5;c.fillStyle=MO;c.beginPath();c.moveTo(118,168);c.quadraticCurveTo(128,162,138,168);c.quadraticCurveTo(136,178,128,178);c.quadraticCurveTo(120,178,118,168);c.fill();c.stroke()
// bangs swept left and fluttering
const f=k=>4*sin(T*t*2+k)
c.lineWidth=6;c.fillStyle=HAIR;c.beginPath();c.moveTo(70,148)
c.bezierCurveTo(54,74,88,36,128,36);c.bezierCurveTo(168,36,196,70,184,120);c.quadraticCurveTo(182,104,176,98)
c.quadraticCurveTo(160,104,150+f(0),118);c.quadraticCurveTo(140,98,124,96);c.quadraticCurveTo(112,100,98+f(1),118)
c.quadraticCurveTo(96,100,84,98);c.quadraticCurveTo(68,104,50+f(2),112+f(3));c.quadraticCurveTo(66,96,72,90);c.quadraticCurveTo(68,120,70,148);c.closePath();c.fill();c.stroke()
c.strokeStyle=HL;c.lineWidth=5;for(const[a,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,100,56,PI*a,PI*e),c.stroke()
c.strokeStyle='#111'
// droplets flung off to the left
c.fillStyle=DROP;c.lineWidth=3
for(const[y,o]of[[70,0],[120,.33],[170,.66],[96,.5]]){const p=(t+o)%1,x=40-40*p,yy=y-8*p;if(p<.8){c.beginPath();c.ellipse(x,yy,6,4,-.2,0,T);c.fill();c.stroke()}}
// hair dryer from the right, held by its handle
for(const[l,s]of[[26,'#111'],[17,ROBE]])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),c.moveTo(196,256),c.quadraticCurveTo(222,214,228,172),c.stroke()
c.strokeStyle='#111';c.lineWidth=5;c.fillStyle=DRY
c.beginPath();c.roundRect(214,112,22,52,8);c.fill();c.stroke()
c.beginPath();c.moveTo(194,84);c.lineTo(212,78);c.lineTo(212,118);c.lineTo(194,112);c.closePath();c.fill();c.stroke()
c.beginPath();c.roundRect(208,70,42,56,22);c.fill();c.stroke()
c.fillStyle=DD;c.beginPath();c.arc(232,98,12,0,T);c.fill();c.stroke()
c.lineWidth=3;c.beginPath();for(let k=0;k<3;k++){const a=k*T/3+t*T*3;c.moveTo(232,98);c.lineTo(232+cos(a)*10,98+sin(a)*10)}c.stroke()
c.fillStyle='#fff';c.lineWidth=2.5;c.beginPath();c.roundRect(218,128,6,14,3);c.fill();c.stroke()
c.lineWidth=5;c.fillStyle=SKIN;c.beginPath();c.ellipse(226,150,13,14,0,0,T);c.fill();c.stroke()
c.lineWidth=3;c.beginPath();c.moveTo(216,146);c.lineTo(228,146);c.moveTo(216,154);c.lineTo(228,154);c.stroke()
}
+77
View File
@@ -0,0 +1,77 @@
// lavender-gray haired girl with a scrunchie in her teeth gathering her long hair up, tying a high ponytail that swishes, then pulling it loose again
const{sin,cos,PI,max,min}=Math,T=2*PI
export const frames=20,delay=80
const SKIN='#ffe3d1',HAIR='#b9b8d6',HD='#8d8ab8',HL='#f1f0fa',EYE='#f06595',ED='#a61e4d',HOOD='#74c0fc',HOD='#4dabf7',SCR='#ff8787',SCD='#e03131',BL='#ffa8a8',MO='#c92a2a'
const ease=x=>x<=0?0:x>=1?1:x*x*(3-2*x)
const MOUTH=[128,174],TIE=[128,40]
const eye=(c,x,y,d,u)=>{
c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill()
c.save();c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.clip();c.fillStyle=EYE;c.fill();c.fillStyle=ED;c.beginPath();c.ellipse(x,y-8,13,10,0,0,T);c.fill()
c.fillStyle='#111';c.beginPath();c.ellipse(x,y+3-u,5.5,7.5,0,0,T);c.fill();c.fillStyle='#fff';c.beginPath();c.arc(x-4,y-5-u,4.5,0,T);c.fill();c.beginPath();c.arc(x+5,y+8-u,2,0,T);c.fill();c.restore()
c.lineWidth=2.5;c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.stroke()
c.lineWidth=6;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke()
}
// puffy scrunchie ring
const scrunchie=(c,x,y,sx,sy)=>{
c.fillStyle=SCR;c.lineWidth=4;c.beginPath();for(let k=0;k<=24;k++){const a=k*T/24,r=1+.14*(k%2);c.lineTo(x+cos(a)*sx*r,y+sin(a)*sy*r)}c.closePath();c.fill();c.stroke()
c.fillStyle=SCD;c.beginPath();c.ellipse(x,y,sx*.45,sy*.45,0,0,T);c.fill();c.stroke()
}
export default(c,t)=>{
const g=ease((t-.12)/.2)-ease((t-.84)/.1),tied=t>=.42&&t<.84
const al=ease((t-.12)/.18)-ease((t-.42)/.1),ar=max(al,ease((t-.78)/.06)-ease((t-.88)/.06))
// where the scrunchie is: teeth, carried round the side of her head, on the ponytail, then back to her teeth
const side=s=>{const u=1-s;return[u*u*MOUTH[0]+2*u*s*226+s*s*TIE[0]+12*s*(1-s),u*u*MOUTH[1]+2*u*s*110+s*s*TIE[1]]}
const sp=t<.32?MOUTH:t<.42?side(Math.sqrt((t-.32)/.1)):t<.82?TIE:t<.94?side(1-((t-.82)/.12)**2):MOUTH
const carry=t>=.32&&t<.42||t>=.82&&t<.94,sw=.16*sin(T*(t-.42)/.42*2)
c.lineWidth=6
// ponytail sits behind the head, swinging from the tie
if(tied){
c.save();c.translate(...TIE);c.rotate(sw)
c.fillStyle=HAIR;c.beginPath();c.moveTo(-12,4);c.bezierCurveTo(-10,-30,46,-40,70,-6);c.bezierCurveTo(94,30,86,90,96,134);c.bezierCurveTo(70,108,66,60,56,20);c.bezierCurveTo(44,-6,14,-6,12,6);c.closePath();c.fill();c.stroke()
c.strokeStyle=HD;c.lineWidth=3;c.beginPath();c.moveTo(30,-16);c.bezierCurveTo(64,-14,76,40,84,100);c.stroke();c.strokeStyle='#111'
c.restore()
}
// back hair: long and loose, shrinking into the gathered shape
const by=250-112*g,bw=86-14*g
c.fillStyle=HD;c.beginPath();c.moveTo(128,34);c.bezierCurveTo(128+bw,34,128+bw+8,110,128+bw+2,by-20);c.quadraticCurveTo(128+bw-4,by+4,128+bw-24,by)
c.lineTo(128-bw+24,by);c.quadraticCurveTo(128-bw+4,by+4,128-bw-2,by-20);c.bezierCurveTo(128-bw-8,110,128-bw,34,128,34);c.fill();c.stroke()
// the bundle she's holding up before it's tied
if(g>.05&&!tied){c.fillStyle=HAIR;c.beginPath();c.moveTo(108,44);c.quadraticCurveTo(112,44-30*g,128,40-36*g);c.quadraticCurveTo(144,44-30*g,148,44);c.closePath();c.fill();c.stroke()}
c.fillStyle=HOOD;c.beginPath();c.moveTo(100,190);c.quadraticCurveTo(62,198,54,256);c.lineTo(202,256);c.quadraticCurveTo(194,198,156,190);c.closePath();c.fill();c.stroke()
c.fillStyle=HOD;for(const d of[-1,1])c.beginPath(),c.moveTo(128+d*6,194),c.quadraticCurveTo(128+d*44,190,128+d*52,214),c.quadraticCurveTo(128+d*30,206,128+d*6,214),c.closePath(),c.fill(),c.stroke()
c.lineWidth=4;for(const d of[-1,1])c.beginPath(),c.moveTo(128+d*12,212),c.lineTo(128+d*14,240),c.stroke()
c.fillStyle=SKIN;c.lineWidth=6;c.beginPath();c.moveTo(116,168);c.lineTo(116,194);c.lineTo(140,194);c.lineTo(140,168);c.fill();c.beginPath();c.moveTo(116,168);c.lineTo(116,192);c.moveTo(140,168);c.lineTo(140,192);c.stroke()
// arms up behind her head
const hands=[]
for(const[d,a]of[[-1,al],[1,ar]]){
if(a<.02)continue
// elbows and hands swing out wide on the way up and down instead of crossing the chest
const q=(p0,p1,p2)=>[0,1].map(i=>(1-a)*(1-a)*p0[i]+2*a*(1-a)*p1[i]+a*a*p2[i])
const hp=d>0&&carry?sp:[128+d*60,58],e=q([128+d*70,282],[128+d*126,214],[128+d*110,116]),h=q([128+d*64,310],[128+d*134,170],hp)
for(const[l,s]of[[28,'#111'],[18,HOOD]])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),c.moveTo(128+d*46,216),c.lineTo(...e),c.lineTo(...h),c.stroke()
hands.push(h)
}
c.strokeStyle='#111';c.lineWidth=6
c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke()
if(tied){c.lineWidth=6;for(const x of[103,153])c.beginPath(),c.arc(x,146,13,PI*1.15,PI*1.85),c.stroke()}
else{const u=g>.3?6:0;eye(c,103,140,-1,u);eye(c,153,140,1,u)}
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,160,13,6,0,0,T),c.fill()
c.lineWidth=3.5;c.fillStyle=MO
if(tied){c.beginPath();c.moveTo(116,164);c.quadraticCurveTo(128,184,140,164);c.closePath();c.fill();c.stroke()}
else{c.beginPath();c.ellipse(128,172,9,6,0,0,T);c.fill();c.stroke()}
// side locks framing the face, short once the hair is gathered
const sy=232-84*g
c.lineWidth=6;c.fillStyle=HAIR
for(const d of[-1,1])c.beginPath(),c.moveTo(128+d*52,100),c.quadraticCurveTo(128+d*64,sy-40,128+d*56,sy),c.quadraticCurveTo(128+d*48,sy-30,128+d*40,120),c.closePath(),c.fill(),c.stroke()
c.beginPath();c.moveTo(70,140);c.bezierCurveTo(54,74,88,36,128,36);c.bezierCurveTo(168,36,202,74,186,140)
c.quadraticCurveTo(184,112,178,100);c.quadraticCurveTo(168,100,162,114);c.quadraticCurveTo(156,98,144,94);c.quadraticCurveTo(140,106,130,112)
c.quadraticCurveTo(124,98,112,94);c.quadraticCurveTo(108,106,98,112);c.quadraticCurveTo(92,98,84,98);c.quadraticCurveTo(78,110,78,104)
c.quadraticCurveTo(70,120,70,140);c.closePath();c.fill();c.stroke()
c.strokeStyle=HL;c.lineWidth=5;for(const[a,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,102,56,PI*a,PI*e),c.stroke()
c.strokeStyle='#111'
// scrunchie: squashed in her teeth, upright on the ponytail
const m=(sp[1]-TIE[1])/(MOUTH[1]-TIE[1])
scrunchie(c,...sp,13-3*m,8+6*(1-m)*(tied?1:.6))
c.lineWidth=5;c.fillStyle=SKIN;for(const[x,y]of hands)c.beginPath(),c.ellipse(x,y+6,11,12,0,0,T),c.fill(),c.stroke()
if(tied&&t<.56){c.fillStyle='#ffd43b';c.lineWidth=3.5;const r=12*sin(PI*(t-.42)/.14);for(const[x,y]of[[96,24],[176,44]]){c.beginPath();c.moveTo(x,y-r);c.quadraticCurveTo(x+r*.2,y-r*.2,x+r,y);c.quadraticCurveTo(x+r*.2,y+r*.2,x,y+r);c.quadraticCurveTo(x-r*.2,y+r*.2,x-r,y);c.quadraticCurveTo(x-r*.2,y-r*.2,x,y-r);c.fill();c.stroke()}}
}
+71
View File
@@ -0,0 +1,71 @@
// full-body chibi with apricot pigtails hiccuping twice per loop: a little hop, wide eyes, a hand over her mouth and a tiny hic bubble popping out
const{sin,PI,max,min,exp}=Math,T=2*PI
export const frames=20,delay=70
const SKIN='#ffe3d1',HAIR='#ffb87a',HD='#f0883e',HL='#ffe8cc',EYE='#f59f00',ED='#b35900',DR='#38d9a9',DRD='#0ca678',SHOE='#8d6346',BOB='#ffd43b',BL='#ffa8a8',HIC=[.1,.6]
const eye=(c,x,y,d,wide)=>{
c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill()
c.save();c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.clip()
if(wide){c.fillStyle=EYE;c.beginPath();c.arc(x,y+2,6.5,0,T);c.fill();c.fillStyle='#111';c.beginPath();c.arc(x,y+2,3,0,T);c.fill();c.fillStyle='#fff';c.beginPath();c.arc(x-2,y,1.6,0,T);c.fill()}
else{c.fillStyle=EYE;c.fill();c.fillStyle=ED;c.beginPath();c.ellipse(x,y-8,13,10,0,0,T);c.fill();c.fillStyle='#111';c.beginPath();c.ellipse(x,y+3,5.5,7.5,0,0,T);c.fill()
c.fillStyle='#fff';c.beginPath();c.arc(x-4,y-5,4.5,0,T);c.fill();c.beginPath();c.arc(x+5,y+8,2,0,T);c.fill()}
c.restore();c.lineWidth=3.5;c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.stroke()
c.lineWidth=8;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke()
}
export default(c,t)=>{
// u is time since the latest hiccup, so everything below reacts to it
const u=min(...HIC.map(h=>(t-h+1)%1)),hop=u<.16?-18*sin(PI*u/.16):0,jolt=exp(-u*14),wide=u<.22,Z=.66
const dy=Math.round(hop)
c.fillStyle='rgba(17,17,17,.18)';c.beginPath();c.ellipse(128,248,32*(1+hop/60),5,0,0,T);c.fill()
c.translate(128,250);c.scale(1.1,1.1);c.translate(-128,-250+dy)
for(const d of[-1,1])for(const[l,s]of[[15,'#111'],[8,SKIN]])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),c.moveTo(128+d*12,212),c.lineTo(128+d*12-d*3*(hop<0?1:0),234),c.stroke()
c.strokeStyle='#111';c.lineWidth=5;c.fillStyle='#fff';for(const d of[-1,1])c.beginPath(),c.roundRect(128+d*12-6,224,12,10,3),c.fill(),c.stroke()
c.fillStyle=SHOE;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*14,240,11,6.5,0,0,T),c.fill(),c.stroke()
// left arm hangs, flapping out a little on each hiccup
for(const[l,s]of[[15,'#111'],[8,SKIN]])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),c.moveTo(104,180),c.lineTo(90-8*jolt,204-6*jolt),c.stroke()
c.strokeStyle='#111';c.lineWidth=5;c.fillStyle=SKIN;c.beginPath();c.arc(89-8*jolt,207-6*jolt,6,0,T);c.fill();c.stroke()
c.fillStyle='#fff';c.beginPath();c.moveTo(112,164);c.lineTo(144,164);c.lineTo(146,184);c.lineTo(110,184);c.closePath();c.fill();c.stroke()
c.fillStyle=DR;c.beginPath();c.moveTo(108,178);c.lineTo(148,178);c.lineTo(166,218);c.quadraticCurveTo(128,228,90,218);c.closePath();c.fill();c.stroke()
c.lineWidth=4;for(const d of[-1,1])c.beginPath(),c.moveTo(128+d*16,178),c.lineTo(128+d*14,166),c.stroke()
c.fillStyle=BOB;for(const d of[-1,1])c.beginPath(),c.arc(128+d*15,182,3.5,0,T),c.fill(),c.stroke()
c.strokeStyle=DRD;c.lineWidth=3;c.beginPath();c.moveTo(94,212);c.quadraticCurveTo(128,220,162,212);c.stroke();c.strokeStyle='#111'
c.save();c.translate(128,72-4*jolt);c.scale(Z,Z);c.translate(-128,-40)
// pigtails swing out with each hop
c.lineWidth=8;c.fillStyle=HAIR
for(const d of[-1,1]){
c.save();c.translate(128+d*70,148);c.scale(d,1);c.rotate(-(.2+.3*jolt))
c.beginPath();c.moveTo(-10,-4);c.bezierCurveTo(-12,30,-4,64,14,84);c.bezierCurveTo(22,70,18,62,12,58);c.bezierCurveTo(18,36,16,14,10,-4);c.closePath();c.fill();c.stroke()
c.restore()
}
c.fillStyle=HD;c.beginPath();c.moveTo(128,36);c.bezierCurveTo(196,36,206,96,196,150);c.lineTo(60,150);c.bezierCurveTo(50,96,60,36,128,36);c.fill();c.stroke()
c.fillStyle=BOB;for(const d of[-1,1])c.beginPath(),c.arc(128+d*70,150,10,0,T),c.fill(),c.stroke()
c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke()
eye(c,103,140,-1,wide);eye(c,153,140,1,wide)
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,164,14,7,0,0,T),c.fill()
c.lineWidth=8;c.fillStyle=HAIR;c.beginPath();c.moveTo(68,146)
c.bezierCurveTo(52,74,88,38,128,38);c.bezierCurveTo(168,38,204,74,188,146)
c.quadraticCurveTo(186,118,180,104);c.lineTo(166,110);c.quadraticCurveTo(160,96,150,94);c.lineTo(142,110)
c.quadraticCurveTo(132,96,122,94);c.lineTo(114,110);c.quadraticCurveTo(106,96,96,96);c.lineTo(88,110)
c.lineTo(76,104);c.quadraticCurveTo(70,126,68,146);c.closePath();c.fill();c.stroke()
c.strokeStyle=HL;c.lineWidth=6;for(const[a,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,58,PI*a,PI*e),c.stroke()
// worried brows, raised on the hiccup
c.strokeStyle='#111';c.lineWidth=6;for(const d of[-1,1])c.beginPath(),c.moveTo(128+d*14,116-6*jolt),c.lineTo(128+d*38,110-10*jolt),c.stroke()
c.restore()
// right hand clapped over her mouth
for(const[l,s]of[[15,'#111'],[8,SKIN]])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),c.moveTo(150,180),c.lineTo(168,184),c.lineTo(142,158-4*jolt),c.stroke()
c.strokeStyle='#111';c.lineWidth=5;c.fillStyle=SKIN;c.beginPath();c.ellipse(136,157-4*jolt,13,9,-.3,0,T);c.fill();c.stroke()
c.beginPath();c.ellipse(147,151-4*jolt,4.5,6.5,-.5,0,T);c.fill();c.stroke()
// jolt ticks beside her head
if(jolt>.25)for(const[l,st]of[[7,'#111'],[2.5,'#fff']]){c.lineWidth=l;c.strokeStyle=st;for(const d of[-1,1])for(const k of[-1,0,1])c.beginPath(),c.moveTo(128+d*(56+4*k*k),66+k*16),c.lineTo(128+d*(68+4*k*k),62+k*20),c.stroke()}
c.strokeStyle='#111'
// the hic bubble pops out and floats away, in screen space so the hop doesn't push it off the top
if(u<.4){
const p=u/.4,sc=min(1,u/.05),x=204,y=48-14*p
c.setTransform(1,0,0,1,0,0);c.save();c.globalAlpha=p>.7?1-(p-.7)/.3:1;c.translate(x,y);c.scale(sc,sc)
c.fillStyle='#fff';c.lineWidth=4;c.beginPath();c.roundRect(-27,-17,54,32,14);c.fill();c.stroke()
c.beginPath();c.moveTo(-20,10);c.lineTo(-30,26);c.lineTo(-8,14);c.fill();c.stroke()
c.fillStyle='#fff';c.beginPath();c.roundRect(-24,-14,48,26,12);c.fill()
c.lineWidth=3.5;c.beginPath();c.moveTo(-16,-8);c.lineTo(-16,8);c.moveTo(-16,0);c.quadraticCurveTo(-10,-6,-7,0);c.lineTo(-7,8);c.moveTo(1,-1);c.lineTo(1,8);c.stroke()
c.beginPath();c.arc(14,3,5.5,.25*PI,1.75*PI);c.stroke();c.fillStyle='#111';c.beginPath();c.arc(1,-7,2.2,0,T);c.fill()
c.restore()
}
}
+43
View File
@@ -0,0 +1,43 @@
// girl with long magenta hair twirling a striped hula hoop around her waist, hips swaying against it, arms up
const{sin,cos,PI,max,min}=Math,T=2*PI
export const frames=16,delay=70
const SKIN='#ffe3d1',HAIR='#da3ea0',HD='#a61e7a',HL='#fcc2e7',EYE='#15aabf',ED='#0b7285',TEE='#ffd43b',TD='#f59f00',SHO='#20c997',SD='#0ca678',SHOE='#f783ac',BL='#ffa8a8',HOOP=['#ff6b6b','#ffd43b','#69db7c','#4dabf7','#b197fc','#ff922b']
const line=(c,pts,w,col)=>{for(const[lw,s]of[[w+8,'#111'],[w,col]]){c.lineWidth=lw;c.strokeStyle=s;c.beginPath();pts.forEach(([x,y],k)=>k?c.lineTo(x,y):c.moveTo(x,y));c.stroke()}c.strokeStyle='#111'}
export default(c,t,i)=>{
const a=T*2*t,hx=128-6*cos(a),wy=168,sx=128-2*cos(a),bob=1.5*sin(2*a)
const hc=[hx+14*cos(a),wy+2+4*sin(a)],R=[64,15]
const hoop=(a0,a1)=>{
for(const[lw,s]of[[15,'#111']])c.lineWidth=lw,c.strokeStyle=s,c.beginPath(),c.ellipse(...hc,...R,0,a0,a1),c.stroke()
const n=12;for(let k=0;k<n;k++){const s0=((k*T/n-a*1.5)%T+T)%T;for(let j=-1;j<=1;j++){const u0=max(a0,s0+j*T),u1=min(a1,s0+T/n+j*T);if(u1>u0)c.lineWidth=8,c.strokeStyle=HOOP[k%6],c.beginPath(),c.ellipse(...hc,...R,0,u0,u1),c.stroke()}}
c.strokeStyle='#111'
}
c.translate(128,150);c.scale(1.07,1.07);c.translate(-128,-150)
c.fillStyle='#dee2e6';c.beginPath();c.ellipse(128,234,46,6,0,0,T);c.fill()
hoop(PI,T)
const head=g=>{c.save();c.translate(sx,90+bob);c.rotate(-.04*cos(a));c.scale(.56,.56);c.translate(-128,-120);g();c.restore()}
head(()=>{
c.lineWidth=9;c.fillStyle=HAIR;c.beginPath();c.moveTo(128,36);c.bezierCurveTo(200,36,212,110,208,190);c.quadraticCurveTo(216+10*cos(a),236,200+14*cos(a),262);c.quadraticCurveTo(186,252,176,264+4*sin(a));c.lineTo(80,264-4*sin(a));c.quadraticCurveTo(70,252,56+14*cos(a),262);c.quadraticCurveTo(40+10*cos(a),236,48,190);c.bezierCurveTo(44,110,56,36,128,36);c.fill();c.stroke()
c.strokeStyle=HD;c.lineWidth=5;for(const d of[-1,1])c.beginPath(),c.moveTo(128+d*62,150),c.quadraticCurveTo(128+d*70+8*cos(a),210,128+d*64+10*cos(a),248),c.stroke();c.strokeStyle='#111'
})
for(const[x,d]of[[hx-10,-1],[hx+10,1]]){const kx=(x+128+d*12)/2+d*2;line(c,[[x,186],[kx,206],[128+d*12,226]],8,SKIN)}
for(const d of[-1,1]){c.fillStyle=SHOE;c.lineWidth=5;c.beginPath();c.ellipse(128+d*15,229,12,7,0,0,T);c.fill();c.stroke();c.fillStyle='#fff';c.beginPath();c.ellipse(128+d*15,233,12,3,0,0,PI);c.fill()}
c.fillStyle=SHO;c.lineWidth=5;c.beginPath();c.moveTo(hx-20,168);c.lineTo(hx+20,168);c.lineTo(hx+25,192);c.lineTo(hx+3,192);c.lineTo(hx,186);c.lineTo(hx-3,192);c.lineTo(hx-25,192);c.closePath();c.fill();c.stroke()
c.fillStyle=SKIN;c.beginPath();c.rect(sx-6,124+bob,12,10);c.fill()
c.fillStyle=TEE;c.lineWidth=5;c.beginPath();c.moveTo(sx-14,130+bob);c.lineTo(sx+14,130+bob);c.lineTo(sx+28,138+bob);c.lineTo(sx+30,148+bob);c.lineTo(sx+20,146+bob);c.lineTo(hx+21,172);c.lineTo(hx-21,172);c.lineTo(sx-20,146+bob);c.lineTo(sx-30,148+bob);c.lineTo(sx-28,138+bob);c.closePath();c.fill();c.stroke()
c.lineWidth=4;c.beginPath();c.moveTo(sx-9,131+bob);c.quadraticCurveTo(sx,139+bob,sx+9,131+bob);c.stroke()
c.fillStyle='#ff6b6b';c.lineWidth=3.5;c.beginPath();const px=(sx+hx)/2,py=154+bob/2;c.moveTo(px,py+7);c.bezierCurveTo(px-11,py-1,px-7,py-10,px,py-4);c.bezierCurveTo(px+7,py-10,px+11,py-1,px,py+7);c.fill();c.stroke()
head(()=>{
c.lineWidth=9;c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke()
c.lineWidth=8;for(const x of[103,153])c.beginPath(),c.arc(x,148,14,PI*1.15,PI*1.85),c.stroke()
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*42,160,13,7,0,0,T),c.fill()
c.fillStyle='#c92a2a';c.lineWidth=6;c.beginPath();c.moveTo(114,162);c.quadraticCurveTo(128,186,142,162);c.closePath();c.fill();c.stroke()
c.save();c.clip();c.fillStyle='#ff8fab';c.beginPath();c.ellipse(128,178,9,6,0,0,T);c.fill();c.restore()
c.fillStyle=HAIR;c.lineWidth=9;c.beginPath();c.moveTo(66,150);c.bezierCurveTo(50,74,90,36,132,36);c.bezierCurveTo(176,36,206,80,188,150)
c.quadraticCurveTo(184,118,174,100);c.quadraticCurveTo(160,104,150,118);c.quadraticCurveTo(146,98,134,88);c.quadraticCurveTo(116,110,92,116);c.quadraticCurveTo(100,104,102,92);c.quadraticCurveTo(84,104,76,118);c.quadraticCurveTo(68,130,66,150);c.closePath();c.fill();c.stroke()
c.strokeStyle=HL;c.lineWidth=8;for(const[a0,a1]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,56,PI*a0,PI*a1),c.stroke();c.strokeStyle='#111'
c.fillStyle='#ffd43b';c.lineWidth=6;c.beginPath();for(let k=0;k<10;k++){const r=k%2?6:14,b=k*PI/5-PI/2;c.lineTo(84+r*cos(b),74+r*sin(b))}c.closePath();c.fill();c.stroke()
})
for(const d of[-1,1]){const s=[sx+d*20,140+bob],w=sin(a+(d>0?PI:0)),e=[sx+d*42,118+bob],h=[sx+d*(54+4*w),78+bob-3*w];line(c,[s,e,h],8,SKIN);c.fillStyle=SKIN;c.lineWidth=4;c.beginPath();c.ellipse(h[0],h[1]-3,7,9,d*.3,0,T);c.fill();c.stroke()}
hoop(0,PI)
c.lineWidth=4;for(const d of[-1,1]){const x=hc[0]+d*78,y=hc[1]-2;c.beginPath();c.arc(x-d*14,y,16,d>0?-.5:PI-.5,d>0?.5:PI+.5);c.stroke()}
}
+52
View File
@@ -0,0 +1,52 @@
// figure skater with a sky-blue bun spinning on the ice, arms joined overhead, skirt flaring, a sparkle trail circling her
const{sin,cos,PI,max,min,abs}=Math,T=2*PI
export const frames=16,delay=70
const SKIN='#ffe3d1',HAIR='#8ec5fc',HD='#4dabf7',HL='#e7f5ff',DR='#cc5de8',DD='#9c36b5',SK=['#e599f7','#f783ac'],RIB='#f783ac',BL='#ffa8a8',ICE='#e7f5ff',IL='#a5d8ff'
const line=(c,pts,w,col)=>{for(const[lw,s]of[[w+8,'#111'],[w,col]]){c.lineWidth=lw;c.strokeStyle=s;c.beginPath();pts.forEach(([x,y],k)=>k?c.lineTo(x,y):c.moveTo(x,y));c.stroke()}c.strokeStyle='#111'}
const star=(c,x,y,r,col)=>{c.fillStyle=col;c.lineWidth=3.5;c.beginPath();for(let k=0;k<8;k++){const q=k%2?r*.38:r,b=k*PI/4;c.lineTo(x+q*cos(b),y+q*sin(b))}c.closePath();c.fill();c.stroke()}
export default(c,t,i)=>{
const q=T*2*t,cq=cos(q),sq=sin(q),w=abs(cq),bob=1.5*sin(2*q)
c.fillStyle=ICE;c.lineWidth=6;c.beginPath();c.ellipse(128,226,92,20,0,0,T);c.fill();c.stroke()
c.strokeStyle=IL;c.lineWidth=3;c.beginPath();c.ellipse(128,226,30,7,0,0,T);c.stroke();c.beginPath();c.ellipse(128,226,58,12,0,-2.6,-.4);c.stroke();c.strokeStyle='#fff';c.lineWidth=4;c.beginPath();c.moveTo(56,222);c.lineTo(74,218);c.moveTo(178,232);c.lineTo(198,229);c.stroke();c.strokeStyle='#111'
const orb=f=>{for(let k=0;k<3;k++){const a=q*.5+k*T/3+1,s=sin(a);if(f(s))star(c,128+84*cos(a),174+18*s,5+3*(s+1),['#ffd43b','#fff','#f783ac'][k])}}
orb(s=>s<0)
const arcs=d=>{for(const[y,r]of[[176,70],[116,58]]){const a0=d>0?.1:PI+.1;for(const[lw,s]of[[9,'#111'],[3.5,'#fff']])c.lineWidth=lw,c.strokeStyle=s,c.beginPath(),c.ellipse(128,y,r,r*.22,0,a0,a0+.9),c.stroke()}c.strokeStyle='#111'}
arcs(-1)
const sx=16*cq,fl=sq
line(c,[[128-4,184],[128-2,214]],8,SKIN)
c.fillStyle='#fff';c.lineWidth=5;c.beginPath();c.roundRect(118,206,18,14,5);c.fill();c.stroke();c.lineWidth=4;c.beginPath();c.moveTo(114,224);c.lineTo(142,224);c.stroke()
const kx=128+18*fl,fx=128+6*fl;line(c,[[132,184],[kx,198],[fx,206]],8,SKIN)
c.fillStyle='#fff';c.lineWidth=5;c.beginPath();c.ellipse(fx+4*fl,207,9,6,0,0,T);c.fill();c.stroke()
const skirt=()=>{c.beginPath();c.moveTo(104,160+bob);c.lineTo(152,160+bob);c.quadraticCurveTo(178,174,188,190);c.quadraticCurveTo(128,202,68,190);c.quadraticCurveTo(78,174,104,160+bob);c.closePath()}
c.fillStyle=SK[0];c.lineWidth=5;skirt();c.fill();c.save();c.clip()
for(let k=0;k<8;k++){const a=q+k*T/8;if(sin(a)>-.2&&k%2){const x=128+64*cos(a),wd=10+10*sin(a);c.fillStyle=SK[1];c.beginPath();c.moveTo(128+22*cos(a)-wd*.3,160);c.lineTo(128+22*cos(a)+wd*.3,160);c.lineTo(x+wd,200);c.lineTo(x-wd,200);c.closePath();c.fill()}}
c.restore();skirt();c.stroke()
c.fillStyle=DR;c.lineWidth=5;c.beginPath();c.moveTo(112,128+bob);c.lineTo(144,128+bob);c.quadraticCurveTo(152,146,150,164+bob);c.lineTo(106,164+bob);c.quadraticCurveTo(104,146,112,128+bob);c.closePath();c.fill();c.stroke()
c.fillStyle='#fff';for(let k=0;k<6;k++){const a=q+k*T/6;if(sin(a)>0){c.beginPath();c.arc(128+18*cos(a),146+bob+6*(k%2),2.4,0,T);c.fill()}}
for(const d of[-1,1]){const s=[128+d*14,134+bob],e=[128+d*(56+4*w),86+bob],h=[128+d*6,14+bob];line(c,[s,e,h],8,SKIN)}
c.fillStyle=SKIN;c.lineWidth=4;c.beginPath();c.ellipse(128,13+bob,9,7,0,0,T);c.fill();c.stroke()
c.fillStyle=SKIN;c.beginPath();c.rect(122,120+bob,12,10);c.fill()
const head=g=>{c.save();c.translate(128,96+bob);c.scale(.56,.56);c.translate(-128,-120);g();c.restore()}
const front=cq>-.25,ex=36*sq,es=26*cq
head(()=>{
c.lineWidth=9;c.fillStyle=HAIR;c.beginPath();c.moveTo(128,36);c.bezierCurveTo(196,36,206,96,198,150);c.lineTo(58,150);c.bezierCurveTo(50,96,60,36,128,36);c.fill();c.stroke()
c.beginPath();c.arc(128,30,30,0,T);c.fill();c.stroke();c.strokeStyle=HD;c.lineWidth=5;c.beginPath();c.arc(128,30,18,PI*.9,PI*2.1);c.stroke();c.strokeStyle='#111'
if(front){
c.fillStyle=SKIN;c.lineWidth=9;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke()
c.save();c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.clip()
c.lineWidth=8;for(const d of[-1,1]){const x=128+ex+d*es;if(abs(es)>8||d*sq>0)c.beginPath(),c.arc(x,146,13,PI*1.15,PI*1.85),c.stroke(),c.beginPath(),c.moveTo(x+d*12*sign(cq),138),c.lineTo(x+d*19*sign(cq),134),c.stroke()}
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+ex*1.1+d*42*cq,162,11*max(.4,w),6,0,0,T),c.fill()
c.fillStyle='#c92a2a';c.lineWidth=5;c.beginPath();c.arc(128+ex*1.1,166,7,.1*PI,.9*PI);c.closePath();c.fill();c.stroke();c.restore()
c.fillStyle=HAIR;c.lineWidth=9;c.beginPath();c.moveTo(70,140);c.bezierCurveTo(54,74,88,40,128,40);c.bezierCurveTo(168,40,202,74,186,140)
c.quadraticCurveTo(182,112,170,96);c.quadraticCurveTo(160,104,152,112);c.quadraticCurveTo(150,96,138,88);c.quadraticCurveTo(128,104,112,110);c.quadraticCurveTo(116,98,112,88);c.quadraticCurveTo(96,104,86,112);c.quadraticCurveTo(74,120,70,140);c.closePath();c.fill();c.stroke()
}else{
c.fillStyle=HAIR;c.lineWidth=9;c.beginPath();c.moveTo(72,100);c.bezierCurveTo(68,160,100,186,128,186);c.bezierCurveTo(156,186,188,160,184,100);c.bezierCurveTo(184,44,72,44,72,100);c.fill();c.stroke()
c.strokeStyle=HD;c.lineWidth=5;for(const d of[-1,0,1])c.beginPath(),c.moveTo(128+d*20,70),c.quadraticCurveTo(128+d*30,130,128+d*22,176),c.stroke();c.strokeStyle='#111'
}
c.strokeStyle=HL;c.lineWidth=8;c.beginPath();c.arc(128,104,56,PI*1.28,PI*1.42);c.stroke();c.beginPath();c.arc(128,30,22,PI*1.2,PI*1.5);c.stroke();c.strokeStyle='#111'
c.save();c.translate(128+34*sq,28);c.fillStyle=RIB;c.lineWidth=7;for(const d of[-1,1])c.beginPath(),c.moveTo(0,0),c.lineTo(d*24*max(.35,w),-12),c.lineTo(d*24*max(.35,w),12),c.closePath(),c.fill(),c.stroke();c.beginPath();c.arc(0,0,8,0,T);c.fill();c.stroke();c.restore()
})
arcs(1)
orb(s=>s>=0)
}
const sign=x=>x<0?-1:1
+51
View File
@@ -0,0 +1,51 @@
// chibi jiangshi with dark violet hair and a qing hat hopping with stiff arms held out, long sleeves swinging, the paper talisman fluttering up on each fall
const{sin,cos,PI,max,round}=Math,T=2*PI
export const frames=12,delay=80
const SKIN='#e9f5e1',HAIR='#5f3dc4',HD='#3b2a8c',HL='#b197fc',EYE='#fcc419',ED='#e67700',ROBE='#3bc9db',RD='#1098ad',GO='#ffd43b',HAT='#7048e8',HTD='#4c2fb0',RED='#fa5252',PAP='#ffe066',SH='#845ef7',BL='#ffc9c9'
const eye=(c,x,y,d)=>{
c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill()
c.save();c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.clip();c.fillStyle=EYE;c.fill();c.fillStyle=ED;c.beginPath();c.ellipse(x,y-8,13,10,0,0,T);c.fill();c.restore()
c.lineWidth=3;c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.stroke()
c.fillStyle='#111';c.beginPath();c.ellipse(x,y+3,5.5,7.5,0,0,T);c.fill()
c.fillStyle='#fff';c.beginPath();c.arc(x-4,y+1,4,0,T);c.fill()
c.fillStyle=SKIN;c.beginPath();c.rect(x-18,y-22,36,18);c.fill()
c.lineWidth=8;c.beginPath();c.moveTo(x-16,y-4);c.quadraticCurveTo(x,y-8,x+16,y-4);c.moveTo(x+d*15,y-5);c.lineTo(x+d*21,y-9);c.stroke()
}
const line=(c,pts,w,col)=>{for(const[lw,s]of[[w+8,'#111'],[w,col]]){c.lineWidth=lw;c.strokeStyle=s;c.beginPath();pts.forEach(([x,y],k)=>k?c.lineTo(x,y):c.moveTo(x,y));c.stroke()}c.strokeStyle='#111'}
export default(c,t)=>{
let sq=0,h=0,v=0
if(t<.2)sq=.7*sin(PI*t/.2)
else if(t<.8){const p=(t-.2)/.6;h=round(30*sin(PI*p));v=cos(PI*p)}
else sq=.5*sin(PI*(t-.8)/.2)
const fl=max(0,-v)
c.fillStyle='#e9ecef';c.beginPath();c.ellipse(128,240,44-h*.4,7-h*.08,0,0,T);c.fill()
c.save();c.translate(128,236-h);c.scale(.95*(1+sq*.1),.95*(1-sq*.12));c.translate(-128,-236)
for(const x of[120,136]){line(c,[[x,202],[x,224]],8,SKIN);c.lineWidth=5;c.fillStyle=SH;c.beginPath();c.ellipse(x+(x<128?-3:3),228,11,7,0,0,T);c.fill();c.stroke()}
c.fillStyle=ROBE;c.lineWidth=5;c.beginPath();c.moveTo(110,134);c.lineTo(146,134);c.lineTo(158,208);c.lineTo(98,208);c.closePath();c.fill();c.stroke()
c.fillStyle=GO;c.beginPath();c.rect(100,196,56,12);c.fill();c.stroke()
c.fillStyle=RD;c.beginPath();c.moveTo(128,136);c.lineTo(128,196);c.stroke()
c.fillStyle=GO;c.lineWidth=4;c.beginPath();c.arc(128,170,9,0,T);c.fill();c.stroke();c.beginPath();c.moveTo(122,170);c.lineTo(134,170);c.moveTo(128,164);c.lineTo(128,176);c.stroke()
const ay=146-6*v,dr=6+10*fl
for(const d of[-1,1]){
c.fillStyle=ROBE;c.lineWidth=5;c.beginPath();c.moveTo(128+d*14,136);c.lineTo(128+d*64,ay-8);c.lineTo(128+d*70,ay+12+dr);c.lineTo(128+d*50,ay+18+dr*.6);c.lineTo(128+d*16,156);c.closePath();c.fill();c.stroke()
c.fillStyle=GO;c.beginPath();c.moveTo(128+d*64,ay-8);c.lineTo(128+d*72,ay-6);c.lineTo(128+d*78,ay+14+dr);c.lineTo(128+d*70,ay+12+dr);c.closePath();c.fill();c.stroke()
c.fillStyle=SKIN;c.beginPath();c.ellipse(128+d*84,ay+8+dr*.5,7,10,-d*.3,0,T);c.fill();c.stroke()}
c.save();c.translate(128,92);c.scale(.6,.6);c.translate(-128,-128)
c.lineWidth=9;c.fillStyle=HD;c.beginPath();c.moveTo(128,44);c.bezierCurveTo(200,44,212,104,202,162);c.quadraticCurveTo(190,176,176,168);c.lineTo(80,168);c.quadraticCurveTo(66,176,54,162);c.bezierCurveTo(44,104,56,44,128,44);c.fill();c.stroke()
c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke()
eye(c,101,142,-1);eye(c,155,142,1)
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,164,13,7,0,0,T),c.fill()
c.lineWidth=6;c.beginPath();c.moveTo(114,168);c.quadraticCurveTo(128,178,142,168);c.stroke()
c.fillStyle='#fff';c.lineWidth=4;c.beginPath();c.moveTo(132,171);c.lineTo(136,180);c.lineTo(140,170);c.fill();c.stroke()
c.lineWidth=9;c.fillStyle=HAIR;c.beginPath();c.moveTo(68,150)
c.bezierCurveTo(56,90,90,64,128,64);c.bezierCurveTo(166,64,200,90,188,150)
c.quadraticCurveTo(184,118,174,106);c.lineTo(160,114);c.lineTo(150,100);c.lineTo(138,112);c.lineTo(118,112);c.lineTo(106,100);c.lineTo(96,114);c.lineTo(82,106);c.quadraticCurveTo(72,118,68,150);c.closePath();c.fill();c.stroke()
c.strokeStyle=HL;c.lineWidth=7;c.beginPath();c.moveTo(80,92);c.quadraticCurveTo(86,80,96,76);c.moveTo(168,86);c.quadraticCurveTo(174,96,176,104);c.stroke();c.strokeStyle='#111'
c.fillStyle=HAT;c.beginPath();c.moveTo(70,76);c.bezierCurveTo(70,20,186,20,186,76);c.closePath();c.fill();c.stroke()
c.fillStyle=HTD;c.beginPath();c.ellipse(128,78,76,16,0,0,T);c.fill();c.stroke()
c.fillStyle=RED;c.beginPath();c.arc(128,22,13,0,T);c.fill();c.stroke()
c.save();c.translate(128,82);c.transform(1,0,-.25*fl,1,0,0);c.scale(1,1-.55*fl)
c.fillStyle=PAP;c.lineWidth=6;c.beginPath();c.rect(-15,0,30,80);c.fill();c.stroke()
c.strokeStyle=RED;c.lineWidth=4;c.beginPath();c.moveTo(-6,10);c.lineTo(6,10);c.moveTo(0,10);c.lineTo(0,30);c.moveTo(-6,22);c.quadraticCurveTo(8,26,-4,36);c.quadraticCurveTo(8,44,-6,52);c.moveTo(-6,64);c.lineTo(6,64);c.moveTo(0,58);c.lineTo(0,72);c.stroke()
c.restore();c.restore();c.restore()
}
+54
View File
@@ -0,0 +1,54 @@
// girl with lime pigtails skipping rope, the rope sweeping over her head and under her hopping feet, pigtails bouncing
const{sin,cos,PI,max,min,abs}=Math,T=2*PI
export const frames=16,delay=70
const SKIN='#ffe3d1',HAIR='#94d82d',HD='#66a80f',HL='#e9fac8',EYE='#f06595',ED='#a61e4d',TEE='#ff922b',TD='#e8590c',JEAN='#4dabf7',JD='#1c7ed6',ROPE='#38d9a9',GRIP='#9775fa',TIE='#f783ac',BL='#ffa8a8'
const eye=(c,x,y,d)=>{
c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill()
c.save();c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.clip();c.fillStyle=EYE;c.fill();c.fillStyle=ED;c.beginPath();c.ellipse(x,y-8,13,10,0,0,T);c.fill();c.restore()
c.lineWidth=2.5;c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.stroke()
c.fillStyle='#111';c.beginPath();c.ellipse(x,y+3,5.5,7.5,0,0,T);c.fill()
c.fillStyle='#fff';c.beginPath();c.arc(x-4,y-5,4.5,0,T);c.fill();c.beginPath();c.arc(x+5,y+8,2,0,T);c.fill()
c.lineWidth=8;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke()
}
const line=(c,pts,w,col)=>{for(const[lw,s]of[[w+8,'#111'],[w,col]]){c.lineWidth=lw;c.strokeStyle=s;c.beginPath();pts.forEach(([x,y],k)=>k?c.lineTo(x,y):c.moveTo(x,y));c.stroke()}c.strokeStyle='#111'}
export default(c,t,i)=>{
const f=T*2*t,h=26*max(0,-cos(f)),cr=7*max(0,(cos(f)-.55)/.45),oy=cr-h,sw=sin(f)
const hy=162+oy,hl=[84-4*sw,hy-5*cos(f)],hr=[172+4*sw,hy-5*cos(f)],by=hy-(cos(f)>0?134:100)*cos(f)
const rope=()=>{const q=[2*128-(hl[0]+hr[0])/2,2*by-(hl[1]+hr[1])/2];for(const[lw,s]of[[10,'#111'],[5,ROPE]])c.lineWidth=lw,c.strokeStyle=s,c.beginPath(),c.moveTo(...hl),c.quadraticCurveTo(...q,...hr),c.stroke();c.strokeStyle='#111'}
c.translate(128,134);c.scale(1.06,1.06);c.translate(-128,-134)
c.fillStyle='#dee2e6';c.beginPath();c.ellipse(128,232,44*(1-h/70),6*(1-h/70),0,0,T);c.fill()
if(sw<=0)rope()
const head=g=>{c.save();c.translate(128,88+oy);c.scale(.56,.56);c.translate(-128,-120);g();c.restore()}
head(()=>{
for(const d of[-1,1]){
c.save();c.translate(128+d*60,78);c.rotate(-d*(.3-.32*sin(f-.6)))
c.lineWidth=9;c.fillStyle=HAIR;c.beginPath();c.moveTo(0,-6);c.bezierCurveTo(d*44,0,d*50,70,d*22,118);c.quadraticCurveTo(d*14,128,d*6,116);c.bezierCurveTo(d*18,70,d*6,30,0,-6);c.closePath();c.fill();c.stroke()
c.strokeStyle=HD;c.lineWidth=5;c.beginPath();c.moveTo(d*12,14);c.bezierCurveTo(d*28,40,d*30,74,d*20,100);c.stroke();c.strokeStyle='#111'
c.restore()
}
c.lineWidth=9;c.fillStyle=HAIR;c.beginPath();c.moveTo(128,36);c.bezierCurveTo(194,36,204,96,196,150);c.lineTo(60,150);c.bezierCurveTo(52,96,62,36,128,36);c.fill();c.stroke()
})
const lg=[[118,-1],[138,1]],fy=224-h
for(const[x,d]of lg){const air=h>4?min(1,h/14):0,kx=x+d*(3+cr*.8)-d*air*2,ky=(186+oy+fy)/2-air*4;line(c,[[x,184+oy],[kx,ky],[x+d*2-d*air*6*0,fy-6]],8,SKIN)}
for(const[x,d]of lg){c.fillStyle='#fff';c.lineWidth=5;c.beginPath();c.ellipse(x+d*5,fy-3,11,7,0,0,T);c.fill();c.stroke();c.strokeStyle=TD;c.lineWidth=3;c.beginPath();c.moveTo(x+d*5-7,fy-5);c.lineTo(x+d*5+7,fy-5);c.stroke();c.strokeStyle='#111'}
c.fillStyle=JEAN;c.lineWidth=5;c.beginPath();c.moveTo(106,166+oy);c.lineTo(150,166+oy);c.lineTo(154,190+oy);c.lineTo(131,190+oy);c.lineTo(128,182+oy);c.lineTo(125,190+oy);c.lineTo(102,190+oy);c.closePath();c.fill();c.stroke()
c.strokeStyle=JD;c.lineWidth=3;c.beginPath();c.moveTo(128,168+oy);c.lineTo(128,180+oy);c.stroke();c.strokeStyle='#111'
for(const[s,hd,d]of[[[110,136+oy],hl,-1],[[146,136+oy],hr,1]]){const e=[s[0]+d*12,(s[1]+hd[1])/2+4];line(c,[s,e,hd],8,SKIN)}
c.fillStyle=SKIN;c.beginPath();c.rect(122,122+oy,12,10);c.fill()
c.fillStyle=TEE;c.lineWidth=5;c.beginPath();c.moveTo(114,128+oy);c.lineTo(142,128+oy);c.lineTo(158,138+oy);c.lineTo(152,150+oy);c.lineTo(146,146+oy);c.lineTo(150,172+oy);c.lineTo(106,172+oy);c.lineTo(110,146+oy);c.lineTo(104,150+oy);c.lineTo(98,138+oy);c.closePath();c.fill();c.stroke()
c.fillStyle='#fff';c.lineWidth=4;c.beginPath();c.moveTo(118,129+oy);c.quadraticCurveTo(128,138+oy,138,129+oy);c.stroke()
c.fillStyle='#ffd43b';c.lineWidth=3.5;c.beginPath();for(let k=0;k<10;k++){const r=k%2?3.5:8,a=k*PI/5-PI/2;c.lineTo(128+r*cos(a),154+oy+r*sin(a))}c.closePath();c.fill();c.stroke()
for(const hd of[hl,hr]){c.save();c.translate(...hd);c.rotate(hd==hl?-.3:.3);c.fillStyle=GRIP;c.lineWidth=4;c.beginPath();c.roundRect(-5,-12,10,22,5);c.fill();c.stroke();c.restore();c.fillStyle=SKIN;c.lineWidth=4;c.beginPath();c.arc(hd[0],hd[1],6.5,0,T);c.fill();c.stroke()}
head(()=>{
c.lineWidth=9;c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke()
if(i==11){c.lineWidth=8;for(const x of[103,153])c.beginPath(),c.moveTo(x-15,142),c.quadraticCurveTo(x,150,x+15,142),c.stroke()}else eye(c,103,140,-1),eye(c,153,140,1)
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*42,162,12,6,0,0,T),c.fill()
c.fillStyle='#c92a2a';c.lineWidth=6;c.beginPath();c.moveTo(116,164);c.quadraticCurveTo(128,186,140,164);c.closePath();c.fill();c.stroke()
c.fillStyle=HAIR;c.lineWidth=9;c.beginPath();c.moveTo(70,140);c.bezierCurveTo(54,74,88,36,128,36);c.bezierCurveTo(168,36,202,74,186,140)
c.quadraticCurveTo(184,116,176,102);c.quadraticCurveTo(168,100,162,110);c.quadraticCurveTo(156,96,146,92);c.quadraticCurveTo(140,104,132,110)
c.quadraticCurveTo(126,96,118,92);c.quadraticCurveTo(112,104,104,110);c.quadraticCurveTo(98,96,90,98);c.quadraticCurveTo(84,104,80,110);c.quadraticCurveTo(72,118,70,140);c.closePath();c.fill();c.stroke()
c.strokeStyle=HL;c.lineWidth=8;for(const[a,e]of[[1.26,1.38],[1.46,1.54],[1.62,1.74]])c.beginPath(),c.arc(128,104,56,PI*a,PI*e),c.stroke();c.strokeStyle='#111'
c.fillStyle=TIE;c.lineWidth=7;for(const d of[-1,1])c.beginPath(),c.arc(128+d*60,76,11,0,T),c.fill(),c.stroke()
})
if(sw>0)rope()
}
+60
View File
@@ -0,0 +1,60 @@
// cozy chibi with a messy sandy bun and round glasses knitting cross-legged, needles clicking, the striped scarf creeping down, yarn ball rolling
const{sin,cos,PI,max}=Math,T=2*PI
export const frames=12,delay=100
const SKIN='#ffe3d1',HAIR='#e2c08d',HD='#b8955e',HL='#f7e8cc',EYE='#4dabf7',ED='#1864ab',BL='#ffa8a8',SW='#f783ac',SWD='#e64980',PANT='#748ffc',SOCK='#fff',CUSH='#ffc078',CUD='#fd7e14',Y1='#38d9a9',Y2='#fff4e6',YD='#0ca678',ND='#e0a96d'
const ds=(c,a,b,s,f)=>{for(const[l,k]of[[a,'#111'],[b,s]])c.lineWidth=l,c.strokeStyle=k,c.beginPath(),f(),c.stroke();c.strokeStyle='#111'}
const eye=(c,x,y,d)=>{
c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill()
c.save();c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.clip()
c.beginPath();c.ellipse(x,y+7,11.5,15,0,0,T);c.fillStyle=EYE;c.fill();c.lineWidth=2.5;c.stroke()
c.save();c.clip();c.fillStyle=ED;c.beginPath();c.ellipse(x,y-3,13,10,0,0,T);c.fill();c.restore()
c.fillStyle='#111';c.beginPath();c.ellipse(x,y+8,5.5,7.5,0,0,T);c.fill()
c.fillStyle='#fff';c.beginPath();c.arc(x-4,y+2,4.5,0,T);c.fill();c.beginPath();c.arc(x+5,y+12,2,0,T);c.fill();c.restore()
c.lineWidth=7;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke()
}
export default(c,t)=>{
const k=sin(3*T*t),rot=-t*T
c.translate(122,250);c.scale(1.08,1.08);c.translate(-122,-250)
c.lineWidth=6;c.fillStyle=CUSH;c.beginPath();c.ellipse(112,226,80,18,0,0,T);c.fill();c.stroke()
c.fillStyle=CUD;for(const a of[-1,1])c.beginPath(),c.arc(112+a*62,224,5,0,T),c.fill(),c.stroke()
const bx=206+3*sin(T*t),by=216-Math.abs(2*sin(2*T*t))
ds(c,7,3,Y1,()=>{c.moveTo(bx-14,by-14);c.bezierCurveTo(176,190+6*k,150,160,124,178)})
c.save();c.translate(bx,by);c.rotate(rot);c.fillStyle=Y1;c.lineWidth=6;c.beginPath();c.arc(0,0,22,0,T);c.fill();c.stroke()
c.save();c.clip();c.strokeStyle=YD;c.lineWidth=3;for(const a of[-.6,0,.6])c.beginPath(),c.ellipse(0,0,24,10,a,0,T),c.stroke();c.restore()
c.lineWidth=6;c.beginPath();c.arc(0,0,22,0,T);c.stroke();c.restore()
c.lineWidth=6;c.fillStyle=PANT;c.beginPath();c.moveTo(60,214);c.quadraticCurveTo(70,188,112,190);c.quadraticCurveTo(156,188,166,214);c.quadraticCurveTo(112,226,60,214);c.fill();c.stroke()
c.lineWidth=4;c.beginPath();c.moveTo(112,192);c.quadraticCurveTo(108,206,96,214);c.stroke()
c.fillStyle=SOCK;c.lineWidth=5;for(const[x,a]of[[62,-.3],[164,.3]])c.beginPath(),c.ellipse(x,212,11,8,a,0,T),c.fill(),c.stroke()
c.lineWidth=7;c.fillStyle=SW;c.beginPath();c.moveTo(94,124);c.quadraticCurveTo(70,132,72,196);c.lineTo(152,196);c.quadraticCurveTo(154,132,130,124);c.closePath();c.fill();c.stroke()
c.strokeStyle=SWD;c.lineWidth=3;c.beginPath();for(let y=140;y<192;y+=10)c.moveTo(80,y),c.lineTo(84,y+4),c.moveTo(144,y),c.lineTo(140,y+4);c.stroke();c.strokeStyle='#111'
c.fillStyle=SWD;c.lineWidth=5;c.beginPath();c.moveTo(96,124);c.quadraticCurveTo(112,140,128,124);c.lineTo(126,132);c.quadraticCurveTo(112,146,98,132);c.closePath();c.fill();c.stroke()
c.save();c.beginPath();c.rect(98,176,28,56);c.clip()
c.fillStyle=Y1;c.fillRect(98,176,28,56);c.fillStyle=Y2;const o=16*t*3%16;for(let y=150+o;y<240;y+=16)c.fillRect(98,y,28,8)
c.strokeStyle=YD;c.lineWidth=2;c.beginPath();for(let y=150+o;y<240;y+=8)for(const x of[104,112,120])c.moveTo(x-3,y),c.lineTo(x,y+4),c.lineTo(x+3,y);c.stroke();c.restore()
c.lineWidth=5;c.beginPath();c.moveTo(98,176);c.lineTo(98,230);c.quadraticCurveTo(112,234,126,230);c.lineTo(126,176);c.stroke()
c.save();c.translate(112,106);c.scale(.6,.6);c.translate(-128,-120)
c.lineWidth=7;c.fillStyle=HAIR;c.beginPath();c.arc(128,24,30,0,T);c.fill();c.stroke()
c.strokeStyle=HD;c.lineWidth=4;c.beginPath();c.arc(128,24,18,.5,3.6);c.stroke();c.strokeStyle='#111'
for(const[a,b]of[[[104,10],[90,-6]],[[150,6],[166,-8]]])ds(c,7,3,HAIR,()=>{c.moveTo(...a);c.quadraticCurveTo(a[0],b[1]+4,...b)})
c.fillStyle=HD;c.beginPath();c.moveTo(128,40);c.bezierCurveTo(194,40,206,100,196,160);c.lineTo(60,160);c.bezierCurveTo(50,100,62,40,128,40);c.fill();c.stroke()
c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke()
eye(c,103,140,-1);eye(c,153,140,1)
c.lineWidth=5;c.strokeStyle='#495057';for(const x of[103,153])c.beginPath(),c.arc(x,141,23,0,T),c.stroke();c.beginPath();c.moveTo(126,138);c.quadraticCurveTo(128,132,130,138);c.stroke();c.strokeStyle='#111'
c.strokeStyle='#fff';c.lineWidth=4;for(const x of[94,144])c.beginPath(),c.moveTo(x,128),c.lineTo(x+8,124),c.stroke();c.strokeStyle='#111'
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*48,168,11,6,0,0,T),c.fill()
c.lineWidth=5;c.beginPath();c.moveTo(118,172);c.quadraticCurveTo(128,180,138,172);c.stroke()
c.lineWidth=7;c.fillStyle=HAIR;c.beginPath();c.moveTo(68,150)
c.bezierCurveTo(52,80,90,44,128,44);c.bezierCurveTo(166,44,204,80,188,150)
c.quadraticCurveTo(186,120,176,108);c.quadraticCurveTo(168,96,154,100);c.quadraticCurveTo(148,110,140,112)
c.quadraticCurveTo(132,98,118,98);c.quadraticCurveTo(116,108,104,112);c.quadraticCurveTo(96,100,86,104)
c.quadraticCurveTo(72,122,68,150);c.closePath();c.fill();c.stroke()
for(const d of[-1,1])ds(c,7,3,HAIR,()=>{c.moveTo(128+d*58,120);c.quadraticCurveTo(128+d*70,150,128+d*60,176)})
c.strokeStyle=HL;c.lineWidth=6;for(const[s,e]of[[1.28,1.4],[1.5,1.58],[1.66,1.76]])c.beginPath(),c.arc(128,110,56,PI*s,PI*e),c.stroke();c.strokeStyle='#111'
c.restore()
const hl=[100,178+2*k],hr=[124,178-2*k]
ds(c,18,10,SW,()=>{c.moveTo(90,134);c.lineTo(80,168);c.lineTo(hl[0]-4,hl[1]+2)})
ds(c,18,10,SW,()=>{c.moveTo(134,134);c.lineTo(144,168);c.lineTo(hr[0]+4,hr[1]+2)})
for(const[[x,y],a]of[[hl,-.42+.14*k],[hr,PI+.42+.14*k]]){ds(c,8,4,ND,()=>{c.moveTo(x-cos(a)*8,y-sin(a)*8);c.lineTo(x+cos(a)*42,y+sin(a)*42)});c.fillStyle='#f06595';c.lineWidth=3;c.beginPath();c.arc(x-cos(a)*10,y-sin(a)*10,5,0,T);c.fill();c.stroke()}
c.fillStyle=SKIN;c.lineWidth=5;for(const[x,y]of[hl,hr])c.beginPath(),c.ellipse(x,y,9,9,0,0,T),c.fill(),c.stroke()
if(Math.abs(k)>.8)for(const d of[-1,1])ds(c,6,2.5,'#fff',()=>{c.moveTo(112+d*20,158);c.lineTo(112+d*26,150)})
}
+59
View File
@@ -0,0 +1,59 @@
// magical girl with violet twin tails raising her heart wand while a pink ribbon spirals up around her skirt, sparkles popping
const{sin,cos,PI,max,round}=Math,T=2*PI
export const frames=12,delay=80
const SKIN='#ffe3d1',HAIR='#9775fa',HD='#7048e8',HL='#e5dbff',EYE='#f783ac',ED='#c2255c',DR='#fff',PK='#faa2c1',PD='#f06595',GO='#ffd43b',GD='#f59f00',BL='#ffa8a8'
const eye=(c,x,y,d)=>{
c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill()
c.save();c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.clip();c.fillStyle=EYE;c.fill();c.fillStyle=ED;c.beginPath();c.ellipse(x,y-8,13,10,0,0,T);c.fill();c.restore()
c.lineWidth=3;c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.stroke()
c.fillStyle='#fff';c.beginPath();for(let k=0;k<10;k++){const r=k%2?3:8,a=k*PI/5-PI/2;c.lineTo(x+cos(a)*r,y+3+sin(a)*r)}c.closePath();c.fill()
c.beginPath();c.arc(x+6,y+10,2.5,0,T);c.fill()
c.lineWidth=8;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke()
}
const line=(c,pts,w,col)=>{for(const[lw,s]of[[w+8,'#111'],[w,col]]){c.lineWidth=lw;c.strokeStyle=s;c.beginPath();pts.forEach(([x,y],k)=>k?c.lineTo(x,y):c.moveTo(x,y));c.stroke()}c.strokeStyle='#111'}
const heart=(c,x,y,s)=>{c.save();c.translate(x,y);c.scale(s,s);c.beginPath();c.moveTo(0,8);c.bezierCurveTo(-13,-1,-9,-12,0,-5);c.bezierCurveTo(9,-12,13,-1,0,8);c.restore();c.fill();c.stroke()}
const spark=(c,x,y,r)=>{const q=r*.2;c.beginPath();c.moveTo(x,y-r);c.quadraticCurveTo(x+q,y-q,x+r,y);c.quadraticCurveTo(x+q,y+q,x,y+r);c.quadraticCurveTo(x-q,y+q,x-r,y);c.quadraticCurveTo(x-q,y-q,x,y-r);c.fill();c.stroke()}
const ribbon=(c,ph,col,front)=>{
const P=[];for(let k=0;k<=36;k++){const s=k/36,a=T*1.2*s+ph,r=86-22*s;P.push([128+r*cos(a),230-104*s+12*sin(a),sin(a)>0])}
for(const[lw,st]of[[13,'#111'],[6,col]]){c.lineWidth=lw;c.strokeStyle=st;c.beginPath();let on=false
for(let k=1;k<P.length;k++){const f=P[k][2]&&P[k-1][2];if(f==front){if(!on)c.moveTo(P[k-1][0],P[k-1][1]),on=true;c.lineTo(P[k][0],P[k][1])}else on=false}c.stroke()}
c.strokeStyle='#111'
}
export default(c,t)=>{
const ph=-T*t,sw=.12*sin(T*t)
ribbon(c,ph,PD,false)
c.save();c.translate(128,90);c.scale(.6,.6);c.translate(-128,-128)
for(const d of[-1,1]){c.save();c.translate(128+d*66,64);c.rotate(d*(.15+sw*d))
c.lineWidth=9;c.fillStyle=HAIR;c.beginPath();c.moveTo(0,0);c.bezierCurveTo(d*70,10,d*84,110,d*44,170);c.bezierCurveTo(d*20,206,d*60,236,d*74,214);c.bezierCurveTo(d*70,250,d*10,236,d*14,190);c.bezierCurveTo(d*20,130,d*24,60,0,20);c.closePath();c.fill();c.stroke()
c.strokeStyle=HD;c.lineWidth=5;c.beginPath();c.moveTo(d*18,30);c.bezierCurveTo(d*50,70,d*54,120,d*30,170);c.stroke();c.restore()}
c.restore()
for(const x of[118,138]){line(c,[[x,192],[x+(x<128?-2:2),214]],8,SKIN);c.lineWidth=5;c.fillStyle=PD;c.beginPath();c.roundRect(x-9+(x<128?-2:2),208,18,20,6);c.fill();c.stroke()}
c.fillStyle=PK;c.lineWidth=5;c.beginPath();c.moveTo(110,148);c.lineTo(146,148);c.bezierCurveTo(166,160,176,180,182,196);for(let k=0;k<6;k++)c.quadraticCurveTo(174-k*18,206,164-k*18,198);c.bezierCurveTo(80,180,90,160,110,148);c.closePath();c.fill();c.stroke()
c.fillStyle=DR;c.beginPath();c.moveTo(112,148);c.lineTo(144,148);c.bezierCurveTo(158,160,164,172,166,184);for(let k=0;k<5;k++)c.quadraticCurveTo(160-k*16,192,154-k*16,186);c.bezierCurveTo(92,172,98,160,112,148);c.closePath();c.fill();c.stroke()
c.fillStyle=DR;c.beginPath();c.moveTo(112,124);c.lineTo(144,124);c.lineTo(146,150);c.lineTo(110,150);c.closePath();c.fill();c.stroke()
c.fillStyle=PD;for(const d of[-1,1])c.beginPath(),c.moveTo(128,132),c.quadraticCurveTo(128+d*22,118,128+d*24,136),c.quadraticCurveTo(128+d*20,148,128,134),c.fill(),c.stroke()
c.fillStyle=GO;heart(c,128,133,.7)
line(c,[[112,130],[96,146],[94,160]],7,SKIN)
c.lineWidth=4;c.fillStyle=SKIN;c.beginPath();c.arc(94,162,6,0,T);c.fill();c.stroke()
const wx=190,wy=40+round(3*sin(2*T*t))
line(c,[[144,128],[172,112],[wx,wy+30]],7,SKIN)
for(const[lw,col]of[[11,'#111'],[5,GO]])c.lineWidth=lw,c.strokeStyle=col,c.beginPath(),c.moveTo(wx-2,wy+44),c.lineTo(wx,wy),c.stroke()
c.strokeStyle='#111';c.lineWidth=4;c.fillStyle=SKIN;c.beginPath();c.arc(wx,wy+30,7,0,T);c.fill();c.stroke()
c.lineWidth=5;c.fillStyle=PD;heart(c,wx,wy-6,1.7);c.fillStyle='#fff';c.lineWidth=0;c.beginPath();c.ellipse(wx-6,wy-10,3,2,-.5,0,T);c.fill()
c.fillStyle=GO;c.lineWidth=4;for(const d of[-1,1])c.beginPath(),c.moveTo(wx+d*10,wy-2),c.lineTo(wx+d*24,wy-12),c.lineTo(wx+d*20,wy+2),c.closePath(),c.fill(),c.stroke()
c.save();c.translate(128,90);c.scale(.6,.6);c.translate(-128,-128)
c.lineWidth=9;c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke()
eye(c,103,140,-1);eye(c,153,140,1)
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*42,163,13,7,0,0,T),c.fill()
c.lineWidth=6;c.fillStyle='#c92a2a';c.beginPath();c.moveTo(114,164);c.quadraticCurveTo(128,184,142,164);c.closePath();c.fill();c.stroke()
c.lineWidth=9;c.fillStyle=HAIR;c.beginPath();c.moveTo(66,140)
c.bezierCurveTo(52,70,90,36,128,36);c.bezierCurveTo(166,36,204,70,190,140)
c.quadraticCurveTo(186,112,176,100);c.quadraticCurveTo(168,104,162,112);c.quadraticCurveTo(156,96,146,90);c.quadraticCurveTo(140,104,132,110)
c.quadraticCurveTo(126,94,116,90);c.quadraticCurveTo(110,104,100,110);c.quadraticCurveTo(96,96,88,96);c.quadraticCurveTo(82,108,80,114)
c.quadraticCurveTo(70,112,66,140);c.closePath();c.fill();c.stroke()
c.strokeStyle=HL;c.lineWidth=7;for(const[a,e]of[[1.26,1.38],[1.46,1.54],[1.62,1.72]])c.beginPath(),c.arc(128,104,56,PI*a,PI*e),c.stroke()
c.strokeStyle='#111';c.lineWidth=7;c.fillStyle=GO;for(const d of[-1,1])heart(c,128+d*66,62,1.6)
c.restore()
ribbon(c,ph,PD,true)
for(let k=0;k<4;k++){const p=(t+k/4)%1,a=k*1.7,r=round(10*sin(PI*p));if(r>2){c.fillStyle=[GO,PK,'#fff','#99e9f2'][k];c.lineWidth=3;spark(c,128+92*cos(a),120+86*sin(a)*.8,r)}}
}
+71
View File
@@ -0,0 +1,71 @@
// new year girl in a red furisode pulling a stretchy mochi out of her ozoni bowl with chopsticks, it stretches long, she bites it and chews happily
const{sin,cos,PI,max,min,abs}=Math,T=2*PI
export const frames=16,delay=90
const SKIN='#ffe3d1',HAIR='#364fc7',HD='#253789',HL='#91a7ff',EYE='#12b886',ED='#087f5b',KIM='#e03131',KD='#a61e1e',COL='#fff',COL2='#faa2c1',BOWL='#c92a2a',BI='#2b2b2b',SOUP='#ffe8cc',MOCHI='#fff',STICK='#a9744f',KAN='#ffd43b',BL='#ffa8a8',MO='#c92a2a'
const cl=x=>max(0,min(1,x)),ease=x=>x*x*(3-2*x)
const eye=(c,x,y,d)=>{
c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill()
c.save();c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.clip();c.fillStyle=EYE;c.fill();c.fillStyle=ED;c.beginPath();c.ellipse(x,y-8,13,10,0,0,T);c.fill();c.restore()
c.lineWidth=2.5;c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.stroke()
c.fillStyle='#111';c.beginPath();c.ellipse(x,y+3,5.5,7.5,0,0,T);c.fill()
c.fillStyle='#fff';c.beginPath();c.arc(x-4,y-5,4.5,0,T);c.fill();c.beginPath();c.arc(x+5,y+8,2,0,T);c.fill()
c.lineWidth=6;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke()
}
export default(c,t)=>{
const up=ease(cl(t/.38)),go=ease(cl((t-.38)/.12)),down=ease(cl((t-.72)/.26)),bite=t>=.48&&t<.72,chew=t>=.56&&t<.95,snap=t>=.56,u=snap?1-down:up
// chopstick tip pulls up and out beside her face, swings to her mouth for the bite, then goes back to the bowl
const [tx,ty]=snap?[136+10*down,170+40*down]:[146+44*up-54*go,210-92*up+52*go]
// hair up in a bun
c.lineWidth=6;c.fillStyle=HD;c.beginPath();c.arc(128,34,28,0,T);c.fill();c.stroke()
c.strokeStyle=HAIR;c.lineWidth=4;c.beginPath();c.arc(128,34,16,PI*1.1,PI*1.9);c.stroke();c.strokeStyle='#111';c.lineWidth=6
c.fillStyle=HD;c.beginPath();c.moveTo(128,40);c.bezierCurveTo(196,40,206,100,196,150);c.lineTo(60,150);c.bezierCurveTo(50,100,60,40,128,40);c.fill();c.stroke()
// furisode
c.fillStyle=KIM;c.beginPath();c.moveTo(100,188);c.quadraticCurveTo(58,198,48,262);c.lineTo(208,262);c.quadraticCurveTo(198,198,156,188);c.closePath();c.fill();c.stroke()
c.fillStyle='#fff';c.lineWidth=3;for(const[x,y]of[[70,236],[188,226],[82,208]]){for(let k=0;k<5;k++){const a=k*T/5-PI/2;c.beginPath();c.arc(x+5*cos(a),y+5*sin(a),3.5,0,T);c.fill();c.stroke()}c.fillStyle='#ffd43b';c.beginPath();c.arc(x,y,2.5,0,T);c.fill();c.fillStyle='#fff'}
c.lineWidth=5;c.fillStyle=COL;c.beginPath();c.moveTo(108,188);c.lineTo(128,226);c.lineTo(148,188);c.lineTo(140,188);c.lineTo(128,212);c.lineTo(116,188);c.closePath();c.fill();c.stroke()
c.fillStyle=COL2;c.beginPath();c.moveTo(100,190);c.lineTo(126,236);c.lineTo(114,236);c.lineTo(92,194);c.closePath();c.fill();c.stroke()
c.beginPath();c.moveTo(156,190);c.lineTo(130,236);c.lineTo(142,236);c.lineTo(164,194);c.closePath();c.fill();c.stroke()
c.fillStyle=SKIN;c.beginPath();c.moveTo(116,168);c.lineTo(116,188);c.lineTo(128,208);c.lineTo(140,188);c.lineTo(140,168);c.fill()
c.lineWidth=5;c.beginPath();c.moveTo(116,168);c.lineTo(116,188);c.moveTo(140,168);c.lineTo(140,188);c.stroke()
// face
c.lineWidth=6;c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke()
if(chew){const pf=1+.2*abs(sin(4*T*t));c.fillStyle=SKIN;for(const d of[-1,1])c.beginPath(),c.arc(128+d*40,162,13*pf,d<0?PI*.5:-PI*.5,d<0?PI*1.5:PI*.5),c.fill(),c.stroke()
c.lineWidth=5;for(const x of[103,153])c.beginPath(),c.arc(x,144,12,PI*1.15,PI*1.85),c.stroke()}
else{eye(c,103,140,-1);eye(c,153,140,1)}
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*42,161,12,6,0,0,T),c.fill()
c.lineWidth=3.5;c.fillStyle=MO;c.beginPath()
if(bite&&!snap)c.ellipse(128,170,9,10,0,0,T),c.fill(),c.stroke()
else if(chew)c.ellipse(128,170,4+2*abs(sin(4*T*t)),3,0,0,T),c.stroke()
else c.moveTo(118,166),c.quadraticCurveTo(128,175,138,166),c.stroke()
// swept bangs and thin side locks
c.lineWidth=6;c.fillStyle=HAIR;for(const d of[-1,1])c.beginPath(),c.moveTo(128+d*52,118),c.quadraticCurveTo(128+d*62,150,128+d*56,178),c.quadraticCurveTo(128+d*50,160,128+d*44,124),c.closePath(),c.fill(),c.stroke()
c.beginPath();c.moveTo(66,146);c.bezierCurveTo(50,74,88,40,128,40);c.bezierCurveTo(168,40,206,74,190,146)
c.quadraticCurveTo(186,118,178,104);c.quadraticCurveTo(170,102,164,110);c.quadraticCurveTo(160,96,150,92);c.quadraticCurveTo(144,104,136,110)
c.quadraticCurveTo(132,96,122,90);c.quadraticCurveTo(116,104,106,108);c.quadraticCurveTo(102,96,92,96);c.quadraticCurveTo(86,106,80,112);c.quadraticCurveTo(70,124,66,146);c.closePath();c.fill();c.stroke()
c.strokeStyle=HL;c.lineWidth=5;for(const[a,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,56,PI*a,PI*e),c.stroke();c.strokeStyle='#111'
c.fillStyle=KAN;c.lineWidth=4;for(let k=0;k<5;k++){const a=k*T/5;c.beginPath();c.arc(160+8*cos(a),30+8*sin(a),6,0,T);c.fill();c.stroke()}
c.fillStyle=KIM;c.beginPath();c.arc(160,30,5,0,T);c.fill();c.stroke()
const sw=4*sin(T*t);c.lineWidth=3;c.beginPath();c.moveTo(166,38);c.lineTo(178+sw,62);c.stroke();c.fillStyle=COL2;c.beginPath();c.arc(178+sw,66,5,0,T);c.fill();c.stroke()
// ozoni bowl
c.lineWidth=6;c.fillStyle=BOWL;c.beginPath();c.moveTo(84,214);c.quadraticCurveTo(88,254,128,254);c.quadraticCurveTo(168,254,172,214);c.closePath();c.fill();c.stroke()
c.fillStyle=SOUP;c.beginPath();c.ellipse(128,214,44,9,0,0,T);c.fill();c.stroke()
c.fillStyle='#51cf66';c.lineWidth=3;c.beginPath();c.ellipse(108,214,8,3,.3,0,T);c.fill();c.stroke()
c.fillStyle='#ffa8a8';c.beginPath();c.ellipse(112,216,5,3,0,0,T);c.fill();c.stroke()
c.strokeStyle='#ffd43b';c.lineWidth=4;c.beginPath();c.arc(128,238,10,PI*1.1,PI*1.9);c.stroke();c.strokeStyle='#111'
// the mochi: a blob in the bowl stretching up to the chopstick tip, snapping back after the bite
const st=snap?0:u,mh=8+6*(1-st),bx=146,by=212
c.fillStyle=MOCHI;c.lineWidth=4
if(st>.05){const w=max(4,14*(1-st*.7));c.beginPath();c.moveTo(bx-14,by);c.bezierCurveTo(bx-w,by-12,tx-w,ty+18,tx-10,ty+4);c.lineTo(tx+10,ty+4);c.bezierCurveTo(tx+w,ty+18,bx+w,by-12,bx+14,by);c.closePath();c.fill();c.stroke()}
c.beginPath();c.ellipse(bx,by-2,18,mh*.6,0,0,T);c.fill();c.stroke()
if(!snap&&u>.05){c.beginPath();c.ellipse(tx,ty+2,13,9,0,0,T);c.fill();c.stroke()}
// steam
c.strokeStyle='#fff';c.lineWidth=3;for(const x of[100,118]){const p=(t*2+(x-100)/36)%1;c.globalAlpha=sin(PI*p);for(const[w,s]of[[7,'#111'],[3,'#fff']])c.lineWidth=w,c.strokeStyle=s,c.beginPath(),c.moveTo(x,206-12*p),c.quadraticCurveTo(x+6,200-12*p,x,192-12*p),c.stroke()}
c.globalAlpha=1;c.strokeStyle='#111'
// chopsticks in her hand
const hx=min(tx+52,222),hy=ty+28
for(const k of[0,1])for(const[l,s]of[[9,'#111'],[4,STICK]])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),c.moveTo(hx+8+k*4,hy-2+k*6),c.lineTo(tx+(k?2:-2),ty+(k?3:-1)),c.stroke()
c.strokeStyle='#111';c.lineWidth=5;c.fillStyle=SKIN;c.beginPath();c.ellipse(hx,hy,13,11,-.4,0,T);c.fill();c.stroke()
for(const[l,s]of[[30,'#111'],[19,KIM]])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),c.moveTo(214,262),c.quadraticCurveTo(214,244,hx+10,hy+8),c.stroke()
c.strokeStyle='#111'
if(chew&&t<.9){c.fillStyle='#ffd43b';c.lineWidth=3;for(const[x,y,o]of[[52,110,0],[206,104,.5]]){const s=8*sin(PI*((t*4+o)%1));if(s>1.5){c.beginPath();c.moveTo(x,y-s);for(const[px,py,qx,qy]of[[s,0,s*.18,-s*.18],[0,s,s*.18,s*.18],[-s,0,-s*.18,s*.18],[0,-s,-s*.18,-s*.18]])c.quadraticCurveTo(x+qx,y+qy,x+px,y+py);c.fill();c.stroke()}}}
}
+61
View File
@@ -0,0 +1,61 @@
// girl with dark brown half-up hair folding a pink paper square, poof, it becomes a paper crane that flaps up out of her hands while she watches in delight
const{sin,cos,PI,max,min}=Math,T=2*PI
export const frames=16,delay=90
const SKIN='#ffe3d1',HAIR='#6b4a35',HD='#4f3526',HL='#b8927a',EYE='#9c36b5',ED='#5f1f6e',BL='#ffa8a8',CAR='#96f2d7',CAD='#38d9a9',PAP='#faa2c1',PAD='#f06595',TIE='#fa5252',STK='#ffd43b'
const ds=(c,a,b,s,f)=>{for(const[l,k]of[[a,'#111'],[b,s]])c.lineWidth=l,c.strokeStyle=k,c.beginPath(),f(),c.stroke();c.strokeStyle='#111'}
const eye=(c,x,y,d,ly,lx=0)=>{
c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill()
c.save();c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.clip()
c.beginPath();c.ellipse(x+lx,y+2+ly,11.5,15,0,0,T);c.fillStyle=EYE;c.fill();c.lineWidth=2.5;c.stroke()
c.save();c.clip();c.fillStyle=ED;c.beginPath();c.ellipse(x+lx,y-8+ly,13,10,0,0,T);c.fill();c.restore()
c.fillStyle='#111';c.beginPath();c.ellipse(x+lx,y+3+ly,5.5,7.5,0,0,T);c.fill()
c.fillStyle='#fff';c.beginPath();c.arc(x+lx-4,y-5+ly,4.5,0,T);c.fill();c.beginPath();c.arc(x+lx+5,y+8+ly,2,0,T);c.fill();c.restore()
c.lineWidth=7;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke()
}
const P=(c,...q)=>{c.beginPath();q.forEach(([x,y],i)=>i?c.lineTo(x,y):c.moveTo(x,y));c.closePath()}
const crane=(c,x,y,f)=>{
c.save();c.translate(x,y);c.scale(-1.3,1.3);c.lineWidth=3.5;c.fillStyle=PAD
P(c,[-14,-2],[-4,5],[-32,-28]);c.fill();c.stroke();P(c,[-32,-28],[-42,-20],[-29,-21]);c.fill();c.stroke()
P(c,[14,-2],[5,5],[26,-20]);c.fill();c.stroke()
c.fillStyle=PAP;P(c,[-16,0],[0,-8],[16,0],[0,11]);c.fill();c.stroke()
c.fillStyle=PAD;P(c,[-9,-3],[9,-3],[6,-3-36*f]);c.fill();c.stroke()
c.fillStyle=PAP;P(c,[-9,-3],[9,-3],[-4,-3-40*f]);c.fill();c.stroke()
c.strokeStyle=PAD;c.lineWidth=2;c.beginPath();c.moveTo(0,-8);c.lineTo(0,11);c.stroke();c.strokeStyle='#111'
c.restore()
}
const poof=(c,x,y,r)=>{c.fillStyle='#fff';c.lineWidth=3.5;c.beginPath();for(let k=0;k<6;k++){const a=k*PI/3,X=x+cos(a)*r*.7,Y=y+sin(a)*r*.5;c.moveTo(X+r*.4,Y);c.arc(X,Y,r*.4,0,T)}c.fill();c.stroke();for(let k=0;k<4;k++){const a=k*PI/2+.4;ds(c,6,2.5,'#ffd43b',()=>{c.moveTo(x+cos(a)*r*1.1,y+sin(a)*r*.9);c.lineTo(x+cos(a)*r*1.5,y+sin(a)*r*1.2)})}}
export default(c,t)=>{
const fold=min(1,max(0,(t-.12)/.26)),fly=t>=.44&&t<.92,fp=fly?(t-.44)/.48:0,cy=198-92*sin(PI*fp),cx=128+70*sin(PI*fp),flap=.4+.6*Math.abs(sin(3*T*fp)),ly=fly?5-11*sin(PI*fp):5,lx=fly?5*sin(PI*fp):0,joy=fly&&fp>.15&&fp<.85
c.lineWidth=7;c.fillStyle=CAR;c.beginPath();c.moveTo(102,150);c.quadraticCurveTo(62,160,54,250);c.lineTo(202,250);c.quadraticCurveTo(194,160,154,150);c.closePath();c.fill();c.stroke()
c.fillStyle='#fff';c.lineWidth=5;c.beginPath();c.moveTo(110,152);c.lineTo(128,176);c.lineTo(146,152);c.closePath();c.fill();c.stroke()
c.fillStyle=TIE;c.beginPath();c.moveTo(128,168);c.lineTo(120,190);c.lineTo(128,198);c.lineTo(136,190);c.closePath();c.fill();c.stroke()
c.strokeStyle=CAD;c.lineWidth=3;c.beginPath();for(const y of[200,214,228])c.moveTo(66,y),c.lineTo(80,y),c.moveTo(176,y),c.lineTo(190,y);c.stroke();c.strokeStyle='#111'
c.fillStyle=SKIN;c.lineWidth=6;c.beginPath();c.moveTo(118,134);c.lineTo(118,152);c.quadraticCurveTo(128,160,138,152);c.lineTo(138,134);c.fill();c.beginPath();c.moveTo(118,134);c.lineTo(118,150);c.moveTo(138,134);c.lineTo(138,150);c.stroke()
c.save();c.translate(128,96);c.scale(.68,.68);c.translate(-128,-120)
c.lineWidth=7;c.fillStyle=HD;c.beginPath();c.moveTo(128,36);c.bezierCurveTo(198,36,210,100,202,176);c.quadraticCurveTo(190,188,180,180);c.lineTo(76,180);c.quadraticCurveTo(66,188,54,176);c.bezierCurveTo(46,100,58,36,128,36);c.fill();c.stroke()
c.fillStyle=HAIR;c.beginPath();c.moveTo(150,40);c.bezierCurveTo(190,6,214,30,200,66);c.quadraticCurveTo(188,48,164,52);c.closePath();c.fill();c.stroke()
c.fillStyle=TIE;c.lineWidth=5;c.beginPath();c.ellipse(160,46,8,11,.6,0,T);c.fill();c.stroke()
ds(c,9,4,STK,()=>{c.moveTo(138,30);c.lineTo(186,62)});c.fillStyle=STK;c.lineWidth=4;c.beginPath();c.arc(136,28,6,0,T);c.fill();c.stroke()
c.lineWidth=7;c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke()
if(t>=.4&&t<.46){c.lineWidth=7;for(const x of[103,153])c.beginPath(),c.moveTo(x-14,132),c.lineTo(x+8,140),c.lineTo(x-14,148),c.stroke()}else eye(c,103,140,-1,ly,lx),eye(c,153,140,1,ly,lx)
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,164,13,7,0,0,T),c.fill()
c.lineWidth=5;c.fillStyle='#c92a2a';c.beginPath()
if(joy)c.moveTo(114,164),c.quadraticCurveTo(128,186,142,164),c.closePath(),c.fill(),c.stroke();else c.moveTo(120,168),c.quadraticCurveTo(128,174,136,168),c.stroke()
c.lineWidth=7;c.fillStyle=HAIR;c.beginPath();c.moveTo(64,172)
c.bezierCurveTo(46,80,86,38,128,38);c.bezierCurveTo(170,38,210,80,192,172)
c.quadraticCurveTo(188,140,182,112);c.lineTo(168,114);c.lineTo(166,98);c.lineTo(150,112);c.lineTo(144,96);c.lineTo(128,112)
c.lineTo(118,96);c.lineTo(106,112);c.lineTo(96,98);c.lineTo(88,114);c.lineTo(74,112);c.quadraticCurveTo(68,140,64,172);c.closePath();c.fill();c.stroke()
c.strokeStyle=HL;c.lineWidth=6;for(const[s,e]of[[1.26,1.38],[1.46,1.54],[1.62,1.72]])c.beginPath(),c.arc(128,106,58,PI*s,PI*e),c.stroke();c.strokeStyle='#111'
c.restore()
const hy=fly?214:206
ds(c,20,11,CAR,()=>{c.moveTo(98,168);c.lineTo(80,200);c.lineTo(104,hy)})
ds(c,20,11,CAR,()=>{c.moveTo(158,168);c.lineTo(176,200);c.lineTo(152,hy)})
if(!fly&&t<.4){const top=-36+52*fold,w=36-10*fold
c.fillStyle=PAP;c.lineWidth=5;P(c,[128-w,196],[128,196+top],[128+w,196],[128,232-8*fold]);c.fill();c.stroke()
c.strokeStyle=PAD;c.lineWidth=2.5;c.beginPath();c.moveTo(128-w,196);c.lineTo(128+w,196);c.moveTo(128,196+top);c.lineTo(128,232-8*fold);c.stroke();c.strokeStyle='#111'}
if(fly||t>=.4&&t<.46||t>=.92)crane(c,cx,cy,fly?flap:.4)
if(t>=.38&&t<.48)poof(c,128,196,30*sin(PI*(t-.38)/.1))
if(t>=.92)poof(c,128,200,30*sin(PI*(t-.92)/.08))
c.fillStyle=SKIN;c.lineWidth=5;for(const x of[104,152])c.beginPath(),c.ellipse(x,hy,12,10,0,0,T),c.fill(),c.stroke()
if(joy)for(const[x,y,r]of[[cx-34,cy-34,7],[cx+30,cy+30,6]]){c.fillStyle='#ffd43b';c.lineWidth=3;c.beginPath();for(let k=0;k<8;k++){const a=k*PI/4,q=k%2?r*.35:r;c.lineTo(x+cos(a)*q,y+sin(a)*q)}c.closePath();c.fill();c.stroke()}
}
+64
View File
@@ -0,0 +1,64 @@
// side-view chibi with long black-brown hair and a white bow playing an upright piano, hands taking turns on the keys, swaying, notes floating up
// the dark hair gets a white rim so it doesn't vanish on black
const{sin,cos,PI,max}=Math,T=2*PI
export const frames=12,delay=110
const SKIN='#ffe3d1',HAIR='#4d4549',HD='#363134',HL='#a5b1c4',EYE='#748ffc',ED='#3b5bdb',BL='#ffa8a8',DRS='#5c7cfa',DRD='#4263eb',WOOD='#a9744f',WDD='#7f5539',WDL='#c99a6e',BENCH='#e8590c',SOCK='#fff',SHOE='#c2255c'
const ds=(c,a,b,s,f)=>{for(const[l,k]of[[a,'#111'],[b,s]])c.lineWidth=l,c.strokeStyle=k,c.beginPath(),f(),c.stroke();c.strokeStyle='#111'}
const eye=(c,x,y,d)=>{
c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill()
c.save();c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.clip()
c.beginPath();c.ellipse(x+5,y+5,11.5,15,0,0,T);c.fillStyle=EYE;c.fill();c.lineWidth=2.5;c.stroke()
c.save();c.clip();c.fillStyle=ED;c.beginPath();c.ellipse(x+5,y-5,13,10,0,0,T);c.fill();c.restore()
c.fillStyle='#111';c.beginPath();c.ellipse(x+6,y+6,5.5,7.5,0,0,T);c.fill()
c.fillStyle='#fff';c.beginPath();c.arc(x+1,y-1,4.5,0,T);c.fill();c.beginPath();c.arc(x+10,y+11,2,0,T);c.fill();c.restore()
c.lineWidth=7;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke()
}
const note=(c,x,y,s,col)=>{ds(c,8,3,col,()=>{c.moveTo(x+6*s,y);c.lineTo(x+6*s,y-22*s);c.quadraticCurveTo(x+18*s,y-16*s,x+14*s,y-6*s)});c.fillStyle=col;c.lineWidth=3.5;c.beginPath();c.ellipse(x,y,7*s,5*s,-.4,0,T);c.fill();c.stroke()}
export default(c,t)=>{
const sw=.03*sin(2*PI*t),p1=max(0,sin(4*T*t)),p2=max(0,sin(4*T*t+PI))
for(const[x,o,col]of[[170,0,'#ffd43b'],[214,.33,'#f783ac'],[192,.66,'#74c0fc']]){const p=(t+o)%1,s=sin(PI*p);if(s>.2)note(c,x+6*sin(p*T),54-34*p,.45+.4*s,col)}
const K=(f,d)=>[112+138*f+6*d,170-24*f+14*d],P=(...q)=>{c.beginPath();q.forEach(([x,y],i)=>i?c.lineTo(x,y):c.moveTo(x,y));c.closePath()}
c.lineWidth=7;c.fillStyle=WOOD;P([118,184],[252,158],[252,246],[122,246]);c.fill();c.stroke()
c.fillStyle=WDD;c.lineWidth=5;P([140,196],[236,178],[236,232],[140,236]);c.fill();c.stroke()
c.lineWidth=7;c.fillStyle=WOOD;P([112,170],[250,146],[250,70],[116,96]);c.fill();c.stroke()
c.fillStyle=WDL;P([108,98],[254,70],[254,58],[108,86]);c.fill();c.stroke()
c.fillStyle='#fff';c.lineWidth=5;P([156,110],[206,101],[206,136],[156,145]);c.fill();c.stroke()
c.lineWidth=2;c.beginPath();for(const y of[0,8,16])c.moveTo(162,116+y),c.lineTo(200,109+y);c.stroke()
c.fillStyle='#111';for(const[x,y]of[[168,121],[180,127],[192,115]])c.beginPath(),c.ellipse(x,y,3,2.2,-.4,0,T),c.fill()
c.fillStyle='#fff';c.lineWidth=6;P(K(0,0),K(1,0),K(1,1),K(0,1));c.fill();c.stroke()
const n=16;c.fillStyle='#ced4da';for(const[f,p]of[[.2,p1],[.32,p2]])if(p>.3){const k=Math.floor(f*n);P(K(k/n,0),K((k+1)/n,0),K((k+1)/n,1),K(k/n,1));c.fill()}
c.lineWidth=2;c.beginPath();for(let k=1;k<n;k++){const[a,b]=K(k/n,0),[x,y]=K(k/n,1);c.moveTo(a,b);c.lineTo(x,y)}c.stroke()
c.fillStyle='#111';for(let k=1;k<n;k++)if(![3,7,10,14].includes(k)){const w=.018;P(K(k/n-w,0),K(k/n+w,0),K(k/n+w,.55),K(k/n-w,.55));c.fill()}
c.lineWidth=6;P(K(0,0),K(1,0),K(1,1),K(0,1));c.stroke()
c.lineWidth=6;c.fillStyle=BENCH;c.beginPath();c.roundRect(36,198,84,12,5);c.fill();c.stroke()
for(const x of[44,110])ds(c,12,6,BENCH,()=>{c.moveTo(x,210);c.lineTo(x,244)})
ds(c,14,7,SKIN,()=>{c.moveTo(112,204);c.lineTo(120,234)})
c.fillStyle=SOCK;c.lineWidth=4;c.beginPath();c.roundRect(113,226,14,10,3);c.fill();c.stroke()
c.fillStyle=SHOE;c.lineWidth=5;c.beginPath();c.ellipse(126,240,13,6,0,0,T);c.fill();c.stroke()
c.save();c.translate(84,200);c.rotate(sw);c.translate(-84,-200)
c.lineWidth=6;c.fillStyle=DRS;c.beginPath();c.moveTo(74,150);c.quadraticCurveTo(64,170,60,200);c.lineTo(122,204);c.quadraticCurveTo(116,188,104,180);c.quadraticCurveTo(102,160,96,150);c.closePath();c.fill();c.stroke()
c.fillStyle=DRD;c.lineWidth=5;c.beginPath();c.moveTo(60,200);c.quadraticCurveTo(90,192,122,204);c.lineTo(124,210);c.quadraticCurveTo(90,200,58,206);c.closePath();c.fill();c.stroke()
c.fillStyle='#fff';c.lineWidth=4;c.beginPath();c.moveTo(76,150);c.quadraticCurveTo(86,162,96,150);c.quadraticCurveTo(86,156,76,150);c.fill();c.stroke()
c.save();c.translate(84,108);c.scale(.56,.56);c.translate(-128,-120)
const back=()=>{c.moveTo(118,40);c.bezierCurveTo(56,40,40,110,46,196);c.quadraticCurveTo(40,236,58,262);c.quadraticCurveTo(80,250,96,268);c.quadraticCurveTo(110,236,104,190);c.lineTo(170,150);c.bezierCurveTo(196,96,180,40,118,40)}
c.strokeStyle='#fff';c.lineWidth=22;c.beginPath();back();c.stroke();c.strokeStyle='#111'
c.lineWidth=7;c.fillStyle=HD;c.beginPath();back();c.fill();c.stroke()
c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,190,152,186,96);c.bezierCurveTo(184,44,74,44,74,96);c.fill();c.stroke()
eye(c,112,140,-1);eye(c,162,140,1)
c.fillStyle=BL;for(const x of[86,174])c.beginPath(),c.ellipse(x,164,12,7,0,0,T),c.fill()
c.lineWidth=5;c.beginPath();c.moveTo(130,168);c.quadraticCurveTo(140,176,150,167);c.stroke()
const hair=()=>{c.moveTo(70,150);c.bezierCurveTo(52,74,90,38,130,38);c.bezierCurveTo(172,38,208,76,190,140)
c.quadraticCurveTo(188,118,182,104);c.quadraticCurveTo(172,104,164,112);c.quadraticCurveTo(162,98,152,92);c.quadraticCurveTo(144,106,134,110)
c.quadraticCurveTo(132,98,124,92);c.quadraticCurveTo(116,104,104,110);c.quadraticCurveTo(100,98,94,96);c.quadraticCurveTo(84,110,80,118);c.quadraticCurveTo(72,130,70,150);c.closePath()}
c.strokeStyle='#fff';c.lineWidth=20;c.beginPath();hair();c.stroke();c.strokeStyle='#111'
c.lineWidth=7;c.fillStyle=HAIR;c.beginPath();hair();c.fill();c.stroke()
c.strokeStyle=HL;c.lineWidth=6;for(const[s,e]of[[1.24,1.36],[1.44,1.52],[1.6,1.7]])c.beginPath(),c.arc(130,106,58,PI*s,PI*e),c.stroke();c.strokeStyle='#111'
c.fillStyle='#fff';c.lineWidth=6;for(const a of[-.9,.9])c.beginPath(),c.ellipse(58+cos(a+PI)*0,70+18*sin(a),24,13,a*.6,0,T),c.fill(),c.stroke()
c.beginPath();c.arc(58,70,9,0,T);c.fill();c.stroke()
c.restore()
const h1=[146,170+4*p1],h2=[162,167+4*p2]
ds(c,17,9,DRS,()=>{c.moveTo(90,158);c.lineTo(106,178);c.lineTo(h1[0]-6,h1[1]+2)})
ds(c,17,9,DRS,()=>{c.moveTo(96,154);c.lineTo(118,170);c.lineTo(h2[0]-6,h2[1]+2)})
c.restore()
c.fillStyle=SKIN;c.lineWidth=5;for(const[x,y]of[h1,h2])c.beginPath(),c.ellipse(x,y,9,7,-.2,0,T),c.fill(),c.stroke()
}
+72
View File
@@ -0,0 +1,72 @@
// cream-haired hime-cut girl nibbling a chocolate stick snack bite by bite until it's gone, then pulling a fresh one out of the box
const{sin,cos,PI,min,max,floor}=Math,T=2*PI
export const frames=24,delay=80
const SKIN='#ffe3d1',HAIR='#fff1c9',HD='#e8c98f',HL='#fff',EYE='#a9744f',ED='#6b4226',SW='#ff8787',SD='#e03131',COL='#fff',RIB='#4dabf7',BIS='#f0c27b',CHO='#7b4a2e',BOX='#fa5252',BL='#ffa8a8',MO='#c92a2a'
const ease=x=>x<=0?0:x>=1?1:x*x*(3-2*x),M=[140,172],A=.38,D=[cos(A),sin(A)],B=[46,184],FULL=74
const eye=(c,x,y,d)=>{
c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill()
c.save();c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.clip();c.fillStyle=EYE;c.fill();c.fillStyle=ED;c.beginPath();c.ellipse(x,y-8,13,10,0,0,T);c.fill()
c.fillStyle='#111';c.beginPath();c.ellipse(x+3,y+4,5.5,7.5,0,0,T);c.fill();c.fillStyle='#fff';c.beginPath();c.arc(x-1,y-4,4.5,0,T);c.fill();c.beginPath();c.arc(x+7,y+9,2,0,T);c.fill();c.restore()
c.lineWidth=2.5;c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.stroke()
c.lineWidth=6;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke()
}
// stick held at (x,y) pointing along angle a, chocolate except the 16px biscuit handle
const stick=(c,x,y,L,a=A+PI)=>{
if(L<2)return
const u=[cos(a),sin(a)],e=[x+u[0]*L,y+u[1]*L],h=min(16,L),m=[x+u[0]*h,y+u[1]*h]
for(const[l,s]of[[11,'#111'],[5,BIS]])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),c.moveTo(x,y),c.lineTo(...e),c.stroke()
if(L>16){c.lineWidth=6;c.strokeStyle=CHO;c.beginPath();c.moveTo(...m);c.lineTo(...e);c.stroke()}
c.strokeStyle='#111'
}
export default(c,t)=>{
// five bites over the first 60% of the loop, each shortening the stick a chunk
const bt=min(1,t/.6),bite=floor(bt*5),bp=bt*5-bite,L=t<.6?FULL-(bite+ease(bp/.3))*FULL/5:0
const chew=t<.68&&bp>.25,happy=t>=.6&&t<.7
const tip=[M[0]+D[0]*L,M[1]+D[1]*L],lerp=(a,b,s)=>[a[0]+(b[0]-a[0])*s,a[1]+(b[1]-a[1])*s]
const end=[M[0]+D[0]*FULL,M[1]+D[1]*FULL]
const H=t<.62?tip:t<.78?lerp([M[0]+D[0]*14,M[1]+D[1]*14],B,ease((t-.62)/.16)):t<.94?lerp(B,end,ease((t-.78)/.16)):end
const carry=t>=.78?FULL:0,ang=t>=.78&&t<.94?-PI/2+(A+PI*1.5)*ease((t-.8)/.12):A+PI
c.lineWidth=6
c.fillStyle=HD;c.beginPath();c.moveTo(128,34);c.bezierCurveTo(198,34,210,100,204,200);c.lineTo(52,200);c.bezierCurveTo(46,100,58,34,128,34);c.fill();c.stroke()
// sweater with a sailor collar
c.fillStyle=SW;c.beginPath();c.moveTo(100,190);c.quadraticCurveTo(62,198,54,256);c.lineTo(202,256);c.quadraticCurveTo(194,198,156,190);c.closePath();c.fill();c.stroke()
c.fillStyle=COL;c.beginPath();c.moveTo(100,190);c.lineTo(128,226);c.lineTo(156,190);c.lineTo(170,198);c.lineTo(128,244);c.lineTo(86,198);c.closePath();c.fill();c.stroke()
c.fillStyle=RIB;for(const d of[-1,1])c.beginPath(),c.moveTo(128,232),c.lineTo(128+d*16,222),c.lineTo(128+d*14,242),c.closePath(),c.fill(),c.stroke()
c.beginPath();c.arc(128,232,4.5,0,T);c.fill();c.stroke()
c.fillStyle=SKIN;c.beginPath();c.moveTo(116,168);c.lineTo(116,194);c.lineTo(128,212);c.lineTo(140,194);c.lineTo(140,168);c.fill();c.beginPath();c.moveTo(116,168);c.lineTo(116,192);c.moveTo(140,168);c.lineTo(140,192);c.stroke()
// face
c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke()
if(chew||happy){c.lineWidth=6;for(const x of[103,153])c.beginPath(),c.arc(x,146,13,PI*1.15,PI*1.85),c.stroke()}
else{eye(c,103,140,-1);eye(c,153,140,1)}
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,160,13,6,0,0,T),c.fill()
c.lineWidth=2.5;for(const d of[-1,1])for(const k of[-5,0,5])c.beginPath(),c.moveTo(128+d*44+k-2,163),c.lineTo(128+d*44+k+2,157),c.stroke()
// little mouth: open around the stick while biting, munching otherwise
c.lineWidth=3.5;c.fillStyle=MO
if(L>2&&!chew){c.beginPath();c.ellipse(M[0]-4,M[1],7,6,0,0,T);c.fill();c.stroke()}
else{c.beginPath();c.moveTo(M[0]-12,M[1]-2);c.quadraticCurveTo(M[0]-8,M[1]+3+2*sin(T*t*12),M[0]-4,M[1]);c.quadraticCurveTo(M[0],M[1]+3,M[0]+4,M[1]-2);c.stroke()}
if(chew){c.lineWidth=5;c.fillStyle=SKIN;c.beginPath();c.arc(164,162,6+3*sin(T*t*12),-PI*.5,PI*.5);c.fill();c.stroke()}
// hime cut: straight blunt bangs and long side locks
c.lineWidth=6;c.fillStyle=HAIR;c.beginPath();c.moveTo(66,190)
c.bezierCurveTo(50,74,88,36,128,36);c.bezierCurveTo(168,36,206,74,190,190);c.lineTo(178,190);c.lineTo(176,112)
c.lineTo(80,112);c.lineTo(78,190);c.closePath();c.fill();c.stroke()
c.lineWidth=3;for(const x of[100,128,156])c.beginPath(),c.moveTo(x,90),c.lineTo(x,110),c.stroke()
c.strokeStyle=HL;c.lineWidth=5;for(const[a,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,100,56,PI*a,PI*e),c.stroke()
c.strokeStyle=HD;c.lineWidth=3;for(const[a,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,100,60,PI*a,PI*e),c.stroke()
c.strokeStyle='#111'
// the box in her other hand, tilted toward her
c.save();c.translate(58,226);c.rotate(-.3)
for(const x of[-8,0,8])stick(c,x,-24,22+(x==0?4:0),-PI/2)
c.lineWidth=5;c.fillStyle=BOX;c.beginPath();c.roundRect(-20,-30,40,64,4);c.fill();c.stroke()
c.fillStyle='#fff';c.beginPath();c.roundRect(-12,-16,24,26,3);c.fill();c.stroke()
c.strokeStyle=CHO;c.lineWidth=4;c.beginPath();c.moveTo(-6,6);c.lineTo(6,-10);c.stroke();c.strokeStyle='#111'
c.restore()
for(const[l,s]of[[24,'#111'],[15,SKIN]])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),c.moveTo(86,262),c.lineTo(76,238),c.stroke()
c.strokeStyle='#111';c.lineWidth=5;c.fillStyle=SKIN;c.beginPath();c.ellipse(76,234,11,12,-.3,0,T);c.fill();c.stroke()
// the stick and the hand holding its biscuit end
stick(c,...H,L||carry,ang)
for(const[l,s]of[[24,'#111'],[15,SKIN]])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),c.moveTo(184,262),c.quadraticCurveTo(H[0]+30,H[1]+44,H[0]+4,H[1]+10),c.stroke()
c.strokeStyle='#111';c.lineWidth=5;c.fillStyle=SKIN;c.beginPath();c.ellipse(H[0]+2,H[1]+5,10,9,0,0,T);c.fill();c.stroke()
c.beginPath();c.ellipse(H[0]-6,H[1]-2,4,6,A,0,T);c.fill();c.stroke()
// crumbs from each bite
if(t<.62&&bp<.5){c.fillStyle=CHO;c.lineWidth=2;for(const[dx,dy,o]of[[0,0,0],[6,4,.2],[-4,6,.4]]){const p=bp*2,x=M[0]+4+dx,y=M[1]+12+dy+30*p*p;c.beginPath();c.arc(x,y,2.5,0,T);c.fill();c.stroke()}}
}
+63
View File
@@ -0,0 +1,63 @@
// chibi with chestnut pigtails shaking an instant photo while the picture develops, beaming at it, then flipping it over to a fresh blank one
const{sin,cos,PI,max,min}=Math,T=2*PI
export const frames=16,delay=90
const SKIN='#ffe3d1',HAIR='#8b4f2f',HD='#6a3a21',HL='#d9a382',EYE='#c0803f',ED='#7f5539',BL='#ffa8a8',CAR='#fcc419',CAD='#f59f00',SKT='#4dabf7',SKD='#1c7ed6',SCR='#f06595',CAM='#ffc9de',CMD='#f783ac',SHOE='#e03131'
const ds=(c,a,b,s,f)=>{for(const[l,k]of[[a,'#111'],[b,s]])c.lineWidth=l,c.strokeStyle=k,c.beginPath(),f(),c.stroke();c.strokeStyle='#111'}
const eye=(c,x,y,d)=>{
c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill()
c.save();c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.clip()
c.beginPath();c.ellipse(x+5,y,11.5,15,0,0,T);c.fillStyle=EYE;c.fill();c.lineWidth=2.5;c.stroke()
c.save();c.clip();c.fillStyle=ED;c.beginPath();c.ellipse(x+5,y-10,13,10,0,0,T);c.fill();c.restore()
c.fillStyle='#111';c.beginPath();c.ellipse(x+6,y+1,5.5,7.5,0,0,T);c.fill()
c.fillStyle='#fff';c.beginPath();c.arc(x+1,y-6,4.5,0,T);c.fill();c.beginPath();c.arc(x+10,y+7,2,0,T);c.fill();c.restore()
c.lineWidth=7;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke()
}
const star=(c,x,y,r)=>{c.fillStyle='#ffd43b';c.lineWidth=3;c.beginPath();for(let k=0;k<8;k++){const a=k*PI/4,q=k%2?r*.35:r;c.lineTo(x+cos(a)*q,y+sin(a)*q)}c.closePath();c.fill();c.stroke()}
export default(c,t,i)=>{
const sh=t<.6,dev=sh?1-t/.6:t<.85?0:1,fl=t>=.85?cos(PI*(t-.85)/.15):1,happy=!sh&&t<.85,j=sh?(i%2?1:-1):0,ov=t>=.85&&fl<0?1:dev
c.translate(140,246);c.scale(1.1,1.1);c.translate(-140,-246)
for(const d of[-1,1])ds(c,13,7,SKIN,()=>{c.moveTo(104+d*10,200);c.lineTo(104+d*11,232)})
c.fillStyle='#fff';c.lineWidth=4;for(const d of[-1,1])c.beginPath(),c.roundRect(98+d*11,222,12,12,3),c.fill(),c.stroke()
c.fillStyle=SHOE;c.lineWidth=5;for(const d of[-1,1])c.beginPath(),c.ellipse(104+d*13,240,12,6,0,0,T),c.fill(),c.stroke()
c.lineWidth=6;c.fillStyle=SKT;c.beginPath();c.moveTo(84,180);c.lineTo(124,180);c.lineTo(134,208);c.lineTo(74,208);c.closePath();c.fill();c.stroke()
c.strokeStyle=SKD;c.lineWidth=3;c.beginPath();for(const x of[94,104,114])c.moveTo(x,184),c.lineTo(x+(x-104)*.3,206);c.stroke();c.strokeStyle='#111'
c.lineWidth=6;c.fillStyle=CAR;c.beginPath();c.moveTo(90,128);c.quadraticCurveTo(76,134,78,186);c.lineTo(130,186);c.quadraticCurveTo(132,134,118,128);c.closePath();c.fill();c.stroke()
c.fillStyle='#fff';c.lineWidth=4;c.beginPath();c.moveTo(94,128);c.lineTo(104,148);c.lineTo(114,128);c.closePath();c.fill();c.stroke()
c.fillStyle=CAD;for(const y of[156,170])c.beginPath(),c.arc(104,y,3,0,T),c.fill(),c.stroke()
ds(c,6,2.5,CMD,()=>{c.moveTo(94,130);c.lineTo(90,158);c.moveTo(114,130);c.lineTo(118,158)})
c.fillStyle=CAM;c.lineWidth=5;c.beginPath();c.roundRect(84,152,40,28,6);c.fill();c.stroke()
c.fillStyle='#fff';c.beginPath();c.arc(104,167,9,0,T);c.fill();c.stroke();c.fillStyle='#495057';c.beginPath();c.arc(104,167,4.5,0,T);c.fill()
c.fillStyle=CMD;c.lineWidth=3;c.beginPath();c.rect(88,156,7,5);c.fill();c.stroke()
ds(c,17,9,CAR,()=>{c.moveTo(86,136);c.lineTo(72,170);c.lineTo(80,186)})
c.fillStyle=SKIN;c.lineWidth=5;c.beginPath();c.arc(81,188,7,0,T);c.fill();c.stroke()
c.save();c.translate(104,86);c.scale(.6,.6);c.translate(-128,-120)
for(const d of[-1,1]){c.save();c.translate(128+d*66,150);c.rotate(d*.15)
c.lineWidth=7;c.fillStyle=HAIR;c.beginPath();c.moveTo(0,0);c.bezierCurveTo(d*30,10,d*30,60,d*10,98);c.quadraticCurveTo(d*2,108,-d*6,96);c.bezierCurveTo(d*10,60,-d*4,26,0,0);c.fill();c.stroke()
c.restore();c.fillStyle=SCR;c.beginPath();c.ellipse(128+d*64,150,14,10,d*.5,0,T);c.fill();c.stroke()}
c.lineWidth=7;c.fillStyle=HD;c.beginPath();c.moveTo(128,36);c.bezierCurveTo(196,36,208,100,196,156);c.lineTo(60,156);c.bezierCurveTo(48,100,60,36,128,36);c.fill();c.stroke()
c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke()
if(happy){c.lineWidth=7;for(const x of[103,153])c.beginPath(),c.arc(x,146,15,1.15*PI,1.85*PI),c.stroke()}else eye(c,103,140,-1),eye(c,153,140,1)
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,164,13,7,0,0,T),c.fill()
c.lineWidth=5;c.fillStyle='#c92a2a';c.beginPath();c.moveTo(114,164);c.quadraticCurveTo(128,186,142,164);c.closePath();c.fill();c.stroke()
c.fillStyle='#ff8fab';c.lineWidth=3;c.beginPath();c.ellipse(128,176,6,4,0,0,T);c.fill()
c.lineWidth=7;c.fillStyle=HAIR;c.beginPath();c.moveTo(68,150)
c.bezierCurveTo(52,76,88,38,128,38);c.bezierCurveTo(168,38,204,76,188,150)
c.quadraticCurveTo(188,118,180,102);c.lineTo(166,108);c.lineTo(160,92);c.lineTo(146,104);c.lineTo(138,88);c.lineTo(126,104)
c.lineTo(116,88);c.lineTo(106,106);c.lineTo(94,94);c.lineTo(88,110);c.lineTo(78,104);c.quadraticCurveTo(70,124,68,150);c.closePath();c.fill();c.stroke()
c.strokeStyle=HL;c.lineWidth=6;for(const[s,e]of[[1.26,1.38],[1.46,1.54],[1.62,1.72]])c.beginPath(),c.arc(128,106,58,PI*s,PI*e),c.stroke();c.strokeStyle='#111'
c.restore()
const hx=172+5*j,hy=118
ds(c,17,9,CAR,()=>{c.moveTo(120,136);c.lineTo(150,140);c.lineTo(hx,hy+6)})
c.save();c.translate(hx+4,hy-24);c.rotate(.22*j+.05);c.scale(fl,1)
c.fillStyle=fl<0?'#e9ecef':'#fff';c.lineWidth=5;c.beginPath();c.roundRect(-24,-30,48,58,3);c.fill();c.stroke()
if(fl>=0){c.save();c.beginPath();c.rect(-18,-24,36,36);c.clip()
c.fillStyle='#a5d8ff';c.fillRect(-18,-24,36,36);c.fillStyle='#69db7c';c.beginPath();c.ellipse(-4,16,30,14,0,0,T);c.fill();c.stroke()
c.fillStyle='#ffd43b';c.lineWidth=3;c.beginPath();c.arc(8,-12,6,0,T);c.fill();c.stroke()
c.fillStyle='#fff';c.beginPath();c.ellipse(-8,-10,7,4,0,0,T);c.fill();c.stroke()
if(ov>0)c.fillStyle=`rgba(92,75,64,${min(1,ov)})`,c.fillRect(-18,-24,36,36)
c.restore();c.lineWidth=3;c.strokeRect(-18,-24,36,36)}
c.restore()
c.fillStyle=SKIN;c.lineWidth=5;c.beginPath();c.ellipse(hx,hy,9,10,0,0,T);c.fill();c.stroke()
if(sh)for(const d of[-1,1])ds(c,6,2.5,'#fff',()=>{c.moveTo(hx+4+d*34,hy-34);c.quadraticCurveTo(hx+4+d*40,hy-24,hx+4+d*34,hy-14)})
if(happy){const s=sin(PI*(t-.6)/.25);star(c,214,60,9*s);star(c,146,58,6*s);star(c,222,124,5*s)}
}
+58
View File
@@ -0,0 +1,58 @@
// potter girl with a mahogany ponytail and a clay smudge on her cheek coning clay up into a tall pot and pressing it back down on a spinning wheel
// the dark back hair gets a white rim so it doesn't vanish on black
const{sin,cos,PI,max,min}=Math,T=2*PI
export const frames=16,delay=90
const SKIN='#ffe3d1',HAIR='#8a3330',HD='#5c1f1f',HL='#d19494',EYE='#0ca678',ED='#087f5b',BL='#ffa8a8',APR='#4dabf7',APD='#1c7ed6',CLAY='#c08552',CLD='#8d5a33',CLL='#dba67a',WH='#ced4da',WHD='#868e96',BASE='#495057'
const ds=(c,a,b,s,f)=>{for(const[l,k]of[[a,'#111'],[b,s]])c.lineWidth=l,c.strokeStyle=k,c.beginPath(),f(),c.stroke();c.strokeStyle='#111'}
const eye=(c,x,y,d)=>{
c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill()
c.save();c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.clip()
c.beginPath();c.ellipse(x,y+7,11.5,15,0,0,T);c.fillStyle=EYE;c.fill();c.lineWidth=2.5;c.stroke()
c.save();c.clip();c.fillStyle=ED;c.beginPath();c.ellipse(x,y-3,13,10,0,0,T);c.fill();c.restore()
c.fillStyle='#111';c.beginPath();c.ellipse(x,y+8,5.5,7.5,0,0,T);c.fill()
c.fillStyle='#fff';c.beginPath();c.arc(x-4,y+2,4.5,0,T);c.fill();c.beginPath();c.arc(x+5,y+12,2,0,T);c.fill();c.restore()
c.lineWidth=7;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke()
}
export default(c,t)=>{
const h=(1-cos(T*t))/2,H=24+34*h,top=206-H,bw=34-6*h,mw=30-12*h,tw=18-4*h,sp=t*6%1
c.lineWidth=7;c.fillStyle='#fff';c.beginPath();c.moveTo(100,148);c.quadraticCurveTo(60,158,52,240);c.lineTo(204,240);c.quadraticCurveTo(196,158,156,148);c.closePath();c.fill();c.stroke()
c.fillStyle=APR;c.lineWidth=6;c.beginPath();c.moveTo(104,170);c.lineTo(152,170);c.lineTo(160,240);c.lineTo(96,240);c.closePath();c.fill();c.stroke()
c.lineWidth=5;c.beginPath();c.moveTo(106,170);c.lineTo(112,152);c.moveTo(150,170);c.lineTo(144,152);c.stroke()
c.fillStyle=CLD;for(const[x,y]of[[112,190],[140,184],[148,202]])c.beginPath(),c.ellipse(x,y,4,3,.5,0,T),c.fill()
c.fillStyle=SKIN;c.lineWidth=6;c.beginPath();c.moveTo(118,134);c.lineTo(118,152);c.quadraticCurveTo(128,160,138,152);c.lineTo(138,134);c.fill();c.beginPath();c.moveTo(118,134);c.lineTo(118,150);c.moveTo(138,134);c.lineTo(138,150);c.stroke()
c.save();c.translate(128,94);c.scale(.68,.68);c.translate(-128,-120)
const tail=()=>{c.moveTo(150,40);c.bezierCurveTo(206,10,236,60,222,120);c.quadraticCurveTo(218,150,200,170);c.quadraticCurveTo(206,130,196,96);c.quadraticCurveTo(186,70,164,62)}
const back=()=>{c.moveTo(128,36);c.bezierCurveTo(196,36,208,100,198,150);c.lineTo(58,150);c.bezierCurveTo(48,100,60,36,128,36)}
c.strokeStyle='#fff';c.lineWidth=20;for(const f of[tail,back])c.beginPath(),f(),c.stroke();c.strokeStyle='#111'
c.lineWidth=7;c.fillStyle=HAIR;c.beginPath();tail();c.fill();c.stroke()
c.fillStyle=HD;c.beginPath();back();c.fill();c.stroke()
c.fillStyle=APR;c.lineWidth=5;c.beginPath();c.ellipse(158,50,12,9,.5,0,T);c.fill();c.stroke()
c.lineWidth=7;c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke()
eye(c,103,140,-1);eye(c,153,140,1)
c.fillStyle=BL;c.beginPath();c.ellipse(172,164,13,7,0,0,T);c.fill()
c.fillStyle=CLAY;c.lineWidth=3;c.beginPath();c.moveTo(70,158);c.quadraticCurveTo(84,150,96,156);c.quadraticCurveTo(92,164,80,166);c.quadraticCurveTo(72,166,70,158);c.fill();c.stroke()
c.lineWidth=5;c.fillStyle='#c92a2a';c.beginPath();c.moveTo(118,166);c.quadraticCurveTo(128,176,138,166);c.closePath();c.fill();c.stroke()
c.fillStyle='#ff8fab';c.lineWidth=3;c.beginPath();c.ellipse(132,171,4,3,0,0,T);c.fill();c.stroke()
const fr=()=>{c.moveTo(68,150);c.bezierCurveTo(52,78,90,40,128,40);c.bezierCurveTo(166,40,204,78,188,150)
c.quadraticCurveTo(186,120,178,104);c.quadraticCurveTo(168,98,156,104);c.quadraticCurveTo(150,92,138,88);c.quadraticCurveTo(134,102,124,108)
c.quadraticCurveTo(120,96,110,94);c.quadraticCurveTo(102,106,90,110);c.quadraticCurveTo(80,104,76,108);c.quadraticCurveTo(70,126,68,150);c.closePath()}
c.strokeStyle='#fff';c.lineWidth=20;c.beginPath();fr();c.stroke();c.strokeStyle='#111'
c.lineWidth=7;c.fillStyle=HAIR;c.beginPath();fr();c.fill();c.stroke()
c.strokeStyle=HL;c.lineWidth=6;for(const[s,e]of[[1.26,1.38],[1.46,1.54],[1.62,1.72]])c.beginPath(),c.arc(128,106,58,PI*s,PI*e),c.stroke();c.strokeStyle='#111'
c.restore()
c.lineWidth=7;c.fillStyle=BASE;c.strokeStyle='#fff';c.lineWidth=14;c.beginPath();c.moveTo(90,222);c.lineTo(166,222);c.lineTo(178,250);c.lineTo(78,250);c.closePath();c.stroke();c.strokeStyle='#111';c.lineWidth=7;c.fill();c.stroke()
c.fillStyle=WHD;c.lineWidth=6;c.beginPath();c.ellipse(128,217,62,12,0,0,PI);c.lineTo(66,212);c.ellipse(128,212,62,12,0,PI,0,true);c.closePath();c.fill();c.stroke()
c.fillStyle=WH;c.beginPath();c.ellipse(128,212,62,12,0,0,T);c.fill();c.stroke()
c.fillStyle=WHD;for(let k=0;k<6;k++){const a=k*T/6+t*T*2;if(sin(a)>0)c.beginPath(),c.ellipse(128+50*cos(a),212+9*sin(a),4,2,0,0,T),c.fill()}
const pot=()=>{c.moveTo(128-bw,207);c.bezierCurveTo(128-bw-8,207-H*.4,128-mw,207-H*.7,128-tw,top);c.lineTo(128+tw,top);c.bezierCurveTo(128+mw,207-H*.7,128+bw+8,207-H*.4,128+bw,207);c.quadraticCurveTo(128,214,128-bw,207)}
c.fillStyle=CLAY;c.lineWidth=6;c.beginPath();pot();c.fill();c.stroke()
c.save();c.beginPath();pot();c.clip();c.strokeStyle=CLD;c.lineWidth=2.5
for(let k=0;k<4;k++){const y=207-H*(k+.5)/4;c.beginPath();c.moveTo(80,y);c.lineTo(176,y);c.stroke()}
c.strokeStyle=CLL;c.lineWidth=4;for(const o of[0,.5]){const x=128-bw+2*bw*((sp+o)%1);c.beginPath();c.moveTo(x,214);c.lineTo(x+(128-x)*.4,top);c.stroke()}
c.restore()
c.fillStyle=CLD;c.lineWidth=4;c.beginPath();c.ellipse(128,top,tw,4,0,0,T);c.fill();c.stroke()
const hy=207-H*.55,hw=bw*.5+mw*.5+4
ds(c,20,11,'#fff',()=>{c.moveTo(100,164);c.lineTo(78,186)});ds(c,18,9,SKIN,()=>{c.moveTo(78,186);c.lineTo(128-hw-6,hy)})
ds(c,20,11,'#fff',()=>{c.moveTo(156,164);c.lineTo(178,186)});ds(c,18,9,SKIN,()=>{c.moveTo(178,186);c.lineTo(128+hw+6,hy)})
c.fillStyle=SKIN;c.lineWidth=5;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*hw,hy,10,13,d*.2,0,T),c.fill(),c.stroke()
}
+77
View File
@@ -0,0 +1,77 @@
// chibi in a pumpkin dress and cat-ear headband shaking her jack-o-lantern candy bucket, candies hopping out and dropping back in
const{sin,cos,PI,max}=Math,T=2*PI
export const frames=16,delay=80
const SKIN='#ffe3d1',HAIR='#862e9c',HD='#5f1f6e',HL='#e5c4ee',EYE='#94d82d',ED='#5c940d',PUMP='#ff922b',PD='#e8590c',STEM='#51cf66',SD='#2f9e44',EAR='#495057',PINK='#faa2c1',SOCK='#b197fc',BL='#ffa8a8',MO='#c92a2a',CANDY=['#f783ac','#4dabf7','#ffd43b','#69db7c']
const eye=(c,x,y,d)=>{
c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill()
c.save();c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.clip();c.fillStyle=EYE;c.fill();c.fillStyle=ED;c.beginPath();c.ellipse(x,y-8,13,10,0,0,T);c.fill();c.restore()
c.lineWidth=3.5;c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.stroke()
c.fillStyle='#111';c.beginPath();c.ellipse(x,y+3,5.5,7.5,0,0,T);c.fill()
c.fillStyle='#fff';c.beginPath();c.arc(x-4,y-5,4.5,0,T);c.fill();c.beginPath();c.arc(x+5,y+8,2,0,T);c.fill()
c.lineWidth=8;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke()
}
const candy=(c,x,y,col,a)=>{
c.save();c.translate(x,y);c.rotate(a);c.fillStyle=col;c.lineWidth=3.5
for(const d of[-1,1])c.beginPath(),c.moveTo(d*6,0),c.lineTo(d*15,-6),c.lineTo(d*15,6),c.closePath(),c.fill(),c.stroke()
c.beginPath();c.ellipse(0,0,8,6.5,0,0,T);c.fill();c.stroke();c.restore()
}
export default(c,t)=>{
const s=5*sin(2*T*t),b=0,Z=.62,bx=194,by=214+s
// twin tails behind everything
c.save();c.translate(122,70+b);c.scale(Z,Z);c.translate(-128,-40)
c.fillStyle=HAIR;c.lineWidth=8
for(const d of[-1,1]){const sw=d*6*sin(2*T*t+1);c.beginPath();c.moveTo(128+d*58,110);c.bezierCurveTo(128+d*96,130,128+d*92+sw,190,128+d*72+sw,226);c.quadraticCurveTo(128+d*60,214,128+d*62,196);c.bezierCurveTo(128+d*64,160,128+d*52,140,128+d*44,126);c.closePath();c.fill();c.stroke()}
c.restore()
// legs, stockings and shoes
for(const d of[-1,1]){for(const[l,col]of[[16,'#111'],[9,SOCK]])c.lineWidth=l,c.strokeStyle=col,c.beginPath(),c.moveTo(122+d*12,208),c.lineTo(122+d*13,234),c.stroke()
c.strokeStyle=HD;c.lineWidth=3;for(const y of[214,222,230])c.beginPath(),c.moveTo(122+d*12-4,y),c.lineTo(122+d*12+4,y),c.stroke()}
c.strokeStyle='#111';c.lineWidth=5;c.fillStyle=EAR
for(const d of[-1,1]){c.beginPath();c.ellipse(122+d*15,240,11,6.5,0,0,T);c.lineWidth=12;c.strokeStyle='#fff';c.stroke();c.lineWidth=5;c.strokeStyle='#111';c.fill();c.stroke()}
// arm holding the bucket
for(const[l,col]of[[16,'#111'],[9,SKIN]])c.lineWidth=l,c.strokeStyle=col,c.beginPath(),c.moveTo(146,180+b),c.lineTo(bx-6,by-46),c.stroke()
c.strokeStyle='#111'
// pumpkin dress
c.save();c.translate(122,196+b)
c.lineWidth=6;c.fillStyle=PUMP;c.beginPath();c.ellipse(0,0,44,30,0,0,T);c.fill();c.stroke()
c.strokeStyle=PD;c.lineWidth=4;for(const k of[-1,0,1])c.beginPath(),c.ellipse(k*20,0,k?14:12,28,0,k<0?PI*.5:-PI*.5,k<0?PI*1.5:PI*.5),c.stroke()
c.strokeStyle='#111';c.lineWidth=5;c.fillStyle=STEM
for(const d of[-1,1])c.beginPath(),c.moveTo(0,-28),c.quadraticCurveTo(d*14,-38,d*24,-26),c.quadraticCurveTo(d*12,-24,0,-24),c.closePath(),c.fill(),c.stroke()
c.restore()
// candies hopping out of the bucket, drawn behind its front
for(let k=0;k<3;k++){const p=(2*t+k/3)%1,h=46*sin(PI*p);if(p<.9)candy(c,bx-14+k*14+(k-1)*10*p,by-26-h,CANDY[(k+(2*t+k/3>=1?1:0))%4],(k-1)*1.5*p+k)}
// jack-o-lantern bucket
c.lineWidth=5;c.beginPath();c.moveTo(bx-24,by-18);c.quadraticCurveTo(bx,by-56,bx+24,by-18);c.lineWidth=11;c.stroke();c.strokeStyle=EAR;c.lineWidth=4;c.stroke();c.strokeStyle='#111'
c.lineWidth=6;c.fillStyle=PUMP;c.beginPath();c.ellipse(bx,by,30,26,0,0,T);c.fill();c.stroke()
c.strokeStyle=PD;c.lineWidth=4;for(const d of[-1,1])c.beginPath(),c.ellipse(bx+d*12,by,10,24,0,0,T),c.stroke()
c.strokeStyle='#111';c.fillStyle=PD;c.lineWidth=5;c.beginPath();c.ellipse(bx,by-22,22,6,0,0,T);c.fill();c.stroke()
c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.moveTo(bx+d*12,by-8),c.lineTo(bx+d*5,by+1),c.lineTo(bx+d*18,by+1),c.closePath(),c.fill()
c.beginPath();c.moveTo(bx-15,by+8);c.quadraticCurveTo(bx,by+22,bx+15,by+8);c.lineTo(bx+8,by+12);c.lineTo(bx+4,by+8);c.lineTo(bx-4,by+12);c.lineTo(bx-8,by+8);c.closePath();c.fill()
c.lineWidth=5;c.fillStyle=SKIN;c.beginPath();c.arc(bx-6,by-46,8,0,T);c.fill();c.stroke()
if(Math.abs(s)>3.5){c.lineWidth=4;for(const d of[-1,1])c.beginPath(),c.moveTo(bx+d*40,by-14),c.lineTo(bx+d*48,by-20),c.moveTo(bx+d*40,by-2),c.lineTo(bx+d*50,by-2),c.stroke()}
// head
c.save();c.translate(122,70+b);c.scale(Z,Z);c.translate(-128,-40)
c.lineWidth=8;c.fillStyle=HD;c.beginPath();c.moveTo(128,36);c.bezierCurveTo(196,36,206,96,196,150);c.lineTo(60,150);c.bezierCurveTo(50,96,60,36,128,36);c.fill();c.stroke()
c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke()
eye(c,103,140,-1)
if(t>=.5&&t<.75){c.lineWidth=8;c.beginPath();c.moveTo(166,130);c.lineTo(146,141);c.lineTo(166,152);c.stroke()}else eye(c,153,140,1)
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,162,14,7,0,0,T),c.fill()
c.lineWidth=4.5;c.fillStyle=MO;c.beginPath();c.moveTo(114,164);c.quadraticCurveTo(128,186,142,164);c.closePath();c.fill();c.stroke()
c.fillStyle='#fff';c.lineWidth=3;c.beginPath();c.moveTo(132,165);c.lineTo(136,173);c.lineTo(139,165);c.closePath();c.fill();c.stroke()
c.lineWidth=8;c.fillStyle=HAIR;c.beginPath();c.moveTo(66,146)
c.bezierCurveTo(50,74,88,38,128,38);c.bezierCurveTo(168,38,206,74,190,146)
c.quadraticCurveTo(186,118,178,104);c.quadraticCurveTo(170,104,164,112);c.quadraticCurveTo(160,96,150,92);c.quadraticCurveTo(144,104,136,110)
c.quadraticCurveTo(132,96,122,90);c.quadraticCurveTo(116,104,106,108);c.quadraticCurveTo(102,96,92,96);c.quadraticCurveTo(86,106,80,112)
c.quadraticCurveTo(70,124,66,146);c.closePath();c.fill();c.stroke()
c.strokeStyle=HL;c.lineWidth=6;for(const[a,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,58,PI*a,PI*e),c.stroke()
c.strokeStyle='#111'
// cat-ear headband, white rimmed so it shows on black
for(const d of[-1,1]){const tw=d>0&&t>=.25&&t<.375?.25:0;c.save();c.translate(128+d*44,52);c.rotate(d*(.35+tw))
c.beginPath();c.moveTo(-24,14);c.lineTo(0,-38);c.lineTo(24,14);c.closePath();c.lineWidth=20;c.strokeStyle='#fff';c.stroke();c.fillStyle=EAR;c.fill();c.lineWidth=8;c.strokeStyle='#111';c.stroke()
c.fillStyle=PINK;c.beginPath();c.moveTo(-11,8);c.lineTo(0,-18);c.lineTo(11,8);c.closePath();c.fill();c.restore()}
c.restore()
// free arm making a cat paw by her cheek
const pw=4*sin(2*T*t+1)
for(const[l,col]of[[16,'#111'],[9,SKIN]])c.lineWidth=l,c.strokeStyle=col,c.beginPath(),c.moveTo(98,180+b),c.quadraticCurveTo(70,172,74+pw*.3,146+pw+b),c.stroke()
c.strokeStyle='#111';c.lineWidth=5;c.fillStyle=SKIN;c.beginPath();c.arc(76,140+pw+b,10,0,T);c.fill();c.stroke()
c.lineWidth=3;for(const k of[-4,4])c.beginPath(),c.moveTo(76+k,132+pw+b),c.lineTo(76+k,138+pw+b),c.stroke()
}
+57
View File
@@ -0,0 +1,57 @@
// girl in a santa hat and red coat tossing a wrapped present up past her head and catching it, eyes following it, snowflakes drifting
const{sin,cos,PI,max,min}=Math,T=2*PI
export const frames=16,delay=80
const SKIN='#ffe3d1',HAIR='#6b4226',HD='#4a2c17',HL='#c08a5e',EYE='#2f9e44',ED='#1b5e20',RED='#fa5252',RD='#c92a2a',FUR='#fff',BOX='#51cf66',BXD='#2f9e44',RIB='#ffd43b',BL='#ffa8a8',MO='#c92a2a'
const cl=x=>max(0,min(1,x))
const eye=(c,x,y,d,dx,dy)=>{
c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill()
c.save();c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.clip()
c.fillStyle=EYE;c.beginPath();c.ellipse(x+dx,y+2+dy,11.5,15,0,0,T);c.fill();c.fillStyle=ED;c.beginPath();c.ellipse(x+dx,y-8+dy,13,10,0,0,T);c.fill()
c.fillStyle='#111';c.beginPath();c.ellipse(x+dx,y+3+dy,5.5,7.5,0,0,T);c.fill()
c.fillStyle='#fff';c.beginPath();c.arc(x-4+dx,y-5+dy,4.5,0,T);c.fill();c.beginPath();c.arc(x+5+dx,y+8+dy,2,0,T);c.fill();c.restore()
c.lineWidth=3;c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.stroke()
c.lineWidth=7;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke()
}
const flake=(c,x,y,r)=>{for(const[w,s]of[[7,'#111'],[3,'#fff']]){c.lineWidth=w;c.strokeStyle=s;c.beginPath();for(let k=0;k<3;k++){const a=k*PI/3;c.moveTo(x-r*cos(a),y-r*sin(a));c.lineTo(x+r*cos(a),y+r*sin(a))}c.stroke()}c.strokeStyle='#111'}
export default(c,t)=>{
const a=cl((t-.1)/.62),air=a>0&&a<1,h=sin(PI*a),px=136+76*h,py=230-182*h+(t<.1?6*sin(PI*t/.1):0)+(t>.72&&t<.86?8*sin(PI*(t-.72)/.14):0),hu=air?10*h:0,dx=3*h,dy=-5*h
for(const[x,o]of[[30,0],[226,.5],[56,.3]]){const p=(t+o)%1;flake(c,x+8*sin(T*p),20+200*p,7)}
c.save();c.translate(128,256);c.scale(.82,.82);c.translate(-128,-256)
// hat tip flops behind the head
const fl=8*sin(T*t)
c.lineWidth=7;c.fillStyle=RED;c.beginPath();c.moveTo(72,74);c.bezierCurveTo(90,18,160,0,200+fl,40);c.quadraticCurveTo(206+fl,58,214+fl,74);c.quadraticCurveTo(190,56,184,74);c.closePath();c.fill();c.stroke()
c.fillStyle=FUR;c.beginPath();c.arc(214+fl,82,15,0,T);c.fill();c.stroke()
c.fillStyle=HD;c.beginPath();c.moveTo(128,50);c.bezierCurveTo(194,50,204,110,198,172);c.quadraticCurveTo(186,182,172,170);c.lineTo(84,170);c.quadraticCurveTo(70,182,58,172);c.bezierCurveTo(52,110,62,50,128,50);c.fill();c.stroke()
// coat
c.fillStyle=RED;c.beginPath();c.moveTo(102,188);c.quadraticCurveTo(52,196,40,262);c.lineTo(216,262);c.quadraticCurveTo(204,196,154,188);c.closePath();c.fill();c.stroke()
c.fillStyle=FUR;c.beginPath();c.moveTo(94,190);c.quadraticCurveTo(128,214,162,190);c.quadraticCurveTo(166,204,156,210);c.quadraticCurveTo(128,226,100,210);c.quadraticCurveTo(90,204,94,190);c.fill();c.stroke()
c.lineWidth=5;c.fillStyle=RIB;for(const y of[234,252])c.beginPath(),c.arc(128,y,5,0,T),c.fill(),c.stroke()
c.lineWidth=7;c.fillStyle=SKIN;c.beginPath();c.rect(116,170,24,20);c.fill();c.beginPath();c.moveTo(116,170);c.lineTo(116,188);c.moveTo(140,170);c.lineTo(140,188);c.stroke()
c.fillStyle=SKIN;c.beginPath();c.moveTo(74,108);c.bezierCurveTo(70,160,100,190,128,192);c.bezierCurveTo(156,190,186,160,182,108);c.bezierCurveTo(182,58,74,58,74,108);c.fill();c.stroke()
eye(c,103,146,-1,dx,dy);eye(c,153,146,1,dx,dy)
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*42,166,12,6,0,0,T),c.fill()
c.lineWidth=4;c.fillStyle=MO;c.beginPath()
if(air)c.moveTo(117,170),c.quadraticCurveTo(128,186,139,170),c.closePath(),c.fill(),c.stroke();else c.arc(128,170,7,.15*PI,.85*PI),c.stroke()
c.lineWidth=7;c.fillStyle=HAIR;c.beginPath();c.moveTo(66,150)
c.bezierCurveTo(58,104,72,78,92,74);c.lineTo(166,74);c.bezierCurveTo(186,78,198,104,190,150)
c.quadraticCurveTo(186,124,176,112);c.quadraticCurveTo(168,110,162,118);c.quadraticCurveTo(156,104,146,100);c.quadraticCurveTo(140,112,132,116)
c.quadraticCurveTo(126,102,116,98);c.quadraticCurveTo(110,112,100,116);c.quadraticCurveTo(94,104,86,106);c.quadraticCurveTo(76,120,66,150);c.closePath();c.fill();c.stroke()
for(const d of[-1,1])c.beginPath(),c.moveTo(128+d*60,150),c.quadraticCurveTo(128+d*76,170,128+d*68,186),c.quadraticCurveTo(128+d*60,172,128+d*56,160),c.fill(),c.stroke()
c.strokeStyle=HL;c.lineWidth=5;for(const[x,y]of[[100,90],[150,90]])c.beginPath(),c.moveTo(x-8,y+4),c.quadraticCurveTo(x,y-2,x+8,y+4),c.stroke();c.strokeStyle='#111'
// fur band of the hat
c.lineWidth=7;c.fillStyle=FUR;c.beginPath();c.moveTo(64,82);c.quadraticCurveTo(128,52,192,82);c.quadraticCurveTo(198,92,190,100);c.quadraticCurveTo(128,72,66,100);c.quadraticCurveTo(58,92,64,82);c.fill();c.stroke()
c.restore()
// arms: sleeves with fur cuffs, hands lift a little as she tosses
for(const d of[-1,1]){const hx=128+d*(24+4*h),hy=242-hu
for(const[l,s]of[[30,'#111'],[19,RED]])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),c.moveTo(128+d*66,256),c.quadraticCurveTo(128+d*52,236,hx+d*10,hy+6),c.stroke()
c.strokeStyle='#111';c.lineWidth=5;c.fillStyle=FUR;c.beginPath();c.ellipse(hx+d*12,hy+6,9,12,d*.6,0,T);c.fill();c.stroke()
c.fillStyle=SKIN;c.beginPath();c.ellipse(hx,hy,11,9,0,0,T);c.fill();c.stroke()}
// the present
c.save();c.translate(px,py);c.rotate(air?T*a:0)
c.lineWidth=5;c.fillStyle=BOX;c.beginPath();c.roundRect(-20,-16,40,32,4);c.fill();c.stroke()
c.fillStyle=RIB;c.beginPath();c.rect(-5,-16,10,32);c.fill();c.stroke()
c.fillStyle=BXD;c.beginPath();c.roundRect(-23,-20,46,10,3);c.fill();c.stroke();c.fillStyle=RIB;c.beginPath();c.rect(-5,-20,10,10);c.fill();c.stroke()
c.lineWidth=4;for(const d of[-1,1])c.beginPath(),c.moveTo(0,-20),c.quadraticCurveTo(d*16,-36,d*4,-22),c.closePath(),c.fill(),c.stroke()
c.restore()
if(t>.72&&t<.84){c.lineWidth=4;for(const d of[-1,1])c.beginPath(),c.moveTo(128+d*40,214),c.lineTo(128+d*50,208),c.moveTo(128+d*40,224),c.lineTo(128+d*52,224),c.stroke()}
}
+44
View File
@@ -0,0 +1,44 @@
// girl with neon pink hair watching her jelly slime pet bounce on top of her head, both grinning, boing lines on each landing
const{sin,cos,PI,max,round,pow}=Math,T=2*PI
export const frames=16,delay=70
const SKIN='#ffe3d1',HAIR='#f06595',HD='#c2255c',HL='#ffdeeb',EYE='#94d82d',ED='#5c940d',TOP='#ffec99',TD='#fab005',SL='#99e9f2',SD='#3bc9db',BL='#ffa8a8'
const eye=(c,x,y,d,u)=>{
c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill()
c.save();c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.clip();c.beginPath();c.ellipse(x,y-u+2,11.5,15,0,0,T);c.fillStyle=EYE;c.fill();c.lineWidth=2.5;c.stroke()
c.fillStyle=ED;c.beginPath();c.ellipse(x,y-u-8,13,10,0,0,T);c.fill()
c.fillStyle='#111';c.beginPath();c.ellipse(x,y-u+3,5.5,7.5,0,0,T);c.fill()
c.fillStyle='#fff';c.beginPath();c.arc(x-4,y-u-5,4.5,0,T);c.fill();c.beginPath();c.arc(x+5,y-u+8,2,0,T);c.fill();c.restore()
c.lineWidth=6;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke()
}
export default(c,t)=>{
const u=(t*2)%1,h=round(26*sin(PI*u)),sq=pow(1-sin(PI*u),3),st=cos(PI*u)*(1-sq)*.18,dip=round(3*sq)
c.save();c.translate(128,262);c.scale(.8,.8);c.translate(-128,-262+dip)
c.lineWidth=6;c.fillStyle=HD;c.beginPath();c.moveTo(128,34);c.bezierCurveTo(200,34,216,100,208,170);c.quadraticCurveTo(214,214,196,236);c.lineTo(60,236);c.quadraticCurveTo(42,214,48,170);c.bezierCurveTo(40,100,56,34,128,34);c.fill();c.stroke()
c.fillStyle=TOP;c.beginPath();c.moveTo(98,190);c.quadraticCurveTo(58,198,50,256);c.lineTo(206,256);c.quadraticCurveTo(198,198,158,190);c.closePath();c.fill();c.stroke()
c.strokeStyle=TD;c.lineWidth=4;for(const y of[222,238])c.beginPath(),c.moveTo(62,y),c.quadraticCurveTo(128,y-10,194,y),c.stroke();c.strokeStyle='#111'
c.fillStyle='#fff';c.lineWidth=5;for(const d of[-1,1])c.beginPath(),c.moveTo(128,206),c.quadraticCurveTo(128+d*18,206,128+d*30,190),c.lineTo(128+d*8,188),c.closePath(),c.fill(),c.stroke()
c.fillStyle=SKIN;c.beginPath();c.rect(116,168,24,22);c.fill();c.beginPath();c.moveTo(116,168);c.lineTo(116,190);c.moveTo(140,168);c.lineTo(140,190);c.stroke()
c.lineWidth=6;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke()
const up=round(6-h/8);eye(c,103,140,-1,up);eye(c,153,140,1,up)
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*42,162,12,6,0,0,T),c.fill()
c.lineWidth=2.5;for(const d of[-1,1])for(const k of[-5,0,5])c.beginPath(),c.moveTo(128+d*42+k-2,165),c.lineTo(128+d*42+k+2,159),c.stroke()
c.lineWidth=4;c.fillStyle='#c92a2a';c.beginPath();c.moveTo(114,164);c.quadraticCurveTo(128,186,142,164);c.closePath();c.fill();c.stroke()
c.save();c.clip();c.fillStyle='#ff8fab';c.beginPath();c.ellipse(128,180,9,6,0,0,T);c.fill();c.restore()
c.lineWidth=6;c.fillStyle=HAIR;c.beginPath();c.moveTo(62,170)
c.bezierCurveTo(46,74,88,34,128,34);c.bezierCurveTo(168,34,210,74,194,170)
c.quadraticCurveTo(190,128,180,104);c.quadraticCurveTo(170,98,166,112);c.quadraticCurveTo(160,94,148,88);c.quadraticCurveTo(144,102,136,108)
c.quadraticCurveTo(130,92,120,88);c.quadraticCurveTo(116,102,106,108);c.quadraticCurveTo(100,94,90,94);c.quadraticCurveTo(86,108,84,114)
c.quadraticCurveTo(76,104,74,104);c.quadraticCurveTo(66,134,62,170);c.closePath();c.fill();c.stroke()
c.strokeStyle=HL;c.lineWidth=5;for(const[a,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,56,PI*a,PI*e),c.stroke();c.strokeStyle='#111'
if(sq>.45){c.lineWidth=4;for(const d of[-1,1])c.beginPath(),c.arc(128+d*58,38,10,d<0?PI*1.05:PI*1.55,d<0?PI*1.45:PI*1.95),c.stroke(),c.beginPath(),c.arc(128+d*58,38,18,d<0?PI*1.05:PI*1.55,d<0?PI*1.45:PI*1.95),c.stroke()}
const w=56*(1+sq*.3-st),hh=46*(1-sq*.3+st),by=40-h
c.save();c.translate(128,by)
const sp=()=>{c.beginPath();c.moveTo(-w,0);c.bezierCurveTo(-w,-hh*.9,-w*.5,-hh*1.25,0,-hh*1.25);c.bezierCurveTo(w*.5,-hh*1.25,w,-hh*.9,w,0);c.quadraticCurveTo(0,8,-w,0);c.closePath()}
c.lineWidth=6;c.fillStyle=SL;sp();c.fill();c.save();c.clip();c.fillStyle=SD;c.beginPath();c.ellipse(0,6,w*1.1,hh*.4,0,0,T);c.fill();c.restore();sp();c.stroke()
c.fillStyle='#fff';c.beginPath();c.ellipse(-w*.45,-hh*.8,7,4,-.6,0,T);c.fill();c.beginPath();c.arc(-w*.62,-hh*.5,3,0,T);c.fill()
c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.ellipse(d*16,-hh*.52,6,8,0,0,T),c.fill()
c.fillStyle='#fff';for(const d of[-1,1])c.beginPath(),c.arc(d*16-2,-hh*.52-3,2.5,0,T),c.fill()
c.fillStyle='#ff8fab';for(const d of[-1,1])c.beginPath(),c.ellipse(d*30,-hh*.34,7,4,0,0,T),c.fill()
c.lineWidth=4;c.beginPath();c.arc(0,-hh*.4,7,.15*PI,.85*PI);c.stroke()
c.restore();c.restore()
}
+64
View File
@@ -0,0 +1,64 @@
// mint-haired girl with a soft-serve cone that tilts and starts to drip, she licks the drip up the side and beams with happy eyes
const{sin,cos,PI,max,min}=Math,T=2*PI
export const frames=16,delay=80
const SKIN='#ffe3d1',HAIR='#96f2d7',HD='#20c997',HL='#e6fcf5',EYE='#ff922b',ED='#d9480f',TEE='#fff',STR='#f783ac',VAN='#fff9db',VD='#ffe8a3',CONE='#e0a96d',CD='#b07d4f',BL='#ffa8a8',MO='#c92a2a',TG='#ff8fab',HT='#ff6b9d'
const ease=x=>x<=0?0:x>=1?1:x*x*(3-2*x)
const eye=(c,x,y,d)=>{
c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill()
c.save();c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.clip();c.fillStyle=EYE;c.fill();c.fillStyle=ED;c.beginPath();c.ellipse(x,y-8,13,10,0,0,T);c.fill()
c.fillStyle='#111';c.beginPath();c.ellipse(x+3,y+3,5.5,7.5,0,0,T);c.fill();c.fillStyle='#fff';c.beginPath();c.arc(x-1,y-5,4.5,0,T);c.fill();c.beginPath();c.arc(x+7,y+8,2,0,T);c.fill();c.restore()
c.lineWidth=2.5;c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.stroke()
c.lineWidth=6;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke()
}
const heart=(c,x,y,s)=>{c.save();c.translate(x,y);c.scale(s,s);c.beginPath();c.moveTo(0,8);c.bezierCurveTo(-13,-1,-9,-12,0,-5);c.bezierCurveTo(9,-12,13,-1,0,8);c.restore();c.fill();c.stroke()}
export default(c,t)=>{
const lick=ease((t-.38)/.08)-ease((t-.54)/.08),happy=t>=.4&&t<.82,r=-.04+.1*sin(T*t)-.3*lick,cx=214-28*lick,cy=208-8*lick,drip=t<.46?ease(t/.4):0
c.lineWidth=6
c.fillStyle=HD;c.beginPath();c.moveTo(128,34);c.bezierCurveTo(198,34,212,100,206,200);c.quadraticCurveTo(190,214,170,204);c.lineTo(86,204);c.quadraticCurveTo(66,214,50,200);c.bezierCurveTo(44,100,58,34,128,34);c.fill();c.stroke()
c.fillStyle=HAIR;c.beginPath();c.arc(128,32,18,0,T);c.fill();c.stroke()
c.fillStyle=STR;c.beginPath();c.ellipse(128,46,14,6,0,0,T);c.fill();c.stroke()
// striped tee
c.fillStyle=TEE;c.beginPath();c.moveTo(100,190);c.quadraticCurveTo(62,198,54,256);c.lineTo(202,256);c.quadraticCurveTo(194,198,156,190);c.closePath();c.fill();c.stroke()
c.save();c.clip();c.fillStyle=STR;for(const y of[206,226,246])c.fillRect(40,y,180,9);c.restore()
c.beginPath();c.moveTo(100,190);c.quadraticCurveTo(62,198,54,256);c.lineTo(202,256);c.quadraticCurveTo(194,198,156,190);c.stroke()
c.fillStyle=SKIN;c.beginPath();c.moveTo(116,168);c.lineTo(116,194);c.quadraticCurveTo(128,204,140,194);c.lineTo(140,168);c.fill();c.beginPath();c.moveTo(116,168);c.lineTo(116,192);c.moveTo(140,168);c.lineTo(140,192);c.stroke()
// face
c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke()
if(happy){c.lineWidth=6;for(const x of[103,153])c.beginPath(),c.arc(x,146,13,PI*1.15,PI*1.85),c.stroke()}
else{eye(c,103,140,-1);eye(c,153,140,1)}
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,160,13,6,0,0,T),c.fill()
c.lineWidth=2.5;for(const d of[-1,1])for(const k of[-5,0,5])c.beginPath(),c.moveTo(128+d*44+k-2,163),c.lineTo(128+d*44+k+2,157),c.stroke()
c.lineWidth=3.5;c.fillStyle=MO
if(lick>.05){c.beginPath();c.ellipse(132,170,8,7,0,0,T);c.fill();c.stroke()}
else{c.beginPath();c.moveTo(120,166);c.quadraticCurveTo(128,176,136,166);c.stroke()}
c.lineWidth=6;c.fillStyle=HAIR;c.beginPath();c.moveTo(70,150)
c.bezierCurveTo(54,74,88,36,128,36);c.bezierCurveTo(168,36,202,74,186,150)
c.quadraticCurveTo(186,118,178,104);c.quadraticCurveTo(170,100,164,110);c.quadraticCurveTo(156,94,140,92);c.quadraticCurveTo(138,104,130,110)
c.quadraticCurveTo(122,96,108,94);c.quadraticCurveTo(106,106,96,112);c.quadraticCurveTo(90,100,82,100);c.quadraticCurveTo(76,108,76,112)
c.quadraticCurveTo(70,128,70,150);c.closePath();c.fill();c.stroke()
c.strokeStyle=HL;c.lineWidth=5;for(const[a,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,102,56,PI*a,PI*e),c.stroke()
c.strokeStyle='#111'
// cone in her hand, tilting
for(const[l,s]of[[26,'#111'],[17,SKIN]])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),c.moveTo(230,256),c.lineTo(cx+6,cy+12),c.stroke()
c.strokeStyle='#111'
c.save();c.translate(cx,cy);c.rotate(r)
c.lineWidth=5;c.fillStyle=CONE;c.beginPath();c.moveTo(-22,-34);c.lineTo(22,-34);c.lineTo(2,30);c.lineTo(-2,30);c.closePath();c.fill();c.stroke()
c.save();c.clip();c.strokeStyle=CD;c.lineWidth=3;c.beginPath();for(let k=-3;k<4;k++)c.moveTo(-30+k*12,-36),c.lineTo(10+k*12,34),c.moveTo(30+k*12,-36),c.lineTo(-10+k*12,34);c.stroke();c.restore()
c.lineWidth=5
for(const[y,w]of[[-42,26],[-60,21],[-76,15]]){c.fillStyle=VAN;c.beginPath();c.ellipse(0,y,w,11,0,0,T);c.fill();c.stroke();c.strokeStyle=VD;c.lineWidth=3;c.beginPath();c.arc(-w*.2,y-1,w*.6,PI*1.1,PI*1.6);c.stroke();c.strokeStyle='#111';c.lineWidth=5}
c.fillStyle=VAN;c.beginPath();c.moveTo(-8,-84);c.quadraticCurveTo(0,-104,10,-96);c.quadraticCurveTo(4,-90,8,-82);c.fill();c.stroke()
// the drip slides down the cone until she licks it off
if(drip>0){const len=6+30*drip;c.fillStyle=VAN;c.beginPath();c.moveTo(-24,-40);c.lineTo(-24,-40+len);c.arc(-19,-40+len,5,PI,0,true);c.lineTo(-14,-40);c.fill();c.stroke()}
c.restore()
c.lineWidth=5;c.fillStyle=SKIN;c.beginPath();c.ellipse(cx+2,cy+6,14,12,0,0,T);c.fill();c.stroke()
c.lineWidth=3;c.beginPath();c.moveTo(cx-10,cy+2);c.lineTo(cx+4,cy+2);c.moveTo(cx-10,cy+10);c.lineTo(cx+4,cy+10);c.stroke()
// tongue sweeping up the side of the swirl
if(lick>.05){
const a=-.4-.5*ease((t-.4)/.14),L=4+12*lick
c.save();c.translate(136,172);c.rotate(a);c.fillStyle=TG;c.lineWidth=4
c.beginPath();c.moveTo(0,-7);c.lineTo(L,-7);c.arc(L,0,7,-PI/2,PI/2);c.lineTo(0,7);c.closePath();c.fill();c.stroke()
c.strokeStyle=MO;c.lineWidth=2;c.beginPath();c.moveTo(2,0);c.lineTo(L,0);c.stroke()
c.restore()
}
if(t>.5&&t<.86){c.fillStyle=HT;c.lineWidth=3.5;for(const[x,y,o]of[[52,92,0],[208,60,.1]]){const p=(t-.5-o)/.3;if(p>0&&p<1)heart(c,x,y-20*p,1.1*sin(PI*p))}}
}
+65
View File
@@ -0,0 +1,65 @@
// blindfolded chibi playing suikawari on the beach: wobbles around with her stick raised, swings it down onto the watermelon with a bonk, raises it again
const{sin,cos,PI,max,min}=Math,T=2*PI
export const frames=16,delay=80
const SKIN='#ffe3d1',HAIR='#ffa94d',HD='#f76707',HL='#ffe8cc',TEE='#fff',TS='#ff6b6b',SHORT='#4dabf7',SD='#1c7ed6',BAND='#fff',STICK='#c08a5e',SAND='#ffe8a3',SAND2='#f5d27a',TOWEL='#74c0fc',MEL='#51cf66',MD='#2b8a3e',BL='#ffa8a8',MO='#c92a2a'
const cl=x=>max(0,min(1,x)),ease=x=>x*x*(3-2*x)
const spark=(c,x,y,r)=>{c.beginPath();c.moveTo(x,y-r);for(const[px,py,qx,qy]of[[r,0,r*.18,-r*.18],[0,r,r*.18,r*.18],[-r,0,-r*.18,r*.18],[0,-r,-r*.18,-r*.18]])c.quadraticCurveTo(x+qx,y+qy,x+px,y+py);c.fill();c.stroke()}
export default(c,t)=>{
const sw=ease(cl((t-.52)/.1))*(1-ease(cl((t-.74)/.2))),wob=t<.52?.1*sin(T*2*t/.52):0,hit=t>=.62&&t<.74,hk=hit?sin(PI*(t-.62)/.12):0
// sand and towel
c.lineWidth=6;c.fillStyle=SAND;c.beginPath();c.ellipse(128,236,124,18,0,0,T);c.fill();c.stroke()
c.fillStyle=SAND2;for(const[x,y]of[[40,236],[90,244],[150,230],[226,240]])c.beginPath(),c.arc(x,y,2.5,0,T),c.fill()
c.fillStyle=TOWEL;c.beginPath();c.moveTo(160,226);c.lineTo(242,222);c.lineTo(248,244);c.lineTo(164,248);c.closePath();c.fill();c.stroke()
c.save();c.clip();c.fillStyle='#fff';for(const x of[176,202,228])c.beginPath(),c.rect(x,216,10,36),c.fill();c.restore()
c.beginPath();c.moveTo(160,226);c.lineTo(242,222);c.lineTo(248,244);c.lineTo(164,248);c.closePath();c.stroke()
// watermelon, squashing on the hit
c.save();c.translate(204,226);c.scale(1+.12*hk,1-.14*hk)
c.fillStyle=MEL;c.lineWidth=6;c.beginPath();c.ellipse(0,-20,30,24,0,0,T);c.fill();c.stroke()
c.save();c.beginPath();c.ellipse(0,-20,30,24,0,0,T);c.clip();c.strokeStyle=MD;c.lineWidth=6
for(const x of[-18,-4,10,24]){c.beginPath();c.moveTo(x-4,-46);for(let k=0;k<6;k++)c.lineTo(x+(k%2?4:-4)-(x/30)*k*2,-40+k*8);c.stroke()}c.restore()
c.fillStyle='#fff';c.beginPath();c.ellipse(-12,-32,6,3,-.5,0,T);c.fill()
c.restore()
if(hit){c.fillStyle='#ffd43b';c.lineWidth=4;c.beginPath();for(let k=0;k<16;k++){const a=k*PI/8,r=(k%2?10:24)*(.6+.4*hk);c.lineTo(198+r*cos(a),190+r*sin(a))}c.closePath();c.fill();c.stroke()
c.lineWidth=3;for(const[dx,dy]of[[-30,-24],[30,-26]])spark(c,198+dx,190+dy,8*hk)}
// the whole girl wobbles around her feet
c.save();c.translate(96,238);c.rotate(wob);c.translate(-96,-238)
// legs and sandals
for(const d of[-1,1]){const f=t<.52?3*sin(T*4*t/.52+(d>0?PI:0)):0
for(const[l,s]of[[16,'#111'],[9,SKIN]])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),c.moveTo(96+d*11,206),c.lineTo(96+d*(13+f),230),c.stroke()
c.strokeStyle='#111';c.lineWidth=5;c.fillStyle=TS;c.beginPath();c.ellipse(96+d*(14+f),236,11,5,0,0,T);c.fill();c.stroke()}
// shorts and tee
c.lineWidth=5;c.fillStyle=SHORT;c.beginPath();c.moveTo(78,190);c.lineTo(114,190);c.lineTo(118,212);c.lineTo(98,212);c.lineTo(96,204);c.lineTo(94,212);c.lineTo(74,212);c.closePath();c.fill();c.stroke()
c.fillStyle=TEE;c.beginPath();c.moveTo(82,162);c.quadraticCurveTo(70,166,72,182);c.lineTo(76,196);c.lineTo(116,196);c.lineTo(120,182);c.quadraticCurveTo(122,166,110,162);c.closePath();c.fill();c.stroke()
c.strokeStyle=TS;c.lineWidth=5;c.beginPath();c.moveTo(76,180);c.lineTo(118,180);c.stroke();c.strokeStyle='#111'
// stick and arms: raised back over her shoulder, then swung down onto the melon
const G=[116+34*sw,36+122*sw],a=-2.65+3.4*sw,L=64,S=[G[0]+L*cos(a),G[1]+L*sin(a)],B=[G[0]-12*cos(a),G[1]-12*sin(a)]
const stick=()=>{for(const[l,s]of[[13,'#111'],[6,STICK]])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),c.moveTo(...B),c.lineTo(...S),c.stroke();c.strokeStyle='#111'}
const arms=()=>{for(const sx of[76,116]){const qx=(sx+(sx-96)*1.6)*(1-sw)+((sx+G[0])/2+6)*sw,qy=104*(1-sw)+((170+G[1])/2+14)*sw;for(const[l,s]of[[15,'#111'],[8,SKIN]])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),c.moveTo(sx,170),c.quadraticCurveTo(qx,qy,G[0],G[1]),c.stroke()}
c.strokeStyle='#111';c.lineWidth=5;c.fillStyle=SKIN;c.beginPath();c.arc(G[0],G[1],9,0,T);c.fill();c.stroke()}
if(sw<.5)stick(),arms()
// high ponytail swinging
const pt=.25*sin(T*2*t)+(sw>.5?.6:0)
c.save();c.translate(78,52);c.rotate(-.5+pt*.4)
c.fillStyle=HAIR;c.lineWidth=5;c.beginPath();c.moveTo(0,0);c.bezierCurveTo(-30,4,-42,40,-30,70);c.quadraticCurveTo(-20,58,-14,64);c.bezierCurveTo(-18,40,-6,16,8,8);c.closePath();c.fill();c.stroke()
c.restore()
// head
const Z=.6;c.save();c.translate(96,66);c.scale(Z,Z);c.translate(-128,-40)
c.lineWidth=8;c.fillStyle=HD;c.beginPath();c.moveTo(128,36);c.bezierCurveTo(196,36,206,96,196,150);c.lineTo(60,150);c.bezierCurveTo(50,96,60,36,128,36);c.fill();c.stroke()
c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke()
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,164,14,7,0,0,T),c.fill()
c.lineWidth=5;c.fillStyle=MO;c.beginPath()
if(hit)c.moveTo(112,164),c.quadraticCurveTo(128,190,144,164),c.closePath(),c.fill(),c.stroke();else c.moveTo(114,170),c.quadraticCurveTo(122,164,128,170),c.quadraticCurveTo(134,176,142,168),c.stroke()
c.lineWidth=8;c.fillStyle=HAIR;c.beginPath();c.moveTo(66,140);c.bezierCurveTo(50,74,88,38,128,38);c.bezierCurveTo(168,38,206,74,190,140)
c.quadraticCurveTo(186,118,178,104);c.quadraticCurveTo(170,102,164,110);c.quadraticCurveTo(160,96,150,92);c.quadraticCurveTo(144,104,136,110)
c.quadraticCurveTo(132,96,122,90);c.quadraticCurveTo(116,104,106,108);c.quadraticCurveTo(102,96,92,96);c.quadraticCurveTo(86,106,80,112);c.quadraticCurveTo(70,124,66,140);c.closePath();c.fill();c.stroke()
c.strokeStyle=HL;c.lineWidth=6;for(const[a0,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,58,PI*a0,PI*e),c.stroke();c.strokeStyle='#111'
// blindfold with fluttering tails
c.fillStyle=BAND;c.lineWidth=8;c.beginPath();c.moveTo(66,116);c.quadraticCurveTo(128,104,192,116);c.lineTo(190,150);c.quadraticCurveTo(128,140,66,150);c.closePath();c.fill();c.stroke()
const fl=10*sin(T*4*t);c.beginPath();c.moveTo(66,128);c.quadraticCurveTo(40,120+fl,22,132+fl);c.lineTo(28,148+fl);c.quadraticCurveTo(44,140,66,140);c.fill();c.stroke()
c.beginPath();c.moveTo(64,134);c.quadraticCurveTo(44,150-fl,36,170-fl);c.lineTo(50,174-fl);c.quadraticCurveTo(56,152,68,142);c.fill();c.stroke()
c.restore()
if(sw>=.5)stick(),arms()
// sweat drop while she wobbles
if(t<.5){c.fillStyle='#a5d8ff';c.lineWidth=4;const y=58+10*((t*4)%1);c.beginPath();c.moveTo(136,y);c.quadraticCurveTo(144,y+12,136,y+18);c.quadraticCurveTo(128,y+12,136,y);c.fill();c.stroke()}
c.restore()
}
+63
View File
@@ -0,0 +1,63 @@
// surfer girl with a teal ponytail and a yellow rash guard rides along a curling wave, arms out for balance, spray flying off the tail
const{sin,cos,PI,max,min}=Math,T=2*PI
export const frames=12,delay=85
const SKIN='#ffe3d1',HAIR='#1098ad',HD='#0b7285',HL='#c5f6fa',EYE='#fd7e14',ED='#d9480f',RG='#fcc419',RD='#f08c00',SH='#ff6b6b',SHD='#e03131',BRD='#fff',BS='#20c997',HIB='#f06595',WA='#4dabf7',WD='#1c7ed6',WB='#1971c2',FO='#fff',BL='#ffa8a8'
const eye=(c,x,y,d)=>{
c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill()
c.save();c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.clip()
c.beginPath();c.ellipse(x+3,y+2,11.5,15,0,0,T);c.fillStyle=EYE;c.fill();c.save();c.clip();c.fillStyle=ED;c.beginPath();c.ellipse(x+3,y-8,13,10,0,0,T);c.fill();c.restore()
c.lineWidth=2.5;c.beginPath();c.ellipse(x+3,y+2,11.5,15,0,0,T);c.stroke()
c.fillStyle='#111';c.beginPath();c.ellipse(x+5,y+3,5.5,7.5,0,0,T);c.fill()
c.fillStyle='#fff';c.beginPath();c.arc(x,y-5,4.5,0,T);c.fill();c.beginPath();c.arc(x+9,y+8,2,0,T);c.fill();c.restore()
c.lineWidth=8;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke()
}
const line=(c,pts,w,col)=>{for(const[lw,s]of[[w+8,'#111'],[w,col]]){c.lineWidth=lw;c.strokeStyle=s;c.beginPath();pts.forEach(([x,y],k)=>k?c.lineTo(x,y):c.moveTo(x,y));c.stroke()}c.strokeStyle='#111'}
export default(c,t,i)=>{
const f=T*t,bx=150+5*sin(f),by=192+4*sin(2*f+.5),ba=.1+.05*sin(f+.8),lb=sin(f)
const B=(x,y)=>[bx+x*cos(ba)-y*sin(ba),by+x*sin(ba)+y*cos(ba)]
const face=()=>{c.beginPath();c.moveTo(16,238);c.lineTo(16,150);c.bezierCurveTo(18,90,24,46,58,34);c.bezierCurveTo(86,26,118,40,124,62);c.quadraticCurveTo(122,78,106,80);c.quadraticCurveTo(110,66,96,62);c.bezierCurveTo(80,60,72,96,84,132);c.bezierCurveTo(100,180,170,196,244,200);c.quadraticCurveTo(250,220,244,238);c.quadraticCurveTo(130,248,16,238);c.closePath()}
c.fillStyle=WA;c.lineWidth=6;face();c.fill();c.save();c.clip()
c.fillStyle=WB;c.beginPath();c.moveTo(96,62);c.bezierCurveTo(80,60,72,96,84,132);c.bezierCurveTo(60,120,40,90,54,58);c.quadraticCurveTo(74,44,96,62);c.fill()
c.fillStyle=WD;c.beginPath();c.moveTo(16,150);c.bezierCurveTo(30,180,50,200,66,256);c.lineTo(16,256);c.fill()
c.strokeStyle='#a5d8ff';c.lineWidth=4;for(let k=0;k<4;k++){const u=((k/4+t)%1),x=100+u*170,y=150+u*48;c.beginPath();c.moveTo(x-30,y-14);c.quadraticCurveTo(x-10,y-2,x+14,y+2);c.stroke()}
c.restore();c.strokeStyle='#111';c.lineWidth=6;face();c.stroke()
for(let k=0;k<7;k++){const a=k/6,x=60+60*a,y=34-10*sin(PI*a)+4*sin(f*2+k*1.3),r=9+3*sin(f*2+k);c.fillStyle=FO;c.lineWidth=4;c.beginPath();c.arc(x,y,r,0,T);c.fill();c.stroke()}
c.fillStyle=FO;c.lineWidth=4;c.beginPath();c.moveTo(124,62);c.quadraticCurveTo(132,78,118,86);c.quadraticCurveTo(116,74,106,80);c.quadraticCurveTo(122,78,124,62);c.fill();c.stroke()
for(let k=0;k<6;k++){const u=(t*2+k/6)%1,x=136-u*60+8*sin(k*2),y=86+u*u*90-30*sin(PI*u),r=4*(1-u)+2;c.fillStyle=FO;c.lineWidth=3.5;c.beginPath();c.arc(x,y,r,0,T);c.fill();c.stroke()}
const tail=B(-52,0)
for(let k=0;k<7;k++){const u=(t*2+k/7)%1,a=PI*1.1+.5*(k%3)/2,x=tail[0]+cos(a)*u*60,y=tail[1]-6+sin(a)*u*50+u*u*40,r=(1-u)*6+1.5;c.fillStyle=FO;c.lineWidth=3.5;c.beginPath();c.arc(x,y,r,0,T);c.fill();c.stroke()}
c.save();c.translate(bx,by);c.rotate(ba)
c.fillStyle=BRD;c.lineWidth=5;c.beginPath();c.moveTo(-60,-4);c.lineTo(44,-6);c.quadraticCurveTo(70,-4,74,4);c.quadraticCurveTo(66,10,44,8);c.lineTo(-60,6);c.quadraticCurveTo(-68,1,-60,-4);c.closePath();c.fill();c.stroke()
c.strokeStyle=BS;c.lineWidth=4;c.beginPath();c.moveTo(-54,1);c.lineTo(52,1);c.stroke();c.strokeStyle=SH;c.lineWidth=3;c.beginPath();c.moveTo(-50,-1);c.lineTo(-30,-1);c.stroke();c.strokeStyle='#111'
c.fillStyle=BS;c.lineWidth=4;c.beginPath();c.moveTo(-50,6);c.lineTo(-58,18);c.lineTo(-42,7);c.closePath();c.fill();c.stroke()
c.restore()
c.fillStyle=FO;c.lineWidth=4;for(let k=0;k<5;k++){const p=B(-50+k*26,8),r=5+3*sin(f*3+k*2);c.beginPath();c.arc(p[0],p[1]+2,r,PI,T);c.closePath();c.fill();c.stroke()}
const hip=[bx-4,by-40+lb*1.5],fb=B(-26,-6),ff=B(24,-6)
for(const[ft,kx]of[[fb,-20],[ff,18]]){const k=[(hip[0]+ft[0])/2+kx*.5,(hip[1]+ft[1])/2-2];line(c,[hip,k,ft],9,SKIN)}
for(const ft of[fb,ff]){c.save();c.translate(...ft);c.rotate(ba);c.fillStyle=SKIN;c.lineWidth=4;c.beginPath();c.ellipse(3,-2,10,5,0,0,T);c.fill();c.stroke();c.restore()}
c.fillStyle=SH;c.lineWidth=5;c.beginPath();c.moveTo(hip[0]-18,hip[1]-10);c.lineTo(hip[0]+18,hip[1]-10);c.lineTo(hip[0]+26,hip[1]+10);c.lineTo(hip[0]+4,hip[1]+12);c.lineTo(hip[0],hip[1]+4);c.lineTo(hip[0]-4,hip[1]+12);c.lineTo(hip[0]-26,hip[1]+10);c.closePath();c.fill();c.stroke()
c.strokeStyle=SHD;c.lineWidth=3;c.beginPath();c.moveTo(hip[0]+12,hip[1]-6);c.lineTo(hip[0]+18,hip[1]+8);c.stroke();c.fillStyle='#fff';c.beginPath();c.arc(hip[0]-12,hip[1]+2,3,0,T);c.fill();c.strokeStyle='#111'
const sx=bx-2,sy=hip[1]-36
for(const d of[-1,1]){const s=[sx+d*14,sy+4],w=d*lb*.5,e=[sx+d*34,sy+2-10*w],h=[sx+d*54,sy-4-22*w];line(c,[s,e,h],9,RG);c.fillStyle=SKIN;c.lineWidth=4;c.beginPath();c.arc(h[0]+d*2,h[1],6.5,0,T);c.fill();c.stroke();c.strokeStyle=RD;c.lineWidth=3;c.beginPath();c.moveTo(h[0]-d*5,h[1]-6);c.lineTo(h[0]-d*5,h[1]+6);c.stroke();c.strokeStyle='#111'}
c.fillStyle=SKIN;c.beginPath();c.rect(sx-6,sy-10,12,10);c.fill()
c.fillStyle=RG;c.lineWidth=5;c.beginPath();c.moveTo(sx-14,sy-6);c.lineTo(sx+14,sy-6);c.quadraticCurveTo(sx+22,sy+14,sx+18,hip[1]-6);c.lineTo(sx-18,hip[1]-6);c.quadraticCurveTo(sx-22,sy+14,sx-14,sy-6);c.closePath();c.fill();c.stroke()
c.fillStyle='#fff';c.beginPath();c.moveTo(sx-17,sy+12);c.lineTo(sx+17,sy+8);c.lineTo(sx+18,sy+16);c.lineTo(sx-18,sy+20);c.closePath();c.fill();c.stroke()
c.fillStyle=RD;c.lineWidth=4;c.beginPath();c.moveTo(sx-9,sy-6);c.quadraticCurveTo(sx,sy+2,sx+9,sy-6);c.quadraticCurveTo(sx,sy-11,sx-9,sy-6);c.fill();c.stroke()
c.save();c.translate(sx+2,sy-28+lb);c.rotate(.04*sin(f));c.scale(.5,.5);c.translate(-128,-128)
c.save();c.translate(70,104);c.rotate(1.2+.18*sin(f*2))
c.lineWidth=8;c.fillStyle=HAIR;c.beginPath();c.moveTo(0,-10);c.bezierCurveTo(40,-6,60,40,40,86);c.quadraticCurveTo(52,110,28,124);c.quadraticCurveTo(26,100,10,110);c.bezierCurveTo(22,70,8,30,-10,10);c.closePath();c.fill();c.stroke()
c.strokeStyle=HD;c.lineWidth=5;c.beginPath();c.moveTo(6,6);c.bezierCurveTo(30,26,36,58,28,90);c.stroke();c.strokeStyle='#111'
c.fillStyle=RD;c.lineWidth=7;c.beginPath();c.ellipse(0,0,10,14,0,0,T);c.fill();c.stroke();c.restore()
c.lineWidth=8;c.fillStyle=HAIR;c.beginPath();c.moveTo(126,36);c.bezierCurveTo(192,36,200,94,190,146);c.lineTo(64,146);c.bezierCurveTo(54,94,62,36,126,36);c.fill();c.stroke()
c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke()
if(i==9){c.lineWidth=7;for(const x of[107,157])c.beginPath(),c.moveTo(x-15,142),c.quadraticCurveTo(x,150,x+15,142),c.stroke()}else eye(c,107,140,-1),eye(c,157,140,1)
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(132+d*42,162,12,6,0,0,T),c.fill()
c.fillStyle='#c92a2a';c.lineWidth=5;c.beginPath();c.moveTo(118,164);c.quadraticCurveTo(132,186,146,164);c.closePath();c.fill();c.stroke()
c.lineWidth=8;c.fillStyle=HAIR;c.beginPath();c.moveTo(70,140)
c.bezierCurveTo(56,80,86,46,130,46);c.bezierCurveTo(176,46,200,84,186,140)
c.quadraticCurveTo(184,116,174,100);c.quadraticCurveTo(168,108,160,114);c.quadraticCurveTo(158,96,146,88);c.quadraticCurveTo(136,104,124,110)
c.quadraticCurveTo(122,96,114,90);c.quadraticCurveTo(102,104,94,112);c.quadraticCurveTo(92,100,86,96);c.quadraticCurveTo(76,112,70,140);c.closePath();c.fill();c.stroke()
c.strokeStyle=HL;c.lineWidth=8;for(const[a0,a1]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,56,PI*a0,PI*a1),c.stroke();c.strokeStyle='#111'
c.save();c.translate(178,80);c.fillStyle=HIB;c.lineWidth=6;for(let k=0;k<5;k++){const b=k*T/5-PI/2;c.beginPath();c.ellipse(13*cos(b),13*sin(b),11,8,b,0,T);c.fill();c.stroke()}c.fillStyle='#ffd43b';c.beginPath();c.arc(0,0,7,0,T);c.fill();c.stroke();c.restore()
c.restore()
}
+40
View File
@@ -0,0 +1,40 @@
// swimmer in a cobalt cap and goggles doing the front crawl, arms windmilling over the water, turning to breathe, splashes at each stroke
const{sin,cos,PI,max,min,hypot}=Math,T=2*PI
export const frames=16,delay=75
const SKIN='#ffe3d1',HAIR='#3b5bdb',CAP='#4263eb',CD='#364fc7',GOG='#ff922b',LENS='#c5f6fa',EYE='#7950f2',SUIT='#f06595',WA='#4dabf7',WD='#1c7ed6',WL='#a5d8ff',BL='#ffa8a8'
const line=(c,pts,w,col)=>{for(const[lw,s]of[[w+8,'#111'],[w,col]]){c.lineWidth=lw;c.strokeStyle=s;c.beginPath();pts.forEach(([x,y],k)=>k?c.lineTo(x,y):c.moveTo(x,y));c.stroke()}c.strokeStyle='#111'}
const WY=174
const surf=(x,t)=>WY+4*sin(x/256*T*3-T*t)
export default(c,t,i)=>{
const f=T*t,br=max(0,sin(f+.6)),bob=2*sin(2*f)
c.fillStyle=WA;c.lineWidth=6;c.beginPath();c.moveTo(10,surf(10,t)-10);for(let x=10;x<=246;x+=6)c.lineTo(x,surf(x,t)-10);c.lineTo(246,200);c.quadraticCurveTo(128,206,10,200);c.closePath();c.fill();c.stroke()
c.strokeStyle=WL;c.lineWidth=3;for(const[x0,y]of[[40,172],[180,178]]){c.beginPath();c.moveTo(x0,y);c.lineTo(x0+26,y);c.stroke()}c.strokeStyle='#111'
const G=()=>{c.translate(128,172);c.scale(1.35,1.35);c.translate(-128,-166)}
const sh=[[118,168+bob],[98,166+bob]],arm=(k)=>{const a=f+k*PI,s=sh[k],hx=s[0]+44*cos(a),hy=s[1]+40*sin(a)-4,ex=s[0]+24*cos(a),ey=s[1]+18*sin(a)-16*max(0,-sin(a));return[s,[ex,ey],[hx,hy],a]}
const draw=k=>{const[s,e,h]=arm(k);line(c,[s,e,h],10,SKIN);c.fillStyle=SKIN;c.lineWidth=5;c.beginPath();c.ellipse(h[0],h[1],8,7,0,0,T);c.fill();c.stroke()}
c.save();G()
draw(1)
c.fillStyle=SUIT;c.lineWidth=6;c.beginPath();c.ellipse(110,172+bob,34,13,-.08,PI,T);c.fill();c.stroke()
c.fillStyle=SKIN;c.beginPath();c.ellipse(110,166+bob,17,6,-.08,PI,T);c.fill();c.lineWidth=4;c.stroke()
c.save();c.translate(158,146+bob);c.rotate(-.15-.3*br);c.scale(.48,.48);c.translate(-128,-128)
c.lineWidth=10;c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke()
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,162,12,6,0,0,T),c.fill()
c.fillStyle='#c92a2a';c.lineWidth=7;c.beginPath();if(br>.5)c.ellipse(132,168,11,13*br,0,0,T),c.fill();else c.moveTo(118,168),c.quadraticCurveTo(128,174,138,168);c.stroke()
c.fillStyle=CAP;c.lineWidth=10;c.beginPath();c.moveTo(66,120);c.bezierCurveTo(52,30,204,30,190,120);c.quadraticCurveTo(128,100,66,120);c.closePath();c.fill();c.stroke()
c.strokeStyle=CD;c.lineWidth=6;c.beginPath();c.arc(128,96,52,PI*1.15,PI*1.5);c.stroke();c.strokeStyle='#fff';c.lineWidth=7;c.beginPath();c.arc(128,96,52,PI*1.58,PI*1.7);c.stroke();c.strokeStyle='#111'
c.fillStyle=HAIR;c.lineWidth=8;c.beginPath();c.moveTo(70,118);c.quadraticCurveTo(80,132,94,122);c.quadraticCurveTo(88,114,70,118);c.fill();c.stroke()
c.strokeStyle='#111';c.lineWidth=16;c.beginPath();c.moveTo(66,128);c.lineTo(190,128);c.stroke();c.strokeStyle=GOG;c.lineWidth=8;c.stroke();c.strokeStyle='#111'
for(const x of[103,153]){c.fillStyle=GOG;c.lineWidth=9;c.beginPath();c.ellipse(x,132,24,21,0,0,T);c.fill();c.stroke();c.fillStyle=LENS;c.lineWidth=5;c.beginPath();c.ellipse(x,132,16,14,0,0,T);c.fill();c.stroke()
if(br>.5&&i%8<3){c.lineWidth=7;c.beginPath();c.arc(x,138,9,PI*1.15,PI*1.85);c.stroke()}else{c.fillStyle=EYE;c.beginPath();c.ellipse(x+3,134,7,9,0,0,T);c.fill();c.fillStyle='#111';c.beginPath();c.ellipse(x+4,135,3.5,5,0,0,T);c.fill()}
c.fillStyle='#fff';c.beginPath();c.ellipse(x-7,126,5,4,-.5,0,T);c.fill()}
c.restore()
draw(0)
c.restore()
c.fillStyle=WA;c.lineWidth=6;c.beginPath();c.moveTo(4,surf(4,t)+6);for(let x=4;x<=252;x+=6)c.lineTo(x,surf(x,t)+6+3*sin(x/40+f));c.lineTo(252,236);c.quadraticCurveTo(128,248,4,236);c.closePath();c.fill();c.stroke()
c.save();c.clip();c.fillStyle=WD;c.globalAlpha=.35;c.beginPath();c.ellipse(118,206,70,14,0,0,T);c.fill();c.globalAlpha=1;c.restore()
c.strokeStyle='#fff';c.lineWidth=4;for(const[x,y,w]of[[30,196,22],[200,214,30],[96,226,26]]){c.beginPath();c.moveTo(x,y);c.quadraticCurveTo(x+w/2,y-5,x+w,y);c.stroke()}c.strokeStyle='#111'
c.save();G()
for(const k of[0,1]){const[,,h,a]=arm(k),m=((a%T)+T)%T,u=(m-PI*.02)/(PI*.6);if(u>0&&u<1){const s=sin(PI*u),x=sh[k][0]+42,y=WY-2;c.fillStyle='#fff';c.lineWidth=3.5;for(const[dx,dy,r]of[[-12,-14,4],[0,-22,5],[12,-12,4],[20,-20,3],[-20,-20,3]]){c.beginPath();c.arc(x+dx*s,y+dy*s,r*max(.4,s),0,T);c.fill();c.stroke()}}}
c.restore()
for(const[x,o]of[[222,0],[238,.5],[30,.25]]){const u=(t*2+o)%1,y=140-u*40,r=3+4*u;if(u<.85){c.fillStyle='#fff';c.lineWidth=3.5;c.beginPath();c.arc(x+4*sin(u*T),y,r,0,T);c.fill();c.stroke()}}
}
+59
View File
@@ -0,0 +1,59 @@
// festival girl in a happi coat and hachimaki pounding a big taiko drum with two bachi, sticks alternating, impact rings on the drumhead
const{sin,cos,PI,max,min,hypot}=Math,T=2*PI
export const frames=16,delay=70
const SKIN='#ffe3d1',HAIR='#c92a2a',HD='#8f1d1d',HL='#ffa8a8',EYE='#fd7e14',ED='#d9480f',HAPPI='#364fc7',HP='#fff',BAND='#fff',KNOT='#e03131',DRUM='#a9744f',DD='#7f5539',HEAD='#fff4e6',RIV='#ffd43b',BACHI='#e9c46a',BL='#ffa8a8',MO='#c92a2a',TOM=['#e03131','#ffd43b','#4dabf7']
const cl=x=>max(0,min(1,x)),ease=x=>x*x*(3-2*x)
const eye=(c,x,y,d)=>{
c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,16,0,0,T);c.fill()
c.save();c.beginPath();c.ellipse(x,y+2,11.5,14,0,0,T);c.clip();c.fillStyle=EYE;c.fill();c.fillStyle=ED;c.beginPath();c.ellipse(x,y-8,13,10,0,0,T);c.fill();c.restore()
c.lineWidth=3;c.beginPath();c.ellipse(x,y+2,11.5,14,0,0,T);c.stroke()
c.fillStyle='#111';c.beginPath();c.ellipse(x,y+3,5.5,7.5,0,0,T);c.fill()
c.fillStyle='#fff';c.beginPath();c.arc(x-4,y-5,4.5,0,T);c.fill();c.beginPath();c.arc(x+5,y+8,2,0,T);c.fill()
c.lineWidth=8;c.beginPath();c.moveTo(x-16,y-4);c.quadraticCurveTo(x,y-14,x+16,y-6);c.moveTo(x+d*15,y-6);c.lineTo(x+d*21,y-11);c.stroke()
c.lineWidth=7;c.beginPath();c.moveTo(x-d*16,y-28);c.lineTo(x+d*14,y-20);c.stroke()
}
export default(c,t)=>{
const ph=d=>(2*t+(d>0?.5:0))%1,up=p=>p<.12?0:p<.55?ease((p-.12)/.43):p<.85?1:1-ease((p-.85)/.15),hit=d=>ph(d)<.14,anyhit=hit(-1)||hit(1)
const hand=d=>{const u=up(ph(d)),R=[128+d*82,96],D=[128+d*44,152];return[D[0]+(R[0]-D[0])*u,D[1]+(R[1]-D[1])*u,u]}
c.save();c.translate(128,6);c.scale(.78,.78);c.translate(-128,0)
// bun and back hair
c.lineWidth=8;c.fillStyle=HAIR;c.beginPath();c.arc(128,30,26,0,T);c.fill();c.stroke()
c.fillStyle=HD;c.beginPath();c.moveTo(128,40);c.bezierCurveTo(196,40,206,100,196,150);c.lineTo(60,150);c.bezierCurveTo(50,100,60,40,128,40);c.fill();c.stroke()
// happi coat
c.fillStyle=HAPPI;c.beginPath();c.moveTo(100,188);c.quadraticCurveTo(48,196,36,262);c.lineTo(220,262);c.quadraticCurveTo(208,196,156,188);c.closePath();c.fill();c.stroke()
c.strokeStyle=HP;c.lineWidth=6;for(let y=208;y<262;y+=18)c.beginPath(),c.moveTo(48,y),c.lineTo(60,y+6),c.moveTo(208,y),c.lineTo(196,y+6),c.stroke();c.strokeStyle='#111'
c.fillStyle=HP;c.lineWidth=7;for(const d of[-1,1])c.beginPath(),c.moveTo(128+d*24,186),c.lineTo(128+d*4,262),c.lineTo(128+d*18,262),c.lineTo(128+d*36,190),c.closePath(),c.fill(),c.stroke()
c.fillStyle=SKIN;c.beginPath();c.moveTo(116,168);c.lineTo(116,190);c.lineTo(128,214);c.lineTo(140,190);c.lineTo(140,168);c.fill();c.lineWidth=6;c.beginPath();c.moveTo(116,168);c.lineTo(116,188);c.moveTo(140,168);c.lineTo(140,188);c.stroke()
// face
c.lineWidth=7;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke()
eye(c,103,140,-1);eye(c,153,140,1)
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,162,13,6,0,0,T),c.fill()
c.lineWidth=5;c.fillStyle=MO;c.beginPath()
if(anyhit)c.moveTo(112,162),c.quadraticCurveTo(128,190,144,162),c.closePath(),c.fill(),c.stroke();else c.moveTo(116,168),c.lineTo(140,168),c.stroke()
// bangs
c.lineWidth=7;c.fillStyle=HAIR;c.beginPath();c.moveTo(66,140);c.bezierCurveTo(50,74,88,40,128,40);c.bezierCurveTo(168,40,206,74,190,140)
c.quadraticCurveTo(186,118,178,104);c.quadraticCurveTo(170,102,164,110);c.quadraticCurveTo(160,96,150,92);c.quadraticCurveTo(144,104,136,110)
c.quadraticCurveTo(132,96,122,90);c.quadraticCurveTo(116,104,106,108);c.quadraticCurveTo(102,96,92,96);c.quadraticCurveTo(86,106,80,112);c.quadraticCurveTo(70,124,66,140);c.closePath();c.fill();c.stroke()
c.strokeStyle=HL;c.lineWidth=6;for(const[a,e]of[[1.24,1.36],[1.62,1.74]])c.beginPath(),c.arc(128,104,58,PI*a,PI*e),c.stroke();c.strokeStyle='#111'
// hachimaki with fluttering knot
c.fillStyle=BAND;c.lineWidth=7;c.beginPath();c.moveTo(64,76);c.quadraticCurveTo(128,58,192,76);c.lineTo(194,92);c.quadraticCurveTo(128,74,62,92);c.closePath();c.fill();c.stroke()
c.fillStyle=KNOT;c.beginPath();c.arc(128,70,9,0,T);c.fill();c.stroke()
const fl=8*sin(4*T*t);c.fillStyle=BAND;for(const[dy,k]of[[0,1],[12,-1]])c.beginPath(),c.moveTo(192,80+dy*.5),c.quadraticCurveTo(212,70+dy+fl*k,232,78+dy+fl*k),c.lineTo(228,90+dy+fl*k),c.quadraticCurveTo(212,84+dy,194,90+dy*.5),c.closePath(),c.fill(),c.stroke()
c.restore()
// drum
c.lineWidth=6;c.fillStyle=DRUM;c.beginPath();c.moveTo(42,176);c.quadraticCurveTo(34,214,46,250);c.lineTo(210,250);c.quadraticCurveTo(222,214,214,176);c.closePath();c.fill();c.stroke()
c.strokeStyle=DD;c.lineWidth=4;for(const x of[78,104,152,178])c.beginPath(),c.moveTo(x,186),c.lineTo(x+(x-128)*.06,248),c.stroke();c.strokeStyle='#111'
c.save();c.translate(128,220);c.lineWidth=4;for(let k=0;k<3;k++){c.save();c.rotate(k*T/3);c.fillStyle=TOM[k];c.beginPath();c.arc(0,-8,9,0,T);c.moveTo(9,-8);c.quadraticCurveTo(14,8,-6,14);c.quadraticCurveTo(4,4,0,1);c.fill();c.stroke();c.restore()}c.restore()
c.fillStyle=RIV;c.lineWidth=3;for(let k=0;k<9;k++){const x=50+k*19.5;c.beginPath();c.arc(x,190+((x-128)/80)**2*-6+6,3.5,0,T);c.fill();c.stroke()}
const flex=anyhit?3:0
c.fillStyle=HEAD;c.lineWidth=6;c.beginPath();c.ellipse(128,174,88,22-flex,0,0,T);c.fill();c.stroke()
// impact rings and burst lines
for(const d of[-1,1])if(hit(d)){const p=ph(d)/.14,x=128+d*22;c.strokeStyle=d<0?'#ff8787':'#74c0fc';c.lineWidth=4;for(const k of[0,.5]){const r=cl(p*1.2-k);if(r>0)c.beginPath(),c.ellipse(x,180,14+26*r,4+6*r,0,0,T),c.stroke()}
c.strokeStyle='#111';c.lineWidth=5;for(const a of[-2.4,-1.9,-1.2])c.beginPath(),c.moveTo(x+d*20+30*cos(a),196+30*sin(a)*.6),c.lineTo(x+d*20+44*cos(a),196+44*sin(a)*.6),c.stroke()}
// arms and bachi
for(const d of[-1,1]){const[hx,hy,u]=hand(d),sx=128+d*50,sy=158,th=PI/2+d*.6+(-PI+d*-.1)*u,bx=hx+44*cos(th),by=hy+44*sin(th),ux=cos(th),uy=sin(th)
for(const[l,s]of[[22,'#111'],[13,SKIN]])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),c.moveTo(sx,sy),c.quadraticCurveTo(sx+d*18,(sy+hy)/2,hx,hy),c.stroke()
for(const[l,s]of[[12,'#111'],[5,BACHI]])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),c.moveTo(hx-ux*8,hy-uy*8),c.lineTo(bx,by),c.stroke()
c.strokeStyle='#111';c.lineWidth=5;c.fillStyle=SKIN;c.beginPath();c.arc(hx,hy,10,0,T);c.fill();c.stroke()
if(u>.6){c.lineWidth=4;c.beginPath();c.arc(hx,hy,22,d<0?PI*.9:-PI*.1,d<0?PI*1.3:PI*.1+.2);c.stroke()}}
}
+54
View File
@@ -0,0 +1,54 @@
// tanuki girl with silver-blue hair, round ears and a ringed tail wagging, then the leaf on her head spins and she vanishes in a puff of smoke and pops back
const{sin,cos,PI,max,min,round}=Math,T=2*PI
export const frames=16,delay=80
const SKIN='#ffe3d1',HAIR='#a5b4cb',HD='#748ba8',HL='#e7ecf5',DK='#5c677d',EYE='#a9744f',ED='#6b4226',TOP='#ffa94d',TD='#e8590c',OBI='#38d9a9',LF='#51cf66',LD='#2f9e44',BL='#ffa8a8',SM='#f1f3f5'
const eye=(c,x,y,d)=>{
c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill()
c.save();c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.clip();c.fillStyle=EYE;c.fill();c.fillStyle=ED;c.beginPath();c.ellipse(x,y-8,13,10,0,0,T);c.fill();c.restore()
c.lineWidth=3;c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.stroke()
c.fillStyle='#111';c.beginPath();c.ellipse(x,y+3,5.5,7.5,0,0,T);c.fill()
c.fillStyle='#fff';c.beginPath();c.arc(x-4,y-5,4.5,0,T);c.fill();c.beginPath();c.arc(x+5,y+8,2,0,T);c.fill()
c.lineWidth=8;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke()
}
const line=(c,pts,w,col)=>{for(const[lw,s]of[[w+8,'#111'],[w,col]]){c.lineWidth=lw;c.strokeStyle=s;c.beginPath();pts.forEach(([x,y],k)=>k?c.lineTo(x,y):c.moveTo(x,y));c.stroke()}c.strokeStyle='#111'}
const leaf=(c,x,y,a,s)=>{c.save();c.translate(x,y);c.rotate(a);c.scale(s,1)
c.fillStyle=LF;c.lineWidth=5;c.beginPath();c.moveTo(0,16);c.bezierCurveTo(-22,4,-18,-18,0,-26);c.bezierCurveTo(18,-18,22,4,0,16);c.fill();c.stroke()
c.strokeStyle=LD;c.lineWidth=3;c.beginPath();c.moveTo(0,20);c.lineTo(0,-20);c.moveTo(0,0);c.lineTo(-9,-8);c.moveTo(0,0);c.lineTo(9,-8);c.stroke();c.strokeStyle='#111';c.restore()}
const cloud=(c,cx,cy,r,a)=>{
const P=[[0,0,1]];for(let k=0;k<8;k++){const b=k*T/8+a;P.push([cos(b)*.7,sin(b)*.62,.48+.08*(k%2)])}
for(const[lw,col]of[[12,'#111'],[0,SM]])for(const[x,y,s]of P){c.beginPath();c.arc(cx+x*r,cy+y*r,s*r*.7,0,T);if(lw)c.lineWidth=lw,c.strokeStyle=col,c.stroke();else c.fillStyle=col,c.fill()}
c.strokeStyle='#ced4da';c.lineWidth=4;for(let k=0;k<3;k++){const b=k*T/3+a*2;c.beginPath();c.arc(cx+cos(b)*r*.3,cy+sin(b)*r*.25,r*.16,b,b+PI*1.2);c.stroke()}c.strokeStyle='#111'
}
export default(c,t,i)=>{
const r=[0,0,0,0,0,0,0,.55,1,1,1,1,.7,.35,0,0][i],hide=i>=8&&i<12
const tada=i>=12||i==0,wag=.25*sin(2*T*t),la=i==6||i==7?(i-5)*1.6:0
if(!hide){
c.save();c.translate(160,192);c.rotate(.4+wag)
const tp=()=>{c.beginPath();c.moveTo(-12,0);c.bezierCurveTo(-44,-30,-34,-96,10,-98);c.bezierCurveTo(52,-96,56,-34,20,2);c.closePath()}
c.fillStyle=HAIR;c.lineWidth=6;tp();c.fill();c.save();tp();c.clip();c.fillStyle=DK;for(const y of[-30,-62])c.beginPath(),c.ellipse(8,y,40,8,-.06,0,T),c.fill();c.beginPath();c.ellipse(10,-98,34,16,0,0,T);c.fill();c.restore();tp();c.stroke();c.restore()
for(const x of[118,138]){line(c,[[x,198],[x,220]],8,SKIN);c.lineWidth=5;c.fillStyle=DK;c.beginPath();c.ellipse(x+(x<128?-3:3),224,11,7,0,0,T);c.fill();c.lineWidth=10;c.strokeStyle='#fff';c.stroke();c.lineWidth=5;c.strokeStyle='#111';c.stroke()}
c.fillStyle=TOP;c.lineWidth=5;c.beginPath();c.moveTo(110,136);c.lineTo(146,136);c.quadraticCurveTo(160,170,162,204);c.lineTo(94,204);c.quadraticCurveTo(96,170,110,136);c.closePath();c.fill();c.stroke()
c.fillStyle='#fff';c.beginPath();c.moveTo(114,136);c.lineTo(128,156);c.lineTo(142,136);c.closePath();c.fill();c.stroke()
c.fillStyle=OBI;c.beginPath();c.rect(102,164,52,14);c.fill();c.stroke()
c.strokeStyle=TD;c.lineWidth=3;c.beginPath();c.moveTo(108,186);c.lineTo(104,200);c.moveTo(148,186);c.lineTo(152,200);c.stroke();c.strokeStyle='#111'
for(const d of[-1,1]){line(c,[[128+d*16,140],[128+d*30,160],[128+d*22,176]],8,TOP);c.lineWidth=4;c.fillStyle=SKIN;c.beginPath();c.arc(128+d*20,176,6,0,T);c.fill();c.stroke()}
c.save();c.translate(128,92);c.scale(.6,.6);c.translate(-128,-128)
c.lineWidth=9;c.fillStyle=HAIR;for(const d of[-1,1]){c.beginPath();c.arc(128+d*58,50,24,0,T);c.fill();c.stroke();c.fillStyle=DK;c.beginPath();c.arc(128+d*58,52,12,0,T);c.fill();c.fillStyle=HAIR}
c.fillStyle=HD;c.beginPath();c.moveTo(128,40);c.bezierCurveTo(200,40,212,100,202,160);c.quadraticCurveTo(190,174,176,166);c.lineTo(80,166);c.quadraticCurveTo(66,174,54,160);c.bezierCurveTo(44,100,56,40,128,40);c.fill();c.stroke()
c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke()
if(tada||i==3){c.lineWidth=8;for(const x of[103,153])c.beginPath(),c.moveTo(x-15,144),c.quadraticCurveTo(x,128,x+15,144),c.stroke()}else eye(c,103,140,-1),eye(c,153,140,1)
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*42,163,13,7,0,0,T),c.fill()
c.lineWidth=6;if(tada){c.fillStyle='#c92a2a';c.beginPath();c.moveTo(114,164);c.quadraticCurveTo(128,184,142,164);c.closePath();c.fill();c.stroke()}else{c.beginPath();c.moveTo(116,166);c.quadraticCurveTo(122,172,128,166);c.quadraticCurveTo(134,172,140,166);c.stroke()}
c.lineWidth=9;c.fillStyle=HAIR;c.beginPath();c.moveTo(66,146)
c.bezierCurveTo(54,72,90,40,128,40);c.bezierCurveTo(166,40,202,72,190,146)
c.quadraticCurveTo(186,114,176,102);c.quadraticCurveTo(168,106,162,114);c.quadraticCurveTo(156,98,146,92);c.quadraticCurveTo(140,106,130,112)
c.quadraticCurveTo(124,98,114,92);c.quadraticCurveTo(108,106,98,112);c.quadraticCurveTo(94,100,86,100);c.quadraticCurveTo(80,110,78,116)
c.quadraticCurveTo(70,116,66,146);c.closePath();c.fill();c.stroke()
c.strokeStyle=HL;c.lineWidth=7;for(const[a,e]of[[1.26,1.38],[1.46,1.54],[1.62,1.72]])c.beginPath(),c.arc(128,104,56,PI*a,PI*e),c.stroke();c.strokeStyle='#111'
c.restore()
}
if(r>0)cloud(c,128,138,94*r,t*T)
const ly=hide?84-6*sin(T*t*4):42,ls=hide||la?cos(T*t*4+la):1
leaf(c,128,ly,hide?.3*sin(T*t*2):-.2,max(.15,Math.abs(ls)))
if(tada&&!r){const k=i?i-14:2;c.lineWidth=5;for(const a of[-2.4,-1.6,-.8])c.beginPath(),c.moveTo(128+cos(a)*(60+k*10),110+sin(a)*(60+k*10)),c.lineTo(128+cos(a)*(74+k*10),110+sin(a)*(74+k*10)),c.stroke()}
}
+74
View File
@@ -0,0 +1,74 @@
// girl with a sunflower ponytail and visor tosses the ball up, swings the racket over her head and serves it streaking away
const{sin,cos,PI,max,min}=Math,T=2*PI
export const frames=20,delay=70
const SKIN='#ffe3d1',HAIR='#fcc419',HD='#f08c00',HL='#fff3bf',EYE='#20c997',ED='#087f5b',VIS='#51cf66',VD='#2f9e44',RQ='#ff6b6b',BAND='#ffd43b',BALL='#d8f5a2',BL='#ffa8a8'
const eye=(c,x,y,d,ly)=>{
c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill()
c.save();c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.clip();const Y=y+ly
c.beginPath();c.ellipse(x,Y+2,11.5,15,0,0,T);c.fillStyle=EYE;c.fill();c.save();c.clip();c.fillStyle=ED;c.beginPath();c.ellipse(x,Y-8,13,10,0,0,T);c.fill();c.restore()
c.lineWidth=2.5;c.beginPath();c.ellipse(x,Y+2,11.5,15,0,0,T);c.stroke()
c.fillStyle='#111';c.beginPath();c.ellipse(x,Y+3,5.5,7.5,0,0,T);c.fill()
c.fillStyle='#fff';c.beginPath();c.arc(x-4,Y-5,4.5,0,T);c.fill();c.beginPath();c.arc(x+5,Y+8,2,0,T);c.fill();c.restore()
c.lineWidth=8;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke()
}
const line=(c,pts,w,col)=>{for(const[lw,s]of[[w+8,'#111'],[w,col]]){c.lineWidth=lw;c.strokeStyle=s;c.beginPath();pts.forEach(([x,y],k)=>k?c.lineTo(x,y):c.moveTo(x,y));c.stroke()}c.strokeStyle='#111'}
const ss=u=>u*u*(3-2*u)
const key=(K,t)=>{let k=0;while(k<K.length-2&&t>=K[k+1][0])k++;const[t0,...a]=K[k],[t1,...b]=K[k+1],u=ss(min(1,max(0,(t-t0)/(t1-t0))));return a.map((v,j)=>v+(b[j]-v)*u)}
const RK=[[0,168,172,1.3],[.12,168,172,1.3],[.32,152,104,1.95],[.44,150,84,3.6],[.5,150,72,4.55],[.6,176,128,6.6],[.8,168,172,7.58],[1,168,172,7.58]]
const TK=[[0,92,170],[.1,92,170],[.24,100,70],[.5,102,76],[.62,116,150],[.8,92,170],[1,92,170]]
const ball=(c,x,y,r)=>{c.fillStyle=BALL;c.lineWidth=4;c.beginPath();c.arc(x,y,r,0,T);c.fill();c.stroke();c.strokeStyle='#fff';c.lineWidth=2.5;c.beginPath();c.arc(x-r*.9,y,r*.8,-.9,.9);c.stroke();c.strokeStyle='#111'}
export default(c,t,i)=>{
const oy=t>.28&&t<.5?6*sin(PI*(t-.28)/.22*.5):t>=.5&&t<.66?-5*sin(PI*(t-.5)/.16):0
const[rx,ry,ra]=key(RK,t),[tx,ty]=key(TK,t),behind=t>.22&&t<.47,look=t>.12&&t<.52?-5:0
const racket=()=>{
c.save();c.translate(rx,ry);c.rotate(ra)
line(c,[[0,0],[24,0]],6,'#fff');c.strokeStyle=RQ;c.lineWidth=6;c.beginPath();c.moveTo(-4,0);c.lineTo(12,0);c.stroke();c.strokeStyle='#111'
c.lineWidth=5;c.beginPath();c.moveTo(22,0);c.lineTo(30,-7);c.moveTo(22,0);c.lineTo(30,7);c.stroke()
c.fillStyle='#fff';c.beginPath();c.ellipse(48,0,20,15,0,0,T);c.fill();c.save();c.clip();c.strokeStyle='#adb5bd';c.lineWidth=1.5;for(let k=-20;k<=20;k+=6)c.beginPath(),c.moveTo(28,k),c.lineTo(68,k),c.moveTo(48+k,-16),c.lineTo(48+k,16),c.stroke();c.restore()
c.strokeStyle='#111';c.lineWidth=10;c.beginPath();c.ellipse(48,0,20,15,0,0,T);c.stroke();c.strokeStyle=RQ;c.lineWidth=5;c.stroke();c.strokeStyle='#111'
c.restore()
}
c.fillStyle='#dee2e6';c.beginPath();c.ellipse(120,234,48,6,0,0,T);c.fill()
const head=g=>{c.save();c.translate(116,90+oy);c.rotate(t>.1&&t<.52?-.07:0);c.scale(.56,.56);c.translate(-128,-120);g();c.restore()}
head(()=>{
c.save();c.translate(178,36);c.rotate(-.15+.22*sin(T*t-1.2)+(t>.48&&t<.7?.25:0))
c.lineWidth=9;c.fillStyle=HAIR;c.beginPath();c.moveTo(-8,0);c.bezierCurveTo(56,-14,92,50,80,124);c.quadraticCurveTo(72,140,58,146);c.quadraticCurveTo(66,96,4,30);c.closePath();c.fill();c.stroke()
c.strokeStyle=HD;c.lineWidth=5;c.beginPath();c.moveTo(14,8);c.bezierCurveTo(50,22,68,66,66,116);c.stroke();c.strokeStyle='#111'
c.fillStyle=VIS;c.lineWidth=7;c.beginPath();c.arc(0,4,11,0,T);c.fill();c.stroke();c.restore()
c.lineWidth=9;c.fillStyle=HAIR;c.beginPath();c.moveTo(128,36);c.bezierCurveTo(208,36,216,100,206,158);c.lineTo(50,158);c.bezierCurveTo(40,100,48,36,128,36);c.fill();c.stroke();c.strokeStyle=HD;c.lineWidth=5;for(const d of[-1,1])c.beginPath(),c.moveTo(128+d*70,100),c.quadraticCurveTo(128+d*74,130,128+d*70,150),c.stroke();c.strokeStyle='#111'
})
if(behind)racket()
const lg=[[110,-1],[128,1]]
for(const[x,d]of lg){const fx=x+d*8,kx=x+d*(2+oy*.6);line(c,[[x,186+oy],[kx,206+oy*.5],[fx,222]],8,SKIN);line(c,[[fx,214],[fx,222]],8,'#fff')}
for(const[x,d]of lg){const fx=x+d*8;c.fillStyle='#fff';c.lineWidth=5;c.beginPath();c.ellipse(fx+d*4,228,12,7,0,0,T);c.fill();c.stroke();c.strokeStyle=VIS;c.lineWidth=3;c.beginPath();c.moveTo(fx+d*4-6,228);c.quadraticCurveTo(fx+d*4,224,fx+d*4+7,227);c.stroke();c.strokeStyle='#111'}
c.fillStyle='#fff';c.lineWidth=5;c.beginPath();c.moveTo(102,164+oy);c.lineTo(134,164+oy);c.lineTo(148,194+oy);c.lineTo(88,194+oy);c.closePath();c.fill();c.stroke()
c.lineWidth=3;for(const x of[104,118,132])c.beginPath(),c.moveTo(118+(x-118)*.6,168+oy),c.lineTo(x,192+oy),c.stroke()
c.strokeStyle=VIS;c.lineWidth=4;c.beginPath();c.moveTo(91,188+oy);c.lineTo(145,188+oy);c.stroke();c.strokeStyle='#111'
const sl=[104,138+oy],sr=[132,138+oy]
line(c,[sl,[(sl[0]+tx)/2-8,(sl[1]+ty)/2],[tx,ty]],8,SKIN)
c.fillStyle=SKIN;c.beginPath();c.rect(110,124+oy,12,10);c.fill()
c.fillStyle='#fff';c.lineWidth=5;c.beginPath();c.moveTo(104,130+oy);c.lineTo(128,130+oy);c.lineTo(136,140+oy);c.lineTo(134,168+oy);c.lineTo(100,168+oy);c.lineTo(98,140+oy);c.closePath();c.fill();c.stroke()
c.strokeStyle=VIS;c.lineWidth=4;c.beginPath();c.moveTo(108,131+oy);c.lineTo(116,142+oy);c.lineTo(124,131+oy);c.stroke();c.strokeStyle='#111'
c.fillStyle=SKIN;c.lineWidth=4;c.beginPath();c.arc(tx,ty,6.5,0,T);c.fill();c.stroke()
head(()=>{
c.lineWidth=9;c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke()
if(t>.48&&t<.54){c.lineWidth=8;for(const[x,d]of[[103,1],[153,-1]])c.beginPath(),c.moveTo(x-12*d,128),c.lineTo(x+10*d,140),c.lineTo(x-12*d,152),c.stroke()}else eye(c,103,140,-1,look),eye(c,153,140,1,look)
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*42,162,12,6,0,0,T),c.fill()
c.fillStyle='#c92a2a';c.lineWidth=6;c.beginPath()
if(t>.46&&t<.6)c.ellipse(128,168,8,10,0,0,T),c.fill();else if(t>.6||t<.1)c.moveTo(116,164),c.quadraticCurveTo(128,182,140,164),c.closePath(),c.fill();else c.moveTo(120,168),c.lineTo(136,168)
c.stroke()
c.fillStyle=HAIR;c.lineWidth=9;c.beginPath();c.moveTo(68,150);c.bezierCurveTo(52,74,88,40,128,40);c.bezierCurveTo(168,40,204,74,188,150)
c.quadraticCurveTo(184,128,176,114);c.quadraticCurveTo(168,112,162,122);c.quadraticCurveTo(156,108,146,106);c.quadraticCurveTo(140,116,132,122)
c.quadraticCurveTo(126,108,118,106);c.quadraticCurveTo(112,116,104,122);c.quadraticCurveTo(98,108,90,110);c.quadraticCurveTo(84,116,80,122);c.quadraticCurveTo(70,130,68,150);c.closePath();c.fill();c.stroke()
c.fillStyle='#fff';c.lineWidth=8;c.beginPath();c.moveTo(66,84);c.quadraticCurveTo(128,58,190,84);c.lineTo(190,98);c.quadraticCurveTo(128,72,66,98);c.closePath();c.fill();c.stroke()
c.fillStyle=VIS;c.beginPath();c.moveTo(62,96);c.quadraticCurveTo(128,66,194,96);c.quadraticCurveTo(204,110,186,110);c.quadraticCurveTo(128,90,70,110);c.quadraticCurveTo(52,110,62,96);c.closePath();c.fill();c.stroke()
c.strokeStyle=VD;c.lineWidth=5;c.beginPath();c.moveTo(80,102);c.quadraticCurveTo(128,86,176,102);c.stroke();c.strokeStyle='#111'
})
line(c,[sr,[(sr[0]+rx)/2+10,(sr[1]+ry)/2+(ry<120?10:0)],[rx,ry]],8,SKIN)
if(!behind)racket()
c.fillStyle=BAND;c.lineWidth=4;c.beginPath();c.arc(rx,ry,7,0,T);c.fill();c.stroke()
if(t<.2||t>=.84){const s=t>=.84?min(1,(t-.84)/.06):1;ball(c,tx+2,ty-9,8*s)}
else if(t<.5){const u=(t-.2)/.3,x=101+(138-101)*u,y=62-(62-26)*(1-(1-u)**2)*1.1+(u>.85?(u-.85)*30:0);ball(c,x,y,8)}
else if(t<.62){const u=(t-.5)/.12,x=140+u*150,y=28+u*30;c.strokeStyle='#fff';for(const k of[-6,0,6]){line(c,[[x-60,y+k*.9-10*.2],[x-14,y+k]],2,'#fff')}ball(c,x,y,8)
if(t<.56){c.fillStyle='#fff3bf';c.lineWidth=4;c.beginPath();for(let k=0;k<16;k++){const r=k%2?8:20,b=k*PI/8;c.lineTo(140+r*cos(b),30+r*sin(b))}c.closePath();c.fill();c.stroke()}}
}
+71
View File
@@ -0,0 +1,71 @@
// girl praying under the teru teru bozu she hung in the window: the rain stops, clouds roll away, the sun comes out and she cheers, then the clouds return
const{sin,cos,PI,max,min,round}=Math,T=2*PI
export const frames=16,delay=90
const SKIN='#ffe3d1',HAIR='#69db7c',HD='#2f9e44',HL='#d3f9d8',EYE='#5c7cfa',ED='#364fc7',SHIRT='#fff',STR='#74c0fc',WOOD='#c08a5e',WD='#8d6346',RAIN=[159,179,200],SUN=[116,192,252],CLOUD='#dee2e6',CD='#adb5bd',SUNC='#ffd43b',DOLL='#fff',TIE='#fa5252',CLIP='#ffd43b',BL='#ffa8a8',MO='#c92a2a'
const cl=x=>max(0,min(1,x)),ease=x=>x*x*(3-2*x)
const mix=(a,b,k)=>`rgb(${a.map((v,i)=>round(v+(b[i]-v)*k)).join()})`
const eye=(c,x,y,d)=>{
c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill()
c.save();c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.clip();c.fillStyle=EYE;c.fill();c.fillStyle=ED;c.beginPath();c.ellipse(x,y-8,13,10,0,0,T);c.fill()
c.fillStyle='#111';c.beginPath();c.ellipse(x,y+3,5.5,7.5,0,0,T);c.fill()
c.fillStyle='#fff';c.beginPath();c.arc(x-4,y-5,4.5,0,T);c.fill();c.beginPath();c.arc(x+5,y+8,2,0,T);c.fill();c.restore()
c.lineWidth=3.5;c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.stroke()
c.lineWidth=8;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke()
}
// clouds use the union-outline trick: stroke every puff wide, then fill them all over the inner lines
const cloud=(c,x,y,s,f)=>{c.fillStyle=f;c.lineWidth=10;c.beginPath();for(const[dx,dy,r]of[[-22,4,16],[0,-6,22],[24,4,15]])c.moveTo(x+(dx+r)*s,y+dy*s),c.arc(x+dx*s,y+dy*s,r*s,0,T);c.stroke();c.fill()}
export default(c,t)=>{
const w=t<.85?ease(cl((t-.38)/.16)):1-ease(cl((t-.85)/.15)),sunny=w>.6,X0=40,Y0=12,X1=232,Y1=198
// window: sky panes behind the frame
c.lineWidth=7;c.fillStyle=mix(RAIN,SUN,w);c.beginPath();c.rect(X0+10,Y0+10,X1-X0-20,Y1-Y0-20);c.fill()
c.save();c.beginPath();c.rect(X0+10,Y0+10,X1-X0-20,Y1-Y0-20);c.clip()
if(w>.05){const s=w,rot=T*t;c.save();c.translate(92,62+30*(1-w));c.scale(s,s);c.strokeStyle='#111';c.lineWidth=7
for(let k=0;k<8;k++){const a=rot/4+k*PI/4;c.beginPath();c.moveTo(30*cos(a),30*sin(a));c.lineTo(44*cos(a),44*sin(a));c.stroke()}
c.strokeStyle=SUNC;c.lineWidth=3;for(let k=0;k<8;k++){const a=rot/4+k*PI/4;c.beginPath();c.moveTo(30*cos(a),30*sin(a));c.lineTo(44*cos(a),44*sin(a));c.stroke()}
c.strokeStyle='#111';c.fillStyle=SUNC;c.lineWidth=6;c.beginPath();c.arc(0,0,22,0,T);c.fill();c.stroke();c.restore()}
if(w<.5){c.globalAlpha=1-2*w;for(const[x,o]of[[70,0],[110,.4],[150,.7],[190,.2],[210,.55],[130,.9]]){const y=((t*3+o)%1)*200;for(const[l,s]of[[6,'#5c7cfa'],[2.5,'#fff']])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),c.moveTo(x-y*.15,Y0+y),c.lineTo(x-y*.15-4,Y0+y+18),c.stroke()}c.globalAlpha=1;c.strokeStyle='#111'}
const cx=t<.85?w*170:-170*w;cloud(c,92+cx,36,1.1,w<.5?CD:CLOUD);cloud(c,170+cx,48,1,w<.5?CD:CLOUD);cloud(c,128+cx*1.2,24,.8,w<.5?CD:CLOUD)
c.restore()
// frame and cross bars
c.lineWidth=6;c.fillStyle=WOOD
c.beginPath();c.rect(X0,Y0,X1-X0,Y1-Y0);c.rect(X0+10,Y1-10,X1-X0-20,-(Y1-Y0-20));c.fill('evenodd');c.stroke()
c.beginPath();c.rect(X0+10,Y0+10,X1-X0-20,Y1-Y0-20);c.stroke()
c.beginPath();c.rect(131,Y0+10,10,Y1-Y0-20);c.fill();c.stroke();c.beginPath();c.rect(X0+10,100,X1-X0-20,10);c.fill();c.stroke()
c.strokeStyle=WD;c.lineWidth=3;for(const[x,y]of[[60,18],[200,18],[60,192],[200,192]])c.beginPath(),c.moveTo(x-10,y),c.lineTo(x+10,y),c.stroke();c.strokeStyle='#111'
c.fillStyle=WD;c.lineWidth=6;c.beginPath();c.roundRect(X0-10,Y1-4,X1-X0+20,14,4);c.fill();c.stroke()
// teru teru bozu swinging on its string from the top bar
const a=.22*sin(T*t);c.save();c.translate(182,Y0+10);c.rotate(a)
c.lineWidth=3;c.beginPath();c.moveTo(0,0);c.lineTo(0,34);c.stroke()
c.fillStyle=DOLL;c.lineWidth=5;c.beginPath();c.moveTo(-10,52);c.quadraticCurveTo(-26,74,-24,88);c.quadraticCurveTo(-16,82,-10,90);c.quadraticCurveTo(-4,82,2,90);c.quadraticCurveTo(8,82,14,90);c.quadraticCurveTo(20,82,26,88);c.quadraticCurveTo(26,72,10,52);c.closePath();c.fill();c.stroke()
c.beginPath();c.arc(0,40,18,0,T);c.fill();c.stroke()
c.strokeStyle=TIE;c.lineWidth=5;c.beginPath();c.moveTo(-11,56);c.lineTo(11,56);c.stroke();c.strokeStyle='#111'
c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.arc(d*7,38,2.6,0,T),c.fill()
c.lineWidth=2.5;c.beginPath();c.arc(0,42,5,.15*PI,.85*PI);c.stroke()
if(sunny){c.fillStyle='#ffa8a8';for(const d of[-1,1])c.beginPath(),c.ellipse(d*11,45,4,2.5,0,0,T),c.fill()}
c.restore()
// the girl in front, bottom left
c.save();c.translate(84,256);c.scale(.66,.66);c.translate(-128,-256)
c.lineWidth=9;c.fillStyle=HD;c.beginPath();c.moveTo(128,40);c.bezierCurveTo(196,40,206,100,198,168);c.lineTo(58,168);c.bezierCurveTo(50,100,60,40,128,40);c.fill();c.stroke()
c.fillStyle=SHIRT;c.beginPath();c.moveTo(100,188);c.quadraticCurveTo(56,198,44,262);c.lineTo(212,262);c.quadraticCurveTo(200,198,156,188);c.closePath();c.fill();c.stroke()
c.save();c.clip();c.strokeStyle=STR;c.lineWidth=9;for(let y=206;y<262;y+=20)c.beginPath(),c.moveTo(40,y),c.lineTo(216,y),c.stroke();c.restore()
c.beginPath();c.moveTo(100,188);c.quadraticCurveTo(56,198,44,262);c.lineTo(212,262);c.quadraticCurveTo(200,198,156,188);c.closePath();c.stroke()
c.fillStyle=SKIN;c.beginPath();c.rect(116,168,24,24);c.fill();c.beginPath();c.moveTo(116,168);c.lineTo(116,190);c.moveTo(140,168);c.lineTo(140,190);c.stroke()
c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke()
if(sunny){c.lineWidth=8;for(const x of[103,153])c.beginPath(),c.arc(x,146,13,PI*1.15,PI*1.85),c.stroke()}
else if(w<.2){c.lineWidth=8;for(const x of[103,153])c.beginPath(),c.arc(x,140,12,PI*.15,PI*.85),c.stroke()}
else eye(c,103,140,-1),eye(c,153,140,1)
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,162,14,7,0,0,T),c.fill()
c.lineWidth=5;c.fillStyle=MO;c.beginPath()
if(sunny)c.moveTo(112,164),c.quadraticCurveTo(128,190,144,164),c.closePath(),c.fill(),c.stroke();else c.arc(128,168,7,1.15*PI,1.85*PI),c.stroke()
c.lineWidth=9;c.fillStyle=HAIR;c.beginPath();c.moveTo(62,166);c.bezierCurveTo(46,74,88,38,128,38);c.bezierCurveTo(168,38,210,74,194,166)
c.quadraticCurveTo(186,124,178,106);c.quadraticCurveTo(170,102,164,110);c.quadraticCurveTo(160,96,150,92);c.quadraticCurveTo(144,104,136,110)
c.quadraticCurveTo(132,96,122,90);c.quadraticCurveTo(116,104,106,108);c.quadraticCurveTo(102,96,92,96);c.quadraticCurveTo(86,106,80,112);c.quadraticCurveTo(70,126,62,166);c.closePath();c.fill();c.stroke()
c.strokeStyle=HL;c.lineWidth=7;for(const[a0,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,58,PI*a0,PI*e),c.stroke();c.strokeStyle='#111'
c.fillStyle=CLIP;c.lineWidth=7;for(const k of[0,1])c.beginPath(),c.roundRect(150+k*6,70+k*14,28,10,4),c.fill(),c.stroke()
// hands: clasped under her chin while praying, thrown up when the sun comes out
const u=ease(cl((w-.5)/.3))
for(const d of[-1,1]){const hx=128+d*(10+70*u),hy=200-140*u
for(const[l,s]of[[30,'#111'],[17,SHIRT]])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),c.moveTo(128+d*66,250),c.quadraticCurveTo(128+d*(60+30*u),220-60*u,hx,hy+14),c.stroke()
c.strokeStyle='#111';c.lineWidth=7;c.fillStyle=SKIN;c.beginPath();c.ellipse(hx,hy,15,17,0,0,T);c.fill();c.stroke()}
c.restore()
}
+57
View File
@@ -0,0 +1,57 @@
// baby-blue haired girl lying on her tummy on a bed, giggling at her phone and kicking her feet while hearts pop out of the screen
const{sin,cos,PI,abs,min}=Math,T=2*PI
export const frames=16,delay=80
const SKIN='#ffe3d1',HAIR='#a5d8ff',HD='#4dabf7',HL='#e7f5ff',PJ='#ffd43b',PD='#fab005',BED='#eebefa',BD='#cc5de8',PH='#f783ac',SCR='#e3fafc',SOCK='#b197fc',BL='#ff8fab',MO='#c92a2a',TG='#ff8fab',HT='#ff6b9d'
const heart=(c,x,y,s)=>{c.save();c.translate(x,y);c.scale(s,s);c.beginPath();c.moveTo(0,8);c.bezierCurveTo(-13,-1,-9,-12,0,-5);c.bezierCurveTo(9,-12,13,-1,0,8);c.restore();c.fill();c.stroke()}
// one leg: thigh along the bed from the hip, calf swinging up from the knee
const leg=(c,a,dx)=>{
const kx=212+dx,ky=206,fx=kx+cos(a)*50,fy=ky-sin(a)*50
for(const[l,s]of[[22,'#111'],[13,PJ]])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),c.moveTo(176,200),c.lineTo(kx,ky),c.stroke()
for(const[l,s]of[[19,'#111'],[10,SKIN]])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),c.moveTo(kx,ky),c.lineTo(fx,fy),c.stroke()
c.strokeStyle='#111';c.lineWidth=5;c.fillStyle=SOCK;c.beginPath();c.ellipse(fx,fy,8,12,-a+PI/2,0,T);c.fill();c.stroke()
}
export default(c,t)=>{
const g=abs(sin(2*T*t)),Z=.68
c.lineWidth=6
// bed
c.fillStyle=BED;c.beginPath();c.roundRect(10,204,236,32,14);c.fill();c.stroke()
c.strokeStyle=BD;c.lineWidth=4;c.beginPath();c.moveTo(24,222);c.lineTo(232,222);c.stroke();c.strokeStyle='#111'
leg(c,1.25+.5*sin(2*T*t+PI),10)
// body lying along the bed
c.lineWidth=6;c.fillStyle=PJ;c.beginPath();c.moveTo(96,170);c.quadraticCurveTo(150,166,184,182);c.quadraticCurveTo(196,198,180,208);c.lineTo(100,208);c.quadraticCurveTo(84,192,96,170);c.closePath();c.fill();c.stroke()
c.fillStyle=PD;for(const[x,y]of[[124,184],[150,190],[170,196],[134,200]])c.beginPath(),c.arc(x,y,4.5,0,T),c.fill()
leg(c,1.25+.5*sin(2*T*t),0)
// arm propped on its elbow, hand holding the phone up
for(const[l,s]of[[22,'#111'],[13,PJ]])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),c.moveTo(108,184),c.lineTo(80,202),c.lineTo(58,166),c.stroke()
c.strokeStyle='#111'
// head, bobbing with each giggle
c.save();c.translate(112,110+3*g);c.rotate(.08);c.scale(Z,Z);c.translate(-128,-128)
c.lineWidth=9;c.fillStyle=HD;c.beginPath();c.moveTo(128,36);c.bezierCurveTo(196,36,210,110,198,176);c.quadraticCurveTo(188,198,170,190);c.lineTo(86,190);c.quadraticCurveTo(68,198,58,176);c.bezierCurveTo(46,110,60,36,128,36);c.fill();c.stroke()
c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke()
c.lineWidth=9;for(const x of[103,153])c.beginPath(),c.arc(x,148,13,PI*1.15,PI*1.85),c.stroke()
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,164,16,8,0,0,T),c.fill()
c.lineWidth=4;for(const d of[-1,1])for(const k of[-6,0,6])c.beginPath(),c.moveTo(128+d*44+k-2,168),c.lineTo(128+d*44+k+2,160),c.stroke()
c.lineWidth=5;c.fillStyle=MO;c.beginPath();c.moveTo(114,166);c.quadraticCurveTo(128,166,142,166);c.quadraticCurveTo(140,180+6*g,128,182+6*g);c.quadraticCurveTo(116,180+6*g,114,166);c.fill();c.stroke()
c.save();c.clip();c.fillStyle=TG;c.beginPath();c.ellipse(128,184+6*g,8,6,0,0,T);c.fill();c.restore()
c.lineWidth=9;c.fillStyle=HAIR;c.beginPath();c.moveTo(64,156)
c.bezierCurveTo(48,74,88,36,128,36);c.bezierCurveTo(168,36,208,74,192,156)
c.quadraticCurveTo(188,120,182,106);c.quadraticCurveTo(172,100,166,112);c.quadraticCurveTo(160,96,146,92);c.quadraticCurveTo(142,108,132,112)
c.quadraticCurveTo(126,96,112,94);c.quadraticCurveTo(108,108,98,112);c.quadraticCurveTo(92,98,82,102);c.quadraticCurveTo(78,112,78,112)
c.quadraticCurveTo(68,130,64,156);c.closePath();c.fill();c.stroke()
c.strokeStyle=HL;c.lineWidth=7;for(const[a,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,102,56,PI*a,PI*e),c.stroke()
c.restore()
c.strokeStyle='#111'
// phone in her hand, screen turned toward her
c.save();c.translate(46,146);c.rotate(-.3)
c.lineWidth=5;c.fillStyle=PH;c.beginPath();c.roundRect(-15,-30,30,52,7);c.fill();c.stroke()
c.fillStyle=SCR;c.beginPath();c.roundRect(-10,-24,20,38,3);c.fill();c.lineWidth=3;c.stroke()
c.fillStyle=HT;c.lineWidth=2;heart(c,0,-6,.75)
c.restore()
c.lineWidth=5;c.fillStyle=SKIN;c.beginPath();c.ellipse(58,166,10,11,0,0,T);c.fill();c.stroke()
// hearts popping out of the screen and floating up
c.fillStyle=HT;c.lineWidth=3.5
for(const o of[0,.33,.66]){const p=(t+o)%1,x=34+14*p+8*sin(T*p*2),y=108-84*p;if(p>.04)heart(c,x,y,.4+.8*min(1,p*3)*(1-p*.4))}
// giggle ticks beside her head
for(const[l,s]of[[7,'#111'],[2.5,'#fff']]){c.lineWidth=l;c.strokeStyle=s;for(const k of[-1,0,1])c.beginPath(),c.moveTo(176+4*g,72+k*14),c.lineTo(190+4*g,68+k*18),c.stroke()}
c.strokeStyle='#111'
}
+67
View File
@@ -0,0 +1,67 @@
// sleepy aqua-haired girl with a headband and towel brushing her teeth, the brush scrubbing back and forth, foam bubbles puffing and floating off, rinse cup in her other hand
const{sin,cos,PI,max}=Math,T=2*PI
export const frames=16,delay=70
const SKIN='#ffe3d1',HAIR='#66d9e8',HD='#1098ad',HL='#e3fafc',EYE='#9775fa',ED='#5f3dc4',BAND='#f783ac',TEE='#ffa94d',TOW='#fff',STR='#74c0fc',CUP='#faa2c1',WAT='#a5d8ff',BRUSH='#69db7c',BL='#ffa8a8',MO='#c92a2a'
const eye=(c,x,y,d)=>{
c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill()
c.save();c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.clip();c.fillStyle=EYE;c.fill();c.fillStyle=ED;c.beginPath();c.ellipse(x,y-8,13,10,0,0,T);c.fill()
c.fillStyle='#111';c.beginPath();c.ellipse(x,y+3,5.5,7.5,0,0,T);c.fill();c.fillStyle='#fff';c.beginPath();c.arc(x-4,y+6,3,0,T);c.fill();c.restore()
c.lineWidth=2.5;c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.stroke()
// drowsy lid
c.fillStyle=SKIN;c.beginPath();c.moveTo(x-19,y+2);c.quadraticCurveTo(x,y-8,x+19,y+2);c.lineTo(x+19,y-24);c.lineTo(x-19,y-24);c.fill()
c.lineWidth=6;c.beginPath();c.moveTo(x-16,y+2);c.quadraticCurveTo(x,y-7,x+16,y+2);c.moveTo(x+d*15,y+1);c.lineTo(x+d*20,y-3);c.stroke()
}
const bub=(c,x,y,r)=>{c.beginPath();c.arc(x,y,r,0,T);c.fill();c.stroke();c.save();c.fillStyle=WAT;c.beginPath();c.arc(x-r*.35,y-r*.35,r*.28,0,T);c.fill();c.restore()}
export default(c,t)=>{
const ox=6*sin(4*T*t)
c.lineWidth=6
c.fillStyle=HD;c.beginPath();c.moveTo(128,34);c.bezierCurveTo(198,34,212,100,204,178);c.quadraticCurveTo(190,192,178,182);c.lineTo(78,182);c.quadraticCurveTo(66,192,52,178);c.bezierCurveTo(44,100,58,34,128,34);c.fill();c.stroke()
c.fillStyle=TEE;c.beginPath();c.moveTo(100,190);c.quadraticCurveTo(62,198,54,256);c.lineTo(202,256);c.quadraticCurveTo(194,198,156,190);c.closePath();c.fill();c.stroke()
c.fillStyle=SKIN;c.beginPath();c.moveTo(116,168);c.lineTo(116,194);c.lineTo(140,194);c.lineTo(140,168);c.fill();c.beginPath();c.moveTo(116,168);c.lineTo(116,192);c.moveTo(140,168);c.lineTo(140,192);c.stroke()
// striped towel around the neck
c.fillStyle=TOW;c.beginPath();c.moveTo(90,186);c.quadraticCurveTo(128,212,166,186);c.lineTo(178,198);c.lineTo(172,256);c.lineTo(146,256);c.lineTo(150,214);c.quadraticCurveTo(128,222,106,214);c.lineTo(110,256);c.lineTo(84,256);c.lineTo(78,198);c.closePath();c.fill();c.stroke()
c.strokeStyle=STR;c.lineWidth=4;c.beginPath();for(const y of[232,244])c.moveTo(85,y),c.lineTo(108,y),c.moveTo(148,y),c.lineTo(171,y);c.stroke();c.strokeStyle='#111'
// left hand holding the rinse cup
for(const[l,s]of[[24,'#111'],[15,SKIN]])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),c.moveTo(70,256),c.lineTo(62,232),c.stroke()
c.strokeStyle='#111';c.lineWidth=5
c.fillStyle=CUP;c.beginPath();c.moveTo(34,190);c.lineTo(76,190);c.lineTo(72,236);c.lineTo(38,236);c.closePath();c.fill();c.stroke()
c.fillStyle=WAT;c.beginPath();c.ellipse(55,194,19,5,0,0,T);c.fill();c.stroke()
c.fillStyle='#fff';c.lineWidth=3;c.beginPath();c.moveTo(42,204);c.lineTo(44,226);c.stroke()
c.lineWidth=5;c.fillStyle=SKIN;c.beginPath();c.ellipse(64,220,13,11,0,0,T);c.fill();c.stroke()
// face
c.lineWidth=6;c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke()
eye(c,103,140,-1);eye(c,153,140,1)
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,160,13,6,0,0,T),c.fill()
c.fillStyle=MO;c.lineWidth=3.5;c.beginPath();c.ellipse(130,170,9,7,0,0,T);c.fill();c.stroke()
// hair pulled back off the forehead under a headband, side locks framing the face
c.lineWidth=6;c.fillStyle=HAIR;c.beginPath();c.moveTo(68,150);c.bezierCurveTo(52,74,88,34,128,34);c.bezierCurveTo(168,34,204,74,188,150)
c.quadraticCurveTo(184,128,182,112);c.bezierCurveTo(176,74,80,74,74,112);c.quadraticCurveTo(72,128,68,150);c.closePath();c.fill();c.stroke()
c.strokeStyle=HL;c.lineWidth=5;for(const[a,e]of[[1.26,1.36],[1.44,1.54],[1.64,1.74]])c.beginPath(),c.arc(128,96,56,PI*a,PI*e),c.stroke()
// soft bangs falling from under the headband, tips ending above the eyes, then the band over their roots
c.strokeStyle='#111';c.lineWidth=6;c.fillStyle=HAIR;c.beginPath();c.moveTo(78,110);c.quadraticCurveTo(128,68,178,110)
c.quadraticCurveTo(176,114,170,118);c.quadraticCurveTo(164,106,152,104);c.quadraticCurveTo(150,112,142,118)
c.quadraticCurveTo(136,104,124,102);c.quadraticCurveTo(122,112,114,118);c.quadraticCurveTo(108,106,96,104)
c.quadraticCurveTo(92,112,86,116);c.quadraticCurveTo(80,114,78,110);c.closePath();c.fill();c.stroke()
for(const[l,st]of[[17,'#111'],[10,BAND]])c.lineWidth=l,c.strokeStyle=st,c.beginPath(),c.moveTo(72,116),c.bezierCurveTo(78,72,178,72,184,116),c.stroke()
c.strokeStyle='#111';c.lineWidth=4;c.fillStyle=BAND
for(const d of[-1,1])c.beginPath(),c.moveTo(166,84),c.quadraticCurveTo(166+d*14,70,166+d*16,88),c.quadraticCurveTo(166+d*8,94,166,84),c.fill(),c.stroke()
c.beginPath();c.arc(166,84,4,0,T);c.fill();c.stroke()
// toothbrush scrubbing, its head tucked in her cheek
const bx=136+ox
for(const[l,s]of[[13,'#111'],[6,BRUSH]])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),c.moveTo(bx,170),c.lineTo(bx+70,182),c.stroke()
for(const[l,s]of[[24,'#111'],[15,SKIN]])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),c.moveTo(186,256),c.lineTo(bx+66,198),c.stroke()
c.strokeStyle='#111';c.lineWidth=5;c.fillStyle=SKIN;c.beginPath();c.ellipse(bx+64,184,12,13,0,0,T);c.fill();c.stroke()
c.lineWidth=3;c.beginPath();c.moveTo(bx+56,180);c.lineTo(bx+66,180);c.moveTo(bx+56,187);c.lineTo(bx+66,187);c.stroke()
// foam puffing around her lips
c.fillStyle='#fff';c.lineWidth=3
for(const[k,[x,y,r]]of[[118,174,5],[124,180,5],[134,179,5.5],[141,173,4.5],[114,166,3.5]].entries())bub(c,x,y,r+1.2*sin(4*T*t+k*1.7))
// bubbles drifting up from her mouth and popping
for(const o of[0,.5]){
const p=(2*t+o)%1,x=108-56*p,y=170-50*p+4*sin(T*p*2)
if(p<.85)bub(c,x,y,3+4*p)
else{c.lineWidth=3;const r=10;c.beginPath();for(let k=0;k<6;k++){const a=k*T/6;c.moveTo(x+cos(a)*r*.6,y+sin(a)*r*.6);c.lineTo(x+cos(a)*r,y+sin(a)*r)}c.stroke()}
}
// scrub lines by the brush hand
for(const[l,s]of[[7,'#111'],[2.5,'#fff']]){c.lineWidth=l;c.strokeStyle=s;for(const k of[-1,1])c.beginPath(),c.arc(bx+64,184,24,PI*(k>0?-.25:.75),PI*(k>0?.05:1.05)),c.stroke()}
c.strokeStyle='#111'
}
+69
View File
@@ -0,0 +1,69 @@
// moon viewing: silver-haired girl in a kimono sits on the veranda with a tri-color dango skewer under a huge full moon, susuki swaying, the moon rabbit pounding mochi
const{sin,cos,PI,max,min}=Math,T=2*PI
export const frames=12,delay=110
const SKIN='#ffe3d1',HAIR='#e9ecef',HD='#adb5bd',HL='#fff',EYE='#fab005',ED='#e67700',KIM='#7048e8',KD='#5f3dc4',OBI='#ffd43b',MOON='#fff3bf',MD='#ffe066',RAB='#fcc419',WOOD='#c08a5e',WD='#8d6346',SUS='#e8c99b',SUD='#c9a46a',STEM='#94d82d',D1='#faa2c1',D2='#fff',D3='#8ce99a',BL='#ffa8a8',MO='#c92a2a'
const eye=(c,x,y,d)=>{
c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill()
c.save();c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.clip()
c.fillStyle=EYE;c.beginPath();c.ellipse(x+3,y,11.5,15,0,0,T);c.fill();c.fillStyle=ED;c.beginPath();c.ellipse(x+3,y-10,13,10,0,0,T);c.fill()
c.fillStyle='#111';c.beginPath();c.ellipse(x+3,y+1,5.5,7.5,0,0,T);c.fill()
c.fillStyle='#fff';c.beginPath();c.arc(x-1,y-7,4.5,0,T);c.fill();c.beginPath();c.arc(x+8,y+6,2,0,T);c.fill();c.restore()
c.lineWidth=3.5;c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.stroke()
c.lineWidth=8;c.beginPath();c.moveTo(x-16,y-6);c.quadraticCurveTo(x,y-20,x+16,y-6);c.moveTo(x+d*15,y-7);c.lineTo(x+d*21,y-12);c.stroke()
}
const plume=(c,x,y,a)=>{c.save();c.translate(x,y);c.rotate(a);c.fillStyle=SUS;c.lineWidth=4;c.beginPath();c.moveTo(0,0);c.bezierCurveTo(-12,-14,-8,-40,4,-54);c.bezierCurveTo(14,-36,12,-12,0,0);c.fill();c.stroke()
c.strokeStyle=SUD;c.lineWidth=2.5;for(const k of[-14,-26,-38])c.beginPath(),c.moveTo(2,k),c.lineTo(-5,k+6),c.moveTo(3,k),c.lineTo(9,k+6),c.stroke();c.strokeStyle='#111';c.restore()}
export default(c,t)=>{
const sw=k=>.12*sin(T*t+k),blink=t>=.58&&t<.67,pound=sin(2*T*t),db=3*sin(T*t)
// full moon
c.lineWidth=7;c.fillStyle=MOON;c.beginPath();c.arc(150,100,90,0,T);c.fill();c.stroke()
c.fillStyle=MD;for(const[x,y,r]of[[112,58,12],[196,72,9],[184,150,14],[120,150,8]])c.beginPath(),c.arc(x,y,r,0,T),c.fill()
// moon rabbit pounding mochi
c.fillStyle=RAB;c.save();c.translate(166,108)
c.beginPath();c.ellipse(0,0,16,13,0,0,T);c.fill();c.beginPath();c.arc(10,-12,9,0,T);c.fill()
for(const k of[0,1])c.beginPath(),c.ellipse(8+k*7,-28,4,11,.2+k*.25,0,T),c.fill()
c.beginPath();c.ellipse(-16,12,13,6,0,0,T);c.fill();c.beginPath();c.rect(-20,12,8,12);c.fill()
c.save();c.translate(2,-4);c.rotate(-.9+.5*pound);c.fillRect(-2,-26,4,26);c.fillRect(-8,-32,16,8);c.restore()
c.restore()
// susuki grass in a vase
for(const[k,a0]of[[0,-.3],[1,-.02],[2,.2]]){const a=a0+sw(k)
c.lineWidth=8;c.strokeStyle='#111';c.beginPath();c.moveTo(214,190);c.quadraticCurveTo(214+40*sin(a)*.4,150,214+90*sin(a),190-90*cos(a));c.stroke()
c.lineWidth=3.5;c.strokeStyle=STEM;c.stroke();c.strokeStyle='#111';plume(c,214+90*sin(a),190-90*cos(a),a)}
c.fillStyle='#4dabf7';c.lineWidth=6;c.beginPath();c.moveTo(200,186);c.lineTo(228,186);c.quadraticCurveTo(232,200,226,210);c.lineTo(202,210);c.quadraticCurveTo(196,200,200,186);c.fill();c.stroke()
// veranda plank
c.lineWidth=6;c.fillStyle=WOOD;c.beginPath();c.roundRect(14,208,228,16,5);c.fill();c.stroke()
c.strokeStyle=WD;c.lineWidth=3;for(const x of[60,130,196])c.beginPath(),c.moveTo(x,212),c.lineTo(x+18,212),c.stroke();c.strokeStyle='#111'
// dangling legs
for(const[d,ph]of[[-1,0],[1,PI]]){const k=7*sin(T*t+ph)
for(const[l,s]of[[17,'#111'],[10,SKIN]])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),c.moveTo(84+d*11,214),c.lineTo(84+d*11+k*.4,234),c.stroke()
c.strokeStyle='#111';c.lineWidth=5;c.fillStyle='#fff';c.beginPath();c.ellipse(84+d*11+k*.5,240,9,6,0,0,T);c.fill();c.stroke()
c.fillStyle=WD;c.beginPath();c.roundRect(76+d*11+k*.5,242,16,5,2);c.fill();c.stroke()}
// ponytail flowing behind
c.fillStyle=HAIR;c.lineWidth=6;c.beginPath();c.moveTo(56,118);c.bezierCurveTo(30,140,30,180,40,206);c.quadraticCurveTo(52,196,54,206);c.bezierCurveTo(56,176,60,150,72,130);c.closePath();c.fill();c.stroke()
// kimono body sitting
c.fillStyle=KIM;c.beginPath();c.moveTo(72,146);c.quadraticCurveTo(58,154,56,178);c.lineTo(50,212);c.quadraticCurveTo(84,220,118,212);c.lineTo(112,178);c.quadraticCurveTo(110,154,96,146);c.closePath();c.fill();c.stroke()
c.fillStyle=OBI;c.beginPath();c.rect(56,178,56,14);c.fill();c.stroke()
c.fillStyle='#fff';c.lineWidth=4;c.beginPath();c.moveTo(74,146);c.lineTo(84,166);c.lineTo(94,146);c.fill();c.stroke()
c.fillStyle='#ff922b';c.lineWidth=3;for(const[x,y]of[[64,202],[100,204],[66,164]]){c.beginPath();for(let k=0;k<5;k++){const a=k*T/5-PI/2;c.lineTo(x+6*cos(a),y+6*sin(a));c.lineTo(x+2.5*cos(a+PI/5),y+2.5*sin(a+PI/5))}c.closePath();c.fill();c.stroke()}
// head
const Z=.58;c.save();c.translate(84,64);c.scale(Z,Z);c.translate(-128,-40)
c.lineWidth=8;c.fillStyle=HD;c.beginPath();c.moveTo(128,36);c.bezierCurveTo(196,36,206,96,196,150);c.lineTo(60,150);c.bezierCurveTo(50,96,60,36,128,36);c.fill();c.stroke()
c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke()
if(blink){c.lineWidth=8;for(const x of[103,153])c.beginPath(),c.arc(x,140,12,PI*.15,PI*.85),c.stroke()}else eye(c,103,140,-1),eye(c,153,140,1)
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,162,14,7,0,0,T),c.fill()
c.lineWidth=5;c.beginPath();c.arc(132,166,8,.15*PI,.85*PI);c.stroke()
c.lineWidth=8;c.fillStyle=HAIR;c.beginPath();c.moveTo(66,146);c.bezierCurveTo(50,74,88,38,128,38);c.bezierCurveTo(168,38,206,74,190,146)
c.quadraticCurveTo(186,118,178,104);c.quadraticCurveTo(170,102,164,110);c.quadraticCurveTo(160,96,150,92);c.quadraticCurveTo(144,104,136,110)
c.quadraticCurveTo(132,96,122,90);c.quadraticCurveTo(116,104,106,108);c.quadraticCurveTo(102,96,92,96);c.quadraticCurveTo(86,106,80,112);c.quadraticCurveTo(70,124,66,146);c.closePath();c.fill();c.stroke()
c.strokeStyle=HD;c.lineWidth=5;for(const[a,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,58,PI*a,PI*e),c.stroke();c.strokeStyle='#111'
c.fillStyle='#e64980';c.lineWidth=6;for(let k=0;k<5;k++){const a=k*T/5;c.beginPath();c.arc(66+9*cos(a),84+9*sin(a),7,0,T);c.fill();c.stroke()}
c.fillStyle=OBI;c.beginPath();c.arc(66,84,6,0,T);c.fill();c.stroke()
c.restore()
// dango in her hand
c.save();c.translate(110,168+db);c.rotate(.55)
c.lineWidth=7;c.beginPath();c.moveTo(0,10);c.lineTo(0,-66);c.stroke();c.strokeStyle=WOOD;c.lineWidth=3;c.stroke();c.strokeStyle='#111'
c.lineWidth=5;for(const[k,f]of[[0,D3],[1,D2],[2,D1]])c.fillStyle=f,c.beginPath(),c.arc(0,-16-k*18,10,0,T),c.fill(),c.stroke()
c.restore()
for(const[l,s]of[[16,'#111'],[9,KIM]])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),c.moveTo(96,154),c.quadraticCurveTo(104,176,110,170+db),c.stroke()
c.strokeStyle='#111';c.lineWidth=5;c.fillStyle=SKIN;c.beginPath();c.arc(111,169+db,7,0,T);c.fill();c.stroke()
}
+54
View File
@@ -0,0 +1,54 @@
// violinist with an auburn side braid playing with her eyes closed, the bow sawing across the strings, swaying gently, notes drifting up
const{sin,cos,PI}=Math,T=2*PI
export const frames=12,delay=100
const SKIN='#ffe3d1',HAIR='#a0442a',HD='#7a2f1c',HL='#e3a08a',BL='#ffa8a8',DRS='#20c997',DRD='#0ca678',VIO='#e8590c',VIL='#ffa94d',FB='#495057',BOW='#a9744f',HAIRB='#fff',RIB='#ffd43b'
const ds=(c,a,b,s,f)=>{for(const[l,k]of[[a,'#111'],[b,s]])c.lineWidth=l,c.strokeStyle=k,c.beginPath(),f(),c.stroke();c.strokeStyle='#111'}
const shut=(c,x,y,d)=>{c.lineWidth=7;c.beginPath();c.arc(x,y-6,15,.12*PI,.88*PI);c.stroke();c.lineWidth=4;c.beginPath();for(const a of[.3,.5,.7])c.moveTo(x+15*cos(a*PI),y-6+15*sin(a*PI)),c.lineTo(x+20*cos(a*PI),y-6+20*sin(a*PI)+1);c.moveTo(x+d*14,y-1);c.lineTo(x+d*22,y+2);c.stroke()}
const note=(c,x,y,s,col)=>{ds(c,8,3,col,()=>{c.moveTo(x+6*s,y);c.lineTo(x+6*s,y-22*s);c.quadraticCurveTo(x+18*s,y-16*s,x+14*s,y-6*s)});c.fillStyle=col;c.lineWidth=3.5;c.beginPath();c.ellipse(x,y,7*s,5*s,-.4,0,T);c.fill();c.stroke()}
export default(c,t)=>{
const sw=.035*sin(T*t),st=50+34*sin(2*T*t),va=-.22,vx=150,vy=172,ba=-1.02,bd=[cos(ba),sin(ba)]
const L=(x,y)=>[vx+x*cos(va)-y*sin(va),vy+x*sin(va)+y*cos(va)],cp=L(-12,0),hx=cp[0]-bd[0]*st,hy=cp[1]-bd[1]*st
for(const[x,o,col]of[[206,0,'#ffd43b'],[230,.5,'#f783ac']]){const p=(t+o)%1,s=sin(PI*p);if(s>.2)note(c,x+5*sin(p*T),110-70*p,.45+.4*s,col)}
c.save();c.translate(128,256);c.rotate(sw);c.translate(-128,-256)
c.lineWidth=7;c.fillStyle=DRS;c.beginPath();c.moveTo(102,150);c.quadraticCurveTo(62,160,54,250);c.lineTo(202,250);c.quadraticCurveTo(194,160,154,150);c.closePath();c.fill();c.stroke()
c.fillStyle='#fff';c.lineWidth=5;c.beginPath();c.moveTo(108,152);c.quadraticCurveTo(128,176,148,152);c.quadraticCurveTo(128,162,108,152);c.fill();c.stroke()
c.fillStyle=SKIN;c.lineWidth=6;c.beginPath();c.moveTo(118,134);c.lineTo(118,152);c.quadraticCurveTo(128,160,138,152);c.lineTo(138,134);c.fill();c.beginPath();c.moveTo(118,134);c.lineTo(118,150);c.moveTo(138,134);c.lineTo(138,150);c.stroke()
c.save();c.translate(124,98);c.rotate(.14);c.scale(.68,.68);c.translate(-128,-120)
c.lineWidth=7;c.fillStyle=HD;c.beginPath();c.moveTo(128,36);c.bezierCurveTo(198,36,210,100,198,170);c.lineTo(58,170);c.bezierCurveTo(46,100,58,36,128,36);c.fill();c.stroke()
c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke()
shut(c,103,142,-1);shut(c,153,142,1)
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,164,13,7,0,0,T),c.fill()
c.lineWidth=2.5;for(const d of[-1,1])for(const x of[-5,0,5])c.beginPath(),c.moveTo(128+d*44+x-2,167),c.lineTo(128+d*44+x+2,161),c.stroke()
c.lineWidth=5;c.beginPath();c.moveTo(119,168);c.quadraticCurveTo(128,175,137,168);c.stroke()
c.lineWidth=7;c.fillStyle=HAIR;c.beginPath();c.moveTo(66,160)
c.bezierCurveTo(48,78,86,38,128,38);c.bezierCurveTo(170,38,208,78,190,160)
c.quadraticCurveTo(190,124,180,104);c.quadraticCurveTo(160,100,142,86);c.quadraticCurveTo(140,98,132,104)
c.quadraticCurveTo(122,92,118,84);c.quadraticCurveTo(106,104,84,112);c.quadraticCurveTo(70,130,66,160);c.closePath();c.fill();c.stroke()
c.strokeStyle=HL;c.lineWidth=6;for(const[s,e]of[[1.26,1.38],[1.46,1.54],[1.62,1.72]])c.beginPath(),c.arc(128,106,58,PI*s,PI*e),c.stroke();c.strokeStyle='#111'
c.restore()
for(let k=0;k<5;k++){const x=78-k*1.5,y=150+k*17;c.fillStyle=k%2?HD:HAIR;c.lineWidth=6;c.beginPath();c.ellipse(x,y,13-k,11,.15,0,T);c.fill();c.stroke()}
c.fillStyle=RIB;c.lineWidth=5;for(const d of[-1,1])c.beginPath(),c.ellipse(71+d*10,236,10,6,d*.4,0,T),c.fill(),c.stroke()
c.beginPath();c.arc(71,236,5,0,T);c.fill();c.stroke()
const nk=L(80,0)
ds(c,20,11,DRS,()=>{c.moveTo(150,170);c.lineTo(196,196);c.lineTo(nk[0]-4,nk[1]+10)})
c.save();c.translate(vx,vy);c.rotate(va)
const body=()=>{c.moveTo(-40,0);c.bezierCurveTo(-40,-26,-16,-26,-10,-16);c.quadraticCurveTo(-2,-12,6,-16);c.bezierCurveTo(14,-24,36,-22,36,0);c.bezierCurveTo(36,22,14,24,6,16);c.quadraticCurveTo(-2,12,-10,16);c.bezierCurveTo(-16,26,-40,26,-40,0)}
c.fillStyle=VIO;c.lineWidth=6;c.beginPath();body();c.fill();c.stroke()
c.strokeStyle=VIL;c.lineWidth=4;c.beginPath();c.moveTo(-30,-12);c.quadraticCurveTo(-20,-18,-12,-12);c.moveTo(14,-14);c.quadraticCurveTo(24,-16,30,-8);c.stroke();c.strokeStyle='#111'
c.lineWidth=2.5;for(const d of[-1,1]){c.beginPath();c.moveTo(-6,d*8);c.bezierCurveTo(-2,d*14,2,d*4,6,d*10);c.stroke()}
c.fillStyle=FB;c.lineWidth=5;c.beginPath();c.moveTo(-4,-5);c.lineTo(80,-4);c.lineTo(80,4);c.lineTo(-4,5);c.closePath();c.fill();c.stroke()
c.fillStyle=VIO;c.beginPath();c.roundRect(78,-6,16,12,3);c.fill();c.stroke();c.beginPath();c.arc(98,0,7,0,T);c.fill();c.stroke()
c.fillStyle='#111';c.beginPath();c.moveTo(-34,-6);c.lineTo(-20,-4);c.lineTo(-20,4);c.lineTo(-34,6);c.closePath();c.fill()
c.strokeStyle='#fff';c.lineWidth=1.2;c.beginPath();for(const y of[-3,-1,1,3])c.moveTo(-22,y*.9),c.lineTo(80,y*.9);c.stroke();c.strokeStyle='#111'
c.fillStyle='#fff';c.lineWidth=3;c.beginPath();c.rect(-14,-8,4,16);c.fill();c.stroke()
c.restore()
c.fillStyle=SKIN;c.lineWidth=5;c.beginPath();c.ellipse(nk[0],nk[1],10,11,0,0,T);c.fill();c.stroke()
ds(c,20,11,DRS,()=>{c.moveTo(104,170);c.lineTo(84,206);c.lineTo(hx-4,hy+4)})
c.restore()
const tx=hx+bd[0]*150,ty=hy+bd[1]*150,nx=-bd[1],ny=bd[0]
ds(c,9,4,BOW,()=>{c.moveTo(hx,hy);c.lineTo(tx,ty)})
ds(c,6,2.5,HAIRB,()=>{c.moveTo(hx+nx*6,hy+ny*6);c.lineTo(tx+nx*3,ty+ny*3)})
c.fillStyle='#111';c.beginPath();c.moveTo(hx+nx*7,hy+ny*7);c.lineTo(hx+bd[0]*14+nx*7,hy+bd[1]*14+ny*7);c.lineTo(hx+bd[0]*14,hy+bd[1]*14);c.lineTo(hx,hy);c.fill()
c.fillStyle=SKIN;c.lineWidth=5;c.beginPath();c.ellipse(hx,hy,11,11,0,0,T);c.fill();c.stroke()
if(Math.abs(cos(2*T*t))>.5)for(const d of[-1,1])ds(c,6,2.5,'#fff',()=>{c.moveTo(cp[0]+d*14+12,cp[1]-12);c.lineTo(cp[0]+d*18+16,cp[1]-18)})
}
+70
View File
@@ -0,0 +1,70 @@
// strawberry bedhead girl in star pajamas stretching both arms overhead in a big morning yawn, eyes squeezed shut and tears beading
const{sin,PI}=Math,T=2*PI
export const frames=16,delay=90
const SKIN='#ffe3d1',HAIR='#ff9fb8',HD='#e8708f',HL='#ffe0ea',EYE='#20c997',ED='#087f5b',PJ='#bac8ff',PD='#748ffc',BL='#ffa8a8',MO='#c92a2a',TG='#ff8fab',TEAR='#a5d8ff'
const ease=x=>x<=0?0:x>=1?1:x*x*(3-2*x)
const eye=(c,x,y,d)=>{
c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill()
c.save();c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.clip();c.fillStyle=EYE;c.fill();c.fillStyle=ED;c.beginPath();c.ellipse(x,y-8,13,10,0,0,T);c.fill()
c.fillStyle='#111';c.beginPath();c.ellipse(x,y+3,5.5,7.5,0,0,T);c.fill();c.fillStyle='#fff';c.beginPath();c.arc(x+4,y+7,2.5,0,T);c.fill();c.restore()
c.lineWidth=2.5;c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.stroke()
// heavy sleepy lid: a dome that hides the top half of the eye
c.fillStyle=SKIN;c.beginPath();c.moveTo(x-19,y+5);c.quadraticCurveTo(x,y-12,x+19,y+5);c.lineTo(x+19,y-24);c.lineTo(x-19,y-24);c.fill()
c.lineWidth=6;c.beginPath();c.moveTo(x-16,y+5);c.quadraticCurveTo(x,y-11,x+16,y+5);c.stroke()
c.lineWidth=2.5;c.beginPath();c.moveTo(x-9,y+23);c.quadraticCurveTo(x,y+26,x+9,y+23);c.stroke()
}
const drop=(c,x,y,r)=>{c.beginPath();c.moveTo(x,y-r*1.6);c.quadraticCurveTo(x+r,y-r*.2,x+r,y+r*.3);c.arc(x,y+r*.3,r,0,PI);c.quadraticCurveTo(x-r,y-r*.2,x,y-r*1.6);c.fill();c.stroke()}
export default(c,t)=>{
const s=ease((t-.06)/.28)-ease((t-.62)/.22),w=sin(2*T*t),hy=-6*s
c.translate(128,256);c.scale(.86,.86);c.translate(-128,-256)
// bedhead strands sticking up, drawn first so the hair covers their roots
// bedhead flyaways curling off the top and sides
for(const[x0,y0,x1,y1,x2,y2,o]of[[104,48,84,40,80,22,0],[136,40,150,24,140,12,1.4],[186,66,206,66,214,48,2.8],[70,80,52,74,48,58,4.2]])
for(const[l,st]of[[10,'#111'],[4,HAIR]])c.lineWidth=l,c.strokeStyle=st,c.beginPath(),c.moveTo(x0,y0+hy),c.quadraticCurveTo(x1,y1+hy,x2+4*sin(2*T*t+o),y2+hy+2*sin(2*T*t+o)),c.stroke()
c.strokeStyle='#111';c.lineWidth=6
c.fillStyle=HD;c.beginPath();c.moveTo(128,34+hy);c.bezierCurveTo(200,34+hy,214,100,206,168)
for(const[x,y]of[[198,186],[188,170],[176,192],[164,178]])c.lineTo(x,y)
c.lineTo(92,178);for(const[x,y]of[[80,192],[68,170],[58,186],[50,168]])c.lineTo(x,y)
c.bezierCurveTo(42,100,56,34+hy,128,34+hy);c.fill();c.stroke()
// pajama top with piping and star print
c.fillStyle=PJ;c.beginPath();c.moveTo(100,190);c.quadraticCurveTo(62,198,54,262);c.lineTo(202,262);c.quadraticCurveTo(194,198,156,190);c.closePath();c.fill();c.stroke()
c.fillStyle='#fff';c.lineWidth=2.5;for(const[x,y]of[[78,236],[178,230],[112,250],[150,252]]){c.beginPath();for(let k=0;k<10;k++){const r=k%2?2.5:6,a=k*PI/5-PI/2;c.lineTo(x+Math.cos(a)*r,y+Math.sin(a)*r)}c.closePath();c.fill();c.stroke()}
c.lineWidth=5;c.fillStyle='#fff';for(const d of[-1,1])c.beginPath(),c.moveTo(128,212),c.lineTo(128+d*30,190),c.lineTo(128+d*34,204),c.closePath(),c.fill(),c.stroke()
c.fillStyle=PD;for(const y of[226,246])c.beginPath(),c.arc(128,y,3.5,0,T),c.fill(),c.stroke()
c.fillStyle=SKIN;c.beginPath();c.moveTo(116,170+hy);c.lineTo(116,192);c.lineTo(128,210);c.lineTo(140,192);c.lineTo(140,170+hy);c.fill();c.beginPath();c.moveTo(116,170+hy);c.lineTo(116,192);c.moveTo(140,170+hy);c.lineTo(140,192);c.stroke()
// arms rise from the sides to clasp overhead
const hands=[]
for(const d of[-1,1]){
// elbow and hand swing out to the side on the way up instead of crossing the chest
const q=(a,b,e)=>(1-s)*(1-s)*a+2*s*(1-s)*b+s*s*e
const ex=128+d*q(66,118,102),ey=q(270,220,112),hx=128+d*q(58,124,20),hy2=q(312,160,16)
for(const[l,st]of[[30,'#111'],[19,PJ]])c.lineWidth=l,c.strokeStyle=st,c.beginPath(),c.moveTo(128+d*46,214),c.lineTo(ex,ey),c.lineTo(hx,hy2+10),c.stroke()
hands.push([hx,hy2])
}
c.strokeStyle='#111'
c.save();c.translate(0,hy)
c.lineWidth=6;c.fillStyle=SKIN;c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke()
if(s<.35){eye(c,103,142,-1);eye(c,153,142,1)}
else for(const d of[-1,1]){
const x=128+d*25
c.lineWidth=6;c.beginPath();c.moveTo(x+d*13,132);c.lineTo(x-d*9,142);c.lineTo(x+d*13,150);c.stroke()
c.fillStyle=TEAR;c.lineWidth=3;drop(c,x+d*20,146,2+4*s)
}
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*44,162,13,6,0,0,T),c.fill()
c.lineWidth=3.5
if(s>.12){
const rx=6+8*s,ry=4+13*s,my=166+3*s
c.fillStyle=MO;c.beginPath();c.ellipse(128,my,rx,ry,0,0,T);c.fill();c.stroke()
c.save();c.clip();c.fillStyle=TG;c.beginPath();c.ellipse(128,my+ry,rx*.8,ry*.55,0,0,T);c.fill();c.restore()
c.beginPath();c.ellipse(128,my,rx,ry,0,0,T);c.stroke()
}else c.beginPath(),c.moveTo(120,168),c.quadraticCurveTo(124,165,128,168),c.quadraticCurveTo(132,171,136,168),c.stroke()
c.lineWidth=6;c.fillStyle=HAIR;c.beginPath();c.moveTo(68,150)
c.bezierCurveTo(52,74,88,36,128,36);c.bezierCurveTo(168,36,204,74,188,150)
c.quadraticCurveTo(186,118,180,104);c.quadraticCurveTo(172,96,168,112);c.quadraticCurveTo(160,88,146,90);c.quadraticCurveTo(144,104,134,112)
c.quadraticCurveTo(128,92,114,90);c.quadraticCurveTo(112,104,100,110);c.quadraticCurveTo(94,92,84,100);c.quadraticCurveTo(84,110,78,114)
c.quadraticCurveTo(70,128,68,150);c.closePath();c.fill();c.stroke()
c.strokeStyle=HL;c.lineWidth=5;for(const[a,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,56,PI*a,PI*e),c.stroke()
c.restore()
c.strokeStyle='#111';c.lineWidth=5;c.fillStyle=SKIN
for(const[k,[x,y]]of hands.entries())c.beginPath(),c.ellipse(x,y+4,10,12,(k?-1:1)*.5,0,T),c.fill(),c.stroke()
}
+51
View File
@@ -0,0 +1,51 @@
// snow maiden with long ice-blue hair blowing frosty breath over her palm, the wisps curling away and turning into spinning snowflakes, sleeve drifting
const{sin,cos,PI,max,min,round}=Math,T=2*PI
export const frames=16,delay=80
const SKIN='#f8f0fc',HAIR='#a5d8ff',HD='#4dabf7',HL='#fff',EYE='#91a7ff',ED='#364fc7',KI='#fff',KP='#d0ebff',OBI='#9775fa',OD='#7048e8',ICE='#e7f5ff',BL='#d0bfff'
const eye=(c,x,y,d)=>{
c.fillStyle='#fff';c.beginPath();c.ellipse(x,y,14,17,0,0,T);c.fill()
c.save();c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.clip();c.fillStyle=EYE;c.fill();c.fillStyle=ED;c.beginPath();c.ellipse(x,y-8,13,10,0,0,T);c.fill();c.restore()
c.lineWidth=2.5;c.beginPath();c.ellipse(x,y+2,11.5,15,0,0,T);c.stroke()
c.fillStyle='#111';c.beginPath();c.ellipse(x+3,y+3,5.5,7.5,0,0,T);c.fill()
c.fillStyle='#fff';c.beginPath();c.arc(x,y+1,4,0,T);c.fill();c.beginPath();c.arc(x+7,y+9,2,0,T);c.fill()
c.fillStyle=SKIN;c.beginPath();c.rect(x-17,y-21,34,15);c.fill()
c.lineWidth=6;c.beginPath();c.moveTo(x-16,y-5);c.quadraticCurveTo(x,y-11,x+16,y-5);c.moveTo(x+d*15,y-6);c.lineTo(x+d*21,y-11);c.stroke()
c.lineWidth=2.5;for(const k of[-6,0,6])c.beginPath(),c.moveTo(x+k,y-6),c.lineTo(x+k*1.4,y-11),c.stroke()
}
const flake=(c,x,y,r,a)=>{for(const[lw,col]of[[8,'#111'],[3.5,'#fff']]){c.lineWidth=lw;c.strokeStyle=col;c.beginPath()
for(let k=0;k<6;k++){const b=a+k*PI/3,ex=x+cos(b)*r,ey=y+sin(b)*r,mx=x+cos(b)*r*.55,my=y+sin(b)*r*.55
c.moveTo(x,y);c.lineTo(ex,ey);for(const s of[-1,1])c.moveTo(mx,my),c.lineTo(mx+cos(b+s*.8)*r*.35,my+sin(b+s*.8)*r*.35)}
c.stroke()}c.strokeStyle='#111'}
const path=p=>[146+92*p+6*sin(p*T*2),178-24*p-96*p*p]
export default(c,t)=>{
const sw=.06*sin(T*t),puff=1+.12*sin(4*T*t)
c.save();c.translate(116,256);c.scale(.9,.9);c.translate(-128,-256)
c.lineWidth=6;c.fillStyle=HD;c.beginPath();c.moveTo(128,34);c.bezierCurveTo(200,34,214,100,206,160);c.bezierCurveTo(214,200,206,236,214,256);c.lineTo(42,256);c.bezierCurveTo(50,236,42,200,50,160);c.bezierCurveTo(42,100,56,34,128,34);c.fill();c.stroke()
c.fillStyle=KI;c.beginPath();c.moveTo(98,186);c.quadraticCurveTo(58,194,48,256);c.lineTo(208,256);c.quadraticCurveTo(198,194,158,186);c.closePath();c.fill();c.stroke()
c.fillStyle=KP;for(const[x,y]of[[70,236],[96,220],[180,230]])c.beginPath(),c.arc(x,y,7,0,T),c.fill()
c.fillStyle=KI;c.beginPath();c.moveTo(104,186);c.lineTo(128,222);c.lineTo(152,186);c.fill();c.stroke()
c.fillStyle=OBI;c.beginPath();c.moveTo(68,240);c.quadraticCurveTo(128,230,190,240);c.lineTo(194,256);c.lineTo(64,256);c.closePath();c.fill();c.stroke()
c.fillStyle=SKIN;c.beginPath();c.rect(116,168,24,24);c.fill();c.beginPath();c.moveTo(116,168);c.lineTo(116,190);c.moveTo(140,168);c.lineTo(140,190);c.stroke()
c.beginPath();c.moveTo(74,96);c.bezierCurveTo(70,152,100,184,128,186);c.bezierCurveTo(156,184,186,152,182,96);c.bezierCurveTo(182,44,74,44,74,96);c.fill();c.stroke()
c.lineWidth=6;for(const[x,d]of[[103,-1],[153,1]]){c.beginPath();c.moveTo(x-16,138);c.quadraticCurveTo(x,150,x+16,138);c.moveTo(x+d*15,140);c.lineTo(x+d*21,136);c.stroke();c.lineWidth=3;for(const k of[-8,0,8])c.beginPath(),c.moveTo(x+k,145),c.lineTo(x+k*1.2,151),c.stroke();c.lineWidth=6}
c.fillStyle=BL;for(const d of[-1,1])c.beginPath(),c.ellipse(128+d*42,162,12,6,0,0,T),c.fill()
c.lineWidth=4;c.fillStyle='#e64980';c.beginPath();c.ellipse(140,168,5*puff,6*puff,0,0,T);c.fill();c.stroke()
c.lineWidth=6;c.fillStyle=HAIR;c.beginPath();c.moveTo(62,170)
c.bezierCurveTo(46,74,88,34,128,34);c.bezierCurveTo(168,34,210,74,194,170)
c.quadraticCurveTo(188,128,182,106);c.quadraticCurveTo(176,108,170,116);c.quadraticCurveTo(164,100,156,94);c.quadraticCurveTo(150,104,142,110)
c.quadraticCurveTo(136,98,128,92);c.quadraticCurveTo(120,98,114,110);c.quadraticCurveTo(106,104,100,94);c.quadraticCurveTo(92,100,86,116)
c.quadraticCurveTo(80,108,74,106);c.quadraticCurveTo(68,128,62,170);c.closePath();c.fill();c.stroke()
c.strokeStyle=HL;c.lineWidth=5;for(const[a,e]of[[1.24,1.36],[1.44,1.52],[1.62,1.74]])c.beginPath(),c.arc(128,104,56,PI*a,PI*e),c.stroke();c.strokeStyle='#111'
for(const d of[-1,1]){c.lineWidth=6;c.fillStyle=HAIR;c.beginPath();c.moveTo(128+d*58,106);c.quadraticCurveTo(128+d*70,170,128+d*62,226);c.quadraticCurveTo(128+d*52,212,128+d*50,196);c.quadraticCurveTo(128+d*54,150,128+d*48,112);c.closePath();c.fill();c.stroke()}
flake(c,82,62,13,PI/6)
c.save();c.translate(182,192);c.rotate(sw)
c.fillStyle=KI;c.lineWidth=6;c.beginPath();c.moveTo(-14,0);c.lineTo(8,-6);c.lineTo(42,52);c.quadraticCurveTo(36,76,30,80);c.quadraticCurveTo(10,70,-2,74);c.closePath();c.fill();c.stroke()
c.fillStyle=KP;c.beginPath();c.arc(18,46,7,0,T);c.fill();c.strokeStyle=KP;c.lineWidth=4;c.beginPath();c.moveTo(6,68);c.quadraticCurveTo(20,72,30,72);c.stroke();c.strokeStyle='#111'
c.restore()
c.fillStyle=SKIN;c.lineWidth=5;c.beginPath();c.moveTo(168,196);c.quadraticCurveTo(170,180,188,178);c.quadraticCurveTo(204,176,212,180);c.quadraticCurveTo(212,188,202,190);c.quadraticCurveTo(186,196,178,200);c.closePath();c.fill();c.stroke()
c.lineWidth=3;c.beginPath();c.moveTo(196,180);c.quadraticCurveTo(204,182,206,186);c.stroke()
c.restore()
for(let k=0;k<5;k++){const p=(t*2+k/5)%1,[x,y]=path(p)
if(p<.35){const r=4+9*p/.35;c.fillStyle=ICE;c.lineWidth=4;c.beginPath();c.arc(x,y,r,0,T);c.fill();c.stroke();c.strokeStyle=KP;c.lineWidth=2.5;c.beginPath();c.arc(x,y,r*.55,PI,PI*1.7);c.stroke();c.strokeStyle='#111'}
else{const r=round(14*min(1,(1-p)/.2)*min(1,(p-.35)/.12+.5));if(r>2)flake(c,x,y,r,p*5)}}
}