diff --git a/gen/mini/catwhale/swim.js b/gen/mini/catwhale/swim.js index 192f242..d4585d1 100644 --- a/gen/mini/catwhale/swim.js +++ b/gen/mini/catwhale/swim.js @@ -1,9 +1,9 @@ -// cat-whale drifting along: one solid ink shape, it bobs, flicks its tail, twitches an ear, puffs a spout and blinks +// cat-whale drifting along: one solid white shape with a dark edge, it bobs, flicks its tail, twitches an ear, puffs a spout and blinks const{sin,cos,PI,min,max}=Math,T=2*PI -export const frames=24,delay=85,rim=3,invert=true +export const frames=24,delay=85,rim=3,rimColor='#111' export default(c,t)=>{ const s=sin(T*t),k=sin(T*t-1.4),p=t/.45,tw=t>.6&&t<.68?.3:0,bl=t>.82&&t<.9,tx=46+4*k,ty=92-5*k - c.fillStyle=c.strokeStyle='#111';c.lineWidth=6 + c.fillStyle=c.strokeStyle='#fff';c.lineWidth=6 c.translate(128,132+7*s);c.rotate(.04*cos(T*t));c.scale(.9,.9);c.translate(-126,-128) const shape=(x,y,r,f)=>{c.save();c.translate(x,y);c.rotate(r);c.beginPath();f();c.fill();c.stroke();c.restore()} shape(0,0,0,()=>{ @@ -24,7 +24,7 @@ export default(c,t)=>{ for(const d of[-1,1])c.beginPath(),c.moveTo(x,y-h),c.quadraticCurveTo(x+d*w*.8,y-h-w*.5,x+d*w,y-h+w*.5),c.stroke(), c.beginPath(),c.arc(x+d*w,y-h+w*.5+5,5*g,0,T),c.fill() } - c.fillStyle=c.strokeStyle='#fff' + c.fillStyle=c.strokeStyle='#111' if(bl)c.lineWidth=3.5,c.beginPath(),c.arc(190,128,6,.15*PI,.85*PI),c.stroke() else c.beginPath(),c.arc(190,130,6.5,0,T),c.fill() c.lineWidth=3;c.beginPath();c.moveTo(214,160);c.quadraticCurveTo(206,167,196,165);c.stroke() diff --git a/gen/mini/dandelion/drift.js b/gen/mini/dandelion/drift.js index c05d9e4..3ecaa2a 100644 --- a/gen/mini/dandelion/drift.js +++ b/gen/mini/dandelion/drift.js @@ -1,11 +1,11 @@ // lion whose mane is dandelion fluff: three seeds blow off and drift away, new ones grow back in their place const{sin,cos,PI,min,max}=Math,T=2*PI -export const frames=24,delay=85,rim=3,invert=true +export const frames=24,delay=85,rim=3,rimColor='#111' const N=18,F=[1,2,3] const seed=c=>{c.beginPath();c.moveTo(0,0);c.lineTo(24,0);for(let j=-2;j<=2;j++)c.moveTo(24,0),c.lineTo(24+10*cos(j*.42),10*sin(j*.42));c.stroke()} export default(c,t)=>{ const bl=t>.86&&t<.92 - c.fillStyle=c.strokeStyle='#111';c.lineWidth=6 + c.fillStyle=c.strokeStyle='#fff';c.lineWidth=6 c.translate(128,128);c.scale(1.1,1.1);c.translate(-128,-128) const shape=g=>{c.beginPath();g();c.fill();c.stroke()} c.lineWidth=7;c.beginPath();c.moveTo(150,204);c.quadraticCurveTo(186,210,188+6*sin(T*t),178);c.stroke();c.lineWidth=6 @@ -23,7 +23,7 @@ export default(c,t)=>{ c.lineWidth=6 for(const d of[-1,1])shape(()=>c.arc(128+d*30,70,11,0,T)) shape(()=>c.arc(128,100,40,0,T)) - c.fillStyle=c.strokeStyle='#fff' + c.fillStyle=c.strokeStyle='#111' for(const d of[-1,1])if(bl)c.lineWidth=3.5,c.beginPath(),c.arc(128+d*15,94,5,.15*PI,.85*PI),c.stroke() else c.beginPath(),c.arc(128+d*15,96,5,0,T),c.fill() c.beginPath();c.moveTo(121,108);c.lineTo(135,108);c.lineTo(128,116);c.closePath();c.fill() diff --git a/gen/mini/mantis/pray.js b/gen/mini/mantis/pray.js index df9658b..7d5c8e9 100644 --- a/gen/mini/mantis/pray.js +++ b/gen/mini/mantis/pray.js @@ -1,9 +1,9 @@ // praying mantis: it sways, tilts its triangle head side to side, and gives its folded forearms a little pump const{sin,cos,PI,max}=Math,T=2*PI -export const frames=24,delay=85,rim=3,invert=true +export const frames=24,delay=85,rim=3,rimColor='#111' export default(c,t)=>{ const s=sin(T*t),pm=t>.3&&t<.6?sin(PI*(t-.3)/.3):0,ht=.3*sin(T*t+1) - c.fillStyle=c.strokeStyle='#111';c.lineWidth=4 + c.fillStyle=c.strokeStyle='#fff';c.lineWidth=4 const shape=f=>{c.beginPath();f();c.fill();c.stroke()} for(const[hx,kx,ky,fx]of[[130,152,186,166],[118,98,190,82],[112,62,184,46]])c.beginPath(),c.moveTo(hx,160),c.lineTo(kx,ky),c.lineTo(fx,212),c.stroke() c.translate(122,212);c.rotate(.03*s);c.translate(-122,-212) @@ -17,6 +17,6 @@ export default(c,t)=>{ c.save();c.translate(152,80);c.rotate(ht) c.lineWidth=3;for(const d of[-1,1])c.beginPath(),c.moveTo(d*6,-16),c.quadraticCurveTo(d*12,-48,d*30,-64),c.stroke() c.lineWidth=6;shape(()=>{c.moveTo(-20,-16);c.lineTo(20,-16);c.lineTo(0,10);c.closePath()}) - c.fillStyle='#fff';for(const d of[-1,1])c.beginPath(),c.arc(d*15,-15,3.5,0,T),c.fill() + c.fillStyle='#111';for(const d of[-1,1])c.beginPath(),c.arc(d*15,-15,3.5,0,T),c.fill() c.restore() } diff --git a/gen/mini/wisp/float.js b/gen/mini/wisp/float.js index 9a947d3..cc8634b 100644 --- a/gen/mini/wisp/float.js +++ b/gen/mini/wisp/float.js @@ -1,16 +1,16 @@ // will-o-wisp floating: a round flame spirit bobbing and tilting, its flame tips flicker, embers drift up beside it, it blinks const{sin,PI}=Math,T=2*PI -export const frames=24,delay=80,rim=3,invert=true +export const frames=24,delay=80,rim=3,rimColor='#111' export default(c,t)=>{ const bl=t>.4&&t<.46,Mx=128+6*sin(T*t*2),My=40+4*sin(T*t*3),R=4*sin(T*t*2+1),L=4*sin(T*t*2+2.5) - c.fillStyle=c.strokeStyle='#111';c.lineWidth=6 + c.fillStyle=c.strokeStyle='#fff';c.lineWidth=6 for(const[i,x]of[-46,40,-30].entries()){const q=(t+i/3)%1;c.beginPath();c.arc(128+x+5*sin(T*q),110-74*q,5*sin(PI*q),0,T);c.fill()} c.translate(128,132+8*sin(T*t));c.rotate(.05*sin(T*t+1));c.scale(1.15,1.15);c.translate(-128,-128) c.beginPath();c.moveTo(82,148);c.arc(128,148,46,PI,0,true) c.bezierCurveTo(176,122,176,96,170+R,74);c.quadraticCurveTo(158,84,150,94) c.bezierCurveTo(152,72,140,54,Mx,My);c.bezierCurveTo(116,56,104,74,106,92) c.quadraticCurveTo(98,86,88+L,80);c.bezierCurveTo(80,100,80,124,82,148);c.fill();c.stroke() - c.fillStyle=c.strokeStyle='#fff' + c.fillStyle=c.strokeStyle='#111' for(const d of[-1,1])if(bl)c.lineWidth=3.5,c.beginPath(),c.arc(128+d*16,136,7,.15*PI,.85*PI),c.stroke() else c.beginPath(),c.ellipse(128+d*16,138,7,10,0,0,T),c.fill() c.lineWidth=3.5;c.beginPath();c.arc(128,156,7,.2*PI,.8*PI);c.stroke() diff --git a/public/catwhale/swim.gif b/public/catwhale/swim.gif index 4126a2d..33ed0c8 100644 Binary files a/public/catwhale/swim.gif and b/public/catwhale/swim.gif differ diff --git a/public/catwhale/swim.webp b/public/catwhale/swim.webp index 402deac..183a63a 100644 Binary files a/public/catwhale/swim.webp and b/public/catwhale/swim.webp differ diff --git a/public/dandelion/drift.gif b/public/dandelion/drift.gif index 3acfd99..a52f423 100644 Binary files a/public/dandelion/drift.gif and b/public/dandelion/drift.gif differ diff --git a/public/dandelion/drift.webp b/public/dandelion/drift.webp index dce8c2d..dd2c754 100644 Binary files a/public/dandelion/drift.webp and b/public/dandelion/drift.webp differ diff --git a/public/mantis/pray.gif b/public/mantis/pray.gif index 8d814ec..6132f1e 100644 Binary files a/public/mantis/pray.gif and b/public/mantis/pray.gif differ diff --git a/public/mantis/pray.webp b/public/mantis/pray.webp index 23fcd63..f9ba9af 100644 Binary files a/public/mantis/pray.webp and b/public/mantis/pray.webp differ diff --git a/public/wisp/float.gif b/public/wisp/float.gif index c32f571..c9d52fb 100644 Binary files a/public/wisp/float.gif and b/public/wisp/float.gif differ diff --git a/public/wisp/float.webp b/public/wisp/float.webp index f85088c..c3d8de2 100644 Binary files a/public/wisp/float.webp and b/public/wisp/float.webp differ diff --git a/scripts/gen.js b/scripts/gen.js index 1a1d604..a5d52c1 100644 --- a/scripts/gen.js +++ b/scripts/gen.js @@ -2,9 +2,8 @@ // the section folder (bw, color, anime, manga, mini, minicolor) only picks where it shows in the gallery, it isn't part of the url // npm run gen renders only what's missing (published files never change by accident) // npm run gen -- cat/blink renders only the named ones, even if they already exist -// a file can export rim= to get a white sticker border, so black ink still shows on a black page +// a file can export rim= to get a sticker border, white unless it also exports rimColor, so a shape that matches the page still shows // delay can be one number or a list with one entry per frame (ms) -// invert=true swaps ink and paper (#111 <-> #fff), turning a black silhouette with a white rim into a white one with a dark rim import{createCanvas}from'@napi-rs/canvas' import sharp from'sharp' import{readdirSync as rd,existsSync as ex,mkdirSync as mk,statSync as st}from'fs' @@ -18,22 +17,19 @@ if(dup)throw Error(`${dup} is in more than one section`) for(const[k,f]of files.entries()){ const id=ids[k],o=`public/${id}` if(redo.length?!redo.includes(id):ex(o+'.webp')&&ex(o+'.gif'))continue - const{default:draw,frames=16,delay=80,rim=0,invert=false}=await import(url(resolve(f))) + const{default:draw,frames=16,delay=80,rim=0,rimColor='#fff'}=await import(url(resolve(f))) const px=[...Array(frames)].map((_,i)=>{ let c=createCanvas(S,S).getContext('2d') Object.assign(c,{lineWidth:7,lineCap:'round',lineJoin:'round',strokeStyle:'#111',fillStyle:'#fff'}) draw(c,i/frames,i) if(rim){ - // white silhouette grown by rim px (copies shifted around rings 1..rim px out), then the frame on top + // silhouette grown by rim px (copies shifted around rings 1..rim px out) filled with rimColor, then the frame on top const r=createCanvas(S,S).getContext('2d') for(let d=1;d<=rim;d++)for(let a=0;a<24;a++)r.drawImage(c.canvas,d*Math.cos(a*Math.PI/12),d*Math.sin(a*Math.PI/12)) - r.globalCompositeOperation='source-in';r.fillStyle='#fff';r.fillRect(0,0,S,S) + r.globalCompositeOperation='source-in';r.fillStyle=rimColor;r.fillRect(0,0,S,S) r.globalCompositeOperation='source-over';r.drawImage(c.canvas,0,0);c=r } - const b=Buffer.from(c.getImageData(0,0,S,S).data.buffer) - // 17 and 255 trade places, the antialiased grays in between flip along, alpha is untouched - if(invert)for(let j=0;jsharp(Buffer.concat(px),{raw:{width:S,height:S*frames,channels:4,pageHeight:S}})