0xa89f3db4…071asent to0xecb92cc7…1463·#25,210,181·view on Etherscan
or = vec2(float(x), float(y));\n vec2 point = hash3(i + neighbor).xy;\n float dist = length(neighbor + point - f);\n minDist = min(minDist, dist);\n }\n }\n return minDist;\n }\n\n float worley(vec2 p) {\n vec2 i = floor(p);\n vec2 f = fract(p);\n float minDist1 = 1.0;\n float minDist2 = 1.0;\n\n for (int y = -1; y <= 1; y++) {\n for (int x = -1; x <= 1; x++) {\n vec2 neighbor = vec2(float(x), float(y));\n vec2 point = hash3(i + neighbor).xy;\n float dist = length(neighbor + point - f);\n if (dist < minDist1) {\n minDist2 = minDist1;\n minDist1 = dist;\n } else if (dist < minDist2) {\n minDist2 = dist;\n }\n }\n }\n return minDist2 - minDist1;\n }\n\n float fbm(vec2 p) {\n float value = 0.0;\n float amplitude = 1.0;\n float frequency = 1.0;\n float totalAmplitude = 0.0;\n\n for (int i = 0; i < 8; i++) {\n if (i >= u_octaves) break;\n\n float n;\n if (u_noiseType == 0) {\n n = simplex(p * frequency);\n } else if (u_noiseType == 1) {\n n = voronoi(p * frequency) * 2.0 - 1.0;\n } else {\n n = worley(p * frequency) * 2.0 - 1.0;\n }\n\n value += amplitude * n;\n totalAmplitude += amplitude;\n amplitude *= u_persistence;\n frequency *= u_lacunarity;\n }\n\n return value / totalAmplitude;\n }\n\n vec3 rainbow(float t) {\n return 0.5 + 0.5 * cos(6.28318 * (t + vec3(0.0, 0.33, 0.67)));\n }\n\n vec3 fire(float t) {\n return vec3(\n smoothstep(0.0, 0.5, t),\n smoothstep(0.3, 0.7, t) * 0.8,\n smoothstep(0.7, 1.0, t) * 0.5\n );\n }\n\n vec3 ocean(float t) {\n return vec3(\n smoothstep(0.5, 1.0, t) * 0.3,\n 0.3 + 0.4 * t,\n 0.5 + 0.5 * t\n );\n }\n\n void main() {\n vec2 fragCoord = gl_FragCoord.xy;\n vec2 r = u_resolution;\n float t = u_time * u_speed;\n\n vec2 uv = (fragCoord * 2.0 - r) / min(r.x, r.y);\n uv *= u_scale;\n\n float n = fbm(uv + t * 0.3);\n n = n * 0.5 + 0.5;\n\n vec3 col;\n if (u_colorMode == 0) {\n col = rainbow(n + t * 0.1);\n } else if (u_colorMode == 1) {\n col = fire(n);\n } else if (u_colorMode == 2) {\n col = ocean(n);\n } else {\n col = vec3(n);\n }\n\n col += u_high * 0.15;\n col *= 1.0 + u_mid * 0.2;\n\n if (u_beat > 0.5) {\n col *= 1.2;\n }\n\n gl_FragColor = vec4(col, 1.0);\n }\n "}_initWebGL(){if(this._webglGraphics&&this._lastWidth===this.width&&this._lastHeight===this.height&&this._shader)return!0;this._webglGraphics&&this._webglGraphics.remove();try{this._webglGraphics=createGraphics(this.width,this.height,WEBGL),this._webglGraphics.pixelDensity(1);const e=this._getVertexShader(),t=this._getFragmentShader();return this._shader=this._webglGraphics.createShader(e,t),this._lastWidth=this.width,this._lastHeight=this.height,!0}catch(e){return console.error("[NoiseLayer] WebGL init failed:",e),this._webglGraphics=null,this._shader=null,!1}}update(e,t){const i=void 0!==window._playbackDirection?window._playbackDirection:1;this._time+=t/1e3*i,e&&(this._metrics.amplitude=e.amplitude||0,this._metrics.bass=e.fftEnergy?.bass||e.bass||0,this._metrics.mid=e.fftEnergy?.mid||e.mid||0,this._metrics.high=e.fftEnergy?.treble||e.high||0,this._metrics.beat=e.beatDetected||e.beat||!1)}draw(e){if(!this._initWebGL())return void this._drawFallback(e);const t=this._webglGraphics,i=this._shader,a=this.params;let o=a.scale,s=a.speed;a.audioReactive&&(o+=this._metrics.bass*a.audioScaleMult,s+=this._metrics.amplitude*a.audioSpeedMult);let n=0;"voronoi"===a.noiseType?n=1:"worley"===a.noiseType&&(n=2);let r=0;"fire"===a.colorMode?r=1:"ocean"===a.colorMode?r=2:"grayscale"===a.colorMode&&(r=3);try{t.clear(),t.shader(i),i.setUniform("u_resolution",[this.width,this.height]),i.setUniform("u_time",this._time),i.setUniform("u_noiseType",n),i.setUniform("u_scale",o),i.setUniform("u_speed",s),i.setUniform("u_octaves",a.octaves),i.setUniform("u_persistence",a.persistence),i.setUniform("u_lacunarity",a.lacunarity),i.setUniform("u_colorMode",r),i.setUniform("u_amplitude",this._metrics.amplitude),i.setUniform("u_bass",this._metrics.bass),i.setUniform("u_mid",this._metrics.mid),i.setUniform("u_high",this._metrics.high),i.setUniform("u_beat",this._metrics.beat?1:0),t.noStroke(),t.rect(-this.width/2,-this.height/2,this.width,this.height),e.image(t,0,0,this.width,this.height)}catch(t){console.error("[NoiseLayer] Shader processing failed:",t),this._drawFallback(e)}}_drawFallback(e){e.push(),e.colorMode(e.HSB,360,100,100,100);for(let t=0;t<this.height;t+=20)for(let i=0;i<this.width;i+=20){const a=(360*noise(.01*i+this._time,.01*t)+50*this._time)%360;e.fill(a,70,80,80),e.noStroke(),e.rect(i,t,20,20)}e.colorMode(e.RGB,255),e.pop()}resize(e,t){super.resize(e,t),this._lastWidth=0,this._lastHeight=0}dispose(){this._webglGraphics&&(this._webglGraphics.remove(),this._webglGraphics=null),this._shader=null}}class DrawWaveform extends BaseComponent{static category="fft";static isAudioReactive=!0;static displayName="Draw Waveform";static description="Waveform rendered along a user-drawn path (click+drag the canvas to draw axis)";getDefaultParams(){return{drawingEnabled:!1,lockPath:!1,pathMode:"freeform",mirror:!0,showPath:!0,clearAll:!1,undoLast:!1,clearPath:!1,_paths:null,_path:null,amplitude:50,strokeWeight:2,color:"#ffffff",opacity:80,smoothing:0,pathColor:"#444444",pathOpacity:30}}getParameters(){return[{name:"drawingEnabled",type:"boolean",label:"Drawing Mode (ON = draw more paths · OFF = locked / static)"},{name:"lockPath",type:"boolean",label:"→ Lock Paths (finalize + exit drawing)"},{name:"pathMode",type:"select",label:"Path Mode",options:[{value:"freeform",label:"Freeform (all drag points)"},{value:"line",label:"Line (first + last only)"}]},{name:"mirror",type:"boolean",label:"Mirror (reflect each path across its first click)"},{name:"showPath",type:"boolean",label:"Show Drawn Paths"},{name:"undoLast",type:"boolean",label:"→ Undo Last Path"},{name:"clearAll",type:"boolean",label:"→ Clear All Paths"},{name:"amplitude",type:"range",min:1,max:200,step:1,label:"Amplitude (% of half-canvas)"},{name:"strokeWeight",type:"range",min:.5,max:6,step:.5,label:"Stroke Weight"},{name:"color",type:"color",label:"Color"},{name:"opacity",type:"range",min:10,max:100,step:5,label:"Opacity"},{name:"smoothing",type:"range",min:0,max:.9,step:.05,label:"Smoothing"},{name:"pathColor",type:"color",label:"Path Outline Color"},{name:"pathOpacity",type:"range",min:0,max:100,step:5,label:"Path Outline Opacity"}]}constructor(e,t,i){super(e,t,i),this._metrics=null,this._smoothedWaveform=null,this._tempPath=[],this._isDrawing=!1,this._lastRecordedPoint=null,this._listenersInstalled=!1,this.params.drawingEnabled=!1,this.params.lockPath=!1,this.params.clearAll=!1,this.params.undoLast=!1,this.params.clearPath=!1,!this.params._paths&&this.params._path&&this.params._path.length>=2&&(this.params._paths=[this.params._path]),this.params._path=null}_installListeners(){"undefined"==typeof document||this._listenersInstalled||(this._mouseDownHandler=e=>{if(!this.params.drawingEnabled)return;if(!e.target||!("CANVAS"===e.target.tagName||e.target.closest&&e.target.closest("#canvas-container")))return;const t=this._eventToNormalized(e);t&&(this._isDrawing=!0,this._tempPath=[t],this._lastRecordedPoint=t)},this._mouseMoveHandler=e=>{if(!this._isDrawing)return;const t=this._eventToNormalized(e);if(t){if(this._lastRecordedPoint){const e=t.x-this._lastRecordedPoint.x,i=t.y-this._lastRecordedPoint.y;if(Math.sqrt(e*e+i*i)<.005)return}this._tempPath.push(t),this._lastRecordedPoint=t}},this._mouseUpHandler=e=>{this._isDrawing&&(this._isDrawing=!1,this._finalizePath())},document.addEventListener("mousedown",this._mouseDownHandler),document.addEventListener("mousemove",this._mouseMoveHandler),document.addEventListener("mouseup",this._mouseUpHandler),this._listenersInstalled=!0)}_uninstallListeners(){"undefined"!=typeof document&&this._listenersInstalled&&(document.removeEventListener("mousedown",this._mouseDownHandler),document.removeEventListener("mousemove",this._mouseMoveHandler),document.removeEventListener("mouseup",this._mouseUpHandler),this._listenersInstalled=!1)}_finalizePath(){if(this._tempPath.length>=2){const e="line"===this.params.pathMode?[this._tempPath[0],this._tempPath[this._tempPath.length-1]]:[...this._tempPath];this.params._paths||(this.params._paths=[]),this.params._paths.push(e)}this._tempPath=[],this._lastRecordedPoint=null,this._isDrawing=!1}_eventToNormalized(e){const t=document.querySelector("#canvas-container canvas")||document.querySelector("canvas");if(!t)return null;const i=t.getBoundingClientRect();if(i.width<=0||i.height<=0)return null;const a=(e.clientX-i.left)/i.width,o=(e.clientY-i.top)/i.height;return a<0||a>1||o<0||o>1?null:{x:a,y:o}}dispose(){this._uninstallListeners()}onParameterChange(e,t){"drawingEnabled"===e?!0===t?this._installListeners():this._uninstallListeners():"lockPath"===e&&!0===t?(this._finalizePath(),this.params.drawingEnabled=!1,this._uninstallListeners(),this.params.lockPath=!1):"clearAll"!==e&&"clearPath"!==e||!0!==t?"undoLast"===e&&!0===t&&(this.params._paths&&this.params._paths.length>0&&this.params._paths.pop(),this.params.undoLast=!1):(this.params._paths=[],this.params._path=null,this._tempPath=[],this.params.clearAll=!1,this.params.clearPath=!1)}update(e,t){this._metrics=e}draw(e){const t=this.params,waveform=this._metrics&&this._metrics.waveform;if(!waveform||0===waveform.length)return;let i=waveform;t.smoothing>0