const view=document.getElementById("view"),vctx=view.getContext("2d",{alpha:!1}),sourceCanvas=document.createElement("canvas"),sctx=sourceCanvas.getContext("2d",{alpha:!1}),stateCanvas=document.createElement("canvas"),stctx=stateCanvas.getContext("2d",{alpha:!1}),workCanvas=document.createElement("canvas"),wctx=workCanvas.getContext("2d",{alpha:!1}),tinyCanvas=document.createElement("canvas"),tctx=tinyCanvas.getContext("2d",{alpha:!1}),probeCanvas=document.createElement("canvas"),pctx=probeCanvas.getContext("2d",{alpha:!1,willReadFrequently:!0}),hint=document.getElementById("hint");let W=0,H=0,ready=!1,compressionBusy=!1,depth=.2,depthVel=0,targetDepth=.2,burst=0,audioCtx=null,audioStarted=!1,audioPossible=!1,audioEnabled=!1,noiseNode=null,masterGain=null,audioLP=null,audioShelf=null,audioHP=null,audioComp=null,audioImpact=0,audioCrush=0,audioDensity=0,audioJerk=0,audioThump=0,audioFreak=0,audioChaos=0,audioSlam=0,audioDownsample=0,prevCompressionScore=0,compressionLoopToken=0,compressionTimer=0,lastVisualSig="",lastVisualChangeAt=0,lastHardResetAt=0,toneControl=Number.isFinite(window.TONE)?window.TONE:10,activityBoost=0,lastCompressionProgressAt=0,consecutiveStalls=0,audioBurstTone=0,audioBurstPitch=0,audioTransient=0,lastCompressionStartAt=0,watchdogTimer=0,lastResizeShockAt=0,audioVisualChange=0,audioVisualMotion=0,lastVisualChangePulseAt=0;const RESET_COOLDOWN_MS=700,LOW_ACTIVITY_START_MS=420,LOW_ACTIVITY_FULL_MS=1200,COMPRESSION_PROGRESS_TIMEOUT_MS=1400,VISUAL_FREEZE_TIMEOUT_MS=1800,MAX_CONSECUTIVE_STALLS_BEFORE_HARD_RESET=2,RESIZE_SHOCK_COOLDOWN_MS=420,ART_HASH=normalizeEthHash(window.ART_HASH),ART_PALETTES=window.ART_PALETTES;function normalizeEthHash(t){const a="0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";if("string"!=typeof t)return a;const e=t.trim().toLowerCase();return/^0x[0-9a-f]{64}$/.test(e)?e:a}function createHashRng(t){const a=normalizeEthHash(t).slice(2);let e=parseInt(a.slice(0,8),16)>>>0,n=parseInt(a.slice(8,16),16)>>>0,o=parseInt(a.slice(16,24),16)>>>0,s=parseInt(a.slice(24,32),16)>>>0;return 0===(e|n|o|s)&&(e=305419896,n=2596069104,o=4275878552,s=2271560481),function(){let t=e+n+s|0;return s=s+1|0,e=n^n>>>9,n=o+(o<<3)|0,o=o<<21|o>>>11,o=o+t|0,(t>>>0)/4294967296}}function hashUnitAt(t){const a=ART_HASH.slice(2),e=8*t%(a.length-8),n=a.slice(e,e+8);return parseInt(n,16)/4294967295}function makeSeededRandom(t){return function(a,e){return a+t()*(e-a)}}function hideHint(){hint&&hint.classList.add("hidden")}function showHint(){hint&&hint.classList.remove("hidden")}function canUseAudio(){return!(!(window.AudioContext||window.webkitAudioContext)||!window.isSecureContext)}function clamp(t,a,e){return Number.isFinite(t)?Math.max(a,Math.min(e,t)):a}function finiteOr(t,a=0){return Number.isFinite(t)?t:a}function safeParam(t,a,e,n,o,s,i=e){if(!t)return;const r=clamp(finiteOr(a,i),e,n);t.setTargetAtTime(r,o,s)}function lerp(t,a,e){return t+(a-t)*e}function hslToHex(t,a,e){e/=100;const n=a=>(a+t/30)%12,o=(a/=100)*Math.min(e,1-e),s=t=>e-o*Math.max(-1,Math.min(n(t)-3,Math.min(9-n(t),1))),i=t=>Math.round(255*t).toString(16).padStart(2,"0");return`#${i(s(0))}${i(s(8))}${i(s(4))}`}function makeLandscapePalette(t){const a=hslToHex(t(0,360),t(65,92),t(38,58)),e=t(0,360);let n=(e+t(70,220))%360,o=(e+t(140,300))%360;return t(0,1)<.35&&(n=(e+t(20,60))%360),t(0,1)<.25&&(o=(n+t(20,80))%360),{bg:a,top:hslToHex(e,t(65,92),t(38,58)),mid:hslToHex(n,t(30,85),t(10,34)),low:hslToHex(o,t(35,88),t(18,46)),extra:hslToHex(t(0,360),t(20,70),t(18,62))}}function getSeededPalette(t){return a=ART_PALETTES,a?{bg:a[0],top:a[1],mid:a[2],low:a[3],extra:a[4]}:makeLandscapePalette(t)}function makeNoise(t){return function(a){const e=43758.5453123*Math.sin(12.9898*a+78.233*t);return e-Math.floor(e)}}function buildPolyline(t){if(!t.length)return"";let a=`M ${t[0].x.toFixed(2)} ${t[0].y.toFixed(2)}`;for(let e=1;e<t.length;e++)a+=` L ${t[e].x.toFixed(2)} ${t[e].y.toFixed(2)}`;return a}function resize(){const t=window.innerHeight/window.innerWidth;W=640,H=Math.round(640*t),view.width=W,view.height=H,sourceCanvas.width=W,sourceCanvas.height=H,stateCanvas.width=W,stateCanvas.height=H,workCanvas.width=W,workCanvas.height=H,generateBaseSVG()}function buildSmoothPath(t){if(!t.length)return"";if(t.length<2)return`M ${t[0].x.toFixed(2)} ${t[0].y.toFixed(2)}`;let a=`M ${t[0].x.toFixed(2)} ${t[0].y.toFixed(2)}`;for(let e=0;e<t.length-1;e++){const n=t[Math.max(0,e-1)],o=t[e],s=t[e+1],i=t[Math.min(t.length-1,e+2)],r=.22,u=o.x+(s.x-n.x)*r,h=o.y+(s.y-n.y)*r,m=s.x-(i.x-o.x)*r,c=s.y-(i.y-o.y)*r;a+=` C ${u.toFixed(2)} ${h.toFixed(2)}, ${m.toFixed(2)} ${c.toFixed(2)}, ${s.x.toFixed(2)} ${s.y.toFixed(2)}`}return a}function makeSoftWaveLine(t,a,e,n,o={}){const s=makeNoise(e),i=[],r=o.steps||14,u=n(.8,2.2),h=n(2,4.5),m=n(4,8),c=n(-Math.PI,Math.PI),d=n(-Math.PI,Math.PI),l=n(-Math.PI,Math.PI),p=n(.05*-H,.05*H),f=n(.04*-H,.06*H);for(let e=0;e<=r;e++){const o=e/r,g=o*W,w=t+(Math.sin(o*Math.PI*u+c)*a*n(.55,1)+Math.sin(o*Math.PI*h+d)*a*n(.1,.3)+Math.sin(o*Math.PI*m+l)*a*n(.03,.14)+(s(o*n(1.5,4.5))-.5)*a*n(.05,.16))+(o-.5)*p+Math.sin(o*Math.PI)*f;i.push({x:g,y:w})}return i}function makeRibbonBand(t,a){const{yBase:e,thickness:n,amp:o,seed:s}=t,i=makeSoftWaveLine(e,o,s,a,{steps:14}),r=[],u=makeNoise(s+100),h=a(.8,2.6),m=a(-Math.PI,Math.PI);for(let t=0;t<i.length;t++){const e=i[t],o=t/(i.length-1),s=n*(.9+.22*Math.sin(o*Math.PI*h+m))+(u(3.2*o)-.5)*n*.08,c=Math.sin(o*Math.PI*a(1.2,3.5)+a(-Math.PI,Math.PI))*n*.08;r.push({x:e.x+c,y:e.y+s})}return{top:i,bottom:r}}function ribbonPath(t,a){const e=buildSmoothPath(t),n=[...a].reverse(),o=buildSmoothPath(n).replace(/^M[^CML]*/,"");return`${e} L ${n[0].x.toFixed(2)} ${n[0].y.toFixed(2)} ${o} Z`}function linePath(t){return buildSmoothPath(t)}function generateBaseSVG(){ready=!1;const t=makeSeededRandom(createHashRng(ART_HASH)),a=getSeededPalette(t),e=[];e.push(`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${W} ${H}" width="${W}" height="${H}">`),e.push(`<rect width="${W}" height="${H}" fill="${a.bg}"/>`);let n=-.02*H;const o=Math.max(2,Math.floor(t(5,8)));for(let s=0;s<o;s++){const o=t(.035*H,.075*H),i=makeRibbonBand({yBase:n,thickness:o,amp:t(.012*H,.035*H),seed:t(0,1e3)},t),r=0===s?a.top:1===s?a.extra:a.top;if(e.push(`<path d="${ribbonPath(i.top,i.bottom)}" fill="${r}"/>`),t(0,1)<.92){const n=i.top.map((a,e)=>{const n=i.bottom[e];return{x:lerp(a.x,n.x,t(.45,.7)),y:lerp(a.y,n.y,t(.45,.7))}});e.push(`<path d="${linePath(n)}" fill="none" stroke="${a.bg}" stroke-width="${t(.006*H,.012*H).toFixed(2)}" stroke-linecap="round" stroke-linejoin="round"/>`)}n+=o*t(.52,.74)}let s=H*t(.28,.36);const i=Math.max(5,Math.floor(t(5,8))),r=[a.mid,a.low,a.extra];for(let n=0;n<i;n++){const o=t(.055*H,.11*H),i=t(.035*H,.095*H),u=n<r.length?r[n]:r[n%r.length],h=makeRibbonBand({yBase:s,thickness:o,amp:i,seed:t(0,1e3)},t);e.push(`<path d="${ribbonPath(h.top,h.bottom)}" fill="${u}"/>`);const m=t(0,1)<.55?1:2;for(let n=0;n<m;n++){const o=(n+1)/(m+1),s=h.top.map((t,a)=>{const e=h.bottom[a];return{x:lerp(t.x,e.x,o),y:lerp(t.y,e.y,o)}});e.push(`<path d="${linePath(s)}" fill="none" stroke="${a.bg}" stroke-width="${t(.006*H,.014*H).toFixed(2)}" stroke-linecap="round" stroke-linejoin="round"/>`)}s+=o*t(.45,.64)}let u=H+.03*H;const h=Math.max(4,Math.floor(t(4,7))),m=[a.low,a.mid];for(let n=0;n<h;n++){const o=t(.07*H,.14*H),s=t(.025*H,.07*H),i=n<m.length?m[n]:m[n%m.length],r=makeRibbonBand({yBase:u-o,thickness:o,amp:s,seed:t(0,1e3)},t),h=r.bottom.map(t=>({x:t.x,y:Math.max(t.y,H+4)}));e.push(`<path d="${ribbonPath(r.top,h)}" fill="${i}"/>`);const c=t(0,1)<.7?1:2;for(let n=0;n<c;n++){const o=(n+1)/(c+1),s=r.top.map((a,e)=>{const n=h[e],s=o*t(.7,.95);return{x:lerp(a.x,n.x,s),y:lerp(a.y,n.y,s)}});e.push(`<path d="${linePath(s)}" fill="none" stroke="${a.bg}" stroke-width="${t(.007*H,.015*H).toFixed(2)}" stroke-linecap="round" stroke-linejoin="round"/>`)}u-=o*t(.48,.7)}e.push("</svg>");const c=new Image;c.onload=()=>{sctx.clearRect(0,0,W,H),sctx.drawImage(c,0,0,W,H),resetCompressionStateForFreshStart(),ready=!0,drawDisplay(),queueCompressionStart(0)},c.src="data:image/svg+xml;charset=utf-8,"+encodeURIComponent(e.join(""))}function canvasToBlob(t,a){return new Promise((e,n)=>{t.toBlob(t=>{t?e(t):n(new Error("JPEG export failed"))},"image/jpeg",a)})}async function blobToBitmap(t){return createImageBitmap(t)}function queueCompressionStart(t=0){clearTimeout(compressionTimer),compressionTimer=setTimeout(startCompressionLoop,t)}function getVisualSignature(){probeCanvas.width=16,probeCanvas.height=16,pctx.imageSmoothingEnabled=!1,pctx.clearRect(0,0,16,16),pctx.drawImage(stateCanvas,0,0,16,16);const t=pctx.getImageData(0,0,16,16).data;let a=2166136261;for(let e=0;e<t.length;e+=16)a^=t[e]|t[e+1]<<8|t[e+2]<<16|t[e+3]<<24,a=Math.imul(a,16777619);return(a>>>0).toString(16)}function checkForVisualFreeze(){const t=performance.now(),a=getVisualSignature();if(a!==lastVisualSig){const e=clamp(1-(t-lastVisualChangeAt)/900,.15,1);return audioVisualChange=Math.max(audioVisualChange,e),audioVisualMotion=Math.max(audioVisualMotion,.35+.65*e),t-lastVisualChangePulseAt>160&&(audioBurstTone=Math.max(audioBurstTone,.18+.35*e),audioBurstPitch=Math.max(audioBurstPitch,.18+.45*Math.random()),audioTransient=Math.max(audioTransient,.22+.35*e),lastVisualChangePulseAt=t),lastVisualSig=a,lastVisualChangeAt=t,consecutiveStalls=0,!1}return(depth>.08||Math.abs(depthVel)>.001||targetDepth>.16||burst>.02||activityBoost>.05)&&t-lastVisualChangeAt>1800}function getLowActivityAmount(){const t=performance.now();if(!(depth>.08||Math.abs(depthVel)>.0012||targetDepth>.16||burst>.02))return 0;const a=t-lastVisualChangeAt;return a<=420?0:clamp((a-420)/780,0,1)}function resetCompressionStateForFreshStart(){audioBurstTone=0,audioBurstPitch=0,audioTransient=0,stctx.clearRect(0,0,W,H),stctx.drawImage(sourceCanvas,0,0,W,H),wctx.clearRect(0,0,W,H),wctx.drawImage(sourceCanvas,0,0,W,H),depth=.78,depthVel=0,targetDepth=.78,burst=.95,audioImpact=0,audioCrush=0,audioDensity=0,audioJerk=0,audioThump=0,audioFreak=0,audioChaos=0,audioSlam=0,audioDownsample=0,prevCompressionScore=0,lastVisualSig="",lastVisualChangeAt=performance.now()}function hardResetCompression(t="stall"){const a=performance.now();a-lastHardResetAt<700||(lastHardResetAt=a,compressionLoopToken++,clearTimeout(compressionTimer),compressionBusy=!1,ready=!1,consecutiveStalls=0,lastVisualSig="",lastVisualChangeAt=a,lastCompressionProgressAt=a,lastCompressionStartAt=a,console.warn("Hard resetting renderer:",t),generateBaseSVG())}function saveCurrentImage(){const t=document.createElement("a");t.download=`compressed-nostalgia-${Date.now()}.png`,t.href=view.toDataURL("image/png"),t.click()}async function toggleFullscreen(){try{document.fullscreenElement?await(document.exitFullscreen?.()):await(document.documentElement.requestFullscreen?.())}catch(t){console.error(t)}}async function toggleAudio(){if(audioPossible)try{if(audioStarted||await setupAudio(),!audioCtx)return;if("running"!==audioCtx.state&&await audioCtx.resume(),audioEnabled=!audioEnabled,masterGain){const t=audioCtx.currentTime;masterGain.gain.cancelScheduledValues(t),masterGain.gain.setTargetAtTime(audioEnabled?.36:1e-4,t,.04)}audioEnabled?hideHint():showHint()}catch(t){console.error(t)}}function computeTargetDepth(t){let a=.22*(.5+.5*Math.sin(.19*t))+.28*(.5+.5*Math.sin(.071*t+1.1))+.3*(.5+.5*Math.sin(.031*t+4))+.2*(.5+.5*Math.sin(.013*t+2.6));return a=Math.pow(a,1.15),a+=.9*burst,clamp(a,.03,1)}function qualityFromDepth(t,a){return clamp(.92-.72*Math.pow(t,1.15)-.2*Math.pow(t,3.8)-.12*a,8e-5,.95)}function scaleFromDepth(t,a){return clamp(1-.88*Math.pow(t,1)-.1*Math.pow(t,3)-.08*a,.0022,1)}function passesFromDepth(t,a){const e=.8*t+.6*a;return e>1.05?7:e>.88?6:e>.7?5:e>.5?4:e>.28?3:2}function reinjectFromDepth(t){return t>.9?5e-4:t>.75?.001:t>.55?.0025:t>.35?.004:.006}function drawDisplay(){vctx.clearRect(0,0,W,H),vctx.drawImage(stateCanvas,0,0,W,H)}function stepMotion(t,a){const e=.001*t;Math.random()<.02&&(burst=Math.max(burst,.5*Math.random()+.5)),burst*=Math.pow(.9,60*a),targetDepth=computeTargetDepth(e),lowActivityScore=getLowActivityAmount(),lowActivityScore>0&&(activityBoost=Math.max(activityBoost,lowActivityScore),burst=Math.max(burst,.12+.22*lowActivityScore)),audioVisualChange*=Math.pow(.7,60*a),audioVisualMotion*=Math.pow(.9,60*a),audioBurstTone*=Math.pow(.82,60*a),audioBurstPitch=lerp(audioBurstPitch,0,1-Math.pow(.86,60*a)),audioTransient*=Math.pow(.78,60*a),activityBoost*=Math.pow(.88,60*a),depthVel+=.06*(targetDepth-depth)*a*60,depthVel*=Math.pow(.84,60*a),depth+=depthVel*a*60,depth=clamp(depth,0,1),audioImpact*=Math.pow(.84,60*a),audioJerk*=Math.pow(.86,60*a),audioThump*=Math.pow(.8,60*a),audioFreak*=Math.pow(.72,60*a),audioChaos*=Math.pow(.78,60*a),audioSlam*=Math.pow(.55,60*a),audioDownsample*=Math.pow(.64,60*a),audioCrush=lerp(audioCrush,0,1-Math.pow(.9,60*a)),audioDensity=lerp(audioDensity,0,1-Math.pow(.92,60*a))}function applyBlockDrift(t,a){if(a<=.001)return;const e=Math.random()<.8,n=e?Math.max(10,Math.round(H*(.035+.06*a))):Math.max(10,Math.round(W*(.035+.06*a))),o=e?Math.max(2,Math.round(W*(.004+.012*a))):Math.max(2,Math.round(H*(.004+.012*a))),s=(Math.random()<.5?-1:1)*o;if(t.save(),t.imageSmoothingEnabled=!1,t.globalCompositeOperation=["color","color-burn"][Math.floor(2*Math.random())],e){const a=Math.floor(Math.random()*Math.max(1,H-n));if(s>0){const e=W-s;e>1&&t.drawImage(workCanvas,0,a,e,n,s,a,e,n)}else{const e=-s,o=W-e;o>1&&t.drawImage(workCanvas,e,a,o,n,0,a,o,n)}}else{const a=Math.floor(Math.random()*Math.max(1,W-n));if(s>0){const e=H-s;e>1&&t.drawImage(workCanvas,a,0,n,e,a,s,n,e)}else{const e=-s,o=H-e;o>1&&t.drawImage(workCanvas,a,e,n,o,a,0,n,o)}}t.restore()}function applyResizeShock(t,a=1){const e=performance.now();if(e-lastResizeShockAt<420)return;lastResizeShockAt=e;const n=clamp(a,0,1),o=Math.random()<.72?.018+Math.random()*(.055+.08*n):.08+Math.random()*(.18+.12*n),s=Math.max(2,Math.round(W*o)),i=Math.max(2,Math.round(H*o));tinyCanvas.width=s,tinyCanvas.height=i,tctx.imageSmoothingEnabled=Math.random()<.25,tctx.clearRect(0,0,s,i),tctx.drawImage(workCanvas,0,0,s,i),t.save(),t.imageSmoothingEnabled=!1,t.clearRect(0,0,W,H),t.drawImage(workCanvas,0,0,W,H);const r=1.03+n*(.08+.18*Math.random()),u=W*r,h=H*r,m=Math.max(0,u-W),c=Math.max(0,h-H),d=-Math.random()*m,l=-Math.random()*c;t.drawImage(tinyCanvas,0,0,s,i,d,l,u,h),t.restore(),audioDownsample=Math.max(audioDownsample,.8+1.1*n),audioImpact=Math.max(audioImpact,.5+.7*n),audioThump=Math.max(audioThump,.45+.7*n),audioSlam=Math.max(audioSlam,.35+.7*n),audioTransient=Math.max(audioTransient,.5+.5*n)}function markCompressionProgress(){lastCompressionProgressAt=performance.now()}async function compressionLoop(){const t=compressionLoopToken;if(lastCompressionStartAt=performance.now(),markCompressionProgress(),!ready)return compressionBusy=!1,void queueCompressionStart(16);if(!canvasesAreValid())return compressionBusy=!1,void hardResetCompression("invalid canvas dimensions");const a=clamp(3.2*Math.abs(depthVel),0,1),e=depth,n=Math.max(activityBoost,getLowActivityAmount()),o=qualityFromDepth(e,a),s=clamp(scaleFromDepth(e,a)-.14*n,.0015,1),i=passesFromDepth(e,a)+(n>.45?1:0),r=reinjectFromDepth(e),u=.45*(1-o)+.35*(1-s)+.2*clamp((i-2)/5,0,1),h=Math.abs(u-prevCompressionScore);prevCompressionScore=u,audioJerk=Math.max(audioJerk,h),audioDensity=Math.max(audioDensity,clamp(i/7,0,1)),audioCrush=Math.max(audioCrush,u);const m=clamp(5.5*h,0,1)*clamp(.35+.9*burst+.7*Math.abs(depthVel),0,1.5);m>.06&&(audioBurstTone=Math.max(audioBurstTone,m),audioTransient=Math.max(audioTransient,.9*m),audioBurstPitch=Math.max(audioBurstPitch,clamp(.35*m+.22*clamp(audioDownsample,0,1)+.18*clamp(audioFreak,0,1)+.12*Math.random(),0,1)));const c=clamp(4.2*h,0,1.2)*clamp(1.9*(u-.22),0,1),d=.95*clamp((i-4)/3,0,1);audioFreak=Math.max(audioFreak,c),audioChaos=Math.max(audioChaos,clamp(.7*c+d,0,1)),wctx.clearRect(0,0,W,H),wctx.drawImage(stateCanvas,0,0,W,H),wctx.globalAlpha=r,wctx.drawImage(sourceCanvas,0,0,W,H),wctx.globalAlpha=1,markCompressionProgress();let l=workCanvas;try{for(let a=0;a<i;a++){if(markCompressionProgress(),t!==compressionLoopToken)return void(compressionBusy=!1);const r=i<=1?0:a/(i-1);n>.35&&Math.random()<.06+.08*n&&(burst=Math.max(burst,.16+.24*n));const u=clamp(s*(1-r*lerp(.28,.88,e)),e>.88?.0015:.0022,1),m=i<=1?0:Math.max(0,(a-1)/(i-1)),c=a<=0?1:clamp(s*(1-m*lerp(.18,.72,e)),e>.88?.0015:.0022,1),d=clamp((c-u)/Math.max(1e-4,c),0,1),p=clamp(1-u,0,1),f=clamp(.7*p+1.2*d+.2*r,0,1.6),g=clamp(1-u,0,1),w=Math.max(2,Math.round(W*u)),M=Math.max(2,Math.round(H*u));if(w<2||M<2||!Number.isFinite(w)||!Number.isFinite(M))throw new Error("Invalid tiny canvas size");tinyCanvas.width=w,tinyCanvas.height=M,tctx.imageSmoothingEnabled=!0,wctx.imageSmoothingEnabled=!1,tctx.clearRect(0,0,w,M),tctx.drawImage(l,0,0,w,M),wctx.clearRect(0,0,W,H),wctx.drawImage(tinyCanvas,0,0,w,M,0,0,W,H),markCompressionProgress();const x=clamp(o*(1-r*lerp(.25,.9,e)),e>.88?3e-5:8e-5,.95),b=.55*(1-u)+.45*(1-x);f>.14&&(audioDownsample=Math.max(audioDownsample,1.15*f),audioImpact=Math.max(audioImpact,1*f),audioJerk=Math.max(audioJerk,.95*f),audioFreak=Math.max(audioFreak,1.05*f),audioChaos=Math.max(audioChaos,.8*f),audioBurstTone=Math.max(audioBurstTone,.75*f),audioBurstPitch=Math.max(audioBurstPitch,.45+.35*f),audioTransient=Math.max(audioTransient,.7*f));const C=n>.25?.04+.18*n:0,v=u<.16||d>.22?.035+.05*clamp(f,0,1):0;if(Math.random()<C+v&&(applyResizeShock(wctx,Math.max(n,f)),markCompressionProgress(),burst=Math.max(burst,.35+.45*n),activityBoost=Math.max(activityBoost,.25+.5*n)),u<.12||d>.28){const t=clamp(.5+1.05*p+1.6*d,0,2);audioDownsample=Math.max(audioDownsample,t),audioThump=Math.max(audioThump,1*t),audioSlam=Math.max(audioSlam,1.05*t),audioBurstTone=Math.max(audioBurstTone,.65*t),audioBurstPitch=Math.max(audioBurstPitch,.25+.2*t),audioTransient=Math.max(audioTransient,.85*t)}if(b>.35){const t=clamp(b*(.55+.8*r),0,1);audioImpact=Math.max(audioImpact,t);const a=t*clamp(.45+.8*(1-u)+1.6*Math.abs(x-o),0,1.4);audioThump=Math.max(audioThump,a)}const P=clamp(1.6*(g-.35),0,1)*clamp(.45+.9*r+2.5*h,0,1.8);if(P>0&&(audioSlam=Math.max(audioSlam,P)),b>.52||h>.12&&r>.35){const t=clamp(1.8*(b-.45),0,1)*clamp(.6+3*h+.4*r,0,1.5);audioFreak=Math.max(audioFreak,t),audioChaos=Math.max(audioChaos,clamp(.8*t,0,1)),audioBurstTone=Math.max(audioBurstTone,.55*t),audioBurstPitch=Math.max(audioBurstPitch,.55+.25*t)}const R=clamp(.15+.95*e+.8*h+.35*r-.25*(1-u),0,1)*(b>.26?1:0);R>.94&&Math.random()<.01&&(applyBlockDrift(wctx,R),audioJerk=Math.max(audioJerk,.08*R));const k=await canvasToBlob(workCanvas,x);if(t!==compressionLoopToken)return void(compressionBusy=!1);const T=await blobToBitmap(k);if(t!==compressionLoopToken)return T.close?.(),void(compressionBusy=!1);wctx.clearRect(0,0,W,H),wctx.drawImage(T,0,0,W,H),T.close?.(),markCompressionProgress(),l=workCanvas}if(t!==compressionLoopToken)return void(compressionBusy=!1);if(stctx.clearRect(0,0,W,H),stctx.drawImage(workCanvas,0,0,W,H),markCompressionProgress(),checkForVisualFreeze())return compressionBusy=!1,void softRecoverCompression("end-of-loop visual freeze")}catch(a){if(t===compressionLoopToken)return console.error(a),compressionBusy=!1,void hardResetCompression("compression loop error")}compressionBusy=!1,queueCompressionStart(0)}function canvasesAreValid(){return W>1&&H>1&&view.width>1&&view.height>1&&sourceCanvas.width>1&&sourceCanvas.height>1&&stateCanvas.width>1&&stateCanvas.height>1&&workCanvas.width>1&&workCanvas.height>1}function startCompressionLoop(){compressionBusy||(compressionBusy=!0,compressionLoop())}function watchdogTick(){const t=performance.now();if(ready&&compressionBusy){const a=t-lastVisualChangeAt;if(t-lastCompressionProgressAt>1400)return console.warn("Watchdog: compression loop stopped making progress"),consecutiveStalls++,void(consecutiveStalls>=2?hardResetCompression("watchdog: no compression progress"):softRecoverCompression("watchdog: no compression progress"));if(a>1800&&checkForVisualFreeze())return console.warn("Watchdog: visual output frozen"),consecutiveStalls++,void(consecutiveStalls>=2?hardResetCompression("watchdog: visual freeze"):softRecoverCompression("watchdog: visual freeze"))}watchdogTimer=setTimeout(watchdogTick,250)}function softRecoverCompression(t="soft recover"){audioBurstTone=0,audioBurstPitch=0,audioTransient=0,console.warn("Soft recovering renderer:",t),compressionLoopToken++,clearTimeout(compressionTimer),compressionBusy=!1,stctx.clearRect(0,0,W,H),stctx.drawImage(sourceCanvas,0,0,W,H),wctx.clearRect(0,0,W,H),wctx.drawImage(sourceCanvas,0,0,W,H),depth=Math.max(depth,.55),targetDepth=Math.max(targetDepth,.7),depthVel=0,burst=Math.max(burst,.8),lastVisualSig="",lastVisualChangeAt=performance.now(),markCompressionProgress(),queueCompressionStart(0)}async function setupAudio(){if(!audioStarted&&audioPossible){audioStarted=!0;try{const t=window.AudioContext||window.webkitAudioContext;audioCtx=new t({latencyHint:"interactive"});const a=new Blob(["\n class NoiseCompressionProcessor extends AudioWorkletProcessor {\n static get parameterDescriptors() {\n return [\n { name: 'depth', defaultValue: 0.2, minValue: 0, maxValue: 1, automationRate: 'k-rate' },\n { name: 'speed', defaultValue: 0, minValue: 0, maxValue: 1, automationRate: 'k-rate' },\n { name: 'gain', defaultValue: 0.2, minValue: 0, maxValue: 2, automationRate: 'k-rate' },\n { name: 'impact', defaultValue: 0, minValue: 0, maxValue: 1.5, automationRate: 'k-rate' },\n { name: 'crush', defaultValue: 0, minValue: 0, maxValue: 1, automationRate: 'k-rate' },\n { name: 'density', defaultValue: 0, minValue: 0, maxValue: 1, automationRate: 'k-rate' },\n { name: 'jerk', defaultValue: 0, minValue: 0, maxValue: 1, automationRate: 'k-rate' },\n { name: 'thump', defaultValue: 0, minValue: 0, maxValue: 2, automationRate: 'k-rate' },\n { name: 'freak', defaultValue: 0, minValue: 0, maxValue: 2, automationRate: 'k-rate' },\n { name: 'chaos', defaultValue: 0, minValue: 0, maxValue: 1, automationRate: 'k-rate' },\n { name: 'slam', defaultValue: 0, minValue: 0, maxValue: 2, automationRate: 'k-rate' },\n { name: 'tone', defaultValue: 0.5, minValue: 0, maxValue: 1, automationRate: 'k-rate' },\n { name: 'downsample', defaultValue: 0, minValue: 0, maxValue: 2, automationRate: 'k-rate' },\n { name: 'burstTone', defaultValue: 0, minValue: 0, maxValue: 1, automationRate: 'k-rate' },\n { name: 'burstPitch', defaultValue: 0, minValue: 0, maxValue: 1, automationRate: 'k-rate' },\n { name: 'transient', defaultValue: 0, minValue: 0, maxValue: 1, automationRate: 'k-rate' },\n { name: 'visualChange', defaultValue: 0, minValue: 0, maxValue: 1, automationRate: 'k-rate' },\n { name: 'visualMotion', defaultValue: 0, minValue: 0, maxValue: 1, automationRate: 'k-rate' }\n ];\n }\n\n constructor() {\n super();\n this.holdValueL = 0;\n this.holdValueR = 0;\n this.holdCounter = 0;\n this.brownL = 0;\n this.brownR = 0;\n this.deepL = 0;\n this.deepR = 0;\n this.subL = 0;\n this.subR = 0;\n this.airL = 0;\n this.airR = 0;\n this.pulseL = 0;\n this.pulseR = 0;\n this.thumpEnv = 0;\n this.lastThump = 0;\n this.subResL = 0;\n this.subResR = 0;\n this.glitchPhase = 0;\n this.scrambleL = 0;\n this.scrambleR = 0;\n this.gateEnv = 1;\n this.gateCounter = 0;\n this.tonePhaseL = 0;\n this.tonePhaseR = 0;\n this.toneSmoothed = 0.5;\n this.burstPhaseL = 0;\n this.burstPhaseR = 0;\n this.transientEnv = 0;\n }\n\n onePole(current, target, alpha) {\n return current + (target - current) * alpha;\n }\n\n sat(x) {\n return Math.tanh(x);\n }\n\n process(inputs, outputs, parameters) {\n const output = outputs[0];\n const left = output[0];\n const right = output[1] || output[0];\n\n const depth = parameters.depth[0];\n const speed = parameters.speed[0];\n const gain = parameters.gain[0];\n const impact = parameters.impact[0];\n const crush = parameters.crush[0];\n const density = parameters.density[0];\n const jerk = parameters.jerk[0];\n const thump = parameters.thump[0];\n const freak = parameters.freak[0];\n const chaos = parameters.chaos[0];\n const slam = parameters.slam[0];\n const tone = parameters.tone[0];\n const downsample = parameters.downsample[0];\n const burstTone = parameters.burstTone[0];\n const burstPitch = parameters.burstPitch[0];\n const transient = parameters.transient[0];\n const visualChange = parameters.visualChange[0];\n const visualMotion = parameters.visualMotion[0];\n this.toneSmoothed += (tone - this.toneSmoothed) * 0.02;\n const tone01 = this.toneSmoothed;\n\n const pitchHz =\n tone01 < 0.8\n ? 18 + Math.pow(tone01 / 0.8, 1.4) * 220\n : 240 + Math.pow((tone01 - 0.8) / 0.2, 2.2) * 2400;\n\n const burstPitchHz =\n 140 +\n burstPitch * 900 +\n transient * 1400 +\n downsample * 320 +\n visualChange * 950 +\n visualMotion * 260;\n \n const holdJitter =\n 1 +\n freak * 1.8 * (0.35 + Math.random() * 0.65) +\n slam * 2.8 +\n downsample * 3.4;\n\n const hold = Math.max(\n 1,\n Math.floor(\n (2 + depth * 120 + speed * 30 + crush * 40 + density * 16 + slam * 120 + downsample * 160) *\n holdJitter\n )\n );\n\n const bits = Math.max(\n 1,\n Math.floor(\n 13 -\n depth * 8 -\n crush * 3 -\n jerk * 2 -\n freak * 2.5 -\n slam * 6.5 -\n downsample * 5.5\n )\n );\n\n const steps = Math.pow(2, bits - 1);\n\n const broadCutoff =\n 35 +\n tone * 5200 +\n (1 - depth) * 900 +\n speed * 220 -\n crush * 120 -\n slam * 180;\n\n const deepCutoff =\n 8 +\n tone * 90 +\n depth * 22 +\n crush * 10 +\n impact * 16 +\n slam * 22;\n\n const airCutoff =\n 120 +\n tone * 9000 +\n (1 - depth) * 1200 -\n crush * 400 -\n slam * 1200;\n\n const broadAlpha = Math.min(1, 2 * Math.PI * Math.max(20, broadCutoff) / sampleRate);\n const deepAlpha = Math.min(1, 2 * Math.PI * Math.max(6, deepCutoff) / sampleRate);\n const airAlpha = Math.min(1, 2 * Math.PI * Math.max(40, airCutoff) / sampleRate);\n\n const thumpRise = Math.max(0, thump - this.lastThump);\n this.lastThump = thump;\n\n if (thumpRise > 0.01) {\n this.thumpEnv = Math.min(1.8, this.thumpEnv + thumpRise * 1.7);\n }\n\n if (transient > 0.01) {\n this.transientEnv = Math.min(1.4, this.transientEnv + transient * 0.9);\n }\n\n for (let i = 0; i < left.length; i++) {\n const wL = Math.random() * 2 - 1;\n const wR = Math.random() * 2 - 1;\n\n this.brownL = this.brownL * 0.9972 + wL * 0.026;\n this.brownR = this.brownR * 0.9972 + wR * 0.026;\n\n if (this.holdCounter <= 0) {\n const whiteAmt = 0.10 - depth * 0.04 - crush * 0.03;\n const brownAmt = 0.85 + depth * 0.65 + crush * 0.50;\n\n const rawL = wL * whiteAmt + this.brownL * brownAmt;\n const rawR = wR * whiteAmt + this.brownR * brownAmt;\n\n this.holdValueL = rawL;\n this.holdValueR = rawR;\n this.holdCounter = hold;\n }\n\n this.tonePhaseL += (2 * Math.PI * pitchHz) / sampleRate;\n this.tonePhaseR += (2 * Math.PI * (pitchHz * 1.003)) / sampleRate;\n\n if (this.tonePhaseL > Math.PI * 2) this.tonePhaseL -= Math.PI * 2;\n if (this.tonePhaseR > Math.PI * 2) this.tonePhaseR -= Math.PI * 2;\n\n const beepBaseL = Math.sin(this.tonePhaseL);\n const beepBaseR = Math.sin(this.tonePhaseR);\n\n this.burstPhaseL += (2 * Math.PI * burstPitchHz) / sampleRate;\n this.burstPhaseR += (2 * Math.PI * (burstPitchHz * 1.01)) / sampleRate;\n\n if (this.burstPhaseL > Math.PI * 2) this.burstPhaseL -= Math.PI * 2;\n if (this.burstPhaseR > Math.PI * 2) this.burstPhaseR -= Math.PI * 2;\n\n this.holdCounter--;\n\n let crushedL = Math.round(this.holdValueL * steps) / steps;\n let crushedR = Math.round(this.holdValueR * steps) / steps;\n\n const burstBaseL = Math.sin(this.burstPhaseL);\n const burstBaseR = Math.sin(this.burstPhaseR);\n\n this.glitchPhase +=\n 0.00025 +\n tone * 0.02 +\n freak * 0.015 +\n chaos * 0.006 +\n downsample * 0.03 +\n (Math.random() * 2 - 1) * (0.001 + freak * 0.002 + downsample * 0.004);\n\n const glitchOsc = Math.sin(this.glitchPhase * sampleRate * (0.00035 + tone * 0.0038));\n const ringAmt = freak * (0.08 + chaos * 0.10) + downsample * 0.22;\n\n crushedL += crushedL * glitchOsc * ringAmt;\n crushedR += crushedR * -glitchOsc * ringAmt;\n\n const scrambleAmt = freak * 0.22 + chaos * 0.10;\n this.scrambleL =\n this.scrambleL * (0.82 - freak * 0.18) +\n (Math.random() * 2 - 1) * scrambleAmt;\n this.scrambleR =\n this.scrambleR * (0.82 - freak * 0.18) +\n (Math.random() * 2 - 1) * scrambleAmt;\n\n crushedL += this.scrambleL;\n crushedR += this.scrambleR;\n\n this.deepL = this.onePole(this.deepL, crushedL, broadAlpha);\n this.deepR = this.onePole(this.deepR, crushedR, broadAlpha);\n\n const subSourceL = this.brownL * (1.5 + depth * 1.9 + crush * 1.2) + crushedL * 0.24;\n const subSourceR = this.brownR * (1.5 + depth * 1.9 + crush * 1.2) + crushedR * 0.24;\n\n this.subL = this.onePole(this.subL, subSourceL, deepAlpha);\n this.subR = this.onePole(this.subR, subSourceR, deepAlpha);\n\n const airySourceL =\n wL * (0.12 + freak * 0.22) +\n crushedL * (0.05 + freak * 0.08);\n\n const airySourceR =\n wR * (0.12 + freak * 0.22) +\n crushedR * (0.05 + freak * 0.08);\n\n this.airL = this.onePole(this.airL, airySourceL, airAlpha);\n this.airR = this.onePole(this.airR, airySourceR, airAlpha);\n\n this.pulseL = this.pulseL * 0.992 + (Math.random() * 2 - 1) * impact * 0.18;\n this.pulseR = this.pulseR * 0.992 + (Math.random() * 2 - 1) * impact * 0.18;\n\n const glitchChance = 0.0006 + freak * 0.18 + chaos * 0.4;\n\n if (this.gateCounter <= 0 && Math.random() < glitchChance) {\n this.gateCounter = Math.floor(8 + Math.random() * (100 + freak * 220));\n this.gateEnv = Math.random() < 0.55\n ? 0.0 + Math.random() * 0.18\n : 0.35 + Math.random() * 0.45;\n }\n\n if (this.gateCounter > 0) {\n this.gateCounter--;\n } else {\n this.gateEnv += (1 - this.gateEnv) * 0.02;\n }\n\n this.thumpEnv *= 0.9972;\n this.transientEnv *= 0.985 - burstTone * 0.01;\n\n const bodyCut = 28 + depth * 38 + crush * 20;\n const bodyAlpha = Math.min(1, 2 * Math.PI * bodyCut / sampleRate);\n\n const thumpSourceL =\n this.subL * 1.6 +\n crushedL * 0.15 +\n (Math.random() * 2 - 1) * this.thumpEnv * 0.2;\n\n const thumpSourceR =\n this.subR * 1.6 +\n crushedR * 0.15 +\n (Math.random() * 2 - 1) * this.thumpEnv * 0.2;\n\n this.subResL = this.onePole(this.subResL, thumpSourceL, bodyAlpha);\n this.subResR = this.onePole(this.subResR, thumpSourceR, bodyAlpha);\n\n const broadGain = 0.16 + depth * 0.18 + speed * 0.05 + density * 0.05;\n const subGain =\n (1.4 + depth * 2.6 + crush * 1.4 + impact * 0.9) * (1.35 - tone01 * 1.22);\n\n const airGain =\n 0.002 +\n (1 - depth) * 0.012 +\n tone01 * 0.24 +\n visualChange * 0.09 +\n visualMotion * 0.035;\n const pulseGain =\n 0.08 +\n impact * 0.85 +\n jerk * 0.35 +\n freak * 0.7 +\n chaos * 0.25 +\n downsample * 1.1 +\n visualChange * 0.55 +\n visualMotion * 0.25;\n const thumpGain = thump * (0.5 + crush * 0.8) + this.thumpEnv * 0.8;\n\n const beepAmount =\n Math.max(0, (tone01 - 0.62) / 0.38) + downsample * 0.45;\n const beepShape = 0.55 + freak * 0.2 + chaos * 0.15;\n\n const burstAmount =\n burstTone *\n (0.18 +\n transient * 0.9 +\n freak * 0.15 +\n downsample * 0.22 +\n visualChange * 0.45);\n\n const burstShape =\n 2.2 + burstTone * 3.5 + transient * 2.2;\n\n const burstL =\n Math.tanh(burstBaseL * burstShape) *\n burstAmount *\n (0.35 + this.transientEnv);\n\n const burstR =\n Math.tanh(burstBaseR * burstShape) *\n burstAmount *\n (0.35 + this.transientEnv);\n\n const beepL =\n Math.tanh(beepBaseL * (1.5 + beepShape * 3.0)) *\n (0.08 + beepAmount * 0.9);\n\n const beepR =\n Math.tanh(beepBaseR * (1.5 + beepShape * 3.0)) *\n (0.08 + beepAmount * 0.9);\n\n let outL =\n this.deepL * broadGain +\n this.subL * subGain +\n this.airL * airGain +\n this.pulseL * pulseGain +\n this.subResL * thumpGain +\n beepL +\n burstL;\n\n let outR =\n this.deepR * broadGain +\n this.subR * subGain +\n this.airR * airGain +\n this.pulseR * pulseGain +\n this.subResR * thumpGain +\n beepR +\n burstR;\n\n const drive =\n 0.92 +\n impact * 0.6 +\n thump * 0.8 +\n freak * 0.9 +\n slam * 2.2 +\n downsample * 1.7;\n\n const slamGate = 1 - slam * 0.38;\n\n outL = this.sat(outL * drive) * gain * this.gateEnv * slamGate;\n outR = this.sat(outR * drive) * gain * this.gateEnv * slamGate;\n\n left[i] = outL;\n right[i] = outR;\n }\n\n return true;\n }\n }\n\n registerProcessor('noise-compression-processor', NoiseCompressionProcessor);\n "],{type:"application/javascript"}),e=URL.createObjectURL(a);await audioCtx.audioWorklet.addModule(e),URL.revokeObjectURL(e),noiseNode=new AudioWorkletNode(audioCtx,"noise-compression-processor",{numberOfOutputs:1,outputChannelCount:[2]}),audioHP=audioCtx.createBiquadFilter(),audioHP.type="highpass",audioHP.frequency.value=18,audioHP.Q.value=.7,audioLP=audioCtx.createBiquadFilter(),audioLP.type="lowpass",audioLP.frequency.value=220,audioLP.Q.value=.9,audioShelf=audioCtx.createBiquadFilter(),audioShelf.type="lowshelf",audioShelf.frequency.value=70,audioShelf.gain.value=18,audioComp=audioCtx.createDynamicsCompressor(),audioComp.threshold.value=-22,audioComp.knee.value=18,audioComp.ratio.value=8,audioComp.attack.value=.004,audioComp.release.value=.16,masterGain=audioCtx.createGain(),masterGain.gain.value=0,noiseNode.connect(audioHP),audioHP.connect(audioLP),audioLP.connect(audioShelf),audioShelf.connect(audioComp),audioComp.connect(masterGain),masterGain.connect(audioCtx.destination);const n=audioCtx.currentTime;masterGain.gain.setValueAtTime(1e-4,n),audioEnabled&&masterGain.gain.setTargetAtTime(.36,n,.04),showHint()}catch(t){console.error(t),audioPossible=!1,hideHint()}}}function updateAudio(){if(!(audioCtx&&noiseNode&&masterGain&&audioLP&&audioShelf&&audioHP&&audioComp))return;const t=audioCtx.currentTime;if(!Number.isFinite(t))return;if(!audioEnabled)return void masterGain.gain.setTargetAtTime(1e-4,t,.03);const a=clamp(finiteOr(3.2*Math.abs(depthVel),0),0,1),e=clamp(finiteOr(toneControl,50)/100,0,1);safeParam(noiseNode.parameters.get("depth"),depth,0,1,t,.04,.2),safeParam(noiseNode.parameters.get("speed"),a,0,1,t,.04,0),safeParam(noiseNode.parameters.get("impact"),audioImpact,0,1.5,t,.012,0),safeParam(noiseNode.parameters.get("crush"),audioCrush,0,1,t,.03,0),safeParam(noiseNode.parameters.get("density"),audioDensity,0,1,t,.05,0),safeParam(noiseNode.parameters.get("jerk"),audioJerk,0,1,t,.02,0),safeParam(noiseNode.parameters.get("thump"),audioThump,0,2,t,.008,0),safeParam(noiseNode.parameters.get("freak"),audioFreak,0,2,t,.006,0),safeParam(noiseNode.parameters.get("chaos"),audioChaos,0,1,t,.02,0),safeParam(noiseNode.parameters.get("slam"),audioSlam,0,2,t,.003,0),safeParam(noiseNode.parameters.get("tone"),e,0,1,t,.02,.5),safeParam(noiseNode.parameters.get("downsample"),audioDownsample,0,2,t,.006,0),safeParam(noiseNode.parameters.get("burstTone"),audioBurstTone,0,1,t,.01,0),safeParam(noiseNode.parameters.get("burstPitch"),audioBurstPitch,0,1,t,.008,0),safeParam(noiseNode.parameters.get("transient"),audioTransient,0,1,t,.006,0),safeParam(noiseNode.parameters.get("visualChange"),audioVisualChange,0,1,t,.01,0),safeParam(noiseNode.parameters.get("visualMotion"),audioVisualMotion,0,1,t,.04,0);const n=.34+.32*finiteOr(depth,.2)+.08*a+.16*finiteOr(audioCrush,0)+.22*finiteOr(audioImpact,0)+.18*finiteOr(audioThump,0);safeParam(noiseNode.parameters.get("gain"),n,0,2,t,.05,.2);const o=8+420*e+5*finiteOr(depth,.2)+4*finiteOr(audioImpact,0)+180*finiteOr(audioDownsample,0);audioHP.frequency.setTargetAtTime(clamp(o,8,520),t,.03);const s=30+12e3*e+100*(1-finiteOr(depth,.2))+20*a-90*finiteOr(audioCrush,0)-60*finiteOr(audioImpact,0)-50*finiteOr(audioThump,0)-120*finiteOr(audioFreak,0)+4200*finiteOr(audioDownsample,0)+2600*finiteOr(audioVisualChange,0);audioLP.frequency.setTargetAtTime(clamp(s,25,14e3),t,.02);const i=22-26*e+8*finiteOr(depth,.2)+4*finiteOr(audioCrush,0)+4*finiteOr(audioImpact,0);audioShelf.gain.setTargetAtTime(clamp(i,-8,26),t,.03);const r=55+22*finiteOr(depth,.2)+10*finiteOr(audioImpact,0)+8*finiteOr(audioThump,0);audioShelf.frequency.setTargetAtTime(clamp(r,20,400),t,.04);const u=.5+.14*finiteOr(depth,.2)+.08*finiteOr(audioCrush,0)+.1*finiteOr(audioImpact,0)+.08*finiteOr(audioThump,0)+.05*finiteOr(audioFreak,0)+.13*finiteOr(audioDownsample,0)-.05*finiteOr(audioSlam,0);masterGain.gain.setTargetAtTime(clamp(u,1e-4,1.2),t,.05),audioComp.threshold.setTargetAtTime(clamp(4*finiteOr(depth,.2)-26-6*finiteOr(audioImpact,0)-5*finiteOr(audioThump,0)-18*finiteOr(audioSlam,0),-100,0),t,.01),audioComp.ratio.setTargetAtTime(clamp(8+10*finiteOr(audioSlam,0),1,20),t,.01),audioComp.knee.setTargetAtTime(clamp(18-14*finiteOr(audioSlam,0),0,40),t,.01)}let lastNow=performance.now();function frame(t){const a=Math.min(.05,(t-lastNow)/1e3);lastNow=t,ready&&(stepMotion(t,a),drawDisplay(),updateAudio()),requestAnimationFrame(frame)}async function enableAudioFromGesture(){if(audioPossible)try{await setupAudio(),audioCtx&&"running"!==audioCtx.state&&await audioCtx.resume()}catch(t){console.error(t),audioPossible=!1,hideHint()}}audioPossible=canUseAudio(),audioPossible?showHint():hideHint(),window.addEventListener("resize",resize),window.addEventListener("dblclick",()=>{toggleFullscreen()}),window.addEventListener("keydown",t=>{const a=t.key.toLowerCase();"a"===a?(t.preventDefault(),toggleAudio()):"s"===a&&(t.preventDefault(),saveCurrentImage())}),resize(),startCompressionLoop(),requestAnimationFrame(frame),lastCompressionProgressAt=performance.now(),lastVisualChangeAt=performance.now(),watchdogTick();