0xd2af…0475

All memos sent from and to 0xd2af…0475.

Universal Declaration of Human RightsWhereas recognition of the inherent dignity and of the equal and inalienable rights of all members of the human family is the foundation of freedom,Whereas a common understanding of these rights and freedoms is of the greatest importance for the full realization of this pledge,Article 5No one shall be subjected to torture or to cruel, inhuman or degrading treatment or punishment.Article 6Everyone has the right to recognition everywhere as a person before the law.All are entitled to equal protection against any discrimination in violation of this Declaration and against any incitement to such discrimination.Article 9No one shall be subjected to arbitrary arrest, detention or exile.in the determination of his rights and obligations and of any criminal charge against him.Everyone has the right to the protection of the law against such interference or attacks.Article 13Everyone has the right to leave any country, including his own, and to return to his country.Article 14Article 16Article 17Everyone has the right to freedom of thought, conscience and religion; this right includes freedom to change his religion or belief,to manifest his religion or belief in teaching, practice, worship and observance.Everyone has the right to freedom of opinion and expression; this right includes freedom to hold opinions without interference and to seek,receive and impart information and ideas through any media and regardless of frontiers.Article 20Everyone has the right to work, to free choice of employment, to just and favourable conditions of work and to protection against unemployment.Everyone who works has the right to just and favourable remuneration ensuring for himself and his family an existence worthy of human dignity,Everyone has the right to form and to join trade unions for the protection of his interests.All children, whether born in or out of wedlock, shall enjoy the same social protection.Technical and professional education shall be made generally available and higher education shall be equally accessible to all on the basis of merit.Education shall be directed to the full development of the human personality and to the strengthening of respect for human rights and fundamental freedoms.Article 27Everyone is entitled to a social and international order in which the rights and freedoms set forth in this Declaration can be fully realized.Article 30
#C9C9BD#E0170F#260A0F#12050F#A3A3A3#C74D61#0A0A0A#0F0F0F#E0DECF#F5451C#F7D999#F7B324#14170F#EDD45C#F5C403#050D0D#080A08#F5EDE0#EDFF00#1A1A1A#BFD9A1#CCED73#0D0D0D#24292E#EDEDEB#30E682#CCCCCC#78BF94#0D0D0D#CCD4C7#9E9E9E#3B3B3B#0F0F0F#EBF0E8#149EC2#0F0F0F#FCFCFC#B0B0B0#0F3354#14142E#E6E6DB#3B40F2#081C4F#0A0A26#C4CFC9#3D12E8#0D0808#0F0F0F#E8E6E8#8769AD#1A1254#DEDEDE#FA69D1#0A0F0A#FAFAFA
0xd2af9f3e…0475·#25,558,760·0x6b07fef8…5055ab
RPC registry requiredRlNote too long`RoNote set missing`V[a@"W_a?rV[` T`@QcRtPalette chunk missing`XRtPalette row too large`XaRJWaRJaR"V[__` PPPPPPPPPPPPV[____``PPPPPPV[nPrivate Notes #`
function parsePalette(e){const t=Object.fromEntries(e.split("|").map(e=>{const t=e.indexOf("=");return[e.slice(0,t),e.slice(t+1)]})),r=e=>e.trim().split(/\s+/).map(Number);return{bg:r(t.bg),grid:r(t.grid),highlight:r(t.highlight),inks:t.inks.split(";").map(e=>{const t=r(e);return{color:t.slice(0,4),weight:t[4]}})}}palette=parsePalette(palette);class Random{constructor(e){this.useA=!1,this.prngA=this.sfc32(e.slice(2,34)),this.prngB=this.sfc32(e.slice(34,66));for(let e=0;e<1e5;e++)this.prngA(),this.prngB()}sfc32(e){let t=parseInt(e.slice(0,8),16),r=parseInt(e.slice(8,16),16),n=parseInt(e.slice(16,24),16),o=parseInt(e.slice(24,32),16);return function(){t|=0,r|=0,n|=0,o|=0;let e=(t+r|0)+o|0;return o=o+1|0,t=r^r>>>9,r=n+(n<<3)|0,n=n<<21|n>>>11,n=n+e|0,(e>>>0)/4294967296}}g(){return this.useA=!this.useA,this.useA?this.prngA():this.prngB()}range(e,t){return e+this.g()*(t-e)}int(e,t){return Math.floor(this.range(e,t+1))}pick(e){return e[Math.floor(this.g()*e.length)]}chance(e){return this.g()<e}}let R=new Random(HASH);const wordStream={fetching:!1,done:WORDS.length>=WORD_COUNT,failed:!1,nextOffset:WORDS.length};let customRpcUrl="";function getRpcUrls(){return customRpcUrl?[customRpcUrl,...RPC_URLS.filter(e=>e!==customRpcUrl)]:RPC_URLS}function setCustomRpcUrl(){const e=prompt("Custom RPC URL:",customRpcUrl||"https://...");if(!e)return;const t=e.trim();/^https?:\/\//i.test(t)?(customRpcUrl=t,wordStream.fetching=!1,wordStream.failed=!1,wordStream.done=WORDS.length>=WORD_COUNT,wordStream.nextOffset=WORDS.length,maybeFetchMoreWords(),requestRun(),console.log("Custom RPC set:",customRpcUrl)):alert("Please enter a valid http(s) RPC URL.")}const STRUCT_W=3e3,STRUCT_H=4e3,STRUCT_ASPECT=.75;let customRenderWidth=null,customRenderHeight=null,lastGoodWidth=1200,lastGoodHeight=1500,restartQueued=!1,blackFrameCount=0,lastProgressFrame=0,lastProgressPlacementIndex=0;const MAX_BLACK_FRAMES=90,MAX_STUCK_FRAMES=240,MAX_SMUDGE=R.int(2,6),MRATIO=R.g()>.2?R.range(.005,.025):0,MARGINS={left:2*MRATIO,top:MRATIO,right:MRATIO,bottom:MRATIO};let renderLoopRunning=!1;function requestRun(){renderLoopRunning||(renderLoopRunning=!0,requestAnimationFrame(run))}const GRAIN_SEED=parseInt(HASH.slice(2,10),16)/4294967295,RENDERING_MODES=["scrambled","horizontal","vertical","crosswriting"],configuredRenderingMode="string"==typeof MODE?MODE.trim().toLowerCase():"scrambled",configuredLoopCount="undefined"!=typeof LOOP_COUNT?Number(LOOP_COUNT):0,settings={aspect:.75,loopWords:LOOP_WORDS,loopCount:Number.isFinite(configuredLoopCount)&&configuredLoopCount>=0?Math.floor(configuredLoopCount):0,renderingMode:RENDERING_MODES.includes(configuredRenderingMode)?configuredRenderingMode:"scrambled",washStrength:R.range(.1,.5),smudgeChance:0,textureAmount:R.range(.025,.08),pauseFrames:0,revealFrames:Math.floor(R.range(1,4)),revealSpeed:1,backgroundWashChance:.01,backgroundWashMinWords:5,backgroundWashMaxWords:50,backgroundWashColor:palette.highlight,baseGrainAmount:.02,baseMottleAmount:8e-4,gridDefinitions:[...Array(5)].map((e,t)=>(co=Math.floor(R.range(50,128)),ro=Math.floor(co*R.range(1.25,1.7)),rot=0,{name:t.toString(),cols:co,rows:ro,rotation:rot,scale:1,offsetX:0,offsetY:0,letterScale:.8})),showReference:!1};function shuffled(e){const t=[...e];for(let e=t.length-1;e>0;e--){const r=R.int(0,e);[t[e],t[r]]=[t[r],t[e]]}return t}const view=document.getElementById("view"),ref=document.getElementById("ref"),refCtx=ref.getContext("2d",{alpha:!1});let gl,vertexBuffer,washProgram,screenProgram,refTexture,width=0,height=0,dpr=1,frameBuffers=[],frameBufferId=0,resizeQueued=!1,isResizing=!1;const MIN_GL_SIZE=2,state={frame:0,grids:[],placements:[],activePlacementIndex:0,activePlacementFrame:0,loopWordIndex:0,completedWordIterations:0},vertexShader="\n in vec3 pos;\n out vec2 vUv;\n\n void main() {\n gl_Position = vec4(pos, 1.0);\n vUv = (pos.xy + 1.0) * 0.5;\n }\n",washShader="\n uniform sampler2D previousFrame;\n uniform sampler2D referenceMask;\n uniform float frame;\n uniform float dirx;\n uniform float diry;\n uniform float washStrength;\n uniform float smudgeChance;\n uniform float smudgeOnly;\n uniform float smudgeStrength;\n uniform float smudgeLength;\n uniform vec4 bgColor;\n uniform vec4 inkColor;\n uniform vec4 highlightColor;\n\n uniform vec2 resolution;\n uniform float grainSeed;\n uniform float baseGrainAmount;\n uniform float baseMottleAmount;\n\n in vec2 vUv;\n out vec4 col;\n\n vec3 random3(vec3 c) {\n float j = 4096.0 * sin(dot(c, vec3(17.0, 59.4, 15.0)));\n vec3 r;\n r.z = fract(512.0 * j);\n j *= 0.125;\n r.x = fract(512.0 * j);\n j *= 0.125;\n r.y = fract(512.0 * j);\n return r - 0.5;\n }\n\n const float F3 = 0.3333333;\n const float G3 = 0.1666667;\n\n float simplex3(vec3 p) {\n vec3 s = floor(p + dot(p, vec3(F3)));\n vec3 x = p - s + dot(s, vec3(G3));\n vec3 e = step(vec3(0.0), x - x.yzx);\n vec3 i1 = e * (1.0 - e.zxy);\n vec3 i2 = 1.0 - e.zxy * (1.0 - e);\n vec3 x1 = x - i1 + G3;\n vec3 x2 = x - i2 + 2.0 * G3;\n vec3 x3 = x - 1.0 + 3.0 * G3;\n vec4 w, d;\n w.x = dot(x, x);\n w.y = dot(x1, x1);\n w.z = dot(x2, x2);\n w.w = dot(x3, x3);\n w = max(0.6 - w, 0.0);\n d.x = dot(random3(s), x);\n d.y = dot(random3(s + i1), x1);\n d.z = dot(random3(s + i2), x2);\n d.w = dot(random3(s + 1.0), x3);\n w *= w;\n w *= w;\n d *= w;\n return dot(d, vec4(52.0));\n }\n\n float hash12(vec2 p) {\n vec3 p3 = fract(vec3(p.xyx) * 0.1031);\n p3 += dot(p3, p3.yzx + 33.33 + grainSeed * 17.17);\n return fract((p3.x + p3.y) * p3.z);\n }\n\n void main() {\n vec4 ref = texture(referenceMask, vUv);\n vec4 prev = texture(previousFrame, vUv);\n\n col = prev;\n\n if (frame < 0.5) {\n vec2 px = gl_FragCoord.xy;\n\n float fine = hash12(px) - 0.5;\n\n float fine2 = hash12(px * 0.5 + 91.7) - 0.5;\n float mottle = simplex3(vec3(\n vUv.x * 95.0 + grainSeed * 13.0,\n vUv.y * 95.0 - grainSeed * 9.0,\n 4.0\n ));\n\n float paper =\n fine * baseGrainAmount +\n fine2 * baseGrainAmount * 0.45 +\n mottle * baseMottleAmount;\n\n col.rgb += vec3(paper);\n }\n\n if (ref.g > 0.001) {\n float rnd = simplex3(vec3(\n (vUv.x + frame / 100.0) * 5000.0,\n (vUv.y - frame / 100.0) * 50.0,\n grainSeed * 100000.0\n ));\n\n vec4 textureBG = mix(\n bgColor,\n vec4(\n bgColor.rgb - vec3(\n simplex3(vec3(\n (vUv.x + frame / 1000.0) * 500.0,\n (vUv.y - frame / 1000.0) * 500.0,\n grainSeed * 100000.0\n )) / 80.0\n ),\n 1.0\n ),\n simplex3(vec3(\n (vUv.x + frame / 1000.0) * 5.0,\n (vUv.y - frame / 1000.0) / 4.0,\n grainSeed * 100000.0\n ))\n );\n\n vec2 smudgeOffset = vec2(\n smudgeLength * dirx,\n smudgeLength * diry\n );\n\n vec4 draggedFrame = texture(\n previousFrame,\n vUv + smudgeOffset\n );\n\n if (smudgeOnly > 0.5) {\n // Dedicated post-reveal pass.\n // Only move the existing pixels; do not apply new wash or ink.\n float smudgeMask = clamp(ref.g * smudgeStrength, 0.0, 1.0);\n\n // Noise breaks up the drag so it does not look like motion blur.\n smudgeMask *= smoothstep(\n -0.5,\n smudgeChance,\n rnd\n );\n\n col = mix(\n prev,\n draggedFrame,\n smudgeMask\n );\n } else {\n // Normal reveal/wash pass.\n col = mix(\n textureBG,\n prev,\n simplex3(vec3(\n (vUv.x + frame / 100.0) * 5000.0,\n (vUv.y - frame / 100.0) * 5000.0,\n grainSeed * 100000.0\n )) * 4.0\n );\n\n if (rnd < smudgeChance) {\n col = mix(\n draggedFrame,\n textureBG,\n rnd\n );\n }\n\n float washMask = clamp(\n ref.g * washStrength,\n 0.0,\n 1.0\n );\n\n vec4 washResult = mix(\n bgColor,\n col,\n washMask\n );\n\n float opacityAmount = mix(\n 0.75,\n 0.99,\n pow(\n hash12(\n floor(gl_FragCoord.xy / 17.0) +\n grainSeed * 431.0\n ),\n 2.0\n )\n );\n\n col = mix(\n prev,\n washResult,\n opacityAmount\n );\n }\n }\n\n if (ref.b > 0.01 && smudgeOnly < 0.5) {\n float paintMask = ref.b;\n\n float roughA = simplex3(vec3(\n vUv.x * 900.0,\n vUv.y * 900.0,\n frame * 0.012\n ));\n\n float roughB = simplex3(vec3(\n vUv.x * 2200.0,\n vUv.y * 2200.0,\n 19.0\n ));\n\n float brokenMask = paintMask;\n brokenMask *= smoothstep(-0.45, 0.55, roughA);\n brokenMask *= 0.72 + roughB * 0.28;\n\n vec4 noisyPaint = highlightColor;\n noisyPaint.rgb += vec3(roughB * 0.10 + roughA * 0.035);\n\n vec2 dragUv = vUv + vec2(\n roughA * 0.0025,\n roughB * 0.0015\n );\n\n vec4 draggedSurface = texture(previousFrame, dragUv);\n\n vec4 paintOnSurface = mix(draggedSurface, noisyPaint, brokenMask);\n\n col = mix(col, paintOnSurface, brokenMask);\n }\n\n // Red = foreground ink. The incoming reference contains only the current word.\n if (ref.r > 0.01 && smudgeOnly < 0.5) {\n float smearNoise = simplex3(vec3(\n vUv.x * 900.0 + frame * 0.03,\n vUv.y * 220.0 - frame * 0.02,\n grainSeed * 9999.0\n ));\n\n float smearMask = ref.r * smoothstep(-0.35, 0.55, smearNoise);\n\n vec2 smearUv = vUv + vec2(\n -0.006 * dirx,\n 0.002 * diry\n );\n\n vec4 draggedInk = texture(previousFrame, smearUv);\n\n col = mix(col, draggedInk, smearMask * 0.65);\n\n vec4 brokenInk = inkColor;\n\n col = mix(col, brokenInk, ref.r);\n }\n }\n",screenShader="\n uniform sampler2D buffer;\n uniform vec2 resolution;\n uniform float radius;\n\n in vec2 vUv;\n out vec4 col;\n\n float roundedRectMask(vec2 p, vec2 size, float r) {\n vec2 q = abs(p - size * 0.5) - size * 0.5 + vec2(r);\n return 1.0 - step(r, length(max(q, 0.0)) + min(max(q.x, q.y), 0.0));\n }\n\n void main() {\n vec2 px = vUv * resolution;\n\n float mask = roundedRectMask(px, resolution, radius);\n\n if (mask < 0.5) {\n col = vec4(0.0, 0.0, 0.0, 0.0);\n return;\n }\n\n col = texture(buffer, vec2(vUv.x, 1.0 - vUv.y));\n }\n";async function maybeFetchMoreWords(){if(!wordStream.fetching&&!wordStream.done&&!wordStream.failed)if(RPC_URLS.length){wordStream.fetching=!0;try{const e=await fetchNotesSlice(wordStream.nextOffset,FETCH_BATCH_SIZE);if(!e.length)return void(wordStream.done=!0);for(const t of e)WORDS.push(t),addWordPlacement(t);wordStream.nextOffset+=e.length,wordStream.nextOffset>=WORD_COUNT&&(wordStream.done=!0)}catch(e){console.warn("RPC word fetch failed:",e),wordStream.failed=!0}finally{wordStream.fetching=!1}}else wordStream.failed=!0}async function fetchNotesSlice(e,t){let r=null;for(const n of getRpcUrls())try{return await fetchNotesSliceFromRpc(n,TOKEN_ID,e,t)}catch(e){r=e,console.warn("RPC failed, trying next:",n,e)}throw r||new Error("No RPC worked")}const NOTES_SLICE_SELECTOR="0x91cf7995";async function fetchNotesSliceFromRpc(e,t,r,n){const o=NOTES_SLICE_SELECTOR+encodeUint256(t)+encodeUint256(r)+encodeUint256(n),a=await fetch(e,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({jsonrpc:"2.0",id:1,method:"eth_call",params:[{to:CONTRACT_ADDRESS,data:o},"latest"]})}),s=await a.json();if(s.error)throw new Error(s.error.message||"RPC error");return s.result&&"0x"!==s.result?decodeStringArray(s.result):[]}function encodeUint256(e){return BigInt(e).toString(16).padStart(64,"0")}function decodeStringArray(e){e=e.replace(/^0x/,"");const t=t=>{const r=2*t;return BigInt("0x"+e.slice(r,r+64))},r=(t,r)=>{const n=2*t;return e.slice(n,n+2*r)},n=Number(t(0)),o=Number(t(n)),a=[];for(let e=0;e<o;e++){const o=n+32+Number(t(n+32+32*e)),s=r(o+32,Number(t(o)));a.push(hexToUtf8(s))}return a}function hexToUtf8(e){const t=[];for(let r=0;r<e.length;r+=2)t.push(parseInt(e.slice(r,r+2),16));return(new TextDecoder).decode(new Uint8Array(t)).replace(/\0/g,"").trim()}function varyColor(e,t=.01){return[Math.max(0,Math.min(1,e[0]+R.range(-t,t))),Math.max(0,Math.min(1,e[1]+R.range(-t,t))),Math.max(0,Math.min(1,e[2]+R.range(-t,t))),e[3]??1]}function init(){if(gl=view.getContext("webgl2",{alpha:!0,antialias:!1,preserveDrawingBuffer:!0,premultipliedAlpha:!1}),!gl)return void(document.body.innerHTML="WebGL2 is required.");vertexBuffer=createVertexBuffer(),washProgram=createProgram(vertexShader,washShader),screenProgram=createProgram(vertexShader,screenShader),createGrids(),createWordPlacements(),window.addEventListener("resize",requestResize),window.addEventListener("keydown",handleKey),view.addEventListener("webglcontextlost",e=>{e.preventDefault(),console.warn("WebGL context lost")},!1),view.addEventListener("webglcontextrestored",()=>{console.warn("WebGL context restored, rebuilding"),hardRebuild()},!1);new ResizeObserver(()=>requestResize()).observe(document.body),resize(),requestRun()}function resetRandom(){R=new Random(HASH)}function requestResize(){resizeQueued||(resizeQueued=!0,requestAnimationFrame(()=>{resizeQueued=!1,resize()}))}function resetWordsToDefault(){WORDS.length=0,WORDS.push(...INITIAL_WORDS),wordStream.fetching=!1,wordStream.done=WORDS.length>=WORD_COUNT,wordStream.failed=!1,wordStream.nextOffset=WORDS.length}let lastRenderedPixelCount=0;function restartAfterResize(){resetWordsToDefault(),resetRandom(),state.frame=0,state.activePlacementIndex=0,state.activePlacementFrame=0,state.loopWordIndex=0,state.completedWordIterations=0,createGrids(),createWordPlacements(),drawBaseReference(),refTexture&&gl.deleteTexture(refTexture),refTexture=createTexture(width,height,ref),resetFrameBuffers(),window.__RESIDUAL_NOTES_RENDERED__=!1,blackFrameCount=0,lastProgressFrame=0,lastRenderedPixelCount=width*height,requestRun()}let renderW=null,renderH=null;function resize(){const e=1*Math.floor(window.innerWidth||document.documentElement.clientWidth||0),t=1*Math.floor(window.innerHeight||document.documentElement.clientHeight||0);if(e<20||t<20)return void requestAnimationFrame(requestResize);let r,n;e/t>settings.aspect?(n=t,r=t*settings.aspect):(r=e,n=e/settings.aspect),dpr=Math.max(1,window.devicePixelRatio||1);const o=renderW??Math.max(20,Math.round(r*dpr)),a=renderH??Math.max(20,Math.round(n*dpr));if(!(o===width&&a===height)){if(width>0&&height>0&&!(o*a>width*height))return view.style.width=`${r}px`,void(view.style.height=`${n}px`);isResizing=!0,width=o,height=a,view.width=width,view.height=height,view.style.display="block",ref.width=width,ref.height=height,ref.style.display=settings.showReference?"block":"none",restartAfterResize(),isResizing=!1}}function setCustomRenderSize(){const e=prompt("Render width in pixels:",width);if(!e)return;const t=Math.max(100,Math.floor(Number(e)));Number.isFinite(t)&&(renderW=t,renderH=Math.round(renderW/settings.aspect),resize())}function useStructureSpace(){refCtx.setTransform(width/3e3,0,0,height/4e3,0,0)}function resetFrameBuffers(){for(const e of frameBuffers)gl.deleteFramebuffer(e.buffer),gl.deleteTexture(e.texture);frameBuffers=[createFrameBuffer(width,height,ref),createFrameBuffer(width,height,null)],frameBufferId=0}function queueHardRebuild(e="unknown"){restartQueued||(restartQueued=!0,console.warn("Queueing hard rebuild:",e),requestAnimationFrame(()=>{restartQueued=!1,hardRebuild(e)}))}function hardRebuild(e="unknown"){if(console.warn("Hard rebuild:",e),gl&&!gl.isContextLost())try{if(resize(),width<MIN_GL_SIZE||height<MIN_GL_SIZE)return;restartAfterResize(),blackFrameCount=0,lastProgressFrame=state.frame,window.__RESIDUAL_NOTES_RENDERED__=!1}catch(e){console.warn("Hard rebuild failed:",e)}}function assertFramebufferHealthy(e=""){const t=gl.checkFramebufferStatus(gl.FRAMEBUFFER);return t===gl.FRAMEBUFFER_COMPLETE||(queueHardRebuild(`bad framebuffer ${e}: ${t}`),!1)}function drawBaseReference(){useStructureSpace(),refCtx.fillStyle=rgb(palette.bg),refCtx.fillRect(0,0,3e3,4e3),refCtx.fillStyle=rgb(palette.grid);const e=Math.floor(settings.gridDefinitions[0].cols),t=Math.floor(settings.gridDefinitions[0].rows),r=Math.floor(e*MARGINS.left),n=Math.floor(t*MARGINS.top),o=Math.floor(e*MARGINS.right),a=Math.floor(t*MARGINS.bottom);for(let t=r;t<e-o;t++){const n=3e3/e*t;t===r?refCtx.fillRect(n,0,2,4e3):refCtx.fillRect(n,0,1,4e3)}for(let e=n;e<t-a;e++)refCtx.fillRect(0,4e3/t*e,3e3,1)}function createGrids(){state.grids=settings.gridDefinitions.map((e,t)=>({id:t,name:e.name||`grid ${t}`,cols:Math.floor(e.cols),rows:Math.floor(e.rows),rotation:e.rotation||0,scale:e.scale||1,offsetX:e.offsetX||0,offsetY:e.offsetY||0,letterScale:e.letterScale||.8,occupied:null}))}function createWordPlacements(){state.placements=[];let e=R.int(settings.backgroundWashMinWords,settings.backgroundWashMaxWords);for(const t of WORDS)addWordPlacement(t),e--,e<=0&&R.chance(settings.backgroundWashChance)&&(addBackgroundWashPlacement(),e=R.int(settings.backgroundWashMinWords,settings.backgroundWashMaxWords))}function addLoopWordPlacement(){if(!settings.loopWords)return!1;if(!WORDS.length)return!1;if(0===state.completedWordIterations&&(state.completedWordIterations=1),settings.loopCount>0&&state.completedWordIterations>=settings.loopCount)return!1;for(let e=0;e<WORDS.length;e++){const e=WORDS[state.loopWordIndex];if(state.loopWordIndex++,state.loopWordIndex>=WORDS.length&&(state.loopWordIndex=0,state.completedWordIterations++),addWordPlacement(e))return!0}return!1}function addWordPlacement(e){if(!e||!String(e).trim())return!1;const t=String(e).toUpperCase(),r=tryCreateWordPlacement(t)||tryCreateWordPlacement(t)||tryCreateWordPlacement(t);return!!r&&(state.placements.push(r),!0)}function addBackgroundWashPlacement(){state.placements.push({type:"backgroundWash",color:R.chance(.15)?palette.highlight:darkenedBgColor(.1),dirx:R.range(-1,1),diry:R.range(-1,1),washStrength:R.range(.03,.16),smudgeChance:R.range(.1,.32),smudgeFrames:R.int(3,10),smudgeStrength:R.range(.12,.42),smudgeLength:R.range(.001,.004),x:3e3*R.range(-.08,.85),y:4e3*R.range(-.08,.85),w:3e3*R.range(.18,.55),h:4e3*R.range(.12,.38),seed:9999*R.g(),alpha:R.range(.02,.175),dripChance:R.range(.08,.28),force:1})}function tryCreateWordPlacement(e){for(let t=0;t<80;t++){const t=R.pick(state.grids),r=pickPlacementDirection();let n;if("vertical"===r)n=rotatedVerticalTextCells(t,e);else{const o=randomStartForTextBlock(t,e,r);n=textBlockCells(o.x,o.y,e,r,t)}if(cellsFit(t,n))return{word:e,grid:t,direction:r,cells:n,color:varyColor(pickInkForWord(),.05),dirx:R.range(-2,2),diry:R.range(-2,2),washSeed:R.g(),washStrength:R.range(.05,.35),smudgeChance:R.range(.1,.32),smudgeFrames:R.int(1,MAX_SMUDGE),smudgeStrength:R.range(.08,.25),smudgeLength:R.range(.0015,.005),washPad:R.range(.04,.2),washGaps:0,washStampCount:R.int(1,6),underline:R.chance(.065),strikethrough:R.chance(.065),scratched:R.chance(.045),lettergrid:R.chance(.01),square:R.chance(.015),cross:R.chance(.01),plus:R.chance(.005),force:1}}return null}function pickPlacementDirection(){return"horizontal"===settings.renderingMode?"right":"vertical"===settings.renderingMode?"vertical":"crosswriting"===settings.renderingMode?R.chance(.5)?"right":"vertical":R.pick(["right","down","right","down","right","down","right","down","right","down","diagDown","diagUp"])}function randomStartForTextBlock(e,t,r){const n=Math.min(String(t).length,"right"===r?e.cols:e.rows),o=Math.floor(e.cols*MARGINS.left),a=Math.floor(e.rows*MARGINS.top),s=Math.floor(e.cols*MARGINS.right),i=Math.floor(e.rows*MARGINS.bottom),l=R.int(o,e.cols-s-1),f=R.int(a,e.rows-i-1);return"right"===r?{x:Math.max(0,Math.min(e.cols-1,l-Math.floor(n*R.range(.25,.65)))),y:Math.max(0,Math.min(e.rows-1,f-R.int(0,2)))}:"down"===r?{x:Math.max(0,Math.min(e.cols-1,l-R.int(0,2))),y:Math.max(0,Math.min(e.rows-1,f-Math.floor(n*R.range(.25,.65))))}:{x:l,y:f}}function textBlockCells(e,t,r,n,o){if("diagDown"===n||"diagUp"===n)return diagonalTextCells(e,t,r,n);const a=String(r).split(/\s+/),s=[],i="right"===n?Math.max(1,o.cols-e):Math.max(1,o.rows-t);let l=0,f=0;for(const r of a){if(f+(f>0?1:0)+r.length>i&&(l++,f=0),"right"===n&&t+l>=o.rows)break;if("down"===n&&e+l>=o.cols)break;f>0&&(addTextCharCell(s,e,t,n,f,l," "),f++);for(let a=0;a<r.length&&(f>=i&&(l++,f=0),!("right"===n&&t+l>=o.rows))&&!("down"===n&&e+l>=o.cols);a++)addTextCharCell(s,e,t,n,f,l,r[a]),f++}return s.map((e,t)=>({...e,index:t}))}function rotatedVerticalTextCells(e,t){const r=Math.floor(e.cols*MARGINS.left),n=Math.floor(e.rows*MARGINS.top),o=e.cols-Math.floor(e.cols*MARGINS.right),a=e.rows-Math.floor(e.rows*MARGINS.bottom),s=wrapTextLines(t,Math.max(1,a-n));if(!s.length||s.length>o-r)return[];const i=n+Math.max(...s.map(e=>e.length))-1,l=o-s.length;if(i>=a||l<r)return[];const f=R.int(r,l),c=R.int(i,a-1),d=[];for(let e=0;e<s.length;e++){const t=s[e];for(let r=0;r<t.length;r++)d.push({x:f+e,y:c-r,char:t[r],index:d.length,rotation:.5*-Math.PI})}return d}function wrapTextLines(e,t){const r=String(e).split(/\s+/).filter(Boolean),n=[];let o="";for(const e of r){if(e.length>t){o&&(n.push(o),o="");for(let r=0;r<e.length;r+=t)n.push(e.slice(r,r+t));continue}const r=o?`${o} ${e}`:e;r.length>t?(n.push(o),o=e):o=r}return o&&n.push(o),n}function addTextCharCell(e,t,r,n,o,a,s){"right"===n&&e.push({x:t+o,y:r+a,char:s}),"down"===n&&e.push({x:t+a,y:r+o,char:s})}function diagonalTextCells(e,t,r,n){const o=[];for(let a=0;a<r.length;a++){let s=e+a,i="diagDown"===n?t+a:t-a;o.push({x:s,y:i,char:r[a],index:a})}return o}function cellsFit(e,t){const r=Math.floor(e.cols*MARGINS.left),n=Math.floor(e.rows*MARGINS.top),o=Math.floor(e.cols*MARGINS.right),a=Math.floor(e.rows*MARGINS.bottom);return t.every(t=>t.x>=r&&t.y>=n&&t.x<e.cols-o&&t.y<e.rows-a)}function pickInkForWord(){return weightedPick(palette.inks).color}function weightedPick(e){const t=e.reduce((e,t)=>e+t.weight,0);let r=R.g()*t;for(const t of e)if(r-=t.weight,r<=0)return t;return e[e.length-1]}function clearReferenceToBlack(){refCtx.setTransform(1,0,0,1,0,0),refCtx.fillStyle="black",refCtx.fillRect(0,0,width,height)}function drawPlacementReference(e,t){if("backgroundWash"===e.type)return void drawBackgroundWashReference(e,t);clearReferenceToBlack(),refCtx.save(),useStructureSpace(),applyGridTransform(e.grid);const r=Math.ceil(e.cells.length*t),n=e.cells.slice(0,r);drawWashForCells(e.grid,n,e.washPad,e),drawWordCells(e.grid,n,e),e.underline&&t>.72&&drawUnderline(e),e.strikethrough&&t>.65&&drawStrikethrough(e),e.lettergrid&&t>.7&&drawGridAroundLetters(e,n),e.square&&t>.82&&drawSquareAroundWord(e),e.cross&&t>.78&&drawCrossThroughWord(e),e.plus&&t>.78&&drawPlusThroughWord(e),e.scratched&&t>.68&&drawScratchedLetters(e,n),refCtx.restore()}function applyGridTransform(e){refCtx.translate(1500+3e3*e.offsetX,2e3+4e3*e.offsetY),refCtx.rotate(e.rotation),refCtx.scale(e.scale,e.scale),refCtx.translate(-1500,-2e3)}function drawWashForCells(e,t,r,n){const o=3e3/e.cols,a=4e3/e.rows;refCtx.save(),refCtx.fillStyle="rgba(0,255,0,.5)";for(const e of t){const t=n.washStampCount??1;for(let s=0;s<t;s++){const t=1e3*n.washSeed+97*s;if(stable01(e.x,e.y,e.index+t)<n.washGaps)continue;const i=stable01(e.x,e.y,101+t),l=stable01(e.x,e.y,202+t),f=stableNoise(e.x,e.y,303+t)*o*.22,c=stableNoise(e.x,e.y,404+t)*a*.22,d=o*(.04+.14*i),g=a*(.04+.14*l),h=o*r,u=a*r;refCtx.fillRect(e.x*o+d-h+f,e.y*a+g-u+c,o-2*d+2*h,a-2*g+2*u)}}refCtx.restore()}function stable01(e,t,r){const n=43758.5453*Math.sin(12.9898*e+78.233*t+37.719*r);return n-Math.floor(n)}function drawWordCells(e,t,r){const n=3e3/e.cols,o=4e3/e.rows;refCtx.fillStyle="rgb(255,0,0)",refCtx.strokeStyle="rgb(255,0,0)",refCtx.lineWidth=Math.max(1,.09*Math.min(n,o)),refCtx.lineCap="round",refCtx.lineJoin="round";for(const e of t)drawLetterInCell(e.char,e.x*n,e.y*o,n,o,r,e.index,e.rotation||0)}function drawLetterInCell(e,t,r,n,o,a,s,i=0){if(" "===e)return;const l=Math.min(n,o)*RangedLetterScale(a,s);refCtx.save(),refCtx.translate(t+.5*n+0,r+.54*o+0),0!==i&&refCtx.rotate(i),refCtx.font=`${l}px monospace`,refCtx.textAlign="center",refCtx.textBaseline="middle",refCtx.fillText(e,0,0),refCtx.restore()}function RangedLetterScale(e,t){return e.grid.letterScale}function darkenedBgColor(e=.1){return[Math.max(0,palette.bg[0]-e),Math.max(0,palette.bg[1]-e),Math.max(0,palette.bg[2]-e),palette.bg[3]??1]}function drawUnderline(e){const t=3e3/e.grid.cols,r=4e3/e.grid.rows,n=e.cells.filter(e=>" "!==e.char);if(!n.length)return;refCtx.save(),refCtx.strokeStyle="rgb(255,0,0)",refCtx.lineWidth=Math.max(.6,.08*Math.min(t,r)),refCtx.lineCap="round",refCtx.lineJoin="round";const o=n[0],a=n[n.length-1],s=o.x*t+.15*t,i=o.y*r+.84*r,l=a.x*t+.85*t,f=a.y*r+.84*r,c=l-s,d=f-i,g=Math.max(1e-4,Math.sqrt(c*c+d*d)),h=-d/g,u=c/g,m=.28*Math.min(t,r);refCtx.beginPath(),refCtx.moveTo(s+h*m,i+u*m),refCtx.lineTo(l+h*m+stableNoise(l,f,9)*t*.25,f+u*m+stableNoise(s,i,10)*r*.25),refCtx.stroke(),refCtx.restore()}function drawStrikethrough(e){const t=3e3/e.grid.cols,r=4e3/e.grid.rows,n=e.cells.filter(e=>" "!==e.char);if(!n.length)return;const o=n[0],a=n[n.length-1],s=o.x*t+.15*t,i=o.y*r+.5*r,l=a.x*t+.85*t,f=a.y*r+.5*r;refCtx.save(),refCtx.strokeStyle="rgb(255,0,0)",refCtx.lineWidth=Math.max(.6,.08*Math.min(t,r)),refCtx.lineCap="round",refCtx.lineJoin="round",refCtx.beginPath(),refCtx.moveTo(s+stableNoise(s,i,21)*t*.18,i+stableNoise(s,i,22)*r*.18),refCtx.lineTo(l+stableNoise(l,f,23)*t*.18,f+stableNoise(l,f,24)*r*.18),refCtx.stroke(),refCtx.restore()}function drawScratchedLetters(e,t){const r=e.cells.filter(e=>" "!==e.char);if(!r.length)return;const n=new Set(t.map(e=>e.index)),o=Math.floor(stable01(e.washSeed,r.length,501)*r.length),a=[o];if(r.length>1&&stable01(e.washSeed,r.length,502)<.45){const t=1+Math.floor(stable01(e.washSeed,r.length,503)*(r.length-1));a.push((o+t)%r.length)}const s=3e3/e.grid.cols,i=4e3/e.grid.rows,l=Math.min(s,i);refCtx.save(),refCtx.strokeStyle="rgb(255,0,0)",refCtx.lineWidth=Math.max(.7,.075*l),refCtx.lineCap="round",refCtx.lineJoin="round";for(const t of a){const o=r[t];if(!n.has(o.index))continue;const a=1e3*e.washSeed+17*o.index,f=3+Math.floor(6*stable01(a,0,511));refCtx.save(),refCtx.translate(o.x*s+.5*s,o.y*i+.5*i),refCtx.rotate((o.rotation||0)+.3*stableNoise(a,1,512));for(let e=0;e<f;e++){const t=e%3;let r=0===t?0:.5*Math.PI;2===t&&(r=stable01(a,e,513)<.5?.25*Math.PI:.25*-Math.PI),r+=.42*stableNoise(a,e,514);const n=stableNoise(a,e,515)*s*.5,o=stableNoise(a,e,516)*i*.5,f=l*(.7+.45*stable01(a,e,517)),c=Math.cos(r)*f*.5,d=Math.sin(r)*f*.5;refCtx.lineWidth=Math.max(.7,l*(.055+.055*stable01(a,e,518))),refCtx.beginPath(),refCtx.moveTo(n-c,o-d),refCtx.lineTo(n+c,o+d),refCtx.stroke()}refCtx.restore()}refCtx.restore()}function drawGridAroundLetters(e,t){const r=3e3/e.grid.cols,n=4e3/e.grid.rows,o=t.filter(e=>" "!==e.char);if(o.length){refCtx.save(),refCtx.strokeStyle="rgb(255,0,0)",refCtx.lineWidth=Math.max(.5,.045*Math.min(r,n)),refCtx.lineCap="square",refCtx.lineJoin="miter";for(const t of o){const o=t.x*r,a=t.y*n,s=.025*Math.min(r,n),i=t.index+1e3*e.washSeed;refCtx.beginPath(),refCtx.rect(o+stableNoise(t.x,t.y,i+1)*s,a+stableNoise(t.x,t.y,i+2)*s,r+stableNoise(t.x,t.y,i+3)*s,n+stableNoise(t.x,t.y,i+4)*s),refCtx.stroke()}refCtx.restore()}}function drawSquareAroundWord(e){const t=expandedWordBox(e,.22),r=Math.min(3e3/e.grid.cols,4e3/e.grid.rows);refCtx.save(),refCtx.strokeStyle="rgb(255,0,0)",refCtx.lineWidth=Math.max(.6,.08*r),refCtx.lineCap="round",refCtx.lineJoin="round";const n=.12*r;refCtx.beginPath(),refCtx.moveTo(t.x1+stableNoise(t.x1,t.y1,301)*n,t.y1+stableNoise(t.x1,t.y1,302)*n),refCtx.lineTo(t.x2+stableNoise(t.x2,t.y1,303)*n,t.y1+stableNoise(t.x2,t.y1,304)*n),refCtx.lineTo(t.x2+stableNoise(t.x2,t.y2,305)*n,t.y2+stableNoise(t.x2,t.y2,306)*n),refCtx.lineTo(t.x1+stableNoise(t.x1,t.y2,307)*n,t.y2+stableNoise(t.x1,t.y2,308)*n),refCtx.closePath(),refCtx.stroke(),refCtx.restore()}function drawCrossThroughWord(e){const t=expandedWordBox(e,.12),r=Math.min(3e3/e.grid.cols,4e3/e.grid.rows);refCtx.save(),refCtx.strokeStyle="rgb(255,0,0)",refCtx.lineWidth=Math.max(.6,.08*r),refCtx.lineCap="round",refCtx.lineJoin="round",drawNoisyLine(t.x1,t.y1,t.x2,t.y2,r,401),drawNoisyLine(t.x2,t.y1,t.x1,t.y2,r,411),refCtx.restore()}function drawPlusThroughWord(e){const t=expandedWordBox(e,.1),r=Math.min(3e3/e.grid.cols,4e3/e.grid.rows),n=.5*(t.x1+t.x2),o=.5*(t.y1+t.y2);refCtx.save(),refCtx.strokeStyle="rgb(255,0,0)",refCtx.lineWidth=Math.max(.6,.08*r),refCtx.lineCap="round",refCtx.lineJoin="round",drawNoisyLine(t.x1,o,t.x2,o,r,501),drawNoisyLine(n,t.y1,n,t.y2,r,511),refCtx.restore()}function drawBackgroundWashReference(e,t){clearReferenceToBlack(),refCtx.save(),useStructureSpace(),refCtx.globalAlpha=e.alpha*t,refCtx.fillStyle="rgb(0,0,255)",refCtx.strokeStyle="rgb(0,0,255)",refCtx.lineCap="round",refCtx.lineJoin="round";const r=e.y+.42*e.h;for(let n=0;n<44;n++){const o=n/Math.max(1,43),a=e.x+e.w*o+stableNoise(e.seed,n,11)*e.w*.025,s=Math.sin(o*Math.PI),i=r-e.h*(.25+.75*s+.45*stable01(e.seed,n,12)),l=r+e.h*(.15+.55*s+.75*stable01(e.seed,n,13)),f=e.w*(.018+.045*stable01(e.seed,n,14));drawVerticalPaintColumn(a,i,l,f,e.seed+91*n,t),stable01(e.seed,n,77)<e.dripChance&&drawPaintDrip(a+stableNoise(e.seed,n,21)*f,l-.05*e.h,e.h*(.35+1.4*stable01(e.seed,n,22)),e.seed+200*n)}for(let n=0;n<9;n++){const o=r+stableNoise(e.seed,n,301)*e.h*.45;refCtx.globalAlpha=e.alpha*t*.22,refCtx.lineWidth=e.h*(.025+.045*stable01(e.seed,n,302)),drawNoisyHorizontalStroke(e.x+stableNoise(e.seed,n,303)*e.w*.05,o,e.x+e.w+stableNoise(e.seed,n,304)*e.w*.05,o+stableNoise(e.seed,n,305)*e.h*.18,e.seed+400*n)}refCtx.restore()}function drawVerticalPaintColumn(e,t,r,n,o,a){refCtx.beginPath();for(let a=0;a<=12;a++){const s=t+(r-t)*(a/12),i=e-.5*n+stableNoise(o,a,31)*n*.75;0===a?refCtx.moveTo(i,s):refCtx.lineTo(i,s)}for(let a=12;a>=0;a--){const s=t+(r-t)*(a/12),i=e+.5*n+stableNoise(o,a,41)*n*.75;refCtx.lineTo(i,s)}refCtx.closePath(),refCtx.fill(),refCtx.save(),refCtx.globalAlpha*=.35;const s=2+Math.floor(5*stable01(o,1,55));for(let a=0;a<s;a++){const s=e+stableNoise(o,a,61)*n*.45;refCtx.lineWidth=n*(.08+.18*stable01(o,a,62)),refCtx.beginPath(),refCtx.moveTo(s,t+stableNoise(o,a,63)*n),refCtx.lineTo(s+stableNoise(o,a,64)*n*.45,r-stable01(o,a,65)*n),refCtx.stroke()}refCtx.restore(),refCtx.save(),refCtx.globalCompositeOperation="destination-out";for(let s=0;s<22;s++){const i=stable01(o,s,71)<.5?-1:1,l=t+stable01(o,s,72)*(r-t),f=e+i*n*(.3+.45*stable01(o,s,73));refCtx.globalAlpha=a*(.04+.14*stable01(o,s,74)),refCtx.beginPath(),refCtx.ellipse(f,l,n*(.15+.55*stable01(o,s,75)),n*(.25+1.25*stable01(o,s,76)),stableNoise(o,s,77),0,2*Math.PI),refCtx.fill()}refCtx.restore()}function drawNoisyHorizontalStroke(e,t,r,n,o){refCtx.beginPath();for(let a=0;a<=18;a++){const s=a/18,i=e+(r-e)*s,l=t+(n-t)*s+4e3*stableNoise(o,a,91)*.006;0===a?refCtx.moveTo(i,l):refCtx.lineTo(i,l)}refCtx.stroke()}function drawPainterlyBlob(e,t,r,n,o,a){const s=[];for(let a=0;a<28;a++){const i=a/28*Math.PI*2,l=1+.12*stableNoise(o,a,31)+.06*stableNoise(o,a,32)+.06*Math.sin(2*i+o)+.04*Math.sin(5*i+.37*o);s.push({x:e+Math.cos(i)*r*.5*l,y:t+Math.sin(i)*n*.5*l})}refCtx.beginPath();for(let e=0;e<s.length;e++){const t=s[(e-1+s.length)%s.length],r=s[e],n=s[(e+1)%s.length],o={x:.5*(t.x+r.x),y:.5*(t.y+r.y)},a={x:.5*(r.x+n.x),y:.5*(r.y+n.y)};0===e&&refCtx.moveTo(o.x,o.y),refCtx.quadraticCurveTo(r.x,r.y,a.x,a.y)}refCtx.closePath(),refCtx.fill(),refCtx.save(),refCtx.globalCompositeOperation="destination-out",refCtx.globalAlpha=.1*a;for(let s=0;s<160;s++){const i=stable01(o,s,41)*Math.PI*2,l=Math.sqrt(stable01(o,s,42)),f=Math.cos(i)*l,c=Math.sin(i)*l,d=e+f*r*.48,g=t+c*n*.48,h=Math.min(1,Math.sqrt(f*f+c*c)),u=Math.pow(h,2.2),m=r*(.004+.09*u*stable01(o,s,43)),x=n*(.003+.05*u*stable01(o,s,44));refCtx.globalAlpha=(.01+.18*u)*a,refCtx.beginPath(),refCtx.ellipse(d,g,m,x,stableNoise(o,s,45)*Math.PI,0,2*Math.PI),refCtx.fill()}refCtx.restore()}function drawPaintDrip(e,t,r,n){const o=.045*r;refCtx.beginPath(),refCtx.moveTo(e,t);for(let a=1;a<=5;a++){const s=a/5;refCtx.lineTo(e+stableNoise(n,a,51)*o,t+r*s)}refCtx.lineWidth=Math.max(1,3e3*.0012),refCtx.lineCap="round",refCtx.strokeStyle="rgb(0,0,255)",refCtx.stroke()}function drawNoisyLine(e,t,r,n,o,a){const s=.16*o;refCtx.beginPath(),refCtx.moveTo(e+stableNoise(e,t,a+1)*s,t+stableNoise(e,t,a+2)*s),refCtx.lineTo(r+stableNoise(r,n,a+3)*s,n+stableNoise(r,n,a+4)*s),refCtx.stroke()}function expandedWordBox(e,t=.15){const r=wordBox(e),n=3e3/e.grid.cols,o=4e3/e.grid.rows;return{x1:r.x1-n*t,y1:r.y1-o*t,x2:r.x2+n*t,y2:r.y2+o*t}}function wordBox(e){const t=3e3/e.grid.cols,r=4e3/e.grid.rows,n=e.cells.map(e=>e.x*t),o=e.cells.map(e=>e.y*r);return{x1:Math.min(...n),y1:Math.min(...o),x2:Math.max(...n)+t,y2:Math.max(...o)+r}}function stableNoise(e,t,r){const n=43758.5453*Math.sin(12.9898*e+78.233*t+37.719*r);return n-Math.floor(n)-.5}function run(){if(renderLoopRunning=!1,isResizing||width<MIN_GL_SIZE||height<MIN_GL_SIZE||!refTexture||frameBuffers.length<2)return void requestRun();maybeFetchMoreWords();const e=state.placements[state.activePlacementIndex];if(!e)return wordStream.done||wordStream.failed?addLoopWordPlacement()?void requestRun():(renderScreen(),state.frame%30==0&&sampleVisibleCanvasHealth(),void(window.__RESIDUAL_NOTES_RENDERED__||(window.__RESIDUAL_NOTES_RENDERED__=!0,window.dispatchEvent(new Event("residual-notes:rendered"))))):void requestRun();const t=settings.pauseFrames,r=settings.revealFrames,n=e.smudgeFrames??0,o=state.activePlacementFrame,a=t,s=t+r,i=s+n;let l=!1;if(o<a)clearReferenceToBlack();else if(o<s){const t=o-a;drawPlacementReference(e,Math.min(1,(t+1)*settings.revealSpeed/r))}else drawPlacementReference(e,1),l=!0;updateReferenceTexture(),renderWash(e,l),renderScreen(),state.frame++,state.activePlacementFrame++,state.activePlacementFrame>=i&&(state.activePlacementIndex++,state.activePlacementFrame=0),requestRun()}function renderWash(e,t=!1){const r=frameBufferId,n=1^frameBufferId;frameBufferId=n,useProgram(washProgram),gl.bindFramebuffer(gl.FRAMEBUFFER,frameBuffers[n].buffer),assertFramebufferHealthy("renderWash")&&(gl.viewport(0,0,width,height),gl.clearColor(0,0,0,1),gl.clear(gl.COLOR_BUFFER_BIT),gl.activeTexture(gl.TEXTURE0),gl.bindTexture(gl.TEXTURE_2D,frameBuffers[r].texture),gl.uniform1i(gl.getUniformLocation(washProgram,"previousFrame"),0),gl.activeTexture(gl.TEXTURE1),gl.bindTexture(gl.TEXTURE_2D,refTexture),gl.uniform1i(gl.getUniformLocation(washProgram,"referenceMask"),1),gl.uniform1f(gl.getUniformLocation(washProgram,"frame"),state.frame),gl.uniform1f(gl.getUniformLocation(washProgram,"dirx"),e.dirx),gl.uniform1f(gl.getUniformLocation(washProgram,"diry"),e.diry),gl.uniform1f(gl.getUniformLocation(washProgram,"washStrength"),e.washStrength??settings.washStrength),gl.uniform1f(gl.getUniformLocation(washProgram,"smudgeChance"),e.smudgeChance??settings.smudgeChance),gl.uniform1f(gl.getUniformLocation(washProgram,"smudgeOnly"),t?1:0),gl.uniform1f(gl.getUniformLocation(washProgram,"smudgeStrength"),e.smudgeStrength??.3),gl.uniform1f(gl.getUniformLocation(washProgram,"smudgeLength"),e.smudgeLength??.003),gl.uniform1f(gl.getUniformLocation(washProgram,"textureAmount"),settings.textureAmount),gl.uniform4fv(gl.getUniformLocation(washProgram,"bgColor"),palette.bg),gl.uniform4fv(gl.getUniformLocation(washProgram,"inkColor"),e.color),gl.uniform4fv(gl.getUniformLocation(washProgram,"highlightColor"),"backgroundWash"===e.type?e.color:palette.highlight),gl.uniform2f(gl.getUniformLocation(washProgram,"resolution"),width,height),gl.uniform1f(gl.getUniformLocation(washProgram,"grainSeed"),GRAIN_SEED),gl.uniform1f(gl.getUniformLocation(washProgram,"baseGrainAmount"),settings.baseGrainAmount),gl.uniform1f(gl.getUniformLocation(washProgram,"baseMottleAmount"),settings.baseMottleAmount),gl.drawArrays(gl.TRIANGLE_STRIP,0,4))}function sampleVisibleCanvasHealth(){if(!gl||gl.isContextLost())return;const e=new Uint8Array(4);gl.bindFramebuffer(gl.FRAMEBUFFER,null),gl.readPixels(Math.floor(.5*width),Math.floor(.5*height),1,1,gl.RGBA,gl.UNSIGNED_BYTE,e);e[0]+e[1]+e[2]<8&&state.frame>20?blackFrameCount++:blackFrameCount=0,blackFrameCount>90&&queueHardRebuild("visible canvas stayed black"),state.activePlacementIndex!==lastProgressPlacementIndex&&(lastProgressPlacementIndex=state.activePlacementIndex,lastProgressFrame=state.frame);state.activePlacementIndex>0&&state.activePlacementIndex<state.placements.length&&state.frame-lastProgressFrame>240&&queueHardRebuild("render loop appears stuck")}function renderScreen(){useProgram(screenProgram),gl.bindFramebuffer(gl.FRAMEBUFFER,null),gl.viewport(0,0,width,height),gl.clearColor(0,0,0,0),gl.clear(gl.COLOR_BUFFER_BIT),gl.activeTexture(gl.TEXTURE0),gl.bindTexture(gl.TEXTURE_2D,frameBuffers[frameBufferId].texture),gl.uniform1i(gl.getUniformLocation(screenProgram,"buffer"),0),gl.uniform2f(gl.getUniformLocation(screenProgram,"resolution"),width,height),gl.uniform1f(gl.getUniformLocation(screenProgram,"radius"),.015*width),gl.drawArrays(gl.TRIANGLE_STRIP,0,4)}function useProgram(e){gl.useProgram(e);const t=gl.getAttribLocation(e,"pos");gl.enableVertexAttribArray(t),gl.bindBuffer(gl.ARRAY_BUFFER,vertexBuffer),gl.vertexAttribPointer(t,3,gl.FLOAT,!1,0,0)}function createProgram(e,t){const r=gl.createProgram(),n=createShader(`#version 300 es\n${e}`,gl.VERTEX_SHADER),o=createShader(`#version 300 es\nprecision highp float;\n${t}`,gl.FRAGMENT_SHADER);return gl.attachShader(r,n),gl.attachShader(r,o),gl.linkProgram(r),gl.getProgramParameter(r,gl.LINK_STATUS)||console.error(gl.getProgramInfoLog(r)),r}function createShader(e,t){const r=gl.createShader(t);return gl.shaderSource(r,e),gl.compileShader(r),gl.getShaderParameter(r,gl.COMPILE_STATUS)||console.error(gl.getShaderInfoLog(r)),r}function createVertexBuffer(){const e=gl.createBuffer();return gl.bindBuffer(gl.ARRAY_BUFFER,e),gl.bufferData(gl.ARRAY_BUFFER,new Float32Array([-1,1,0,-1,-1,0,1,1,0,1,-1,0]),gl.STATIC_DRAW),e}function createFrameBuffer(e,t,r=null){e=Math.max(MIN_GL_SIZE,Math.floor(e)),t=Math.max(MIN_GL_SIZE,Math.floor(t));const n=gl.createFramebuffer(),o=createTexture(e,t,r);gl.bindFramebuffer(gl.FRAMEBUFFER,n),gl.framebufferTexture2D(gl.FRAMEBUFFER,gl.COLOR_ATTACHMENT0,gl.TEXTURE_2D,o,0);const a=gl.checkFramebufferStatus(gl.FRAMEBUFFER);return a!==gl.FRAMEBUFFER_COMPLETE&&console.warn("Framebuffer incomplete:",a,e,t),gl.bindFramebuffer(gl.FRAMEBUFFER,null),{buffer:n,texture:o}}function createTexture(e,t,r=null){e=Math.max(MIN_GL_SIZE,Math.floor(e)),t=Math.max(MIN_GL_SIZE,Math.floor(t));const n=gl.createTexture();return gl.bindTexture(gl.TEXTURE_2D,n),gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.NEAREST),gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.NEAREST),gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_S,gl.CLAMP_TO_EDGE),gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_T,gl.CLAMP_TO_EDGE),r&&r.width>0&&r.height>0?gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,gl.RGBA,gl.UNSIGNED_BYTE,r):gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,e,t,0,gl.RGBA,gl.UNSIGNED_BYTE,null),n}function updateReferenceTexture(){refTexture&&(!ref||ref.width<MIN_GL_SIZE||ref.height<MIN_GL_SIZE||(gl.bindTexture(gl.TEXTURE_2D,refTexture),gl.texSubImage2D(gl.TEXTURE_2D,0,0,0,gl.RGBA,gl.UNSIGNED_BYTE,ref)))}function rgb(e){return`rgb(${Math.floor(255*e[0])}, ${Math.floor(255*e[1])}, ${Math.floor(255*e[2])})`}function clamp255(e){return Math.max(0,Math.min(255,e))}function handleKey(e){"s"===e.key&&savePNG(),"m"===e.key&&(settings.showReference=!settings.showReference,ref.style.display=settings.showReference?"block":"none"),"c"===e.key&&setCustomRenderSize(),"p"===e.key.toLowerCase()&&setCustomRpcUrl()}function savePNG(){renderScreen();const e=document.createElement("a");e.download=`private-notes-${HASH.slice(2,10)}-${width}x${height}.png`,e.href=view.toDataURL("image/png"),e.click()}function restart(){restartAfterResize()}init();
0xd2af9f3e…0475·#25,558,738·0xc8eb8599…fab155
RlMissing chunk`RnChunk too large`RnChunk too large`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef`ghijklmnopqrstuvwxyz0123456789+/Rm(private)notes`RmRegistry notes`data:application/json;base64,<!doctype html><html><head><meta name="viewport" content="w`1idth=device-width,initial-scale=`Q<style>html,body{margin:0;width:`100%;height:100%;overflow:hidden`(;background:#ddd;display:flex;al`Hign-items:center;justify-content`h:center;}#view,#ref{margin:0 aut`o;aspect-ratio:4/5;width:min(90v`w,calc(90vh*4/5));height:min(90v`ȃh,calc(90vw*5/4));}</style><canvas id='view'></canvas><canv` <svg xmlns="http://www.w3.org/2000/svg" width="500" height="500"` viewBox="0 0 500 500" fill="non`@<style>text { font: 82px sans-se`c<rect width="500" height="500" f`PPPPPV[_a4,a/Oa3data:image/svg+xml;base64,"description":"Generative notebo`oks stored on ethereum.","animation_url":"data:text/html;`a/*V[nlet LOOP_WORDS=`Rnlet LOOP_COUNT=`Rsconst INITIAL_WORDS=``let WORDS=[...INITIAL_WORDS];" text-anchor="middle">{"trait_type":"Note source","val`{"trait_type":"Mode","value":"{"trait_type":"Visible notes","v`{"trait_type":"Owner","value":"a/*V[llet palette='`PPPV[_a9삄a/*V[`]`PPPV[nconst TOKEN_ID=`Rpconst TOKEN_NAME=`xRtlet CONTRACT_ADDRESS=`XV[llet RPC_URLS=`PPPV[nlet WORD_COUNT=`const INLINE_WORD_LIMIT=const FETCH_BATCH_SIZE=Pqconst NOTE_SOURCE=`pPqconst TOKEN_OWNER=`p
Lorem IpsumPhasellus et faucibus elit, vel ultrices leo.Morbi vitae condimentum magna.Suspendisse sodales pulvinar tempor.Donec nec molestie velit.Donec elementum, nisl in pulvinar tincidunt, lorem urna sollicitudin justo, id pellentesque ipsum tellus non ipsum.Pellentesque a pretium purus.Curabitur non bibendum sem, sed elementum odio.Nam pharetra molestie nisl in sagittis.Donec non vestibulum lorem.
0xd2af9f3e…0475·#25,558,720·0xac16e7f8…a1b641
RoNote set missing`RlChunk missing`PPPPPPPa sV[PPPPPP[RmEmpty bytecode`RpPointer too large`xRsInvalid pointer code``RlNote too long`RmNote too large`RlChunk missing`
Future Artifactbg=.89 .07 .55 1|grid=.82 .08 .44 1|highlight=.07 .86 .87 1|inks=.54 1 .99 1 4;.45 .05 .26 1 2;.13 .13 .13 1 10x4d1d9ea58684f9ef6549ab43bc3d75754194f719d778a8629b137f1ab33ba3ce#E3128C#8AFFFC
Signal vs Noisebg=.04 .07 .05 1|grid=.13 .17 .15 1|highlight=.99 .29 .25 1|inks=.98 .18 .16 1 3;.93 1 .9 1 5;.86 .66 .15 1 3;.66 .66 .94 1 3 10xc6e08ad8bd6b33e0c304dc97d9a542609d8d6f9f1804e87558f59b3ffbe950d8#09100B#FB2E23
Instructionsbg=.9 .9 .86 1|grid=.83 .83 .8 1|highlight=.06 .47 .92 1|inks=.11 .1 .08 1 5;.67 .2 .21 1 3;.16 .28 .54 1 3;.22 .08 .77 1 3 10xc393ffbbf420c22dbd8751dabc12c4a5a397be86420ef9db186f65ac524da785#E4E4DA#3814C4
bg=.03 .03 .03 1|grid=.13 .13 .13 1|highlight=.07 .98 .04 1|inks=.54 .96 .57 1 4;.36 .65 .19 1 3;.93 .93 .93 1 1 10xa875bafbd382d3a81cd46a10c0ada9d7c6a375eef3a232cf61d50663c2fe5852#8AF591
Overheardbg=0 .15 .44 1|grid=.05 .2 .49 1|highlight=.17 .6 .75 1|inks=1 1 1 1 4;1 .69 .02 1 1;.22 .6 .84 1 .5;.54 .08 .37 1 .250x0c20a5503b98d9d839b2ad4534cc04ee6f7f42ffa6556d63d21544efd9bdf43d#FEFFF5
function parsePalette(e){const t=Object.fromEntries(e.split("|").map(e=>{const t=e.indexOf("=");return[e.slice(0,t),e.slice(t+1)]})),r=e=>e.trim().split(/\s+/).map(Number);return{bg:r(t.bg),grid:r(t.grid),highlight:r(t.highlight),inks:t.inks.split(";").map(e=>{const t=r(e);return{color:t.slice(0,4),weight:t[4]}})}}palette=parsePalette(palette);class Random{constructor(e){this.useA=!1,this.prngA=this.sfc32(e.slice(2,34)),this.prngB=this.sfc32(e.slice(34,66));for(let e=0;e<1e5;e++)this.prngA(),this.prngB()}sfc32(e){let t=parseInt(e.slice(0,8),16),r=parseInt(e.slice(8,16),16),n=parseInt(e.slice(16,24),16),o=parseInt(e.slice(24,32),16);return function(){t|=0,r|=0,n|=0,o|=0;let e=(t+r|0)+o|0;return o=o+1|0,t=r^r>>>9,r=n+(n<<3)|0,n=n<<21|n>>>11,n=n+e|0,(e>>>0)/4294967296}}g(){return this.useA=!this.useA,this.useA?this.prngA():this.prngB()}range(e,t){return e+this.g()*(t-e)}int(e,t){return Math.floor(this.range(e,t+1))}pick(e){return e[Math.floor(this.g()*e.length)]}chance(e){return this.g()<e}}let R=new Random(HASH);const wordStream={fetching:!1,done:WORDS.length>=WORD_COUNT,failed:!1,nextOffset:WORDS.length};let customRpcUrl="";function getRpcUrls(){return customRpcUrl?[customRpcUrl,...RPC_URLS.filter(e=>e!==customRpcUrl)]:RPC_URLS}function setCustomRpcUrl(){const e=prompt("Custom RPC URL:",customRpcUrl||"https://...");if(!e)return;const t=e.trim();/^https?:\/\//i.test(t)?(customRpcUrl=t,wordStream.fetching=!1,wordStream.failed=!1,wordStream.done=WORDS.length>=WORD_COUNT,wordStream.nextOffset=WORDS.length,maybeFetchMoreWords(),requestRun(),console.log("Custom RPC set:",customRpcUrl)):alert("Please enter a valid http(s) RPC URL.")}const STRUCT_W=4e3,STRUCT_H=5e3,STRUCT_ASPECT=.8;let customRenderWidth=null,customRenderHeight=null,lastGoodWidth=1200,lastGoodHeight=1500,restartQueued=!1,blackFrameCount=0,lastProgressFrame=0,lastProgressPlacementIndex=0;const MAX_BLACK_FRAMES=90,MAX_STUCK_FRAMES=240;let renderLoopRunning=!1;function requestRun(){renderLoopRunning||(renderLoopRunning=!0,requestAnimationFrame(run))}const GRAIN_SEED=parseInt(HASH.slice(2,10),16)/4294967295,settings={aspect:.8,washStrength:R.range(.1,.8),smudgeChance:R.range(.1,.24),textureAmount:R.range(.025,.08),pauseFrames:0,revealFrames:2,revealSpeed:1,backgroundWashChance:.01,backgroundWashMinWords:5,backgroundWashMaxWords:50,backgroundWashColor:palette.highlight,baseGrainAmount:.02,baseMottleAmount:8e-4,gridDefinitions:[...Array(5)].map((e,t)=>(co=t>0?Math.floor(R.range(70,130)):Math.floor(R.range(45,65)),ro=Math.floor(1.25*co),{name:t.toString(),cols:co,rows:ro,rotation:R.g()/25-.02,scale:1,offsetX:0,offsetY:0,letterScale:.8})),showReference:!1};function shuffled(e){const t=[...e];for(let e=t.length-1;e>0;e--){const r=R.int(0,e);[t[e],t[r]]=[t[r],t[e]]}return t}const view=document.getElementById("view"),ref=document.getElementById("ref"),refCtx=ref.getContext("2d",{alpha:!1});let gl,vertexBuffer,washProgram,screenProgram,refTexture,width=0,height=0,dpr=1,frameBuffers=[],frameBufferId=0,resizeQueued=!1,isResizing=!1;const MIN_GL_SIZE=2,state={frame:0,grids:[],placements:[],activePlacementIndex:0},vertexShader="\n in vec3 pos;\n out vec2 vUv;\n\n void main() {\n gl_Position = vec4(pos, 1.0);\n vUv = (pos.xy + 1.0) * 0.5;\n }\n",washShader="\n uniform sampler2D previousFrame;\n uniform sampler2D referenceMask;\n uniform float frame;\n uniform float dirx;\n uniform float diry;\n uniform float washStrength;\n uniform float smudgeChance;\n uniform vec4 bgColor;\n uniform vec4 inkColor;\n uniform vec4 highlightColor;\n\n uniform vec2 resolution;\n uniform float grainSeed;\n uniform float baseGrainAmount;\n uniform float baseMottleAmount;\n\n in vec2 vUv;\n out vec4 col;\n\n vec3 random3(vec3 c) {\n float j = 4096.0 * sin(dot(c, vec3(17.0, 59.4, 15.0)));\n vec3 r;\n r.z = fract(512.0 * j);\n j *= 0.125;\n r.x = fract(512.0 * j);\n j *= 0.125;\n r.y = fract(512.0 * j);\n return r - 0.5;\n }\n\n const float F3 = 0.3333333;\n const float G3 = 0.1666667;\n\n float simplex3(vec3 p) {\n vec3 s = floor(p + dot(p, vec3(F3)));\n vec3 x = p - s + dot(s, vec3(G3));\n vec3 e = step(vec3(0.0), x - x.yzx);\n vec3 i1 = e * (1.0 - e.zxy);\n vec3 i2 = 1.0 - e.zxy * (1.0 - e);\n vec3 x1 = x - i1 + G3;\n vec3 x2 = x - i2 + 2.0 * G3;\n vec3 x3 = x - 1.0 + 3.0 * G3;\n vec4 w, d;\n w.x = dot(x, x);\n w.y = dot(x1, x1);\n w.z = dot(x2, x2);\n w.w = dot(x3, x3);\n w = max(0.6 - w, 0.0);\n d.x = dot(random3(s), x);\n d.y = dot(random3(s + i1), x1);\n d.z = dot(random3(s + i2), x2);\n d.w = dot(random3(s + 1.0), x3);\n w *= w;\n w *= w;\n d *= w;\n return dot(d, vec4(52.0));\n }\n\n float hash12(vec2 p) {\n vec3 p3 = fract(vec3(p.xyx) * 0.1031);\n p3 += dot(p3, p3.yzx + 33.33 + grainSeed * 17.17);\n return fract((p3.x + p3.y) * p3.z);\n }\n\n void main() {\n vec4 ref = texture(referenceMask, vUv);\n vec4 prev = texture(previousFrame, vUv);\n\n col = prev;\n\n if (frame < 0.5) {\n vec2 px = gl_FragCoord.xy;\n\n float fine = hash12(px) - 0.5;\n\n float fine2 = hash12(px * 0.5 + 91.7) - 0.5;\n float mottle = simplex3(vec3(\n vUv.x * 95.0 + grainSeed * 13.0,\n vUv.y * 95.0 - grainSeed * 9.0,\n 4.0\n ));\n\n float paper =\n fine * baseGrainAmount +\n fine2 * baseGrainAmount * 0.45 +\n mottle * baseMottleAmount;\n\n col.rgb += vec3(paper);\n }\n\n if (ref.g > 0.001) {\n float rnd = simplex3(vec3(\n (vUv.x + frame / 100.0) * 5000.0,\n (vUv.y - frame / 100.0) * 50.0,\n grainSeed * 100000.0\n ));\n\n vec4 textureBG = mix(\n bgColor,\n vec4(\n bgColor.rgb - vec3(\n simplex3(vec3(\n (vUv.x + frame / 1000.0) * 500.0,\n (vUv.y - frame / 1000.0) * 500.0,\n grainSeed * 100000.0\n )) / 80.\n ),\n 1.0\n ),\n simplex3(vec3(\n (vUv.x + frame / 1000.0) * 5.0,\n (vUv.y - frame / 1000.0) / 4.0,\n grainSeed * 100000.0\n ))\n );\n\n // This is the core wash behavior from the second project:\n // replace/scratch toward textured background, instead of dragging black blocks.\n col = mix(\n textureBG,\n prev,\n simplex3(vec3(\n (vUv.x + frame / 100.0) * 5000.0,\n (vUv.y - frame / 100.0) * 5000.0,\n grainSeed * 100000.0\n ))*4.\n );\n\n // Directional smudge, but only sometimes.\n if (rnd < smudgeChance) {\n col = mix(\n texture(previousFrame, vec2(\n vUv.x + 0.003 * dirx,\n vUv.y + 0.003 * diry\n )),\n textureBG,\n rnd\n );\n }\n\n // Let the green mask control strength.\n col = mix(bgColor, col, ref.g * washStrength);\n }\n\n if (ref.b > 0.01) {\n float paintMask = ref.b;\n\n float roughA = simplex3(vec3(\n vUv.x * 900.0,\n vUv.y * 900.0,\n frame * 0.012\n ));\n\n float roughB = simplex3(vec3(\n vUv.x * 2200.0,\n vUv.y * 2200.0,\n 19.0\n ));\n\n float brokenMask = paintMask;\n brokenMask *= smoothstep(-0.45, 0.55, roughA);\n brokenMask *= 0.72 + roughB * 0.28;\n\n vec4 noisyPaint = highlightColor;\n noisyPaint.rgb += vec3(roughB * 0.10 + roughA * 0.035);\n\n vec2 dragUv = vUv + vec2(\n roughA * 0.0025,\n roughB * 0.0015\n );\n\n vec4 draggedSurface = texture(previousFrame, dragUv);\n\n vec4 paintOnSurface = mix(draggedSurface, noisyPaint, brokenMask);\n\n col = mix(col, paintOnSurface, brokenMask);\n }\n\n // Red = foreground ink. The incoming reference contains only the current word.\n if (ref.r > 0.01) {\n float smearNoise = simplex3(vec3(\n vUv.x * 900.0 + frame * 0.03,\n vUv.y * 220.0 - frame * 0.02,\n grainSeed * 9999.0\n ));\n\n float smearMask = ref.r * smoothstep(-0.35, 0.55, smearNoise);\n\n vec2 smearUv = vUv + vec2(\n -0.006 * dirx,\n 0.002 * diry\n );\n\n vec4 draggedInk = texture(previousFrame, smearUv);\n\n col = mix(col, draggedInk, smearMask * 0.65);\n\n vec4 brokenInk = inkColor;\n\n col = mix(col, brokenInk, ref.r);\n }\n }\n",screenShader="\n uniform sampler2D buffer;\n in vec2 vUv;\n out vec4 col;\n\n void main() {\n col = texture(buffer, vec2(vUv.x, 1.0 - vUv.y));\n }\n";async function maybeFetchMoreWords(){if(!wordStream.fetching&&!wordStream.done&&!wordStream.failed)if(RPC_URLS.length){wordStream.fetching=!0;try{const e=await fetchNotesSlice(wordStream.nextOffset,FETCH_BATCH_SIZE);if(!e.length)return void(wordStream.done=!0);for(const t of e)WORDS.push(t),addWordPlacement(t);wordStream.nextOffset+=e.length,wordStream.nextOffset>=WORD_COUNT&&(wordStream.done=!0)}catch(e){console.warn("RPC word fetch failed:",e),wordStream.failed=!0}finally{wordStream.fetching=!1}}else wordStream.failed=!0}async function fetchNotesSlice(e,t){let r=null;for(const n of getRpcUrls())try{return await fetchNotesSliceFromRpc(n,TOKEN_ID,e,t)}catch(e){r=e,console.warn("RPC failed, trying next:",n,e)}throw r||new Error("No RPC worked")}const NOTES_SLICE_SELECTOR="0x91cf7995";async function fetchNotesSliceFromRpc(e,t,r,n){const o=NOTES_SLICE_SELECTOR+encodeUint256(t)+encodeUint256(r)+encodeUint256(n),a=await fetch(e,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({jsonrpc:"2.0",id:1,method:"eth_call",params:[{to:CONTRACT_ADDRESS,data:o},"latest"]})}),s=await a.json();if(s.error)throw new Error(s.error.message||"RPC error");return s.result&&"0x"!==s.result?decodeStringArray(s.result):[]}function encodeUint256(e){return BigInt(e).toString(16).padStart(64,"0")}function decodeStringArray(e){e=e.replace(/^0x/,"");const t=t=>{const r=2*t;return BigInt("0x"+e.slice(r,r+64))},r=(t,r)=>{const n=2*t;return e.slice(n,n+2*r)},n=Number(t(0)),o=Number(t(n)),a=[];for(let e=0;e<o;e++){const o=n+32+Number(t(n+32+32*e)),s=r(o+32,Number(t(o)));a.push(hexToUtf8(s))}return a}function hexToUtf8(e){const t=[];for(let r=0;r<e.length;r+=2)t.push(parseInt(e.slice(r,r+2),16));return(new TextDecoder).decode(new Uint8Array(t)).replace(/\0/g,"").trim()}function varyColor(e,t=.01){return[Math.max(0,Math.min(1,e[0]+R.range(-t,t))),Math.max(0,Math.min(1,e[1]+R.range(-t,t))),Math.max(0,Math.min(1,e[2]+R.range(-t,t))),e[3]??1]}function init(){if(gl=view.getContext("webgl2",{alpha:!1,antialias:!1,preserveDrawingBuffer:!0}),!gl)return void(document.body.innerHTML="WebGL2 is required.");vertexBuffer=createVertexBuffer(),washProgram=createProgram(vertexShader,washShader),screenProgram=createProgram(vertexShader,screenShader),createGrids(),createWordPlacements(),window.addEventListener("resize",requestResize),window.addEventListener("keydown",handleKey),view.addEventListener("webglcontextlost",e=>{e.preventDefault(),console.warn("WebGL context lost")},!1),view.addEventListener("webglcontextrestored",()=>{console.warn("WebGL context restored, rebuilding"),hardRebuild()},!1);new ResizeObserver(()=>requestResize()).observe(document.body),resize(),requestRun()}function resetRandom(){R=new Random(HASH)}function requestResize(){resizeQueued||(resizeQueued=!0,requestAnimationFrame(()=>{resizeQueued=!1,resize()}))}function resetWordsToDefault(){WORDS.length=0,WORDS.push(...INITIAL_WORDS),wordStream.fetching=!1,wordStream.done=WORDS.length>=WORD_COUNT,wordStream.failed=!1,wordStream.nextOffset=WORDS.length}let lastRenderedPixelCount=0;function restartAfterResize(){resetWordsToDefault(),resetRandom(),state.frame=0,state.activePlacementIndex=0,createGrids(),createWordPlacements(),drawBaseReference(),refTexture&&gl.deleteTexture(refTexture),refTexture=createTexture(width,height,ref),resetFrameBuffers(),window.__RESIDUAL_NOTES_RENDERED__=!1,blackFrameCount=0,lastProgressFrame=0,lastRenderedPixelCount=width*height,requestRun()}let renderW=null,renderH=null;function resize(){const e=1*Math.floor(window.innerWidth||document.documentElement.clientWidth||0),t=1*Math.floor(window.innerHeight||document.documentElement.clientHeight||0);if(e<20||t<20)return void requestAnimationFrame(requestResize);let r,n;e/t>settings.aspect?(n=t,r=t*settings.aspect):(r=e,n=e/settings.aspect),dpr=Math.max(1,window.devicePixelRatio||1);const o=renderW??Math.max(20,Math.round(r*dpr)),a=renderH??Math.max(20,Math.round(n*dpr));if(!(o===width&&a===height)){if(width>0&&height>0&&!(o*a>width*height))return view.style.width=`${r}px`,void(view.style.height=`${n}px`);isResizing=!0,width=o,height=a,view.width=width,view.height=height,view.style.display="block",ref.width=width,ref.height=height,ref.style.display=settings.showReference?"block":"none",restartAfterResize(),isResizing=!1}}function setCustomRenderSize(){const e=prompt("Render width in pixels:",width);if(!e)return;const t=Math.max(100,Math.floor(Number(e)));Number.isFinite(t)&&(renderW=t,renderH=Math.round(renderW/settings.aspect),resize())}function useStructureSpace(){refCtx.setTransform(width/4e3,0,0,height/5e3,0,0)}function resetFrameBuffers(){for(const e of frameBuffers)gl.deleteFramebuffer(e.buffer),gl.deleteTexture(e.texture);frameBuffers=[createFrameBuffer(width,height,ref),createFrameBuffer(width,height,null)],frameBufferId=0}function queueHardRebuild(e="unknown"){restartQueued||(restartQueued=!0,console.warn("Queueing hard rebuild:",e),requestAnimationFrame(()=>{restartQueued=!1,hardRebuild(e)}))}function hardRebuild(e="unknown"){if(console.warn("Hard rebuild:",e),gl&&!gl.isContextLost())try{if(resize(),width<MIN_GL_SIZE||height<MIN_GL_SIZE)return;restartAfterResize(),blackFrameCount=0,lastProgressFrame=state.frame,window.__RESIDUAL_NOTES_RENDERED__=!1}catch(e){console.warn("Hard rebuild failed:",e)}}function assertFramebufferHealthy(e=""){const t=gl.checkFramebufferStatus(gl.FRAMEBUFFER);return t===gl.FRAMEBUFFER_COMPLETE||(queueHardRebuild(`bad framebuffer ${e}: ${t}`),!1)}function drawBaseReference(){useStructureSpace(),refCtx.fillStyle=rgb(palette.bg),refCtx.fillRect(0,0,4e3,5e3),refCtx.fillStyle=rgb(palette.grid);const e=Math.floor(settings.gridDefinitions[0].cols),t=Math.floor(settings.gridDefinitions[0].rows);for(let t=2;t<e-2;t++)refCtx.fillRect(4e3/e*t,0,1,5e3);for(let e=2;e<t-2;e++)refCtx.fillRect(0,5e3/t*e,4e3,1)}function createGrids(){state.grids=settings.gridDefinitions.map((e,t)=>({id:t,name:e.name||`grid ${t}`,cols:Math.floor(e.cols),rows:Math.floor(e.rows),rotation:e.rotation||0,scale:e.scale||1,offsetX:e.offsetX||0,offsetY:e.offsetY||0,letterScale:e.letterScale||.8,occupied:null}))}function createWordPlacements(){state.placements=[];let e=R.int(settings.backgroundWashMinWords,settings.backgroundWashMaxWords);for(const t of WORDS)addWordPlacement(t),e--,e<=0&&R.chance(settings.backgroundWashChance)&&(addBackgroundWashPlacement(),e=R.int(settings.backgroundWashMinWords,settings.backgroundWashMaxWords))}function addWordPlacement(e){if(!e||!String(e).trim())return!1;const t=String(e).toUpperCase(),r=tryCreateWordPlacement(t)||tryCreateWordPlacement(t)||tryCreateWordPlacement(t);return!!r&&(state.placements.push(r),!0)}function addBackgroundWashPlacement(){state.placements.push({type:"backgroundWash",color:R.chance(.15)?palette.highlight:darkenedBgColor(.1),dirx:R.range(-1,1),diry:R.range(-1,1),washStrength:R.range(.03,.16),smudgeChance:R.range(.1,.32),x:4e3*R.range(-.08,.85),y:5e3*R.range(-.08,.85),w:4e3*R.range(.18,.55),h:5e3*R.range(.12,.38),seed:9999*R.g(),alpha:R.range(.02,.175),dripChance:R.range(.08,.28),force:1})}function tryCreateWordPlacement(e){for(let t=0;t<80;t++){const t=R.pick(state.grids),r=R.pick(["right","down","right","down","right","down","right","down","right","down","right","down","right","down","diagDown","diagUp"]),n=randomStartForTextBlock(t,e,r),o=textBlockCells(n.x,n.y,e,r,t);if(cellsFit(t,o))return{word:e,grid:t,direction:r,cells:o,color:varyColor(pickInkForWord(),.05),dirx:R.range(-2,2),diry:R.range(-2,2),washSeed:R.g(),washStrength:R.range(.05,.35),smudgeChance:R.range(.1,.32),washPad:R.range(.04,.2),washGaps:0,washStampCount:R.int(1,6),circle:R.chance(.065),underline:R.chance(.05),strikethrough:R.chance(.05),lettergrid:R.chance(.01),square:R.chance(.01),cross:R.chance(.01),plus:R.chance(.005),force:1}}return null}function randomStartForTextBlock(e,t,r){const n=Math.min(String(t).length,"right"===r?e.cols:e.rows),o=R.int(0,e.cols-1),a=R.int(0,e.rows-1);return"right"===r?{x:Math.max(0,Math.min(e.cols-1,o-Math.floor(n*R.range(.25,.65)))),y:Math.max(0,Math.min(e.rows-1,a-R.int(0,2)))}:"down"===r?{x:Math.max(0,Math.min(e.cols-1,o-R.int(0,2))),y:Math.max(0,Math.min(e.rows-1,a-Math.floor(n*R.range(.25,.65))))}:{x:o,y:a}}function textBlockCells(e,t,r,n,o){if("diagDown"===n||"diagUp"===n)return diagonalTextCells(e,t,r,n);const a=String(r).split(/\s+/),s=[],i="right"===n?Math.max(1,o.cols-e):Math.max(1,o.rows-t);let l=0,f=0;for(const r of a){if(f+(f>0?1:0)+r.length>i&&(l++,f=0),"right"===n&&t+l>=o.rows)break;if("down"===n&&e+l>=o.cols)break;f>0&&(addTextCharCell(s,e,t,n,f,l," "),f++);for(let a=0;a<r.length&&(f>=i&&(l++,f=0),!("right"===n&&t+l>=o.rows))&&!("down"===n&&e+l>=o.cols);a++)addTextCharCell(s,e,t,n,f,l,r[a]),f++}return s.map((e,t)=>({...e,index:t}))}function addTextCharCell(e,t,r,n,o,a,s){"right"===n&&e.push({x:t+o,y:r+a,char:s}),"down"===n&&e.push({x:t+a,y:r+o,char:s})}function diagonalTextCells(e,t,r,n){const o=[];for(let a=0;a<r.length;a++){let s=e+a,i="diagDown"===n?t+a:t-a;o.push({x:s,y:i,char:r[a],index:a})}return o}function cellsFit(e,t){return t.every(t=>t.x>=0&&t.y>=0&&t.x<e.cols&&t.y<e.rows)}function pickInkForWord(){return weightedPick(palette.inks).color}function weightedPick(e){const t=e.reduce((e,t)=>e+t.weight,0);let r=R.g()*t;for(const t of e)if(r-=t.weight,r<=0)return t;return e[e.length-1]}function clearReferenceToBlack(){refCtx.setTransform(1,0,0,1,0,0),refCtx.fillStyle="black",refCtx.fillRect(0,0,width,height)}function drawPlacementReference(e,t){if("backgroundWash"===e.type)return void drawBackgroundWashReference(e,t);clearReferenceToBlack(),refCtx.save(),useStructureSpace(),applyGridTransform(e.grid);const r=Math.ceil(e.cells.length*t),n=e.cells.slice(0,r);drawWashForCells(e.grid,n,e.washPad,e),drawWordCells(e.grid,n,e),e.underline&&t>.72&&drawUnderline(e),e.circle&&t>.84&&drawCircleAroundWord(e),e.strikethrough&&t>.65&&drawStrikethrough(e),e.lettergrid&&t>.7&&drawGridAroundLetters(e,n),e.square&&t>.82&&drawSquareAroundWord(e),e.cross&&t>.78&&drawCrossThroughWord(e),e.plus&&t>.78&&drawPlusThroughWord(e),refCtx.restore()}function applyGridTransform(e){refCtx.translate(2e3+4e3*e.offsetX,2500+5e3*e.offsetY),refCtx.rotate(e.rotation),refCtx.scale(e.scale,e.scale),refCtx.translate(-2e3,-2500)}function drawWashForCells(e,t,r,n){const o=4e3/e.cols,a=5e3/e.rows;refCtx.save(),refCtx.fillStyle="rgb(0,255,0)";for(const e of t){const t=n.washStampCount??1;for(let s=0;s<t;s++){const t=1e3*n.washSeed+97*s;if(stable01(e.x,e.y,e.index+t)<n.washGaps)continue;const i=stable01(e.x,e.y,101+t),l=stable01(e.x,e.y,202+t),f=stableNoise(e.x,e.y,303+t)*o*.22,c=stableNoise(e.x,e.y,404+t)*a*.22,d=o*(.04+.14*i),g=a*(.04+.14*l),h=o*r,u=a*r;refCtx.fillRect(e.x*o+d-h+f,e.y*a+g-u+c,o-2*d+2*h,a-2*g+2*u)}}refCtx.restore()}function stable01(e,t,r){const n=43758.5453*Math.sin(12.9898*e+78.233*t+37.719*r);return n-Math.floor(n)}function drawWordCells(e,t,r){const n=4e3/e.cols,o=5e3/e.rows;refCtx.fillStyle="rgb(255,0,0)",refCtx.strokeStyle="rgb(255,0,0)",refCtx.lineWidth=Math.max(1,.09*Math.min(n,o)),refCtx.lineCap="round",refCtx.lineJoin="round";for(const e of t)drawLetterInCell(e.char,e.x*n,e.y*o,n,o,r,e.index)}function drawLetterInCell(e,t,r,n,o,a,s){if(" "===e)return;const i=Math.min(n,o)*RangedLetterScale(a,s),l=stableNoise(t,r,s+1)*n*.1,f=stableNoise(t,r,s+2)*o*.1,c=.05*stableNoise(t,r,s+3);refCtx.save(),refCtx.translate(t+.5*n+l,r+.54*o+f),refCtx.rotate(c),refCtx.font=`${i}px ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace`,refCtx.textAlign="center",refCtx.textBaseline="middle",refCtx.fillText(e,0,0),refCtx.restore()}function RangedLetterScale(e,t){return e.grid.letterScale}function darkenedBgColor(e=.1){return[Math.max(0,palette.bg[0]-e),Math.max(0,palette.bg[1]-e),Math.max(0,palette.bg[2]-e),palette.bg[3]??1]}function drawUnderline(e){const t=4e3/e.grid.cols,r=5e3/e.grid.rows,n=e.cells.filter(e=>" "!==e.char);if(!n.length)return;refCtx.save(),refCtx.strokeStyle="rgb(255,0,0)",refCtx.lineWidth=Math.max(.6,.08*Math.min(t,r)),refCtx.lineCap="round",refCtx.lineJoin="round";const o=n[0],a=n[n.length-1],s=o.x*t+.15*t,i=o.y*r+.84*r,l=a.x*t+.85*t,f=a.y*r+.84*r,c=l-s,d=f-i,g=Math.max(1e-4,Math.sqrt(c*c+d*d)),h=-d/g,u=c/g,x=.28*Math.min(t,r);refCtx.beginPath(),refCtx.moveTo(s+h*x,i+u*x),refCtx.lineTo(l+h*x+stableNoise(l,f,9)*t*.25,f+u*x+stableNoise(s,i,10)*r*.25),refCtx.stroke(),refCtx.restore()}function drawStrikethrough(e){const t=4e3/e.grid.cols,r=5e3/e.grid.rows,n=e.cells.filter(e=>" "!==e.char);if(!n.length)return;const o=n[0],a=n[n.length-1],s=o.x*t+.15*t,i=o.y*r+.5*r,l=a.x*t+.85*t,f=a.y*r+.5*r;refCtx.save(),refCtx.strokeStyle="rgb(255,0,0)",refCtx.lineWidth=Math.max(.6,.08*Math.min(t,r)),refCtx.lineCap="round",refCtx.lineJoin="round",refCtx.beginPath(),refCtx.moveTo(s+stableNoise(s,i,21)*t*.18,i+stableNoise(s,i,22)*r*.18),refCtx.lineTo(l+stableNoise(l,f,23)*t*.18,f+stableNoise(l,f,24)*r*.18),refCtx.stroke(),refCtx.restore()}function drawCircleAroundWord(e){const t=wordBox(e),r=.5*(t.x1+t.x2),n=.5*(t.y1+t.y2),o=.62*Math.abs(t.x2-t.x1)+4e3/e.grid.cols,a=.62*Math.abs(t.y2-t.y1)+5e3/e.grid.rows,s=.35*stableNoise(r,n,4),i=refCtx.lineWidth,l=refCtx.strokeStyle;refCtx.strokeStyle="rgb(255,0,0)",refCtx.lineCap="round";const f=stableNoise(r,n,999),c=1+Math.floor(5*f);for(let e=0;e<c;e++){const t=1e3+137*e,l=stableNoise(r,n,t+1),f=stableNoise(r,n,t+2),c=stableNoise(r,n,t+3),d=stableNoise(r,n,t+4),g=stableNoise(r,n,t+5),h=.94+.18*g,u=.18+.95*stableNoise(r,n,t+6),x=.35+.65*d,m=4e3*l*.006,C=5e3*f*.006,w=o*h*(1+.04*c),b=a*h*(1-.04*c),R=g*Math.PI*2,p=stableNoise(r,n,t+7)<.45?.55+.35*stableNoise(r,n,t+8):1,v=R+2*Math.PI*p;refCtx.save(),refCtx.globalAlpha*=x,refCtx.lineWidth=i*u,refCtx.beginPath(),refCtx.ellipse(r+m,n+C,w,b,s+.22*d,R,v),refCtx.stroke(),refCtx.restore()}refCtx.lineWidth=i,refCtx.strokeStyle=l}function drawGridAroundLetters(e,t){const r=4e3/e.grid.cols,n=5e3/e.grid.rows,o=t.filter(e=>" "!==e.char);if(o.length){refCtx.save(),refCtx.strokeStyle="rgb(255,0,0)",refCtx.lineWidth=Math.max(.5,.045*Math.min(r,n)),refCtx.lineCap="square",refCtx.lineJoin="miter";for(const t of o){const o=t.x*r,a=t.y*n,s=.025*Math.min(r,n),i=t.index+1e3*e.washSeed;refCtx.beginPath(),refCtx.rect(o+stableNoise(t.x,t.y,i+1)*s,a+stableNoise(t.x,t.y,i+2)*s,r+stableNoise(t.x,t.y,i+3)*s,n+stableNoise(t.x,t.y,i+4)*s),refCtx.stroke()}refCtx.restore()}}function drawSquareAroundWord(e){const t=expandedWordBox(e,.22),r=Math.min(4e3/e.grid.cols,5e3/e.grid.rows);refCtx.save(),refCtx.strokeStyle="rgb(255,0,0)",refCtx.lineWidth=Math.max(.6,.08*r),refCtx.lineCap="round",refCtx.lineJoin="round";const n=.12*r;refCtx.beginPath(),refCtx.moveTo(t.x1+stableNoise(t.x1,t.y1,301)*n,t.y1+stableNoise(t.x1,t.y1,302)*n),refCtx.lineTo(t.x2+stableNoise(t.x2,t.y1,303)*n,t.y1+stableNoise(t.x2,t.y1,304)*n),refCtx.lineTo(t.x2+stableNoise(t.x2,t.y2,305)*n,t.y2+stableNoise(t.x2,t.y2,306)*n),refCtx.lineTo(t.x1+stableNoise(t.x1,t.y2,307)*n,t.y2+stableNoise(t.x1,t.y2,308)*n),refCtx.closePath(),refCtx.stroke(),refCtx.restore()}function drawCrossThroughWord(e){const t=expandedWordBox(e,.12),r=Math.min(4e3/e.grid.cols,5e3/e.grid.rows);refCtx.save(),refCtx.strokeStyle="rgb(255,0,0)",refCtx.lineWidth=Math.max(.6,.08*r),refCtx.lineCap="round",refCtx.lineJoin="round",drawNoisyLine(t.x1,t.y1,t.x2,t.y2,r,401),drawNoisyLine(t.x2,t.y1,t.x1,t.y2,r,411),refCtx.restore()}function drawPlusThroughWord(e){const t=expandedWordBox(e,.1),r=Math.min(4e3/e.gr*wid.cols,5e3/e.grid.rows),n=.5*(t.x1+t.x2),o=.5*(t.y1+t.y2);refCtx.save(),refCtx.strokeStyle="rgb(255,0,0)",refCtx.lineWidth=Math.max(.6,.08*r),refCtx.lineCap="round",refCtx.lineJoin="round",drawNoisyLine(t.x1,o,t.x2,o,r,501),drawNoisyLine(n,t.y1,n,t.y2,r,511),refCtx.restore()}function drawBackgroundWashReference(e,t){clearReferenceToBlack(),refCtx.save(),useStructureSpace(),refCtx.globalAlpha=e.alpha*t,refCtx.fillStyle="rgb(0,0,255)",refCtx.strokeStyle="rgb(0,0,255)",refCtx.lineCap="round",refCtx.lineJoin="round";const r=e.y+.42*e.h;for(let n=0;n<44;n++){const o=n/Math.max(1,43),a=e.x+e.w*o+stableNoise(e.seed,n,11)*e.w*.025,s=Math.sin(o*Math.PI),i=r-e.h*(.25+.75*s+.45*stable01(e.seed,n,12)),l=r+e.h*(.15+.55*s+.75*stable01(e.seed,n,13)),f=e.w*(.018+.045*stable01(e.seed,n,14));drawVerticalPaintColumn(a,i,l,f,e.seed+91*n,t),stable01(e.seed,n,77)<e.dripChance&&drawPaintDrip(a+stableNoise(e.seed,n,21)*f,l-.05*e.h,e.h*(.35+1.4*stable01(e.seed,n,22)),e.seed+200*n)}for(let n=0;n<9;n++){const o=r+stableNoise(e.seed,n,301)*e.h*.45;refCtx.globalAlpha=e.alpha*t*.22,refCtx.lineWidth=e.h*(.025+.045*stable01(e.seed,n,302)),drawNoisyHorizontalStroke(e.x+stableNoise(e.seed,n,303)*e.w*.05,o,e.x+e.w+stableNoise(e.seed,n,304)*e.w*.05,o+stableNoise(e.seed,n,305)*e.h*.18,e.seed+400*n)}refCtx.restore()}function drawVerticalPaintColumn(e,t,r,n,o,a){refCtx.beginPath();for(let a=0;a<=12;a++){const s=t+(r-t)*(a/12),i=e-.5*n+stableNoise(o,a,31)*n*.75;0===a?refCtx.moveTo(i,s):refCtx.lineTo(i,s)}for(let a=12;a>=0;a--){const s=t+(r-t)*(a/12),i=e+.5*n+stableNoise(o,a,41)*n*.75;refCtx.lineTo(i,s)}refCtx.closePath(),refCtx.fill(),refCtx.save(),refCtx.globalAlpha*=.35;const s=2+Math.floor(5*stable01(o,1,55));for(let a=0;a<s;a++){const s=e+stableNoise(o,a,61)*n*.45;refCtx.lineWidth=n*(.08+.18*stable01(o,a,62)),refCtx.beginPath(),refCtx.moveTo(s,t+stableNoise(o,a,63)*n),refCtx.lineTo(s+stableNoise(o,a,64)*n*.45,r-stable01(o,a,65)*n),refCtx.stroke()}refCtx.restore(),refCtx.save(),refCtx.globalCompositeOperation="destination-out";for(let s=0;s<22;s++){const i=stable01(o,s,71)<.5?-1:1,l=t+stable01(o,s,72)*(r-t),f=e+i*n*(.3+.45*stable01(o,s,73));refCtx.globalAlpha=a*(.04+.14*stable01(o,s,74)),refCtx.beginPath(),refCtx.ellipse(f,l,n*(.15+.55*stable01(o,s,75)),n*(.25+1.25*stable01(o,s,76)),stableNoise(o,s,77),0,2*Math.PI),refCtx.fill()}refCtx.restore()}function drawNoisyHorizontalStroke(e,t,r,n,o){refCtx.beginPath();for(let a=0;a<=18;a++){const s=a/18,i=e+(r-e)*s,l=t+(n-t)*s+5e3*stableNoise(o,a,91)*.006;0===a?refCtx.moveTo(i,l):refCtx.lineTo(i,l)}refCtx.stroke()}function drawPainterlyBlob(e,t,r,n,o,a){const s=[];for(let a=0;a<28;a++){const i=a/28*Math.PI*2,l=1+.12*stableNoise(o,a,31)+.06*stableNoise(o,a,32)+.06*Math.sin(2*i+o)+.04*Math.sin(5*i+.37*o);s.push({x:e+Math.cos(i)*r*.5*l,y:t+Math.sin(i)*n*.5*l})}refCtx.beginPath();for(let e=0;e<s.length;e++){const t=s[(e-1+s.length)%s.length],r=s[e],n=s[(e+1)%s.length],o={x:.5*(t.x+r.x),y:.5*(t.y+r.y)},a={x:.5*(r.x+n.x),y:.5*(r.y+n.y)};0===e&&refCtx.moveTo(o.x,o.y),refCtx.quadraticCurveTo(r.x,r.y,a.x,a.y)}refCtx.closePath(),refCtx.fill(),refCtx.save(),refCtx.globalCompositeOperation="destination-out",refCtx.globalAlpha=.1*a;for(let s=0;s<160;s++){const i=stable01(o,s,41)*Math.PI*2,l=Math.sqrt(stable01(o,s,42)),f=Math.cos(i)*l,c=Math.sin(i)*l,d=e+f*r*.48,g=t+c*n*.48,h=Math.min(1,Math.sqrt(f*f+c*c)),u=Math.pow(h,2.2),x=r*(.004+.09*u*stable01(o,s,43)),m=n*(.003+.05*u*stable01(o,s,44));refCtx.globalAlpha=(.01+.18*u)*a,refCtx.beginPath(),refCtx.ellipse(d,g,x,m,stableNoise(o,s,45)*Math.PI,0,2*Math.PI),refCtx.fill()}refCtx.restore()}function drawPaintDrip(e,t,r,n){const o=.045*r;refCtx.beginPath(),refCtx.moveTo(e,t);for(let a=1;a<=5;a++){const s=a/5;refCtx.lineTo(e+stableNoise(n,a,51)*o,t+r*s)}refCtx.lineWidth=Math.max(1,4.8),refCtx.lineCap="round",refCtx.strokeStyle="rgb(0,0,255)",refCtx.stroke()}function drawNoisyLine(e,t,r,n,o,a){const s=.16*o;refCtx.beginPath(),refCtx.moveTo(e+stableNoise(e,t,a+1)*s,t+stableNoise(e,t,a+2)*s),refCtx.lineTo(r+stableNoise(r,n,a+3)*s,n+stableNoise(r,n,a+4)*s),refCtx.stroke()}function expandedWordBox(e,t=.15){const r=wordBox(e),n=4e3/e.grid.cols,o=5e3/e.grid.rows;return{x1:r.x1-n*t,y1:r.y1-o*t,x2:r.x2+n*t,y2:r.y2+o*t}}function wordBox(e){const t=4e3/e.grid.cols,r=5e3/e.grid.rows,n=e.cells.map(e=>e.x*t),o=e.cells.map(e=>e.y*r);return{x1:Math.min(...n),y1:Math.min(...o),x2:Math.max(...n)+t,y2:Math.max(...o)+r}}function stableNoise(e,t,r){const n=43758.5453*Math.sin(12.9898*e+78.233*t+37.719*r);return n-Math.floor(n)-.5}function run(){if(renderLoopRunning=!1,isResizing||width<MIN_GL_SIZE||height<MIN_GL_SIZE||!refTexture||frameBuffers.length<2)return void requestRun();maybeFetchMoreWords();const e=state.placements[state.activePlacementIndex];if(!e)return renderScreen(),state.frame%30==0&&sampleVisibleCanvasHealth(),void(window.__RESIDUAL_NOTES_RENDERED__||(window.__RESIDUAL_NOTES_RENDERED__=!0,window.dispatchEvent(new Event("residual-notes:rendered"))));const t=settings.pauseFrames+settings.revealFrames,r=state.frame%t;let n=0,o=!1;if(r<settings.pauseFrames)clearReferenceToBlack();else{const t=r-settings.pauseFrames;n=Math.min(1,(t+1)*settings.revealSpeed/settings.revealFrames),o=t>=settings.revealFrames-1,drawPlacementReference(e,n)}updateReferenceTexture(),renderWash(e),renderScreen(),(o||r===t-1)&&state.activePlacementIndex++,state.frame++,requestRun()}function renderWash(e){const t=frameBufferId,r=1^frameBufferId;frameBufferId=r,useProgram(washProgram),gl.bindFramebuffer(gl.FRAMEBUFFER,frameBuffers[r].buffer),assertFramebufferHealthy("renderWash")&&(gl.viewport(0,0,width,height),gl.clearColor(0,0,0,1),gl.clear(gl.COLOR_BUFFER_BIT),gl.activeTexture(gl.TEXTURE0),gl.bindTexture(gl.TEXTURE_2D,frameBuffers[t].texture),gl.uniform1i(gl.getUniformLocation(washProgram,"previousFrame"),0),gl.activeTexture(gl.TEXTURE1),gl.bindTexture(gl.TEXTURE_2D,refTexture),gl.uniform1i(gl.getUniformLocation(washProgram,"referenceMask"),1),gl.uniform1f(gl.getUniformLocation(washProgram,"frame"),state.frame),gl.uniform1f(gl.getUniformLocation(washProgram,"dirx"),e.dirx),gl.uniform1f(gl.getUniformLocation(washProgram,"diry"),e.diry),gl.uniform1f(gl.getUniformLocation(washProgram,"washStrength"),e.washStrength??settings.washStrength),gl.uniform1f(gl.getUniformLocation(washProgram,"smudgeChance"),e.smudgeChance??settings.smudgeChance),gl.uniform4fv(gl.getUniformLocation(washProgram,"bgColor"),palette.bg),gl.uniform4fv(gl.getUniformLocation(washProgram,"inkColor"),e.color),gl.uniform4fv(gl.getUniformLocation(washProgram,"highlightColor"),"backgroundWash"===e.type?e.color:palette.highlight),gl.uniform2f(gl.getUniformLocation(washProgram,"resolution"),width,height),gl.uniform1f(gl.getUniformLocation(washProgram,"grainSeed"),GRAIN_SEED),gl.uniform1f(gl.getUniformLocation(washProgram,"baseGrainAmount"),settings.baseGrainAmount),gl.uniform1f(gl.getUniformLocation(washProgram,"baseMottleAmount"),settings.baseMottleAmount),gl.drawArrays(gl.TRIANGLE_STRIP,0,4))}function sampleVisibleCanvasHealth(){if(!gl||gl.isContextLost())return;const e=new Uint8Array(4);gl.bindFramebuffer(gl.FRAMEBUFFER,null),gl.readPixels(Math.floor(.5*width),Math.floor(.5*height),1,1,gl.RGBA,gl.UNSIGNED_BYTE,e);e[0]+e[1]+e[2]<8&&state.frame>20?blackFrameCount++:blackFrameCount=0,blackFrameCount>90&&queueHardRebuild("visible canvas stayed black"),state.activePlacementIndex!==lastProgressPlacementIndex&&(lastProgressPlacementIndex=state.activePlacementIndex,lastProgressFrame=state.frame);state.activePlacementIndex>0&&state.activePlacementIndex<state.placements.length&&state.frame-lastProgressFrame>240&&queueHardRebuild("render loop appears stuck")}function renderScreen(){useProgram(screenProgram),gl.bindFramebuffer(gl.FRAMEBUFFER,null),gl.viewport(0,0,width,height),gl.clearColor(0,0,0,1),gl.clear(gl.COLOR_BUFFER_BIT),gl.activeTexture(gl.TEXTURE0),gl.bindTexture(gl.TEXTURE_2D,frameBuffers[frameBufferId].texture),gl.uniform1i(gl.getUniformLocation(screenProgram,"buffer"),0),gl.drawArrays(gl.TRIANGLE_STRIP,0,4)}function useProgram(e){gl.useProgram(e);const t=gl.getAttribLocation(e,"pos");gl.enableVertexAttribArray(t),gl.bindBuffer(gl.ARRAY_BUFFER,vertexBuffer),gl.vertexAttribPointer(t,3,gl.FLOAT,!1,0,0)}function createProgram(e,t){const r=gl.createProgram(),n=createShader(`#version 300 es\n${e}`,gl.VERTEX_SHADER),o=createShader(`#version 300 es\nprecision highp float;\n${t}`,gl.FRAGMENT_SHADER);return gl.attachShader(r,n),gl.attachShader(r,o),gl.linkProgram(r),gl.getProgramParameter(r,gl.LINK_STATUS)||console.error(gl.getProgramInfoLog(r)),r}function createShader(e,t){const r=gl.createShader(t);return gl.shaderSource(r,e),gl.compileShader(r),gl.getShaderParameter(r,gl.COMPILE_STATUS)||console.error(gl.getShaderInfoLog(r)),r}function createVertexBuffer(){const e=gl.createBuffer();return gl.bindBuffer(gl.ARRAY_BUFFER,e),gl.bufferData(gl.ARRAY_BUFFER,new Float32Array([-1,1,0,-1,-1,0,1,1,0,1,-1,0]),gl.STATIC_DRAW),e}function createFrameBuffer(e,t,r=null){e=Math.max(MIN_GL_SIZE,Math.floor(e)),t=Math.max(MIN_GL_SIZE,Math.floor(t));const n=gl.createFramebuffer(),o=createTexture(e,t,r);gl.bindFramebuffer(gl.FRAMEBUFFER,n),gl.framebufferTexture2D(gl.FRAMEBUFFER,gl.COLOR_ATTACHMENT0,gl.TEXTURE_2D,o,0);const a=gl.checkFramebufferStatus(gl.FRAMEBUFFER);return a!==gl.FRAMEBUFFER_COMPLETE&&console.warn("Framebuffer incomplete:",a,e,t),gl.bindFramebuffer(gl.FRAMEBUFFER,null),{buffer:n,texture:o}}function createTexture(e,t,r=null){e=Math.max(MIN_GL_SIZE,Math.floor(e)),t=Math.max(MIN_GL_SIZE,Math.floor(t));const n=gl.createTexture();return gl.bindTexture(gl.TEXTURE_2D,n),gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.NEAREST),gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.NEAREST),gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_S,gl.CLAMP_TO_EDGE),gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_T,gl.CLAMP_TO_EDGE),r&&r.width>0&&r.height>0?gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,gl.RGBA,gl.UNSIGNED_BYTE,r):gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,e,t,0,gl.RGBA,gl.UNSIGNED_BYTE,null),n}function updateReferenceTexture(){refTexture&&(!ref||ref.width<MIN_GL_SIZE||ref.height<MIN_GL_SIZE||(gl.bindTexture(gl.TEXTURE_2D,refTexture),gl.texSubImage2D(gl.TEXTURE_2D,0,0,0,gl.RGBA,gl.UNSIGNED_BYTE,ref)))}function rgb(e){return`rgb(${Math.floor(255*e[0])}, ${Math.floor(255*e[1])}, ${Math.floor(255*e[2])})`}function clamp255(e){return Math.max(0,Math.min(255,e))}function handleKey(e){"s"===e.key&&savePNG(),"m"===e.key&&(settings.showReference=!settings.showReference,ref.style.display=settings.showReference?"block":"none"),"c"===e.key&&setCustomRenderSize(),"p"===e.key.toLowerCase()&&setCustomRpcUrl()}function savePNG(){renderScreen();const e=document.createElement("a");e.download=`residual-notes-${HASH.slice(2,10)}-${width}x${height}.png`,e.href=view.toDataURL("image/png"),e.click()}function restart(){restartAfterResize()}init();
function parsePalette(e){const t=Object.fromEntries(e.split("|").map(e=>{const t=e.indexOf("=");return[e.slice(0,t),e.slice(t+1)]})),r=e=>e.trim().split(/\s+/).map(Number);return{bg:r(t.bg),grid:r(t.grid),highlight:r(t.highlight),inks:t.inks.split(";").map(e=>{const t=r(e);return{color:t.slice(0,4),weight:t[4]}})}}palette=parsePalette(palette);class Random{constructor(e){this.useA=!1,this.prngA=this.sfc32(e.slice(2,34)),this.prngB=this.sfc32(e.slice(34,66));for(let e=0;e<1e5;e++)this.prngA(),this.prngB()}sfc32(e){let t=parseInt(e.slice(0,8),16),r=parseInt(e.slice(8,16),16),n=parseInt(e.slice(16,24),16),o=parseInt(e.slice(24,32),16);return function(){t|=0,r|=0,n|=0,o|=0;let e=(t+r|0)+o|0;return o=o+1|0,t=r^r>>>9,r=n+(n<<3)|0,n=n<<21|n>>>11,n=n+e|0,(e>>>0)/4294967296}}g(){return this.useA=!this.useA,this.useA?this.prngA():this.prngB()}range(e,t){return e+this.g()*(t-e)}int(e,t){return Math.floor(this.range(e,t+1))}pick(e){return e[Math.floor(this.g()*e.length)]}chance(e){return this.g()<e}}let R=new Random(HASH);const wordStream={fetching:!1,done:WORDS.length>=WORD_COUNT,failed:!1,nextOffset:WORDS.length};let customRpcUrl="";function getRpcUrls(){return customRpcUrl?[customRpcUrl,...RPC_URLS.filter(e=>e!==customRpcUrl)]:RPC_URLS}function setCustomRpcUrl(){const e=prompt("Custom RPC URL:",customRpcUrl||"https://...");if(!e)return;const t=e.trim();/^https?:\/\//i.test(t)?(customRpcUrl=t,wordStream.fetching=!1,wordStream.failed=!1,wordStream.done=WORDS.length>=WORD_COUNT,wordStream.nextOffset=WORDS.length,maybeFetchMoreWords(),requestRun(),console.log("Custom RPC set:",customRpcUrl)):alert("Please enter a valid http(s) RPC URL.")}const STRUCT_W=4e3,STRUCT_H=5e3,STRUCT_ASPECT=.8;let customRenderWidth=null,customRenderHeight=null,lastGoodWidth=1200,lastGoodHeight=1500,restartQueued=!1,blackFrameCount=0,lastProgressFrame=0,lastProgressPlacementIndex=0;const MAX_BLACK_FRAMES=90,MAX_STUCK_FRAMES=240;let renderLoopRunning=!1;function requestRun(){renderLoopRunning||(renderLoopRunning=!0,requestAnimationFrame(run))}const GRAIN_SEED=parseInt(HASH.slice(2,10),16)/4294967295,settings={aspect:.8,washStrength:R.range(.1,.8),smudgeChance:R.range(.1,.24),textureAmount:R.range(.025,.08),pauseFrames:0,revealFrames:2,revealSpeed:1,backgroundWashChance:.01,backgroundWashMinWords:5,backgroundWashMaxWords:50,backgroundWashColor:palette.highlight,baseGrainAmount:.02,baseMottleAmount:8e-4,gridDefinitions:[...Array(5)].map((e,t)=>(co=t>0?Math.floor(R.range(70,130)):Math.floor(R.range(45,65)),ro=Math.floor(1.25*co),{name:t.toString(),cols:co,rows:ro,rotation:R.g()/25-.02,scale:1,offsetX:0,offsetY:0,letterScale:.8})),showReference:!1};function shuffled(e){const t=[...e];for(let e=t.length-1;e>0;e--){const r=R.int(0,e);[t[e],t[r]]=[t[r],t[e]]}return t}const view=document.getElementById("view"),ref=document.getElementById("ref"),refCtx=ref.getContext("2d",{alpha:!1});let gl,vertexBuffer,washProgram,screenProgram,refTexture,width=0,height=0,dpr=1,frameBuffers=[],frameBufferId=0,resizeQueued=!1,isResizing=!1;const MIN_GL_SIZE=2,state={frame:0,grids:[],placements:[],activePlacementIndex:0},vertexShader="\n in vec3 pos;\n out vec2 vUv;\n\n void main() {\n gl_Position = vec4(pos, 1.0);\n vUv = (pos.xy + 1.0) * 0.5;\n }\n",washShader="\n uniform sampler2D previousFrame;\n uniform sampler2D referenceMask;\n uniform float frame;\n uniform float dirx;\n uniform float diry;\n uniform float washStrength;\n uniform float smudgeChance;\n uniform float textureAmount;\n uniform vec4 bgColor;\n uniform vec4 inkColor;\n uniform vec4 highlightColor;\n\n uniform vec2 resolution;\n uniform float grainSeed;\n uniform float baseGrainAmount;\n uniform float baseMottleAmount;\n\n in vec2 vUv;\n out vec4 col;\n\n vec3 random3(vec3 c) {\n float j = 4096.0 * sin(dot(c, vec3(17.0, 59.4, 15.0)));\n vec3 r;\n r.z = fract(512.0 * j);\n j *= 0.125;\n r.x = fract(512.0 * j);\n j *= 0.125;\n r.y = fract(512.0 * j);\n return r - 0.5;\n }\n\n const float F3 = 0.3333333;\n const float G3 = 0.1666667;\n\n float simplex3(vec3 p) {\n vec3 s = floor(p + dot(p, vec3(F3)));\n vec3 x = p - s + dot(s, vec3(G3));\n vec3 e = step(vec3(0.0), x - x.yzx);\n vec3 i1 = e * (1.0 - e.zxy);\n vec3 i2 = 1.0 - e.zxy * (1.0 - e);\n vec3 x1 = x - i1 + G3;\n vec3 x2 = x - i2 + 2.0 * G3;\n vec3 x3 = x - 1.0 + 3.0 * G3;\n vec4 w, d;\n w.x = dot(x, x);\n w.y = dot(x1, x1);\n w.z = dot(x2, x2);\n w.w = dot(x3, x3);\n w = max(0.6 - w, 0.0);\n d.x = dot(random3(s), x);\n d.y = dot(random3(s + i1), x1);\n d.z = dot(random3(s + i2), x2);\n d.w = dot(random3(s + 1.0), x3);\n w *= w;\n w *= w;\n d *= w;\n return dot(d, vec4(52.0));\n }\n\n float hash12(vec2 p) {\n vec3 p3 = fract(vec3(p.xyx) * 0.1031);\n p3 += dot(p3, p3.yzx + 33.33 + grainSeed * 17.17);\n return fract((p3.x + p3.y) * p3.z);\n }\n\n void main() {\n vec4 ref = texture(referenceMask, vUv);\n vec4 prev = texture(previousFrame, vUv);\n\n float grainA = simplex3(vec3(vUv.x * 380.0 + frame * 0.011, vUv.y * 380.0 - frame * 0.013, 11.0));\n float grainB = simplex3(vec3(vUv.x * 7500.0, vUv.y * 7500.0, frame * 0.018));\n\n vec4 texturedBg = bgColor + vec4(vec3(grainB * textureAmount), 0.0);\n\n col = prev;\n\n // Only bake paper grain into the very first rendered frame.\n // After that it becomes part of previousFrame.\n if (frame < 0.5) {\n vec2 px = gl_FragCoord.xy;\n\n float fine = hash12(px) - 0.5;\n\n float fine2 = hash12(px * 0.5 + 91.7) - 0.5;\n float mottle = simplex3(vec3(\n vUv.x * 95.0 + grainSeed * 13.0,\n vUv.y * 95.0 - grainSeed * 9.0,\n 4.0\n ));\n\n float paper =\n fine * baseGrainAmount +\n fine2 * baseGrainAmount * 0.45 +\n mottle * baseMottleAmount;\n\n col.rgb += vec3(paper);\n }\n\n if (ref.g > 0.001) {\n float rnd = simplex3(vec3(\n (vUv.x + frame / 100.0) * 5000.0,\n (vUv.y - frame / 100.0) * 50.0,\n grainSeed * 100000.0\n ));\n\n vec4 textureBG = mix(\n bgColor,\n vec4(\n bgColor.rgb - vec3(\n simplex3(vec3(\n (vUv.x + frame / 1000.0) * 500.0,\n (vUv.y - frame / 1000.0) * 500.0,\n grainSeed * 100000.0\n )) / 80.\n ),\n 1.0\n ),\n simplex3(vec3(\n (vUv.x + frame / 1000.0) * 5.0,\n (vUv.y - frame / 1000.0) / 4.0,\n grainSeed * 100000.0\n ))\n );\n\n // This is the core wash behavior from the second project:\n // replace/scratch toward textured background, instead of dragging black blocks.\n col = mix(\n textureBG,\n // vec4(1.,0.,0.,1.),\n // bgColor,\n prev,\n simplex3(vec3(\n (vUv.x + frame / 100.0) * 5000.0,\n (vUv.y - frame / 100.0) * 5000.0,\n grainSeed * 100000.0\n ))*4.\n );\n\n // Directional smudge, but only sometimes.\n if (rnd < smudgeChance) {\n col = mix(\n texture(previousFrame, vec2(\n vUv.x + 0.003 * dirx,\n vUv.y + 0.003 * diry\n )),\n textureBG,\n rnd\n );\n }\n\n // Let the green mask control strength.\n prev = bgColor;\n col = mix(prev, col, ref.g * washStrength);\n }\n\n if (ref.b > 0.01) {\n float paintMask = ref.b;\n\n float roughA = simplex3(vec3(\n vUv.x * 900.0,\n vUv.y * 900.0,\n frame * 0.012\n ));\n\n float roughB = simplex3(vec3(\n vUv.x * 2200.0,\n vUv.y * 2200.0,\n 19.0\n ));\n\n float brokenMask = paintMask;\n brokenMask *= smoothstep(-0.45, 0.55, roughA);\n brokenMask *= 0.72 + roughB * 0.28;\n\n vec4 noisyPaint = highlightColor;\n noisyPaint.rgb += vec3(roughB * 0.10 + roughA * 0.035);\n\n vec2 dragUv = vUv + vec2(\n roughA * 0.0025,\n roughB * 0.0015\n );\n\n vec4 draggedSurface = texture(previousFrame, dragUv);\n\n vec4 paintOnSurface = mix(draggedSurface, noisyPaint, brokenMask);\n\n col = mix(col, paintOnSurface, brokenMask);\n }\n\n // Red = foreground ink. The incoming reference contains only the current word.\n if (ref.r > 0.01) {\n float smearNoise = simplex3(vec3(\n vUv.x * 900.0 + frame * 0.03,\n vUv.y * 220.0 - frame * 0.02,\n grainSeed * 9999.0\n ));\n\n float smearMask = ref.r * smoothstep(-0.35, 0.55, smearNoise);\n\n vec2 smearUv = vUv + vec2(\n -0.006 * dirx,\n 0.002 * diry\n );\n\n vec4 draggedInk = texture(previousFrame, smearUv);\n\n col = mix(col, draggedInk, smearMask * 0.65);\n\n vec4 brokenInk = inkColor;\n brokenInk.rgb += vec3(smearNoise * 0.16);\n\n col = mix(col, brokenInk, ref.r);\n }\n }\n",screenShader="\n uniform sampler2D buffer;\n in vec2 vUv;\n out vec4 col;\n\n void main() {\n col = texture(buffer, vec2(vUv.x, 1.0 - vUv.y));\n }\n";async function maybeFetchMoreWords(){if(!wordStream.fetching&&!wordStream.done&&!wordStream.failed)if(RPC_URLS.length){wordStream.fetching=!0;try{const e=await fetchNotesSlice(wordStream.nextOffset,FETCH_BATCH_SIZE);if(!e.length)return void(wordStream.done=!0);for(const t of e)WORDS.push(t),addWordPlacement(t);wordStream.nextOffset+=e.length,wordStream.nextOffset>=WORD_COUNT&&(wordStream.done=!0)}catch(e){console.warn("RPC word fetch failed:",e),wordStream.failed=!0}finally{wordStream.fetching=!1}}else wordStream.failed=!0}async function fetchNotesSlice(e,t){let r=null;for(const n of getRpcUrls())try{return await fetchNotesSliceFromRpc(n,TOKEN_ID,e,t)}catch(e){r=e,console.warn("RPC failed, trying next:",n,e)}throw r||new Error("No RPC worked")}const NOTES_SLICE_SELECTOR="0x91cf7995";async function fetchNotesSliceFromRpc(e,t,r,n){const o=NOTES_SLICE_SELECTOR+encodeUint256(t)+encodeUint256(r)+encodeUint256(n),a=await fetch(e,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({jsonrpc:"2.0",id:1,method:"eth_call",params:[{to:CONTRACT_ADDRESS,data:o},"latest"]})}),s=await a.json();if(s.error)throw new Error(s.error.message||"RPC error");return s.result&&"0x"!==s.result?decodeStringArray(s.result):[]}function encodeUint256(e){return BigInt(e).toString(16).padStart(64,"0")}function decodeStringArray(e){e=e.replace(/^0x/,"");const t=t=>{const r=2*t;return BigInt("0x"+e.slice(r,r+64))},r=(t,r)=>{const n=2*t;return e.slice(n,n+2*r)},n=Number(t(0)),o=Number(t(n)),a=[];for(let e=0;e<o;e++){const o=n+32+Number(t(n+32+32*e)),s=r(o+32,Number(t(o)));a.push(hexToUtf8(s))}return a}function hexToUtf8(e){const t=[];for(let r=0;r<e.length;r+=2)t.push(parseInt(e.slice(r,r+2),16));return(new TextDecoder).decode(new Uint8Array(t)).replace(/\0/g,"").trim()}function varyColor(e,t=.01){return[Math.max(0,Math.min(1,e[0]+R.range(-t,t))),Math.max(0,Math.min(1,e[1]+R.range(-t,t))),Math.max(0,Math.min(1,e[2]+R.range(-t,t))),e[3]??1]}function init(){if(gl=view.getContext("webgl2",{alpha:!1,antialias:!1,preserveDrawingBuffer:!0}),!gl)return void(document.body.innerHTML="WebGL2 is required.");vertexBuffer=createVertexBuffer(),washProgram=createProgram(vertexShader,washShader),screenProgram=createProgram(vertexShader,screenShader),createGrids(),createWordPlacements(),window.addEventListener("resize",requestResize),window.addEventListener("keydown",handleKey),view.addEventListener("webglcontextlost",e=>{e.preventDefault(),console.warn("WebGL context lost")},!1),view.addEventListener("webglcontextrestored",()=>{console.warn("WebGL context restored, rebuilding"),hardRebuild()},!1);new ResizeObserver(()=>requestResize()).observe(document.body),resize(),requestRun()}function resetRandom(){R=new Random(HASH)}function requestResize(){resizeQueued||(resizeQueued=!0,requestAnimationFrame(()=>{resizeQueued=!1,resize()}))}function resetWordsToDefault(){WORDS.length=0,WORDS.push(...INITIAL_WORDS),wordStream.fetching=!1,wordStream.done=WORDS.length>=WORD_COUNT,wordStream.failed=!1,wordStream.nextOffset=WORDS.length}let lastRenderedPixelCount=0;function restartAfterResize(){resetWordsToDefault(),resetRandom(),state.frame=0,state.activePlacementIndex=0,createGrids(),createWordPlacements(),drawBaseReference(),refTexture&&gl.deleteTexture(refTexture),refTexture=createTexture(width,height,ref),resetFrameBuffers(),window.__RESIDUAL_NOTES_RENDERED__=!1,blackFrameCount=0,lastProgressFrame=0,lastRenderedPixelCount=width*height,requestRun()}let renderW=null,renderH=null;function resize(){const e=1*Math.floor(window.innerWidth||document.documentElement.clientWidth||0),t=1*Math.floor(window.innerHeight||document.documentElement.clientHeight||0);if(e<20||t<20)return void requestAnimationFrame(requestResize);let r,n;e/t>settings.aspect?(n=t,r=t*settings.aspect):(r=e,n=e/settings.aspect),dpr=Math.max(1,window.devicePixelRatio||1);const o=renderW??Math.max(20,Math.round(r*dpr)),a=renderH??Math.max(20,Math.round(n*dpr));if(!(o===width&&a===height)){if(width>0&&height>0&&!(o*a>width*height))return view.style.width=`${r}px`,void(view.style.height=`${n}px`);isResizing=!0,width=o,height=a,view.width=width,view.height=height,view.style.display="block",ref.width=width,ref.height=height,ref.style.display=settings.showReference?"block":"none",restartAfterResize(),isResizing=!1}}function setCustomRenderSize(){const e=prompt("Render width in pixels:",width);if(!e)return;const t=Math.max(100,Math.floor(Number(e)));Number.isFinite(t)&&(renderW=t,renderH=Math.round(renderW/settings.aspect),resize())}function useStructureSpace(){refCtx.setTransform(width/4e3,0,0,height/5e3,0,0)}function resetFrameBuffers(){for(const e of frameBuffers)gl.deleteFramebuffer(e.buffer),gl.deleteTexture(e.texture);frameBuffers=[createFrameBuffer(width,height,ref),createFrameBuffer(width,height,null)],frameBufferId=0}function queueHardRebuild(e="unknown"){restartQueued||(restartQueued=!0,console.warn("Queueing hard rebuild:",e),requestAnimationFrame(()=>{restartQueued=!1,hardRebuild(e)}))}function hardRebuild(e="unknown"){if(console.warn("Hard rebuild:",e),gl&&!gl.isContextLost())try{if(resize(),width<MIN_GL_SIZE||height<MIN_GL_SIZE)return;restartAfterResize(),blackFrameCount=0,lastProgressFrame=state.frame,window.__RESIDUAL_NOTES_RENDERED__=!1}catch(e){console.warn("Hard rebuild failed:",e)}}function assertFramebufferHealthy(e=""){const t=gl.checkFramebufferStatus(gl.FRAMEBUFFER);return t===gl.FRAMEBUFFER_COMPLETE||(queueHardRebuild(`bad framebuffer ${e}: ${t}`),!1)}function drawBaseReference(){useStructureSpace(),refCtx.fillStyle=rgb(palette.bg),refCtx.fillRect(0,0,4e3,5e3),refCtx.fillStyle=rgb(palette.grid);const e=Math.floor(settings.gridDefinitions[0].cols),t=Math.floor(settings.gridDefinitions[0].rows);for(let t=2;t<e-2;t++)refCtx.fillRect(4e3/e*t,0,1,5e3);for(let e=2;e<t-2;e++)refCtx.fillRect(0,5e3/t*e,4e3,1)}function createGrids(){state.grids=settings.gridDefinitions.map((e,t)=>({id:t,name:e.name||`grid ${t}`,cols:Math.floor(e.cols),rows:Math.floor(e.rows),rotation:e.rotation||0,scale:e.scale||1,offsetX:e.offsetX||0,offsetY:e.offsetY||0,letterScale:e.letterScale||.8,occupied:null}))}function createWordPlacements(){state.placements=[];let e=R.int(settings.backgroundWashMinWords,settings.backgroundWashMaxWords);for(const t of WORDS)addWordPlacement(t),e--,e<=0&&R.chance(settings.backgroundWashChance)&&(addBackgroundWashPlacement(),e=R.int(settings.backgroundWashMinWords,settings.backgroundWashMaxWords))}function addWordPlacement(e){if(!e||!String(e).trim())return!1;const t=String(e).toUpperCase(),r=tryCreateWordPlacement(t)||tryCreateWordPlacement(t)||tryCreateWordPlacement(t);return!!r&&(state.placements.push(r),!0)}function addBackgroundWashPlacement(){state.placements.push({type:"backgroundWash",color:R.chance(.15)?palette.highlight:darkenedBgColor(.1),dirx:R.range(-1,1),diry:R.range(-1,1),washStrength:R.range(.03,.16),smudgeChance:R.range(.1,.32),x:4e3*R.range(-.08,.85),y:5e3*R.range(-.08,.85),w:4e3*R.range(.18,.55),h:5e3*R.range(.12,.38),seed:9999*R.g(),alpha:R.range(.02,.175),dripChance:R.range(.08,.28),force:1})}function tryCreateWordPlacement(e){for(let t=0;t<80;t++){const t=R.pick(state.grids),r=R.pick(["right","down","right","down","right","down","right","down","right","down","right","down","right","down","diagDown","diagUp"]),n=randomStartForTextBlock(t,e,r),o=textBlockCells(n.x,n.y,e,r,t);if(cellsFit(t,o))return{word:e,grid:t,direction:r,cells:o,color:varyColor(pickInkForWord(),.05),dirx:R.range(-2,2),diry:R.range(-2,2),washSeed:R.g(),washStrength:R.range(.05,.35),smudgeChance:R.range(.1,.32),washPad:R.range(.04,.2),washGaps:0,washStampCount:R.int(1,6),circle:R.chance(.065),underline:R.chance(.05),strikethrough:R.chance(.05),lettergrid:R.chance(.01),square:R.chance(.01),cross:R.chance(.01),plus:R.chance(.005),force:1}}return null}function randomStartForTextBlock(e,t,r){const n=Math.min(String(t).length,"right"===r?e.cols:e.rows),o=R.int(0,e.cols-1),a=R.int(0,e.rows-1);return"right"===r?{x:Math.max(0,Math.min(e.cols-1,o-Math.floor(n*R.range(.25,.65)))),y:Math.max(0,Math.min(e.rows-1,a-R.int(0,2)))}:"down"===r?{x:Math.max(0,Math.min(e.cols-1,o-R.int(0,2))),y:Math.max(0,Math.min(e.rows-1,a-Math.floor(n*R.range(.25,.65))))}:{x:o,y:a}}function textBlockCells(e,t,r,n,o){if("diagDown"===n||"diagUp"===n)return diagonalTextCells(e,t,r,n);const a=String(r).split(/\s+/),s=[],i="right"===n?Math.max(1,o.cols-e):Math.max(1,o.rows-t);let l=0,f=0;for(const r of a){if(f+(f>0?1:0)+r.length>i&&(l++,f=0),"right"===n&&t+l>=o.rows)break;if("down"===n&&e+l>=o.cols)break;f>0&&(addTextCharCell(s,e,t,n,f,l," "),f++);for(let a=0;a<r.length&&(f>=i&&(l++,f=0),!("right"===n&&t+l>=o.rows))&&!("down"===n&&e+l>=o.cols);a++)addTextCharCell(s,e,t,n,f,l,r[a]),f++}return s.map((e,t)=>({...e,index:t}))}function addTextCharCell(e,t,r,n,o,a,s){"right"===n&&e.push({x:t+o,y:r+a,char:s}),"down"===n&&e.push({x:t+a,y:r+o,char:s})}function diagonalTextCells(e,t,r,n){const o=[];for(let a=0;a<r.length;a++){let s=e+a,i="diagDown"===n?t+a:t-a;o.push({x:s,y:i,char:r[a],index:a})}return o}function cellsFit(e,t){return t.every(t=>t.x>=0&&t.y>=0&&t.x<e.cols&&t.y<e.rows)}function pickInkForWord(){return weightedPick(palette.inks).color}function weightedPick(e){const t=e.reduce((e,t)=>e+t.weight,0);let r=R.g()*t;for(const t of e)if(r-=t.weight,r<=0)return t;return e[e.length-1]}function clearReferenceToBlack(){refCtx.setTransform(1,0,0,1,0,0),refCtx.fillStyle="black",refCtx.fillRect(0,0,width,height)}function drawPlacementReference(e,t){if("backgroundWash"===e.type)return void drawBackgroundWashReference(e,t);clearReferenceToBlack(),refCtx.save(),useStructureSpace(),applyGridTransform(e.grid);const r=Math.ceil(e.cells.length*t),n=e.cells.slice(0,r);drawWashForCells(e.grid,n,e.washPad,e),drawWordCells(e.grid,n,e),e.underline&&t>.72&&drawUnderline(e),e.circle&&t>.84&&drawCircleAroundWord(e),e.strikethrough&&t>.65&&drawStrikethrough(e),e.lettergrid&&t>.7&&drawGridAroundLetters(e,n),e.square&&t>.82&&drawSquareAroundWord(e),e.cross&&t>.78&&drawCrossThroughWord(e),e.plus&&t>.78&&drawPlusThroughWord(e),refCtx.restore()}function applyGridTransform(e){refCtx.translate(2e3+4e3*e.offsetX,2500+5e3*e.offsetY),refCtx.rotate(e.rotation),refCtx.scale(e.scale,e.scale),refCtx.translate(-2e3,-2500)}function drawWashForCells(e,t,r,n){const o=4e3/e.cols,a=5e3/e.rows;refCtx.save(),refCtx.fillStyle="rgb(0,255,0)";for(const e of t){const t=n.washStampCount??1;for(let s=0;s<t;s++){const t=1e3*n.washSeed+97*s;if(stable01(e.x,e.y,e.index+t)<n.washGaps)continue;const i=stable01(e.x,e.y,101+t),l=stable01(e.x,e.y,202+t),f=stableNoise(e.x,e.y,303+t)*o*.22,c=stableNoise(e.x,e.y,404+t)*a*.22,d=o*(.04+.14*i),g=a*(.04+.14*l),u=o*r,h=a*r;refCtx.fillRect(e.x*o+d-u+f,e.y*a+g-h+c,o-2*d+2*u,a-2*g+2*h)}}refCtx.restore()}function stable01(e,t,r){const n=43758.5453*Math.sin(12.9898*e+78.233*t+37.719*r);return n-Math.floor(n)}function drawWordCells(e,t,r){const n=4e3/e.cols,o=5e3/e.rows;refCtx.fillStyle="rgb(255,0,0)",refCtx.strokeStyle="rgb(255,0,0)",refCtx.lineWidth=Math.max(1,.09*Math.min(n,o)),refCtx.lineCap="round",refCtx.lineJoin="round";for(const e of t)drawLetterInCell(e.char,e.x*n,e.y*o,n,o,r,e.index)}function drawLetterInCell(e,t,r,n,o,a,s){if(" "===e)return;const i=Math.min(n,o)*RangedLetterScale(a,s),l=stableNoise(t,r,s+1)*n*.1,f=stableNoise(t,r,s+2)*o*.1,c=.05*stableNoise(t,r,s+3);refCtx.save(),refCtx.translate(t+.5*n+l,r+.54*o+f),refCtx.rotate(c),refCtx.font=`${i}px ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace`,refCtx.textAlign="center",refCtx.textBaseline="middle",refCtx.fillText(e,0,0),refCtx.restore()}function RangedLetterScale(e,t){return e.grid.letterScale}function darkenedBgColor(e=.1){return[Math.max(0,palette.bg[0]-e),Math.max(0,palette.bg[1]-e),Math.max(0,palette.bg[2]-e),palette.bg[3]??1]}function drawUnderline(e){const t=4e3/e.grid.cols,r=5e3/e.grid.rows,n=e.cells.filter(e=>" "!==e.char);if(!n.length)return;refCtx.save(),refCtx.strokeStyle="rgb(255,0,0)",refCtx.lineWidth=Math.max(.6,.08*Math.min(t,r)),refCtx.lineCap="round",refCtx.lineJoin="round";const o=n[0],a=n[n.length-1],s=o.x*t+.15*t,i=o.y*r+.84*r,l=a.x*t+.85*t,f=a.y*r+.84*r,c=l-s,d=f-i,g=Math.max(1e-4,Math.sqrt(c*c+d*d)),u=-d/g,h=c/g,x=.28*Math.min(t,r);refCtx.beginPath(),refCtx.moveTo(s+u*x,i+h*x),refCtx.lineTo(l+u*x+stableNoise(l,f,9)*t*.25,f+h*x+stableNoise(s,i,10)*r*.25),refCtx.stroke(),refCtx.restore()}function drawStrikethrough(e){const t=4e3/e.grid.cols,r=5e3/e.grid.rows,n=e.cells.filter(e=>" "!==e.char);if(!n.length)return;const o=n[0],a=n[n.length-1],s=o.x*t+.15*t,i=o.y*r+.5*r,l=a.x*t+.85*t,f=a.y*r+.5*r;refCtx.save(),refCtx.strokeStyle="rgb(255,0,0)",refCtx.lineWidth=Math.max(.6,.08*Math.min(t,r)),refCtx.lineCap="round",refCtx.lineJoin="round",refCtx.beginPath(),refCtx.moveTo(s+stableNoise(s,i,21)*t*.18,i+stableNoise(s,i,22)*r*.18),refCtx.lineTo(l+stableNoise(l,f,23)*t*.18,f+stableNoise(l,f,24)*r*.18),refCtx.stroke(),refCtx.restore()}function drawCircleAroundWord(e){const t=wordBox(e),r=.5*(t.x1+t.x2),n=.5*(t.y1+t.y2),o=.62*Math.abs(t.x2-t.x1)+4e3/e.grid.cols,a=.62*Math.abs(t.y2-t.y1)+5e3/e.grid.rows,s=.35*stableNoise(r,n,4),i=refCtx.lineWidth,l=refCtx.strokeStyle;refCtx.strokeStyle="rgb(255,0,0)",refCtx.lineCap="round";const f=stableNoise(r,n,999),c=1+Math.floor(5*f);for(let e=0;e<c;e++){const t=1e3+137*e,l=stableNoise(r,n,t+1),f=stableNoise(r,n,t+2),c=stableNoise(r,n,t+3),d=stableNoise(r,n,t+4),g=stableNoise(r,n,t+5),u=.94+.18*g,h=.18+.95*stableNoise(r,n,t+6),x=.35+.65*d,m=4e3*l*.006,C=5e3*f*.006,w=o*u*(1+.04*c),b=a*u*(1-.04*c),R=g*Math.PI*2,p=stableNoise(r,n,t+7)<.45?.55+.35*stableNoise(r,n,t+8):1,v=R+2*Math.PI*p;refCtx.save(),refCtx.globalAlpha*=x,refCtx.lineWidth=i*h,refCtx.beginPath(),refCtx.ellipse(r+m,n+C,w,b,s+.22*d,R,v),refCtx.stroke(),refCtx.restore()}refCtx.lineWidth=i,refCtx.strokeStyle=l}function drawGridAroundLetters(e,t){const r=4e3/e.grid.cols,n=5e3/e.grid.rows,o=t.filter(e=>" "!==e.char);if(o.length){refCtx.save(),refCtx.strokeStyle="rgb(255,0,0)",refCtx.lineWidth=Math.max(.5,.045*Math.min(r,n)),refCtx.lineCap="square",refCtx.lineJoin="miter";for(const t of o){const o=t.x*r,a=t.y*n,s=.025*Math.min(r,n),i=t.index+1e3*e.washSeed;refCtx.beginPath(),refCtx.rect(o+stableNoise(t.x,t.y,i+1)*s,a+stableNoise(t.x,t.y,i+2)*s,r+stableNoise(t.x,t.y,i+3)*s,n+stableNoise(t.x,t.y,i+4)*s),refCtx.stroke()}refCtx.restore()}}function drawSquareAroundWord(e){const t=expandedWordBox(e,.22),r=Math.min(4e3/e.grid.cols,5e3/e.grid.rows);refCtx.save(),refCtx.strokeStyle="rgb(255,0,0)",refCtx.lineWidth=Math.max(.6,.08*r),refCtx.lineCap="round",refCtx.lineJoin="round";const n=.12*r;refCtx.beginPath(),refCtx.moveTo(t.x1+stableNoise(t.x1,t.y1,301)*n,t.y1+stableNoise(t.x1,t.y1,302)*n),refCtx.lineTo(t.x2+stableNoise(t.x2,t.y1,303)*n,t.y1+stableNoise(t.x2,t.y1,304)*n),refCtx.lineTo(t.x2+stableNoise(t.x2,t.y2,305)*n,t.y2+stableNoise(t.x2,t.y2,306)*n),refCtx.lineTo(t.x1+stableNoise(t.x1,t.y2,307)*n,t.y2+stableNoise(t.x1,t.y2,308)*n),refCtx.closePath(),refCtx.stroke(),refCtx.restore()}function drawCrossThroughWord(e){const t=expandedWordBox(e,.12),r=Math.min(4e3/e.grid.cols,5e3/e.grid.rows);refCtx.save(),refCtx.strokeStyle="rgb(255,0,0)",refCtx.lineWidth=Math.max(.6,.08*r),refCtx.lineCap="round",refCtx.lineJoin="round",drawNoisyLine(t.x1,t.y1,t.x2,t.y2,r,401),drawNoisyLine(t.x2,t.y1,t.x1,t.y2,r,411),refCtx.restore()}function drawPlusThroughWord(e){const t=expandedWordBox(e,.1),r=Math.min(4e3/e.grid.cols,5e3/e.grid.rows),n=.5*(t.x1+t.x2),o=.5*(t.y1+t.y2);refCtx.save(),refCtx.strokeStyle="rgb(255,0,0)",refCtx.lineWidth=Math.max(.6,.08*r),refCtx.lineCap="round",refCtx.lineJoin="round",drawNoisyLine(t.x1,o,t.x2,o,r,501),drawNoisyLine(n,t.y1,n,t.y2,r,511),refCtx.restore()}function drawBackgroundWashReference(e,t){clearReferenceToBlack(),refCtx.save(),useStructureSpace(),refCtx.globalAlpha=e.alpha*t,refCtx.fillStyle="rgb(0,0,255)",refCtx.strokeStyle="rgb(0,0,255)",refCtx.lineCap="round",refCtx.lineJoin="round";const r=e.y+.42*e.h;for(let n=0;n<44;n++){const o=n/Math.max(1,43),a=e.x+e.w*o+stableNoise(e.seed,n,11)*e.w*.025,s=Math.sin(o*Math.PI),i=r-e.h*(.25+.75*s+.45*stable01(e.seed,n,12)),l=r+e.h*(.15+.55*s+.75*stable01(e.seed,n,13)),f=e.w*(.018+.045*stable01(e.seed,n,14));drawVerticalPaintColumn(a,i,l,f,e.seed+91*n,t),stable01(e.seed,n,77)<e.dripChance&&drawPaintDrip(a+stableNoise(e.seed,n,21)*f,l-.05*e.h,e.h*(.35+1.4*stable01(e.seed,n,22)),e.seed+200*n)}for(let n=0;n<9;n++){const o=r+stableNoise(e.seed,n,301)*e.h*.45;refCtx.globalAlpha=e.alpha*t*.22,refCtx.lineWidth=e.h*(.025+.045*stable01(e.seed,n,302)),drawNoisyHorizontalStroke(e.x+stableNoise(e.seed,n,303)*e.w*.05,o,e.x+e.w+stableNoise(e.seed,n,304)*e.w*.05,o+stableNoise(e.seed,n,305)*e.h*.18,e.seed+400*n)}refCtx.restore()}function drawVerticalPaintColumn(e,t,r,n,o,a){refCtx.beginPath();for(let a=0;a<=12;a++){const s=t+(r-t)*(a/12),i=e-.5*n+stableNoise(o,a,31)*n*.75;0===a?refCtx.moveTo(i,s):refCtx.lineTo(i,s)}for(let a=12;a>=0;a--){const s=t+(r-t)*(a/12),i=e+.5*n+stableNoise(o,a,41)*n*.75;refCtx.lineTo(i,s)}refCtx.closePath(),refCtx.fill(),refCtx.save(),refCtx.globalAlpha*=.35;const s=2+Math.floor(5*stable01(o,1,55));for(let a=0;a<s;a++){const s=e+stableNoise(o,a,61)*n*.45;refCtx.lineWidth=n*(.08+.18*stable01(o,a,62)),refCtx.beginPath(),refCtx.moveTo(s,t+stableNoise(o,a,63)*n),refCtx.lineTo(s+stableNoise(o,a,64)*n*.45,r-stable01(o,a,65)*n),refCtx.stroke()}refCtx.restore(),refCtx.save(),refCtx.globalCompositeOperation="destination-out";for(let s=0;s<22;s++){const i=stable01(o,s,71)<.5?-1:1,l=t+stable01(o,s,72)*(r-t),f=e+i*n*(.3+.45*stable01(o,s,73));refCtx.globalAlpha=a*(.04+.14*stable01(o,s,74)),refCtx.beginPath(),refCtx.ellipse(f,l,n*(.15+.55*stable01(o,s,75)),n*(.25+1.25*stable01(o,s,76)),stableNoise(o,s,77),0,2*Math.PI),refCtx.fill()}refCtx.restore()}function drawNoisyHorizontalStroke(e,t,r,n,o){refCtx.beginPath();for(let a=0;a<=18;a++){const s=a/18,i=e+(r-e)*s,l=t+(n-t)*s+5e3*stableNoise(o,a,91)*.006;0===a?refCtx.moveTo(i,l):refCtx.lineTo(i,l)}refCtx.stroke()}function drawPainterlyBlob(e,t,r,n,o,a){const s=[];for(let a=0;a<28;a++){const i=a/28*Math.PI*2,l=1+.12*stableNoise(o,a,31)+.06*stableNoise(o,a,32)+.06*Math.sin(2*i+o)+.04*Math.sin(5*i+.37*o);s.push({x:e+Math.cos(i)*r*.5*l,y:t+Math.sin(i)*n*.5*l})}refCtx.beginPath();for(let e=0;e<s.length;e++){const t=s[(e-1+s.length)%s.length],r=s[e],n=s[(e+1)%s.length],o={x:.5*(t.x+r.x),y:.5*(t.y+r.y)},a={x:.5*(r.x+n.x),y:.5*(r.y+n.y)};0===e&&refCtx.moveTo(o.x,o.y),refCtx.quadraticCurveTo(r.x,r.y,a.x,a.y)}refCtx.closePath(),refCtx.fill(),refCtx.save(),refCtx.globalCompositeOperation="destination-out",refCtx.globalAlpha=.1*a;for(let s=0;s<160;s++){const i=stable01(o,s,41)*Math.PI*2,l=Math.sqrt(stable01(o,s,42)),f=Math.cos(i)*l,c=Math.sin(i)*l,d=e+f*r*.48,g=t+c*n*.48,u=Math.min(1,Math.sqrt(f*f+c*c)),h=Math.pow(u,2.2),x=r*(.004+.09*h*stable01(o,s,43)),m=n*(.003+.05*h*stable01(o,s,44));refCtx.globalAlpha=(.01+.18*h)*a,refCtx.beginPath(),refCtx.ellipse(d,g,x,m,stableNoise(o,s,45)*Math.PI,0,2*Math.PI),refCtx.fill()}refCtx.restore()}function drawPaintDrip(e,t,r,n){const o=.045*r;refCtx.beginPath(),refCtx.moveTo(e,t);for(let a=1;a<=5;a++){const s=a/5;refCtx.lineTo(e+stableNoise(n,a,51)*o,t+r*s)}refCtx.lineWidth=Math.max(1,4.8),refCtx.lineCap="round",refCtx.strokeStyle="rgb(0,0,255)",refCtx.stroke()}function drawNoisyLine(e,t,r,n,o,a){const s=.16*o;refCtx.beginPath(),refCtx.moveTo(e+stableNoise(e,t,a+1)*s,t+stableNoise(e,t,a+2)*s),refCtx.lineTo(r+stableNoise(r,n,a+3)*s,n+stableNoise(r,n,a+4)*s),refCtx.stroke()}function expandedWordBox(e,t=.15){const r=wordBox(e),n=4e3/e.grid.cols,o=5e3/e.grid.rows;return{x1:r.x1-n*t,y1:r.y1-o*t,x2:r.x2+n*t,y2:r.y2+o*t}}function wordBox(e){const t=4e3/e.grid.cols,r=5e3/e.grid.rows,n=e.cells.map(e=>e.x*t),o=e.cells.map(e=>e.y*r);return{x1:Math.min(...n),y1:Math.min(...o),x2:Math.max(...n)+t,y2:Math.max(...o)+r}}function stableNoise(e,t,r){const n=43758.5453*Math.sin(12.9898*e+78.233*t+37.719*r);return n-Math.floor(n)-.5}function run(){if(renderLoopRunning=!1,isResizing||width<MIN_GL_SIZE||height<MIN_GL_SIZE||!refTexture||frameBuffers.length<2)return void requestRun();maybeFetchMoreWords();const e=state.placements[state.activePlacementIndex];if(!e)return renderScreen(),state.frame%30==0&&sampleVisibleCanvasHealth(),void(window.__RESIDUAL_NOTES_RENDERED__||(window.__RESIDUAL_NOTES_RENDERED__=!0,window.dispatchEvent(new Event("residual-notes:rendered"))));const t=settings.pauseFrames+settings.revealFrames,r=state.frame%t;let n=0,o=!1;if(r<settings.pauseFrames)clearReferenceToBlack();else{const t=r-settings.pauseFrames;n=Math.min(1,(t+1)*settings.revealSpeed/settings.revealFrames),o=t>=settings.revealFrames-1,drawPlacementReference(e,n)}updateReferenceTexture(),renderWash(e),renderScreen(),(o||r===t-1)&&state.activePlacementIndex++,state.frame++,requestRun()}function renderWash(e){const t=frameBufferId,r=1^frameBufferId;frameBufferId=r,useProgram(washProgram),gl.bindFramebuffer(gl.FRAMEBUFFER,frameBuffers[r].buffer),assertFramebufferHealthy("renderWash")&&(gl.viewport(0,0,width,height),gl.clearColor(0,0,0,1),gl.clear(gl.COLOR_BUFFER_BIT),gl.activeTexture(gl.TEXTURE0),gl.bindTexture(gl.TEXTURE_2D,frameBuffers[t].texture),gl.uniform1i(gl.getUniformLocation(washProgram,"previousFrame"),0),gl.activeTexture(gl.TEXTURE1),gl.bindTexture(gl.TEXTURE_2D,refTexture),gl.uniform1i(gl.getUniformLocation(washProgram,"referenceMask"),1),gl.uniform1f(gl.getUniformLocation(washProgram,"frame"),state.frame),gl.uniform1f(gl.getUniformLocation(washProgram,"dirx"),e.dirx),gl.uniform1f(gl.getUniformLocation(washProgram,"diry"),e.diry),gl.uniform1f(gl.getUniformLocation(washProgram,"washStrength"),e.washStrength??settings.washStrength),gl.uniform1f(gl.getUniformLocation(washProgram,"smudgeChance"),e.smudgeChance??settings.smudgeChance),gl.uniform1f(gl.getUniformLocation(washProgram,"textureAmount"),settings.textureAmount),gl.uniform4fv(gl.getUniformLocation(washProgram,"bgColor"),palette.bg),gl.uniform4fv(gl.getUniformLocation(washProgram,"inkColor"),e.color),gl.uniform4fv(gl.getUniformLocation(washProgram,"highlightColor"),"backgroundWash"===e.type?e.color:palette.highlight),gl.uniform2f(gl.getUniformLocation(washProgram,"resolution"),width,height),gl.uniform1f(gl.getUniformLocation(washProgram,"grainSeed"),GRAIN_SEED),gl.uniform1f(gl.getUniformLocation(washProgram,"baseGrainAmount"),settings.baseGrainAmount),gl.uniform1f(gl.getUniformLocation(washProgram,"baseMottleAmount"),settings.baseMottleAmount),gl.drawArrays(gl.TRIANGLE_STRIP,0,4))}function sampleVisibleCanvasHealth(){if(!gl||gl.isContextLost())return;const e=new Uint8Array(4);gl.bindFramebuffer(gl.FRAMEBUFFER,null),gl.readPixels(Math.floor(.5*width),Math.floor(.5*height),1,1,gl.RGBA,gl.UNSIGNED_BYTE,e);e[0]+e[1]+e[2]<8&&state.frame>20?blackFrameCount++:blackFrameCount=0,blackFrameCount>90&&queueHardRebuild("visible canvas stayed black"),state.activePlacementIndex!==lastProgressPlacementIndex&&(lastProgressPlacementIndex=state.activePlacementIndex,lastProgressFrame=state.frame);state.activePlacementIndex>0&&state.activePlacementIndex<state.placements.length&&state.frame-lastProgressFrame>240&&queueHardRebuild("render loop appears stuck")}function renderScreen(){useProgram(screenProgram),gl.bindFramebuffer(gl.FRAMEBUFFER,null),gl.viewport(0,0,width,height),gl.clearColor(0,0,0,1),gl.clear(gl.COLOR_BUFFER_BIT),gl.activeTexture(gl.TEXTURE0),gl.bindTexture(gl.TEXTURE_2D,frameBuffers[frameBufferId].texture),gl.uniform1i(gl.getUniformLocation(screenProgram,"buffer"),0),gl.drawArrays(gl.TRIANGLE_STRIP,0,4)}function useProgram(e){gl.useProgram(e);const t=gl.getAttribLocation(e,"pos");gl.enableVertexAttribArray(t),gl.bindBuffer(gl.ARRAY_BUFFER,vertexBuffer),gl.vertexAttribPointer(t,3,gl.FLOAT,!1,0,0)}function createProgram(e,t){const r=gl.createProgram(),n=createShader(`#version 300 es\n${e}`,gl.VERTEX_SHADER),o=createShader(`#version 300 es\nprecision highp float;\n${t}`,gl.FRAGMENT_SHADER);return gl.attachShader(r,n),gl.attachShader(r,o),gl.linkProgram(r),gl.getProgramParameter(r,gl.LINK_STATUS)||console.error(gl.getProgramInfoLog(r)),r}function createShader(e,t){const r=gl.createShader(t);return gl.shaderSource(r,e),gl.compileShader(r),gl.getShaderParameter(r,gl.COMPILE_STATUS)||console.error(gl.getShaderInfoLog(r)),r}function createVertexBuffer(){const e=gl.createBuffer();return gl.bindBuffer(gl.ARRAY_BUFFER,e),gl.bufferData(gl.ARRAY_BUFFER,new Float32Array([-1,1,0,-1,-1,0,1,1,0,1,-1,0]),gl.STATIC_DRAW),e}function createFrameBuffer(e,t,r=null){e=Math.max(MIN_GL_SIZE,Math.floor(e)),t=Math.max(MIN_GL_SIZE,Math.floor(t));const n=gl.createFramebuffer(),o=createTexture(e,t,r);gl.bindFramebuffer(gl.FRAMEBUFFER,n),gl.framebufferTexture2D(gl.FRAMEBUFFER,gl.COLOR_ATTACHMENT0,gl.TEXTURE_2D,o,0);const a=gl.checkFramebufferStatus(gl.FRAMEBUFFER);return a!==gl.FRAMEBUFFER_COMPLETE&&console.warn("Framebuffer incomplete:",a,e,t),gl.bindFramebuffer(gl.FRAMEBUFFER,null),{buffer:n,texture:o}}function createTexture(e,t,r=null){e=Math.max(MIN_GL_SIZE,Math.floor(e)),t=Math.max(MIN_GL_SIZE,Math.floor(t));const n=gl.createTexture();return gl.bindTexture(gl.TEXTURE_2D,n),gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.NEAREST),gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.NEAREST),gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_S,gl.CLAMP_TO_EDGE),gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_T,gl.CLAMP_TO_EDGE),r&&r.width>0&&r.height>0?gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,gl.RGBA,gl.UNSIGNED_BYTE,r):gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,e,t,0,gl.RGBA,gl.UNSIGNED_BYTE,null),n}function updateReferenceTexture(){refTexture&&(!ref||ref.width<MIN_GL_SIZE||ref.height<MIN_GL_SIZE||(gl.bindTexture(gl.TEXTURE_2D,refTexture),gl.texSubImage2D(gl.TEXTURE_2D,0,0,0,gl.RGBA,gl.UNSIGNED_BYTE,ref)))}function rgb(e){return`rgb(${Math.floor(255*e[0])}, ${Math.floor(255*e[1])}, ${Math.floor(255*e[2])})`}function clamp255(e){return Math.max(0,Math.min(255,e))}function handleKey(e){"s"===e.key&&savePNG(),"m"===e.key&&(settings.showReference=!settings.showReference,ref.style.display=settings.showReference?"block":"none"),"c"===e.key&&setCustomRenderSize(),"p"===e.key.toLowerCase()&&setCustomRpcUrl()}function savePNG(){renderScreen();const e=document.createElement("a");e.download=`residual-notes-${HASH.slice(2,10)}-${width}x${height}.png`,e.href=view.toDataURL("image/png"),e.click()}function restart(){restartAfterResize()}init();
XOXObg=.93 .93 .93 1|grid=.99 .99 .99 1|highlight=.44 .58 .88 1|inks=.91 .75 .25 1 6;.52 .55 .43 1 2;.39 .39 .39 1 20xe16591fa56c776d2dc429b1c891a71ff2b3ebd4b0393132301c6d1119ef23a5c#EDEDED#EDBB44
function parsePalette(e){const t=Object.fromEntries(e.split("|").map(e=>{const t=e.indexOf("=");return[e.slice(0,t),e.slice(t+1)]})),r=e=>e.trim().split(/\s+/).map(Number);return{bg:r(t.bg),grid:r(t.grid),highlight:r(t.highlight),inks:t.inks.split(";").map(e=>{const t=r(e);return{color:t.slice(0,4),weight:t[4]}})}}palette=parsePalette(palette);class Random{constructor(e){this.useA=!1,this.prngA=this.sfc32(e.slice(2,34)),this.prngB=this.sfc32(e.slice(34,66));for(let e=0;e<1e5;e++)this.prngA(),this.prngB()}sfc32(e){let t=parseInt(e.slice(0,8),16),r=parseInt(e.slice(8,16),16),n=parseInt(e.slice(16,24),16),o=parseInt(e.slice(24,32),16);return function(){t|=0,r|=0,n|=0,o|=0;let e=(t+r|0)+o|0;return o=o+1|0,t=r^r>>>9,r=n+(n<<3)|0,n=n<<21|n>>>11,n=n+e|0,(e>>>0)/4294967296}}g(){return this.useA=!this.useA,this.useA?this.prngA():this.prngB()}range(e,t){return e+this.g()*(t-e)}int(e,t){return Math.floor(this.range(e,t+1))}pick(e){return e[Math.floor(this.g()*e.length)]}chance(e){return this.g()<e}}let R=new Random(HASH);const wordStream={fetching:!1,done:WORDS.length>=WORD_COUNT,failed:!1,nextOffset:WORDS.length};let customRpcUrl="";function getRpcUrls(){return customRpcUrl?[customRpcUrl,...RPC_URLS.filter(e=>e!==customRpcUrl)]:RPC_URLS}function setCustomRpcUrl(){const e=prompt("Custom RPC URL:",customRpcUrl||"https://...");if(!e)return;const t=e.trim();/^https?:\/\//i.test(t)?(customRpcUrl=t,wordStream.fetching=!1,wordStream.failed=!1,wordStream.done=WORDS.length>=WORD_COUNT,wordStream.nextOffset=WORDS.length,maybeFetchMoreWords(),requestRun(),console.log("Custom RPC set:",customRpcUrl)):alert("Please enter a valid http(s) RPC URL.")}const STRUCT_W=4e3,STRUCT_H=5e3,STRUCT_ASPECT=.8;let customRenderWidth=null,customRenderHeight=null,lastGoodWidth=1200,lastGoodHeight=1500,restartQueued=!1,blackFrameCount=0,lastProgressFrame=0;const MAX_BLACK_FRAMES=90,MAX_STUCK_FRAMES=240;let renderLoopRunning=!1;function requestRun(){renderLoopRunning||(renderLoopRunning=!0,requestAnimationFrame(run))}const GRAIN_SEED=parseInt(HASH.slice(2,10),16)/4294967295,settings={aspect:.8,washStrength:R.range(.1,.8),smudgeChance:R.range(.1,.24),textureAmount:R.range(.025,.08),pauseFrames:0,revealFrames:2,revealSpeed:1,backgroundWashChance:.01,backgroundWashMinWords:5,backgroundWashMaxWords:50,backgroundWashColor:palette.highlight,baseGrainAmount:.02,baseMottleAmount:8e-4,gridDefinitions:[...Array(5)].map((e,t)=>(co=t>0?Math.floor(R.range(70,130)):Math.floor(R.range(45,65)),ro=Math.floor(1.25*co),{name:t.toString(),cols:co,rows:ro,rotation:R.g()/25-.02,scale:1,offsetX:0,offsetY:0,letterScale:.8})),showReference:!1};function shuffled(e){const t=[...e];for(let e=t.length-1;e>0;e--){const r=R.int(0,e);[t[e],t[r]]=[t[r],t[e]]}return t}const view=document.getElementById("view"),ref=document.getElementById("ref"),refCtx=ref.getContext("2d",{alpha:!1});let gl,vertexBuffer,washProgram,screenProgram,refTexture,width=0,height=0,dpr=1,frameBuffers=[],frameBufferId=0,resizeQueued=!1,isResizing=!1;const MIN_GL_SIZE=2,state={frame:0,grids:[],placements:[],activePlacementIndex:0},vertexShader="\n in vec3 pos;\n out vec2 vUv;\n\n void main() {\n gl_Position = vec4(pos, 1.0);\n vUv = (pos.xy + 1.0) * 0.5;\n }\n",washShader="\n uniform sampler2D previousFrame;\n uniform sampler2D referenceMask;\n uniform float frame;\n uniform float dirx;\n uniform float diry;\n uniform float washStrength;\n uniform float smudgeChance;\n uniform float textureAmount;\n uniform vec4 bgColor;\n uniform vec4 inkColor;\n uniform vec4 highlightColor;\n\n uniform vec2 resolution;\n uniform float grainSeed;\n uniform float baseGrainAmount;\n uniform float baseMottleAmount;\n\n in vec2 vUv;\n out vec4 col;\n\n vec3 random3(vec3 c) {\n float j = 4096.0 * sin(dot(c, vec3(17.0, 59.4, 15.0)));\n vec3 r;\n r.z = fract(512.0 * j);\n j *= 0.125;\n r.x = fract(512.0 * j);\n j *= 0.125;\n r.y = fract(512.0 * j);\n return r - 0.5;\n }\n\n const float F3 = 0.3333333;\n const float G3 = 0.1666667;\n\n float simplex3(vec3 p) {\n vec3 s = floor(p + dot(p, vec3(F3)));\n vec3 x = p - s + dot(s, vec3(G3));\n vec3 e = step(vec3(0.0), x - x.yzx);\n vec3 i1 = e * (1.0 - e.zxy);\n vec3 i2 = 1.0 - e.zxy * (1.0 - e);\n vec3 x1 = x - i1 + G3;\n vec3 x2 = x - i2 + 2.0 * G3;\n vec3 x3 = x - 1.0 + 3.0 * G3;\n vec4 w, d;\n w.x = dot(x, x);\n w.y = dot(x1, x1);\n w.z = dot(x2, x2);\n w.w = dot(x3, x3);\n w = max(0.6 - w, 0.0);\n d.x = dot(random3(s), x);\n d.y = dot(random3(s + i1), x1);\n d.z = dot(random3(s + i2), x2);\n d.w = dot(random3(s + 1.0), x3);\n w *= w;\n w *= w;\n d *= w;\n return dot(d, vec4(52.0));\n }\n\n float hash12(vec2 p) {\n vec3 p3 = fract(vec3(p.xyx) * 0.1031);\n p3 += dot(p3, p3.yzx + 33.33 + grainSeed * 17.17);\n return fract((p3.x + p3.y) * p3.z);\n }\n\n void main() {\n vec4 ref = texture(referenceMask, vUv);\n vec4 prev = texture(previousFrame, vUv);\n\n float grainA = simplex3(vec3(vUv.x * 380.0 + frame * 0.011, vUv.y * 380.0 - frame * 0.013, 11.0));\n float grainB = simplex3(vec3(vUv.x * 7500.0, vUv.y * 7500.0, frame * 0.018));\n\n vec4 texturedBg = bgColor + vec4(vec3(grainB * textureAmount), 0.0);\n\n col = prev;\n\n // Only bake paper grain into the very first rendered frame.\n // After that it becomes part of previousFrame.\n if (frame < 0.5) {\n vec2 px = gl_FragCoord.xy;\n\n float fine = hash12(px) - 0.5;\n\n float fine2 = hash12(px * 0.5 + 91.7) - 0.5;\n float mottle = simplex3(vec3(\n vUv.x * 95.0 + grainSeed * 13.0,\n vUv.y * 95.0 - grainSeed * 9.0,\n 4.0\n ));\n\n float paper =\n fine * baseGrainAmount +\n fine2 * baseGrainAmount * 0.45 +\n mottle * baseMottleAmount;\n\n col.rgb += vec3(paper);\n }\n\n if (ref.g > 0.001) {\n float rnd = simplex3(vec3(\n (vUv.x + frame / 100.0) * 5000.0,\n (vUv.y - frame / 100.0) * 50.0,\n grainSeed * 100000.0\n ));\n\n vec4 textureBG = mix(\n bgColor,\n vec4(\n bgColor.rgb - vec3(\n simplex3(vec3(\n (vUv.x + frame / 1000.0) * 500.0,\n (vUv.y - frame / 1000.0) * 500.0,\n grainSeed * 100000.0\n )) / 80.\n ),\n 1.0\n ),\n simplex3(vec3(\n (vUv.x + frame / 1000.0) * 5.0,\n (vUv.y - frame / 1000.0) / 4.0,\n grainSeed * 100000.0\n ))\n );\n\n // This is the core wash behavior from the second project:\n // replace/scratch toward textured background, instead of dragging black blocks.\n col = mix(\n textureBG,\n // vec4(1.,0.,0.,1.),\n // bgColor,\n prev,\n simplex3(vec3(\n (vUv.x + frame / 100.0) * 5000.0,\n (vUv.y - frame / 100.0) * 5000.0,\n grainSeed * 100000.0\n ))*4.\n );\n\n // Directional smudge, but only sometimes.\n if (rnd < smudgeChance) {\n col = mix(\n texture(previousFrame, vec2(\n vUv.x + 0.003 * dirx,\n vUv.y + 0.003 * diry\n )),\n textureBG,\n rnd\n );\n }\n\n // Let the green mask control strength.\n prev = bgColor;\n col = mix(prev, col, ref.g * washStrength);\n }\n\n if (ref.b > 0.01) {\n float paintMask = ref.b;\n\n float roughA = simplex3(vec3(\n vUv.x * 900.0,\n vUv.y * 900.0,\n frame * 0.012\n ));\n\n float roughB = simplex3(vec3(\n vUv.x * 2200.0,\n vUv.y * 2200.0,\n 19.0\n ));\n\n float brokenMask = paintMask;\n brokenMask *= smoothstep(-0.45, 0.55, roughA);\n brokenMask *= 0.72 + roughB * 0.28;\n\n vec4 noisyPaint = highlightColor;\n noisyPaint.rgb += vec3(roughB * 0.10 + roughA * 0.035);\n\n vec2 dragUv = vUv + vec2(\n roughA * 0.0025,\n roughB * 0.0015\n );\n\n vec4 draggedSurface = texture(previousFrame, dragUv);\n\n vec4 paintOnSurface = mix(draggedSurface, noisyPaint, brokenMask);\n\n col = mix(col, paintOnSurface, brokenMask);\n }\n\n // Red = foreground ink. The incoming reference contains only the current word.\n if (ref.r > 0.01) {\n float smearNoise = simplex3(vec3(\n vUv.x * 900.0 + frame * 0.03,\n vUv.y * 220.0 - frame * 0.02,\n grainSeed * 9999.0\n ));\n\n float smearMask = ref.r * smoothstep(-0.35, 0.55, smearNoise);\n\n vec2 smearUv = vUv + vec2(\n -0.006 * dirx,\n 0.002 * diry\n );\n\n vec4 draggedInk = texture(previousFrame, smearUv);\n\n col = mix(col, draggedInk, smearMask * 0.65);\n\n vec4 brokenInk = inkColor;\n brokenInk.rgb += vec3(smearNoise * 0.16);\n\n col = mix(col, brokenInk, ref.r);\n }\n }\n",screenShader="\n uniform sampler2D buffer;\n in vec2 vUv;\n out vec4 col;\n\n void main() {\n col = texture(buffer, vec2(vUv.x, 1.0 - vUv.y));\n }\n";async function maybeFetchMoreWords(){if(!wordStream.fetching&&!wordStream.done&&!wordStream.failed)if(RPC_URLS.length){wordStream.fetching=!0;try{const e=await fetchNotesSlice(wordStream.nextOffset,FETCH_BATCH_SIZE);if(!e.length)return void(wordStream.done=!0);for(const t of e)WORDS.push(t),addWordPlacement(t);wordStream.nextOffset+=e.length,wordStream.nextOffset>=WORD_COUNT&&(wordStream.done=!0)}catch(e){console.warn("RPC word fetch failed:",e),wordStream.failed=!0}finally{wordStream.fetching=!1}}else wordStream.failed=!0}async function fetchNotesSlice(e,t){let r=null;for(const n of getRpcUrls())try{return await fetchNotesSliceFromRpc(n,TOKEN_ID,e,t)}catch(e){r=e,console.warn("RPC failed, trying next:",n,e)}throw r||new Error("No RPC worked")}const NOTES_SLICE_SELECTOR="0x91cf7995";async function fetchNotesSliceFromRpc(e,t,r,n){const o=NOTES_SLICE_SELECTOR+encodeUint256(t)+encodeUint256(r)+encodeUint256(n),a=await fetch(e,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({jsonrpc:"2.0",id:1,method:"eth_call",params:[{to:CONTRACT_ADDRESS,data:o},"latest"]})}),s=await a.json();if(s.error)throw new Error(s.error.message||"RPC error");return s.result&&"0x"!==s.result?decodeStringArray(s.result):[]}function encodeUint256(e){return BigInt(e).toString(16).padStart(64,"0")}function decodeStringArray(e){e=e.replace(/^0x/,"");const t=t=>{const r=2*t;return BigInt("0x"+e.slice(r,r+64))},r=(t,r)=>{const n=2*t;return e.slice(n,n+2*r)},n=Number(t(0)),o=Number(t(n)),a=[];for(let e=0;e<o;e++){const o=n+32+Number(t(n+32+32*e)),s=r(o+32,Number(t(o)));a.push(hexToUtf8(s))}return a}function hexToUtf8(e){const t=[];for(let r=0;r<e.length;r+=2)t.push(parseInt(e.slice(r,r+2),16));return(new TextDecoder).decode(new Uint8Array(t)).replace(/\0/g,"").trim()}function varyColor(e,t=.01){return[Math.max(0,Math.min(1,e[0]+R.range(-t,t))),Math.max(0,Math.min(1,e[1]+R.range(-t,t))),Math.max(0,Math.min(1,e[2]+R.range(-t,t))),e[3]??1]}function init(){if(gl=view.getContext("webgl2",{alpha:!1,antialias:!1,preserveDrawingBuffer:!0}),!gl)return void(document.body.innerHTML="WebGL2 is required.");vertexBuffer=createVertexBuffer(),washProgram=createProgram(vertexShader,washShader),screenProgram=createProgram(vertexShader,screenShader),createGrids(),createWordPlacements(),window.addEventListener("resize",requestResize),window.addEventListener("keydown",handleKey),view.addEventListener("webglcontextlost",e=>{e.preventDefault(),console.warn("WebGL context lost")},!1),view.addEventListener("webglcontextrestored",()=>{console.warn("WebGL context restored, rebuilding"),hardRebuild()},!1);new ResizeObserver(()=>requestResize()).observe(document.body),resize(),requestRun()}function resetRandom(){R=new Random(HASH)}function requestResize(){resizeQueued||(resizeQueued=!0,requestAnimationFrame(()=>{resizeQueued=!1,resize()}))}function resetWordsToDefault(){WORDS.length=0,WORDS.push(...INITIAL_WORDS),wordStream.fetching=!1,wordStream.done=WORDS.length>=WORD_COUNT,wordStream.failed=!1,wordStream.nextOffset=WORDS.length}let lastRenderedPixelCount=0;function restartAfterResize(){resetWordsToDefault(),resetRandom(),state.frame=0,state.activePlacementIndex=0,createGrids(),createWordPlacements(),drawBaseReference(),refTexture&&gl.deleteTexture(refTexture),refTexture=createTexture(width,height,ref),resetFrameBuffers(),window.__RESIDUAL_NOTES_RENDERED__=!1,blackFrameCount=0,lastProgressFrame=0,lastRenderedPixelCount=width*height,requestRun()}let renderW=null,renderH=null;function resize(){const e=1*Math.floor(window.innerWidth||document.documentElement.clientWidth||0),t=1*Math.floor(window.innerHeight||document.documentElement.clientHeight||0);if(e<20||t<20)return void requestAnimationFrame(requestResize);let r,n;e/t>settings.aspect?(n=t,r=t*settings.aspect):(r=e,n=e/settings.aspect),dpr=Math.max(1,window.devicePixelRatio||1);const o=renderW??Math.max(20,Math.round(r*dpr)),a=renderH??Math.max(20,Math.round(n*dpr));if(!(o===width&&a===height)){if(width>0&&height>0&&!(o*a>width*height))return view.style.width=`${r}px`,void(view.style.height=`${n}px`);isResizing=!0,width=o,height=a,view.width=width,view.height=height,view.style.display="block",ref.width=width,ref.height=height,ref.style.display=settings.showReference?"block":"none",restartAfterResize(),isResizing=!1}}function setCustomRenderSize(){const e=prompt("Render width in pixels:",width);if(!e)return;const t=Math.max(100,Math.floor(Number(e)));Number.isFinite(t)&&(renderW=t,renderH=Math.round(renderW/settings.aspect),resize())}function useStructureSpace(){refCtx.setTransform(width/4e3,0,0,height/5e3,0,0)}function resetFrameBuffers(){for(const e of frameBuffers)gl.deleteFramebuffer(e.buffer),gl.deleteTexture(e.texture);frameBuffers=[createFrameBuffer(width,height,ref),createFrameBuffer(width,height,null)],frameBufferId=0}function queueHardRebuild(e="unknown"){restartQueued||(restartQueued=!0,console.warn("Queueing hard rebuild:",e),requestAnimationFrame(()=>{restartQueued=!1,hardRebuild(e)}))}function hardRebuild(e="unknown"){if(console.warn("Hard rebuild:",e),gl&&!gl.isContextLost())try{if(resize(),width<MIN_GL_SIZE||height<MIN_GL_SIZE)return;restartAfterResize(),blackFrameCount=0,lastProgressFrame=state.frame,window.__RESIDUAL_NOTES_RENDERED__=!1}catch(e){console.warn("Hard rebuild failed:",e)}}function assertFramebufferHealthy(e=""){const t=gl.checkFramebufferStatus(gl.FRAMEBUFFER);return t===gl.FRAMEBUFFER_COMPLETE||(queueHardRebuild(`bad framebuffer ${e}: ${t}`),!1)}function drawBaseReference(){useStructureSpace(),refCtx.fillStyle=rgb(palette.bg),refCtx.fillRect(0,0,4e3,5e3),refCtx.fillStyle=rgb(palette.grid);const e=Math.floor(settings.gridDefinitions[0].cols),t=Math.floor(settings.gridDefinitions[0].rows);for(let t=2;t<e-2;t++)refCtx.fillRect(4e3/e*t,0,1,5e3);for(let e=2;e<t-2;e++)refCtx.fillRect(0,5e3/t*e,4e3,1)}function createGrids(){state.grids=settings.gridDefinitions.map((e,t)=>({id:t,name:e.name||`grid ${t}`,cols:Math.floor(e.cols),rows:Math.floor(e.rows),rotation:e.rotation||0,scale:e.scale||1,offsetX:e.offsetX||0,offsetY:e.offsetY||0,letterScale:e.letterScale||.8,occupied:null}))}function createWordPlacements(){state.placements=[];let e=R.int(settings.backgroundWashMinWords,settings.backgroundWashMaxWords);for(const t of WORDS)addWordPlacement(t),e--,e<=0&&R.chance(settings.backgroundWashChance)&&(addBackgroundWashPlacement(),e=R.int(settings.backgroundWashMinWords,settings.backgroundWashMaxWords))}function addWordPlacement(e){if(!e||!String(e).trim())return!1;const t=String(e).toUpperCase(),r=tryCreateWordPlacement(t)||tryCreateWordPlacement(t)||tryCreateWordPlacement(t);return!!r&&(state.placements.push(r),!0)}function addBackgroundWashPlacement(){state.placements.push({type:"backgroundWash",color:R.chance(.15)?palette.highlight:darkenedBgColor(.1),dirx:R.range(-1,1),diry:R.range(-1,1),washStrength:R.range(.03,.16),smudgeChance:R.range(.1,.32),x:4e3*R.range(-.08,.85),y:5e3*R.range(-.08,.85),w:4e3*R.range(.18,.55),h:5e3*R.range(.12,.38),seed:9999*R.g(),alpha:R.range(.02,.175),dripChance:R.range(.08,.28),force:1})}function tryCreateWordPlacement(e){for(let t=0;t<80;t++){const t=R.pick(state.grids),r=R.pick(["right","down","right","down","right","down","right","down","right","down","right","down","right","down","diagDown","diagUp"]),n=randomStartForTextBlock(t,e,r),o=textBlockCells(n.x,n.y,e,r,t);if(cellsFit(t,o))return{word:e,grid:t,direction:r,cells:o,color:varyColor(pickInkForWord(),.05),dirx:R.range(-2,2),diry:R.range(-2,2),washSeed:R.g(),washStrength:R.range(.05,.35),smudgeChance:R.range(.1,.32),washPad:R.range(.04,.2),washGaps:0,washStampCount:R.int(1,6),circle:R.chance(.065),underline:R.chance(.05),strikethrough:R.chance(.05),lettergrid:R.chance(.01),square:R.chance(.01),cross:R.chance(.01),plus:R.chance(.005),force:1}}return null}function randomStartForTextBlock(e,t,r){const n=Math.min(String(t).length,"right"===r?e.cols:e.rows),o=R.int(0,e.cols-1),a=R.int(0,e.rows-1);return"right"===r?{x:Math.max(0,Math.min(e.cols-1,o-Math.floor(n*R.range(.25,.65)))),y:Math.max(0,Math.min(e.rows-1,a-R.int(0,2)))}:"down"===r?{x:Math.max(0,Math.min(e.cols-1,o-R.int(0,2))),y:Math.max(0,Math.min(e.rows-1,a-Math.floor(n*R.range(.25,.65))))}:{x:o,y:a}}function textBlockCells(e,t,r,n,o){if("diagDown"===n||"diagUp"===n)return diagonalTextCells(e,t,r,n);const a=String(r).split(/\s+/),s=[],i="right"===n?Math.max(1,o.cols-e):Math.max(1,o.rows-t);let l=0,f=0;for(const r of a){if(f+(f>0?1:0)+r.length>i&&(l++,f=0),"right"===n&&t+l>=o.rows)break;if("down"===n&&e+l>=o.cols)break;f>0&&(addTextCharCell(s,e,t,n,f,l," "),f++);for(let a=0;a<r.length&&(f>=i&&(l++,f=0),!("right"===n&&t+l>=o.rows))&&!("down"===n&&e+l>=o.cols);a++)addTextCharCell(s,e,t,n,f,l,r[a]),f++}return s.map((e,t)=>({...e,index:t}))}function addTextCharCell(e,t,r,n,o,a,s){"right"===n&&e.push({x:t+o,y:r+a,char:s}),"down"===n&&e.push({x:t+a,y:r+o,char:s})}function diagonalTextCells(e,t,r,n){const o=[];for(let a=0;a<r.length;a++){let s=e+a,i="diagDown"===n?t+a:t-a;o.push({x:s,y:i,char:r[a],index:a})}return o}function cellsFit(e,t){return t.every(t=>t.x>=0&&t.y>=0&&t.x<e.cols&&t.y<e.rows)}function pickInkForWord(){return weightedPick(palette.inks).color}function weightedPick(e){const t=e.reduce((e,t)=>e+t.weight,0);let r=R.g()*t;for(const t of e)if(r-=t.weight,r<=0)return t;return e[e.length-1]}function clearReferenceToBlack(){refCtx.setTransform(1,0,0,1,0,0),refCtx.fillStyle="black",refCtx.fillRect(0,0,width,height)}function drawPlacementReference(e,t){if("backgroundWash"===e.type)return void drawBackgroundWashReference(e,t);clearReferenceToBlack(),refCtx.save(),useStructureSpace(),applyGridTransform(e.grid);const r=Math.ceil(e.cells.length*t),n=e.cells.slice(0,r);drawWashForCells(e.grid,n,e.washPad,e),drawWordCells(e.grid,n,e),e.underline&&t>.72&&drawUnderline(e),e.circle&&t>.84&&drawCircleAroundWord(e),e.strikethrough&&t>.65&&drawStrikethrough(e),e.lettergrid&&t>.7&&drawGridAroundLetters(e,n),e.square&&t>.82&&drawSquareAroundWord(e),e.cross&&t>.78&&drawCrossThroughWord(e),e.plus&&t>.78&&drawPlusThroughWord(e),refCtx.restore()}function applyGridTransform(e){refCtx.translate(2e3+4e3*e.offsetX,2500+5e3*e.offsetY),refCtx.rotate(e.rotation),refCtx.scale(e.scale,e.scale),refCtx.translate(-2e3,-2500)}function drawWashForCells(e,t,r,n){const o=4e3/e.cols,a=5e3/e.rows;refCtx.save(),refCtx.fillStyle="rgb(0,255,0)";for(const e of t){const t=n.washStampCount??1;for(let s=0;s<t;s++){const t=1e3*n.washSeed+97*s;if(stable01(e.x,e.y,e.index+t)<n.washGaps)continue;const i=stable01(e.x,e.y,101+t),l=stable01(e.x,e.y,202+t),f=stableNoise(e.x,e.y,303+t)*o*.22,c=stableNoise(e.x,e.y,404+t)*a*.22,d=o*(.04+.14*i),g=a*(.04+.14*l),u=o*r,h=a*r;refCtx.fillRect(e.x*o+d-u+f,e.y*a+g-h+c,o-2*d+2*u,a-2*g+2*h)}}refCtx.restore()}function stable01(e,t,r){const n=43758.5453*Math.sin(12.9898*e+78.233*t+37.719*r);return n-Math.floor(n)}function drawWordCells(e,t,r){const n=4e3/e.cols,o=5e3/e.rows;refCtx.fillStyle="rgb(255,0,0)",refCtx.strokeStyle="rgb(255,0,0)",refCtx.lineWidth=Math.max(1,.09*Math.min(n,o)),refCtx.lineCap="round",refCtx.lineJoin="round";for(const e of t)drawLetterInCell(e.char,e.x*n,e.y*o,n,o,r,e.index)}function drawLetterInCell(e,t,r,n,o,a,s){if(" "===e)return;const i=Math.min(n,o)*RangedLetterScale(a,s),l=stableNoise(t,r,s+1)*n*.1,f=stableNoise(t,r,s+2)*o*.1,c=.05*stableNoise(t,r,s+3);refCtx.save(),refCtx.translate(t+.5*n+l,r+.54*o+f),refCtx.rotate(c),refCtx.font=`${i}px ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace`,refCtx.textAlign="center",refCtx.textBaseline="middle",refCtx.fillText(e,0,0),refCtx.restore()}function RangedLetterScale(e,t){return e.grid.letterScale}function darkenedBgColor(e=.1){return[Math.max(0,palette.bg[0]-e),Math.max(0,palette.bg[1]-e),Math.max(0,palette.bg[2]-e),palette.bg[3]??1]}function drawUnderline(e){const t=4e3/e.grid.cols,r=5e3/e.grid.rows,n=e.cells.filter(e=>" "!==e.char);if(!n.length)return;refCtx.save(),refCtx.strokeStyle="rgb(255,0,0)",refCtx.lineWidth=Math.max(.6,.08*Math.min(t,r)),refCtx.lineCap="round",refCtx.lineJoin="round";const o=n[0],a=n[n.length-1],s=o.x*t+.15*t,i=o.y*r+.84*r,l=a.x*t+.85*t,f=a.y*r+.84*r,c=l-s,d=f-i,g=Math.max(1e-4,Math.sqrt(c*c+d*d)),u=-d/g,h=c/g,x=.28*Math.min(t,r);refCtx.beginPath(),refCtx.moveTo(s+u*x,i+h*x),refCtx.lineTo(l+u*x+stableNoise(l,f,9)*t*.25,f+h*x+stableNoise(s,i,10)*r*.25),refCtx.stroke(),refCtx.restore()}function drawStrikethrough(e){const t=4e3/e.grid.cols,r=5e3/e.grid.rows,n=e.cells.filter(e=>" "!==e.char);if(!n.length)return;const o=n[0],a=n[n.length-1],s=o.x*t+.15*t,i=o.y*r+.5*r,l=a.x*t+.85*t,f=a.y*r+.5*r;refCtx.save(),refCtx.strokeStyle="rgb(255,0,0)",refCtx.lineWidth=Math.max(.6,.08*Math.min(t,r)),refCtx.lineCap="round",refCtx.lineJoin="round",refCtx.beginPath(),refCtx.moveTo(s+stableNoise(s,i,21)*t*.18,i+stableNoise(s,i,22)*r*.18),refCtx.lineTo(l+stableNoise(l,f,23)*t*.18,f+stableNoise(l,f,24)*r*.18),refCtx.stroke(),refCtx.restore()}function drawCircleAroundWord(e){const t=wordBox(e),r=.5*(t.x1+t.x2),n=.5*(t.y1+t.y2),o=.62*Math.abs(t.x2-t.x1)+4e3/e.grid.cols,a=.62*Math.abs(t.y2-t.y1)+5e3/e.grid.rows,s=.35*stableNoise(r,n,4),i=refCtx.lineWidth,l=refCtx.strokeStyle;refCtx.strokeStyle="rgb(255,0,0)",refCtx.lineCap="round";const f=stableNoise(r,n,999),c=1+Math.floor(5*f);for(let e=0;e<c;e++){const t=1e3+137*e,l=stableNoise(r,n,t+1),f=stableNoise(r,n,t+2),c=stableNoise(r,n,t+3),d=stableNoise(r,n,t+4),g=stableNoise(r,n,t+5),u=.94+.18*g,h=.18+.95*stableNoise(r,n,t+6),x=.35+.65*d,m=4e3*l*.006,C=5e3*f*.006,w=o*u*(1+.04*c),b=a*u*(1-.04*c),R=g*Math.PI*2,p=stableNoise(r,n,t+7)<.45?.55+.35*stableNoise(r,n,t+8):1,v=R+2*Math.PI*p;refCtx.save(),refCtx.globalAlpha*=x,refCtx.lineWidth=i*h,refCtx.beginPath(),refCtx.ellipse(r+m,n+C,w,b,s+.22*d,R,v),refCtx.stroke(),refCtx.restore()}refCtx.lineWidth=i,refCtx.strokeStyle=l}function drawGridAroundLetters(e,t){const r=4e3/e.grid.cols,n=5e3/e.grid.rows,o=t.filter(e=>" "!==e.char);if(o.length){refCtx.save(),refCtx.strokeStyle="rgb(255,0,0)",refCtx.lineWidth=Math.max(.5,.045*Math.min(r,n)),refCtx.lineCap="square",refCtx.lineJoin="miter";for(const t of o){const o=t.x*r,a=t.y*n,s=.025*Math.min(r,n),i=t.index+1e3*e.washSeed;refCtx.beginPath(),refCtx.rect(o+stableNoise(t.x,t.y,i+1)*s,a+stableNoise(t.x,t.y,i+2)*s,r+stableNoise(t.x,t.y,i+3)*s,n+stableNoise(t.x,t.y,i+4)*s),refCtx.stroke()}refCtx.restore()}}function drawSquareAroundWord(e){const t=expandedWordBox(e,.22),r=Math.min(4e3/e.grid.cols,5e3/e.grid.rows);refCtx.save(),refCtx.strokeStyle="rgb(255,0,0)",refCtx.lineWidth=Math.max(.6,.08*r),refCtx.lineCap="round",refCtx.lineJoin="round";const n=.12*r;refCtx.beginPath(),refCtx.moveTo(t.x1+stableNoise(t.x1,t.y1,301)*n,t.y1+stableNoise(t.x1,t.y1,302)*n),refCtx.lineTo(t.x2+stableNoise(t.x2,t.y1,303)*n,t.y1+stableNoise(t.x2,t.y1,304)*n),refCtx.lineTo(t.x2+stableNoise(t.x2,t.y2,305)*n,t.y2+stableNoise(t.x2,t.y2,306)*n),refCtx.lineTo(t.x1+stableNoise(t.x1,t.y2,307)*,&n,t.y2+stableNoise(t.x1,t.y2,308)*n),refCtx.closePath(),refCtx.stroke(),refCtx.restore()}function drawCrossThroughWord(e){const t=expandedWordBox(e,.12),r=Math.min(4e3/e.grid.cols,5e3/e.grid.rows);refCtx.save(),refCtx.strokeStyle="rgb(255,0,0)",refCtx.lineWidth=Math.max(.6,.08*r),refCtx.lineCap="round",refCtx.lineJoin="round",drawNoisyLine(t.x1,t.y1,t.x2,t.y2,r,401),drawNoisyLine(t.x2,t.y1,t.x1,t.y2,r,411),refCtx.restore()}function drawPlusThroughWord(e){const t=expandedWordBox(e,.1),r=Math.min(4e3/e.grid.cols,5e3/e.grid.rows),n=.5*(t.x1+t.x2),o=.5*(t.y1+t.y2);refCtx.save(),refCtx.strokeStyle="rgb(255,0,0)",refCtx.lineWidth=Math.max(.6,.08*r),refCtx.lineCap="round",refCtx.lineJoin="round",drawNoisyLine(t.x1,o,t.x2,o,r,501),drawNoisyLine(n,t.y1,n,t.y2,r,511),refCtx.restore()}function drawBackgroundWashReference(e,t){clearReferenceToBlack(),refCtx.save(),useStructureSpace(),refCtx.globalAlpha=e.alpha*t,refCtx.fillStyle="rgb(0,0,255)",refCtx.strokeStyle="rgb(0,0,255)",refCtx.lineCap="round",refCtx.lineJoin="round";const r=e.y+.42*e.h;for(let n=0;n<44;n++){const o=n/Math.max(1,43),a=e.x+e.w*o+stableNoise(e.seed,n,11)*e.w*.025,s=Math.sin(o*Math.PI),i=r-e.h*(.25+.75*s+.45*stable01(e.seed,n,12)),l=r+e.h*(.15+.55*s+.75*stable01(e.seed,n,13)),f=e.w*(.018+.045*stable01(e.seed,n,14));drawVerticalPaintColumn(a,i,l,f,e.seed+91*n,t),stable01(e.seed,n,77)<e.dripChance&&drawPaintDrip(a+stableNoise(e.seed,n,21)*f,l-.05*e.h,e.h*(.35+1.4*stable01(e.seed,n,22)),e.seed+200*n)}for(let n=0;n<9;n++){const o=r+stableNoise(e.seed,n,301)*e.h*.45;refCtx.globalAlpha=e.alpha*t*.22,refCtx.lineWidth=e.h*(.025+.045*stable01(e.seed,n,302)),drawNoisyHorizontalStroke(e.x+stableNoise(e.seed,n,303)*e.w*.05,o,e.x+e.w+stableNoise(e.seed,n,304)*e.w*.05,o+stableNoise(e.seed,n,305)*e.h*.18,e.seed+400*n)}refCtx.restore()}function drawVerticalPaintColumn(e,t,r,n,o,a){refCtx.beginPath();for(let a=0;a<=12;a++){const s=t+(r-t)*(a/12),i=e-.5*n+stableNoise(o,a,31)*n*.75;0===a?refCtx.moveTo(i,s):refCtx.lineTo(i,s)}for(let a=12;a>=0;a--){const s=t+(r-t)*(a/12),i=e+.5*n+stableNoise(o,a,41)*n*.75;refCtx.lineTo(i,s)}refCtx.closePath(),refCtx.fill(),refCtx.save(),refCtx.globalAlpha*=.35;const s=2+Math.floor(5*stable01(o,1,55));for(let a=0;a<s;a++){const s=e+stableNoise(o,a,61)*n*.45;refCtx.lineWidth=n*(.08+.18*stable01(o,a,62)),refCtx.beginPath(),refCtx.moveTo(s,t+stableNoise(o,a,63)*n),refCtx.lineTo(s+stableNoise(o,a,64)*n*.45,r-stable01(o,a,65)*n),refCtx.stroke()}refCtx.restore(),refCtx.save(),refCtx.globalCompositeOperation="destination-out";for(let s=0;s<22;s++){const i=stable01(o,s,71)<.5?-1:1,l=t+stable01(o,s,72)*(r-t),f=e+i*n*(.3+.45*stable01(o,s,73));refCtx.globalAlpha=a*(.04+.14*stable01(o,s,74)),refCtx.beginPath(),refCtx.ellipse(f,l,n*(.15+.55*stable01(o,s,75)),n*(.25+1.25*stable01(o,s,76)),stableNoise(o,s,77),0,2*Math.PI),refCtx.fill()}refCtx.restore()}function drawNoisyHorizontalStroke(e,t,r,n,o){refCtx.beginPath();for(let a=0;a<=18;a++){const s=a/18,i=e+(r-e)*s,l=t+(n-t)*s+5e3*stableNoise(o,a,91)*.006;0===a?refCtx.moveTo(i,l):refCtx.lineTo(i,l)}refCtx.stroke()}function drawPainterlyBlob(e,t,r,n,o,a){const s=[];for(let a=0;a<28;a++){const i=a/28*Math.PI*2,l=1+.12*stableNoise(o,a,31)+.06*stableNoise(o,a,32)+.06*Math.sin(2*i+o)+.04*Math.sin(5*i+.37*o);s.push({x:e+Math.cos(i)*r*.5*l,y:t+Math.sin(i)*n*.5*l})}refCtx.beginPath();for(let e=0;e<s.length;e++){const t=s[(e-1+s.length)%s.length],r=s[e],n=s[(e+1)%s.length],o={x:.5*(t.x+r.x),y:.5*(t.y+r.y)},a={x:.5*(r.x+n.x),y:.5*(r.y+n.y)};0===e&&refCtx.moveTo(o.x,o.y),refCtx.quadraticCurveTo(r.x,r.y,a.x,a.y)}refCtx.closePath(),refCtx.fill(),refCtx.save(),refCtx.globalCompositeOperation="destination-out",refCtx.globalAlpha=.1*a;for(let s=0;s<160;s++){const i=stable01(o,s,41)*Math.PI*2,l=Math.sqrt(stable01(o,s,42)),f=Math.cos(i)*l,c=Math.sin(i)*l,d=e+f*r*.48,g=t+c*n*.48,u=Math.min(1,Math.sqrt(f*f+c*c)),h=Math.pow(u,2.2),x=r*(.004+.09*h*stable01(o,s,43)),m=n*(.003+.05*h*stable01(o,s,44));refCtx.globalAlpha=(.01+.18*h)*a,refCtx.beginPath(),refCtx.ellipse(d,g,x,m,stableNoise(o,s,45)*Math.PI,0,2*Math.PI),refCtx.fill()}refCtx.restore()}function drawPaintDrip(e,t,r,n){const o=.045*r;refCtx.beginPath(),refCtx.moveTo(e,t);for(let a=1;a<=5;a++){const s=a/5;refCtx.lineTo(e+stableNoise(n,a,51)*o,t+r*s)}refCtx.lineWidth=Math.max(1,4.8),refCtx.lineCap="round",refCtx.strokeStyle="rgb(0,0,255)",refCtx.stroke()}function drawNoisyLine(e,t,r,n,o,a){const s=.16*o;refCtx.beginPath(),refCtx.moveTo(e+stableNoise(e,t,a+1)*s,t+stableNoise(e,t,a+2)*s),refCtx.lineTo(r+stableNoise(r,n,a+3)*s,n+stableNoise(r,n,a+4)*s),refCtx.stroke()}function expandedWordBox(e,t=.15){const r=wordBox(e),n=4e3/e.grid.cols,o=5e3/e.grid.rows;return{x1:r.x1-n*t,y1:r.y1-o*t,x2:r.x2+n*t,y2:r.y2+o*t}}function wordBox(e){const t=4e3/e.grid.cols,r=5e3/e.grid.rows,n=e.cells.map(e=>e.x*t),o=e.cells.map(e=>e.y*r);return{x1:Math.min(...n),y1:Math.min(...o),x2:Math.max(...n)+t,y2:Math.max(...o)+r}}function stableNoise(e,t,r){const n=43758.5453*Math.sin(12.9898*e+78.233*t+37.719*r);return n-Math.floor(n)-.5}function run(){if(renderLoopRunning=!1,isResizing||width<MIN_GL_SIZE||height<MIN_GL_SIZE||!refTexture||frameBuffers.length<2)return void requestRun();maybeFetchMoreWords();const e=state.placements[state.activePlacementIndex];if(!e)return renderScreen(),state.frame%30==0&&sampleVisibleCanvasHealth(),void(window.__RESIDUAL_NOTES_RENDERED__||(window.__RESIDUAL_NOTES_RENDERED__=!0,window.dispatchEvent(new Event("residual-notes:rendered"))));const t=settings.pauseFrames+settings.revealFrames,r=state.frame%t;let n=0,o=!1;if(r<settings.pauseFrames)clearReferenceToBlack();else{const t=r-settings.pauseFrames;n=Math.min(1,(t+1)*settings.revealSpeed/settings.revealFrames),o=t>=settings.revealFrames-1,drawPlacementReference(e,n)}updateReferenceTexture(),renderWash(e),renderScreen(),(o||r===t-1)&&state.activePlacementIndex++,state.frame++,requestRun()}function renderWash(e){const t=frameBufferId,r=1^frameBufferId;frameBufferId=r,useProgram(washProgram),gl.bindFramebuffer(gl.FRAMEBUFFER,frameBuffers[r].buffer),assertFramebufferHealthy("renderWash")&&(gl.viewport(0,0,width,height),gl.clearColor(0,0,0,1),gl.clear(gl.COLOR_BUFFER_BIT),gl.activeTexture(gl.TEXTURE0),gl.bindTexture(gl.TEXTURE_2D,frameBuffers[t].texture),gl.uniform1i(gl.getUniformLocation(washProgram,"previousFrame"),0),gl.activeTexture(gl.TEXTURE1),gl.bindTexture(gl.TEXTURE_2D,refTexture),gl.uniform1i(gl.getUniformLocation(washProgram,"referenceMask"),1),gl.uniform1f(gl.getUniformLocation(washProgram,"frame"),state.frame),gl.uniform1f(gl.getUniformLocation(washProgram,"dirx"),e.dirx),gl.uniform1f(gl.getUniformLocation(washProgram,"diry"),e.diry),gl.uniform1f(gl.getUniformLocation(washProgram,"washStrength"),e.washStrength??settings.washStrength),gl.uniform1f(gl.getUniformLocation(washProgram,"smudgeChance"),e.smudgeChance??settings.smudgeChance),gl.uniform1f(gl.getUniformLocation(washProgram,"textureAmount"),settings.textureAmount),gl.uniform4fv(gl.getUniformLocation(washProgram,"bgColor"),palette.bg),gl.uniform4fv(gl.getUniformLocation(washProgram,"inkColor"),e.color),gl.uniform4fv(gl.getUniformLocation(washProgram,"highlightColor"),"backgroundWash"===e.type?e.color:palette.highlight),gl.uniform2f(gl.getUniformLocation(washProgram,"resolution"),width,height),gl.uniform1f(gl.getUniformLocation(washProgram,"grainSeed"),GRAIN_SEED),gl.uniform1f(gl.getUniformLocation(washProgram,"baseGrainAmount"),settings.baseGrainAmount),gl.uniform1f(gl.getUniformLocation(washProgram,"baseMottleAmount"),settings.baseMottleAmount),gl.drawArrays(gl.TRIANGLE_STRIP,0,4))}function sampleVisibleCanvasHealth(){if(!gl||gl.isContextLost())return;const e=new Uint8Array(4);gl.bindFramebuffer(gl.FRAMEBUFFER,null),gl.readPixels(Math.floor(.5*width),Math.floor(.5*height),1,1,gl.RGBA,gl.UNSIGNED_BYTE,e);e[0]+e[1]+e[2]<8&&state.frame>20?blackFrameCount++:blackFrameCount=0,blackFrameCount>90&&queueHardRebuild("visible canvas stayed black"),state.activePlacementIndex>0&&state.frame-lastProgressFrame>240&&queueHardRebuild("render loop appears stuck"),lastProgressFrame=state.frame}function renderScreen(){useProgram(screenProgram),gl.bindFramebuffer(gl.FRAMEBUFFER,null),gl.viewport(0,0,width,height),gl.clearColor(0,0,0,1),gl.clear(gl.COLOR_BUFFER_BIT),gl.activeTexture(gl.TEXTURE0),gl.bindTexture(gl.TEXTURE_2D,frameBuffers[frameBufferId].texture),gl.uniform1i(gl.getUniformLocation(screenProgram,"buffer"),0),gl.drawArrays(gl.TRIANGLE_STRIP,0,4)}function useProgram(e){gl.useProgram(e);const t=gl.getAttribLocation(e,"pos");gl.enableVertexAttribArray(t),gl.bindBuffer(gl.ARRAY_BUFFER,vertexBuffer),gl.vertexAttribPointer(t,3,gl.FLOAT,!1,0,0)}function createProgram(e,t){const r=gl.createProgram(),n=createShader(`#version 300 es\n${e}`,gl.VERTEX_SHADER),o=createShader(`#version 300 es\nprecision highp float;\n${t}`,gl.FRAGMENT_SHADER);return gl.attachShader(r,n),gl.attachShader(r,o),gl.linkProgram(r),gl.getProgramParameter(r,gl.LINK_STATUS)||console.error(gl.getProgramInfoLog(r)),r}function createShader(e,t){const r=gl.createShader(t);return gl.shaderSource(r,e),gl.compileShader(r),gl.getShaderParameter(r,gl.COMPILE_STATUS)||console.error(gl.getShaderInfoLog(r)),r}function createVertexBuffer(){const e=gl.createBuffer();return gl.bindBuffer(gl.ARRAY_BUFFER,e),gl.bufferData(gl.ARRAY_BUFFER,new Float32Array([-1,1,0,-1,-1,0,1,1,0,1,-1,0]),gl.STATIC_DRAW),e}function createFrameBuffer(e,t,r=null){e=Math.max(MIN_GL_SIZE,Math.floor(e)),t=Math.max(MIN_GL_SIZE,Math.floor(t));const n=gl.createFramebuffer(),o=createTexture(e,t,r);gl.bindFramebuffer(gl.FRAMEBUFFER,n),gl.framebufferTexture2D(gl.FRAMEBUFFER,gl.COLOR_ATTACHMENT0,gl.TEXTURE_2D,o,0);const a=gl.checkFramebufferStatus(gl.FRAMEBUFFER);return a!==gl.FRAMEBUFFER_COMPLETE&&console.warn("Framebuffer incomplete:",a,e,t),gl.bindFramebuffer(gl.FRAMEBUFFER,null),{buffer:n,texture:o}}function createTexture(e,t,r=null){e=Math.max(MIN_GL_SIZE,Math.floor(e)),t=Math.max(MIN_GL_SIZE,Math.floor(t));const n=gl.createTexture();return gl.bindTexture(gl.TEXTURE_2D,n),gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.NEAREST),gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.NEAREST),gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_S,gl.CLAMP_TO_EDGE),gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_T,gl.CLAMP_TO_EDGE),r&&r.width>0&&r.height>0?gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,gl.RGBA,gl.UNSIGNED_BYTE,r):gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,e,t,0,gl.RGBA,gl.UNSIGNED_BYTE,null),n}function updateReferenceTexture(){refTexture&&(!ref||ref.width<MIN_GL_SIZE||ref.height<MIN_GL_SIZE||(gl.bindTexture(gl.TEXTURE_2D,refTexture),gl.texSubImage2D(gl.TEXTURE_2D,0,0,0,gl.RGBA,gl.UNSIGNED_BYTE,ref)))}function rgb(e){return`rgb(${Math.floor(255*e[0])}, ${Math.floor(255*e[1])}, ${Math.floor(255*e[2])})`}function clamp255(e){return Math.max(0,Math.min(255,e))}function handleKey(e){"s"===e.key&&savePNG(),"m"===e.key&&(settings.showReference=!settings.showReference,ref.style.display=settings.showReference?"block":"none"),"c"===e.key&&setCustomRenderSize(),"p"===e.key.toLowerCase()&&setCustomRpcUrl()}function savePNG(){renderScreen();const e=document.createElement("a");e.download=`residual-notes-${HASH.slice(2,10)}-${width}x${height}.png`,e.href=view.toDataURL("image/png"),e.click()}function restart(){restartAfterResize()}init();
Common Groundbg=.18 .87 .9 1|grid=.23 .91 .95 1|highlight=1 .06 .02 1|inks=.95 .95 .95 1 5;.04 .2 .4 1 1;.04 .04 .04 1 10x258f9f860ca31837d81476122c0f016f0aa9236db34c4e5e7b28f3c12b0802dc#2EDEE6#F2F2F2
Proof of Existencebg=.10 .10 .10 1|grid=.16 .16 .16 1|highlight=.55 .15 .15 1|inks=.90 .90 .90 1 8;.98 .98 .98 1 2;.95 .95 .85 1 1;.0 .0 .0 1 0.5;.75 .65 .15 1 0.5;.78 .88 .93 1 0.1;.99 .01 .68 1 0.05;.58 .78 .67 1 0.05;1 .97 .0 1 0.050xd3ab064acec0546df96c6f29763776487961cfbeb5467a616104d3d65fdc1228#1B1B1B#ffffff
0xd2af9f3e…0475·#25,309,127·0x207b756f…d44e6d
RmResidual Notes`RPC registry requiredRpOwner pays no fee`xRrBelow current notes`hRpOwner pays no fee`xRlNote too long`_a.aV[PPPPPPPV[a.mPPPPPPPPPPV[___`@
function parsePalette(e){const t=Object.fromEntries(e.split("|").map(e=>{const t=e.indexOf("=");return[e.slice(0,t),e.slice(t+1)]})),r=e=>e.trim().split(/\s+/).map(Number);return{bg:r(t.bg),grid:r(t.grid),highlight:r(t.highlight),inks:t.inks.split(";").map(e=>{const t=r(e);return{color:t.slice(0,4),weight:t[4]}})}}palette=parsePalette(palette);class Random{constructor(e){this.useA=!1,this.prngA=this.sfc32(e.slice(2,34)),this.prngB=this.sfc32(e.slice(34,66));for(let e=0;e<1e5;e++)this.prngA(),this.prngB()}sfc32(e){let t=parseInt(e.slice(0,8),16),r=parseInt(e.slice(8,16),16),n=parseInt(e.slice(16,24),16),o=parseInt(e.slice(24,32),16);return function(){t|=0,r|=0,n|=0,o|=0;let e=(t+r|0)+o|0;return o=o+1|0,t=r^r>>>9,r=n+(n<<3)|0,n=n<<21|n>>>11,n=n+e|0,(e>>>0)/4294967296}}g(){return this.useA=!this.useA,this.useA?this.prngA():this.prngB()}range(e,t){return e+this.g()*(t-e)}int(e,t){return Math.floor(this.range(e,t+1))}pick(e){return e[Math.floor(this.g()*e.length)]}chance(e){return this.g()<e}}let R=new Random(HASH);const wordStream={fetching:!1,done:WORDS.length>=WORD_COUNT,failed:!1,nextOffset:WORDS.length};let customRpcUrl="";function getRpcUrls(){return customRpcUrl?[customRpcUrl,...RPC_URLS.filter(e=>e!==customRpcUrl)]:RPC_URLS}function setCustomRpcUrl(){const e=prompt("Custom RPC URL:",customRpcUrl||"https://...");if(!e)return;const t=e.trim();/^https?:\/\//i.test(t)?(customRpcUrl=t,wordStream.fetching=!1,wordStream.failed=!1,wordStream.done=WORDS.length>=WORD_COUNT,wordStream.nextOffset=WORDS.length,maybeFetchMoreWords(),requestRun(),console.log("Custom RPC set:",customRpcUrl)):alert("Please enter a valid http(s) RPC URL.")}const STRUCT_W=4e3,STRUCT_H=5e3,STRUCT_ASPECT=.8;let customRenderWidth=null,customRenderHeight=null,lastGoodWidth=1200,lastGoodHeight=1500,restartQueued=!1,blackFrameCount=0,lastProgressFrame=0;const MAX_BLACK_FRAMES=90,MAX_STUCK_FRAMES=240;let renderLoopRunning=!1;function requestRun(){renderLoopRunning||(renderLoopRunning=!0,requestAnimationFrame(run))}const GRAIN_SEED=parseInt(HASH.slice(2,10),16)/4294967295,settings={aspect:.8,washStrength:R.range(.1,.8),smudgeChance:R.range(.1,.24),textureAmount:R.range(.025,.08),pauseFrames:0,revealFrames:2,revealSpeed:1,backgroundWashChance:.01,backgroundWashMinWords:5,backgroundWashMaxWords:50,backgroundWashColor:palette.highlight,baseGrainAmount:.02,baseMottleAmount:8e-4,gridDefinitions:[...Array(5)].map((e,t)=>(co=t>0?Math.floor(R.range(70,130)):Math.floor(R.range(45,65)),ro=Math.floor(1.25*co),{name:t.toString(),cols:co,rows:ro,rotation:R.g()/25-.02,scale:1,offsetX:0,offsetY:0,letterScale:.8})),showReference:!1};function shuffled(e){const t=[...e];for(let e=t.length-1;e>0;e--){const r=R.int(0,e);[t[e],t[r]]=[t[r],t[e]]}return t}const view=document.getElementById("view"),ref=document.getElementById("ref"),refCtx=ref.getContext("2d",{alpha:!1});let gl,vertexBuffer,washProgram,screenProgram,refTexture,width=0,height=0,dpr=1,frameBuffers=[],frameBufferId=0,resizeQueued=!1,isResizing=!1;const MIN_GL_SIZE=2,state={frame:0,grids:[],placements:[],activePlacementIndex:0},vertexShader="\n in vec3 pos;\n out vec2 vUv;\n\n void main() {\n gl_Position = vec4(pos, 1.0);\n vUv = (pos.xy + 1.0) * 0.5;\n }\n",washShader="\n uniform sampler2D previousFrame;\n uniform sampler2D referenceMask;\n uniform float frame;\n uniform float dirx;\n uniform float diry;\n uniform float washStrength;\n uniform float smudgeChance;\n uniform float textureAmount;\n uniform vec4 bgColor;\n uniform vec4 inkColor;\n uniform vec4 highlightColor;\n\n uniform vec2 resolution;\n uniform float grainSeed;\n uniform float baseGrainAmount;\n uniform float baseMottleAmount;\n\n in vec2 vUv;\n out vec4 col;\n\n vec3 random3(vec3 c) {\n float j = 4096.0 * sin(dot(c, vec3(17.0, 59.4, 15.0)));\n vec3 r;\n r.z = fract(512.0 * j);\n j *= 0.125;\n r.x = fract(512.0 * j);\n j *= 0.125;\n r.y = fract(512.0 * j);\n return r - 0.5;\n }\n\n const float F3 = 0.3333333;\n const float G3 = 0.1666667;\n\n float simplex3(vec3 p) {\n vec3 s = floor(p + dot(p, vec3(F3)));\n vec3 x = p - s + dot(s, vec3(G3));\n vec3 e = step(vec3(0.0), x - x.yzx);\n vec3 i1 = e * (1.0 - e.zxy);\n vec3 i2 = 1.0 - e.zxy * (1.0 - e);\n vec3 x1 = x - i1 + G3;\n vec3 x2 = x - i2 + 2.0 * G3;\n vec3 x3 = x - 1.0 + 3.0 * G3;\n vec4 w, d;\n w.x = dot(x, x);\n w.y = dot(x1, x1);\n w.z = dot(x2, x2);\n w.w = dot(x3, x3);\n w = max(0.6 - w, 0.0);\n d.x = dot(random3(s), x);\n d.y = dot(random3(s + i1), x1);\n d.z = dot(random3(s + i2), x2);\n d.w = dot(random3(s + 1.0), x3);\n w *= w;\n w *= w;\n d *= w;\n return dot(d, vec4(52.0));\n }\n\n float hash12(vec2 p) {\n vec3 p3 = fract(vec3(p.xyx) * 0.1031);\n p3 += dot(p3, p3.yzx + 33.33 + grainSeed * 17.17);\n return fract((p3.x + p3.y) * p3.z);\n }\n\n void main() {\n vec4 ref = texture(referenceMask, vUv);\n vec4 prev = texture(previousFrame, vUv);\n\n float grainA = simplex3(vec3(vUv.x * 380.0 + frame * 0.011, vUv.y * 380.0 - frame * 0.013, 11.0));\n float grainB = simplex3(vec3(vUv.x * 7500.0, vUv.y * 7500.0, frame * 0.018));\n\n vec4 texturedBg = bgColor + vec4(vec3(grainB * textureAmount), 0.0);\n\n col = prev;\n\n // Only bake paper grain into the very first rendered frame.\n // After that it becomes part of previousFrame.\n if (frame < 0.5) {\n vec2 px = gl_FragCoord.xy;\n\n float fine = hash12(px) - 0.5;\n\n float fine2 = hash12(px * 0.5 + 91.7) - 0.5;\n float mottle = simplex3(vec3(\n vUv.x * 95.0 + grainSeed * 13.0,\n vUv.y * 95.0 - grainSeed * 9.0,\n 4.0\n ));\n\n float paper =\n fine * baseGrainAmount +\n fine2 * baseGrainAmount * 0.45 +\n mottle * baseMottleAmount;\n\n col.rgb += vec3(paper);\n }\n\n if (ref.g > 0.001) {\n float rnd = simplex3(vec3(\n (vUv.x + frame / 100.0) * 5000.0,\n (vUv.y - frame / 100.0) * 50.0,\n grainSeed * 100000.0\n ));\n\n vec4 textureBG = mix(\n bgColor,\n vec4(\n bgColor.rgb - vec3(\n simplex3(vec3(\n (vUv.x + frame / 1000.0) * 500.0,\n (vUv.y - frame / 1000.0) * 500.0,\n grainSeed * 100000.0\n )) / 80.\n ),\n 1.0\n ),\n simplex3(vec3(\n (vUv.x + frame / 1000.0) * 5.0,\n (vUv.y - frame / 1000.0) / 4.0,\n grainSeed * 100000.0\n ))\n );\n\n // This is the core wash behavior from the second project:\n // replace/scratch toward textured background, instead of dragging black blocks.\n col = mix(\n textureBG,\n // vec4(1.,0.,0.,1.),\n // bgColor,\n prev,\n simplex3(vec3(\n (vUv.x + frame / 100.0) * 5000.0,\n (vUv.y - frame / 100.0) * 5000.0,\n grainSeed * 100000.0\n ))*4.\n );\n\n // Directional smudge, but only sometimes.\n if (rnd < smudgeChance) {\n col = mix(\n texture(previousFrame, vec2(\n vUv.x + 0.003 * dirx,\n vUv.y + 0.003 * diry\n )),\n textureBG,\n rnd\n );\n }\n\n // Let the green mask control strength.\n prev = bgColor;\n col = mix(prev, col, ref.g * washStrength);\n }\n\n if (ref.b > 0.01) {\n float paintMask = ref.b;\n\n float roughA = simplex3(vec3(\n vUv.x * 900.0,\n vUv.y * 900.0,\n frame * 0.012\n ));\n\n float roughB = simplex3(vec3(\n vUv.x * 2200.0,\n vUv.y * 2200.0,\n 19.0\n ));\n\n float brokenMask = paintMask;\n brokenMask *= smoothstep(-0.45, 0.55, roughA);\n brokenMask *= 0.72 + roughB * 0.28;\n\n vec4 noisyPaint = highlightColor;\n noisyPaint.rgb += vec3(roughB * 0.10 + roughA * 0.035);\n\n vec2 dragUv = vUv + vec2(\n roughA * 0.0025,\n roughB * 0.0015\n );\n\n vec4 draggedSurface = texture(previousFrame, dragUv);\n\n vec4 paintOnSurface = mix(draggedSurface, noisyPaint, brokenMask);\n\n col = mix(col, paintOnSurface, brokenMask);\n }\n\n // Red = foreground ink. The incoming reference contains only the current word.\n if (ref.r > 0.01) {\n float smearNoise = simplex3(vec3(\n vUv.x * 900.0 + frame * 0.03,\n vUv.y * 220.0 - frame * 0.02,\n grainSeed * 9999.0\n ));\n\n float smearMask = ref.r * smoothstep(-0.35, 0.55, smearNoise);\n\n vec2 smearUv = vUv + vec2(\n -0.006 * dirx,\n 0.002 * diry\n );\n\n vec4 draggedInk = texture(previousFrame, smearUv);\n\n col = mix(col, draggedInk, smearMask * 0.65);\n\n vec4 brokenInk = inkColor;\n brokenInk.rgb += vec3(smearNoise * 0.16);\n\n col = mix(col, brokenInk, ref.r);\n }\n }\n",screenShader="\n uniform sampler2D buffer;\n in vec2 vUv;\n out vec4 col;\n\n void main() {\n col = texture(buffer, vec2(vUv.x, 1.0 - vUv.y));\n }\n";async function maybeFetchMoreWords(){if(!wordStream.fetching&&!wordStream.done&&!wordStream.failed)if(RPC_URLS.length){wordStream.fetching=!0;try{const e=await fetchNotesSlice(wordStream.nextOffset,FETCH_BATCH_SIZE);if(!e.length)return void(wordStream.done=!0);for(const t of e)WORDS.push(t),addWordPlacement(t);wordStream.nextOffset+=e.length,wordStream.nextOffset>=WORD_COUNT&&(wordStream.done=!0)}catch(e){console.warn("RPC word fetch failed:",e),wordStream.failed=!0}finally{wordStream.fetching=!1}}else wordStream.failed=!0}async function fetchNotesSlice(e,t){let r=null;for(const n of getRpcUrls())try{return await fetchNotesSliceFromRpc(n,TOKEN_ID,e,t)}catch(e){r=e,console.warn("RPC failed, trying next:",n,e)}throw r||new Error("No RPC worked")}const NOTES_SLICE_SELECTOR="0x91cf7995";async function fetchNotesSliceFromRpc(e,t,r,n){const o=NOTES_SLICE_SELECTOR+encodeUint256(t)+encodeUint256(r)+encodeUint256(n),a=await fetch(e,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({jsonrpc:"2.0",id:1,method:"eth_call",params:[{to:CONTRACT_ADDRESS,data:o},"latest"]})}),s=await a.json();if(s.error)throw new Error(s.error.message||"RPC error");return s.result&&"0x"!==s.result?decodeStringArray(s.result):[]}function encodeUint256(e){return BigInt(e).toString(16).padStart(64,"0")}function decodeStringArray(e){e=e.replace(/^0x/,"");const t=t=>{const r=2*t;return BigInt("0x"+e.slice(r,r+64))},r=(t,r)=>{const n=2*t;return e.slice(n,n+2*r)},n=Number(t(0)),o=Number(t(n)),a=[];for(let e=0;e<o;e++){const o=n+32+Number(t(n+32+32*e)),s=r(o+32,Number(t(o)));a.push(hexToUtf8(s))}return a}function hexToUtf8(e){const t=[];for(let r=0;r<e.length;r+=2)t.push(parseInt(e.slice(r,r+2),16));return(new TextDecoder).decode(new Uint8Array(t)).replace(/\0/g,"").trim()}function varyColor(e,t=.01){return[Math.max(0,Math.min(1,e[0]+R.range(-t,t))),Math.max(0,Math.min(1,e[1]+R.range(-t,t))),Math.max(0,Math.min(1,e[2]+R.range(-t,t))),e[3]??1]}function init(){if(gl=view.getContext("webgl2",{alpha:!1,antialias:!1,preserveDrawingBuffer:!0}),!gl)return void(document.body.innerHTML="WebGL2 is required.");vertexBuffer=createVertexBuffer(),washProgram=createProgram(vertexShader,washShader),screenProgram=createProgram(vertexShader,screenShader),createGrids(),createWordPlacements(),window.addEventListener("resize",requestResize),window.addEventListener("keydown",handleKey),view.addEventListener("webglcontextlost",e=>{e.preventDefault(),console.warn("WebGL context lost")},!1),view.addEventListener("webglcontextrestored",()=>{console.warn("WebGL context restored, rebuilding"),hardRebuild()},!1);new ResizeObserver(()=>requestResize()).observe(document.body),resize(),requestRun()}function resetRandom(){R=new Random(HASH)}function requestResize(){resizeQueued||(resizeQueued=!0,requestAnimationFrame(()=>{resizeQueued=!1,resize()}))}let lastRenderedPixelCount=0;function restartAfterResize(){resetRandom(),state.frame=0,state.activePlacementIndex=0,createGrids(),createWordPlacements(),drawBaseReference(),refTexture&&gl.deleteTexture(refTexture),refTexture=createTexture(width,height,ref),resetFrameBuffers(),window.__RESIDUAL_NOTES_RENDERED__=!1,blackFrameCount=0,lastProgressFrame=0,lastRenderedPixelCount=width*height,requestRun()}let renderW=null,renderH=null;function resize(){const e=1*Math.floor(window.innerWidth||document.documentElement.clientWidth||0),t=1*Math.floor(window.innerHeight||document.documentElement.clientHeight||0);if(e<20||t<20)return void requestAnimationFrame(requestResize);let r,n;e/t>settings.aspect?(n=t,r=t*settings.aspect):(r=e,n=e/settings.aspect),dpr=Math.max(1,window.devicePixelRatio||1);const o=renderW??Math.max(20,Math.round(r*dpr)),a=renderH??Math.max(20,Math.round(n*dpr));if(!(o===width&&a===height)){if(width>0&&height>0&&!(o*a>width*height))return view.style.width=`${r}px`,void(view.style.height=`${n}px`);isResizing=!0,width=o,height=a,view.width=width,view.height=height,view.style.display="block",ref.width=width,ref.height=height,ref.style.display=settings.showReference?"block":"none",restartAfterResize(),isResizing=!1}}function setCustomRenderSize(){const e=prompt("Render width in pixels:",width);if(!e)return;const t=Math.max(100,Math.floor(Number(e)));Number.isFinite(t)&&(renderW=t,renderH=Math.round(renderW/settings.aspect),resize(),restart())}function useStructureSpace(){refCtx.setTransform(width/4e3,0,0,height/5e3,0,0)}function resetFrameBuffers(){for(const e of frameBuffers)gl.deleteFramebuffer(e.buffer),gl.deleteTexture(e.texture);frameBuffers=[createFrameBuffer(width,height,ref),createFrameBuffer(width,height,null)],frameBufferId=0}function queueHardRebuild(e="unknown"){restartQueued||(restartQueued=!0,console.warn("Queueing hard rebuild:",e),requestAnimationFrame(()=>{restartQueued=!1,hardRebuild(e)}))}function hardRebuild(e="unknown"){if(console.warn("Hard rebuild:",e),gl&&!gl.isContextLost())try{if(resize(),width<MIN_GL_SIZE||height<MIN_GL_SIZE)return;restartAfterResize(),blackFrameCount=0,lastProgressFrame=state.frame,window.__RESIDUAL_NOTES_RENDERED__=!1}catch(e){console.warn("Hard rebuild failed:",e)}}function assertFramebufferHealthy(e=""){const t=gl.checkFramebufferStatus(gl.FRAMEBUFFER);return t===gl.FRAMEBUFFER_COMPLETE||(queueHardRebuild(`bad framebuffer ${e}: ${t}`),!1)}function drawBaseReference(){useStructureSpace(),refCtx.fillStyle=rgb(palette.bg),refCtx.fillRect(0,0,4e3,5e3),refCtx.fillStyle=rgb(palette.grid);const e=Math.floor(settings.gridDefinitions[0].cols),t=Math.floor(settings.gridDefinitions[0].rows);for(let t=2;t<e-2;t++)refCtx.fillRect(4e3/e*t,0,1,5e3);for(let e=2;e<t-2;e++)refCtx.fillRect(0,5e3/t*e,4e3,1)}function createGrids(){state.grids=settings.gridDefinitions.map((e,t)=>({id:t,name:e.name||`grid ${t}`,cols:Math.floor(e.cols),rows:Math.floor(e.rows),rotation:e.rotation||0,scale:e.scale||1,offsetX:e.offsetX||0,offsetY:e.offsetY||0,letterScale:e.letterScale||.8,occupied:null}))}function createWordPlacements(){state.placements=[];let e=R.int(settings.backgroundWashMinWords,settings.backgroundWashMaxWords);for(const t of WORDS)addWordPlacement(t),e--,e<=0&&R.chance(settings.backgroundWashChance)&&(addBackgroundWashPlacement(),e=R.int(settings.backgroundWashMinWords,settings.backgroundWashMaxWords))}function addWordPlacement(e){if(!e||!String(e).trim())return!1;const t=String(e).toUpperCase(),r=tryCreateWordPlacement(t)||tryCreateWordPlacement(t)||tryCreateWordPlacement(t);return!!r&&(state.placements.push(r),!0)}function addBackgroundWashPlacement(){state.placements.push({type:"backgroundWash",color:R.chance(.15)?palette.highlight:darkenedBgColor(.1),dirx:R.range(-1,1),diry:R.range(-1,1),washStrength:R.range(.03,.16),smudgeChance:R.range(.1,.32),x:4e3*R.range(-.08,.85),y:5e3*R.range(-.08,.85),w:4e3*R.range(.18,.55),h:5e3*R.range(.12,.38),seed:9999*R.g(),alpha:R.range(.02,.175),dripChance:R.range(.08,.28),force:1})}function tryCreateWordPlacement(e){for(let t=0;t<80;t++){const t=R.pick(state.grids),r=R.pick(["right","down","right","down","right","down","right","down","right","down","right","down","right","down","diagDown","diagUp"]),n=randomStartForTextBlock(t,e,r),o=textBlockCells(n.x,n.y,e,r,t);if(cellsFit(t,o))return{word:e,grid:t,direction:r,cells:o,color:varyColor(pickInkForWord(),.05),dirx:R.range(-2,2),diry:R.range(-2,2),washSeed:R.g(),washStrength:R.range(.05,.35),smudgeChance:R.range(.1,.32),washPad:R.range(.04,.2),washGaps:0,washStampCount:R.int(1,6),circle:R.chance(.065),underline:R.chance(.05),strikethrough:R.chance(.05),lettergrid:R.chance(.01),square:R.chance(.01),cross:R.chance(.01),plus:R.chance(.005),force:1}}return null}function randomStartForTextBlock(e,t,r){const n=Math.min(String(t).length,"right"===r?e.cols:e.rows),o=R.int(0,e.cols-1),a=R.int(0,e.rows-1);return"right"===r?{x:Math.max(0,Math.min(e.cols-1,o-Math.floor(n*R.range(.25,.65)))),y:Math.max(0,Math.min(e.rows-1,a-R.int(0,2)))}:"down"===r?{x:Math.max(0,Math.min(e.cols-1,o-R.int(0,2))),y:Math.max(0,Math.min(e.rows-1,a-Math.floor(n*R.range(.25,.65))))}:{x:o,y:a}}function textBlockCells(e,t,r,n,o){if("diagDown"===n||"diagUp"===n)return diagonalTextCells(e,t,r,n);const a=String(r).split(/\s+/),s=[],i="right"===n?Math.max(1,o.cols-e):Math.max(1,o.rows-t);let l=0,f=0;for(const r of a){if(f+(f>0?1:0)+r.length>i&&(l++,f=0),"right"===n&&t+l>=o.rows)break;if("down"===n&&e+l>=o.cols)break;f>0&&(addTextCharCell(s,e,t,n,f,l," "),f++);for(let a=0;a<r.length&&(f>=i&&(l++,f=0),!("right"===n&&t+l>=o.rows))&&!("down"===n&&e+l>=o.cols);a++)addTextCharCell(s,e,t,n,f,l,r[a]),f++}return s.map((e,t)=>({...e,index:t}))}function addTextCharCell(e,t,r,n,o,a,s){"right"===n&&e.push({x:t+o,y:r+a,char:s}),"down"===n&&e.push({x:t+a,y:r+o,char:s})}function diagonalTextCells(e,t,r,n){const o=[];for(let a=0;a<r.length;a++){let s=e+a,i="diagDown"===n?t+a:t-a;o.push({x:s,y:i,char:r[a],index:a})}return o}function cellsFit(e,t){return t.every(t=>t.x>=0&&t.y>=0&&t.x<e.cols&&t.y<e.rows)}function pickInkForWord(){return weightedPick(palette.inks).color}function weightedPick(e){const t=e.reduce((e,t)=>e+t.weight,0);let r=R.g()*t;for(const t of e)if(r-=t.weight,r<=0)return t;return e[e.length-1]}function clearReferenceToBlack(){refCtx.setTransform(1,0,0,1,0,0),refCtx.fillStyle="black",refCtx.fillRect(0,0,width,height)}function drawPlacementReference(e,t){if("backgroundWash"===e.type)return void drawBackgroundWashReference(e,t);clearReferenceToBlack(),refCtx.save(),useStructureSpace(),applyGridTransform(e.grid);const r=Math.ceil(e.cells.length*t),n=e.cells.slice(0,r);drawWashForCells(e.grid,n,e.washPad,e),drawWordCells(e.grid,n,e),e.underline&&t>.72&&drawUnderline(e),e.circle&&t>.84&&drawCircleAroundWord(e),e.strikethrough&&t>.65&&drawStrikethrough(e),e.lettergrid&&t>.7&&drawGridAroundLetters(e,n),e.square&&t>.82&&drawSquareAroundWord(e),e.cross&&t>.78&&drawCrossThroughWord(e),e.plus&&t>.78&&drawPlusThroughWord(e),refCtx.restore()}function applyGridTransform(e){refCtx.translate(2e3+4e3*e.offsetX,2500+5e3*e.offsetY),refCtx.rotate(e.rotation),refCtx.scale(e.scale,e.scale),refCtx.translate(-2e3,-2500)}function drawWashForCells(e,t,r,n){const o=4e3/e.cols,a=5e3/e.rows;refCtx.save(),refCtx.fillStyle="rgb(0,255,0)";for(const e of t){const t=n.washStampCount??1;for(let s=0;s<t;s++){const t=1e3*n.washSeed+97*s;if(stable01(e.x,e.y,e.index+t)<n.washGaps)continue;const i=stable01(e.x,e.y,101+t),l=stable01(e.x,e.y,202+t),f=stableNoise(e.x,e.y,303+t)*o*.22,c=stableNoise(e.x,e.y,404+t)*a*.22,d=o*(.04+.14*i),g=a*(.04+.14*l),u=o*r,h=a*r;refCtx.fillRect(e.x*o+d-u+f,e.y*a+g-h+c,o-2*d+2*u,a-2*g+2*h)}}refCtx.restore()}function stable01(e,t,r){const n=43758.5453*Math.sin(12.9898*e+78.233*t+37.719*r);return n-Math.floor(n)}function drawWordCells(e,t,r){const n=4e3/e.cols,o=5e3/e.rows;refCtx.fillStyle="rgb(255,0,0)",refCtx.strokeStyle="rgb(255,0,0)",refCtx.lineWidth=Math.max(1,.09*Math.min(n,o)),refCtx.lineCap="round",refCtx.lineJoin="round";for(const e of t)drawLetterInCell(e.char,e.x*n,e.y*o,n,o,r,e.index)}function drawLetterInCell(e,t,r,n,o,a,s){if(" "===e)return;const i=Math.min(n,o)*RangedLetterScale(a,s),l=stableNoise(t,r,s+1)*n*.1,f=stableNoise(t,r,s+2)*o*.1,c=.05*stableNoise(t,r,s+3);refCtx.save(),refCtx.translate(t+.5*n+l,r+.54*o+f),refCtx.rotate(c),refCtx.font=`${i}px ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace`,refCtx.textAlign="center",refCtx.textBaseline="middle",refCtx.fillText(e,0,0),refCtx.restore()}function RangedLetterScale(e,t){return e.grid.letterScale}function darkenedBgColor(e=.1){return[Math.max(0,palette.bg[0]-e),Math.max(0,palette.bg[1]-e),Math.max(0,palette.bg[2]-e),palette.bg[3]??1]}function drawUnderline(e){const t=4e3/e.grid.cols,r=5e3/e.grid.rows,n=e.cells.filter(e=>" "!==e.char);if(!n.length)return;refCtx.save(),refCtx.strokeStyle="rgb(255,0,0)",refCtx.lineWidth=Math.max(.6,.08*Math.min(t,r)),refCtx.lineCap="round",refCtx.lineJoin="round";const o=n[0],a=n[n.length-1],s=o.x*t+.15*t,i=o.y*r+.84*r,l=a.x*t+.85*t,f=a.y*r+.84*r,c=l-s,d=f-i,g=Math.max(1e-4,Math.sqrt(c*c+d*d)),u=-d/g,h=c/g,x=.28*Math.min(t,r);refCtx.beginPath(),refCtx.moveTo(s+u*x,i+h*x),refCtx.lineTo(l+u*x+stableNoise(l,f,9)*t*.25,f+h*x+stableNoise(s,i,10)*r*.25),refCtx.stroke(),refCtx.restore()}function drawStrikethrough(e){const t=4e3/e.grid.cols,r=5e3/e.grid.rows,n=e.cells.filter(e=>" "!==e.char);if(!n.length)return;const o=n[0],a=n[n.length-1],s=o.x*t+.15*t,i=o.y*r+.5*r,l=a.x*t+.85*t,f=a.y*r+.5*r;refCtx.save(),refCtx.strokeStyle="rgb(255,0,0)",refCtx.lineWidth=Math.max(.6,.08*Math.min(t,r)),refCtx.lineCap="round",refCtx.lineJoin="round",refCtx.beginPath(),refCtx.moveTo(s+stableNoise(s,i,21)*t*.18,i+stableNoise(s,i,22)*r*.18),refCtx.lineTo(l+stableNoise(l,f,23)*t*.18,f+stableNoise(l,f,24)*r*.18),refCtx.stroke(),refCtx.restore()}function drawCircleAroundWord(e){const t=wordBox(e),r=.5*(t.x1+t.x2),n=.5*(t.y1+t.y2),o=.62*Math.abs(t.x2-t.x1)+4e3/e.grid.cols,a=.62*Math.abs(t.y2-t.y1)+5e3/e.grid.rows,s=.35*stableNoise(r,n,4),i=refCtx.lineWidth,l=refCtx.strokeStyle;refCtx.strokeStyle="rgb(255,0,0)",refCtx.lineCap="round";const f=stableNoise(r,n,999),c=1+Math.floor(5*f);for(let e=0;e<c;e++){const t=1e3+137*e,l=stableNoise(r,n,t+1),f=stableNoise(r,n,t+2),c=stableNoise(r,n,t+3),d=stableNoise(r,n,t+4),g=stableNoise(r,n,t+5),u=.94+.18*g,h=.18+.95*stableNoise(r,n,t+6),x=.35+.65*d,m=4e3*l*.006,C=5e3*f*.006,b=o*u*(1+.04*c),w=a*u*(1-.04*c),p=g*Math.PI*2,R=stableNoise(r,n,t+7)<.45?.55+.35*stableNoise(r,n,t+8):1,v=p+2*Math.PI*R;refCtx.save(),refCtx.globalAlpha*=x,refCtx.lineWidth=i*h,refCtx.beginPath(),refCtx.ellipse(r+m,n+C,b,w,s+.22*d,p,v),refCtx.stroke(),refCtx.restore()}refCtx.lineWidth=i,refCtx.strokeStyle=l}function drawGridAroundLetters(e,t){const r=4e3/e.grid.cols,n=5e3/e.grid.rows,o=t.filter(e=>" "!==e.char);if(o.length){refCtx.save(),refCtx.strokeStyle="rgb(255,0,0)",refCtx.lineWidth=Math.max(.5,.045*Math.min(r,n)),refCtx.lineCap="square",refCtx.lineJoin="miter";for(const t of o){const o=t.x*r,a=t.y*n,s=.025*Math.min(r,n),i=t.index+1e3*e.washSeed;refCtx.beginPath(),refCtx.rect(o+stableNoise(t.x,t.y,i+1)*s,a+stableNoise(t.x,t.y,i+2)*s,r+stableNoise(t.x,t.y,i+3)*s,n+stableNoise(t.x,t.y,i+4)*s),refCtx.stroke()}refCtx.restore()}}function drawSquareAroundWord(e){const t=expandedWordBox(e,.22),r=Math.min(4e3/e.grid.cols,5e3/e.grid.rows);refCtx.save(),refCtx.strokeStyle="rgb(255,0,0)",refCtx.lineWidth=Math.max(.6,.08*r),refCtx.lineCap="round",refCtx.lineJoin="round";const n=.12*r;refCtx.beginPath(),refCtx.moveTo(t.x1+stableNoise(t.x1,t.y1,301)*n,t.y1+stableNoise(t.x1,t.y1,302)*n),refCtx.lineTo(t.x2+stableNoise(t.x2,t.y1,303)*n,t.y1+stableNoise(t.x2,t.y1,304)*n),refCtx.lineTo(t.x2+stableNoise(t.x2,t.y2,305)*n,t.y2+stableNoise(t.x2,t.y2,306)*n),refCtx.lineTo(t.x1+stableNoise(t.x1,t.y2,307)*n,t.y2+stableNoise(t.x1,t.y2,308)*n),refCtx.closePath(),refCtx.stroke(),refCtx.restore()}function drawCrossThroughWord(e){const t=expandedWordBox(e,.12),r=Math.min(4e3/e.grid.cols,5e3/e.grid.rows);refCtx.sav+Xe(),refCtx.strokeStyle="rgb(255,0,0)",refCtx.lineWidth=Math.max(.6,.08*r),refCtx.lineCap="round",refCtx.lineJoin="round",drawNoisyLine(t.x1,t.y1,t.x2,t.y2,r,401),drawNoisyLine(t.x2,t.y1,t.x1,t.y2,r,411),refCtx.restore()}function drawPlusThroughWord(e){const t=expandedWordBox(e,.1),r=Math.min(4e3/e.grid.cols,5e3/e.grid.rows),n=.5*(t.x1+t.x2),o=.5*(t.y1+t.y2);refCtx.save(),refCtx.strokeStyle="rgb(255,0,0)",refCtx.lineWidth=Math.max(.6,.08*r),refCtx.lineCap="round",refCtx.lineJoin="round",drawNoisyLine(t.x1,o,t.x2,o,r,501),drawNoisyLine(n,t.y1,n,t.y2,r,511),refCtx.restore()}function drawBackgroundWashReference(e,t){clearReferenceToBlack(),refCtx.save(),useStructureSpace(),refCtx.globalAlpha=e.alpha*t,refCtx.fillStyle="rgb(0,0,255)",refCtx.strokeStyle="rgb(0,0,255)",refCtx.lineCap="round",refCtx.lineJoin="round";const r=e.y+.42*e.h;for(let n=0;n<44;n++){const o=n/Math.max(1,43),a=e.x+e.w*o+stableNoise(e.seed,n,11)*e.w*.025,s=Math.sin(o*Math.PI),i=r-e.h*(.25+.75*s+.45*stable01(e.seed,n,12)),l=r+e.h*(.15+.55*s+.75*stable01(e.seed,n,13)),f=e.w*(.018+.045*stable01(e.seed,n,14));drawVerticalPaintColumn(a,i,l,f,e.seed+91*n,t),stable01(e.seed,n,77)<e.dripChance&&drawPaintDrip(a+stableNoise(e.seed,n,21)*f,l-.05*e.h,e.h*(.35+1.4*stable01(e.seed,n,22)),e.seed+200*n)}for(let n=0;n<9;n++){const o=r+stableNoise(e.seed,n,301)*e.h*.45;refCtx.globalAlpha=e.alpha*t*.22,refCtx.lineWidth=e.h*(.025+.045*stable01(e.seed,n,302)),drawNoisyHorizontalStroke(e.x+stableNoise(e.seed,n,303)*e.w*.05,o,e.x+e.w+stableNoise(e.seed,n,304)*e.w*.05,o+stableNoise(e.seed,n,305)*e.h*.18,e.seed+400*n)}refCtx.restore()}function drawVerticalPaintColumn(e,t,r,n,o,a){refCtx.beginPath();for(let a=0;a<=12;a++){const s=t+(r-t)*(a/12),i=e-.5*n+stableNoise(o,a,31)*n*.75;0===a?refCtx.moveTo(i,s):refCtx.lineTo(i,s)}for(let a=12;a>=0;a--){const s=t+(r-t)*(a/12),i=e+.5*n+stableNoise(o,a,41)*n*.75;refCtx.lineTo(i,s)}refCtx.closePath(),refCtx.fill(),refCtx.save(),refCtx.globalAlpha*=.35;const s=2+Math.floor(5*stable01(o,1,55));for(let a=0;a<s;a++){const s=e+stableNoise(o,a,61)*n*.45;refCtx.lineWidth=n*(.08+.18*stable01(o,a,62)),refCtx.beginPath(),refCtx.moveTo(s,t+stableNoise(o,a,63)*n),refCtx.lineTo(s+stableNoise(o,a,64)*n*.45,r-stable01(o,a,65)*n),refCtx.stroke()}refCtx.restore(),refCtx.save(),refCtx.globalCompositeOperation="destination-out";for(let s=0;s<22;s++){const i=stable01(o,s,71)<.5?-1:1,l=t+stable01(o,s,72)*(r-t),f=e+i*n*(.3+.45*stable01(o,s,73));refCtx.globalAlpha=a*(.04+.14*stable01(o,s,74)),refCtx.beginPath(),refCtx.ellipse(f,l,n*(.15+.55*stable01(o,s,75)),n*(.25+1.25*stable01(o,s,76)),stableNoise(o,s,77),0,2*Math.PI),refCtx.fill()}refCtx.restore()}function drawNoisyHorizontalStroke(e,t,r,n,o){refCtx.beginPath();for(let a=0;a<=18;a++){const s=a/18,i=e+(r-e)*s,l=t+(n-t)*s+5e3*stableNoise(o,a,91)*.006;0===a?refCtx.moveTo(i,l):refCtx.lineTo(i,l)}refCtx.stroke()}function drawPainterlyBlob(e,t,r,n,o,a){const s=[];for(let a=0;a<28;a++){const i=a/28*Math.PI*2,l=1+.12*stableNoise(o,a,31)+.06*stableNoise(o,a,32)+.06*Math.sin(2*i+o)+.04*Math.sin(5*i+.37*o);s.push({x:e+Math.cos(i)*r*.5*l,y:t+Math.sin(i)*n*.5*l})}refCtx.beginPath();for(let e=0;e<s.length;e++){const t=s[(e-1+s.length)%s.length],r=s[e],n=s[(e+1)%s.length],o={x:.5*(t.x+r.x),y:.5*(t.y+r.y)},a={x:.5*(r.x+n.x),y:.5*(r.y+n.y)};0===e&&refCtx.moveTo(o.x,o.y),refCtx.quadraticCurveTo(r.x,r.y,a.x,a.y)}refCtx.closePath(),refCtx.fill(),refCtx.save(),refCtx.globalCompositeOperation="destination-out",refCtx.globalAlpha=.1*a;for(let s=0;s<160;s++){const i=stable01(o,s,41)*Math.PI*2,l=Math.sqrt(stable01(o,s,42)),f=Math.cos(i)*l,c=Math.sin(i)*l,d=e+f*r*.48,g=t+c*n*.48,u=Math.min(1,Math.sqrt(f*f+c*c)),h=Math.pow(u,2.2),x=r*(.004+.09*h*stable01(o,s,43)),m=n*(.003+.05*h*stable01(o,s,44));refCtx.globalAlpha=(.01+.18*h)*a,refCtx.beginPath(),refCtx.ellipse(d,g,x,m,stableNoise(o,s,45)*Math.PI,0,2*Math.PI),refCtx.fill()}refCtx.restore()}function drawPaintDrip(e,t,r,n){const o=.045*r;refCtx.beginPath(),refCtx.moveTo(e,t);for(let a=1;a<=5;a++){const s=a/5;refCtx.lineTo(e+stableNoise(n,a,51)*o,t+r*s)}refCtx.lineWidth=Math.max(1,4.8),refCtx.lineCap="round",refCtx.strokeStyle="rgb(0,0,255)",refCtx.stroke()}function drawNoisyLine(e,t,r,n,o,a){const s=.16*o;refCtx.beginPath(),refCtx.moveTo(e+stableNoise(e,t,a+1)*s,t+stableNoise(e,t,a+2)*s),refCtx.lineTo(r+stableNoise(r,n,a+3)*s,n+stableNoise(r,n,a+4)*s),refCtx.stroke()}function expandedWordBox(e,t=.15){const r=wordBox(e),n=4e3/e.grid.cols,o=5e3/e.grid.rows;return{x1:r.x1-n*t,y1:r.y1-o*t,x2:r.x2+n*t,y2:r.y2+o*t}}function wordBox(e){const t=4e3/e.grid.cols,r=5e3/e.grid.rows,n=e.cells.map(e=>e.x*t),o=e.cells.map(e=>e.y*r);return{x1:Math.min(...n),y1:Math.min(...o),x2:Math.max(...n)+t,y2:Math.max(...o)+r}}function stableNoise(e,t,r){const n=43758.5453*Math.sin(12.9898*e+78.233*t+37.719*r);return n-Math.floor(n)-.5}function run(){if(renderLoopRunning=!1,isResizing||width<MIN_GL_SIZE||height<MIN_GL_SIZE||!refTexture||frameBuffers.length<2)return void requestRun();maybeFetchMoreWords();const e=state.placements[state.activePlacementIndex];if(!e)return renderScreen(),state.frame%30==0&&sampleVisibleCanvasHealth(),void(window.__RESIDUAL_NOTES_RENDERED__||(window.__RESIDUAL_NOTES_RENDERED__=!0,window.dispatchEvent(new Event("residual-notes:rendered"))));const t=settings.pauseFrames+settings.revealFrames,r=state.frame%t;let n=0,o=!1;if(r<settings.pauseFrames)clearReferenceToBlack();else{const t=r-settings.pauseFrames;n=Math.min(1,(t+1)*settings.revealSpeed/settings.revealFrames),o=t>=settings.revealFrames-1,drawPlacementReference(e,n)}updateReferenceTexture(),renderWash(e),renderScreen(),(o||r===t-1)&&state.activePlacementIndex++,state.frame++,requestRun()}function renderWash(e){const t=frameBufferId,r=1^frameBufferId;frameBufferId=r,useProgram(washProgram),gl.bindFramebuffer(gl.FRAMEBUFFER,frameBuffers[r].buffer),assertFramebufferHealthy("renderWash")&&(gl.viewport(0,0,width,height),gl.clearColor(0,0,0,1),gl.clear(gl.COLOR_BUFFER_BIT),gl.activeTexture(gl.TEXTURE0),gl.bindTexture(gl.TEXTURE_2D,frameBuffers[t].texture),gl.uniform1i(gl.getUniformLocation(washProgram,"previousFrame"),0),gl.activeTexture(gl.TEXTURE1),gl.bindTexture(gl.TEXTURE_2D,refTexture),gl.uniform1i(gl.getUniformLocation(washProgram,"referenceMask"),1),gl.uniform1f(gl.getUniformLocation(washProgram,"frame"),state.frame),gl.uniform1f(gl.getUniformLocation(washProgram,"dirx"),e.dirx),gl.uniform1f(gl.getUniformLocation(washProgram,"diry"),e.diry),gl.uniform1f(gl.getUniformLocation(washProgram,"washStrength"),e.washStrength??settings.washStrength),gl.uniform1f(gl.getUniformLocation(washProgram,"smudgeChance"),e.smudgeChance??settings.smudgeChance),gl.uniform1f(gl.getUniformLocation(washProgram,"textureAmount"),settings.textureAmount),gl.uniform4fv(gl.getUniformLocation(washProgram,"bgColor"),palette.bg),gl.uniform4fv(gl.getUniformLocation(washProgram,"inkColor"),e.color),gl.uniform4fv(gl.getUniformLocation(washProgram,"highlightColor"),"backgroundWash"===e.type?e.color:palette.highlight),gl.uniform2f(gl.getUniformLocation(washProgram,"resolution"),width,height),gl.uniform1f(gl.getUniformLocation(washProgram,"grainSeed"),GRAIN_SEED),gl.uniform1f(gl.getUniformLocation(washProgram,"baseGrainAmount"),settings.baseGrainAmount),gl.uniform1f(gl.getUniformLocation(washProgram,"baseMottleAmount"),settings.baseMottleAmount),gl.drawArrays(gl.TRIANGLE_STRIP,0,4))}function sampleVisibleCanvasHealth(){if(!gl||gl.isContextLost())return;const e=new Uint8Array(4);gl.bindFramebuffer(gl.FRAMEBUFFER,null),gl.readPixels(Math.floor(.5*width),Math.floor(.5*height),1,1,gl.RGBA,gl.UNSIGNED_BYTE,e);e[0]+e[1]+e[2]<8&&state.frame>20?blackFrameCount++:blackFrameCount=0,blackFrameCount>90&&queueHardRebuild("visible canvas stayed black"),state.activePlacementIndex>0&&state.frame-lastProgressFrame>240&&queueHardRebuild("render loop appears stuck"),lastProgressFrame=state.frame}function renderScreen(){useProgram(screenProgram),gl.bindFramebuffer(gl.FRAMEBUFFER,null),gl.viewport(0,0,width,height),gl.clearColor(0,0,0,1),gl.clear(gl.COLOR_BUFFER_BIT),gl.activeTexture(gl.TEXTURE0),gl.bindTexture(gl.TEXTURE_2D,frameBuffers[frameBufferId].texture),gl.uniform1i(gl.getUniformLocation(screenProgram,"buffer"),0),gl.drawArrays(gl.TRIANGLE_STRIP,0,4)}function useProgram(e){gl.useProgram(e);const t=gl.getAttribLocation(e,"pos");gl.enableVertexAttribArray(t),gl.bindBuffer(gl.ARRAY_BUFFER,vertexBuffer),gl.vertexAttribPointer(t,3,gl.FLOAT,!1,0,0)}function createProgram(e,t){const r=gl.createProgram(),n=createShader(`#version 300 es\n${e}`,gl.VERTEX_SHADER),o=createShader(`#version 300 es\nprecision highp float;\n${t}`,gl.FRAGMENT_SHADER);return gl.attachShader(r,n),gl.attachShader(r,o),gl.linkProgram(r),gl.getProgramParameter(r,gl.LINK_STATUS)||console.error(gl.getProgramInfoLog(r)),r}function createShader(e,t){const r=gl.createShader(t);return gl.shaderSource(r,e),gl.compileShader(r),gl.getShaderParameter(r,gl.COMPILE_STATUS)||console.error(gl.getShaderInfoLog(r)),r}function createVertexBuffer(){const e=gl.createBuffer();return gl.bindBuffer(gl.ARRAY_BUFFER,e),gl.bufferData(gl.ARRAY_BUFFER,new Float32Array([-1,1,0,-1,-1,0,1,1,0,1,-1,0]),gl.STATIC_DRAW),e}function createFrameBuffer(e,t,r=null){e=Math.max(MIN_GL_SIZE,Math.floor(e)),t=Math.max(MIN_GL_SIZE,Math.floor(t));const n=gl.createFramebuffer(),o=createTexture(e,t,r);gl.bindFramebuffer(gl.FRAMEBUFFER,n),gl.framebufferTexture2D(gl.FRAMEBUFFER,gl.COLOR_ATTACHMENT0,gl.TEXTURE_2D,o,0);const a=gl.checkFramebufferStatus(gl.FRAMEBUFFER);return a!==gl.FRAMEBUFFER_COMPLETE&&console.warn("Framebuffer incomplete:",a,e,t),gl.bindFramebuffer(gl.FRAMEBUFFER,null),{buffer:n,texture:o}}function createTexture(e,t,r=null){e=Math.max(MIN_GL_SIZE,Math.floor(e)),t=Math.max(MIN_GL_SIZE,Math.floor(t));const n=gl.createTexture();return gl.bindTexture(gl.TEXTURE_2D,n),gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.NEAREST),gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.NEAREST),gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_S,gl.CLAMP_TO_EDGE),gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_T,gl.CLAMP_TO_EDGE),r&&r.width>0&&r.height>0?gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,gl.RGBA,gl.UNSIGNED_BYTE,r):gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,e,t,0,gl.RGBA,gl.UNSIGNED_BYTE,null),n}function updateReferenceTexture(){refTexture&&(!ref||ref.width<MIN_GL_SIZE||ref.height<MIN_GL_SIZE||(gl.bindTexture(gl.TEXTURE_2D,refTexture),gl.texSubImage2D(gl.TEXTURE_2D,0,0,0,gl.RGBA,gl.UNSIGNED_BYTE,ref)))}function rgb(e){return`rgb(${Math.floor(255*e[0])}, ${Math.floor(255*e[1])}, ${Math.floor(255*e[2])})`}function clamp255(e){return Math.max(0,Math.min(255,e))}function handleKey(e){"s"===e.key&&savePNG(),"m"===e.key&&(settings.showReference=!settings.showReference,ref.style.display=settings.showReference?"block":"none"),"c"===e.key&&setCustomRenderSize(),"p"===e.key.toLowerCase()&&setCustomRpcUrl()}function savePNG(){renderScreen();const e=document.createElement("a");e.download=`word-field-wash-${HASH.slice(2,10)}-${width}x${height}.png`,e.href=view.toDataURL("image/png"),e.click()}function restart(){restartAfterResize()}init();
0xd2af9f3e…0475·#25,309,101·0xf05ae6ee…c44480
RlMissing chunk`RnChunk too large`RnChunk too large`a /V[PPPV[``_____ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef`ghijklmnopqrstuvwxyz0123456789+/PPPPPV[`@Qc?M1}`data:image/svg+xml;base64,"description":"Residual Notes is` an evolving public canvas built`" from permanently stored written`B"animation_url":"data:text/html;`Pm"attributes":[`{"trait_type":"Notes","value":{"trait_type":"Accepting notes",`data:application/json;base64,<!doctype html><html><head><meta name="viewport" content="w`1idth=device-width,initial-scale=`Q<style>html,body{margin:0;width:`100%;height:100%;overflow:hidden`(;background:#111;}#view, #ref {m`Hargin:0 auto;aspect-ratio: 4 / 5`h;width: min(100vw, calc(100vh * `4 / 5));height: min(100vh, calc(`100vw * 5 / 4));}</style><canvas id='view'></canvas><canv` <svg width="800" height="1000" viewBox="0 0 800 1000" fill="none` " xmlns="http://www.w3.org/2000/`@<style>.sub{font:32px monospace;`e;}.key{font:24px monospace;fill:;}.title{font:48px monospace;fil<rect width="800" height="1000" ` <text x="24" y="54" class="sub"><text x="24" y="116" class="titl`<text x="24" y="874" class="key"<text x="24" y="919" class="key"`<text x="24" y="964" class="key"` V[sconst INITIAL_WORDS=``let WORDS=[...INITIAL_WORDS];V[nconst TOKEN_ID=`Rpconst TOKEN_NAME=`xPtlet CONTRACT_ADDRESS=`XPllet RPC_URLS=`Pnlet WORD_COUNT=`const INLINE_WORD_LIMIT=const FETCH_BATCH_SIZE=Pllet palette='`PPPPPPPPPPPPV[_`
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;const RESET_COOLDOWN_MS=700,LOW_ACTIVITY_START_MS=650,LOW_ACTIVITY_FULL_MS=1600,COMPRESSION_PROGRESS_TIMEOUT_MS=1400,VISUAL_FREEZE_TIMEOUT_MS=1800,MAX_CONSECUTIVE_STALLS_BEFORE_HARD_RESET=2,ART_HASH=normalizeEthHash(window.ART_HASH),ART_PALETTES=window.ART_PALETTES;function normalizeEthHash(t){const e="0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";if("string"!=typeof t)return e;const a=t.trim().toLowerCase();return/^0x[0-9a-f]{64}$/.test(a)?a:e}function createHashRng(t){const e=normalizeEthHash(t).slice(2);let a=parseInt(e.slice(0,8),16)>>>0,n=parseInt(e.slice(8,16),16)>>>0,o=parseInt(e.slice(16,24),16)>>>0,s=parseInt(e.slice(24,32),16)>>>0;return 0===(a|n|o|s)&&(a=305419896,n=2596069104,o=4275878552,s=2271560481),function(){let t=a+n+s|0;return s=s+1|0,a=n^n>>>9,n=o+(o<<3)|0,o=o<<21|o>>>11,o=o+t|0,(t>>>0)/4294967296}}function hashUnitAt(t){const e=ART_HASH.slice(2),a=8*t%(e.length-8),n=e.slice(a,a+8);return parseInt(n,16)/4294967295}function makeSeededRandom(t){return function(e,a){return e+t()*(a-e)}}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,e,a){return Number.isFinite(t)?Math.max(e,Math.min(a,t)):e}function finiteOr(t,e=0){return Number.isFinite(t)?t:e}function safeParam(t,e,a,n,o,s,i=a){if(!t)return;const r=clamp(finiteOr(e,i),a,n);t.setTargetAtTime(r,o,s)}function lerp(t,e,a){return t+(e-t)*a}function hslToHex(t,e,a){a/=100;const n=e=>(e+t/30)%12,o=(e/=100)*Math.min(a,1-a),s=t=>a-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 e=hslToHex(t(0,360),t(65,92),t(38,58)),a=t(0,360);let n=(a+t(70,220))%360,o=(a+t(140,300))%360;return t(0,1)<.35&&(n=(a+t(20,60))%360),t(0,1)<.25&&(o=(n+t(20,80))%360),{bg:e,top:hslToHex(a,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(e){const a=43758.5453123*Math.sin(12.9898*e+78.233*t);return a-Math.floor(a)}}function buildPolyline(t){if(!t.length)return"";let e=`M ${t[0].x.toFixed(2)} ${t[0].y.toFixed(2)}`;for(let a=1;a<t.length;a++)e+=` L ${t[a].x.toFixed(2)} ${t[a].y.toFixed(2)}`;return e}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 e=`M ${t[0].x.toFixed(2)} ${t[0].y.toFixed(2)}`;for(let a=0;a<t.length-1;a++){const n=t[Math.max(0,a-1)],o=t[a],s=t[a+1],i=t[Math.min(t.length-1,a+2)],r=.22,u=o.x+(s.x-n.x)*r,h=o.y+(s.y-n.y)*r,c=s.x-(i.x-o.x)*r,m=s.y-(i.y-o.y)*r;e+=` C ${u.toFixed(2)} ${h.toFixed(2)}, ${c.toFixed(2)} ${m.toFixed(2)}, ${s.x.toFixed(2)} ${s.y.toFixed(2)}`}return e}function makeSoftWaveLine(t,e,a,n,o={}){const s=makeNoise(a),i=[],r=o.steps||14,u=n(.8,2.2),h=n(2,4.5),c=n(4,8),m=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 a=0;a<=r;a++){const o=a/r,w=o*W,g=t+(Math.sin(o*Math.PI*u+m)*e*n(.55,1)+Math.sin(o*Math.PI*h+d)*e*n(.1,.3)+Math.sin(o*Math.PI*c+l)*e*n(.03,.14)+(s(o*n(1.5,4.5))-.5)*e*n(.05,.16))+(o-.5)*p+Math.sin(o*Math.PI)*f;i.push({x:w,y:g})}return i}function makeRibbonBand(t,e){const{yBase:a,thickness:n,amp:o,seed:s}=t,i=makeSoftWaveLine(a,o,s,e,{steps:14}),r=[],u=makeNoise(s+100),h=e(.8,2.6),c=e(-Math.PI,Math.PI);for(let t=0;t<i.length;t++){const a=i[t],o=t/(i.length-1),s=n*(.9+.22*Math.sin(o*Math.PI*h+c))+(u(3.2*o)-.5)*n*.08,m=Math.sin(o*Math.PI*e(1.2,3.5)+e(-Math.PI,Math.PI))*n*.08;r.push({x:a.x+m,y:a.y+s})}return{top:i,bottom:r}}function ribbonPath(t,e){const a=buildSmoothPath(t),n=[...e].reverse(),o=buildSmoothPath(n).replace(/^M[^CML]*/,"");return`${a} 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)),e=getSeededPalette(t),a=[];a.push(`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${W} ${H}" width="${W}" height="${H}">`),a.push(`<rect width="${W}" height="${H}" fill="${e.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?e.top:1===s?e.extra:e.top;if(a.push(`<path d="${ribbonPath(i.top,i.bottom)}" fill="${r}"/>`),t(0,1)<.92){const n=i.top.map((e,a)=>{const n=i.bottom[a];return{x:lerp(e.x,n.x,t(.45,.7)),y:lerp(e.y,n.y,t(.45,.7))}});a.push(`<path d="${linePath(n)}" fill="none" stroke="${e.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=[e.mid,e.low,e.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);a.push(`<path d="${ribbonPath(h.top,h.bottom)}" fill="${u}"/>`);const c=t(0,1)<.55?1:2;for(let n=0;n<c;n++){const o=(n+1)/(c+1),s=h.top.map((t,e)=>{const a=h.bottom[e];return{x:lerp(t.x,a.x,o),y:lerp(t.y,a.y,o)}});a.push(`<path d="${linePath(s)}" fill="none" stroke="${e.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))),c=[e.low,e.mid];for(let n=0;n<h;n++){const o=t(.07*H,.14*H),s=t(.025*H,.07*H),i=n<c.length?c[n]:c[n%c.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)}));a.push(`<path d="${ribbonPath(r.top,h)}" fill="${i}"/>`);const m=t(0,1)<.7?1:2;for(let n=0;n<m;n++){const o=(n+1)/(m+1),s=r.top.map((e,a)=>{const n=h[a],s=o*t(.7,.95);return{x:lerp(e.x,n.x,s),y:lerp(e.y,n.y,s)}});a.push(`<path d="${linePath(s)}" fill="none" stroke="${e.bg}" stroke-width="${t(.007*H,.015*H).toFixed(2)}" stroke-linecap="round" stroke-linejoin="round"/>`)}u-=o*t(.48,.7)}a.push("</svg>");const m=new Image;m.onload=()=>{sctx.clearRect(0,0,W,H),sctx.drawImage(m,0,0,W,H),resetCompressionStateForFreshStart(),ready=!0,drawDisplay(),queueCompressionStart(0)},m.src="data:image/svg+xml;charset=utf-8,"+encodeURIComponent(a.join(""))}function canvasToBlob(t,e){return new Promise((a,n)=>{t.toBlob(t=>{t?a(t):n(new Error("JPEG export failed"))},"image/jpeg",e)})}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 e=2166136261;for(let a=0;a<t.length;a+=16)e^=t[a]|t[a+1]<<8|t[a+2]<<16|t[a+3]<<24,e=Math.imul(e,16777619);return(e>>>0).toString(16)}function checkForVisualFreeze(){const t=performance.now(),e=getVisualSignature();if(e!==lastVisualSig)return lastVisualSig=e,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 e=t-lastVisualChangeAt;return e<=650?0:clamp((e-650)/950,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 e=performance.now();e-lastHardResetAt<700||(lastHardResetAt=e,compressionLoopToken++,clearTimeout(compressionTimer),compressionBusy=!1,ready=!1,consecutiveStalls=0,lastVisualSig="",lastVisualChangeAt=e,lastCompressionProgressAt=e,lastCompressionStartAt=e,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 e=.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 e=Math.pow(e,1.15),e+=.9*burst,clamp(e,.03,1)}function qualityFromDepth(t,e){return clamp(.92-.72*Math.pow(t,1.15)-.2*Math.pow(t,3.8)-.12*e,8e-5,.95)}function scaleFromDepth(t,e){return clamp(1-.88*Math.pow(t,1)-.1*Math.pow(t,3)-.08*e,.0022,1)}function passesFromDepth(t,e){const a=.8*t+.6*e;return a>1.05?7:a>.88?6:a>.7?5:a>.5?4:a>.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,e){const a=.001*t;Math.random()<.02&&(burst=Math.max(burst,.5*Math.random()+.5)),burst*=Math.pow(.9,60*e),targetDepth=computeTargetDepth(a),lowActivityScore=getLowActivityAmount(),lowActivityScore>0&&(activityBoost=Math.max(activityBoost,lowActivityScore),burst=Math.max(burst,.12+.22*lowActivityScore)),audioBurstTone*=Math.pow(.82,60*e),audioBurstPitch=lerp(audioBurstPitch,0,1-Math.pow(.86,60*e)),audioTransient*=Math.pow(.78,60*e),activityBoost*=Math.pow(.88,60*e),depthVel+=.06*(targetDepth-depth)*e*60,depthVel*=Math.pow(.84,60*e),depth+=depthVel*e*60,depth=clamp(depth,0,1),audioImpact*=Math.pow(.84,60*e),audioJerk*=Math.pow(.86,60*e),audioThump*=Math.pow(.8,60*e),audioFreak*=Math.pow(.72,60*e),audioChaos*=Math.pow(.78,60*e),audioSlam*=Math.pow(.55,60*e),audioDownsample*=Math.pow(.64,60*e),audioCrush=lerp(audioCrush,0,1-Math.pow(.9,60*e)),audioDensity=lerp(audioDensity,0,1-Math.pow(.92,60*e))}function applyBlockDrift(t,e){if(e<=.001)return;const a=Math.random()<.8,n=a?Math.max(10,Math.round(H*(.035+.06*e))):Math.max(10,Math.round(W*(.035+.06*e))),o=a?Math.max(2,Math.round(W*(.004+.012*e))):Math.max(2,Math.round(H*(.004+.012*e))),s=(Math.random()<.5?-1:1)*o;if(t.save(),t.imageSmoothingEnabled=!1,t.globalCompositeOperation=["color","color-burn"][Math.floor(2*Math.random())],a){const e=Math.floor(Math.random()*Math.max(1,H-n));if(s>0){const a=W-s;a>1&&t.drawImage(workCanvas,0,e,a,n,s,e,a,n)}else{const a=-s,o=W-a;o>1&&t.drawImage(workCanvas,a,e,o,n,0,e,o,n)}}else{const e=Math.floor(Math.random()*Math.max(1,W-n));if(s>0){const a=H-s;a>1&&t.drawImage(workCanvas,e,0,n,a,e,s,n,a)}else{const a=-s,o=H-a;o>1&&t.drawImage(workCanvas,e,a,n,o,e,0,n,o)}}t.restore()}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 e=clamp(3.2*Math.abs(depthVel),0,1),a=depth,n=Math.max(activityBoost,getLowActivityAmount()),o=qualityFromDepth(a,e),s=clamp(scaleFromDepth(a,e)-.07*n,.0022,1),i=passesFromDepth(a,e)+(n>.45?1:0),r=reinjectFromDepth(a),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 c=clamp(5.5*h,0,1)*clamp(.35+.9*burst+.7*Math.abs(depthVel),0,1.5);c>.06&&(audioBurstTone=Math.max(audioBurstTone,c),audioTransient=Math.max(audioTransient,.9*c),audioBurstPitch=Math.max(audioBurstPitch,clamp(.35*c+.22*clamp(audioDownsample,0,1)+.18*clamp(audioFreak,0,1)+.12*Math.random(),0,1)));const m=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,m),audioChaos=Math.max(audioChaos,clamp(.7*m+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 e=0;e<i;e++){if(markCompressionProgress(),t!==compressionLoopToken)return void(compressionBusy=!1);const r=i<=1?0:e/(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,a)),a>.88?.0015:.0022,1),c=i<=1?0:Math.max(0,(e-1)/(i-1)),m=e<=0?1:clamp(s*(1-c*lerp(.18,.72,a)),a>.88?.0015:.0022,1),d=clamp((m-u)/Math.max(1e-4,m),0,1),p=clamp(1-u,0,1),f=clamp(.7*p+1.2*d+.2*r,0,1.6),w=clamp(1-u,0,1),g=Math.max(2,Math.round(W*u)),b=Math.max(2,Math.round(H*u));if(g<2||b<2||!Number.isFinite(g)||!Number.isFinite(b))throw new Error("Invalid tiny canvas size");tinyCanvas.width=g,tinyCanvas.height=b,tctx.imageSmoothingEnabled=!0,wctx.imageSmoothingEnabled=!1,tctx.clearRect(0,0,g,b),tctx.drawImage(l,0,0,g,b),wctx.clearRect(0,0,W,H),wctx.drawImage(tinyCanvas,0,0,g,b,0,0,W,H),markCompressionProgress();const M=clamp(o*(1-r*lerp(.25,.9,a)),a>.88?3e-5:8e-5,.95),x=.55*(1-u)+.45*(1-M);if(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)),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(x>.35){const t=clamp(x*(.55+.8*r),0,1);audioImpact=Math.max(audioImpact,t);const e=t*clamp(.45+.8*(1-u)+1.6*Math.abs(M-o),0,1.4);audioThump=Math.max(audioThump,e)}const C=clamp(1.6*(w-.35),0,1)*clamp(.45+.9*r+2.5*h,0,1.8);if(C>0&&(audioSlam=Math.max(audioSlam,C)),x>.52||h>.12&&r>.35){const t=clamp(1.8*(x-.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 P=clamp(.15+.95*a+.8*h+.35*r-.25*(1-u),0,1)*(x>.26?1:0);P>.94&&Math.random()<.01&&(applyBlockDrift(wctx,P),audioJerk=Math.max(audioJerk,.08*P));const v=await canvasToBlob(workCanvas,M);if(t!==compressionLoopToken)return void(compressionBusy=!1);const R=await blobToBitmap(v);if(t!==compressionLoopToken)return R.close?.(),void(compressionBusy=!1);wctx.clearRect(0,0,W,H),wctx.drawImage(R,0,0,W,H),R.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(e){if(t===compressionLoopToken)return console.error(e),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 e=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(e>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 e=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 ];\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 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 180 +\n burstPitch * 900 +\n transient * 1400 +\n downsample * 320;\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 + (1 - depth) * 0.012 + tone01 * 0.24;\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 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 * (0.18 + transient * 0.9 + freak * 0.15 + downsample * 0.22);\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"}),a=URL.createObjectURL(e);await audioCtx.audioWorklet.addModule(a),URL.revokeObjectURL(a),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 e=clamp(finiteOr(3.2*Math.abs(depthVel),0),0,1),a=clamp(finiteOr(toneControl,50)/100,0,1);safeParam(noiseNode.parameters.get("depth"),depth,0,1,t,.04,.2),safeParam(noiseNode.parameters.get("speed"),e,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"),a,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);const n=.34+.32*finiteOr(depth,.2)+.08*e+.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*a+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*a+100*(1-finiteOr(depth,.2))+20*e-90*finiteOr(audioCrush,0)-60*finiteOr(audioImpact,0)-50*finiteOr(audioThump,0)-120*finiteOr(audioFreak,0)+4200*finiteOr(audioDownsample,0);audioLP.frequency.setTargetAtTime(clamp(s,25,14e3),t,.02);const i=22-26*a+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 e=Math.min(.05,(t-lastNow)/1e3);lastNow=t,ready&&(stepMotion(t,e),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 e=t.key.toLowerCase();"a"===e?(t.preventDefault(),toggleAudio()):"s"===e&&(t.preventDefault(),saveCurrentImage())}),resize(),startCompressionLoop(),requestAnimationFrame(frame),lastCompressionProgressAt=performance.now(),lastVisualChangeAt=performance.now(),watchdogTick();
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="source-over",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()<.78?.018+Math.random()*(.05+.075*n):.07+Math.random()*(.14+.08*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()<.35,tctx.clearRect(0,0,s,i),tctx.drawImage(workCanvas,0,0,W,H,0,0,s,i),t.save(),t.globalCompositeOperation="source-over",t.imageSmoothingEnabled=!1,t.clearRect(0,0,W,H),t.drawImage(tinyCanvas,0,0,s,i,0,0,W,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();
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();
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;const RESET_COOLDOWN_MS=700,LOW_ACTIVITY_START_MS=650,LOW_ACTIVITY_FULL_MS=1600,COMPRESSION_PROGRESS_TIMEOUT_MS=1400,VISUAL_FREEZE_TIMEOUT_MS=1800,MAX_CONSECUTIVE_STALLS_BEFORE_HARD_RESET=2,ART_HASH=normalizeEthHash(window.ART_HASH),ART_PALETTES=window.ART_PALETTES;function normalizeEthHash(t){const e="0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";if("string"!=typeof t)return e;const a=t.trim().toLowerCase();return/^0x[0-9a-f]{64}$/.test(a)?a:e}function createHashRng(t){const e=normalizeEthHash(t).slice(2);let a=parseInt(e.slice(0,8),16)>>>0,n=parseInt(e.slice(8,16),16)>>>0,o=parseInt(e.slice(16,24),16)>>>0,s=parseInt(e.slice(24,32),16)>>>0;return 0===(a|n|o|s)&&(a=305419896,n=2596069104,o=4275878552,s=2271560481),function(){let t=a+n+s|0;return s=s+1|0,a=n^n>>>9,n=o+(o<<3)|0,o=o<<21|o>>>11,o=o+t|0,(t>>>0)/4294967296}}function hashUnitAt(t){const e=ART_HASH.slice(2),a=8*t%(e.length-8),n=e.slice(a,a+8);return parseInt(n,16)/4294967295}function makeSeededRandom(t){return function(e,a){return e+t()*(a-e)}}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,e,a){return Number.isFinite(t)?Math.max(e,Math.min(a,t)):e}function finiteOr(t,e=0){return Number.isFinite(t)?t:e}function safeParam(t,e,a,n,o,s,i=a){if(!t)return;const r=clamp(finiteOr(e,i),a,n);t.setTargetAtTime(r,o,s)}function lerp(t,e,a){return t+(e-t)*a}function hslToHex(t,e,a){a/=100;const n=e=>(e+t/30)%12,o=(e/=100)*Math.min(a,1-a),s=t=>a-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 e=hslToHex(t(0,360),t(65,92),t(38,58)),a=t(0,360);let n=(a+t(70,220))%360,o=(a+t(140,300))%360;return t(0,1)<.35&&(n=(a+t(20,60))%360),t(0,1)<.25&&(o=(n+t(20,80))%360),{bg:e,top:hslToHex(a,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(e){const a=43758.5453123*Math.sin(12.9898*e+78.233*t);return a-Math.floor(a)}}function buildPolyline(t){if(!t.length)return"";let e=`M ${t[0].x.toFixed(2)} ${t[0].y.toFixed(2)}`;for(let a=1;a<t.length;a++)e+=` L ${t[a].x.toFixed(2)} ${t[a].y.toFixed(2)}`;return e}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 e=`M ${t[0].x.toFixed(2)} ${t[0].y.toFixed(2)}`;for(let a=0;a<t.length-1;a++){const n=t[Math.max(0,a-1)],o=t[a],s=t[a+1],i=t[Math.min(t.length-1,a+2)],r=.22,u=o.x+(s.x-n.x)*r,h=o.y+(s.y-n.y)*r,c=s.x-(i.x-o.x)*r,m=s.y-(i.y-o.y)*r;e+=` C ${u.toFixed(2)} ${h.toFixed(2)}, ${c.toFixed(2)} ${m.toFixed(2)}, ${s.x.toFixed(2)} ${s.y.toFixed(2)}`}return e}function makeSoftWaveLine(t,e,a,n,o={}){const s=makeNoise(a),i=[],r=o.steps||14,u=n(.8,2.2),h=n(2,4.5),c=n(4,8),m=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 a=0;a<=r;a++){const o=a/r,w=o*W,g=t+(Math.sin(o*Math.PI*u+m)*e*n(.55,1)+Math.sin(o*Math.PI*h+d)*e*n(.1,.3)+Math.sin(o*Math.PI*c+l)*e*n(.03,.14)+(s(o*n(1.5,4.5))-.5)*e*n(.05,.16))+(o-.5)*p+Math.sin(o*Math.PI)*f;i.push({x:w,y:g})}return i}function makeRibbonBand(t,e){const{yBase:a,thickness:n,amp:o,seed:s}=t,i=makeSoftWaveLine(a,o,s,e,{steps:14}),r=[],u=makeNoise(s+100),h=e(.8,2.6),c=e(-Math.PI,Math.PI);for(let t=0;t<i.length;t++){const a=i[t],o=t/(i.length-1),s=n*(.9+.22*Math.sin(o*Math.PI*h+c))+(u(3.2*o)-.5)*n*.08,m=Math.sin(o*Math.PI*e(1.2,3.5)+e(-Math.PI,Math.PI))*n*.08;r.push({x:a.x+m,y:a.y+s})}return{top:i,bottom:r}}function ribbonPath(t,e){const a=buildSmoothPath(t),n=[...e].reverse(),o=buildSmoothPath(n).replace(/^M[^CML]*/,"");return`${a} 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)),e=getSeededPalette(t),a=[];a.push(`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${W} ${H}" width="${W}" height="${H}">`),a.push(`<rect width="${W}" height="${H}" fill="${e.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?e.top:1===s?e.extra:e.top;if(a.push(`<path d="${ribbonPath(i.top,i.bottom)}" fill="${r}"/>`),t(0,1)<.92){const n=i.top.map((e,a)=>{const n=i.bottom[a];return{x:lerp(e.x,n.x,t(.45,.7)),y:lerp(e.y,n.y,t(.45,.7))}});a.push(`<path d="${linePath(n)}" fill="none" stroke="${e.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=[e.mid,e.low,e.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);a.push(`<path d="${ribbonPath(h.top,h.bottom)}" fill="${u}"/>`);const c=t(0,1)<.55?1:2;for(let n=0;n<c;n++){const o=(n+1)/(c+1),s=h.top.map((t,e)=>{const a=h.bottom[e];return{x:lerp(t.x,a.x,o),y:lerp(t.y,a.y,o)}});a.push(`<path d="${linePath(s)}" fill="none" stroke="${e.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))),c=[e.low,e.mid];for(let n=0;n<h;n++){const o=t(.07*H,.14*H),s=t(.025*H,.07*H),i=n<c.length?c[n]:c[n%c.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)}));a.push(`<path d="${ribbonPath(r.top,h)}" fill="${i}"/>`);const m=t(0,1)<.7?1:2;for(let n=0;n<m;n++){const o=(n+1)/(m+1),s=r.top.map((e,a)=>{const n=h[a],s=o*t(.7,.95);return{x:lerp(e.x,n.x,s),y:lerp(e.y,n.y,s)}});a.push(`<path d="${linePath(s)}" fill="none" stroke="${e.bg}" stroke-width="${t(.007*H,.015*H).toFixed(2)}" stroke-linecap="round" stroke-linejoin="round"/>`)}u-=o*t(.48,.7)}a.push("</svg>");const m=new Image;m.onload=()=>{sctx.clearRect(0,0,W,H),sctx.drawImage(m,0,0,W,H),resetCompressionStateForFreshStart(),ready=!0,drawDisplay(),queueCompressionStart(0)},m.src="data:image/svg+xml;charset=utf-8,"+encodeURIComponent(a.join(""))}function canvasToBlob(t,e){return new Promise((a,n)=>{t.toBlob(t=>{t?a(t):n(new Error("JPEG export failed"))},"image/jpeg",e)})}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 e=2166136261;for(let a=0;a<t.length;a+=16)e^=t[a]|t[a+1]<<8|t[a+2]<<16|t[a+3]<<24,e=Math.imul(e,16777619);return(e>>>0).toString(16)}function checkForVisualFreeze(){const t=performance.now(),e=getVisualSignature();if(e!==lastVisualSig)return lastVisualSig=e,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 e=t-lastVisualChangeAt;return e<=650?0:clamp((e-650)/950,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 e=performance.now();e-lastHardResetAt<700||(lastHardResetAt=e,compressionLoopToken++,clearTimeout(compressionTimer),compressionBusy=!1,ready=!1,consecutiveStalls=0,lastVisualSig="",lastVisualChangeAt=e,lastCompressionProgressAt=e,lastCompressionStartAt=e,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 e=.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 e=Math.pow(e,1.15),e+=.9*burst,clamp(e,.03,1)}function qualityFromDepth(t,e){return clamp(.92-.72*Math.pow(t,1.15)-.2*Math.pow(t,3.8)-.12*e,8e-5,.95)}function scaleFromDepth(t,e){return clamp(1-.88*Math.pow(t,1)-.1*Math.pow(t,3)-.08*e,.0022,1)}function passesFromDepth(t,e){const a=.8*t+.6*e;return a>1.05?7:a>.88?6:a>.7?5:a>.5?4:a>.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,e){const a=.001*t;Math.random()<.02&&(burst=Math.max(burst,.5*Math.random()+.5)),burst*=Math.pow(.9,60*e),targetDepth=computeTargetDepth(a),lowActivityScore=getLowActivityAmount(),lowActivityScore>0&&(activityBoost=Math.max(activityBoost,lowActivityScore),burst=Math.max(burst,.12+.22*lowActivityScore)),audioBurstTone*=Math.pow(.82,60*e),audioBurstPitch=lerp(audioBurstPitch,0,1-Math.pow(.86,60*e)),audioTransient*=Math.pow(.78,60*e),activityBoost*=Math.pow(.88,60*e),depthVel+=.06*(targetDepth-depth)*e*60,depthVel*=Math.pow(.84,60*e),depth+=depthVel*e*60,depth=clamp(depth,0,1),audioImpact*=Math.pow(.84,60*e),audioJerk*=Math.pow(.86,60*e),audioThump*=Math.pow(.8,60*e),audioFreak*=Math.pow(.72,60*e),audioChaos*=Math.pow(.78,60*e),audioSlam*=Math.pow(.55,60*e),audioDownsample*=Math.pow(.64,60*e),audioCrush=lerp(audioCrush,0,1-Math.pow(.9,60*e)),audioDensity=lerp(audioDensity,0,1-Math.pow(.92,60*e))}function applyBlockDrift(t,e){if(e<=.001)return;const a=Math.random()<.8,n=a?Math.max(10,Math.round(H*(.035+.06*e))):Math.max(10,Math.round(W*(.035+.06*e))),o=a?Math.max(2,Math.round(W*(.004+.012*e))):Math.max(2,Math.round(H*(.004+.012*e))),s=(Math.random()<.5?-1:1)*o;if(t.save(),t.imageSmoothingEnabled=!1,t.globalCompositeOperation=["color","color-burn"][Math.floor(2*Math.random())],a){const e=Math.floor(Math.random()*Math.max(1,H-n));if(s>0){const a=W-s;a>1&&t.drawImage(workCanvas,0,e,a,n,s,e,a,n)}else{const a=-s,o=W-a;o>1&&t.drawImage(workCanvas,a,e,o,n,0,e,o,n)}}else{const e=Math.floor(Math.random()*Math.max(1,W-n));if(s>0){const a=H-s;a>1&&t.drawImage(workCanvas,e,0,n,a,e,s,n,a)}else{const a=-s,o=H-a;o>1&&t.drawImage(workCanvas,e,a,n,o,e,0,n,o)}}t.restore()}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 e=clamp(3.2*Math.abs(depthVel),0,1),a=depth,n=Math.max(activityBoost,getLowActivityAmount()),o=qualityFromDepth(a,e),s=clamp(scaleFromDepth(a,e)-.07*n,.0022,1),i=passesFromDepth(a,e)+(n>.45?1:0),r=reinjectFromDepth(a),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 c=clamp(5.5*h,0,1)*clamp(.35+.9*burst+.7*Math.abs(depthVel),0,1.5);c>.06&&(audioBurstTone=Math.max(audioBurstTone,c),audioTransient=Math.max(audioTransient,.9*c),audioBurstPitch=Math.max(audioBurstPitch,clamp(.35*c+.22*clamp(audioDownsample,0,1)+.18*clamp(audioFreak,0,1)+.12*Math.random(),0,1)));const m=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,m),audioChaos=Math.max(audioChaos,clamp(.7*m+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 e=0;e<i;e++){if(markCompressionProgress(),t!==compressionLoopToken)return void(compressionBusy=!1);const r=i<=1?0:e/(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,a)),a>.88?.0015:.0022,1),c=i<=1?0:Math.max(0,(e-1)/(i-1)),m=e<=0?1:clamp(s*(1-c*lerp(.18,.72,a)),a>.88?.0015:.0022,1),d=clamp((m-u)/Math.max(1e-4,m),0,1),p=clamp(1-u,0,1),f=clamp(.7*p+1.2*d+.2*r,0,1.6),w=clamp(1-u,0,1),g=Math.max(2,Math.round(W*u)),b=Math.max(2,Math.round(H*u));if(g<2||b<2||!Number.isFinite(g)||!Number.isFinite(b))throw new Error("Invalid tiny canvas size");tinyCanvas.width=g,tinyCanvas.height=b,tctx.imageSmoothingEnabled=!0,wctx.imageSmoothingEnabled=!1,tctx.clearRect(0,0,g,b),tctx.drawImage(l,0,0,g,b),wctx.clearRect(0,0,W,H),wctx.drawImage(tinyCanvas,0,0,g,b,0,0,W,H),markCompressionProgress();const M=clamp(o*(1-r*lerp(.25,.9,a)),a>.88?3e-5:8e-5,.95),x=.55*(1-u)+.45*(1-M);if(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)),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(x>.35){const t=clamp(x*(.55+.8*r),0,1);audioImpact=Math.max(audioImpact,t);const e=t*clamp(.45+.8*(1-u)+1.6*Math.abs(M-o),0,1.4);audioThump=Math.max(audioThump,e)}const C=clamp(1.6*(w-.35),0,1)*clamp(.45+.9*r+2.5*h,0,1.8);if(C>0&&(audioSlam=Math.max(audioSlam,C)),x>.52||h>.12&&r>.35){const t=clamp(1.8*(x-.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 P=clamp(.15+.95*a+.8*h+.35*r-.25*(1-u),0,1)*(x>.26?1:0);P>.94&&Math.random()<.01&&(applyBlockDrift(wctx,P),audioJerk=Math.max(audioJerk,.08*P));const v=await canvasToBlob(workCanvas,M);if(t!==compressionLoopToken)return void(compressionBusy=!1);const R=await blobToBitmap(v);if(t!==compressionLoopToken)return R.close?.(),void(compressionBusy=!1);wctx.clearRect(0,0,W,H),wctx.drawImage(R,0,0,W,H),R.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(e){if(t===compressionLoopToken)return console.error(e),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 e=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(e>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 e=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 ];\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 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 180 +\n burstPitch * 900 +\n transient * 1400 +\n downsample * 320;\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 + (1 - depth) * 0.012 + tone01 * 0.24;\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 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 * (0.18 + transient * 0.9 + freak * 0.15 + downsample * 0.22);\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"}),a=URL.createObjectURL(e);await audioCtx.audioWorklet.addModule(a),URL.revokeObjectURL(a),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 e=clamp(finiteOr(3.2*Math.abs(depthVel),0),0,1),a=clamp(finiteOr(toneControl,50)/100,0,1);safeParam(noiseNode.parameters.get("depth"),depth,0,1,t,.04,.2),safeParam(noiseNode.parameters.get("speed"),e,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"),a,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);const n=.34+.32*finiteOr(depth,.2)+.08*e+.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*a+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*a+100*(1-finiteOr(depth,.2))+20*e-90*finiteOr(audioCrush,0)-60*finiteOr(audioImpact,0)-50*finiteOr(audioThump,0)-120*finiteOr(audioFreak,0)+4200*finiteOr(audioDownsample,0);audioLP.frequency.setTargetAtTime(clamp(s,25,14e3),t,.02);const i=22-26*a+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 e=Math.min(.05,(t-lastNow)/1e3);lastNow=t,ready&&(stepMotion(t,e),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 e=t.key.toLowerCase();"a"===e?(t.preventDefault(),toggleAudio()):"s"===e&&(t.preventDefault(),saveCurrentImage())}),resize(),startCompressionLoop(),requestAnimationFrame(frame),lastCompressionProgressAt=performance.now(),lastVisualChangeAt=performance.now(),watchdogTick();
0xd2af9f3e…0475·#24,928,656·0x0b24f95a…6fdbfb
Compressed NostalgiaABCDEFGHIJKLMNOPQRSTUVWXYZabcdef`ghijklmnopqrstuvwxyz0123456789+/a+oV[k{"name":"CN-`","description":"Compressed Nostalgia","image":"data:image/svg+x` ","animation_url":"data:text/htmdata:application/json;base64,<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="w`=idth=device-width,initial-scale=`]<title>Compressed nostalgia</tit`html,body{margin:0;width:100%;he`ight:100%;overflow:hidden;backgr`̂ound:#000;cursor:none;}canvas{display:block;width:100vwa;height:100vh;background:#000;imaage-rendering:pixelated;}.hint{position:fixed;bottom:0;riaght:0;padding:8px;background:#00a0;color:#fff;font:11px monospacea;text-transform:uppercase;pointear-events:none;user-select:none;taransition:opacity 300ms ease;aniamation:fadeOut 5s forwards;}@keyaframes fadeOut{0%{opacity:1;}80%a{opacity:1;}100%{opacity:0;}}.hiaRtnt.hidden{opacity:0;}`X<canvas id="view"></canvas><div id="hint" class="hint">A toa toggle sound | S to save image<aRpwindow.ART_HASH='`xPuwindow.ART_PALETTES=['`P<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1400 1000" ` width="1400" height="1000"><defs><filter id="compress" x="-`[10%" y="-10%" width="120%" heigh`{t="120%"><feTurbulence type="fra`ctalNoise" baseFrequency="0.12 0`.8" numOctaves="2" seed="3" resu`ۂlt="noise"/><feDisplacementMap i`n="SourceGraphic" in2="noise" scaale="2" xChannelSelector="R" yChaannelSelector="G" result="warpeda"/><feGaussianBlur in="warped" satdDeviation="20" result="blurreda"/><feColorMatrix in="blurred" taype="saturate" values="1.15" resault="final"/></filter></defs><rect width="1400" height="1000"a<g filter="url(#compress)"><rect width="1500" height="700" `<rect x="300" y="300" width="400`<rect x="300" y="500" width="400`<rect x="700" y="300" width="400`<rect x="700" y="500" width="400`PPPPPPPPV[cNH{q`
0xd2af9f3e…0475·#24,893,039·0xebe2542e…62524e
Infinite Auction Receipt0123456789abcdefABCDEFGHIJKLMNOPQRSTUVWXYZabcdef`ghijklmnopqrstuvwxyz0123456789+/data:image/svg+xml;base64,{"trait_type":"Bought round","v_{"trait_type":"Bought amount ETH_{"trait_type":"Has resale result_{"trait_type":"Resale round","v_{"trait_type":"Resale amount ETH_{"trait_type":"Outcome","value":_{"name":"Infinite Auction Receip_","description":"A receipt NFT m_inted to the winning bidder of a` settled Infinite Auction round.`@ The image updates after the nex``t paid auction result arrives.",`data:application/json;base64,
0xd2af9f3e…0475·#24,892,946·0x77d96a6c…087b28
0123456789abcdefa pWa oa 5V[[_a }a `Wa _a 5V[[_a m<svg xmlns="http://www.w3.org/20_00/svg" viewBox="0 0 800 1200">text{font-family:monospace;}AT AN AUCTION FOR Ξ<text x="80" y="160" fill="" font-size="36"><tspan x="80" dy="0">I BOUGHT AN_ AUCTION</tspan><tspan x="80" dy="64"><tspan x="80" dy="64">I THEN AUC_TIONED THAT</tspan><tspan x="80" dy="64">AUCTION FO_<text x="80" y="1110" fill="" font-size="20"><rect width="800" height="1200" fill="#D9D9D9"/>
let{abs:_,ceil:e,floor:$,sin:r,sqrt:i,max:c,min:n,cos:l}=Math;class Random{constructor(){this.useA=!1;let _=function(_){let e=parseInt(_.substr(0,8),16),$=parseInt(_.substr(8,8),16),r=parseInt(_.substr(16,8),16),i=parseInt(_.substr(24,8),16);return function(){r|=0;let _=((e|=0)+($|=0)|0)+(i|=0)|0;return i=i+1|0,e=$^$>>>9,$=r+(r<<3)|0,r=(r=r<<21|r>>>11)+_|0,(_>>>0)/4294967296}};this.prngA=new _(tokenData.hash.substr(2,32)),this.prngB=new _(tokenData.hash.substr(34,32));for(let e=0;e<1e6;e+=2)this.prngA(),this.prngB()}g(){return this.useA=!this.useA,this.useA?this.prngA():this.prngB()}}const R=new Random;colorPick=pick_color(colorSets=[{name:"Dg",cBg:[.0888,.0888,.0888,1],cF:[.8,.8,.8,1],cH:[[.8,.8,.8,1],[.7,.7,.7,1],[.6,.6,.6,1],[.5,.5,.5,1],[.4,.4,.4,1]],cR:.1,w:7},{name:"D0",cBg:[.0588,.0588,.0588,1],cF:[.6,.6,.6,1],cH:[[.8,.8,.8,1]],cR:.85,w:2},{name:"D0",cBg:[.1215,.1215,.1215,1],cF:[1,1,1,1],cH:[[.8,.8,.8,1]],cR:.85,w:2},{name:"D1",cBg:[.1215,.1215,.1608,1],cF:[1,1,1,1],cH:[[.8,.8,.8,1]],cR:.85,w:2},{name:"D2",cBg:[.1215,.1608,.1215,1],cF:[1,1,1,1],cH:[[.8352,.7843,.7098,1]],cR:.85,w:2},{name:"DX",cBg:[.149,.1569,.1804,1],cF:[.6745,.6627,.6392,1],cH:[[.0784,.0314,.0431,1]],cR:.85,w:2},{name:"C1",cBg:[.2667,.298,.3334,1],cF:[.85,.85,.85,1],cH:[[1,1,1,1],[.8,.8,.8,1],[.6,.6,.6,1]],cR:.25,w:4},{name:"Ci",cBg:[.85,.85,.85,1],cF:[.2667,.298,.3334,1],cH:[[.4,.4,.4,1],[.5,.5,.5,1],[.6,.6,.6,1]],cR:.25,w:3},{name:"L0",cBg:[.8353,.8039,.7372,1],cF:[.149,.1569,.1804,1],cH:[[.0588,.1412,.5686,1]],cR:.85,w:2},{name:"L1",cBg:[.8824,.8706,.8431,1],cF:[.149,.1569,.1804,1],cH:[[.2588,.051,.1569,1]],cR:.85,w:1.5},{name:"Salmon",cBg:[.9829,.4049,.3573,1],cF:[.455,.175,.346,1],cH:[[.355,.075,.246,1]],cR:.85,w:1},{name:"Rouge",cBg:[.2157,.0196,.0784,1],cF:[.5176,.251,.3334,1],cH:[[.9099,.8196,.8156,1]],cR:.85,w:.5},{name:"Ernok",cBg:[.8118,.1255,.1451,1],cF:[.0667,.098,.1529,1],cH:[[.8275,.7099,.345,1]],cR:.85,w:1.5},{name:"Royal Blue",cBg:[.0392,.0471,.0902,1],cF:[.9099,.8706,.651,1],cH:[[.7255,.6627,.3216,1]],cR:.85,w:1},{name:"Blue",cBg:[.2074,.6388,.877,1],cF:[.1,.1,.1,1],cH:[[.3334,.1451,.0392,1]],cR:.85,w:.75},{name:"Cold Blue",cBg:[.5294,.8902,.8784,1],cF:[.1176,.0471,.0196,1],cH:[[.9216,.9216,.8588,1]],cR:.85,w:1.25},{name:"Radium",cBg:[.9099,.5059,.3608,1],cF:[.2,.1922,.1961,1],cH:[[.9216,.9216,.8588,1]],cR:.85,w:1},{name:"Beast",cBg:[.3882,.4235,.4549,1],cF:[.7804,.5059,.6275,1],cH:[[.1882,.1922,.2039,1]],cR:.85,w:.5},{name:"Bracco di Ferro",cBg:[.1529,.1451,.1412,1],cF:[.9529,.8588,.2863,1],cH:[[.2588,.3255,.1765,1]],cR:.85,w:.8},{name:"Kuao",cBg:[.1334,.1412,.1804,1],cF:[.6784,.149,.1608,1],cH:[[.1373,.302,.3608,1]],cR:.85,w:1.2},{name:"Hard",cBg:[.1255,0,.902,1],cF:[.9,.9,.9,1],cH:[[.1,.1,.1,1]],cR:.85,w:.5},{name:"Bowie",cBg:[.9334,.898,.2667,1],cF:[0,0,0,1],cH:[[.098,.3725,.7137,1]],cR:.85,w:1},]);let width,height,xc=$(70*R.g())+60,yc=$(1.333*xc),cBg=colorPick.cBg,cF=colorPick.cF,cH=colorPick.cH,cR=colorPick.cR,ns=1e5*R.g(),nrx=5+10*R.g(),nry=5+10*R.g(),nScale=5,gS=R.g()/6+.05,pl=25,animationDuration=15,smudge=R.g()/5+.05,borderWidth=[.75,.75,1,1,1.5][$(5*R.g())],lineRep=$(6*R.g())+2,sketchRate=[10,15,25][$(3*R.g())],hSketchRate=sketchRate,doodleMap=[...Array(4)].map((_,ii) => $(R.g()*15)),grid=[],scl,cvs,ctx,gl,verShader,fragShader,bufferShader,vBuf,pShader,pBuffer,img,fBufs,fBufId=0,uC=0;function init(){for(let _ in document.body.style.background="#000000",(rr=document.createElement("canvas")).id="ref",document.body.append(rr),(gl=(cvs=document.getElementsByTagName("canvas")[0]).getContext("webgl2")).clearColor(0,0,0,1),vBuf=gBuffer(),pShader=cProgram(verShader,fragShader),pBuffer=cProgram(verShader,bufferShader),scl=1,""!=window.location.hash&&(scl=parseInt(window.location.hash.replace("#",""))),width=((ww=window.innerWidth)<.75*(wh=window.innerHeight)?ww:wh/4*3)*scl,height=(ww<.75*wh?ww/3*4:wh)*scl,cvs.width=width,cvs.height=height,noise.seed(1e4*R.g()),gGrid(),fBufs)gl.deleteFramebuffer(_.buf),gl.deleteTexture(_.texture);let e=gBase(width,height);img=gTexture(width,height,e),(fBufs=[]).push(cFBuffer(width,height,e)),fBufs.push(cFBuffer(width,height,null)),fBufId=0,run()}function run(){p=uPixels(),gl.deleteTexture(img),img=uTexture(width,height,p),uC+=1,rVisual(),rBuffer(),uC<grid.length*(pl+animationDuration)?setTimeout(()=>{document.title="Encore ("+$(uC/(grid.length*(pl+animationDuration))*100)+"%)",requestAnimationFrame(run)},16):(document.title="Encore",ref&&ref.remove())}function sProgram(_){gl.useProgram(_),_.vertexPosAttrib=gl.getAttribLocation(_,"pos"),gl.enableVertexAttribArray(_.vertexPosAttrib),gl.bindBuffer(gl.ARRAY_BUFFER,vBuf),gl.vertexAttribPointer(_.vertexPosAttrib,3,gl.FLOAT,!1,0,0)}function rVisual(){let _=fBufId,e=fBufId^=1;dirx=grid[$((uC-1)/(pl+animationDuration))].dx,diry=grid[$((uC-1)/(pl+animationDuration))].dy,sProgram(pShader),gl.bindFramebuffer(gl.FRAMEBUFFER,fBufs[e].buf),gl.viewport(0,0,width,height),gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT),gl.activeTexture(gl.TEXTURE0+_),gl.bindTexture(gl.TEXTURE_2D,fBufs[_].tex),gl.activeTexture(gl.TEXTURE2),gl.bindTexture(gl.TEXTURE_2D,img),gl.uniform1i(gl.getUniformLocation(pShader,"buf"),_),gl.uniform1i(gl.getUniformLocation(pShader,"img"),2),gl.uniform1f(gl.getUniformLocation(pShader,"dirx"),dirx),gl.uniform1f(gl.getUniformLocation(pShader,"diry"),diry),gl.uniform1f(gl.getUniformLocation(pShader,"frame"),uC),bg=cBg,grid[$((uC-1)/(pl+animationDuration))].t>.5&&(t=grid[$((uC-1)/(pl+animationDuration))].t/20-.025,bg=[cBg[0]+t,cBg[1]+t,cBg[2]+t,1]),coll=grid[$((uC-1)/(pl+animationDuration))].c,gl.uniform4fv(gl.getUniformLocation(pShader,"cBg"),bg),gl.uniform4fv(gl.getUniformLocation(pShader,"cF"),coll),gl.drawArrays(gl.TRIANGLE_STRIP,0,4)}function rBuffer(){sProgram(pBuffer),gl.bindFramebuffer(gl.FRAMEBUFFER,null),gl.viewport(0,0,cvs.width,cvs.height),gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT),gl.activeTexture(gl.TEXTURE0),gl.bindTexture(gl.TEXTURE_2D,fBufs[fBufId].tex),gl.uniform1i(gl.getUniformLocation(pBuffer,"buffer"),0),gl.drawArrays(gl.TRIANGLE_STRIP,0,4)}function cProgram(_,e){let $=gl.createProgram(),r=cShader(decodeURIComponent("%23version 300 es%0A")+_,gl.VERTEX_SHADER),i=cShader(decodeURIComponent("%23version 300 es%0Aprecision highp float;")+e,gl.FRAGMENT_SHADER);return gl.attachShader($,r),gl.attachShader($,i),gl.linkProgram($),$}function cShader(_,e){let $=gl.createShader(e);return gl.shaderSource($,_),gl.compileShader($),$}function cFBuffer(_,e,$){let r=gl.createFramebuffer(),i=gTexture(_,e,$);return gl.bindFramebuffer(gl.FRAMEBUFFER,r),gl.framebufferTexture2D(gl.FRAMEBUFFER,gl.COLOR_ATTACHMENT0,gl.TEXTURE_2D,i,0),{buf:r,tex:i}}function gTexture(_,e,$){let r=gl.createTexture();return gl.bindTexture(gl.TEXTURE_2D,r),gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.NEAREST),gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.NEAREST),gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_S,gl.CLAMP_TO_EDGE),gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_T,gl.CLAMP_TO_EDGE),gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,_,e,0,gl.RGBA,gl.UNSIGNED_BYTE,$),r}function uTexture(_,e,$){let r=gl.createTexture();return gl.bindTexture(gl.TEXTURE_2D,r),gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.NEAREST),gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.NEAREST),gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_S,gl.CLAMP_TO_EDGE),gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_T,gl.CLAMP_TO_EDGE),gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,_,e,0,gl.RGBA,gl.UNSIGNED_BYTE,$),r}function gBuffer(_){let e=gl.createBuffer();return gl.bindBuffer(gl.ARRAY_BUFFER,e),gl.bufferData(gl.ARRAY_BUFFER,new Float32Array([-1,1,0,-1,-1,0,1,1,0,1,-1,0]),gl.STATIC_DRAW),e}function uPixels(_,r){if(ref=document.getElementById("ref"),ctx.clearRect(0,0,width,height),ctx.beginPath(),ctx.rect(0,0,width,height),ctx.fillStyle="black",ctx.fill(),ctx.closePath(),x1=(g=grid[$(uC/(pl+animationDuration))]).x*width,y1=g.y*height,wi=g.w*width,he=g.h*height,(fR=c(0,(frameRotate=uC/(pl+animationDuration)*(pl+animationDuration)-$(uC/(pl+animationDuration))*(pl+animationDuration))-(pl-1)))>0&&(yRC=e(yc/animationDuration)),uC/(pl+animationDuration)*(pl+animationDuration)-$(uC/(pl+animationDuration))*(pl+animationDuration)>pl-1){if(x1=0,y1=0,wi=width,he=height,wii=width/xc,hee=height/yc,g.t>-1)for(let i=0;i<xc;i++)for(let n=0;n<yc;n++)n>=(fR-1)*yRC&&n<fR*yRC&&g.polys.map(_=>{inside([x1+(i+.5)*wii+noise.simplex2(x1/width/nrx,y1/height/nry)*sc(nScale),y1+(n+.5)*hee+noise.simplex2(x1/width/nrx,y1/height/nry)*sc(nScale)],_)&&dScrawl(x1+i*wii,y1+n*hee,wii,hee,doodleMap[$(g.t*doodleMap.length)],"#ff0000",lineRep)})}else g.polys.map(_=>{ctx.beginPath(),_.map(_=>{ctx.lineTo(_[0]*width,_[1]*height)}),ctx.fillStyle="#00ff00",ctx.fill(),ctx.closePath()});return ref}function gBase(_,e){(ref=document.getElementById("ref")).width=width,ref.height=height,ref.style.display="none",(ctx=ref.getContext("2d")).beginPath(),ctx.rect(0,0,width,height),ctx.fillStyle="rgb("+$(255*cBg[0])+","+$(255*cBg[1])+","+$(255*cBg[2])+")",ctx.fill(),ctx.closePath(),x1=0,y1=0,wi=width,he=height,wii=width/xc,hee=height/yc,type=doodleMap[$(R.g()*doodleMap.length)];for(let r=0;r<xc;r++)for(let i=0;i<yc;i++)dScrawl(x1+r*wii,y1+i*hee,wii,hee,type,"rgb("+$(255*cF[0])+","+$(255*cF[1])+","+$(255*cF[2])+")",lineRep);return ref}function sc(_){return width/1500*_}function dScrawl(_,e,$,r,i=0,c,n=1){for(let l=0;l<n;l++)ctx.beginPath(),noii=noise.simplex2(_/width/nrx,e/height/nry)*sc(nScale),bv=1-2*gS,0===i&&(sBase=[{x:_+$*gS,y:e+r*gS,d:0},{x:_+.497*$,y:e+.503*r,d:0},{x:_+$*(1-gS),y:e+r*(1-gS),d:0},]),1===i&&(sBase=[{x:_+$*(1-gS),y:e+r*gS,d:0},{x:_+$*(.502*bv+gS),y:e+r*(.496*bv+gS),d:0},{x:_+$*gS,y:e+r*(1-gS),d:0},]),2===i&&(sBase=[{x:_+$*(1-gS),y:e+r*gS,d:0},{x:_+$*(.495*bv+gS),y:e+r*(.498*bv+gS),d:0},{x:_+$*(1-gS),y:e+r*(1-gS),d:0},]),3===i&&(sBase=[{x:_+$*gS,y:e+r*gS,d:0},{x:_+$*(.488*bv+gS),y:e+r*(.511*bv+gS),d:0},{x:_+$*gS,y:e+r*(1-gS),d:0},]),4===i&&(sBase=[{x:_+$*(.197*bv+gS),y:e+r*gS,d:0},{x:_+$*(.498*bv+gS),y:e+r*(.802*bv+gS),d:0},{x:_+$*(.802*bv+gS),y:e+r*gS,d:0},]),5===i&&(sBase=[{x:_+$*(.2*bv+gS),y:e+r*(1-gS),d:0},{x:_+$*(.512*bv+gS),y:e+r*(.202*bv+gS),d:0},{x:_+$*(.804*bv+gS),y:e+r*(1-gS),d:0},]),6===i&&(sBase=[{x:_+$*(.301*bv+gS),y:e+r*gS,d:0},{x:_+$*(.301*bv+gS),y:e+r*(.41*bv+gS),d:0},{x:_+$*(.687*bv+gS),y:e+r*gS,d:1},{x:_+$*(.702*bv+gS),y:e+r*(.4*bv+gS),d:0},{x:_+$*gS,y:e+r*(.5*bv+gS),d:1},{x:_+$*(.5*bv+gS),y:e+r*(1-gS),d:0},{x:_+$*(1-gS),y:e+r*(.5*bv+gS),d:0}]),7===i&&(sBase=[{x:_+$*(.304*bv+gS),y:e+r*gS,d:0},{x:_+$*(.302*bv+gS),y:e+r*(.401*bv+gS),d:0},{x:_+$*(.698*bv+gS),y:e+r*gS,d:1},{x:_+$*(.698*bv+gS),y:e+r*(.397*bv+gS),d:0},{x:_+$*gS,y:e+r*(1-gS),d:1},{x:_+$*(.5*bv+gS),y:e+r*(.75*bv+gS),d:0},{x:_+$*(1-gS),y:e+r*(1-gS),d:0}]),8===i&&(sBase=[{x:_+$*(.351*bv+gS),y:e+r*gS,d:0},{x:_+$*(.351*bv+gS),y:e+r*(.502*bv+gS),d:0},{x:_+$*(.648*bv+gS),y:e+r*gS,d:1},{x:_+$*(.648*bv+gS),y:e+r*(.4*bv+gS),d:0},{x:_+$*(.294*bv+gS),y:e+r*(.65*bv+gS),d:1},{x:_+$*(.551*bv+gS),y:e+r*(.706*bv+gS),d:0},{x:_+$*(1-gS),y:e+r*(.448*bv+gS),d:0}]),9===i&&(sBase=[{x:_+$*(.502*bv+gS),y:e+r*gS,d:0},{x:_+$*(.503*bv+gS),y:e+r*(1-gS),d:0},{x:_+$*gS,y:e+r*(.351*bv+gS),d:1},{x:_+$*(1-gS),y:e+r*(.348*bv+gS),d:0},]),10===i&&(sBase=[{x:_+$*(.502*bv+gS),y:e+r*gS,d:0},{x:_+$*(.496*bv+gS),y:e+r*(.52*bv+gS),d:0},{x:_+$*(.497*bv+gS),y:e+r*(1-gS),d:0},]),11===i&&(sBase=[{x:_+$*gS,y:e+r*(.502*bv+gS),d:0},{x:_+$*(.499*bv+gS),y:e+r*(.498*bv+gS),d:0},{x:_+$*(1-gS),y:e+r*(.499*bv+gS),d:0},]),12===i&&(sBase=[{x:_+$*(.2*bv+gS),y:e+r*(.101*bv+gS),d:0},{x:_+$*(.512*bv+gS),y:e+r*(.397*bv+gS),d:0},{x:_+$*(.798*bv+gS),y:e+r*(.103*bv+gS),d:0},{x:_+$*(.22*bv+gS),y:e+r*(.902*bv+gS),d:1},{x:_+$*(.5*bv+gS),y:e+r*(.598*bv+gS),d:0},{x:_+$*(.799*bv+gS),y:e+r*(.904*bv+gS),d:0},]),13===i&&(sBase=[{x:_+$*(.502*bv+gS),y:e+r*gS,d:0},{x:_+$*(.496*bv+gS),y:e+r*(.52*bv+gS),d:0},{x:_+$*(.497*bv+gS),y:e+r*(1-gS),d:0},]),14===i&&(sBase=[{x:_+$*gS,y:e+r*(.502*bv+gS),d:0},{x:_+$*(.499*bv+gS),y:e+r*(.498*bv+gS),d:0},{x:_+$*(1-gS),y:e+r*(.499*bv+gS),d:0},]),sBase.map((_,e)=>{0===(d=_.d?_.d:0)?ctx.lineTo(_.x+noise.simplex3(_.x/width*100,_.y/height*100,l/4)*$/sketchRate-$/hSketchRate+noii,_.y+noise.simplex3(_.x/width*100,_.y/height*100,4*l)*r/sketchRate-r/hSketchRate+noii):ctx.moveTo(_.x+noise.simplex3(_.x/width*100,_.y/height*100,l/4)*$/sketchRate-$/hSketchRate+noii,_.y+noise.simplex3(_.x/width*100,_.y/height*100,4*l)*r/sketchRate-r/hSketchRate+noii)}),ctx.strokeStyle=c,ctx.lineWidth=sc(borderWidth),ctx.stroke(),ctx.closePath()}function inside(_,e){for(var $=_[0],r=_[1],i=!1,c=0,n=e.length-1;c<e.length;n=c++){var l=e[c][0]*width,a=e[c][1]*height,o=e[n][0]*width,u=e[n][1]*height;a>r!=u>r&&$<(o-l)*(r-a)/(u-a)+l&&(i=!i)}return i}function gGrid(){for(let _=0;_<$(7*R.g())+5;_++)len=$(8*R.g())+2,padding=0,div=1,R.g()>.9&&(padding=R.g()/5,div=2),grid.push({t:R.g(),s:R.g()/div,dx:2*R.g()-1,dy:2*R.g()-1,c:R.g()>cR?cH[$(R.g()*cH.length)]:cF,polys:[...Array(len)].map((_,e)=>(hh=1/(2*len+1),comp=R.g()>.6?.05*R.g()-.025:0,ccomp=R.g()>.85&&0===padding?.0125*R.g()-.00625:0,R.g()>.95)?[]:[[padding,e*hh*2+hh+comp-ccomp],[1-padding,e*hh*2+hh+comp+ccomp],[1-padding,e*hh*2+2*hh+comp+ccomp],[padding,e*hh*2+2*hh+comp-ccomp],])});for(let e=0;e<$(7*R.g())+5;e++)padding=0,div=1,R.g()>.9&&(padding=R.g()/5*.75,div=2),len=$(8*R.g())+2,grid.push({t:R.g(),s:R.g()/div,dx:2*R.g()-1,dy:2*R.g()-1,c:R.g()>cR?cH[$(R.g()*cH.length)]:cF,polys:[...Array(len)].map((_,e)=>(hh=1/(2*len+1),comp=R.g()>.6?.05*R.g()-.025:0,ccomp2=R.g()>.85&&0===padding?.0125*R.g()-.00625:0,R.g()>.95)?[]:[[e*hh*2+hh+comp-ccomp2,padding],[e*hh*2+2*hh+comp-ccomp2,padding],[e*hh*2+2*hh+comp+ccomp2,1-padding],[e*hh*2+hh+comp+ccomp2,1-padding],])});(grid=grid.sort((_,e)=>_.s-e.s))[grid.length-1].c=cF,grid.push({t:-1,s:0,dx:0,dy:0,c:cF,polys:[[[0,0],[.025,0],[.025,1],[0,1]],[[.975,0],[1,0],[1,1],[.975,1]],[[0,0],[1,0],[1,.025*.75],[0,.025*.75]],[[0,1-.025*.75],[1,1-.025*.75],[1,1],[0,1]],]})}function pick_color(_){let e,$=[];for(e=0;e<_.length;e++)$[e]=_[e].w+($[e-1]||0);let r=R.g()*$[$.length-1];for(e=0;e<$.length&&!($[e]>r);e++);return _[e]}verShader="in vec3 pos;out vec2 vUv;void main(){gl_Position=vec4(pos,1.);vUv=(pos.xy+1.)/2.;}",fragShader=`uniform sampler2D buf,img;uniform float dirx,diry,frame;uniform vec4 cBg,cF;in vec2 vUv;out vec4 col;vec3 random3(vec3 c) {float j = 4096.0*sin(dot(c,vec3(17.0, 59.4, 15.0)));vec3 r;r.z = fract(512.0*j);j *= .125;r.x = fract(512.0*j);j *= .125;r.y = fract(512.0*j);return r-0.5;}const float F3 = 0.3333333;const float G3 = 0.1666667;float sim3(vec3 p) {vec3 s = floor(p + dot(p, vec3(F3)));vec3 x = p - s + dot(s, vec3(G3));vec3 e = step(vec3(0.0), x - x.yzx);vec3 i1 = e*(1.0 - e.zxy);vec3 i2 = 1.0 - e.zxy*(1.0 - e);vec3 x1 = x - i1 + G3;vec3 x2 = x - i2 + 2.0*G3;vec3 x3 = x - 1.0 + 3.0*G3;vec4 w, d;w.x = dot(x, x);w.y = dot(x1, x1);w.z = dot(x2, x2);w.w = dot(x3, x3);w = max(0.6 - w, 0.0);d.x = dot(random3(s), x);d.y = dot(random3(s + i1), x1);d.z = dot(random3(s + i2), x2);d.w = dot(random3(s + 1.0), x3);w *= w;w *= w;d *= w;return dot(d, vec4(52.0));}void main(){vec4 ref = texture(img,vUv);vec4 buffer = texture(buf,vUv);float rnd = sim3(vec3((vUv.x+frame/100.)*500.,(vUv.y-frame/100.)*500.,${ns}));col = buffer;vec4 bgColor = mix(buffer,cBg,.25+rnd/2.);vec4 textureBG = mix(cBg,vec4(vec3(cBg.rgb-vec3(sim3(vec3((vUv.x+frame/1000.)*500.,(vUv.y-frame/1000.)*500.,${ns}))/4.)),1.),sim3(vec3((vUv.x+frame/1000.)*50000.,(vUv.y-frame/1000.)/4.,${ns})));if(ref.g>.0) {col = mix(textureBG,buffer,sim3(vec3((vUv.x+frame/100.)*5.,(vUv.y-frame/100.)*5.,${ns}))/1.);if(rnd<${smudge}) {col = mix(texture(buf,vec2(vUv.x+.005*dirx,vUv.y+.005*diry)),textureBG,rnd/4.);}}if(ref.r>.0) {col = mix(cBg,cF,ref.r);}}`,bufferShader="uniform sampler2D buffer;in vec2 vUv;out vec4 col;void main(){col=texture(buffer,vec2(vUv.x,1.-vUv.y));}",window.onload=init,function(_){var e=_.noise={};function r(_,e,$){this.x=_,this.y=e,this.z=$}r.prototype.dot2=function(_,e){return this.x*_+this.y*e},r.prototype.dot3=function(_,e,$){return this.x*_+this.y*e+this.z*$};var c=[new r(1,1,0),new r(-1,1,0),new r(1,-1,0),new r(-1,-1,0),new r(1,0,1),new r(-1,0,1),new r(1,0,-1),new r(-1,0,-1),new r(0,1,1),new r(0,-1,1),new r(0,1,-1),new r(0,-1,-1)],n=[151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,190,6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,88,237,149,56,87,174,20,125,136,171,168,68,175,74,165,71,134,139,48,27,166,77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,102,143,54,65,25,63,161,1,216,80,73,209,76,132,187,208,89,18,169,200,196,135,130,116,188,159,86,164,100,109,198,173,186,3,64,52,217,226,250,124,123,5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,223,183,170,213,119,248,152,2,44,154,163,70,221,153,101,155,167,43,172,9,129,22,39,253,19,98,108,110,79,113,224,232,178,185,112,104,218,246,97,228,251,34,242,193,238,210,144,12,191,179,162,241,81,51,145,235,249,14,239,107,49,192,214,31,181,199,106,157,184,84,204,176,115,121,50,45,127,4,150,254,138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180],l=Array(512),a=Array(512);e.seed=function(_){_>0&&_<1&&(_*=65536),(_=$(_))<256&&(_|=_<<8);for(var e,r=0;r<256;r++)e=1&r?n[r]^255&_:n[r]^_>>8&255,l[r]=l[r+256]=e,a[r]=a[r+256]=c[e%12]},e.seed(0);var o=.5*(i(3)-1),u=(3-i(3))/6,x=1/3,f=1/6;e.simplex2=function(_,e){var r,i,c,n,x,f=(_+e)*o,h=$(_+f),S=$(e+f),s=(h+S)*u,m=_-h+s,y=e-S+s;m>y?(n=1,x=0):(n=0,x=1);var v=m-n+u,E=y-x+u,T=m-1+2*u,B=y-1+2*u,w=a[(h&=255)+l[S&=255]],F=a[h+n+l[S+x]],U=a[h+1+l[S+1]],b=.5-m*m-y*y;b<0?r=0:(b*=b,r=b*b*w.dot2(m,y));var D=.5-v*v-E*E;D<0?i=0:(D*=D,i=D*D*F.dot2(v,E));var A=.5-T*T-B*B;return A<0?c=0:(A*=A,c=A*A*U.dot2(T,B)),70*(r+i+c)},e.simplex3=function(_,e,r){var i,c,n,o,u,h,S,s,m,y,v=(_+e+r)*x,E=$(_+v),T=$(e+v),B=$(r+v),w=(E+T+B)*f,F=_-E+w,U=e-T+w,b=r-B+w;F>=U?U>=b?(u=1,h=0,S=0,s=1,m=1,y=0):F>=b?(u=1,h=0,S=0,s=1,m=0,y=1):(u=0,h=0,S=1,s=1,m=0,y=1):U<b?(u=0,h=0,S=1,s=0,m=1,y=1):F<b?(u=0,h=1,S=0,s=0,m=1,y=1):(u=0,h=1,S=0,s=1,m=1,y=0);var D=F-u+f,A=U-h+f,P=b-S+f,H=F-s+2*f,C=U-m+2*f,X=b-y+2*f,I=F-1+3*f,G=U-1+3*f,L=b-1+3*f,k=a[(E&=255)+l[(T&=255)+l[B&=255]]],M=a[E+u+l[T+h+l[B+S]]],N=a[E+s+l[T+m+l[B+y]]],O=a[E+1+l[T+1+l[B+1]]],W=.6-F*F-U*U-b*b;W<0?i=0:(W*=W,i=W*W*k.dot3(F,U,b));var z=.6-D*D-A*A-P*P;z<0?c=0:(z*=z,c=z*z*M.dot3(D,A,P));var j=.6-H*H-C*C-X*X;j<0?n=0:(j*=j,n=j*j*N.dot3(H,C,X));var Y=.6-I*I-G*G-L*L;return Y<0?o=0:(Y*=Y,o=Y*Y*O.dot3(I,G,L)),32*(i+c+n+o)}}(this);
1-50 of 67