← FATHOM v1
index.html
<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>FATHOM</title>
<style>html,body{margin:0;height:100%;background:#e9eaee;overflow:hidden}canvas{position:fixed;inset:0;width:100%;height:100%;display:block}
#sp{position:fixed;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;font:500 12px ui-monospace,"SF Mono",Menlo,Consolas,monospace;color:#16181e;letter-spacing:.3em;text-align:center}
#sp h1{font-weight:400;font-size:min(13vw,104px);letter-spacing:.42em;margin:0 -.42em .1em 0}
#sp p{margin:.5em 1em;opacity:.6;line-height:1.8}
#go{font:inherit;font-weight:700;letter-spacing:.4em;color:#fff;background:#ee4534;border:0;padding:1.3em 2.6em 1.3em 3em;margin:2.2em 0 1.6em;cursor:pointer}
#go:hover{background:#16181e}</style>
<canvas id="g"></canvas><canvas id="h"></canvas>
<div id="sp"><h1>FATHOM</h1><p id="msg">A PATH-TRACED MEASUREMENT IN TWELVE PLATES</p><button id="go">START</button><p>SOUND ON · F FOR FULL SCREEN<br>FABLE 5.2, MODEL SALT AT 2</p></div>
<script>var PRE="#version 300 es\nprecision highp float;precision highp int;uniform vec3 uRo,uU,uV,uW,pRo,pU,pV,pW;uniform vec2 uRes;uniform vec4 uF;uniform vec4 uE;uniform vec4 uM;uniform vec4 uN;uniform vec4 uP[8];uniform sampler2D uA,uG;layout(location=0)out vec4 oC;layout(location=1)out vec4 oG;\n#define T uM.x\n#define KICK uE.x\n#define SNARE uE.y\n#define HAT uE.z\n#define FAR 160.\n#define CORAL vec3(.96,.24,.19)\n#define MINT vec3(.52,.86,.72)\n#define LILAC vec3(.70,.62,.92)\n#define BUTTER vec3(.98,.86,.48)\n#define SKYB vec3(.50,.74,.96)\n#define INK vec3(.05,.055,.07)\nfloat gm;float U(float a,float b,float id){if(b<a){gm=id;return b;}return a;}mat2 rot(float a){float c=cos(a),s=sin(a);return mat2(c,s,-s,c);}float h11(float n){return fract(sin(n*127.1)*43758.5453);}float h21(vec2 p){return fract(sin(dot(p,vec2(127.1,311.7)))*43758.5453);}float smin(float a,float b,float k){float h=max(k-abs(a-b),0.)/k;return min(a,b)-h*h*k*.25;}float sdBox(vec3 p,vec3 b){vec3 d=abs(p)-b;return length(max(d,0.))+min(max(d.x,max(d.y,d.z)),0.);}float sdRBox(vec3 p,vec3 b,float r){return sdBox(p,b-r)-r;}float sdTorus(vec3 p,float R,float r){return length(vec2(length(p.xz)-R,p.y))-r;}float sdCyl(vec3 p,float r,float h){vec2 d=abs(vec2(length(p.xz),p.y))-vec2(r,h);return min(max(d.x,d.y),0.)+length(max(d,0.));}float sdCap(vec3 p,vec3 a,vec3 b,float r){vec3 pa=p-a,ba=b-a;return length(pa-ba*clamp(dot(pa,ba)/dot(ba,ba),0.,1.))-r;}float rb(vec2 q,float a,float w){q*=rot(a);vec2 d=abs(q)-vec2(w,.014);return length(max(d,0.))+min(max(d.x,d.y),0.)-.006;}\n",POST="\n#ifndef KD\n#define KD normalize(vec3(.45,.8,.35))\n#endif\n#ifndef KC\n#define KC vec3(1.25,1.16,1.02)\n#endif\n#ifndef KR\n#define KR .16\n#endif\n#ifndef FOGK\n#define FOGK .00035\n#endif\n#ifndef SKY\nvec3 sky(vec3 d){return mix(vec3(1.02,1.01,1.),vec3(.42,.52,.80),pow(clamp(d.y,0.,1.),.55));}\n#endif\nuint sd;float rnd(){sd=sd*747796405u+2891336453u;uint w=((sd>>((sd>>28)+4u))^sd)*277803737u;return float((w>>22)^w)/4294967296.;}vec3 rs(){float z=rnd()*2.-1.,a=rnd()*6.2832,r=sqrt(1.-z*z);return vec3(r*cos(a),r*sin(a),z);}float mr(vec3 o,vec3 d,float tm,int n,bool pr){float t=0.;for(int i=min(0,int(uF.x));i<n;i++){float h=map(o+d*t);if(h<.0005+.0008*t)return t;t+=h;if(t>tm)return -1.;}if(!pr||d.y>=0.)return -1.;float f=-o.y/d.y;return f<tm?max(t,f-.002):-1.;}vec3 nr(vec3 p){vec3 n=vec3(0);for(int i=min(0,int(uF.x));i<4;i++){vec3 e=.5773*(2.*vec3(((i+3)>>1)&1,(i>>1)&1,i&1)-1.);n+=e*map(p+e*.0008);}return normalize(n);}void main(){vec2 fc=gl_FragCoord.xy;sd=uint(fc.x)*1973u+uint(fc.y)*9277u+uint(uF.x)*26699u;rnd();vec2 q=fc/uRes*2.-1.;vec3 ro=uRo,rd=normalize(uW+uU*q.x+uV*q.y);vec3 col=vec3(0),thr=vec3(1),lc=vec3(0),so=ro,sv=rd,n0=vec3(0);float t0=FAR;bool sh=false;int b=0;for(int i=min(0,int(uF.x));i<5;i++){float t=mr(ro,rd,sh?14.:b==0?FAR:b==1?26.:9.,sh?30:b==0?96:b==1?44:20,b==0&&!sh);if(sh){if(t<0.)col+=lc;ro=so;rd=sv;sh=false;continue;}if(t<0.){col+=thr*sky(rd);break;}if(b==0){t+=map(ro+rd*t);t+=map(ro+rd*t);}vec3 p=ro+rd*t;gm=0.;map(p);float id=gm;vec3 n=nr(p);vec3 al=vec3(.84),em=vec3(0);vec2 sp=vec2(0,1);if(id==1.){al=CORAL;sp=vec2(.06,.25);}else mat(id,p,n,al,em,sp);if(b==0){n0=n;t0=t;}col+=thr*em;if(b==2){col+=thr*al*.3;break;}bool spc=rnd()<sp.x;vec3 nd;if(spc){nd=normalize(reflect(rd,n)+sp.y*rs());if(dot(nd,n)<0.)nd=reflect(nd,n);thr*=mix(vec3(1),al,.7);}else{nd=normalize(n+rs()*.999);thr*=al;}b++;so=p+n*.004;sv=nd;ro=so;rd=nd;if(!spc){vec3 l=normalize(KD+KR*rs());float nl=dot(n,l);if(nl>0.){lc=thr*KC*nl;rd=l;sh=true;}}}col=min(col,vec3(6.));vec3 fgc=sky(vec3(rd.x,0.,rd.z));if(t0<FAR)col=mix(fgc,col,exp(-FOGK*t0*t0));q=fc/uRes*2.-1.;vec3 d=uRo+normalize(uW+uU*q.x+uV*q.y)*t0-pRo;float z=dot(d,pW),cnt=1.;vec2 uv=vec2(dot(d,pU)/dot(pU,pU),dot(d,pV)/dot(pV,pV))/z*.5+.5;if(uF.y<.5&&z>0.&&uv.x>0.&&uv.y>0.&&uv.x<1.&&uv.y<1.){vec4 a=texture(uA,uv);float pd=length(d),e=.012*pd+.02;vec2 px=1./uRes;bool ok=abs(texture(uG,uv).w-pd)<e;if(!ok)for(int k=min(0,int(uF.x));k<12;k++){float an=float(k)*2.4+rnd()*6.;vec2 o=vec2(cos(an),sin(an))*px*(1.+float(k)*.5);if(abs(texture(uG,uv+o).w-pd)<e){a=texture(uA,uv+o);a.w=min(a.w,6.);ok=true;break;}}if(ok){cnt=min(a.w+1.,uF.z);col=mix(a.rgb,col,1./cnt);}}oC=vec4(col,cnt);oG=vec4(n0,t0);}",SC=[];
var FXH='#version 300 es\nprecision highp float;uniform sampler2D uA,uG,uB;uniform vec2 uPx;uniform vec4 uX,uY;out vec4 o;\n';
var FX={
dn:FXH+`void main(){ivec2 c=ivec2(gl_FragCoord.xy);vec4 a=texelFetch(uA,c,0),g=texelFetch(uG,c,0);
float k=uX.x*(a.w<3.?2.:1.),sw=1.,wn=mix(1.,.12,clamp((a.w-2.)/14.,0.,1.));vec3 s=a.rgb;
for(int j=-1;j<2;j++)for(int i=-1;i<2;i++){if(i==0&&j==0)continue;ivec2 q=c+ivec2(vec2(i,j)*k);
vec4 b=texelFetch(uA,q,0),h=texelFetch(uG,q,0);
float w=wn*exp(-abs(h.w-g.w)/(.02*g.w+.01))*pow(max(dot(h.xyz,g.xyz),0.),24.)*(i!=0&&j!=0?.6:1.);
if(g.w>=159.)w=wn*step(159.,h.w);s+=b.rgb*w;sw+=w;}
o=vec4(s/sw,a.w);}`,
dw:FXH+`#define S(a,b) texture(uA,v+vec2(a,b)*uPx).rgb
void main(){vec2 v=gl_FragCoord.xy*uX.xy;o=vec4(S(0,0)*.125+(S(-2,-2)+S(2,-2)+S(-2,2)+S(2,2))*.03125+(S(0,-2)+S(0,2)+S(-2,0)+S(2,0))*.0625+(S(-1,-1)+S(1,-1)+S(-1,1)+S(1,1))*.125,1);}`,
up:FXH+`#define S(a,b) texture(uA,v+vec2(a,b)*uPx).rgb
void main(){vec2 v=gl_FragCoord.xy*uX.xy;o=vec4(texture(uB,v).rgb+S(0,0)*.25+(S(-1,0)+S(1,0)+S(0,-1)+S(0,1))*.125+(S(-1,-1)+S(1,-1)+S(-1,1)+S(1,1))*.0625,1);}`,
fin:FXH+`vec3 nt(vec3 c){float s=.76,d=.15,x=min(c.r,min(c.g,c.b));c-=x<.08?x-6.25*x*x:.04;float p=max(c.r,max(c.g,c.b));if(p<s)return c;
float k=1.-s,n=1.-k*k/(p+k-s);c*=n/p;return mix(c,vec3(n),1.-1./(d*(p-n)+1.));}
float ign(vec2 p){return fract(52.9829189*fract(dot(p,vec2(.06711056,.00583715))));}
float lu(vec3 c){return dot(c,vec3(.3,.59,.11));}
#define X(o) texture(uA,v+(o)).rgb
vec3 aa(vec2 v){vec2 p=uY.xy;vec3 m=X(vec2(0));float a=lu(X(-p)),b=lu(X(vec2(p.x,-p.y))),c=lu(X(vec2(-p.x,p.y))),d=lu(X(p)),l=lu(m),
lo=min(l,min(min(a,b),min(c,d))),hi=max(l,max(max(a,b),max(c,d)));vec2 r=vec2(c+d-a-b,a+c-b-d);
r=clamp(r/(min(abs(r.x),abs(r.y))+max((a+b+c+d)*.03,.008)),-8.,8.)*p;
vec3 A=.5*(X(r*-.1667)+X(r*.1667)),B=A*.5+.25*(X(r*-.5)+X(r*.5));float lb=lu(B);return lb<lo||lb>hi?A:B;}
void main(){vec2 v=gl_FragCoord.xy*uPx,q=v-.5;float r=dot(q,q);vec3 c=aa(v);
c=mix(c,texture(uB,v).rgb*.25,.04);
c*=uX.x*(1.-.22*r);c=nt(c);c=mix(c,c*c*(3.-2.*c),.3);c=mix(c,vec3(1),uX.y);c*=1.-uX.z;
c=pow(c,vec3(.4545));c+=(ign(gl_FragCoord.xy+5.588*mod(uX.w,64.))-.5)/100.;o=vec4(c,1);}`
};
var SONG_SRC="// FATHOM soundtrack: the score. One global, SONG. Loaded on the main thread (picture sync)\n// and in front of synth.js inside the audio worker. 128 bpm, 96 bars = 180 s, A minor -> B minor at bar 64.\nvar SONG = (function () {\n var BPM = 128, BARS = 96, TAIL = 5, SPB = 60 / BPM, END = BARS * 4;\n var names = ['kick', 'snare', 'hat', 'bass', 'acid', 'arp', 'lead', 'bell', 'pad', 'sub', 'stab', 'chord', 'impact', 'crash', 'riser', 'down'];\n var T = {}, i;\n for (i = 0; i < names.length; i++) T[names[i]] = { b: [], n: [], l: [], v: [], p: [] };\n // b beat, n note (midi, or an array of midi notes for pad/stab, or a type), l length in beats, v velocity, p param\n function add(k, b, n, l, v, p) { var t = T[k]; t.b.push(b); t.n.push(n); t.l.push(l); t.v.push(v); t.p.push(p || 0); }\n\n // chords: [bass root, voicing]\n var CH = [\n [33, [57, 60, 64, 67]], // 0 Am7\n [29, [53, 57, 60, 64]], // 1 Fmaj7\n [36, [55, 60, 62, 64]], // 2 Cadd9\n [31, [55, 59, 62, 67]], // 3 G\n [29, [53, 57, 60, 64, 67]], // 4 Fmaj9\n [31, [55, 59, 62, 64]], // 5 G6\n [28, [52, 55, 59, 62]], // 6 Em7\n [33, [57, 60, 64, 71]], // 7 Am(add9)\n [26, [50, 53, 57, 60]], // 8 Dm7\n [29, [53, 57, 60, 65]], // 9 F\n [33, [57, 60, 64, 69]], // 10 Am\n [31, [55, 60, 62, 67]], // 11 Gsus4\n [30, [54, 58, 61, 66]] // 12 F# (dominant of B minor, the lift into the final drop)\n ];\n var MINOR = { 0: 1, 6: 1, 7: 1, 8: 1, 10: 1 };\n var H = [0, 0, 1, 1, 2, 2, 3, 3, 0, 1, 2, 3, 0, 1, 2, 3,\n 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3,\n 0, 0, 1, 1, 0, 0, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7,\n 8, 8, 9, 9, 10, 10, 11, 11, 0, 0, 1, 1, 3, 3, 12, 12,\n 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3,\n 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 2];\n // the hook, 8 bars, [16th step, midi, length in steps] (written in A minor)\n var HOOK = [\n [[0, 76, 3], [3, 72, 3], [6, 69, 2], [8, 76, 3], [11, 74, 3], [14, 72, 2]],\n [[0, 72, 6], [6, 69, 2], [8, 72, 4], [12, 74, 4]],\n [[0, 76, 3], [3, 79, 3], [6, 76, 2], [8, 74, 3], [11, 72, 3], [14, 74, 2]],\n [[0, 74, 8], [8, 71, 4], [12, 74, 4]],\n [[0, 76, 3], [3, 72, 3], [6, 69, 2], [8, 76, 3], [11, 74, 3], [14, 72, 2]],\n [[0, 72, 6], [6, 69, 2], [8, 72, 4], [12, 77, 4]],\n [[0, 79, 3], [3, 76, 3], [6, 72, 2], [8, 79, 3], [11, 81, 3], [14, 79, 2]],\n [[0, 79, 6], [6, 76, 2], [8, 74, 8]]\n ];\n var COUNTER = [\n [[4, 88, 4], [10, 84, 4]],\n [[4, 84, 4], [10, 81, 4], [14, 84, 2]],\n [[4, 88, 4], [10, 91, 4]],\n [[4, 86, 4], [10, 83, 4], [14, 86, 2]],\n [[4, 88, 4], [10, 93, 4]],\n [[4, 89, 4], [10, 84, 4], [14, 81, 2]],\n [[4, 91, 4], [10, 88, 4]],\n [[4, 86, 6], [12, 91, 4]]\n ];\n var ARP = [0, 2, 1, 3, 2, 1, 3, 2, 0, 2, 1, 3, 2, 3, 1, 2];\n var STAB = [0, 3, 6, 8, 11, 14], STABL = [2, 2, 1.5, 2, 2, 1.5];\n var ACID = [0, 0, 12, 0, 3.5, 0, 7, 12, 0, 0, 15.5, 12, 0, 7, 12, 19];\n var ACC = { 0: 1, 4: 1, 7: 1, 10: 1, 13: 1 }, SLD = { 2: 1, 6: 1, 11: 1, 15: 1 };\n var ENERGY = [[.15, .25], [.3, .6], [.8, .82], [.85, .88], [.75, .78], [.2, .25], [.3, .45], [.5, .85], [.93, .95], [.96, .97], [1, 1], [.7, .1]];\n var IMPV = [.5, .7, 1, .8, .8, .7, .5, .7, 1, .85, 1, .8, 1];\n\n function tr(a, t) { var o = [], j; for (j = 0; j < a.length; j++) o.push(a[j] + t); return o; }\n\n var bar, s, j;\n for (bar = 0; bar < BARS; bar++) {\n var sec = bar >> 3, ib = bar & 7, t = bar >= 64 ? 2 : 0, hc = H[bar], c = CH[hc];\n var root = c[0] + t, v = tr(c[1], t), b0 = bar * 4, q = 0.25, drums = (sec >= 2 && sec <= 4) || (sec >= 8 && sec <= 10);\n var drop = sec === 2 || sec === 3 || (sec >= 8 && sec <= 10);\n var fill = drums && ib === 7;\n\n // harmony + pad (one event per chord change)\n if (bar === 0 || H[bar] !== H[bar - 1] || bar === 64) {\n var L = 1; while (bar + L < BARS && H[bar + L] === hc && bar + L !== 64) L++;\n add('chord', b0, hc + (t ? 16 : 0), L * 4, 1);\n if (sec <= 1 || (sec >= 4 && sec <= 7) || sec >= 10)\n add('pad', b0, v, L * 4, sec === 4 ? .55 : sec === 10 ? .7 : 1);\n // a soft sustained sub under the drumless parts, so they are not thin on a big system\n if (sec === 0 || sec === 5 || sec === 6 || bar >= 90) add('sub', b0, root < 29 ? root + 12 : root, L * 4, bar < 4 ? .7 : 1);\n }\n if (ib === 0) { add('impact', b0, 0, 4, IMPV[sec]); }\n if (ib === 4 && sec > 0 && sec < 11) add('crash', b0, 0, 2, drums ? .6 : .25);\n if (bar === 12) add('riser', b0, 57, 16, .8);\n if (bar === 56) add('riser', b0, 54, 31, 1);\n if (bar === 16 || bar === 40 || bar === 64 || bar === 80 || bar === 88 || bar === 32) add('down', b0, 0, bar === 40 ? 16 : 8, bar === 32 ? .6 : 1);\n\n // kick: v velocity, p sidechain depth\n var kv = 0, kp = 0;\n if (bar >= 8 && bar < 15) { kv = .85; kp = .5; }\n else if (drums) { kv = 1; kp = .8; }\n else if (sec === 6) { kv = .5; kp = .35; }\n else if (bar >= 56 && bar < 62) { kv = .92; kp = .65; }\n else if (bar >= 88 && bar < 92) { kv = 1; kp = .7; }\n if (kv) for (s = 0; s < 4; s++) add('kick', b0 + s, 36, 1, kv, kp);\n\n // snare: n 0 = clap + snare backbeat, 1 = roll / fill snare\n if (drums || bar === 12 || bar === 13 || bar === 88 || bar === 89) {\n add('snare', b0 + 1, 0, 1, drums ? 1 : .7); add('snare', b0 + 3, 0, 1, drums ? 1 : .7);\n }\n if (fill) { add('snare', b0 + 2.5, 1, q, .5); add('snare', b0 + 3.25, 1, q, .6); add('snare', b0 + 3.5, 1, q, .75); add('snare', b0 + 3.75, 1, q, .9); }\n var rv;\n if (bar === 14) for (s = 0; s < 8; s++) add('snare', b0 + s * .5, 1, .5, .3 + s * .03);\n if (bar === 15) { for (s = 0; s < 8; s++) add('snare', b0 + s * q, 1, q, .55 + s * .025); for (s = 0; s < 16; s++) add('snare', b0 + 2 + s * .125, 1, .125, .75 + s * .016); }\n if (bar === 60) for (s = 0; s < 4; s++) add('snare', b0 + s, 1, 1, .3 + s * .02);\n if (bar === 61) for (s = 0; s < 8; s++) add('snare', b0 + s * .5, 1, .5, .4 + s * .02);\n if (bar === 62) for (s = 0; s < 16; s++) add('snare', b0 + s * q, 1, q, .55 + s * .012);\n if (bar === 63) { for (s = 0; s < 8; s++) add('snare', b0 + s * q, 1, q, .75 + s * .015); for (s = 0; s < 8; s++) add('snare', b0 + 2 + s * .125, 1, .125, .87 + s * .016); }\n\n // hats: n 0 closed, 1 open, 2 ride\n for (s = 0; s < 16; s++) {\n var hb = b0 + s * q, m = s & 3;\n if (bar >= 8 && bar < 12) { if (m === 2) add('hat', hb, 0, q, .5); }\n else if (bar >= 12 && bar < 15) { add('hat', hb, 0, q, m === 2 ? .7 : m === 0 ? .45 : .28); }\n else if (drums) {\n var full = ib >= 4 || sec !== 2;\n if (m === 2) add('hat', hb, 1, q, sec === 10 ? 1 : .8);\n else if (full || m === 0) add('hat', hb, 0, q, m === 0 ? .55 : m === 1 ? .3 : .42);\n if (sec === 10 && m === 0) add('hat', hb, 2, 1, .7);\n }\n else if (bar >= 52 && bar < 56) { if (m === 2) add('hat', hb, 0, q, .35); }\n else if (bar >= 56 && bar < 62) { add('hat', hb, 0, q, (m === 2 ? .6 : .3) * (.6 + (bar - 56) * .08)); }\n else if (bar >= 88 && bar < 92) { add('hat', hb, 0, q, m === 2 ? .6 : .3); }\n }\n\n // bass\n if (drop || bar === 88 || bar === 89) {\n for (s = 0; s < 16; s++) { m = s & 3; if (m >= 2) add('bass', b0 + s * q, root + (s === 15 && (bar & 1) && ib >= 4 ? 12 : 0), q * .8, m === 2 ? 1 : .75); }\n } else if (sec === 4) {\n var BS = [3, 6, 10, 11, 14, 15], BO = [0, 0, 12, 0, 0, 7];\n for (j = 0; j < 6; j++) add('bass', b0 + BS[j] * q, root + BO[j], q * .8, j === 2 ? .8 : 1);\n } else if (sec === 7) {\n for (s = 0; s < 8; s++) add('bass', b0 + s * .5, root, .4, s & 1 ? 1 : .8);\n }\n\n // acid line (the turn)\n if (sec === 4) for (s = 0; s < 16; s++) {\n var a = ACID[s], third = MINOR[hc] ? 3 : 4;\n a = a === 3.5 ? third : a === 15.5 ? third + 12 : a;\n if (ib >= 4 && (s & 3) === 2) a += 12;\n add('acid', b0 + s * q, root + 12 + a, q * (SLD[(s + 1) & 15] ? 1.05 : .55), ACC[s] ? 1 : .7, (ACC[s] ? 1 : 0) | (SLD[s] ? 2 : 0));\n }\n\n // arp\n var arpOn = sec <= 3 || (sec >= 6 && bar < 94);\n if (arpOn) for (s = 0; s < 16; s++) {\n if ((bar < 4 || (bar >= 48 && bar < 52)) && (s & 1)) continue;\n var an = v[ARP[s] % v.length] + 12;\n if ((ib >= 4 || sec >= 8) && (s & 3) === 3) an += 12;\n add('arp', b0 + s * q, an, q, (s & 3) === 0 ? 1 : (s & 1) ? .6 : .78);\n }\n\n // stabs (the chord hook)\n if (drop) for (j = 0; j < 6; j++) add('stab', b0 + STAB[j] * q, v, STABL[j] * q, j === 0 || j === 3 ? 1 : .8, sec === 10 ? 1 : 0);\n\n // lead hook\n if (sec === 3 || (sec >= 8 && sec <= 10) || bar === 88 || bar === 89) {\n var hk = HOOK[ib];\n for (j = 0; j < hk.length; j++) add('lead', b0 + hk[j][0] * q, hk[j][1] + t, hk[j][2] * q * .9, 1, sec === 10 ? 1 : 0);\n }\n\n // bells: breakdown melody (p 0) and the counter-melody (p 1)\n var bp = null, bi = null;\n if (!(bar & 1)) {\n if (sec === 5) { if (ib < 4) { bp = [0, 3, 6, 10]; bi = [3, 1, 2, 3]; } else { bp = [0, 3, 6, 8, 11, 14]; bi = [3, 1, 2, 3, 0, 2]; } }\n else if (sec === 6) { if (ib < 4) { bp = [0, 6, 10]; bi = [3, 2, 1]; } else { bp = [0, 3, 6, 10, 13]; bi = [3, 1, 2, 3, 2]; } }\n else if (bar >= 92) { bp = [0, 6]; bi = [3, 2]; }\n else if (bar >= 4 && bar < 8) { bp = [0, 6, 11]; bi = [3, 2, 1]; }\n }\n if (bp) for (j = 0; j < bp.length; j++) add('bell', b0 + bp[j] * .5, v[bi[j]] + 12 + (sec === 5 && ib >= 4 && (j === 3 || j === 5) ? 12 : 0), 2, j === 0 ? 1 : .8, 0);\n if (sec === 9 || sec === 10) { var cm = COUNTER[ib]; for (j = 0; j < cm.length; j++) add('bell', b0 + cm[j][0] * q, cm[j][1] + t, cm[j][2] * q, .9, 1); }\n }\n add('impact', END, 0, 4, 1);\n\n // sort every track by beat (stable), then carve the one beat of silence before bar 64\n var SIL0 = 255, SIL1 = 256, k;\n for (k = 0; k < names.length; k++) {\n var tk = T[names[k]], idx = [], o = { b: [], n: [], l: [], v: [], p: [] };\n for (i = 0; i < tk.b.length; i++) idx.push(i);\n idx.sort(function (x, y) { return tk.b[x] - tk.b[y] || x - y; });\n for (i = 0; i < idx.length; i++) {\n j = idx[i]; var bb = tk.b[j], ll = tk.l[j];\n if (bb >= SIL0 && bb < SIL1) continue;\n if (bb < SIL0 && bb + ll > SIL0) ll = SIL0 - bb;\n o.b.push(bb); o.n.push(tk.n[j]); o.l.push(ll); o.v.push(tk.v[j]); o.p.push(tk.p[j]);\n }\n T[names[k]] = o;\n }\n\n // ---- picture API ----\n function last(t, beat) { var b = t.b, lo = 0, hi = b.length - 1, r = -1, m; while (lo <= hi) { m = (lo + hi) >> 1; if (b[m] <= beat) { r = m; lo = m + 1; } else hi = m - 1; } return r; }\n function env(t, beat, tau) { var x = last(t, beat); return x < 0 ? 0 : Math.exp(-(beat - t.b[x]) * SPB / tau); }\n var O = { kick: 0, snare: 0, hat: 0, bass: 0, bassNote: 0, arp: 0, arpNote: 0, lead: 0, leadNote: 0, acid: 0, acidNote: 0, bell: 0, bellNote: 0, chord: 0, chordT: 0, riser: 0, energy: 0, impact: 0, bar: 0, section: 0 };\n var NT = ['bass', 'arp', 'lead', 'acid', 'bell'];\n function at(beat) {\n var n, x, tk;\n if (!(beat >= 0 && beat <= END)) {\n for (n in O) O[n] = 0;\n return O;\n }\n O.kick = env(T.kick, beat, .18); O.snare = env(T.snare, beat, .2); O.hat = env(T.hat, beat, .06); O.impact = env(T.impact, beat, 1.5);\n for (n = 0; n < 5; n++) {\n tk = T[NT[n]]; x = last(tk, beat);\n O[NT[n]] = x < 0 ? 0 : Math.exp(-(beat - tk.b[x]) * SPB / .3);\n O[NT[n] + 'Note'] = x < 0 ? 0 : tk.n[x];\n }\n x = last(T.chord, beat); O.chord = T.chord.n[x]; O.chordT = beat - T.chord.b[x];\n O.riser = beat >= 48 && beat < 64 ? (beat - 48) / 16 : beat >= 224 && beat < 255 ? (beat - 224) / 31 : 0;\n var bar = Math.floor(beat / 4), sec = Math.min(11, bar >> 3), e = ENERGY[sec];\n O.energy = e[0] + (e[1] - e[0]) * Math.min(1, (beat - sec * 32) / 32);\n O.bar = bar; O.section = bar >> 3;\n return O;\n }\n function hits(name, b0, b1) {\n var t = T[name], out = [], x;\n if (!t) return out;\n x = last(t, b0); if (x < 0) x = 0;\n for (; x < t.b.length && t.b[x] < b1; x++) if (t.b[x] >= b0 && out[out.length - 1] !== t.b[x]) out.push(t.b[x]);\n return out;\n }\n return { bpm: BPM, bars: BARS, len: BARS * 4 * SPB, tail: TAIL, spb: SPB, tr: T, names: names, at: at, hits: hits };\n})();\n";(0,eval)(SONG_SRC);
var SYN=SONG_SRC+"// FATHOM soundtrack: the synth. Body of a Web Worker (song.js is concatenated in front), also runs under Node.\n// renderer(sr) -> {total, next(n) -> {L,R}}. Everything is derived from sr; output is identical however next() is chunked.\nfunction renderer(sr, opt) {\n opt = opt || {};\n var S = SONG, T = S.tr, PI = Math.PI, TAU = 2 * PI, BS = 64, i, j;\n var spb = sr * 60 / S.bpm, spt = spb / 8, isr = 1 / sr, fmax = sr * 0.45;\n var totalN = Math.round((S.len + S.tail) * sr);\n var seed = 20261111, ns = 987654321;\n function rnd() { seed = (Math.imul(seed, 1664525) + 1013904223) | 0; return (seed >>> 0) / 4294967296; }\n function mtof(n) { return 440 * Math.pow(2, (n - 69) / 12); }\n function tc(sec) { return Math.exp(-1 / (sec * sr)); }\n function lpc(hz) { return 1 - Math.exp(-TAU * hz / sr); }\n function ft(x) { return x < -3 ? -1 : x > 3 ? 1 : x * (27 + x * x) / (27 + 9 * x * x); }\n function xr(bar, b0, b1, v0, v1) { var x = (bar - b0) / (b1 - b0); x = x < 0 ? 0 : x > 1 ? 1 : x; return v0 * Math.pow(v1 / v0, x); }\n var solo = opt.solo || null, raw = !!opt.raw;\n function gn(name, g) { return solo && solo.indexOf(name) < 0 ? 0 : g; }\n var G = {\n kick: gn('kick', .47), snare: gn('snare', .38), hat: gn('hat', .26), bass: gn('bass', .5), acid: gn('acid', .34),\n arp: gn('arp', .32), lead: gn('lead', .46), bell: gn('bell', .2), pad: gn('pad', .34), stab: gn('stab', .72),\n impact: gn('impact', .6), crash: gn('impact', .28), riser: gn('riser', .3), down: gn('down', .22)\n };\n\n var tL = new Float64Array(BS), tR = new Float64Array(BS), uB = new Float64Array(BS), eB = new Float64Array(BS);\n var mL = new Float64Array(BS), mR = new Float64Array(BS), dL = new Float64Array(BS), dR = new Float64Array(BS);\n var rv = new Float64Array(BS), dl = new Float64Array(BS), oL = new Float64Array(BS), oR = new Float64Array(BS);\n\n // ---------- building blocks ----------\n var envs = [];\n function mkEnv(a, d, s, r) { var e = { v: 0, st: 0, ai: 1 / (a * sr), dc: tc(d), s: s, rc: tc(r) }; envs.push(e); return e; }\n function envRun(e, n) {\n var v = e.v, st = e.st, ai = e.ai, dc = e.dc, s = e.s, rc = e.rc, i;\n for (i = 0; i < n; i++) {\n if (st === 1) { v += ai; if (v >= 1) { v = 1; st = 2; } }\n else if (st === 2) { v = s + (v - s) * dc; if (v < 1e-5) { v = 0; st = 0; } }\n else if (st === 3) { v *= rc; if (v < 1e-5) { v = 0; st = 0; } }\n eB[i] = v;\n }\n e.v = v; e.st = st;\n }\n // PolyBLEP saw, added into tL/tR\n function sawAdd(ph, inc, n, gl, gr) {\n var hi = 1 - inc, ri = 1 / inc, v, t, i;\n for (i = 0; i < n; i++) {\n ph += inc; if (ph >= 1) ph -= 1;\n v = ph + ph - 1;\n if (ph < inc) { t = ph * ri; v -= t + t - t * t - 1; }\n else if (ph > hi) { t = (ph - 1) * ri; v -= t * t + t + t + 1; }\n tL[i] += v * gl; tR[i] += v * gr;\n }\n return ph;\n }\n function zero(n) { for (var i = 0; i < n; i++) { tL[i] = 0; tR[i] = 0; } }\n // ZDF state variable filter (TPT), stereo in place on tL/tR, coefficients interpolated over the block\n function mkF() { var f = new Float64Array(7); f[4] = -1; return f; }\n function svf(f, n, fc, k, cL, cB, cH) {\n var g = Math.tan(PI * (fc > fmax ? fmax : fc) * isr), A1 = 1 / (1 + g * (g + k)), A2 = g * A1, A3 = g * A2;\n var a1 = f[4], a2 = f[5], a3 = f[6];\n if (a1 < 0) { a1 = A1; a2 = A2; a3 = A3; }\n var d1 = (A1 - a1) / n, d2 = (A2 - a2) / n, d3 = (A3 - a3) / n, l1 = f[0], l2 = f[1], r1 = f[2], r2 = f[3], v1, v2, v3, x, i;\n for (i = 0; i < n; i++) {\n a1 += d1; a2 += d2; a3 += d3;\n x = tL[i]; v3 = x - l2; v1 = a1 * l1 + a2 * v3; v2 = l2 + a2 * l1 + a3 * v3; l1 = 2 * v1 - l1; l2 = 2 * v2 - l2;\n tL[i] = cL * v2 + cB * v1 + cH * (x - k * v1 - v2);\n x = tR[i]; v3 = x - r2; v1 = a1 * r1 + a2 * v3; v2 = r2 + a2 * r1 + a3 * v3; r1 = 2 * v1 - r1; r2 = 2 * v2 - r2;\n tR[i] = cL * v2 + cB * v1 + cH * (x - k * v1 - v2);\n }\n f[0] = l1; f[1] = l2; f[2] = r1; f[3] = r2; f[4] = A1; f[5] = A2; f[6] = A3;\n }\n // mono version on an arbitrary buffer\n function svf1(f, b, n, fc, k, cL, cB, cH) {\n var g = Math.tan(PI * (fc > fmax ? fmax : fc) * isr), a1 = 1 / (1 + g * (g + k)), a2 = g * a1, a3 = g * a2;\n var l1 = f[0], l2 = f[1], v1, v2, v3, x, i;\n for (i = 0; i < n; i++) {\n x = b[i]; v3 = x - l2; v1 = a1 * l1 + a2 * v3; v2 = l2 + a2 * l1 + a3 * v3; l1 = 2 * v1 - l1; l2 = 2 * v2 - l2;\n b[i] = cL * v2 + cB * v1 + cH * (x - k * v1 - v2);\n }\n f[0] = l1; f[1] = l2;\n }\n function mix(n, g, rs, ds, bL, bR) {\n var l, r, m, i;\n for (i = 0; i < n; i++) { l = tL[i] * g; r = tR[i] * g; bL[i] += l; bR[i] += r; m = (l + r) * .5; rv[i] += m * rs; dl[i] += m * ds; }\n }\n function mixM(b, n, g, rs, ds, bL, bR) {\n var m, i;\n for (i = 0; i < n; i++) { m = b[i] * g; bL[i] += m; bR[i] += m; rv[i] += m * rs; dl[i] += m * ds; }\n }\n\n // ---------- 7-voice unison supersaw layer (paraphonic: one filter + envelope per layer) ----------\n var DET = [-0.11002313, -0.06288439, -0.01952356, 0, 0.01991221, 0.06216538, 0.10745242];\n var PAN = [-1, 0.66, -0.33, 0, 0.33, -0.66, 1];\n function mkSaw(maxNotes, det, width, e, fa, fd) {\n var m = maxNotes * 7, o = { ph: new Float64Array(m), inc: new Float64Array(m), gl: new Float64Array(m), gr: new Float64Array(m), n: 0, det: det, e: e, f: mkF(), h: new Float64Array(2), off: 0, vel: 1, norm: 1, fe: 0, fa: fa, fd: fd }, k, a, cg;\n for (k = 0; k < m; k++) {\n o.ph[k] = rnd(); j = k % 7; a = (PAN[j] * width * (((k / 7) | 0) & 1 ? -1 : 1) + 1) * PI / 4; cg = j === 3 ? 1 : .82;\n o.gl[k] = Math.cos(a) * cg; o.gr[k] = Math.sin(a) * cg;\n }\n return o;\n }\n function sawNotes(o, notes, cnt, oct) {\n var c = 0, a, f, q;\n for (q = 0; q <= (oct ? 1 : 0); q++) for (a = 0; a < cnt; a++) { f = mtof(notes[a] + q * 12) * isr; for (j = 0; j < 7; j++) o.inc[c++] = f * (1 + DET[j] * o.det); }\n o.n = c; o.norm = 1 / Math.sqrt(c);\n }\n function sawRun(o, n, fc, k, hpc) {\n if (o.e.st === 0) return false;\n var c = o.n, q, i, a, g = o.norm * o.vel, h0 = o.h[0], h1 = o.h[1];\n zero(n);\n for (q = 0; q < c; q++) o.ph[q] = sawAdd(o.ph[q], o.inc[q], n, o.gl[q], o.gr[q]);\n svf(o.f, n, fc * (1 - o.fa + o.fa * o.fe), k, 1, 0, 0);\n o.fe *= Math.exp(-n / (o.fd * sr));\n envRun(o.e, n);\n for (i = 0; i < n; i++) {\n a = tL[i]; h0 += hpc * (a - h0); tL[i] = (a - h0) * eB[i] * g;\n a = tR[i]; h1 += hpc * (a - h1); tR[i] = (a - h1) * eB[i] * g;\n }\n o.h[0] = h0; o.h[1] = h1;\n return true;\n }\n var PD = mkSaw(5, .30, 1, mkEnv(.35, 1, 1, 1.1), 0, 1);\n var ST = mkSaw(8, .24, 1, mkEnv(.003, .25, .55, .12), .6, .14);\n var LD = mkSaw(2, .17, .7, mkEnv(.006, .3, .75, .14), .35, .2);\n var gated = [PD, ST, LD];\n\n // ---------- pluck arp (4 voices) ----------\n var PL = [], plN = 0;\n for (i = 0; i < 4; i++) { PL.push({ p1: rnd(), p2: rnd(), i1: 0, i2: 0, e: mkEnv(.002, .2, 0, .07), f: mkF(), fe: 0, vel: 0, off: 0 }); gated.push(PL[i]); }\n function plRun(o, n, fc) {\n zero(n);\n o.p1 = sawAdd(o.p1, o.i1, n, 1, .3); o.p2 = sawAdd(o.p2, o.i2, n, .3, 1);\n svf(o.f, n, fc * (.35 + 2.2 * o.fe), .55, 1, 0, 0);\n o.fe *= Math.exp(-n / (.08 * sr));\n envRun(o.e, n);\n var g = o.vel, i;\n for (i = 0; i < n; i++) { tL[i] *= eB[i] * g; tR[i] *= eB[i] * g; }\n }\n\n // ---------- FM bell (6 voices) ----------\n var BL = [], blN = 0, blAtt = 1 / (.002 * sr);\n for (i = 0; i < 6; i++) BL.push({ pc: 0, pm: 0, ic: 0, im: 0, ix: 0, a: 0, at: 0, da: 1, di: 1, gl: 1, gr: 1 });\n function bellRun(n) {\n var any = false, q, o, i, pc, pm, ic, im, ix, a, at, da, di, s;\n for (q = 0; q < 6; q++) {\n o = BL[q]; if (o.a < 1e-4) continue;\n if (!any) { zero(n); any = true; }\n pc = o.pc; pm = o.pm; ic = o.ic; im = o.im; ix = o.ix; a = o.a; at = o.at; da = o.da; di = o.di;\n var gl = o.gl, gr = o.gr;\n for (i = 0; i < n; i++) {\n pc += ic; if (pc >= 1) pc -= 1; pm += im; if (pm >= 1) pm -= 1;\n if (at < 1) at += blAtt;\n a *= da; ix = .25 + (ix - .25) * di;\n s = Math.sin(TAU * pc + ix * Math.sin(TAU * pm)) * a * at;\n tL[i] += s * gl; tR[i] += s * gr;\n }\n o.pc = pc; o.pm = pm; o.ix = ix; o.a = a; o.at = at;\n }\n return any;\n }\n\n // ---------- mono saw -> tanh ladder (bass and acid) ----------\n function mkLad(e, fd) { var o = { ph: rnd(), sp: 0, inc: 0, incT: 0, gc: 1, s1: 0, s2: 0, s3: 0, s4: 0, y4: 0, G: -1, e: e, fe: 0, fd: fd, vel: 0, off: 0 }; gated.push(o); return o; }\n function ladRun(o, n, fc, res, drive, mid, sub) {\n envRun(o.e, n);\n var lim = sr * .2, g = Math.tan(PI * (fc > lim ? lim : fc) * isr), GT = g / (1 + g), Gc = o.G < 0 ? GT : o.G, dG = (GT - Gc) / n; o.G = GT;\n var ph = o.ph, sp = o.sp, inc = o.inc, incT = o.incT, gc = o.gc, s1 = o.s1, s2 = o.s2, s3 = o.s3, s4 = o.s4, y = o.y4, v, t, x, i, comp = mid * (1 + res * .5) * o.vel, sv = sub * o.vel;\n for (i = 0; i < n; i++) {\n inc += (incT - inc) * gc;\n ph += inc; if (ph >= 1) ph -= 1;\n v = ph + ph - 1;\n if (ph < inc) { t = ph / inc; v -= t + t - t * t - 1; }\n else if (ph > 1 - inc) { t = (ph - 1) / inc; v -= t * t + t + t + 1; }\n x = v * drive - res * y; x = x < -3 ? -1 : x > 3 ? 1 : x * (27 + x * x) / (27 + 9 * x * x);\n Gc += dG;\n t = (x - s1) * Gc; y = t + s1; s1 = y + t;\n t = (y - s2) * Gc; y = t + s2; s2 = y + t;\n t = (y - s3) * Gc; y = t + s3; s3 = y + t;\n t = (y - s4) * Gc; y = t + s4; s4 = y + t;\n sp += inc; if (sp >= 1) sp -= 1;\n tL[i] = (y * comp + (sv ? Math.sin(TAU * sp) * sv : 0)) * eB[i];\n }\n o.ph = ph; o.sp = sp; o.inc = inc; o.s1 = s1; o.s2 = s2; o.s3 = s3; o.s4 = s4; o.y4 = y;\n o.fe *= Math.exp(-n / (o.fd * sr));\n }\n var BA = mkLad(mkEnv(.003, .12, .6, .03), .07);\n var AC = mkLad(mkEnv(.002, .18, .5, .025), .11);\n var SB = mkLad(mkEnv(.3, 1, 1, .5), .2);\n\n // ---------- kick ----------\n var K = { on: 0, t: 0, ph: 0, p1: 0, p2: 0, a: 0, cl: 0, vel: 0, l1: 0, l2: 0 };\n var kc1 = tc(.05), kc2 = tc(.005), kca = tc(.11), kcc = tc(.0018), kHold = Math.round(.065 * sr);\n var kd = 1e9, kDepth = 0, duckLen = 1 / (.3 * sr), dk = 1, dkc = lpc(110);\n function kickRun(n, lp) {\n var t = K.t, ph = K.ph, p1 = K.p1, p2 = K.p2, a = K.a, cl = K.cl, vel = K.vel, l1 = K.l1, l2 = K.l2, s = ns, x, i;\n var c = lp < 16000 ? lpc(lp) : 1;\n for (i = 0; i < n; i++) {\n p1 *= kc1; p2 *= kc2;\n ph += (47 + 115 * p1 + 420 * p2) * isr; if (ph >= 1) ph -= 1;\n if (t > kHold) a *= kca; t++;\n x = Math.sin(TAU * ph) * a * 2.2;\n x = x * (27 + x * x) / (27 + 9 * x * x);\n cl *= kcc; s = (Math.imul(s, 1664525) + 1013904223) | 0; x += s * 4.6566e-10 * cl * .22;\n x *= vel;\n l1 += c * (x - l1); l2 += c * (l1 - l2);\n tL[i] = l2;\n }\n K.t = t; K.ph = ph; K.p1 = p1; K.p2 = p2; K.a = a; K.cl = cl; K.l1 = l1; K.l2 = l2; ns = s;\n if (a < 2e-4) K.on = 0;\n }\n\n // ---------- clap / snare ----------\n var SN = { on: 0, t: 0, ty: 0, vel: 0, ce: 0, ne: 0, te: 0, pe: 0, ph: 0, fb: mkF(), fh: mkF() };\n var snD = Math.round(.011 * sr), snC1 = tc(.005), snC2 = tc(.075), snN = tc(.085), snNr = tc(.05), snT = tc(.045), snP = tc(.014);\n function snareRun(n) {\n var t = SN.t, ce = SN.ce, ne = SN.ne, te = SN.te, pe = SN.pe, ph = SN.ph, s = ns, i, cc, roll = SN.ty === 1, nd = roll ? snNr : snN, vel = SN.vel;\n var ca = roll ? 0 : .95, na = roll ? .75 : .5, ta = roll ? .55 : .45;\n for (i = 0; i < n; i++) {\n if (t === snD || t === 2 * snD || t === 3 * snD) ce = 1;\n cc = t < 3 * snD ? snC1 : snC2; ce *= cc; ne *= nd; te *= snT; pe *= snP; t++;\n s = (Math.imul(s, 1664525) + 1013904223) | 0; uB[i] = s * 4.6566e-10 * ce;\n s = (Math.imul(s, 1664525) + 1013904223) | 0; tL[i] = s * 4.6566e-10 * ne;\n s = (Math.imul(s, 1664525) + 1013904223) | 0; tR[i] = s * 4.6566e-10 * ne;\n ph += (185 + 160 * pe) * isr; if (ph >= 1) ph -= 1;\n eB[i] = Math.sin(TAU * ph) * te;\n }\n svf1(SN.fb, uB, n, 1250, .7, 0, 1, 0);\n svf(SN.fh, n, 2200, .9, 0, .3, 1);\n for (i = 0; i < n; i++) { cc = uB[i] * ca * 1.6 + eB[i] * ta; tL[i] = (tL[i] * na + cc) * vel; tR[i] = (tR[i] * na + cc) * vel; }\n SN.t = t; SN.ce = ce; SN.ne = ne; SN.te = te; SN.pe = pe; SN.ph = ph; ns = s;\n if (ce < 1e-4 && ne < 1e-4 && te < 1e-4 && t > 4 * snD) SN.on = 0;\n }\n\n // ---------- hats ----------\n var HT = { c: 0, o: 0, r: 0, f: mkF(), f2: mkF() }, hC = tc(.02), hO = tc(.085), hR = tc(.2);\n function hatRun(n) {\n var c = HT.c, o = HT.o, r = HT.r, s = ns, i, h;\n for (i = 0; i < n; i++) { s = (Math.imul(s, 1664525) + 1013904223) | 0; uB[i] = s * 4.6566e-10; }\n ns = s;\n svf1(HT.f, uB, n, 7800, .5, 0, .25, 1);\n svf1(HT.f2, uB, n, 5200, 1.4, 0, 0, 1);\n for (i = 0; i < n; i++) {\n c *= hC; o *= hO; r *= hR; h = uB[i];\n tL[i] = h * (c * .95 + o * .7 + r * .45); tR[i] = h * (c * .7 + o * .95 + r * .5);\n }\n HT.c = c; HT.o = o; HT.r = r;\n }\n\n // ---------- noise sweeps: riser (with a rising tone) and downlifter ----------\n function mkSw(up) { return { on: 0, t: 0, dur: 1, up: up, vel: 0, f: mkF(), p1: rnd(), p2: rnd(), f0: 110 }; }\n var RS = mkSw(1), DN = mkSw(0);\n function sweepRun(o, n) {\n var x = o.t / o.dur, amp, fc, s = ns, i;\n if (x > 1) x = 1;\n if (o.up) { fc = 260 * Math.pow(42, x); amp = (.04 + .96 * x * x) * o.vel; }\n else { fc = 9000 * Math.pow(1 / 28, x); amp = (1 - x) * (1 - x) * o.vel; }\n for (i = 0; i < n; i++) {\n s = (Math.imul(s, 1664525) + 1013904223) | 0; tL[i] = s * 4.6566e-10 * amp;\n s = (Math.imul(s, 1664525) + 1013904223) | 0; tR[i] = s * 4.6566e-10 * amp;\n }\n ns = s;\n if (o.up) { var f = o.f0 * Math.pow(4, x) * isr, ta = amp * .5; o.p1 = sawAdd(o.p1, f * .994, n, ta, ta * .3); o.p2 = sawAdd(o.p2, f * 1.006, n, ta * .3, ta); }\n svf(o.f, n, fc, .45, .5, 1, 0);\n o.t += n; if (o.t >= o.dur) o.on = 0;\n }\n\n // ---------- impact: sub drop + crash ----------\n var IM = { on: 0, t: 0, vel: 0, sub: 0, ph: 0, pe: 0, ae: 0, ce: 0, f: mkF() };\n var imP = tc(.14), imA = tc(.75), imC = tc(.8), imEnd = Math.round(7 * sr);\n function impactRun(n) {\n var ph = IM.ph, pe = IM.pe, ae = IM.ae, ce = IM.ce, s = ns, i, x, sv = IM.sub * IM.vel, cv = IM.vel;\n for (i = 0; i < n; i++) {\n pe *= imP; ae *= imA; ce *= imC;\n ph += (38 + 75 * pe) * isr; if (ph >= 1) ph -= 1;\n x = Math.sin(TAU * ph) * ae * 1.6; uB[i] = x * (27 + x * x) / (27 + 9 * x * x) * sv;\n s = (Math.imul(s, 1664525) + 1013904223) | 0; tL[i] = s * 4.6566e-10 * ce * cv;\n s = (Math.imul(s, 1664525) + 1013904223) | 0; tR[i] = s * 4.6566e-10 * ce * cv;\n }\n ns = s;\n svf(IM.f, n, 3200, 1.1, 0, .5, 1);\n IM.ph = ph; IM.pe = pe; IM.ae = ae; IM.ce = ce; IM.t += n;\n if (IM.t > imEnd) IM.on = 0;\n }\n\n // ---------- ping-pong delay (3/16) ----------\n function line(len) { var z = 1; while (z < len + 64) z <<= 1; return new Float64Array(z); }\n var dN = Math.round(spb * .75), dbL = line(dN), dbR = line(dN), dM = dbL.length - 1, dW = 0, dHp = 0, dLp1 = 0, dLp2 = 0;\n var dHc = lpc(320), dLc = lpc(5200);\n function delayRun(n) {\n var w = dW, hp = dHp, l1 = dLp1, l2 = dLp2, i, x, a, b;\n for (i = 0; i < n; i++) {\n x = dl[i] + 1e-18; hp += dHc * (x - hp); x -= hp;\n a = dbL[(w - dN) & dM]; b = dbR[(w - dN) & dM];\n l1 += dLc * (a - l1); l2 += dLc * (b - l2);\n dbL[w & dM] = x + l2 * .55; dbR[w & dM] = l1 * .8;\n w++;\n mL[i] += l1 * .9; mR[i] += l2 * .9; rv[i] += (l1 + l2) * .12;\n }\n dW = w; dHp = hp; dLp1 = l1; dLp2 = l2;\n }\n\n // ---------- Dattorro plate reverb ----------\n var rsc = sr / 29761;\n function RL(x) { return Math.max(2, Math.round(x * rsc)); }\n var nPre = Math.round(.018 * sr), nI1 = RL(142), nI2 = RL(107), nI3 = RL(379), nI4 = RL(277), nA1 = RL(672), nD1 = RL(4453), nA2 = RL(1800), nD2 = RL(3720), nB1 = RL(908), nE1 = RL(4217), nB2 = RL(2656), nE2 = RL(3163);\n var exc = 9 * rsc;\n var bPre = line(nPre), bI1 = line(nI1), bI2 = line(nI2), bI3 = line(nI3), bI4 = line(nI4), bA1 = line(nA1 + exc + 2), bD1 = line(nD1), bA2 = line(nA2), bD2 = line(nD2), bB1 = line(nB1 + exc + 2), bE1 = line(nE1), bB2 = line(nB2), bE2 = line(nE2);\n var revLines = [bPre, bI1, bI2, bI3, bI4, bA1, bD1, bA2, bD2, bB1, bE1, bB2, bE2];\n var mPre = bPre.length - 1, mI1 = bI1.length - 1, mI2 = bI2.length - 1, mI3 = bI3.length - 1, mI4 = bI4.length - 1, mA1 = bA1.length - 1, mD1 = bD1.length - 1, mA2 = bA2.length - 1, mD2 = bD2.length - 1, mB1 = bB1.length - 1, mE1 = bE1.length - 1, mB2 = bB2.length - 1, mE2 = bE2.length - 1;\n var tA = RL(266), tB = RL(2974), tC = RL(1913), tD = RL(1996), tE = RL(1990), tF = RL(187), tG = RL(1066), tH = RL(353), tI = RL(3627), tJ = RL(1228), tK = RL(2673), tM = RL(2111), tN = RL(335), tO = RL(121);\n var rW = 0, rHp = 0, rLp = 0, rDl = 0, rDr = 0, rLs = 0, rLc = 1, rLe = TAU * .7 / sr, rLe2 = TAU * 1.1 / sr, rMs = 0, rMc = 1;\n var rHc = lpc(260), rLpc = lpc(9500), rDamp = lpc(5200), rDec = .69, rWet = .55;\n function reverbRun(n) {\n var w = rW, hp = rHp, lp = rLp, dmL = rDl, dmR = rDr, ls = rLs, lc = rLc, ms = rMs, mc = rMc, i, x, d, v, y, fp, ip, fr, fbL, fbR, yl, yr, dec = rDec;\n for (i = 0; i < n; i++) {\n x = rv[i] + 1e-18; hp += rHc * (x - hp); x -= hp; lp += rLpc * (x - lp);\n bPre[w & mPre] = lp; x = bPre[(w - nPre) & mPre];\n d = bI1[(w - nI1) & mI1]; v = x - .75 * d; bI1[w & mI1] = v; x = d + .75 * v;\n d = bI2[(w - nI2) & mI2]; v = x - .75 * d; bI2[w & mI2] = v; x = d + .75 * v;\n d = bI3[(w - nI3) & mI3]; v = x - .625 * d; bI3[w & mI3] = v; x = d + .625 * v;\n d = bI4[(w - nI4) & mI4]; v = x - .625 * d; bI4[w & mI4] = v; x = d + .625 * v;\n ls += rLe * lc; lc -= rLe * ls; ms += rLe2 * mc; mc -= rLe2 * ms;\n fbL = bD2[(w - nD2) & mD2]; fbR = bE2[(w - nE2) & mE2];\n // left half\n fp = nA1 + exc * ls; ip = fp | 0; fr = fp - ip;\n d = bA1[(w - ip) & mA1] * (1 - fr) + bA1[(w - ip - 1) & mA1] * fr;\n v = x + dec * fbR + .7 * d; bA1[w & mA1] = v; y = d - .7 * v;\n bD1[w & mD1] = y; y = bD1[(w - nD1) & mD1];\n dmL += rDamp * (y - dmL); y = dmL * dec;\n d = bA2[(w - nA2) & mA2]; v = y - .5 * d; bA2[w & mA2] = v; y = d + .5 * v;\n bD2[w & mD2] = y;\n // right half\n fp = nB1 + exc * ms; ip = fp | 0; fr = fp - ip;\n d = bB1[(w - ip) & mB1] * (1 - fr) + bB1[(w - ip - 1) & mB1] * fr;\n v = x + dec * fbL + .7 * d; bB1[w & mB1] = v; y = d - .7 * v;\n bE1[w & mE1] = y; y = bE1[(w - nE1) & mE1];\n dmR += rDamp * (y - dmR); y = dmR * dec;\n d = bB2[(w - nB2) & mB2]; v = y - .5 * d; bB2[w & mB2] = v; y = d + .5 * v;\n bE2[w & mE2] = y;\n yl = bE1[(w - tA) & mE1] + bE1[(w - tB) & mE1] - bB2[(w - tC) & mB2] + bE2[(w - tD) & mE2] - bD1[(w - tE) & mD1] - bA2[(w - tF) & mA2] - bD2[(w - tG) & mD2];\n yr = bD1[(w - tH) & mD1] + bD1[(w - tI) & mD1] - bA2[(w - tJ) & mA2] + bD2[(w - tK) & mD2] - bE1[(w - tM) & mE1] - bB2[(w - tN) & mB2] - bE2[(w - tO) & mE2];\n mL[i] += yl * rWet; mR[i] += yr * rWet;\n w++;\n }\n rW = w; rHp = hp; rLp = lp; rDl = dmL; rDr = dmR; rLs = ls; rLc = lc; rMs = ms; rMc = mc;\n }\n\n // ---------- master: duck, mono bass, compressor, soft clip, lookahead limiter, gates ----------\n var LA = Math.round(.004 * sr), lbL = line(LA), lbR = line(LA), lgB = line(LA), lM = lbL.length - 1, lW = 0;\n var aL = 0, aR = 0, airC = lpc(3800), airK = .45;\n var sh1 = 0, sh2 = 0, shc = lpc(120), hL = 0, hR = 0, hpc = lpc(22);\n var cEnv = 0, cAtt = lpc(1 / (TAU * .008)), cRel = lpc(1 / (TAU * .16)), cT = .34, cMake = 1.3, mTrim = 1;\n var lEnv = 1, lHold = 0, lRel = lpc(1 / (TAU * .09)), lSum = LA, lCeil = .87;\n for (i = 0; i < lgB.length; i++) lgB[i] = 1;\n var s255 = Math.round(255 * spb), s256 = Math.round(256 * spb), gFade = Math.round(.006 * sr), tFade = Math.round(1.6 * sr), pos = 0;\n function masterRun(n) {\n var i, l, r, m, s, p, g, x, q = pos - LA, w = lW, t, trim = mTrim;\n var kdl = kd, depth = kDepth, d = dk, a1 = sh1, a2 = sh2, h1 = hL, h2 = hR, ce = cEnv, e1 = aL, e2 = aR, le = lEnv, lh = lHold, sum = lSum;\n for (i = 0; i < n; i++) {\n // sidechain duck of everything but the drums\n x = kdl * duckLen; kdl++;\n if (x < 1) { x = 1 - x; g = 1 - depth * x * x; } else g = 1;\n d += dkc * (g - d);\n l = (mL[i] * d + dL[i]) * trim + 1e-18; r = (mR[i] * d + dR[i]) * trim + 1e-18;\n // mono below ~120 Hz, DC / rumble high-pass\n m = (l + r) * .5; s = (l - r) * .5;\n a1 += shc * (s - a1); s -= a1; a2 += shc * (s - a2); s -= a2;\n l = m + s; r = m - s;\n h1 += hpc * (l - h1); l -= h1; h2 += hpc * (r - h2); r -= h2;\n // air shelf (+3 dB above ~4 kHz)\n e1 += airC * (l - e1); l += airK * (l - e1); e2 += airC * (r - e2); r += airK * (r - e2);\n // soft compressor, 2:1 above threshold\n p = l < 0 ? -l : l; x = r < 0 ? -r : r; if (x > p) p = x;\n ce += (p > ce ? cAtt : cRel) * (p - ce);\n g = raw ? 1 : ce > cT ? Math.sqrt(cT / ce) * cMake : cMake;\n l *= g; r *= g;\n // tanh-shaped soft clip\n if (!raw) {\n l = l < -3 ? -1 : l > 3 ? 1 : l * (27 + l * l) / (27 + 9 * l * l);\n r = r < -3 ? -1 : r > 3 ? 1 : r * (27 + r * r) / (27 + 9 * r * r);\n }\n // lookahead limiter: instant attack + hold, smoothed by a boxcar as long as the lookahead\n p = l < 0 ? -l : l; x = r < 0 ? -r : r; if (x > p) p = x;\n g = p > lCeil && !raw ? lCeil / p : 1;\n if (g <= le) { le = g; lh = LA; } else if (lh > 0) lh--; else le += lRel * (1 - le);\n t = w & lM;\n sum += le - lgB[(w - LA) & lM]; lgB[t] = le;\n x = lbL[(w - LA) & lM]; p = lbR[(w - LA) & lM]; lbL[t] = l; lbR[t] = r; w++;\n g = sum / LA;\n // output gate: the beat of silence before bar 64, and the fade at the very end\n if (q >= s255 - gFade) {\n if (q < s255) g *= (s255 - q) / gFade;\n else if (q < s256) g = 0;\n else if (q >= totalN - tFade) { t = (totalN - q) / tFade; g *= t < 0 ? 0 : t * t * (3 - 2 * t); }\n }\n q++;\n x *= g; p *= g;\n if (raw) { oL[i] = x; oR[i] = p; } else { oL[i] = x > .9 ? .9 : x < -.9 ? -.9 : x; oR[i] = p > .9 ? .9 : p < -.9 ? -.9 : p; }\n }\n kd = kdl; dk = d; sh1 = a1; sh2 = a2; hL = h1; hR = h2; cEnv = ce; aL = e1; aR = e2; lEnv = le; lHold = lh; lSum = sum; lW = w;\n }\n\n // ---------- sequencer ----------\n var evT = [], evK = [], evI = [], order = [], names = S.names;\n for (i = 0; i < names.length; i++) { var tk = T[names[i]]; for (j = 0; j < tk.b.length; j++) { order.push(evT.length); evT.push(Math.round(tk.b[j] * 8)); evK.push(names[i]); evI.push(j); } }\n order.sort(function (a, b) { return evT[a] - evT[b] || a - b; });\n var evp = 0, tick = 0, nextTick = 0, killTick = 255 * 8;\n function offAt(tk, x) { return Math.round((tk.b[x] + tk.l[x]) * spb); }\n function killAll() {\n var q;\n for (q = 0; q < envs.length; q++) { envs[q].v = 0; envs[q].st = 0; }\n for (q = 0; q < 6; q++) BL[q].a = 0;\n K.on = 0; SN.on = 0; HT.c = HT.o = HT.r = 0; RS.on = 0; DN.on = 0; IM.on = 0;\n for (q = 0; q < revLines.length; q++) revLines[q].fill(0);\n dbL.fill(0); dbR.fill(0); rDl = rDr = rHp = rLp = dHp = dLp1 = dLp2 = 0;\n }\n function fire(k, x) {\n var tk = T[k], n = tk.n[x], v = tk.v[x], p = tk.p[x], o, f;\n switch (k) {\n case 'kick': K.on = 1; K.t = 0; K.ph = 0; K.p1 = 1; K.p2 = 1; K.a = 1; K.cl = 1; K.vel = v; kd = 0; kDepth = p; break;\n case 'snare': SN.on = 1; SN.t = 0; SN.ty = n; SN.vel = v; SN.ce = n ? 0 : 1; SN.ne = 1; SN.te = 1; SN.pe = 1; SN.ph = 0; break;\n case 'hat': if (n === 0) { HT.c = v; HT.o *= .3; } else if (n === 1) HT.o = v; else HT.r = v; break;\n case 'bass': o = BA; o.incT = mtof(n) * isr; o.inc = o.incT; o.gc = 1; o.e.st = 1; o.fe = 1; o.vel = v; o.off = offAt(tk, x); break;\n case 'sub': o = SB; o.incT = mtof(n) * isr; if (o.e.st === 0) o.inc = o.incT; o.gc = lpc(6); o.e.st = 1; o.vel = v; o.off = offAt(tk, x); break;\n case 'acid': o = AC; o.incT = mtof(n) * isr; o.off = offAt(tk, x);\n if ((p & 2) && o.e.st !== 0) { o.gc = lpc(9); o.vel = v; }\n else { o.inc = o.incT; o.gc = 1; o.e.st = 1; o.vel = v; }\n o.fe = (p & 1) ? 1.5 : Math.max(o.fe, .8); break;\n case 'arp': o = PL[plN++ & 3]; f = mtof(n) * isr; o.i1 = f * .9965; o.i2 = f * 1.0035; o.e.st = 1; o.fe = 1; o.vel = v; o.off = offAt(tk, x); break;\n case 'lead': sawNotes(LD, [n], 1, p); LD.e.st = 1; LD.fe = 1; LD.vel = v; LD.off = offAt(tk, x); break;\n case 'pad': sawNotes(PD, n, n.length, 0); PD.e.st = 1; PD.vel = v; PD.off = offAt(tk, x); break;\n case 'stab': sawNotes(ST, n, n.length, p); ST.e.st = 1; ST.fe = 1; ST.vel = v; ST.off = offAt(tk, x); break;\n case 'bell': o = BL[blN++ % 6]; f = mtof(n) * isr; o.ic = f; o.im = f * (p ? 2 : 3.5); o.pc = 0; o.pm = 0; o.a = v * (p ? .8 : 1); o.at = 0; o.ix = p ? 3.2 : 2.4;\n o.da = tc(p ? .5 : 1.3); o.di = tc(p ? .12 : .3); f = (blN & 1 ? .3 : .7) * PI / 2; o.gl = Math.cos(f); o.gr = Math.sin(f); break;\n case 'impact': case 'crash': IM.on = 1; IM.t = 0; IM.vel = v; IM.sub = k === 'impact' ? 1 : 0; IM.ph = 0; IM.pe = 1; IM.ae = 1; IM.ce = 1; break;\n case 'riser': RS.on = 1; RS.t = 0; RS.dur = tk.l[x] * spb; RS.vel = v; RS.f0 = mtof(n); break;\n case 'down': DN.on = 1; DN.t = 0; DN.dur = tk.l[x] * spb; DN.vel = v; break;\n }\n }\n\n var oN = 0, oI = 0, skip = LA, produced = 0;\n function block() {\n var n, q, o, bar, e;\n while (pos >= nextTick) {\n if (tick === killTick) killAll();\n while (evp < order.length && evT[order[evp]] <= tick) { e = order[evp++]; fire(evK[e], evI[e]); }\n tick++; nextTick = Math.round(tick * spt);\n }\n n = nextTick - pos; if (n > BS) n = BS;\n for (q = 0; q < gated.length; q++) { o = gated[q]; e = o.e; if ((e.st === 1 || e.st === 2) && pos >= o.off) e.st = 3; }\n for (q = 0; q < n; q++) { mL[q] = 0; mR[q] = 0; dL[q] = 0; dR[q] = 0; rv[q] = 0; dl[q] = 0; }\n bar = pos / spb / 4;\n\n // automation\n var kickLP = bar < 8 ? 2e4 : bar < 16 ? xr(bar, 8, 13.5, 110, 2e4) : bar < 48 ? 2e4 : bar < 56 ? xr(bar, 48, 56, 150, 380) : bar < 64 ? xr(bar, 56, 61, 380, 2e4) : 2e4;\n var arpFc = bar < 8 ? xr(bar, 0, 8, 900, 2800) : bar < 16 ? xr(bar, 8, 16, 2800, 5000) : bar < 48 ? 4200 : bar < 56 ? xr(bar, 48, 56, 400, 2200) : bar < 64 ? xr(bar, 56, 64, 2200, 7000) : bar < 88 ? 5600 : xr(bar, 88, 96, 5600, 1000);\n var arpG = bar < 8 ? .65 : bar < 16 ? 1 : bar < 48 ? .8 : bar < 56 ? xr(bar, 48, 56, .45, .9) : bar < 64 ? 1 : bar < 88 ? .8 : 1;\n var padFc = bar < 8 ? xr(bar, 0, 8, 1300, 3600) : bar < 16 ? xr(bar, 8, 16, 3600, 7000) : bar < 40 ? 1600 : bar < 48 ? xr(bar, 40, 48, 1100, 3000) : bar < 56 ? xr(bar, 48, 56, 1400, 3200) : bar < 64 ? xr(bar, 56, 64, 2800, 9000) : bar < 88 ? 4500 : xr(bar, 88, 96, 4500, 1000);\n var stabFc = bar < 24 ? 7000 : bar < 64 ? 8500 : bar < 72 ? 10000 : bar < 80 ? 12000 : 16000;\n var leadFc = bar < 64 ? 6500 : bar < 80 ? 8500 : 12000;\n\n mTrim = bar >= 16 && bar < 40 ? .88 : bar >= 40 && bar < 48 ? .86 : bar >= 80 && bar < 88 ? 1.12 : 1;\n\n // voices -> buses\n if (G.pad && sawRun(PD, n, padFc, 1.3, .016)) mix(n, G.pad * (bar >= 40 && bar < 56 ? .7 : 1), .4, 0, mL, mR);\n if (G.stab && sawRun(ST, n, stabFc, 1.2, .022)) mix(n, G.stab, .22, .14, mL, mR);\n if (G.lead && sawRun(LD, n, leadFc, 1, .03)) mix(n, G.lead, .3, .32, mL, mR);\n if (G.arp) for (q = 0; q < 4; q++) { o = PL[q]; if (o.e.st !== 0) { plRun(o, n, arpFc); mix(n, G.arp * arpG, .28, .4, mL, mR); } }\n if (G.bell && bellRun(n)) mix(n, G.bell, .5, .4, mL, mR);\n if (G.bass && BA.e.st !== 0) {\n ladRun(BA, n, (bar >= 56 && bar < 64 ? xr(bar, 56, 64, 170, 1300) : bar >= 32 && bar < 40 ? 420 : 520) * (1 + 2 * BA.fe), 1.1, 1.5, .55, .7);\n mixM(tL, n, G.bass, 0, 0, mL, mR);\n }\n if (G.bass && SB.e.st !== 0) { ladRun(SB, n, 240, .3, 1.2, .3, .62); mixM(tL, n, G.bass * .42, 0, 0, mL, mR); }\n if (G.acid && AC.e.st !== 0) {\n ladRun(AC, n, xr(bar, 32, 40, 300, 1500) * (1 + .25 * Math.sin(bar * PI)) * (1 + 4.5 * AC.fe), 3.2, 1.3, 1, 0);\n mixM(tL, n, G.acid, .12, .3, mL, mR);\n }\n if (G.kick && K.on) { kickRun(n, kickLP); mixM(tL, n, G.kick, 0, 0, dL, dR); }\n if (G.snare && SN.on) { snareRun(n); mix(n, G.snare, .2, 0, dL, dR); }\n if (G.hat && HT.c + HT.o + HT.r > 1e-4) { hatRun(n); mix(n, G.hat, .04, 0, dL, dR); }\n if (G.riser && RS.on) { sweepRun(RS, n); mix(n, G.riser, .3, .1, mL, mR); }\n if (G.down && DN.on) { sweepRun(DN, n); mix(n, G.down, .3, 0, mL, mR); }\n if (G.impact && IM.on) { impactRun(n); mix(n, G.crash, .55, .1, dL, dR); if (IM.sub) mixM(uB, n, G.impact, .25, 0, mL, mR); }\n\n delayRun(n); reverbRun(n); masterRun(n);\n pos += n; oN = n; oI = 0;\n }\n\n function next(n) {\n var L = new Float32Array(n), R = new Float32Array(n), k = 0, m, q;\n while (k < n && produced < totalN) {\n if (oI >= oN) block();\n if (skip > 0) { m = Math.min(skip, oN - oI); oI += m; skip -= m; continue; }\n m = Math.min(n - k, oN - oI, totalN - produced);\n for (q = 0; q < m; q++) { L[k + q] = oL[oI + q]; R[k + q] = oR[oI + q]; }\n k += m; oI += m; produced += m;\n }\n return { L: L, R: R };\n }\n return { total: totalN, next: next };\n}\n\nif (typeof onmessage !== 'undefined' || typeof self !== 'undefined') {\n (typeof self !== 'undefined' ? self : globalThis).onmessage = function (e) {\n if (!e.data || !e.data.sr) return;\n var sr = e.data.sr, r = renderer(sr), tot = r.total, s = 0, i = 0, n, o;\n while (s < tot) {\n n = Math.min(tot - s, Math.round(sr * (i === 0 ? .5 : 2)));\n o = r.next(n);\n postMessage({ i: i, s: s, L: o.L, R: o.R }, [o.L.buffer, o.R.buffer]);\n s += n; i++;\n }\n postMessage({ done: true, n: tot });\n };\n}\nif (typeof module !== 'undefined' && module && module.exports) module.exports = { renderer: renderer, SONG: SONG };\n";
function mkHud(x,c,proj,st){
const INK='rgba(22,24,30,.86)',DIM='rgba(22,24,30,.42)',COR='#ee4534',FONT='ui-monospace,"SF Mono",Menlo,Consolas,"DejaVu Sans Mono",monospace';
const SIZE='033,090',pad=(n,w,d)=>{let s=Math.abs(n).toFixed(d);while(s.length<w)s='0'+s;return(n<0?'-':'')+s};
let u=1,kvn=0;
const f=(s,b)=>{x.font=(b?'700 ':'500 ')+Math.round(s*u)+'px '+FONT},ln=(a,b,d,e)=>{x.beginPath();x.moveTo(a,b);x.lineTo(d,e);x.stroke()};
const HALO='rgba(243,244,247,.9)',ft=(t,X,Y)=>{const s=x.strokeStyle,w=x.lineWidth;x.strokeStyle=HALO;x.lineWidth=3.5*u;x.lineJoin='round';x.strokeText(t,X,Y);x.strokeStyle=s;x.lineWidth=w;x.fillText(t,X,Y)};
const sp=(t,px,py,ls)=>{let w=0;for(const ch of t){x.fillText(ch,px+w,py);w+=x.measureText(ch).width+ls*u}return w};
const H={pad,
tag(p,t,dx,dy,acc){const q=proj(p);if(!q)return;dx=(dx==null?46:dx)*u;dy=(dy==null?-34:dy)*u;const X=q[0],Y=q[1];
x.strokeStyle=x.fillStyle=acc?COR:INK;x.lineWidth=u;x.beginPath();x.arc(X,Y,3.5*u,0,7);x.stroke();ln(X+Math.sign(dx)*3*u,Y+Math.sign(dy)*3*u,X+dx,Y+dy);
f(11,1);const w=x.measureText(t).width,r=dx>0;ln(X+dx,Y+dy,X+dx+(r?w+8*u:-w-8*u),Y+dy);x.textAlign=r?'left':'right';ft(t,X+dx+(r?5:-5)*u,Y+dy-5*u)},
span(a,b,t,acc){const p=proj(a),q=proj(b);if(!p||!q)return;x.strokeStyle=x.fillStyle=acc?COR:INK;x.lineWidth=u;ln(p[0],p[1],q[0],q[1]);
const dx=q[0]-p[0],dy=q[1]-p[1],l=Math.hypot(dx,dy)||1,nx=-dy/l*5*u,ny=dx/l*5*u;ln(p[0]-nx,p[1]-ny,p[0]+nx,p[1]+ny);ln(q[0]-nx,q[1]-ny,q[0]+nx,q[1]+ny);
f(11,1);x.textAlign='center';ft(t,(p[0]+q[0])/2+nx*2.4,(p[1]+q[1])/2+ny*2.4+4*u)},
cross(p,r){const q=proj(p);if(!q)return;r=(r||9)*u;x.strokeStyle=INK;x.lineWidth=u;ln(q[0]-r,q[1],q[0]-r/3,q[1]);ln(q[0]+r/3,q[1],q[0]+r,q[1]);ln(q[0],q[1]-r,q[0],q[1]-r/3);ln(q[0],q[1]+r/3,q[0],q[1]+r)},
kv(k,v,acc){const X=34*u,Y=c.height-(74+kvn*17)*u;kvn++;f(11,0);x.textAlign='left';x.fillStyle='rgba(22,24,30,.6)';ft(k,X,Y);x.fillStyle=acc?COR:INK;f(11,1);ft(v,X+118*u,Y)},
big(t,s,a,y){if(a<=0)return;x.globalAlpha=Math.min(1,a);x.fillStyle=INK;x.textAlign='left';const u0=u,W0=c.width/Math.max(1,window.devicePixelRatio>2?2:window.devicePixelRatio||1);u=Math.min(u,u*c.width/(1100*u));f(t.length>12?54:92,0);const ls=t.length>12?16:44;let w=0;for(const ch of t)w+=x.measureText(ch).width+ls*u;w-=ls*u;
const Y=c.height*(y||.5);sp(t,(c.width-w)/2,Y,ls);if(s){f(13,1);let w2=0;for(const ch of s)w2+=x.measureText(ch).width+6*u;sp(s,(c.width-w2+6*u)/2,Y+38*u,6)}
x.strokeStyle=COR;x.lineWidth=2*u;ln((c.width-w)/2,Y+14*u,(c.width-w)/2+w*Math.min(1,a),Y+14*u);x.globalAlpha=1;u=u0}
};
return function(s,si,e,cam,t,scale){u=c.height/900;kvn=0;const w=c.width,h=c.height,m=22*u,L=18*u;
x.lineWidth=u;x.strokeStyle=INK;x.fillStyle=INK;x.textBaseline='alphabetic';
for(const[X,Y,a,b]of[[m,m,1,1],[w-m,m,-1,1],[m,h-m,1,-1],[w-m,h-m,-1,-1]]){ln(X,Y,X+a*L,Y);ln(X,Y,X,Y+b*L)}
x.textAlign='left';f(13,1);sp('FATHOM',34*u,46*u,7);f(11,0);x.fillStyle=DIM;
x.fillText(e.started?'PLATE '+pad(si+1,2,0)+' / 12 '+(SC[si].name||''):'PLATE 00 / 12 STANDBY',34*u,64*u);
x.textAlign='right';x.fillStyle=INK;f(11,1);const bar=Math.max(0,e.b)/4;
x.fillText('BAR '+pad(Math.min(96,bar)+1|0,3,0)+'.'+((Math.max(0,e.b)%4|0)+1)+' '+SONG.bpm+' BPM',w-34*u,46*u);
x.fillStyle=DIM;f(11,0);x.fillText('PATH TRACED 1 SPP '+st.pw+'×'+st.ph,w-34*u,64*u);
x.fillText(SIZE+' / 262,144 BYTES',w-34*u,h-52*u);
const x0=34*u,x1=w-34*u,yb=h-34*u;x.strokeStyle=DIM;ln(x0,yb,x1,yb);for(let i=0;i<=96;i++){const X=x0+(x1-x0)*i/96;ln(X,yb,X,yb-(i%8?3:9)*u)}
const X=x0+(x1-x0)*Math.min(96,bar)/96;x.fillStyle=COR;x.fillRect(x0,yb-1.5*u,X-x0,3*u);x.beginPath();x.moveTo(X,yb-12*u);x.lineTo(X-4*u,yb-19*u);x.lineTo(X+4*u,yb-19*u);x.fill();
const y0=h*.24,y1=h*.76;x.strokeStyle=DIM;for(let i=0;i<=40;i++){const Y=y0+(y1-y0)*i/40;ln(m,Y,m+(i%5?4:10)*u,Y)}
if(s&&s.head){const p=s.head(e.t,e),q=p&&proj(p);if(q){const z=q[2],Y=y0+(y1-y0)*Math.min(1,z/40);x.fillStyle=COR;x.fillRect(m,Y-u,16*u,2*u);f(11,1);x.textAlign='left';ft('Z '+pad(z,5,2),m+22*u,Y+4*u);
H.tag(p,'Z '+pad(z,5,2)+' m',40,-46,1)}}
if(s&&s.hud)s.hud(e.t,e,H)}}
SC[0]={name:'ZERO',acc:18,
glsl:`
vec3 rc(float x){return vec3(x,1.15+.32*sin(x*.9+T*.25),.5*sin(x*.5-T*.2));}float map(vec3 p){gm=0.;float d=p.y;vec3 c=rc(p.x);float r=max(rb(p.yz-c.yz,p.x*.7+T*.3,.2)*.65,p.x-uP[0].x);d=U(d,r,1.);d=U(d,length(p-vec3(3.2,.8,-1.7))-.8,2.);vec3 q=p-vec3(-1.4,.45,-2.3);q.xz*=rot(.5);d=U(d,sdRBox(q,vec3(.45),.03),3.);float i=clamp(round(p.x),-9.,9.),h=.14*smoothstep(0.,1.,uP[0].y-(i+9.));d=U(d,sdCyl(p-vec3(i,h,1.5),.05,h)-.012,4.);return d;}void mat(float id,vec3 p,vec3 n,inout vec3 al,inout vec3 em,inout vec2 sp){if(id==2.){al=vec3(.92);sp=vec2(1.,.03);}if(id==3.)al=MINT;if(id==4.)al=vec3(.16);if(id==0.){vec2 g=abs(fract(p.xz-.5)-.5);al=mix(al,vec3(.55),smoothstep(.014,.004,min(g.x,g.y))*.55*exp(-.012*dot(p.xz,p.xz)));}}`,
hx(t){return -9.5+t*.62},
cam(t,e){const x=this.hx(t)*.55+1.5;return[x+1.5+t*.04,1.5+.2*Math.sin(t*.1),7.4-t*.03,x-.4,.95,0,46,0]},
P(t,e,P){P[0]=this.hx(t);P[1]=e.started?Math.max(0,t-4)*.9:19},
head(t,e){const x=this.hx(t);return e.started?[x,1.15+.32*Math.sin(x*.9+t*.25),.5*Math.sin(x*.5-t*.2)]:null},
hud(t,e,H){if(!e.started)return;
H.big('FATHOM','A PATH-TRACED MEASUREMENT IN TWELVE PLATES',Math.min(t-1,(15-t)/2)/2,.3);
if(t>10){H.span([3.2,1.75,-1.7],[3.2,-.0,-1.7].map((v,i)=>i==1?1.75:v+(i==0?.8:0)),'');H.tag([3.2,1.6,-1.7],'Ø 1.600 m',52,-40)}
if(t>16)H.tag([-1.4,.9,-2.3],'0.900 m',-50,-36);
H.kv('REFERENCE','1 PEG = 1.000 m');H.kv('RIBBON',H.pad(Math.max(0,this.hx(t)+9.5),5,2)+' m',1)}};
SC[1]={name:'SCALE',acc:14,
glsl:`
float map(vec3 p){gm=0.;float d=p.y;float u=p.x<0.?p.x/.2426:log2(p.x/.35+1.),ru=.05*exp2(min(u,5.)),g=smoothstep(-2.5,-.3,u);vec2 c=vec2(.035+ru*.34+.2*ru*g*sin(u*2.+T*.8),-(.1+1.25*ru)*g*cos(3.14159*u));float r=max(rb(p.yz-c,.55*g*sin(3.14159*u-T*.4),min(.025+.3*ru,.21))*.5,p.x-uP[6].x);d=U(d,r,1.);for(int i=0;i<6;i++){vec4 s=uP[i];d=U(d,length(p-vec3(s.x,s.z+s.y,0))-s.y,2.+float(i));}return d;}void mat(float id,vec3 p,vec3 n,inout vec3 al,inout vec3 em,inout vec2 sp){if(id>1.){int i=int(id)-2;al=i==0?BUTTER:i==1?LILAC:i==2?MINT:i==3?vec3(.97,.70,.74):i==4?SKYB:MINT;}}`,
X(u){return u<0?.2426*u:.35*(2**u-1)},
sm(x){x=Math.max(0,Math.min(1,x));return x*x*(3-2*x)},
uc(t){const b=Math.min(t,20.6)/4,k=Math.floor(b),f=b-k;return k+.65*this.sm(f*1.7)+.35*f+Math.max(0,t-20.6)*.01},
sph(i,t,e){const x=(t-4*i)/1.1,r=.05*2**i;if(x<0)return[this.X(i),0,-9];
const y=Math.min(x,1)-1,s=1+2.9*y*y*y+1.9*y*y;let hop=0;
if(t>=24&&SONG.hits){const h=SONG.hits('snare',e.b-t+24,e.b-t+32);let L=-1,N=1e9;for(const v of h){if(v<=e.b)L=v;else if(N>1e8)N=v}
if(L>=0){const q=(e.b-L)/(Math.min(N-L,1)*.92);if(q<1)hop=4*q*(1-q)*(.1+.3*Math.sqrt(r))*(1+.25*Math.sin(i*2.4+L*5))}}
return[this.X(i),r*s,hop]},
hu(t){return Math.min(t/4+.45,9)},
cam(t,e){const u=this.uc(t),s=2**u,D=.34*s+.62,x=this.X(u)-.5*D+.1*s*.3;
return[x+.34*D,.2*D+.08,D,x,.045*s+.05,0,42,0]},
P(t,e,P){for(let i=0;i<6;i++){const s=this.sph(i,t,e);P[4*i]=s[0];P[4*i+1]=s[1];P[4*i+2]=s[2]}
P[24]=this.X(this.hu(t))},
head(t,e){const u=this.hu(t),ru=.05*2**Math.min(u,5),g=this.sm((u+2.5)/2.2);
return[this.X(u),.035+ru*.34+.2*ru*g*Math.sin(u*2+t*.8),-(.1+1.25*ru)*g*Math.cos(Math.PI*u)]},
hud(t,e,H){const n=Math.min(6,Math.floor(t/4)+1);
for(let i=Math.max(0,n-3);i<n;i++){const s=this.sph(i,t,e),d=.1*2**i,a=t-4*i;if(a<.25)continue;
H.tag([s[0],s[2]+2*s[1],0],'Ø '+d.toFixed(3)+' m',i==n-1?44:-40,i==n-1?-40:-30-12*(n-1-i),i==n-1&&a<4)}
const s=this.sph(n-1,t,e);if(t-4*(n-1)>.6)H.span([s[0]-s[1],.0,s[1]*1.02+.02],[s[0]+s[1],.0,s[1]*1.02+.02],'');
H.kv('SERIES','Ø × 2 PER BAR');H.kv('COUNT',H.pad(n,2,0)+' / 06');
H.kv('LARGEST Ø',(.1*2**(n-1)).toFixed(3)+' m',1);if(t>=24)H.kv('NEXT Ø','6.400 m NOT IN STOCK')}};
SC[2]={name:'COLUMNS',acc:7,cuts:[16],
glsl:`
#define FOGK .0003
#define SKY
vec3 sky(vec3 d){return mix(vec3(1.02,1.01,1.),vec3(.42,.52,.80),pow(smoothstep(.05,1.1,d.y),.55));}float ch(vec2 c){return mod(c.x*c.x*31.+c.y*c.y*17.+c.x*c.y*23.+c.x*5.+c.y*3.,97.)/97.;}float hh(vec2 c){float m=mod(c.y,3.),h=ch(c);return (.25+h*h*(.5+2.55*(m<.5?uE.x:m<1.5?uN.x:uE.y)))*smoothstep(22.,13.,length(c*2.4+1.2-vec2(0,uP[0].x)))*smoothstep(4.5,8.5,length(c*2.4+1.2-uP[1].xy));}float map(vec3 p){gm=0.;float d=p.y;vec2 c=vec2(.25*sin(p.z*.3),uP[0].y+uP[0].z*sin(p.z*.1)+.4*sin(p.z*.55));d=U(d,max(rb(p.xy-c,.6*sin(p.z*.5),.24)*.75,max(p.z-uP[0].x,uP[0].w-p.z)),1.);vec2 i=floor(p.xz/2.4),q=p.xz-(i+.5)*2.4;float h=hh(i)*.5;float b=sdBox(vec3(q.x,p.y-h,q.y),vec3(.5,h,.5)-.025)-.025,w=1.2-max(abs(q.x),abs(q.y));d=U(d,max(max(h>0.?min(b,w+.7):9.,p.y-3.32),length(p.xz-vec2(0,uP[0].x))-23.8),2.);return d;}void mat(float id,vec3 p,vec3 n,inout vec3 al,inout vec3 em,inout vec2 sp){if(id==2.){vec2 i=floor(p.xz/2.4);float k=mod(i.x*7.+i.y*13.+i.x*i.y*3.,31.);if(k<4.)al=k<1.?MINT:k<2.?LILAC:k<3.?BUTTER:SKYB;}}`,
ch(i,j){return((i*i*31+j*j*17+i*j*23+i*5+j*3)%97+97)%97/97},
hh(i,j,e){const m=(j%3+3)%3,h=this.ch(i,j);const f=this.sm((22-Math.hypot(i*2.4+1.2,j*2.4+1.2-this.hz(e.t)))/9);const c=this.cam(e.t,e);return(.25+h*h*(.5+2.55*(m==0?e.kick:m==1?e.bass:e.snare)))*f*this.sm((Math.hypot(i*2.4+1.2-c[0],j*2.4+1.2-c[2])-4.5)/4)},
sm(x){x=Math.max(0,Math.min(1,x));return x*x*(3-2*x)},
hz(t){return t*4.8},
ry(t){return t<16?[1.3,0]:[2.1,1.2]},
cam(t,e){const z=this.hz(t);
if(t<16)return[.38+.1*Math.sin(t*.4),2.1+.1*Math.sin(t*.25),z-10.5,-.1,1.4,z,58,.05*Math.sin(t*.3)];
const a=(t-16)*.035;return[13+a*10,11-a*4,z-13+a*14,-2,.8,z-2,40,0]},
P(t,e,P){const y=this.ry(t),z=this.hz(t);P[0]=z;P[1]=y[0];P[2]=y[1];P[3]=z-(t<16?9:34);const c=this.cam(t,e);P[4]=c[0];P[5]=c[2]},
head(t,e){const z=this.hz(t),y=this.ry(t);return[.25*Math.sin(z*.3),y[0]+y[1]*Math.sin(z*.1)+.4*Math.sin(z*.55),z]},
hud(t,e,H){const hj=Math.floor(this.hz(t)/2.4),cm=this.cam(t,e),L=(i,j,dx,dy,a)=>{const h=this.hh(i,j,e);if(Math.hypot((i+.5)*2.4-cm[0],(j+.5)*2.4-cm[2])<8.5)return;H.tag([(i+.5)*2.4-Math.sign(i+.5)*.5,h,(j+.5)*2.4-.5],'h '+H.pad(h,5,2)+' m',dx,dy,a)};
const ja=4*Math.floor(hj/4),jb=4*Math.floor((hj+2)/4)-2;
const pick=(j,s)=>{let b=s,v=-1;for(let k=0;k<2;k++){const i=s<0?-2-k:1+k,c=this.ch(i,j);if(c>v){v=c;b=i}}return b};
if(t<16){L(pick(ja+3,-1),ja+3,-70,-50);L(pick(jb+4,1),jb+4,70,-56)}
else{L(pick(ja+2,-1),ja+2,-50,-40);L(pick(jb+1,1),jb+1,50,-44);L(pick(ja-3,1)+2,ja-3,56,-30)}
H.kv('GRID','2.40 m × 2.40 m');H.kv('ROW A / KICK',H.pad(.5+2.55*e.kick,5,2)+' ×');
H.kv('ROW B / BASS',H.pad(.5+2.55*e.bass,5,2)+' ×');H.kv('H MAX',H.pad(.75+2.55*Math.max(e.kick,e.bass,e.snare),5,2)+' m NO LIFT',1)}};
SC[3]={name:'GATES',acc:10,cuts:[16],
glsl:`
#define FOGK .0008
#define SKY
vec3 sky(vec3 d){return mix(vec3(1.02,1.01,1.),vec3(.42,.52,.80),pow(smoothstep(.05,1.1,d.y),.55));}float ga(float k){return (mod(k,2.)<.5?1.:-1.)*uP[0].y*.3927+k*.14;}float map(vec3 p){gm=0.;float d=p.y;vec2 c=vec2(.45*sin(p.z*.25+T*.2),3.3+.45*cos(p.z*.19-T*.15));d=U(d,max(rb(p.xy-c,p.z*.35-T*.5,.19)*.8,p.z-uP[0].x),1.);float k=round(p.z/4.);vec3 q=vec3(p.x,p.y-3.3,p.z-4.*k);q.xy*=rot(ga(k));vec2 a=abs(q.xy)-2.,w=vec2(abs(length(max(a,0.))+min(max(a.x,a.y),0.))-.17,abs(q.z)-.17);d=U(d,min(length(max(w,0.))+min(max(w.x,w.y),0.)-.03,3.8-abs(q.z)),2.);return d;}void mat(float id,vec3 p,vec3 n,inout vec3 al,inout vec3 em,inout vec2 sp){if(id==2.){float k=round(p.z/4.),m=mod(k,4.);al=m<1.?MINT:m<2.?BUTTER:m<3.?LILAC:SKYB;sp=vec2(.1,.3);if(mod(k,10.)==7.){al=vec3(.93);sp=vec2(1.,.03);}else em=al*al*1.5*uN.z*exp(-abs(k*4.-uP[0].x)*.16);}}`,
sn(t,e){const g=e.b-t,h=SONG.hits?SONG.hits('snare',g,g+32):[];let n=0,L=0;for(const v of h)if(v<=e.b){n++;L=v}
if(!n)return 0;const y=Math.min(1,(e.b-L)/.4)-1;return n+2.9*y*y*y+1.9*y*y},
ga(k,t,e){return(k%2?-1:1)*this.sn(t,e)*.3927+k*.14},
hz(t){return 4*t},
rc(z,t){return[.45*Math.sin(z*.25+t*.2),3.3+.45*Math.cos(z*.19-t*.15),z]},
cam(t,e){const z=this.hz(t),a=t*.21;
if(t<16)return[1.4*Math.cos(a),3.3+1.15*Math.sin(a),z-9,.2*Math.cos(a),3.3,z+3,64,t*.05-.4];
const b=(t-16)/16;return[7.5-b*2,1.1+b*1.2,z+7-b*3,-.6,3.1,z-4,50,0]},
P(t,e,P){P[0]=this.hz(t);P[1]=this.sn(t,e)},
head(t,e){return this.rc(this.hz(t),t)},
hud(t,e,H){const f=Math.floor(t),k=f,r=2.17*1.414;let a=this.ga(k,t,e)+Math.PI/4;
a-=Math.PI/2*Math.round((a-Math.PI/2)/(Math.PI/2));
H.tag([r*Math.cos(a),3.3+r*Math.sin(a),4*k],'GATE '+H.pad(k,3,0),t<16?50:-46,-30);
if(t<16)H.span([1.75,1.7,4*f],[1.75,1.7,4*f+4],'SPAN 04.00 m');else H.span([2.6,.02,4*f-8],[2.6,.02,4*f-4],'SPAN 04.00 m');
H.kv('GATE',H.pad(Math.floor(t),3,0)+' / 032');H.kv('NOTCH',H.pad(Math.round(this.sn(t,e))*22.5%360,5,1)+' °');
H.kv('GLOW',H.pad(1.5*e.lead,4,2),e.lead>.5);H.kv('CLEARANCE','1.83 m MIND THE HEAD',0)}};
SC[4]={name:'HELIX',acc:11,exp:1.12,
glsl:`
#define SKY
#define KR .3
vec3 sky(vec3 d){return mix(vec3(1.02,1.01,1.),vec3(.42,.52,.80),pow(smoothstep(.05,1.1,d.y),.55));}float map(vec3 p){gm=0.;float d=p.y;float r=length(p.xz),th=atan(p.z,p.x)/6.2832,P=uP[0].y;float n=round(p.y/P-th),s=n+th;float h=rb(vec2(r-1.05,p.y-P*s),1.5708+uP[0].z*sin(s*12.566-T*.8),.2)*.8;d=U(d,max(h,(s-uP[0].x)*5.5),1.);d=U(d,r-.6,2.);float a=-th-uP[0].w,i=round(a*14.),m=round(p.y/2.8-i/14.-.15);vec3 q=p;q.xz*=rot(-(i/14.+uP[0].w)*6.2832);q-=vec3(2.9,2.8*(i/14.+m+.15),0);d=U(d,max(min(sdRBox(q,vec3(.62,.05,.34),.025),r*(.5-abs(a*14.-i))*.42+.15),r-3.8),3.);return d;}void mat(float id,vec3 p,vec3 n,inout vec3 al,inout vec3 em,inout vec2 sp){if(id==2.){al=vec3(.9);sp=vec2(.1,.15);}if(id==3.){float a=-atan(p.z,p.x)/6.2832-uP[0].w,i=round(a*14.),g=i+14.*round(p.y/2.8-i/14.-.15),k=mod(g,4.);al=k<1.?MINT:k<2.?LILAC:k<3.?BUTTER:SKYB;if(mod(g-uP[1].x,14.)<.5)em=al*(.4+1.3*uN.x);}}`,
tn(t){return .6+t*.372},
pi(e){return .8*(1-.06*e.bass)},
cam(t,e){const a=.9+t*.085,y=this.tn(t)*.8,R=11.5+.05*t;
return[R*Math.cos(a),2+y*.9,R*Math.sin(a),0,.9+y*.62,0,44,0]},
bn(t,e){const g=e.b-t;return SONG.hits?SONG.hits('bass',g,e.b+1e-6).length:Math.floor(t*2)},
P(t,e,P){P[0]=this.tn(t);P[1]=this.pi(e);P[2]=.25+.7*e.bass;const b=t/4,k=Math.floor(b),f=Math.min(1,(b-k)*8);P[3]=(k+f*f*(3-2*f))/14;P[4]=this.bn(t,e)},
head(t,e){const s=this.tn(t),a=s*6.2832;return[1.05*Math.cos(a),this.pi(e)*s,1.05*Math.sin(a)]},
hud(t,e,H){const s=this.tn(t),p=this.pi(e),c=this.cam(t,e),a=Math.atan2(c[2],c[0])+1.35,n=Math.max(1,Math.floor(s-a/6.2832)-2),y=p*(n+a/6.2832);
H.span([1.3*Math.cos(a),y,1.3*Math.sin(a)],[1.3*Math.cos(a),y+p,1.3*Math.sin(a)],'PITCH '+p.toFixed(2)+' m');
const b=a-2.7;H.span([.62*Math.cos(b-.9),.02,.62*Math.sin(b-.9)],[.62*Math.cos(b-.9+3.1416),.02,.62*Math.sin(b-.9+3.1416)],'');
H.tag([.6*Math.cos(b),.5+this.tn(t)*.25,.6*Math.sin(b)],'Ø 1.200 m',56,-30);
H.kv('TURNS',H.pad(Math.floor(s*10)/10,4,1),1);H.kv('PITCH',p.toFixed(2)+' m');
H.kv('RISE',H.pad(s*p,5,2)+' m');H.kv('STAIR','STEP '+H.pad(this.bn(t,e),3,0)+' NO HANDRAIL')}};
SC[5]={name:'STILL',acc:30,exp:2.1,
glsl:`
#define KD normalize(vec3(.5,.84,.06))
#define KC vec3(1.75,1.5,1.12)
#define KR .05
#define FOGK 0.
vec2 rc(float y){return vec2(-.8+.4*sin(y*.7+T*.12)+.28*max(y-3.5,0.),.4*sin(y*.5-T*.09+1.));}float map(vec3 p){gm=0.;float d=p.y;float w=-sdBox(p-vec3(0,3,-3),vec3(4,4,13)),zq=p.z+2.-4.*round((p.z+2.)/4.);w=min(w,max(abs(zq)-.3,-sdBox(vec3(p.xy-vec2(0,2.9),0),vec3(3.3,3.5,1))));w=max(max(w,-sdBox(p-vec3(1.25,7.9,-3),vec3(1.75,1.,7.7))),p.y-7.4);d=U(d,w,2.);d=U(d,max(rb(p.xz-rc(p.y),p.y*.6+T*.15,.22)*.65,uP[0].z-p.y),1.);if(uP[0].x>.5){float i=clamp(round((p.y-1.4)/.42),0.,uP[0].x-1.),y=1.4+.42*i;d=U(d,length(p-vec3(rc(y),y).xzy)-.1*(i>uP[0].x-1.5?1.+.8*uP[0].y:1.),3.);}vec3 q=p-vec3(-2.75,1.7,0);float k=clamp(round(q.z/4.),-2.,0.);q.z-=k*4.;q.xy*=rot(.13);d=U(d,sdRBox(q,vec3(.05,1.7,1.25),.02),4.-k);return d;}void mat(float id,vec3 p,vec3 n,inout vec3 al,inout vec3 em,inout vec2 sp){if(id==3.){al=vec3(.95);sp=vec2(1.,.04);}if(id==4.)al=MINT;if(id==5.)al=BUTTER;if(id==6.)al=LILAC;}`,
sm(x){x=Math.max(0,Math.min(1,x));return x*x*(3-2*x)},
n(e){let c=Math.floor(e.t*2);try{const h=SONG.hits('arp',160,e.b+1e-3);if(h&&h.length)c=h.length}catch(x){}return c%13},
end(t){return .95+.3*Math.sin(t*.2)},
rc(y,t){return[-.8+.4*Math.sin(y*.7+t*.12)+.28*Math.max(y-3.5,0),y,.4*Math.sin(y*.5-t*.09+1)]},
cam(t,e){const s=this.sm(t/32);return[2.6-1.5*s,1.35+.5*s,9.2-4.6*s,-1.1,3.05-.25*s,-2.5,50,0]},
P(t,e,P){P[0]=this.n(e);P[1]=e.arp;P[2]=this.end(t)},
head(t,e){return this.rc(this.end(t),t)},
hud(t,e,H){const n=this.n(e);
H.span([-4,5.2,-15.9],[4,5.2,-15.9],'SPAN 08.00 m');
if(n>0)H.tag(this.rc(1.4+.42*(n-1),t),'BEAD '+H.pad(n,2,0),-54,-18);
if(t>8)H.tag([-2.6,3.35,-4],'BLEED '+H.pad(.18+.02*Math.sin(Math.floor(t*2)),4,2),60,-30);
H.kv('NOISE','NONE (WE WAITED)');H.kv('BOUNCES','3');H.kv('ROOM','SPAN 08.00 m');
H.kv('LUX','12 '+H.pad(400+Math.round(9*Math.sin(Math.floor(t*4)*2.3)+6*e.arp),3,0),1)}};
SC[6]={name:'PULSE',acc:12,cuts:[16],
glsl:`
#define KD normalize(vec3(.5,.7,.45))
float map(vec3 p){gm=0.;float d=p.y,r=length(p.xz),a=atan(p.z,p.x),R=uP[0].x;float k=clamp(round(r/.9),3.,16.),h=.02+.12*exp(-3.5*fract(T-k*.22+.03))*(1.-k/22.);d=min(d,(length(max(abs(vec2(r-k*.9,p.y))-vec2(.2,h),0.))-.025)*.8);d=U(d,length(p-vec3(0,1.62,0))-R,2.);float dc=mod(a-uP[0].y+3.1416,6.2832)-3.1416,da=2.2-dc;d=U(d,max(rb(vec2(r-R-.8,p.y-1.6-.45*sin(da*1.3-T*.3)),da*1.4+T*.2,.22)*.6,(abs(dc)-2.2)*r*.6),1.);if(uP[0].z>.5){float s=.5236,j=round((a+T*.07)/s),i=mod(j,12.);if(i<uP[0].z){float b=j*s-T*.07,o=3.5+.45*sin(i*2.4);d=U(d,(length(p-vec3(o*cos(b),1.3+.9*sin(i*1.7+T*.15),o*sin(b)))-(.17+.07*sin(i*5.))*(i>uP[0].z-1.5?1.+.7*uP[0].w:1.))*.8,3.+mod(i,4.));}}return d;}void mat(float id,vec3 p,vec3 n,inout vec3 al,inout vec3 em,inout vec2 sp){if(id==2.){al=vec3(.9);sp=vec2(.05,.3);}if(id==3.)al=MINT;if(id==4.)al=LILAC;if(id==5.)al=BUTTER;if(id==6.)al=SKYB;if(id>2.5)sp=vec2(.12,.2);}`,
R(e){return 1.5*(1+.075*e.kick)},
ns(t){return Math.max(0,Math.min(12,Math.floor(t/2)-1))},
ha(t){return 2.2+t*.5},
cam(t,e){const a=.9+t*.035,c=t<16?0:1,D=c?8.2:9.4,y=c?6.6-(t-16)*.06:2.3+t*.03;
return[D*Math.cos(a+c*2.2),y,D*Math.sin(a+c*2.2),c?0:.5*Math.cos(a+1.6),c?1.1:1.55,c?0:.5*Math.sin(a+1.6),c?44:40,0]},
P(t,e,P){P[0]=this.R(e);P[1]=this.ha(t)-2.2;P[2]=this.ns(t);P[3]=e.arp},
head(t,e){const a=this.ha(t),r=this.R(e)+.8;return[r*Math.cos(a),1.6+.45*Math.sin(-t*.3),r*Math.sin(a)]},
hud(t,e,H){const R=this.R(e),n=this.ns(t);
H.span([-R,1.62+R+.25,0],[R,1.62+R+.25,0],'Ø '+H.pad(2*R,5,3)+' m');
H.tag([0,1.62,R],'CIRC '+H.pad(6.2832*R,5,2)+' m',-70,34,1);
if(n>0){const i=n-1,b=i*.5236-t*.07,o=3.5+.45*Math.sin(i*2.4);H.tag([o*Math.cos(b),1.3+.9*Math.sin(i*1.7+t*.15),o*Math.sin(b)],'SAT '+H.pad(n,2,0),40,-26)}
H.kv('PATIENT','A SPHERE. STABLE');H.kv('RATE','2.13 Hz');H.kv('BPM','128');
H.kv('CIRC',H.pad(6.2832*R,5,2)+' m',1)}};
SC[7]={name:'COUNT',acc:12,
glsl:`
#define KD normalize(vec3(.4,.75,.5))
#define FOGK .0001
float cb(vec3 p,vec2 c){float hh=h21(c+7.),z=uP[0].z;vec2 l2=-floor(uP[1].zw*.5);float s=any(lessThan(c,l2))||any(greaterThan(c,l2+uP[1].zw-1.))?uP[1].y:1.;vec3 q=p-vec3(c.x*1.3,.37*s+.02+z*(.6+1.6*hh),c.y*1.3);float A=(z*(.8+.3*sin(uP[0].w*.6+hh*40.))+uP[2].x)*2.;q.xy*=rot(A*(hh-.5));q.yz*=rot(A*(fract(hh*7.3)-.5));return sdRBox(q,vec3(.37*s),.035);}float map(vec3 p){gm=0.;float d=p.y;float zc=.65*cos(p.x*2.4166);d=U(d,max(rb(vec2(p.y-.42,p.z-zc),.3*sin(p.x*1.2+uP[0].w*.4),.18)*.5,p.x-uP[1].x),1.);vec2 lo=-floor(uP[0].xy*.5),hi=lo+uP[0].xy-1.,c0=floor(p.xz/1.3),bc=lo,e=abs(p.xz-(lo+hi)*.65)-(hi-lo+1.)*.65;float bd=9.;for(int i=0;i<4;i++){vec2 c=clamp(c0+vec2(i&1,i>>1),lo,hi);float b=cb(p,c);if(b<bd){bd=b;bc=c;}}float hh=h21(bc+7.);d=U(d,min(bd*.95,max(max(max(e.x,e.y),p.y-1.2-uP[0].z*2.3),0.)+.66),hh<.7?2.:3.+floor(fract(hh*13.7)*4.));return d;}void mat(float id,vec3 p,vec3 n,inout vec3 al,inout vec3 em,inout vec2 sp){if(id==3.)al=MINT;if(id==4.)al=LILAC;if(id==5.)al=BUTTER;if(id==6.)al=SKYB;if(id>1.5)sp=vec2(.07,.25);}`,
sm(x){x=Math.max(0,Math.min(1,x));return x*x*(3-2*x)},
k(t){return Math.min(7,Math.floor(t/4))},
rs(t,e){const f=Math.min(t,31)/31;return t<31?Math.max(e.riser||0,f*f*f):1},
hx(t){const f=Math.min(t,31);return -2+.4*(Math.floor(f)+this.sm((f%1)*1.6))},
cam(t,e){const f=Math.min(t,31),k=f/4,s=this.sm((f%4)/4*1.5),q=Math.floor(k)+s,a=.5+f*.012;
const D=1.7+1.8*Math.pow(2,q/2),y=-1+.72*D+this.rs(t,e)*1.2;
const o=.13*D;return[D*Math.sin(a),y,D*Math.cos(a),o*Math.sin(a),.4+this.rs(t,e)*1.1,o*Math.cos(a),32,0]},
P(t,e,P){const k=this.k(t),f=Math.min(t,31);P[0]=1<<((k+1)>>1);P[1]=1<<(k>>1);P[2]=this.rs(t,e);P[3]=f;
P[4]=this.hx(t);const u=Math.min(1,(t-k*4)*2.2);P[5]=t<4?1:1+2.6*u*(1-u)*(1-u)-(1-u)*(1-u)*(1-u);
P[6]=k?1<<(k>>1):1;P[7]=k?1<<((k-1)>>1):1;P[8]=t<31?e.snare*.12*this.rs(t,e):0},
head(t,e){const x=this.hx(t);return[x,.42,.65*Math.cos(x*2.4166)]},
hud(t,e,H){const k=this.k(t),n=1<<k,w=1<<((k+1)>>1),h=1<<(k>>1),r=this.rs(t,e),x1=(-Math.floor(w/2)+w)*1.3-.4,z0=-Math.floor(h/2)*1.3-.55;
H.span([x1,.02,z0],[x1,.02,z0+h*1.3-.2],H.pad(w,2,0)+' × '+H.pad(h,2,0));
H.tag([0,.8+r*1.4,0],'COUNT '+H.pad(n,4,0),64,-44,1);
H.kv('NEXT',t>=31?'HOLD':k<7?H.pad(n*2,4,0):'0256 (NO FLOOR LEFT)');H.kv('LIFT',H.pad(r*1.4,4,2)+' m');
H.kv('RISER',H.pad(Math.floor(r*100),3,0)+' %');H.kv('COUNT',H.pad(n,4,0),1)}};
SC[8]={name:'CITY',acc:6,cuts:[8,16,24],
glsl:`
#define KD normalize(vec3(.1,.62,.62))
#define FOGK .00017
float hc(vec2 c){ivec2 i=ivec2(c);uint n=uint(i.x)*1597334677u^uint(i.y)*3812015801u;n=(n^(n>>15))*739982445u;n^=n>>12;return float(n>>8)/16777216.;}float bh(vec2 c,float h){return c.y==0.?.04:(.4+12.*h*h*min(1.,.4+.2*abs(c.y)))*(1.+.35*KICK*fract(h*9.));}float bx(vec3 p,vec2 c){float h=bh(c,hc(c))*.5;vec2 q=p.xz-c*3.;return sdBox(vec3(q.x,p.y-h,q.y),vec3(.92,h,.92))-.04;}float map(vec3 p){gm=0.;float d=p.y;d=U(d,max(rb(vec2(p.y-1.15-.4*sin(p.x*.21),p.z-.75*sin(p.x*.13)),p.x*.17,.3)*.8,max(p.x-uP[0].x,uP[0].x-30.-p.x)),1.);vec2 c=floor(p.xz/3.);d=U(d,max(min(min(min(bx(p,c),bx(p,c+vec2(1,0))),min(bx(p,c+vec2(0,1)),bx(p,c+1.))),1.8),p.y-17.),2.);return d;}void mat(float id,vec3 p,vec3 n,inout vec3 al,inout vec3 em,inout vec2 sp){if(id==2.){float h=hc(round(p.xz/3.)),k=fract(h*17.);sp=vec2(.06,.3);if(k<.6&&abs(p.z)>1.6)al=k<.15?MINT:k<.3?LILAC:k<.45?BUTTER:SKYB;}}`,
V:60/(128/60),
hc(x,y){let n=Math.imul(x,1597334677)^Math.imul(y,3812015801);n=Math.imul(n^(n>>>15),739982445);n^=n>>>12;return(n>>>8)/16777216},
bh(x,y,e){const h=this.hc(x,y);return y==0?.04:(.4+12*h*h*Math.min(1,.4+.2*Math.abs(y)))*(1+.35*e.kick*((h*9)%1))},
hx(t){return 40+this.V*t},
ry(x){return[x,1.15+.4*Math.sin(x*.21),.75*Math.sin(x*.13)]},
cam(t,e){const x=this.hx(t),u=t%8;
if(t<8)return[x-13+u*.5,1.9+.2*Math.sin(t*.8),-1.25+.25*Math.sin(t*.35),x+9,2.4,.3,62,.05*Math.sin(t*.4)];
if(t<16)return[x-24+u,10-u*.5,.7,x+4,1,0,50,0];
if(t<24)return[x-9,31-u*.8,2,x-8,0,0,46,.5+u*.09];
return[x+6.5-u*.3,.9+u*.14,-1.2+u*.25,x-7,1.6,.2,60,-.06]},
P(t,e,P){P[0]=this.hx(t)},
head(t,e){return this.ry(this.hx(t))},
hud(t,e,H){const x=this.hx(Math.floor(t)+.5),cx=Math.round(x/3);
for(const[dx,z]of t<8||t>=24?[[2,1],[-1,-1]]:[[1,1],[-2,-1]]){const X=cx+(t>=24?-dx-1:dx),h=this.bh(X,z,e);H.tag([X*3,h,z*3],'h '+H.pad(h,5,2)+' m',z>0?44:-44,-30)}
H.kv('PERMITS','0000');H.kv('BLOCKS','NO LIMIT');H.kv('DIST',H.pad(this.V*Math.floor(t*4)/4/1000,5,3)+' km');
H.kv('V',H.pad(60+.4*e.kick,4,1)+' m/s',1)}};
SC[9]={name:'WEAVE',acc:10,
glsl:`
#define KD normalize(vec3(.5,.62,.28))
#define KR .03
#define FOGK .00025
float ch(vec2 p){return 1.3+.2*sin(p.x*.33+T*.4)*cos(p.y*.29-T*.27);}float th(vec3 p,float i,float n,float am,float sl,float sg,float y){i=clamp(i,-n,n-1.);float pr=mod(i,2.)*2.-1.;return max(rb(vec2(p.z-(i+.5)*.5,p.y-y-sg*pr*am*sin(6.2832*p.x)),0.,.17),abs(p.x-pr*sl)-8.3-.25*h11(i+sg*7.));}float th2(vec3 p,float n,float am,float sl,float sg,float y){float c=floor(p.z*2.),s=fract(p.z*2.)<.5?-1.:1.;return min(th(p,c,n,am,sl,sg,y),th(p,c+s,n,am,sl,sg,y));}float map(vec3 p){gm=0.;float d=p.y,y=ch(p.xz),v=abs(p.y-y),bx=sdBox(p-vec3(0,1.3,0),vec3(9.6,.5,9.6));if(bx>.1)return min(d,bx);if(v>.3)return min(d,v-.17);d=U(d,th2(p,uP[0].x,uP[1].x,uP[0].z,1.,y)*.7,h11(clamp(floor(p.z*2.),-uP[0].x,uP[0].x-1.)+43.)>.84?2.:1.);if(uP[0].y>0.)d=U(d,th2(p.zyx,uP[0].y,uP[1].y,uP[0].w,-1.,y)*.7,h11(clamp(floor(p.x*2.),-uP[0].y,uP[0].y-1.))>.6?3.:1.);return d;}vec3 pc(float h){h=fract(h*7.3)*4.;return h<1.?MINT:h<2.?LILAC:h<3.?BUTTER:SKYB;}void mat(float id,vec3 p,vec3 n,inout vec3 al,inout vec3 em,inout vec2 sp){if(id==2.){al=pc(h11(floor(p.z*2.)+43.));sp=vec2(.06,.25);}if(id==3.){al=pc(h11(floor(p.x*2.)));sp=vec2(.06,.25);}}`,
sm(x){x=Math.max(0,Math.min(1,x));return x*x*(3-2*x)},
nw(t){return Math.max(1,Math.min(16,Math.floor(t*2.5)+1))},
nf(t){return Math.max(0,Math.min(16,Math.floor((t-3)*2)))},
st(u,k){const q=[0,1,2,1],n=Math.floor(u),s=this.sm((u-n)*k);return .25*(q[n&3]*(1-s)+q[n+1&3]*s)},
sw(t){return this.st(t,3)},
sf(t){return this.st((t+1)/2,6)},
ch(x,z,t){return 1.3+.2*Math.sin(x*.33+t*.4)*Math.cos(z*.29-t*.27)},
cam(t,e){const k=this.sm(t/30),a=.45+t*.02,r=5.5+15*k;
return[Math.cos(a)*r,2.1+12*k*k,Math.sin(a)*r+2.5*(1-k),1.5*(1-k),1.2-.8*k,0,54-12*k,0]},
P(t,e,P){P[0]=this.nw(t);P[1]=this.nf(t);P[2]=this.sw(t);P[3]=this.sf(t);P[4]=.045+.07*e.kick;P[5]=.045+.07*e.snare},
head(t,e){const x=8.3+.25*.42+this.sw(t);return[x,this.ch(x,.25,t),.25]},
hud(t,e,H){const n=this.nw(t),m=this.nf(t);
H.kv('WARP / WEFT',H.pad(n*2,2,0)+' / '+H.pad(m*2,2,0));
H.kv('PICK','0.25 m');H.kv('THREADS',H.pad(n*2+m*2,3,0),n+m<32);
H.kv('KNOTS','0000');
if(t>12){H.span([-8,this.ch(-8,-8.6,t),-8.6],[8,this.ch(8,-8.6,t),-8.6],'16.00 m');
H.tag([0,this.ch(0,2,t)+.1,2],e.kick>e.snare?'WARP '+H.pad(.045+.07*e.kick,4,3):'WEFT '+H.pad(.045+.07*e.snare,4,3),50,-44)}}};
SC[10]={name:'HORIZON',acc:4,exp:1.08,
glsl:`
#define SKY
#define FOGK .00008
#define KD normalize(vec3(-.39,.44,-.81))
#define KC kc()
vec3 gp;float bsh();vec3 kc(){float s=bsh();return vec3(1.25,1.16,1.02)*s+CORAL*.4*(1.-s);}float bsh(){vec3 c=uP[0].xyz-gp,l=KD;return smoothstep(-30.,30.,length(c-l*dot(c,l))-uP[0].w+19.);}vec3 sk0(vec3 d){return mix(vec3(1.03,1.02,1.),vec3(.55,.66,.9),pow(clamp(d.y,0.,1.),.6));}vec3 sky(vec3 d){vec3 s=sk0(d),C=uP[0].xyz;float R=uP[0].w,b=dot(d,C),D=b*b-dot(C,C)+R*R;if(d.y<=0.||D<=0.||b<0.)return s;vec3 n=(d*(b-sqrt(D))-C)/R,m=n,a=vec3(0,1,0);m.xz*=rot(uP[1].x);m.xy*=rot(.5);float k=0.,ao=1.;for(int i=1;i<7;i++){float j=float(i);vec3 q=normalize(sin(vec3(1.,2.3,3.9)*j*2.1+vec3(.5,1.7,3.)));float v=abs(dot(m,q)+.3*sin(j*4.))-.2-.1*sin(j*7.);if(v<0.){a=q;k=j;ao=1.;}else ao=min(ao,v);}float u=dot(m,a)*36.,w=fract(u)-.5,h=h11(floor(u)+k*31.),e=smoothstep(.03,.35,dot(n,-d));a.xy*=rot(-.5);a.xz*=rot(-uP[1].x);vec3 nn=normalize(n+a*w*.6*e),al=h>.9?(h>.97?BUTTER:h>.95?MINT:h>.92?LILAC:SKYB):CORAL;al*=(1.-.4*e*smoothstep(.3,.5,abs(w)))*(.5+.5*smoothstep(0.,.07,ao));vec3 c=al*(vec3(1.5,1.4,1.2)*max(dot(nn,KD),0.)+mix(vec3(.84,.8,.78),vec3(.45,.52,.74),nn.y*.5+.5));return mix(s,mix(c,vec3(1.03,1.02,1.),.12+.8*exp(-d.y*13.)),smoothstep(0.,2.5*R,D));}float rn(vec3 p){float f=smoothstep(-42.,-8.,p.z);return max(rb(vec2(p.x-.12*sin(p.z*.21+T*.2),p.y-.22-f*(.48+.14*sin(p.z*.45-T*.5))),f*(p.z*.3+uP[1].y),.22)*(1.-.25*f),-90.-p.z);}float map(vec3 p){gm=0.;gp=p;float d=p.y;d=U(d,rn(p),1.);d=U(d,length(p-vec3(-3.,.8,-5.))-.8,2.);vec3 q=p-vec3(5.,.45,-4.);q.xz*=rot(.5);d=U(d,sdRBox(q,vec3(.45),.03),3.);float i=clamp(round(p.z),-70.,5.);d=U(d,sdCyl(p-vec3(1.3,.14,i),.05,.14)-.012,4.);return d;}void mat(float id,vec3 p,vec3 n,inout vec3 al,inout vec3 em,inout vec2 sp){if(id==2.){al=vec3(.92);sp=vec2(1.,.03);}if(id==3.)al=MINT;if(id==4.)al=vec3(.16);}`,
sm(x){x=Math.max(0,Math.min(1,x));return x*x*(3-2*x)},
R:480,
bh(t){t=Math.max(0,Math.min(32,t));const u=t/4,B=Math.floor(u)+this.sm((u%1)*2.2),b=Math.floor(t)+this.sm((t%1)*3);return -458+75*B+5.6*b},
spin(t){return .012*t+.03*(Math.floor(t)+this.sm((t%1)*3))},
cam(t,e){const k=this.sm(t/32),h=this.bh(t);
return[.85+.3*k,1.7+.2*k,9.5-1.2*k,-.4,1.3+Math.max(0,(h+this.R)*.017)*k+1.2*k,-40,62,0]},
P(t,e,P){P[0]=0;P[1]=this.bh(t);P[2]=-1000;P[3]=this.R;P[4]=this.spin(t);P[5]=.25*(Math.floor(t)+this.sm((t%1)*3))},
head(t,e){return null},
D:['0000.8 km','0003.1 km','0018.4 km','0152.0 km','0002.6 Mm','0041.3 Mm','0977.9 Mm'],
hud(t,e,H){const h=this.bh(t),R=this.R,bar=Math.min(7,t/4|0),tk=Math.floor(t*4)/4;
const p=h>-225?[-.47*R,h+.5*R,-1000+.73*R]:[0,h+R,-1000+60];
if(bar<7){const s=this.D[bar],v=+s.slice(0,6)*(1+.02*(tk%4));H.tag(p,'Ø '+H.pad(v,6,1)+s.slice(6),-70,-44)}
else H.tag(p,'Ø OUT OF RANGE',-70,-44,1);
H.tag([-3,1.6,-5],'Ø 1.600 m',-46,-30);
if(t>8&&t<24)H.tag([5,.9,-4],'0.900 m',44,-26);
H.kv('TAPE',t<20?'OK':'INSUFFICIENT',t>=20);
H.kv('RIBBON','41 000 km');
H.kv('ELEV',(h+R<0?'-':'+')+H.pad(Math.atan2(this.bh(tk)+R,1000)*57.3,5,2)+'°');
H.kv('REFERENCE','1 PEG = 1.000 m')}};
SC[11]={name:'FATHOM',acc:14,exp:.85,
glsl:`
#define SKY
#define FOGK .00007
#define KD normalize(vec3(.55,.6,.5))
#define KC (vec3(1.25,1.16,1.02)*bsh())
vec3 gp;float bsh(){vec3 c=vec3(0,9,0)-gp,l=KD;float b=dot(c,l);return b<0.?1.:smoothstep(-.07*b-.05,.07*b+.05,length(c-l*b)-9.);}vec3 sky(vec3 d){return mix(vec3(1.5,1.47,1.44),vec3(.6,.7,.93),smoothstep(0.,.3,d.y));}vec4 wd(vec3 m){m.xz*=rot(uP[0].y);m.xy*=rot(.5);vec3 a=vec3(0,1,0);float k=0.,ao=1.;for(int i=1;i<7;i++){float j=float(i);vec3 q=normalize(sin(vec3(1.,2.3,3.9)*j*2.1+vec3(.5,1.7,3.)));float v=abs(dot(m,q)+.3*sin(j*4.))-.2-.1*sin(j*7.);if(v<0.){a=q;k=j;ao=1.;}else ao=min(ao,v);}float u=dot(m,a)*16.;return vec4(fract(u)-.5,h11(floor(u)+k*31.),ao,k);}float map(vec3 p){gm=0.;p*=2.5;gp=p;float d=p.y;vec3 c=p-vec3(0,9,0);float l=length(c),e=l-9.;if(e<.6){vec4 w=wd(c/l);e=(e-.05*w.w+.12*smoothstep(.2,.5,abs(w.x)))*.5;}else e-=.35;d=U(d,e,5.);float x=min(p.x,66.),f=smoothstep(0.,10.,66.-x),z=7.*sin(x*.0714);float r=max(rb(vec2(p.z-z,p.y-.3-.13*f*sin(x*.5-T*.6)),.3*f*sin(x*.17+T*.2),.3)*.7,max(p.x-66.,2.-p.x));vec2 q=vec2(p.x-66.,p.y-2.5);float a=atan(q.x,-q.y);if(a<-.4)a+=6.2832;float rr=2.2*(1.-.1*a);r=min(r,max(rb(vec2(p.z+7.,length(q)-rr),0.,.3)*.8,max(a-uP[0].x,-a)*rr));d=U(d,r,1.);d=U(d,length(p-vec3(11.5,.2,1.5))-.2,2.);return d*.4;}void mat(float id,vec3 p,vec3 n,inout vec3 al,inout vec3 em,inout vec2 sp){if(id==2.){al=vec3(.92);sp=vec2(1.,.03);}if(id==5.){vec4 w=wd(normalize(p*2.5-vec3(0,9,0)));float h=w.y;al=(h>.9?(h>.97?BUTTER:h>.95?MINT:h>.92?LILAC:SKYB):CORAL)*(.7+.3*smoothstep(0.,.05,w.z));sp=vec2(.06,.25);}}`,
sm(x){x=Math.max(0,Math.min(1,x));return x*x*(3-2*x)},
th(t){return .35+4.75*this.sm((t-1)/30)+Math.min(.75,.07*Math.max(0,t-31))},
tip(t){const a=this.th(t),r=2.2*(1-.1*a);return[26.4+.4*r*Math.sin(a),1-.4*r*Math.cos(a),-2.8]},
cam(t,e){const k=1-Math.exp(-t/10)+.012*Math.max(0,t-30);
return[8.8+17.6*k,2.4+25.6*k,10.4+35.2*k,2+8.6*k,3.2+3.6*k,-11.2*k,36-6*k,0]},
P(t,e,P){P[0]=this.th(t);P[1]=.012*t},
head(t,e){return this.tip(t)},
flash(t,e){return t>=32?.4*e.impact:0},
hud(t,e,H){
H.big('FATHOM','',(t-6)/3,.26);
if(t>=16){const k=.6,x=this.x=this.x||document.getElementById('h').getContext('2d');
if(x){x.save();x.translate(x.canvas.width/2*(1-k),0);x.scale(k,k)}
H.big('FABLE 5.2 · MODEL SALT AT 2','',(t-16)/2,x?.385/k:.385);if(x)x.restore()}
H.tag([0,7.3,0],'Ø OUT OF RANGE',-60,-40,1);H.tag([4.6,.16,.6],'Ø 1.600 m',46,-30);
if(t>=8)H.kv('PLATES','12 / 12');
if(t>=12)H.kv('MEASURED',H.pad(99.9*Math.min(1,Math.floor((t-12)*4)/48),4,1)+' %');
if(t>=28)H.kv('REMAINDER:','UNFATHOMED',1)}};
for(let i=0;i<12;i++)SC[i]=SC[i]||SC[0];
(()=>{
const D=document,$=i=>D.getElementById(i),cv=$('g'),hc=$('h'),hx=hc.getContext('2d'),Q=new URLSearchParams(location.hash.slice(1));
const gl=cv.getContext('webgl2',{antialias:false,alpha:false,powerPreference:'high-performance'});
const st=window.__st={frames:0,dts:[],errs:[],scale:0,ready:0,chunks:0,ended:0,first:-1,sd:[]};
if(!gl||!(gl.getExtension('EXT_color_buffer_float')||gl.getExtension('EXT_color_buffer_half_float'))){$('msg').textContent='THIS DEMO NEEDS WEBGL 2 WITH FLOAT RENDER TARGETS';return}
const par=gl.getExtension('KHR_parallel_shader_compile');
const VS='#version 300 es\nvoid main(){gl_Position=vec4(vec2(gl_VertexID&1,gl_VertexID>>1)*4.-1.,0,1);}';
function sh(t,s){const o=gl.createShader(t);gl.shaderSource(o,s);gl.compileShader(o);return o}
function mk(fs,name){const p=gl.createProgram(),a=sh(gl.VERTEX_SHADER,VS),b=sh(gl.FRAGMENT_SHADER,fs);gl.attachShader(p,a);gl.attachShader(p,b);gl.linkProgram(p);return{p,b,name,ok:0,u:{}}}
function poll(o){if(o.ok)return 1;if(par&&!gl.getProgramParameter(o.p,par.COMPLETION_STATUS_KHR))return 0;
if(!gl.getProgramParameter(o.p,gl.LINK_STATUS)){const e=o.name+': '+gl.getShaderInfoLog(o.b)+gl.getProgramInfoLog(o.p);st.errs.push(e);console.error(e);o.ok=-1;return 1}
const n=gl.getProgramParameter(o.p,gl.ACTIVE_UNIFORMS);for(let i=0;i<n;i++){const u=gl.getActiveUniform(o.p,i).name.replace('[0]','');o.u[u]=gl.getUniformLocation(o.p,u)}o.ok=1;return 1}
const fx={},jobs=[];for(const k in FX)jobs.push(()=>fx[k]=mk(FX[k],k));
SC.forEach((s,i)=>{if(SC.indexOf(s)==i)jobs.push(()=>s.pr=mk(PRE+s.glsl+POST,'scene '+i))});
let cur=null;function compileStep(){if(cur&&!poll(cur))return;if(cur&&cur.ok>0)st.ready++;cur=jobs.length?jobs.shift()():null}
let W=0,H=0,pw=0,ph=0,scale=+Q.get('s')||0,fixed=!!Q.get('s'),pt=[],dn=[],bl=[],flip=0,reset=1;
function tex(w,h,f,lin){const t=gl.createTexture();gl.bindTexture(gl.TEXTURE_2D,t);gl.texStorage2D(gl.TEXTURE_2D,1,f,w,h);
for(const[k,v]of[[gl.TEXTURE_MIN_FILTER,lin?gl.LINEAR:gl.NEAREST],[gl.TEXTURE_MAG_FILTER,lin?gl.LINEAR:gl.NEAREST],[gl.TEXTURE_WRAP_S,gl.CLAMP_TO_EDGE],[gl.TEXTURE_WRAP_T,gl.CLAMP_TO_EDGE]])gl.texParameteri(gl.TEXTURE_2D,k,v);return t}
function fbo(ts,w,h){const f=gl.createFramebuffer();gl.bindFramebuffer(gl.FRAMEBUFFER,f);ts.forEach((t,i)=>gl.framebufferTexture2D(gl.FRAMEBUFFER,gl.COLOR_ATTACHMENT0+i,gl.TEXTURE_2D,t,0));
gl.drawBuffers(ts.map((t,i)=>gl.COLOR_ATTACHMENT0+i));return{f,t:ts,w,h}}
function kill(l){l.forEach(o=>{o.t.forEach(t=>gl.deleteTexture(t));gl.deleteFramebuffer(o.f)})}
function resize(){const dpr=Math.min(devicePixelRatio||1,2),cw=innerWidth,ch=innerHeight;
W=cv.width=cw;H=cv.height=ch;hc.width=cw*dpr|0;hc.height=ch*dpr|0;
if(!scale)scale=Math.min(1,Math.sqrt(72e4/(cw*ch)));
pw=Math.max(8,W*scale&~1);ph=Math.max(8,H*scale&~1);kill(pt);kill(dn);kill(bl);
const F=gl.RGBA16F;pt=[0,1].map(()=>fbo([tex(pw,ph,F,1),tex(pw,ph,F,0)],pw,ph));dn=[0,1].map(()=>fbo([tex(pw,ph,F,1)],pw,ph));
bl=[];for(let i=1,w=pw,h=ph;i<6&&w>16&&h>16;i++){w>>=1;h>>=1;bl.push(fbo([tex(w,h,F,1)],w,h),fbo([tex(w,h,F,1)],w,h))}
reset=1;st.scale=scale;st.pw=pw;st.ph=ph}
addEventListener('resize',resize);resize();
function bind(o,i,t){gl.activeTexture(gl.TEXTURE0+i);gl.bindTexture(gl.TEXTURE_2D,t);gl.uniform1i(o.u[['uA','uG','uB'][i]],i)}
function pass(o,dst,a,g,b,x){gl.bindFramebuffer(gl.FRAMEBUFFER,dst?dst.f:null);gl.viewport(0,0,dst?dst.w:W,dst?dst.h:H);gl.useProgram(o.p);
if(a)bind(o,0,a);if(g)bind(o,1,g);if(b)bind(o,2,b);if(x)gl.uniform4fv(o.u.uX,x);return o}
const BPM=SONG.bpm,END=SONG.len+(SONG.tail||4),mute=Q.has('mute');
let ac=null,gain=null,sr=48000,chunks=[],srcs=[],t0=0,started=0,pn0=0,off=0,B0=+Q.get('b')||0;
try{ac=new(window.AudioContext||webkitAudioContext)({latencyHint:'playback'});sr=ac.sampleRate;gain=ac.createGain();gain.gain.value=mute?0:.9;gain.connect(ac.destination)}catch(e){}
let wk=null;try{wk=new Worker(URL.createObjectURL(new Blob([SYN],{type:'text/javascript'})));wk.onmessage=e=>{const m=e.data;if(m.done){st.audioDone=1;return}
let buf=null;if(ac){buf=ac.createBuffer(2,m.L.length,sr);buf.copyToChannel(m.L,0);buf.copyToChannel(m.R,1)}
const c={s:m.s,n:m.L.length,buf};chunks.push(c);st.chunks=chunks.length;if(started)sched(c)};
wk.onerror=e=>{st.errs.push('worker '+e.message)};wk.postMessage({sr})}catch(e){st.errs.push('worker '+e)}
function sched(c){if(!ac||!c.buf)return;const w=t0+c.s/sr,now=ac.currentTime,d=c.n/sr;if(w+d<now+.01)return;
const s=ac.createBufferSource();s.buffer=c.buf;s.connect(gain);s.onended=()=>st.ended++;if(w>=now)s.start(w);else s.start(now,now-w);srcs.push(s)}
function start(){if(started)return;started=1;const pn=performance.now();
srcs.forEach(s=>{try{s.stop()}catch(e){}});srcs=[];st.ended=0;
if(ac){ac.resume();t0=ac.currentTime+.05-B0*60/BPM;chunks.forEach(sched)}
pn0=pn+50-B0*6e4/BPM;off=0;$('sp').style.display='none';st.started=pn;st.first=-1;reset=1;
frame(pn,1);st.first=performance.now()-pn}
function clock(now){if(!started)return 0;let tp=(now-pn0)/1e3+off;
if(ac&&ac.state=='running'){const ta=ac.currentTime-t0-(ac.outputLatency||ac.baseLatency||0),e=ta-tp;st.aerr=e;if(Math.abs(e)>.15)off+=e;else off+=e*.02;tp=(now-pn0)/1e3+off}
st.t=tp;st.ac=ac?ac.currentTime-t0:0;return tp}
const cam={ro:[0,1,5],u:[1,0,0],v:[0,1,0],w:[0,0,-1]},pc={ro:[0,1,5],u:[1,0,0],v:[0,1,0],w:[0,0,-1]};
const nrm=a=>{const l=Math.hypot(a[0],a[1],a[2])||1;return[a[0]/l,a[1]/l,a[2]/l]},crs=(a,b)=>[a[1]*b[2]-a[2]*b[1],a[2]*b[0]-a[0]*b[2],a[0]*b[1]-a[1]*b[0]];
function setCam(c){const ro=[c[0],c[1],c[2]],w=nrm([c[3]-c[0],c[4]-c[1],c[5]-c[2]]);let r=nrm(crs(w,[0,1,0])),u=crs(r,w);
const ro2=c[7]||0,cs=Math.cos(ro2),sn=Math.sin(ro2),r2=r.map((x,i)=>x*cs+u[i]*sn),u2=u.map((x,i)=>u[i]*cs-r[i]*sn),tf=Math.tan((c[6]||50)*Math.PI/360),as=W/H;
cam.ro=ro;cam.w=w;cam.u=r2.map(x=>x*tf*as);cam.v=u2.map(x=>x*tf)}
function proj(p){const d=[p[0]-cam.ro[0],p[1]-cam.ro[1],p[2]-cam.ro[2]],dt=(a,b)=>a[0]*b[0]+a[1]*b[1]+a[2]*b[2],z=dt(d,cam.w);if(z<.05)return null;
return[(dt(d,cam.u)/dt(cam.u,cam.u)/z*.5+.5)*hc.width,(.5-dt(d,cam.v)/dt(cam.v,cam.v)/z*.5)*hc.height,z]}
const Pv=new Float32Array(32),env={};let frameNo=0,lastScene=-1,lastCut=-1,lastNow=0,slow=0,fast=0,exposure=.66;
const HUD=mkHud(hx,hc,proj,st);
function frame(now,once){if(!once)requestAnimationFrame(frame);compileStep();
if(lastNow&&started&&!once){const dt=now-lastNow;st.dts.push(dt);(st.sd[st.scene]=st.sd[st.scene]||[]).push(dt);if(st.dts.length>12e3)st.dts.shift();
if(!fixed){if(dt>21)slow++;else slow=Math.max(0,slow-.25);if(dt<17.4)fast++;else fast=0;
if(slow>24&&scale>.3){scale=Math.max(.3,scale*.85);slow=0;fast=0;resize()}}}
lastNow=now;
let t=clock(now),beat=Q.has('still')?+Q.get('still')+frameNo*1e-4:t*BPM/60;const still=Q.has('still');if(!started&&!still)beat=0;
if(started&&t>END){started=0;B0=0;$('sp').style.display='';$('go').textContent='AGAIN';st.over=1;beat=0}
const si=Math.max(0,Math.min(SC.length-1,beat/32|0)),s=SC[si],sp=s.pr&&s.pr.ok>0?s:SC.slice(0,si).reverse().find(x=>x.pr&&x.pr.ok>0);
const e=SONG.at(beat);Object.assign(env,e);env.b=beat;env.t=beat-si*32;env.s=si;env.started=started||still;
st.scene=si;st.beat=beat;
hx.setTransform(1,0,0,1,0,0);hx.clearRect(0,0,hc.width,hc.height);
if(sp&&fx.fin&&fx.fin.ok>0&&fx.dn.ok>0&&fx.dw.ok>0&&fx.up.ok>0){
const lt=sp==s?env.t:32;
let ci=si*100;(sp.cuts||[]).forEach((c,i)=>{if(lt>=c)ci=si*100+i+1});if(ci!=lastCut){reset=1;lastCut=ci;
if(!fixed&&started&&fast>240&&scale<1&&sp==s&&lastScene!=si){scale=Math.min(1,scale*1.12);fast=0;resize()}}
lastScene=si;
pc.ro=cam.ro;pc.u=cam.u;pc.v=cam.v;pc.w=cam.w;setCam(sp.cam(lt,env));Pv.fill(0);if(sp.P)sp.P(lt,env,Pv);
if(reset){pc.ro=cam.ro;pc.u=cam.u;pc.v=cam.v;pc.w=cam.w}
const a=pt[flip],b=pt[flip^=1],o=sp.pr,u=o.u;
gl.bindFramebuffer(gl.FRAMEBUFFER,b.f);gl.viewport(0,0,pw,ph);gl.useProgram(o.p);bind(o,0,a.t[0]);bind(o,1,a.t[1]);
gl.uniform3fv(u.uRo,cam.ro);gl.uniform3fv(u.uU,cam.u);gl.uniform3fv(u.uV,cam.v);gl.uniform3fv(u.uW,cam.w);
gl.uniform3fv(u.pRo,pc.ro);gl.uniform3fv(u.pU,pc.u);gl.uniform3fv(u.pV,pc.v);gl.uniform3fv(u.pW,pc.w);
gl.uniform2f(u.uRes,pw,ph);gl.uniform4f(u.uF,frameNo,reset,started?(sp.acc||14):64,0);
gl.uniform4f(u.uE,e.kick,e.snare,e.hat,e.energy);gl.uniform4f(u.uM,lt,beat,e.impact,e.riser);gl.uniform4f(u.uN,e.bass,e.arp,e.lead,e.chord);
gl.uniform4fv(u.uP,Pv);gl.drawArrays(gl.TRIANGLES,0,3);reset=0;
pass(fx.dn,dn[0],b.t[0],b.t[1],0,[1,0,0,0]);gl.drawArrays(gl.TRIANGLES,0,3);
pass(fx.dn,dn[1],dn[0].t[0],b.t[1],0,[2,0,0,0]);gl.drawArrays(gl.TRIANGLES,0,3);
let src=dn[1];const n=bl.length/2;
for(let i=0;i<n;i++){const d=bl[i*2];gl.uniform2f(pass(fx.dw,d,src.t[0],0,0,[1/d.w,1/d.h,0,0]).u.uPx,1/src.w,1/src.h);gl.drawArrays(gl.TRIANGLES,0,3);src=d}
for(let i=n-2;i>=0;i--){const d=bl[i*2+1],lo=i==n-2?bl[i*2+2]:bl[i*2+3];gl.uniform2f(pass(fx.up,d,lo.t[0],0,bl[i*2].t[0],[1/d.w,1/d.h,0,0]).u.uPx,1/lo.w,1/lo.h);gl.drawArrays(gl.TRIANGLES,0,3)}
const fl=started||still?Math.max(0,1-env.t/1.2)*(si>0?.55:0)+(sp.flash?sp.flash(lt,env):0):0,fd=started?Math.max(0,Math.min(1,(t-SONG.len-1)/(END-SONG.len-1.5))):0;
{const o=pass(fx.fin,null,dn[1].t[0],0,n>1?bl[1].t[0]:bl[0].t[0],[(sp.exp||1)*exposure,Math.min(1,fl),fd,frameNo]);gl.uniform2f(o.u.uPx,1/W,1/H);gl.uniform4f(o.u.uY,1/pw,1/ph,0,0)}gl.drawArrays(gl.TRIANGLES,0,3);
if(!Q.has('nohud'))HUD(sp==s?s:null,si,env,cam,t,scale)
}else{hx.fillStyle='#e9eaee';hx.fillRect(0,0,hc.width,hc.height);if(!Q.has('nohud'))HUD(null,si,env,cam,t,scale)}
frameNo++;st.frames++}
if(Q.has('still'))$('sp').style.display='none';$('go').onclick=start;addEventListener('keydown',e=>{if((e.key=='Enter'||e.key==' ')&&!started)start();if(e.key=='f'||e.key=='F'){const el=D.documentElement;(D.fullscreenElement||D.webkitFullscreenElement)?(D.exitFullscreen||D.webkitExitFullscreen).call(D):(el.requestFullscreen||el.webkitRequestFullscreen).call(el)}});
requestAnimationFrame(frame)})();</script>