mirror of
https://github.com/direct-img/vibegif.direct-img.link.git
synced 2026-10-29 19:54:51 +00:00
Black ink, screentone and white only: reaction tropes (gaan shock, gloom corner, menacing aura, crow silence, petrify), comedy and action (harisen, iai draw, kendo, kyudo, miko), school life (locker letters, zero test, rooftop wind, shared umbrella), town and home (omikuji, shrine prayer, tanabata, floating lantern, alarm smash) and fantasy (yurei, oni, dragon, android, summoning circle, knight, pirate, detective, princess). gen files can now export rim=<px> for a white sticker border, so solid black ink still shows on the black page. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
63 lines
6.3 KiB
JavaScript
63 lines
6.3 KiB
JavaScript
// white-ponytailed swordswoman waits eyes shut as a petal falls, then a quick draw flashes and the petal drops in two halves
|
|
import{createCanvas}from'@napi-rs/canvas'
|
|
const{sin,cos,PI,max,min}=Math,T=2*PI
|
|
export const frames=20,delay=70,rim=4
|
|
const dots=(col,r)=>{const k=createCanvas(6,6),x=k.getContext('2d');x.fillStyle=col;for(const[a,b]of[[3,3],[0,0],[6,0],[0,6],[6,6]])x.beginPath(),x.arc(a,b,r,0,T),x.fill();return k}
|
|
const TONE=dots('#111',1.7),LITE=dots('#fff',1.2)
|
|
const ease=u=>u<0?0:u>1?1:u*u*(3-2*u)
|
|
const petal=c=>{c.beginPath();c.moveTo(0,12);c.bezierCurveTo(-12,4,-10,-10,-3,-12);c.lineTo(0,-8);c.lineTo(3,-12);c.bezierCurveTo(10,-10,12,4,0,12);c.closePath()}
|
|
const eye=(c,x,y,d,lt,o)=>{
|
|
if(!o){c.lineWidth=6;c.beginPath();c.moveTo(x-14,y+2);c.quadraticCurveTo(x,y+10,x+14,y+2);c.moveTo(x+d*14,y+2);c.lineTo(x+d*19,y-1);c.stroke();return}
|
|
c.save();c.beginPath();c.moveTo(x-16,y-4+d*2);c.lineTo(x+16,y-4-d*2);c.lineTo(x+16,y+20);c.lineTo(x-16,y+20);c.clip()
|
|
c.fillStyle='#fff';c.beginPath();c.ellipse(x,y+3,12,13,0,0,T);c.fill();c.clip()
|
|
c.fillStyle='#111';c.beginPath();c.ellipse(x+5,y+4,8,11,0,0,T);c.fill();c.fillStyle=lt;c.fillRect(x-4,y+6,20,12)
|
|
c.fillStyle='#fff';c.beginPath();c.arc(x+3,y,3.2,0,T);c.fill();c.restore()
|
|
c.lineWidth=6;c.beginPath();c.moveTo(x-14,y-4+d*2);c.lineTo(x+14,y-4-d*2);c.lineTo(x+d*19,y-8);c.stroke()
|
|
}
|
|
const blade=(c,b=1)=>{
|
|
if(b){c.lineWidth=4;c.fillStyle='#fff';c.beginPath();c.moveTo(0,-4);c.lineTo(78,-6);c.quadraticCurveTo(88,-6,92,-2);c.quadraticCurveTo(84,2,76,3);c.lineTo(0,4);c.closePath();c.fill();c.stroke()
|
|
c.lineWidth=2;c.beginPath();c.moveTo(4,0);c.lineTo(80,-2);c.stroke()}
|
|
c.fillStyle='#111';c.beginPath();c.ellipse(0,0,4,11,0,0,T);c.fill()
|
|
c.beginPath();c.roundRect(-30,-5,28,10,4);c.fill();c.fillStyle='#fff';for(let j=0;j<3;j++)c.beginPath(),c.moveTo(-26+j*8,0),c.lineTo(-22+j*8,-3),c.lineTo(-18+j*8,0),c.lineTo(-22+j*8,3),c.fill()
|
|
}
|
|
export default(c,t)=>{
|
|
const tn=c.createPattern(TONE,'repeat'),lt=c.createPattern(LITE,'repeat')
|
|
const k=t<.45?0:t<.5?1:t<.72?1:1-ease((t-.72)/.2),open=t>=.45&&t<.9,flash=t>=.45&&t<.6
|
|
const hx=165+7*k,hy=205-55*k,ha=-.42-.33*k
|
|
if(flash){const f=1-(t-.45)/.15*.7;c.lineWidth=4;c.fillStyle='#fff';c.beginPath()
|
|
for(let j=0;j<=20;j++){const u=j/20,a=.32-1.05*u;c.lineTo(70+156*cos(a),166+156*sin(a))}
|
|
for(let j=20;j>=0;j--){const u=j/20,a=.32-1.05*u,r=156-18*f*sin(PI*u);c.lineTo(70+r*cos(a),166+r*sin(a))}
|
|
c.closePath();c.fill();c.stroke()}
|
|
const py=t<.45?14+112*t/.45:0,px=212+8*sin(t*T*2)
|
|
if(t<.45){c.save();c.translate(px,py);c.rotate(.6*sin(t*T*3));c.lineWidth=3.5;c.fillStyle='#fff';petal(c);c.fill();c.stroke();c.restore()}
|
|
else{const u=(t-.45)/.55,yy=126+100*u*u+20*u,s=1-u*.6
|
|
for(const d of[-1,1]){c.save();c.translate(px-8*u+d*(5+22*u),yy+d*4*u);c.rotate(-.4+d*(.2+2*u));c.scale(s,s);c.beginPath();c.rect(d<0?-20:0,-20,20,40);c.clip();c.lineWidth=3.5;c.fillStyle='#fff';petal(c);c.fill();c.stroke();c.lineWidth=2.5;c.beginPath();c.moveTo(0,-14);c.lineTo(0,14);c.stroke();c.restore()}}
|
|
const sw=3*sin(t*T)+(t>=.45&&t<.72?8*sin((t-.45)/.27*PI):0)
|
|
c.lineWidth=6;c.fillStyle='#fff';c.beginPath();c.moveTo(88,30);c.bezierCurveTo(40,24,24-sw,90,20-sw,170);c.quadraticCurveTo(30-sw,150,36-sw,190);c.quadraticCurveTo(46-sw,120,58,92);c.quadraticCurveTo(70,60,96,46);c.closePath();c.fill();c.stroke()
|
|
c.lineWidth=2.5;c.beginPath();c.moveTo(70,40);c.bezierCurveTo(44,60,34-sw,110,30-sw,160);c.moveTo(80,46);c.bezierCurveTo(58,80,48-sw,120,44-sw,150);c.stroke()
|
|
c.lineWidth=6;c.fillStyle=tn;c.beginPath();c.moveTo(56,206);c.lineTo(40,256);c.lineTo(160,256);c.lineTo(150,206);c.closePath();c.fill();c.stroke()
|
|
c.lineWidth=3;c.beginPath();for(const x of[74,98,122,140])c.moveTo(x,210),c.lineTo(x-6,252);c.stroke()
|
|
c.lineWidth=6;c.fillStyle='#fff';c.beginPath();c.moveTo(78,150);c.quadraticCurveTo(46,158,46,214);c.lineTo(160,214);c.quadraticCurveTo(156,158,118,150);c.closePath();c.fill();c.stroke()
|
|
c.fillStyle='#111';c.beginPath();c.moveTo(84,150);c.lineTo(112,196);c.lineTo(118,190);c.lineTo(94,150);c.closePath();c.fill();c.beginPath();c.moveTo(114,150);c.lineTo(100,174);c.lineTo(104,180);c.lineTo(120,152);c.fill()
|
|
c.lineWidth=5;c.beginPath();c.moveTo(84,150);c.lineTo(114,198);c.moveTo(114,150);c.lineTo(98,176);c.stroke()
|
|
c.fillStyle='#111';c.fillRect(48,200,112,10)
|
|
c.save();c.translate(150,212);c.rotate(-.42);c.fillStyle='#111';c.beginPath();c.roundRect(-118,-6,118,12,6);c.fill();c.fillStyle='#fff';c.fillRect(-60,-6,4,12);c.restore()
|
|
|
|
c.fillStyle='#fff';c.lineWidth=6;c.beginPath();c.rect(88,128,22,26);c.fill();c.beginPath();c.moveTo(88,128);c.lineTo(88,152);c.moveTo(110,128);c.lineTo(110,152);c.stroke()
|
|
c.save();c.translate(98,92);c.scale(.66,.66);c.translate(-128,-128)
|
|
c.lineWidth=7;c.fillStyle='#fff';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,106,138,-1,lt,open);eye(c,156,138,1,lt,open)
|
|
c.lineWidth=4;c.beginPath();if(open)c.moveTo(130,170),c.lineTo(146,168);else c.moveTo(130,170),c.quadraticCurveTo(138,174,146,170);c.stroke()
|
|
c.lineWidth=7;c.beginPath();c.moveTo(70,150)
|
|
c.bezierCurveTo(54,74,88,40,128,40);c.bezierCurveTo(168,40,202,74,186,150)
|
|
c.quadraticCurveTo(186,118,180,104);c.quadraticCurveTo(176,108,170,118);c.quadraticCurveTo(164,100,150,92);c.quadraticCurveTo(148,106,140,116)
|
|
c.quadraticCurveTo(134,98,124,90);c.quadraticCurveTo(118,104,112,112);c.quadraticCurveTo(104,96,94,94);c.quadraticCurveTo(90,108,84,118)
|
|
c.quadraticCurveTo(80,108,78,106);c.quadraticCurveTo(68,124,70,150);c.closePath();c.fill();c.stroke()
|
|
c.lineWidth=3;c.beginPath();for(const[x0,y0,x1,y1]of[[110,50,96,92],[134,46,130,88],[158,54,160,92],[90,64,80,100],[176,72,180,104]])c.moveTo(x0,y0),c.quadraticCurveTo((x0+x1)/2+4,(y0+y1)/2,x1,y1);c.stroke()
|
|
c.fillStyle='#111';c.beginPath();c.ellipse(86,52,12,9,-.6,0,T);c.fill()
|
|
c.restore()
|
|
if(k<.5){c.save();c.translate(150,212);c.rotate(-.42);c.translate(32,0);blade(c,0);c.restore()}else{c.save();c.translate(hx,hy);c.rotate(ha);c.scale(.85,.85);c.translate(16,0);blade(c);c.restore()}
|
|
for(const[l,s]of[[24,'#111'],[14,'#fff']])c.lineWidth=l,c.strokeStyle=s,c.beginPath(),c.moveTo(70,166),c.quadraticCurveTo(100+20*k,214-50*k,hx-4,hy+4),c.stroke()
|
|
c.strokeStyle='#111';c.lineWidth=5;c.fillStyle='#fff';c.beginPath();c.ellipse(hx,hy,10,9,ha,0,T);c.fill();c.stroke()
|
|
}
|