git / moonbite-network / templates/break.html · raw

<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover"><title>MoonBite — Break</title><meta name="robots" content="noindex"><link rel="icon" type="image/svg+xml" href="/static/moonbite-logo.svg"><style nonce="{{ csp_nonce }}">:root{  --gold:#D9A441; --faint:#5E5A53;  --mono:ui-monospace,'SFMono-Regular',Menlo,Consolas,monospace;  --ease:cubic-bezier(0.22,1,0.36,1);}*{margin:0;padding:0;box-sizing:border-box}html{-webkit-text-size-adjust:100%}body{background:#000;overflow-x:hidden}#run{position:relative;height:240vh}#stage{position:sticky;top:0;height:100svh;overflow:hidden;background:#000}canvas{position:absolute;inset:0;width:100%;height:100%;display:block}#flash{position:absolute;inset:0;background:#EAF2FF;opacity:0;pointer-events:none;mix-blend-mode:screen}.cue{position:absolute;left:50%;bottom:30px;transform:translateX(-50%);z-index:5;  font-family:var(--mono);font-size:.62rem;letter-spacing:.24em;text-transform:uppercase;  color:var(--faint);opacity:0;transition:opacity 600ms var(--ease);  display:flex;flex-direction:column;align-items:center;gap:9px}body.ready .cue{opacity:1}body.blown .cue{opacity:0}.cue i{display:block;width:1px;height:30px;  background:linear-gradient(180deg,var(--gold),transparent);  animation:drop 2.2s ease-in-out infinite}@keyframes drop{0%,100%{opacity:.25;transform:scaleY(.5)}50%{opacity:1;transform:scaleY(1)}}@media(prefers-reduced-motion:reduce){ .cue i{animation:none} }</style></head><body><section id="run">  <div id="stage">    <canvas id="view"></canvas>    <div id="flash"></div>    <div class="cue">Scroll<i></i></div>  </div></section><script nonce="{{ csp_nonce }}">(function(){  var $=function(i){return document.getElementById(i)};  var reduce=matchMedia('(prefers-reduced-motion: reduce)').matches             && !/[?&]motion=1/.test(location.search);  var run=$('run'), stage=$('stage'), view=$('view'), flash=$('flash'), body=document.body;  var ctx=view.getContext('2d');  function clamp(v,a,b){return v<a?a:(v>b?b:v)}  function smooth(a,b,x){if(b===a)return x<a?0:1;var t=clamp((x-a)/(b-a),0,1);return t*t*(3-2*t)}  function lerp(a,b,t){return a+(b-a)*t}  function rnd(a,b){return a+Math.random()*(b-a)}  var W,H,DPR,CX,CY,SC,BT,B1,B2,BW_GLYPH,IX,IY,RMAX=1;  var src=document.createElement('canvas'), sctx=src.getContext('2d');  var mkc=document.createElement('canvas'), mctx=mkc.getContext('2d');  var dmg=document.createElement('canvas'), dctx=dmg.getContext('2d');  var stars=[], impacts=[];  var blown=false, t0=0, barW=0, barTension=0, built=false;  function size(){    DPR=Math.min(devicePixelRatio||1,2);    W=view.width=src.width=mkc.width=dmg.width=Math.floor(innerWidth*DPR);    H=view.height=src.height=mkc.height=dmg.height=Math.floor(innerHeight*DPR);    CX=W/2; CY=H/2;    var mkSize=Math.min(innerWidth*0.38,260)*DPR;    SC=mkSize/300;    BT=Math.max(3*DPR,13*SC);    BW_GLYPH=255*SC;    B1=CY-34*SC; B2=CY+18*SC;    IX=CX; IY=(B1+B2)/2;    RMAX=Math.sqrt(W*W+H*H)*0.75;    if(!blown) barW=BW_GLYPH;    stars=[];    var n=Math.round(clamp(innerWidth*innerHeight/9000,80,240));    for(var i=0;i<n;i++) stars.push({x:Math.random()*W,y:Math.random()*H,      r:(Math.random()*1.2+0.25)*DPR,z:Math.random()*0.9+0.1,t:Math.random()*6.28});    buildGlass();  }  /* the picture that is about to be destroyed */  function paintSrc(bw,glow){    sctx.clearRect(0,0,W,H);    var g=sctx.createRadialGradient(CX,CY*0.92,0,CX,CY,Math.max(W,H)*0.72);    g.addColorStop(0,'#12141C'); g.addColorStop(.62,'#06070A'); g.addColorStop(1,'#000');    sctx.fillStyle=g; sctx.fillRect(0,0,W,H);    for(var i=0;i<stars.length;i++){      var s=stars[i];      sctx.beginPath(); sctx.arc(s.x,s.y,s.r,0,6.283);      sctx.fillStyle='rgba(236,230,214,'+(0.16*s.z)+')'; sctx.fill();    }    mctx.clearRect(0,0,W,H);    mctx.beginPath(); mctx.arc(CX,CY,100*SC,0,6.283);    mctx.fillStyle='#F5F2EA'; mctx.fill();    mctx.save();    mctx.globalCompositeOperation='destination-out';    mctx.beginPath(); mctx.arc(CX+67.18*SC,CY-67.18*SC,62*SC,0,6.283); mctx.fill();    mctx.restore();    sctx.drawImage(mkc,0,0);    sctx.save();    if(glow>0){ sctx.shadowColor='rgba(217,164,65,.9)'; sctx.shadowBlur=BT*(1.2+glow*3); }    sctx.fillStyle='#D9A441';    [B1,B2].forEach(function(y){      sctx.beginPath();      if(sctx.roundRect) sctx.roundRect(CX-bw/2,y-BT/2,bw,BT,BT/2);      else sctx.rect(CX-bw/2,y-BT/2,bw,BT);      sctx.fill();    });    sctx.restore();  }  /* Two strikes. Each builds its own web of radial rays crossed by concentric     rings, plus splinters, ink pools and dead lines. The second lands late. */  function buildImpact(x,y,reach,seg,rings,heavy,delay){    var im={x:x,y:y,reach:reach,delay:delay,shards:[],cracks:[],splinters:[],blobs:[],cols:[]};    var ang=[];    for(var a=0;a<seg;a++) ang.push(a/seg*6.283+rnd(-0.11,0.11));    ang.push(ang[0]+6.283);    var rr=[];    for(var r=0;r<rings.length;r++){      rr[r]=[];      for(var k=0;k<=seg;k++) rr[r][k]=rings[r]*reach*rnd(0.82,1.20);      rr[r][seg]=rr[r][0];    }    function P(r,k){ return [x+Math.cos(ang[k])*rr[r][k], y+Math.sin(ang[k])*rr[r][k]]; }    for(var r2=0;r2<rings.length-1;r2++){      for(var k2=0;k2<seg;k2++){        var p=[P(r2,k2),P(r2,k2+1),P(r2+1,k2+1),P(r2+1,k2)];        var cx=(p[0][0]+p[1][0]+p[2][0]+p[3][0])/4;        var cy=(p[0][1]+p[1][1]+p[2][1]+p[3][1])/4;        im.shards.push({p:p,cx:cx,cy:cy,          d:Math.sqrt((cx-x)*(cx-x)+(cy-y)*(cy-y)),          ox:rnd(-1,1)*DPR*(3.4-r2*0.20)*heavy, oy:rnd(-1,1)*DPR*(3.4-r2*0.20)*heavy,          rot:rnd(-0.011,0.011)*(1.5-r2*0.1)*heavy, lift:rnd(-0.16,0.22)});      }    }    for(var r3=0;r3<rings.length;r3++)      for(var k3=0;k3<seg;k3++)        im.cracks.push({a:P(r3,k3),b:P(r3,k3+1),d:rings[r3]*reach});    for(var k4=0;k4<seg;k4++)      for(var r4=0;r4<rings.length-1;r4++)        im.cracks.push({a:P(r4,k4),b:P(r4+1,k4),d:rings[r4]*reach});    /* splinters: short hairlines branching off the web */    for(var sp=0;sp<Math.round(52*heavy);sp++){      var sa=rnd(0,6.283), sd=rnd(0.06,1.0)*reach, ln=rnd(0.02,0.11)*reach;      var a2=sa+rnd(-0.6,0.6);      im.splinters.push({a:[x+Math.cos(sa)*sd, y+Math.sin(sa)*sd],        b:[x+Math.cos(sa)*sd+Math.cos(a2)*ln, y+Math.sin(sa)*sd+Math.sin(a2)*ln], d:sd});    }    /* liquid crystal pools, kept off the mark */    var keep=110*SC;    for(var b=0;b<Math.round(20*heavy);b++){      var aa=rnd(0,6.283), dd=keep+rnd(0.04,0.42)*reach;      im.blobs.push({x:x+Math.cos(aa)*dd, y:y+Math.sin(aa)*dd,        r:rnd(0.06,0.20)*reach, sq:rnd(0.4,1.7), rot:rnd(0,3.14), t:rnd(0.05,0.5)});    }    for(var c=0;c<Math.round(15*heavy);c++){      im.cols.push({x:x+rnd(-0.5,0.5)*reach, w:rnd(1,6)*DPR, h:rnd(0.3,1.15),        hue:Math.random()<0.45?rnd(150,190):rnd(280,330), a:rnd(0.14,0.62)});    }    return im;  }  function buildGlass(){    impacts=[];    /* the strike, where the bars cross the mark */    impacts.push(buildImpact(CX,(B1+B2)/2, RMAX, 22,      [0.026,0.062,0.110,0.172,0.250,0.348,0.470,0.620,0.800,1.05], 1.0, 0.00));    /* the second, lower right, landing a beat later */    impacts.push(buildImpact(CX+W*0.27, B2+H*0.19, RMAX*0.60, 18,      [0.030,0.075,0.140,0.230,0.350,0.500,0.700,1.02], 0.85, 0.30));  }  /* the damage, painted into its own layer and then left there */  function buildDamage(prog){    dctx.clearRect(0,0,W,H);    /* the picture, still on screen but no longer in one piece */    for(var n=0;n<impacts.length;n++){      var im=impacts[n];      var lp=clamp((prog-im.delay)/(1-im.delay),0,1);      if(lp<=0) { if(n===0) continue; else continue; }      var reach=lp*im.reach*1.18;      for(var i=0;i<im.shards.length;i++){        var s=im.shards[i];        var on=clamp((reach-s.d)/(0.12*im.reach),0,1);        if(on<=0) continue;        dctx.save();        dctx.translate(s.cx+s.ox*on, s.cy+s.oy*on);        dctx.rotate(s.rot*on);        dctx.translate(-s.cx,-s.cy);        dctx.beginPath();        dctx.moveTo(s.p[0][0],s.p[0][1]);        for(var k=1;k<s.p.length;k++) dctx.lineTo(s.p[k][0],s.p[k][1]);        dctx.closePath(); dctx.clip();        dctx.drawImage(src,0,0);        if(s.lift>0){ dctx.fillStyle='rgba(190,214,255,'+(0.07*on*s.lift)+')'; dctx.fillRect(0,0,W,H); }        else { dctx.fillStyle='rgba(0,0,0,'+(0.30*on*-s.lift)+')'; dctx.fillRect(0,0,W,H); }        dctx.restore();      }    }    for(var n2=0;n2<impacts.length;n2++){      var im2=impacts[n2];      var lp2=clamp((prog-im2.delay)/(1-im2.delay),0,1);      if(lp2<=0) continue;      var reach2=lp2*im2.reach*1.18;      /* liquid crystal bleeding into black pools */      for(var b=0;b<im2.blobs.length;b++){        var bl=im2.blobs[b], bp=clamp((lp2-bl.t)/0.45,0,1);        if(bp<=0) continue;        dctx.save();        dctx.translate(bl.x,bl.y); dctx.rotate(bl.rot); dctx.scale(1,bl.sq);        var rg=dctx.createRadialGradient(0,0,0,0,0,bl.r*bp);        rg.addColorStop(0,'rgba(0,0,0,0.95)');        rg.addColorStop(.55,'rgba(0,0,0,0.74)');        rg.addColorStop(.82,'rgba(6,8,16,0.32)');        rg.addColorStop(1,'rgba(6,8,16,0)');        dctx.fillStyle=rg;        dctx.beginPath(); dctx.arc(0,0,bl.r*bp,0,6.283); dctx.fill();        dctx.restore();      }      /* dead driver lines stuck on one colour */      for(var c=0;c<im2.cols.length;c++){        var cl=im2.cols[c], cp=clamp((lp2-0.22)/0.5,0,1);        if(cp<=0) continue;        var hh=H*cl.h*cp;        var lg=dctx.createLinearGradient(0,im2.y-hh/2,0,im2.y+hh/2);        lg.addColorStop(0,'hsla('+cl.hue+',90%,60%,0)');        lg.addColorStop(.5,'hsla('+cl.hue+',90%,60%,'+(cl.a*cp)+')');        lg.addColorStop(1,'hsla('+cl.hue+',90%,60%,0)');        dctx.fillStyle=lg;        dctx.fillRect(cl.x-cl.w/2, im2.y-hh/2, cl.w, hh);      }      /* the cracks: dark fissure, lit edge */      for(var q=0;q<im2.cracks.length;q++){        var cr=im2.cracks[q];        if(cr.d>reach2) continue;        var near=1-clamp(cr.d/im2.reach,0,1);        dctx.beginPath(); dctx.moveTo(cr.a[0],cr.a[1]); dctx.lineTo(cr.b[0],cr.b[1]);        dctx.strokeStyle='rgba(0,0,0,'+(0.62+0.3*near)+')';        dctx.lineWidth=(2.2+3.4*near)*DPR; dctx.stroke();        dctx.beginPath(); dctx.moveTo(cr.a[0],cr.a[1]); dctx.lineTo(cr.b[0],cr.b[1]);        dctx.strokeStyle='rgba(220,234,255,'+(0.26+0.58*near)+')';        dctx.lineWidth=(0.7+1.2*near)*DPR; dctx.stroke();      }      for(var sp2=0;sp2<im2.splinters.length;sp2++){        var sl=im2.splinters[sp2];        if(sl.d>reach2) continue;        dctx.beginPath(); dctx.moveTo(sl.a[0],sl.a[1]); dctx.lineTo(sl.b[0],sl.b[1]);        dctx.strokeStyle='rgba(214,230,255,0.30)';        dctx.lineWidth=0.7*DPR; dctx.stroke();      }      /* pulverised glass at the point of impact */      var ip=clamp(lp2*2,0,1);      var ir=0.11*im2.reach*ip;      var ig=dctx.createRadialGradient(im2.x,im2.y,0,im2.x,im2.y,ir);      ig.addColorStop(0,'rgba(236,243,255,'+(0.58*ip)+')');      ig.addColorStop(.5,'rgba(190,214,255,'+(0.16*ip)+')');      ig.addColorStop(1,'rgba(190,214,255,0)');      dctx.fillStyle=ig;      dctx.beginPath(); dctx.arc(im2.x,im2.y,ir,0,6.283); dctx.fill();    }  }  function detonate(){    if(blown) return;    blown=true; t0=performance.now(); body.classList.add('blown');    paintSrc(barW,1);    flash.style.transition='none'; flash.style.opacity='0.85';    setTimeout(function(){      flash.style.transition='opacity 220ms var(--ease)'; flash.style.opacity='0';    },40);  }  function render(now){    if(!blown){      paintSrc(barW, smooth(0.55,1,barTension));      ctx.clearRect(0,0,W,H);      ctx.drawImage(src,0,0);      return;    }    var el=now-t0;    var prog=clamp(el/1000,0,1);    if(prog<1 || !built){ buildDamage(prog); if(prog>=1) built=true; }    ctx.clearRect(0,0,W,H);    ctx.fillStyle='#000'; ctx.fillRect(0,0,W,H);    ctx.drawImage(dmg,0,0);    /* the panel failing: backlight flicker and banding */    if(el>240){      var f=Math.random();      if(f>0.955){        ctx.fillStyle='rgba(0,0,0,'+rnd(0.10,0.34)+')';        ctx.fillRect(0,Math.random()*H,W,rnd(0.02,0.16)*H);      }      if(f<0.02){ ctx.fillStyle='rgba(150,190,255,0.05)'; ctx.fillRect(0,0,W,H); }    }    var sh=Math.max(0,1-el/300);    stage.style.transform = sh>0      ? 'translate('+(rnd(-1,1)*13*sh)+'px,'+(rnd(-1,1)*13*sh)+'px)' : '';  }  var target=0,cur=0;  function measure(){    var r=run.getBoundingClientRect();    var total=run.offsetHeight-stage.offsetHeight;    target=clamp(-r.top/(total||1),0,1);  }  function frame(now){    cur+=(target-cur)*0.12;    if(!blown){      barTension=smooth(0.008,0.10,cur);      barW=lerp(BW_GLYPH, innerWidth*DPR*1.35, barTension);      if(barTension>=0.999) detonate();    }    render(now);    requestAnimationFrame(frame);  }  addEventListener('scroll',measure,{passive:true});  addEventListener('resize',function(){ built=false; size(); measure(); });  size(); measure();  setTimeout(function(){ body.classList.add('ready') },900);  if(reduce){ paintSrc(BW_GLYPH,0); ctx.drawImage(src,0,0); }  else requestAnimationFrame(frame);  if(/[?&]motion=1/.test(location.search)){    window.__boom=function(){ barW=innerWidth*DPR*1.35; detonate(); return 'boom' };  }})();</script></body></html>