@rosalana/sandbox 0.0.5 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs.js CHANGED
@@ -1,8 +1,834 @@
1
- "use strict";var w=Object.defineProperty;var k=(o,t,e)=>t in o?w(o,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):o[t]=e;var r=(o,t,e)=>k(o,typeof t!="symbol"?t+"":t,e);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});class u{constructor(t,e,i,s){this.target=t,this.type=e,this.listener=i,this.options=s,this.target.addEventListener(this.type,this.listener,this.options)}remove(){this.target.removeEventListener(this.type,this.listener,this.options)}static on(t,e,i,s){return t.addEventListener(e,i,s),()=>t.removeEventListener(e,i,s)}}class l extends Error{constructor(t,e){super(t),this.code=e,this.name="SandboxError"}}class S extends l{constructor(t){const e=t==="not_supported"?"WebGL is not supported in this browser.":"Failed to create WebGL context. The GPU may be unavailable.";super(e,t==="not_supported"?"WEBGL_NOT_SUPPORTED":"CONTEXT_CREATION_FAILED"),this.name="SandboxContextError"}}class L extends l{constructor(t,e){super(`Vertex and fragment shader WebGL versions do not match (${t} vs ${e})`,"SHADER_VERSION_MISMATCH"),this.vertexVersion=t,this.fragmentVersion=e,this.name="SandboxShaderVersionMismatchError"}}class f extends l{constructor(e,i,s){const n=f.parseErrorLines(s),h=n.length>0?` at line(s): ${n.join(", ")}`:"";super(`${e} shader compilation failed${h}
1
+ "use strict";var ie=Object.defineProperty;var re=(u,e,t)=>e in u?ie(u,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):u[e]=t;var o=(u,e,t)=>re(u,typeof e!="symbol"?e+"":e,t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});class b{constructor(e,t,n,i){this.target=e,this.type=t,this.listener=n,this.options=i,this.target.addEventListener(this.type,this.listener,this.options)}remove(){this.target.removeEventListener(this.type,this.listener,this.options)}static on(e,t,n,i){return e.addEventListener(t,n,i),()=>e.removeEventListener(t,n,i)}}class h extends Error{constructor(t,n){super(t);o(this,"name","SandboxError");this.code=n}}class V extends h{constructor(){super("WebGL is not supported in this browser.","CONTEXT_ERROR")}}class se extends h{constructor(){super("Failed to create WebGL context. The GPU may be unavailable.","CONTEXT_ERROR")}}class I extends h{constructor(e,t){super(`Vertex and fragment shader WebGL versions do not match (${e} vs ${t})`,"VALIDATION_ERROR"),this.vertexVersion=e,this.fragmentVersion=t}}class E extends h{constructor(t,n,i){const r=E.parseErrorLines(i),s=r.length>0?` at line(s): ${r.join(", ")}`:"";super(`${t} shader compilation failed${s}
2
2
 
3
- ${s}`,"SHADER_COMPILATION_FAILED");r(this,"lines");this.shaderType=e,this.source=i,this.infoLog=s,this.name="SandboxShaderCompilationError",this.lines=n}static parseErrorLines(e){const i=[/ERROR:\s*\d*:(\d+)/g,/(\d+):(\d+)\(\d+\):/g,/^(\d+):/gm],s=new Set;for(const n of i){let h;for(;(h=n.exec(e))!==null;){const c=parseInt(h[1],10);c>0&&s.add(c)}}return[...s].sort((n,h)=>n-h)}}class d extends l{constructor(t){super(`Shader program linking failed
3
+ ${i}`,"SHADER_ERROR");o(this,"lines");this.shaderType=t,this.source=n,this.infoLog=i,this.lines=r}static parseErrorLines(t){const n=[/ERROR:\s*\d*:(\d+)/g,/(\d+):(\d+)\(\d+\):/g,/^(\d+):/gm],i=new Set;for(const r of n){let s;for(;(s=r.exec(t))!==null;){const a=parseInt(s[1],10);a>0&&i.add(a)}}return[...i].sort((r,s)=>r-s)}}class M extends h{constructor(e,t,n,i){super(`The shader ${e} "${t}" has type "${i}" but expected "${n}"`,"SHADER_ERROR"),this.requirement=e,this.name=t,this.expectedType=n,this.actualType=i}}class P extends h{constructor(){super("Shader source does not contain any function.","SHADER_ERROR")}}class $ extends h{constructor(e,t){super(`Syntax error in shader import statement at line ${e}: ${t}`,"SHADER_ERROR"),this.line=e,this.details=t}}class D extends h{constructor(e,t){super(`Duplicate import name "${e}" found at line ${t}. Each import must have a unique name.`,"SHADER_ERROR"),this.name=e,this.line=t}}class B extends h{constructor(e){super(`Can not find module '${e}'. Check if it is defined before usage or if the name is correct.`,"MODULE_ERROR"),this.moduleName=e}}class N extends h{constructor(e,t){super(`Method '${t}' not found in shader module '${e}'. Check if the method is defined in the module source code or if the name is correct.`,"MODULE_ERROR"),this.moduleName=e,this.methodName=t}}class G extends h{constructor(e){super(`Importing 'main' function from module '${e}' is forbidden.`,"MODULE_ERROR"),this.moduleName=e}}class W extends h{constructor(e){super(`Name 'default' is reserved and cannot be used as a function name in module '${e}'.`,"MODULE_ERROR"),this.moduleName=e}}class z extends h{constructor(e){super(`Module name '${e}' is not allowed. Module names cannot be 'sandbox' or start with 'sandbox/'.`,"MODULE_ERROR"),this.moduleName=e}}class H extends h{constructor(e){super(`Module '${e}' is already defined. Overwriting existing modules is not allowed.`,"MODULE_ERROR"),this.moduleName=e}}class q extends h{constructor(e,t,n){super(`Uniform '${n}' mentioned for function '${t}' of module '${e}' was not found among the module's declared uniforms. Check if the uniform is declared in the module source code or if the name is correct.`,"MODULE_ERROR"),this.moduleName=e,this.functionName=t,this.uniformName=n}}class j extends h{constructor(e,t){super(`Uniform '${t}' mentioned for function '${e}' was not imported from any module. Check if the function is imported from the correct module and if the uniform is declared in that module's source code with the correct name.`,"MODULE_ERROR"),this.functionName=e,this.uniformName=t}}class X extends h{constructor(e,t){super(`Mention '${e}' called in function '${t}' could not be replaced with the corresponding uniform reference. There might be an issue with the compilation process because the referenced uniform was not found among the shader requirements. Try use a different name for uniforms you want to mention in functions or check if the uniform is properly declared and mentioned in the module source code.`,"MODULE_ERROR"),this.mentionName=e,this.calledInFunction=t}}class R extends h{constructor(e){super(`Shader program linking failed
4
4
 
5
- ${t}`,"PROGRAM_LINK_FAILED"),this.infoLog=t,this.name="SandboxProgramError"}}class R{constructor(){r(this,"time",0);r(this,"delta",0);r(this,"frame",0);r(this,"running",!1);r(this,"fps",0);r(this,"startTime",0);r(this,"lastTime",0);r(this,"rafId",null);r(this,"callback",null);r(this,"maxFps",0);this.loop=this.loop.bind(this)}start(t){if(this.running)return this;this.callback=t,this.running=!0;const e=performance.now();return this.frame===0?this.startTime=e:this.startTime=e-this.time*1e3,this.lastTime=e,this.rafId=requestAnimationFrame(this.loop),this}stop(){return this.running?(this.running=!1,this.rafId!==null&&(cancelAnimationFrame(this.rafId),this.rafId=null),this):this}reset(){return this.stop(),this.time=0,this.delta=0,this.frame=0,this.fps=0,this}getState(){return{time:this.time,delta:this.delta,frame:this.frame,running:this.running,fps:Math.round(this.fps)}}tick(t=0){return this.delta=t,this.time+=t,this.frame++,this.callback&&this.callback(this.getState()),this}setTime(t){return this.time=t,this}destroy(){this.reset(),this.callback=null}setMaxFps(t){return this.maxFps=t,this}loop(t){if(!this.running)return;if(this.maxFps>0){const i=1e3/this.maxFps;if(t-this.lastTime<i){this.rafId=requestAnimationFrame(this.loop);return}}this.delta=(t-this.lastTime)/1e3,this.lastTime=t;const e=this.delta>0?1/this.delta:0;this.fps=this.fps*.95+e*.05,this.time=(t-this.startTime)/1e3,this.frame++,this.callback&&this.callback(this.getState()),this.rafId=requestAnimationFrame(this.loop)}}class p{constructor(t){r(this,"gl");r(this,"vao",null);r(this,"vbo",null);r(this,"ibo",null);r(this,"vertexCount",0);r(this,"indexCount",0);r(this,"useIndices",!1);r(this,"vaoExt",null);r(this,"isWebGL2");this.gl=t,this.isWebGL2=t instanceof WebGL2RenderingContext,this.isWebGL2||(this.vaoExt=t.getExtension("OES_vertex_array_object"))}static fullscreenQuad(t){const e=new p(t),i=new Float32Array([-1,-1,0,0,1,-1,1,0,-1,1,0,1,1,1,1,1]),s=new Uint16Array([0,1,2,2,1,3]);return e.setup(i,s),e}setup(t,e){const i=this.gl;return this.createVAO(),this.bindVAO(),this.vbo=i.createBuffer(),i.bindBuffer(i.ARRAY_BUFFER,this.vbo),i.bufferData(i.ARRAY_BUFFER,t,i.STATIC_DRAW),this.vertexCount=t.length/4,e&&(this.ibo=i.createBuffer(),i.bindBuffer(i.ELEMENT_ARRAY_BUFFER,this.ibo),i.bufferData(i.ELEMENT_ARRAY_BUFFER,e,i.STATIC_DRAW),this.indexCount=e.length,this.useIndices=!0),this.unbindVAO(),this}linkAttributes(t){const e=this.gl;this.bindVAO(),e.bindBuffer(e.ARRAY_BUFFER,this.vbo);const i=4*Float32Array.BYTES_PER_ELEMENT,s=this.getPositionLocation(t);s>=0&&(e.enableVertexAttribArray(s),e.vertexAttribPointer(s,2,e.FLOAT,!1,i,0));const n=this.getTexcoordLocation(t);return n>=0&&(e.enableVertexAttribArray(n),e.vertexAttribPointer(n,2,e.FLOAT,!1,i,2*Float32Array.BYTES_PER_ELEMENT)),this.useIndices&&e.bindBuffer(e.ELEMENT_ARRAY_BUFFER,this.ibo),this.unbindVAO(),this}bind(){return this.bindVAO(),this}unbind(){return this.unbindVAO(),this}draw(){const t=this.gl;return this.bindVAO(),this.useIndices?t.drawElements(t.TRIANGLES,this.indexCount,t.UNSIGNED_SHORT,0):t.drawArrays(t.TRIANGLE_STRIP,0,this.vertexCount),this}destroy(){const t=this.gl;this.deleteVAO(),this.vbo&&(t.deleteBuffer(this.vbo),this.vbo=null),this.ibo&&(t.deleteBuffer(this.ibo),this.ibo=null)}getPositionLocation(t){let e=t.getAttribLocation("a_position");return e>=0||(e=t.getAttribLocation("aPosition"),e>=0)||(e=t.getAttribLocation("position"),e>=0)?e:-1}getTexcoordLocation(t){let e=t.getAttribLocation("a_texcoord");return e>=0||(e=t.getAttribLocation("aTexCoord"),e>=0)||(e=t.getAttribLocation("texcoord"),e>=0)||(e=t.getAttribLocation("a_uv"),e>=0)?e:-1}createVAO(){this.isWebGL2?this.vao=this.gl.createVertexArray():this.vaoExt&&(this.vao=this.vaoExt.createVertexArrayOES())}bindVAO(){this.vao&&(this.isWebGL2?this.gl.bindVertexArray(this.vao):this.vaoExt&&this.vaoExt.bindVertexArrayOES(this.vao))}unbindVAO(){this.isWebGL2?this.gl.bindVertexArray(null):this.vaoExt&&this.vaoExt.bindVertexArrayOES(null)}deleteVAO(){this.vao&&(this.isWebGL2?this.gl.deleteVertexArray(this.vao):this.vaoExt&&this.vaoExt.deleteVertexArrayOES(this.vao),this.vao=null)}}class a{constructor(t){r(this,"gl");r(this,"program",null);r(this,"vertexShader",null);r(this,"fragmentShader",null);r(this,"version",1);this.gl=t}static detectVersion(t){return/^\s*#version\s+300\s+es/m.test(t)?2:1}compile(t,e){this.destroy();const i=a.detectVersion(t),s=a.detectVersion(e);if(i!=s)throw new L(i,s);return this.version=Math.max(i,s),this.vertexShader=this.compileShader("vertex",t),this.fragmentShader=this.compileShader("fragment",e),this.linkProgram(),this}use(){return this.program&&this.gl.useProgram(this.program),this}getProgram(){return this.program}getVersion(){return this.version}getAttribLocation(t){return this.program?this.gl.getAttribLocation(this.program,t):-1}getUniformLocation(t){return this.program?this.gl.getUniformLocation(this.program,t):null}destroy(){const t=this.gl;this.program&&(this.vertexShader&&t.detachShader(this.program,this.vertexShader),this.fragmentShader&&t.detachShader(this.program,this.fragmentShader),t.deleteProgram(this.program),this.program=null),this.vertexShader&&(t.deleteShader(this.vertexShader),this.vertexShader=null),this.fragmentShader&&(t.deleteShader(this.fragmentShader),this.fragmentShader=null)}compileShader(t,e){const i=this.gl,s=t==="vertex"?i.VERTEX_SHADER:i.FRAGMENT_SHADER,n=i.createShader(s);if(!n)throw new f(t,e,"Failed to create shader object");if(i.shaderSource(n,e),i.compileShader(n),!i.getShaderParameter(n,i.COMPILE_STATUS)){const c=i.getShaderInfoLog(n)||"Unknown error";throw i.deleteShader(n),new f(t,e,c)}return n}linkProgram(){const t=this.gl;if(!this.vertexShader||!this.fragmentShader)throw new d("Shaders not compiled");const e=t.createProgram();if(!e)throw new d("Failed to create program object");if(t.attachShader(e,this.vertexShader),t.attachShader(e,this.fragmentShader),t.linkProgram(e),!t.getProgramParameter(e,t.LINK_STATUS)){const s=t.getProgramInfoLog(e)||"Unknown error";throw t.deleteProgram(e),new d(s)}this.program=e}}class x{constructor(t,e){r(this,"name");r(this,"method");r(this,"isArray");r(this,"isMatrix");r(this,"location",null);r(this,"locationResolved",!1);r(this,"value");this.name=t,this.value=e;const i=x.inferMethodInfo(e);this.method=i.method,this.isArray=i.isArray,this.isMatrix=i.isMatrix}static inferMethodInfo(t){if(typeof t=="boolean")return{method:"uniform1i",isArray:!1,isMatrix:!1};if(typeof t=="number")return{method:"uniform1f",isArray:!1,isMatrix:!1};if(!Array.isArray(t))return{method:"uniform1f",isArray:!1,isMatrix:!1};const e=t.length,i=t[0];if(Array.isArray(i))switch(i.length){case 2:return{method:"uniform2fv",isArray:!0,isMatrix:!1};case 3:return{method:"uniform3fv",isArray:!0,isMatrix:!1};case 4:return{method:"uniform4fv",isArray:!0,isMatrix:!1};default:return{method:"uniform1fv",isArray:!0,isMatrix:!1}}switch(e){case 2:return{method:"uniform2fv",isArray:!1,isMatrix:!1};case 3:return{method:"uniform3fv",isArray:!1,isMatrix:!1};case 4:return{method:"uniform4fv",isArray:!1,isMatrix:!1};case 9:return{method:"uniformMatrix3fv",isArray:!1,isMatrix:!0};case 16:return{method:"uniformMatrix4fv",isArray:!1,isMatrix:!0};default:return{method:"uniform1fv",isArray:!0,isMatrix:!1}}}resolveLocation(t,e){return this.locationResolved||(this.location=t.getUniformLocation(e,this.name),this.locationResolved=!0),this.location}invalidateLocation(){this.location=null,this.locationResolved=!1}setValue(t){this.value=t}getValue(){return this.value}upload(t,e){const i=this.resolveLocation(t,e);if(i===null)return;const s=this.value;let n;switch(typeof s=="boolean"?n=s?1:0:typeof s=="number"?n=s:this.isArray&&Array.isArray(s[0])?n=new Float32Array(s.flat()):n=new Float32Array(s),this.method){case"uniform1f":t.uniform1f(i,n);break;case"uniform1i":t.uniform1i(i,n);break;case"uniform1fv":t.uniform1fv(i,n);break;case"uniform2fv":t.uniform2fv(i,n);break;case"uniform3fv":t.uniform3fv(i,n);break;case"uniform4fv":t.uniform4fv(i,n);break;case"uniformMatrix2fv":t.uniformMatrix2fv(i,!1,n);break;case"uniformMatrix3fv":t.uniformMatrix3fv(i,!1,n);break;case"uniformMatrix4fv":t.uniformMatrix4fv(i,!1,n);break}}}const m=class m{constructor(t){r(this,"gl");r(this,"program",null);r(this,"uniforms",new Map);this.gl=t}attachProgram(t){this.program=t;for(const e of this.uniforms.values())e.invalidateLocation();return this}set(t,e){const i=this.uniforms.get(t);return i?i.setValue(e):this.uniforms.set(t,new x(t,e)),this}setMany(t){for(const[e,i]of Object.entries(t))this.set(e,i);return this}get(t){var e;return(e=this.uniforms.get(t))==null?void 0:e.getValue()}has(t){return this.uniforms.has(t)}delete(t){return this.uniforms.delete(t)}uploadAll(){if(!this.program)return this;for(const t of this.uniforms.values())t.upload(this.gl,this.program);return this}uploadBuiltIns(t,e,i){if(this.set("u_resolution",e),this.set("u_time",t.time),this.set("u_delta",t.delta),this.set("u_mouse",i),this.set("u_frame",t.frame),!this.program)return this;for(const s of m.BUILT_INS){const n=this.uniforms.get(s);n&&n.upload(this.gl,this.program)}return this}clear(){this.uniforms.clear()}destroy(){this.uniforms.clear(),this.program=null}keys(){return this.uniforms.keys()}get size(){return this.uniforms.size}};r(m,"BUILT_INS",new Set(["u_resolution","u_time","u_delta","u_mouse","u_frame"]));let v=m;class A{constructor(){r(this,"hooks",new Map)}id(){return Math.random().toString(36).substring(2,10)}add(t){const e=this.id();return this.hooks.set(e,t),()=>this.remove(e)}remove(t){this.hooks.delete(t)}run(t){for(const[e,i]of this.hooks)i(t)===!1&&this.remove(e)}destroy(){this.hooks.clear()}}class _{constructor(t,e){r(this,"canvas");r(this,"gl");r(this,"options");r(this,"onBeforeHooks",new A);r(this,"onAfterHooks",new A);r(this,"_program");r(this,"_geometry");r(this,"_uniforms");r(this,"_clock");r(this,"_resolution",[1,1]);r(this,"_mouse",[0,0]);r(this,"_version",1);r(this,"playing",!1);this.canvas=t,this.options=e,this.gl=this.initContext(),this.enableExtensions(),this._program=new a(this.gl),this._geometry=p.fullscreenQuad(this.gl),this._uniforms=new v(this.gl),this._clock=new R,this.options.fps&&this._clock.setMaxFps(this.options.fps),this.options.onBeforeRender&&this.onBeforeHooks.add(this.options.onBeforeRender),this.options.onAfterRender&&this.onAfterHooks.add(this.options.onAfterRender),this.onRender=this.onRender.bind(this)}static setup(t,e){const i=new _(t,e);return e.vertex&&e.fragment&&i.shader(e.vertex,e.fragment),e.uniforms&&i._uniforms.setMany(e.uniforms),i}initContext(){const t={antialias:this.options.antialias,preserveDrawingBuffer:this.options.preserveDrawingBuffer,alpha:!0,depth:!1,stencil:!1},e=this.canvas.getContext("webgl2",t);if(e)return this._version=2,e;const i=this.canvas.getContext("webgl",t);if(i)return this._version=1,i;const s=new S("not_supported");throw this.options.onError(s),s}enableExtensions(){this.gl.getExtension("OES_standard_derivatives"),this.gl.getExtension("OES_texture_float"),this.gl.getExtension("OES_texture_float_linear"),this._version===1&&this.gl.getExtension("OES_vertex_array_object")}viewport(t,e,i,s){return this.canvas.width=i,this.canvas.height=s,this.gl.viewport(t,e,i,s),this._resolution=[i,s],this}clock(t){return this._clock.setTime(t),this}mouse(t,e){return this._mouse=[t,e],this}uniform(t,e){return this._uniforms.set(t,e),this}uniforms(t){return this._uniforms.setMany(t),this}getUniform(t){return this._uniforms.get(t)}shader(t,e){try{this._program.compile(t,e),this._version=this._program.getVersion(),this._geometry.linkAttributes(this._program);const i=this._program.getProgram();i&&this._uniforms.attachProgram(i),this.options.onLoad()}catch(i){i instanceof l&&this.options.onError(i)}return this}play(){return this.playing?this:(this.playing=!0,this._clock.start(this.onRender),this)}pause(){if(!this.playing)return this;const t=this._clock.getState();return this.onBeforeHooks.run(t),this.playing=!1,this._clock.stop(),this.onAfterHooks.run(t),this}render(){return this.onRender(this._clock.getState()),this}getContext(){return this.gl}getVersion(){return this._version}getClock(){return this._clock}destroy(){this.pause(),this._clock.destroy(),this._geometry.destroy(),this._program.destroy(),this._uniforms.destroy(),this.onAfterHooks.destroy(),this.onBeforeHooks.destroy()}onRender(t){const e=this.gl;this.onBeforeHooks.run(t),e.clearColor(0,0,0,0),e.clear(e.COLOR_BUFFER_BIT),this._program.use(),this._uniforms.uploadBuiltIns(t,this._resolution,this._mouse),this._uniforms.uploadAll(),this._geometry.bind(),this._geometry.draw(),this.onAfterHooks.run(t)}}const g=`#ifdef GL_ES
5
+ ${e}`,"PROGRAM_ERROR"),this.infoLog=e}}class oe extends h{constructor(t){super(`Failed to create WebGL texture for "${t}".`,"TEXTURE_ERROR");o(this,"name","SandboxTextureCreationError");this.textureName=t}}class ae extends h{constructor(t,n){super(`Cannot bind texture "${t}": all ${n} texture units are in use.`,"TEXTURE_ERROR");o(this,"name","SandboxTextureUnitLimitError");this.textureName=t,this.maxUnits=n}}class Y extends h{constructor(e){super(`Error in onLoad callback: ${e}`,"UNKNOWN_ERROR")}}class K extends h{constructor(e,t){super(`Error in onBefore/onAfter hook callback with ID ${e}: ${t}`,"UNKNOWN_ERROR")}}class le{constructor(){o(this,"time",0);o(this,"delta",0);o(this,"frame",0);o(this,"running",!1);o(this,"fps",0);o(this,"startTime",0);o(this,"lastTime",0);o(this,"rafId",null);o(this,"callback",null);o(this,"maxFps",0);this.loop=this.loop.bind(this)}start(e){if(this.running)return this;this.callback=e,this.running=!0;const t=performance.now();return this.frame===0?this.startTime=t:this.startTime=t-this.time*1e3,this.lastTime=t,this.rafId=requestAnimationFrame(this.loop),this}stop(){return this.running?(this.running=!1,this.rafId!==null&&(cancelAnimationFrame(this.rafId),this.rafId=null),this):this}reset(){return this.stop(),this.time=0,this.delta=0,this.frame=0,this.fps=0,this}getState(){return{time:this.time,delta:this.delta,frame:this.frame,running:this.running,fps:Math.round(this.fps)}}tick(e=0){return this.delta=e,this.time+=e,this.frame++,this.callback&&this.callback(this.getState()),this}setTime(e){return this.time=e,this}destroy(){this.reset(),this.callback=null}setMaxFps(e){return this.maxFps=e,this}loop(e){if(!this.running)return;if(this.maxFps>0){const n=1e3/this.maxFps;if(e-this.lastTime<n){this.rafId=requestAnimationFrame(this.loop);return}}this.delta=(e-this.lastTime)/1e3,this.lastTime=e;const t=this.delta>0?1/this.delta:0;this.fps=this.fps*.95+t*.05,this.time=(e-this.startTime)/1e3,this.frame++,this.callback&&this.callback(this.getState()),this.rafId=requestAnimationFrame(this.loop)}}class k{constructor(e){o(this,"gl");o(this,"vao",null);o(this,"vbo",null);o(this,"ibo",null);o(this,"vertexCount",0);o(this,"indexCount",0);o(this,"useIndices",!1);o(this,"vaoExt",null);o(this,"isWebGL2");this.gl=e,this.isWebGL2=e instanceof WebGL2RenderingContext,this.isWebGL2||(this.vaoExt=e.getExtension("OES_vertex_array_object"))}static fullscreenQuad(e){const t=new k(e),n=new Float32Array([-1,-1,0,0,1,-1,1,0,-1,1,0,1,1,1,1,1]),i=new Uint16Array([0,1,2,2,1,3]);return t.setup(n,i),t}setup(e,t){const n=this.gl;return this.createVAO(),this.bindVAO(),this.vbo=n.createBuffer(),n.bindBuffer(n.ARRAY_BUFFER,this.vbo),n.bufferData(n.ARRAY_BUFFER,e,n.STATIC_DRAW),this.vertexCount=e.length/4,t&&(this.ibo=n.createBuffer(),n.bindBuffer(n.ELEMENT_ARRAY_BUFFER,this.ibo),n.bufferData(n.ELEMENT_ARRAY_BUFFER,t,n.STATIC_DRAW),this.indexCount=t.length,this.useIndices=!0),this.unbindVAO(),this}linkAttributes(e){const t=this.gl;this.bindVAO(),t.bindBuffer(t.ARRAY_BUFFER,this.vbo);const n=4*Float32Array.BYTES_PER_ELEMENT,i=this.getPositionLocation(e);i>=0&&(t.enableVertexAttribArray(i),t.vertexAttribPointer(i,2,t.FLOAT,!1,n,0));const r=this.getTexcoordLocation(e);return r>=0&&(t.enableVertexAttribArray(r),t.vertexAttribPointer(r,2,t.FLOAT,!1,n,2*Float32Array.BYTES_PER_ELEMENT)),this.useIndices&&t.bindBuffer(t.ELEMENT_ARRAY_BUFFER,this.ibo),this.unbindVAO(),this}bind(){return this.bindVAO(),this}unbind(){return this.unbindVAO(),this}draw(){const e=this.gl;return this.bindVAO(),this.useIndices?e.drawElements(e.TRIANGLES,this.indexCount,e.UNSIGNED_SHORT,0):e.drawArrays(e.TRIANGLE_STRIP,0,this.vertexCount),this}destroy(){const e=this.gl;this.deleteVAO(),this.vbo&&(e.deleteBuffer(this.vbo),this.vbo=null),this.ibo&&(e.deleteBuffer(this.ibo),this.ibo=null)}getPositionLocation(e){let t=e.getAttribLocation("a_position");return t>=0||(t=e.getAttribLocation("aPosition"),t>=0)||(t=e.getAttribLocation("position"),t>=0)?t:-1}getTexcoordLocation(e){let t=e.getAttribLocation("a_texcoord");return t>=0||(t=e.getAttribLocation("aTexCoord"),t>=0)||(t=e.getAttribLocation("texcoord"),t>=0)||(t=e.getAttribLocation("a_uv"),t>=0)?t:-1}createVAO(){this.isWebGL2?this.vao=this.gl.createVertexArray():this.vaoExt&&(this.vao=this.vaoExt.createVertexArrayOES())}bindVAO(){this.vao&&(this.isWebGL2?this.gl.bindVertexArray(this.vao):this.vaoExt&&this.vaoExt.bindVertexArrayOES(this.vao))}unbindVAO(){this.isWebGL2?this.gl.bindVertexArray(null):this.vaoExt&&this.vaoExt.bindVertexArrayOES(null)}deleteVAO(){this.vao&&(this.isWebGL2?this.gl.deleteVertexArray(this.vao):this.vaoExt&&this.vaoExt.deleteVertexArrayOES(this.vao),this.vao=null)}}class ce{constructor(e){o(this,"gl");o(this,"program",null);o(this,"vertexShader",null);o(this,"fragmentShader",null);this.gl=e}compile(e,t){return this.destroy(),this.vertexShader=this.compileShader("vertex",e),this.fragmentShader=this.compileShader("fragment",t),this.linkProgram(),this}use(){return this.program&&this.gl.useProgram(this.program),this}getProgram(){return this.program}getAttribLocation(e){return this.program?this.gl.getAttribLocation(this.program,e):-1}getUniformLocation(e){return this.program?this.gl.getUniformLocation(this.program,e):null}destroy(){const e=this.gl;this.program&&(this.vertexShader&&e.detachShader(this.program,this.vertexShader),this.fragmentShader&&e.detachShader(this.program,this.fragmentShader),e.deleteProgram(this.program),this.program=null),this.vertexShader&&(e.deleteShader(this.vertexShader),this.vertexShader=null),this.fragmentShader&&(e.deleteShader(this.fragmentShader),this.fragmentShader=null)}compileShader(e,t){const n=this.gl,i=e==="vertex"?n.VERTEX_SHADER:n.FRAGMENT_SHADER,r=n.createShader(i);if(!r)throw new E(e,t,"Failed to create shader object");if(n.shaderSource(r,t),n.compileShader(r),!n.getShaderParameter(r,n.COMPILE_STATUS)){const a=n.getShaderInfoLog(r)||"Unknown error";throw n.deleteShader(r),new E(e,t,a)}return r}linkProgram(){const e=this.gl;if(!this.vertexShader||!this.fragmentShader)throw new R("Shaders not compiled");const t=e.createProgram();if(!t)throw new R("Failed to create program object");if(e.attachShader(t,this.vertexShader),e.attachShader(t,this.fragmentShader),e.linkProgram(t),!e.getProgramParameter(t,e.LINK_STATUS)){const i=e.getProgramInfoLog(t)||"Unknown error";throw e.deleteProgram(t),new R(i)}this.program=t}}class T{constructor(e,t){o(this,"name");o(this,"method");o(this,"isArray");o(this,"isMatrix");o(this,"location",null);o(this,"locationResolved",!1);o(this,"value");this.name=e,this.value=t;const n=T.inferMethodInfo(t);this.method=n.method,this.isArray=n.isArray,this.isMatrix=n.isMatrix}static inferMethodInfo(e){if(typeof e=="boolean")return{method:"uniform1i",isArray:!1,isMatrix:!1};if(typeof e=="number")return{method:"uniform1f",isArray:!1,isMatrix:!1};if(!Array.isArray(e))return{method:"uniform1f",isArray:!1,isMatrix:!1};const t=e.length,n=e[0];if(Array.isArray(n))switch(n.length){case 2:return{method:"uniform2fv",isArray:!0,isMatrix:!1};case 3:return{method:"uniform3fv",isArray:!0,isMatrix:!1};case 4:return{method:"uniform4fv",isArray:!0,isMatrix:!1};default:return{method:"uniform1fv",isArray:!0,isMatrix:!1}}switch(t){case 2:return{method:"uniform2fv",isArray:!1,isMatrix:!1};case 3:return{method:"uniform3fv",isArray:!1,isMatrix:!1};case 4:return{method:"uniform4fv",isArray:!1,isMatrix:!1};case 9:return{method:"uniformMatrix3fv",isArray:!1,isMatrix:!0};case 16:return{method:"uniformMatrix4fv",isArray:!1,isMatrix:!0};default:return{method:"uniform1fv",isArray:!0,isMatrix:!1}}}resolveLocation(e,t){return this.locationResolved||(this.location=e.getUniformLocation(t,this.name),this.locationResolved=!0),this.location}invalidateLocation(){this.location=null,this.locationResolved=!1}setValue(e){this.value=e}getValue(){return this.value}upload(e,t){const n=this.resolveLocation(e,t);if(n===null)return;const i=this.value;let r;switch(typeof i=="boolean"?r=i?1:0:typeof i=="number"?r=i:this.isArray&&Array.isArray(i[0])?r=new Float32Array(i.flat()):r=new Float32Array(i),this.method){case"uniform1f":e.uniform1f(n,r);break;case"uniform1i":e.uniform1i(n,r);break;case"uniform1fv":e.uniform1fv(n,r);break;case"uniform2fv":e.uniform2fv(n,r);break;case"uniform3fv":e.uniform3fv(n,r);break;case"uniform4fv":e.uniform4fv(n,r);break;case"uniformMatrix2fv":e.uniformMatrix2fv(n,!1,r);break;case"uniformMatrix3fv":e.uniformMatrix3fv(n,!1,r);break;case"uniformMatrix4fv":e.uniformMatrix4fv(n,!1,r);break}}}class _{constructor(e){o(this,"parsed",null);this.source=e}parse(){if(this.parsed)return this.parsed;const e=this.detectVersion(),t=this.detectImports(),n=this.detectUniforms(),i=this.detectFunctions(n);return this.parsed={version:e,imports:t,uniforms:n,functions:i}}isParsed(){return this.parsed!==null}setSource(e){this.source=e,this.parsed=null}version(){return this.detectVersion()}detectVersion(){return/^\s*#version\s+300\s+es/m.test(this.source)?2:1}detectImports(){const e=/^[ \t]*#import\s+(\w+)(?:\s+as\s+(\w+))?\s+from\s+["'](.+)["']/gm,t=/^[ \t]*[^\w\s]?import\b/gm,n=[],i=new Set;let r,s=1,a=0;for(;(r=e.exec(this.source))!==null;){s+=(this.source.substring(a,r.index).match(/\n/g)||[]).length,a=r.index,i.add(s);const f=r[1],c=r[2]||r[1],d=r[3];if(n.some(p=>p.alias===c))throw new D(c,s);n.push({name:f,alias:c,module:d,line:s})}let l;for(;(l=t.exec(this.source))!==null;){const f=(this.source.substring(0,l.index).match(/\n/g)||[]).length+1;if(i.has(f))continue;const c=this.source.split(`
6
+ `)[f-1].trim();throw new $(f,this.diagnoseImport(c))}return n}diagnoseImport(e){const t=e.match(/^([^\w\s])import\b/);if(t&&t[1]!=="#")return`Invalid prefix '${t[1]}'. Expected: #import <function> from '<module>'`;if(/^import\b/.test(e))return"Missing '#' prefix. Expected: #import <function> from '<module>'";if(/^#import\s+from\b/.test(e))return"Missing function name. Expected: #import <function> from '<module>'";if(/^#import\s+\w+\s*$/.test(e))return`Missing 'from' clause. Expected: #import ${e.split(/\s+/)[1]} from '<module>'`;if(/^#import\s+\w+\s+as\s*$/.test(e)||/^#import\s+\w+\s+as\s+from\b/.test(e))return`Missing alias name after 'as'. Expected: #import ${e.split(/\s+/)[1]} as <alias> from '<module>'`;if(/^#import\s+\w+\s+as\s+\w+\s*$/.test(e)){const n=e.split(/\s+/);return`Missing 'from' clause. Expected: #import ${n[1]} as ${n[3]} from '<module>'`}if(/^#import\s+\w+(?:\s+as\s+\w+)?\s+from\s+\w+/.test(e)){const n=e.match(/from\s+(\S+)/);return`Module name must be quoted. Expected: from '${n==null?void 0:n[1]}'`}return"Invalid syntax. Expected: #import <function> from '<module>'"}detectUniforms(){const e=/^[ \t]*uniform\s+(?:(?:highp|mediump|lowp)\s+)?(\w+)\s+(\w+)(?:\[(\d+)\])?\s*;/gm,t=[];let n,i=1,r=0;for(;(n=e.exec(this.source))!==null;){i+=(this.source.substring(r,n.index).match(/\n/g)||[]).length,r=n.index;const s=n[1],a=n[2],l=n[3]?parseInt(n[3],10):void 0;t.push({name:a,type:s,line:i,arrayNum:l})}return t}detectFunctions(e){const t=[],n="void|float|int|uint|bool|vec[234]|ivec[234]|uvec[234]|bvec[234]|mat[234](?:x[234])?|sampler2D|samplerCube|sampler3D|sampler2DArray",i=new RegExp(`^[ \\t]*(${n})\\s+(\\w+)\\s*\\(([^)]*)\\)\\s*\\{`,"gm");let r;for(;(r=i.exec(this.source))!==null;){const s=r[1],a=r[2],l=r[3].trim(),f=r.index,c=(this.source.substring(0,f).match(/\n/g)||[]).length+1,d=this.source.indexOf("{",f),p=this.findClosingBrace(this.source,d);if(p===-1)continue;const g=this.source.slice(d,p+1),Z=this.parseParams(l),ee=this.findFunctionCalls(g),te=this.findUniformCalls(g,e),ne=this.findMentionCalls(g);t.push({name:a,type:s,params:Z,body:g,dependencies:[...ee,...te,...ne],line:c})}return t}parseParams(e){if(!e.trim())return[];const t=[],n=e.split(",");for(const i of n){const r=i.trim();if(!r)continue;const a=r.replace(/\b(in|out|inout|const|highp|mediump|lowp)\b\s*/g,"").trim().match(/^(\w+)\s+(\w+)(?:\[\d*\])?$/);a&&t.push({type:a[1],name:a[2]})}return t}findClosingBrace(e,t){let n=0,i=!1,r=!1,s=!1,a=!1;for(let l=t;l<e.length;l++){const f=e[l],c=e[l+1],d=e[l-1];if(!r&&!a&&f==="/"&&c==="/"){s=!0;continue}if(s&&f===`
7
+ `){s=!1;continue}if(!r&&!s&&f==="/"&&c==="*"){a=!0,l++;continue}if(a&&f==="*"&&c==="/"){a=!1,l++;continue}if(!(s||a)){if(f==='"'&&d!=="\\"){r=!r;continue}if(!r){if(f==="{")n++,i=!0;else if(f==="}"&&(n--,i&&n===0))return l}}}return-1}findFunctionCalls(e){const t=[],n=new Set(["if","else","for","while","do","switch","case","return","break","continue","discard"]),i=/\b([a-zA-Z_]\w*)\s*\(/g;let r;for(;(r=i.exec(e))!==null;){const s=r[1];n.has(s)||t.push({name:s,type:"function",index:r.index})}return t}findUniformCalls(e,t){const n=[];for(const i of t){const r=new RegExp(`\\b${i.name}\\b`,"g");let s;for(;(s=r.exec(e))!==null;)n.push({name:i.name,type:"uniform",index:s.index})}return n}findMentionCalls(e){const t=[],n=/@(\w+)\.([a-zA-Z_]\w*)/g;let i;for(;(i=n.exec(e))!==null;){const r=i[1],s=i[2];t.push({name:`${r}.${s}`,type:"mention",index:i.index})}return t}}class Q{constructor(e){o(this,"isCompiled",!1);o(this,"original");o(this,"compiled");o(this,"requirements",{uniforms:new Map,functions:new Map});this.original=new _(e),this.compiled=new _(e)}version(){return this.original.version()}source(){return this.original.source}recompile(){return this.isCompiled=!1,this.compile()}compile(){return this.isCompiled?this.compiled.source:(this.original.parse().imports.length>0&&this.processImports(),this.compiled.setSource(this.build()),this.isCompiled=!0,this.compiled.source)}processImports(){const e=this.original.parse(),t=e.functions.flatMap(n=>n.dependencies.filter(i=>i.type==="mention").map(i=>({name:i.name.split(".")[0],uniform:i.name.split(".")[1]})));for(const n of e.imports){const i=w.resolve(n.module),r=i.extract(n.name);let s=t.filter(l=>l.name===r.function.name);if(s.length>0){const l=i.getDefinition().uniforms;if(s=s.filter(f=>{const c=l.find(d=>d.name===`u_${f.uniform}`||d.name===f.uniform);if(c){r.dependencies.uniforms.some(p=>p.name===c.name)||r.dependencies.uniforms.push(c);const d=t.indexOf(f);return d>-1&&t.splice(d,1),!1}return!0}),s.length>0)throw new q(n.module,r.function.name,s[0].uniform)}const a=i.copy();this.processExtraction(r,n.alias,a.options),y.merge(n.module,a)}if(t.length>0)throw new j(t[0].name,t[0].uniform)}processExtraction(e,t,n={}){const i=e.function,r=Math.random().toString(36).substring(2,8),s=`${t}_${r}`;for(let l=e.dependencies.functions.length-1;l>=0;l--){const f=e.dependencies.functions[l],c=this.rewriteFunction(f,t,{uniforms:e.dependencies.uniforms,functions:e.dependencies.functions,unique:s});this.requirements.functions.set(c.name,c)}const a=this.rewriteFunction(i,t,{uniforms:e.dependencies.uniforms,functions:e.dependencies.functions,rename:!0,unique:s});this.requirements.functions.set(a.name,a);for(const l of e.dependencies.uniforms){if(S.has(l.name))continue;const f={...l,name:`${s}_${l.name}${l.arrayNum?`[${l.arrayNum}]`:""}`};if(n[i.name]){const c=Object.entries(n[i.name]).find(([d,p])=>p.uniform===l.name);c&&(c[1].uniform=`${s}_${l.name}`)}this.requirements.uniforms.set(f.name,f)}n[i.name]&&t!==i.name&&(n[t]=n[i.name],delete n[i.name])}rewriteFunction(e,t,n={rename:!1,uniforms:[],functions:[],unique:""}){const i=new Set(n.uniforms.map(c=>c.name)),r=new Set(n.functions.map(c=>c.name)),s=[],a=n.unique?n.unique:t;for(const c of e.dependencies)if(c.index!==void 0)if(c.type==="uniform"&&i.has(c.name)){if(S.has(c.name))continue;s.push({index:c.index,oldText:c.name,newText:`${a}_${c.name}`})}else c.type==="function"&&r.has(c.name)&&s.push({index:c.index,oldText:c.name,newText:`${a}_${c.name}`});const l=this.applyRewrites(e.body,s),f=n.rename?t:`${a}_${e.name}`;return{...e,name:f,body:l}}applyRewrites(e,t){const n=[...t].sort((r,s)=>s.index-r.index);let i=e;for(const r of n)i=i.slice(0,r.index)+r.newText+i.slice(r.index+r.oldText.length);return i}build(){const e=this.original.parse();let t=this.original.source;t=this.removeImportLines(t,e);const n=this.findInsertionPointForUniforms(t),i=this.generateUniformsCode();i&&(t=t.slice(0,n)+i+`
8
+ `+t.slice(n));const r=this.findInsertionPointForFunctions(t),s=this.generateFunctionCode();return s&&(t=t.slice(0,r)+s+t.slice(r)),t=t.replace(/\n{3,}/g,`
9
+
10
+ `),t=this.replaceMentions(t,e),t}replaceMentions(e,t){let n=e;const i=t.functions.filter(r=>r.dependencies.some(s=>s.type==="mention"));for(const r of i){const s=r.dependencies.filter(a=>a.type==="mention");for(const a of s){const l=a.name.split("."),f=new RegExp(`\\b${l[0]}_(\\w+)_${l[1]}\\b`,"g"),c=this.requirements.uniforms.keys().find(p=>{var g;return((g=p.match(f))==null?void 0:g[0])===p});if(!c)throw new X(a.name,r.name);const d=new RegExp(`@\\b${a.name}\\b`,"g");n=n.replace(d,c)}}return n}removeImportLines(e,t){const n=e.split(`
11
+ `),i=new Set(t.imports.map(r=>r.line));return n.filter((r,s)=>{const a=i.has(s+1);if(!a&&r.trim()===""&&s>0){const l=s-1;if(i.has(l+1))return!1}return!a}).join(`
12
+ `)}findInsertionPointForUniforms(e){const t=new _(e).parse(),n=t.uniforms.find(a=>a.line===Math.max(...t.uniforms.map(l=>l.line??0))),i=e.split(`
13
+ `);let r=0;if(n&&n.line)r=n.line;else for(let a=0;a<i.length;a++){const l=i[a].trim();if(l.startsWith("#version")){r=a+1;continue}if(l.startsWith("precision ")){r=a+1;continue}if(l===""||l.startsWith("//")){r===a&&(r=a+1);continue}break}let s=0;for(let a=0;a<r;a++)s+=i[a].length+1;return s}findInsertionPointForFunctions(e){const t=new _(e).parse(),n=t.functions.find(a=>a.line===Math.min(...t.functions.map(l=>l.line??1/0))),i=e.split(`
14
+ `);let r=0;if(n&&n.line)r=n.line-2;else throw new P;let s=0;for(let a=0;a<r;a++)s+=i[a].length+1;return s}generateUniformsCode(){const e=[];if(this.requirements.uniforms.size>0)for(const t of this.checkUniformsPresence())e.push(`uniform ${t.type} ${t.name};`);return e.length===0?"":e.join(`
15
+ `)+`
16
+ `}generateFunctionCode(){const e=[];if(this.requirements.functions.size>0)for(const t of this.checkFunctionsPresence()){const n=t.params.map(i=>`${i.type} ${i.name}`).join(", ");e.push(`
17
+ ${t.type} ${t.name}(${n}) ${t.body}`)}return e.length===0?"":e.join(`
18
+ `)+`
19
+ `}checkUniformsPresence(){const e=this.original.parse(),t=[],n=this.requirements.uniforms;for(const[i,r]of n){const s=e.uniforms.find(a=>a.name===i);if(!s){t.push(r);continue}if(s.type!==r.type)throw new M("uniform",i,r.type,s.type)}return t}checkFunctionsPresence(){const e=this.original.parse(),t=[],n=this.requirements.functions;for(const[i,r]of n){const s=e.functions.find(a=>a.name===i);if(!s){t.push(r);continue}if(s.type!==r.type)throw new M("function",i,r.type,s.type)}return t}}class v extends Q{constructor(t,n,i={}){super(n);o(this,"name");o(this,"options",{});this.name=t,this.options=this.resolveOptions(i)}resolveOptions(t){if(!(t!=null&&t.default))return t||{};const n=this.original.parse(),i=t.default;for(const r of n.functions)if(!(r.name==="main"||r.name==="default"))if(t[r.name]){const s=t[r.name];for(const a in i)a in s||(s[a]=i[a])}else t[r.name]={...i};return delete t.default,t||{}}static define(t){const{name:n,source:i,options:r}=t;if(n==="sandbox"||n.startsWith("sandbox/"))throw new z(n);const s=new v(n,i,r);if(w.has(n))throw new H(n);return w.register(n,s),s}static resolve(t){return w.resolve(t)}copy(t="original"){return new v(this.name,this[t].source,JSON.parse(JSON.stringify(this.options)))}merge(t){this.options=this.options||{};const n=this.getDefinition().uniforms.map(i=>i.name);for(const[i,r]of Object.entries(t.options??{}))if(!this.options[i])this.options[i]=r;else for(const[s,a]of Object.entries(r))n.includes(a.uniform)||(this.options[i][s]=a)}getDefinition(){return this.compile(),{name:this.name,methods:this.compiled.parse().functions.map(t=>t.name).filter(t=>t!=="main"&&t!=="default"),uniforms:this.compiled.parse().uniforms.map(t=>({name:t.name,type:t.type})),options:this.options}}extract(t){if(this.compile(),t==="main")throw new G(this.name);if(t==="default")throw new W(this.name);const n=this.compiled.parse(),i=n.functions.find(a=>a.name===t);if(!i)throw new N(this.name,t);const r=new Map,s=new Map;return this.collectDependencies({current:i,scope:{functions:n.functions,uniforms:n.uniforms},collected:{functions:r,uniforms:s},visited:new Set([t])}),{function:i,dependencies:{functions:Array.from(r.values()),uniforms:Array.from(s.values())}}}collectDependencies(t){for(const n of t.current.dependencies)if(n.type==="function"){if(t.visited.has(n.name))continue;const i=t.scope.functions.find(r=>r.name===n.name);i&&(t.visited.add(n.name),t.collected.functions.set(n.name,i),this.collectDependencies({current:i,scope:{functions:t.scope.functions,uniforms:t.scope.uniforms},collected:{functions:t.collected.functions,uniforms:t.collected.uniforms},visited:t.visited}))}else if(n.type==="uniform"){const i=t.scope.uniforms.find(r=>r.name===n.name);i&&!t.collected.uniforms.has(n.name)&&t.collected.uniforms.set(n.name,i)}}}class J{constructor(e=[]){o(this,"modules",new Map);e.forEach(t=>{this.register(t.name,t)})}compile(){this.modules.forEach(e=>{e.compile()})}available(){return Array.from(this.modules.values()).map(e=>e.getDefinition())}defaults(){const e={};return this.modules.forEach(t=>{const n=t.getDefinition();if(n.options)for(const i in n.options){const r=n.options[i];for(const s in r){const a=r[s];a.default!==void 0&&!n.uniforms.map(l=>l.name).includes(a.uniform)&&(e[a.uniform]=a.default)}}}),e}resolveOptions(e){for(const t of this.modules.values())if(t.options&&t.options[e])return t.options[e];return null}register(e,t){this.modules.set(e,t)}merge(e,t){if(!this.modules.has(e))return this.register(e,t);const n=this.modules.get(e);n.merge(t),this.modules.set(e,n)}resolve(e){const t=this.modules.get(e);if(!t)throw new B(e);return t}has(e){return this.modules.has(e)}isEmpty(){return this.modules.size===0}remove(e){this.modules.delete(e)}load(e){e.forEach(t=>{this.register(t.name,t)})}clear(){this.modules.clear()}}const ue=`// ─── Constants ──────────────────────────────────────────────
20
+
21
+ const float PI = 3.14159265359;
22
+ const float TAU = 6.28318530718;
23
+
24
+ // ─── UV Transforms ──────────────────────────────────────────
25
+
26
+ /**
27
+ * Center UV coordinates — remap to range where (0,0) is canvas center.
28
+ * Aspect-ratio corrected using resolution length.
29
+ * @uv-modifier
30
+ */
31
+ vec2 center(vec2 uv) {
32
+ return (uv - 0.5 * u_resolution) / length(u_resolution);
33
+ }
34
+
35
+ /**
36
+ * Translate UV coordinates by offset.
37
+ * @uv-modifier
38
+ */
39
+ vec2 translate(vec2 uv, vec2 offset) {
40
+ return uv - offset;
41
+ }
42
+
43
+ /**
44
+ * Scale UV coordinates by factor around origin.
45
+ * @uv-modifier
46
+ */
47
+ vec2 scale(vec2 uv, float factor) {
48
+ return uv * factor;
49
+ }
50
+
51
+ /**
52
+ * Zoom — scale UV with aspect ratio correction.
53
+ * Expects centered UV (use center() first).
54
+ * Pushes UV outward/inward from origin.
55
+ * factor = zoom factor (>1 = zoom in, <1 = zoom out)
56
+ * @uv-modifier
57
+ */
58
+ vec2 zoom(vec2 uv, float factor) {
59
+ return uv / max(factor, 0.001);
60
+ }
61
+
62
+ /**
63
+ * Normalize UV to range -1 to 1 with aspect ratio correction.
64
+ * @uv-modifier
65
+ */
66
+ vec2 norm(vec2 uv) {
67
+ uv *= min(u_resolution.x, u_resolution.y) / length(u_resolution);
68
+ return uv;
69
+ }
70
+
71
+ /**
72
+ * Rotate UV coordinates around origin by angle (radians).
73
+ * @uv-modifier
74
+ */
75
+ vec2 rotate(vec2 uv, float angle) {
76
+ float c = cos(angle);
77
+ float s = sin(angle);
78
+ return vec2(uv.x * c - uv.y * s, uv.x * s + uv.y * c);
79
+ }
80
+
81
+ /**
82
+ * Tile — repeat coordinates in a grid of given size.
83
+ * @uv-modifier
84
+ */
85
+ vec2 tile(vec2 uv, float size) {
86
+ return fract(uv / size) * size;
87
+ }
88
+
89
+ /**
90
+ * Cartesian to polar coordinates.
91
+ * Returns vec2(angle, radius) where angle is -PI to PI.
92
+ */
93
+ vec2 polar(vec2 uv) {
94
+ return vec2(atan(uv.y, uv.x), length(uv));
95
+ }
96
+
97
+ /**
98
+ * Aspect ratio correction — makes UV square regardless of canvas shape.
99
+ * @uv-modifier
100
+ */
101
+ vec2 aspect(vec2 uv) {
102
+ return uv * vec2(u_resolution.x / u_resolution.y, 1.0);
103
+ }
104
+
105
+ // ─── Math Utilities ─────────────────────────────────────────
106
+
107
+ /**
108
+ * Remap a value from one range to another.
109
+ * map(0.5, 0.0, 1.0, -1.0, 1.0) → 0.0
110
+ */
111
+ float map(float value, float inMin, float inMax, float outMin, float outMax) {
112
+ return outMin + (value - inMin) * (outMax - outMin) / (inMax - inMin);
113
+ }
114
+
115
+ // ─── Noise & Random ─────────────────────────────────────────
116
+
117
+ /**
118
+ * Pseudo-random hash from 2D coordinates.
119
+ * Returns float in 0–1 range.
120
+ */
121
+ float hash(vec2 p) {
122
+ return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);
123
+ }
124
+
125
+ /**
126
+ * 2D pseudo-random hash.
127
+ * Returns vec2 in 0–1 range — used for point scattering (worley etc).
128
+ */
129
+ vec2 hash2(vec2 p) {
130
+ p = vec2(dot(p, vec2(127.1, 311.7)), dot(p, vec2(269.5, 183.3)));
131
+ return fract(sin(p) * 43758.5453123);
132
+ }
133
+
134
+ /**
135
+ * Smooth value noise — interpolated hash grid.
136
+ */
137
+ float noise(vec2 p) {
138
+ vec2 i = floor(p);
139
+ vec2 f = fract(p);
140
+ vec2 u = f * f * (3.0 - 2.0 * f);
141
+
142
+ return mix(
143
+ mix(hash(i), hash(i + vec2(1.0, 0.0)), u.x),
144
+ mix(hash(i + vec2(0.0, 1.0)), hash(i + vec2(1.0, 1.0)), u.x),
145
+ u.y
146
+ );
147
+ }
148
+
149
+ /**
150
+ * Fractal Brownian Motion — 6 octaves of layered noise.
151
+ * Returns ~0–1 range. Great for clouds, terrain, organic textures.
152
+ */
153
+ float fbm(vec2 p) {
154
+ float value = 0.0;
155
+ float amplitude = 0.5;
156
+
157
+ for (int i = 0; i < 6; i++) {
158
+ value += amplitude * noise(p);
159
+ p *= 2.0;
160
+ amplitude *= 0.5;
161
+ }
162
+
163
+ return value;
164
+ }
165
+
166
+ /**
167
+ * Worley (cellular / voronoi) noise.
168
+ * Returns distance to nearest random cell point.
169
+ * Great for cells, cracks, organic patterns.
170
+ */
171
+ float worley(vec2 p) {
172
+ vec2 i = floor(p);
173
+ vec2 f = fract(p);
174
+ float minDist = 1.0;
175
+
176
+ for (int y = -1; y <= 1; y++) {
177
+ for (int x = -1; x <= 1; x++) {
178
+ vec2 neighbor = vec2(float(x), float(y));
179
+ vec2 point = hash2(i + neighbor);
180
+ float dist = length(neighbor + point - f);
181
+ minDist = min(minDist, dist);
182
+ }
183
+ }
184
+
185
+ return minDist;
186
+ }
187
+
188
+ /**
189
+ * Waves — layered sine wave interference pattern.
190
+ * Creates clean, regular wave lines like fabric or moiré.
191
+ * frequency = wave density (5.0 = fabric, 10.0 = fine lines)
192
+ * Returns 0–1 range.
193
+ */
194
+ float waves(vec2 p, float frequency) {
195
+ return 0.6 + 0.4 * sin(
196
+ frequency * (p.x + p.y + cos(3.0 * p.x + 5.0 * p.y)) +
197
+ sin(frequency * 4.0 * (p.x + p.y))
198
+ );
199
+ }
200
+
201
+ /**
202
+ * Voronoi cell lookup — returns the position of the nearest cell point.
203
+ * Same algorithm as worley, but returns the point instead of distance.
204
+ * Great for UV snapping, cell-based effects.
205
+ */
206
+ vec2 voronoi(vec2 p) {
207
+ vec2 i = floor(p);
208
+ vec2 f = fract(p);
209
+ float minDist = 10.0;
210
+ vec2 nearest = vec2(0.0);
211
+
212
+ for (int y = -1; y <= 1; y++) {
213
+ for (int x = -1; x <= 1; x++) {
214
+ vec2 neighbor = vec2(float(x), float(y));
215
+ vec2 point = hash2(i + neighbor);
216
+ float dist = length(neighbor + point - f);
217
+ if (dist < minDist) {
218
+ minDist = dist;
219
+ nearest = i + neighbor + point;
220
+ }
221
+ }
222
+ }
223
+
224
+ return nearest;
225
+ }
226
+
227
+ void main() {}
228
+ `,fe=`/**
229
+ * Hex integer to RGB.
230
+ * Usage: hex(0xFF6600) → orange
231
+ */
232
+ vec3 hex(int value) {
233
+ float v = float(value);
234
+ float r = floor(v / 65536.0);
235
+ float g = floor((v - r * 65536.0) / 256.0);
236
+ float b = v - r * 65536.0 - g * 256.0;
237
+ return vec3(r, g, b) / 255.0;
238
+ }
239
+
240
+ /**
241
+ * RGB 0–255 to normalized RGB 0–1.
242
+ * Usage: rgb255(255.0, 128.0, 0.0) → orange
243
+ */
244
+ vec3 rgb255(float r, float g, float b) {
245
+ return vec3(r, g, b) / 255.0;
246
+ }
247
+
248
+ /**
249
+ * HSV to RGB.
250
+ * Input: vec3(hue 0–1, saturation 0–1, value 0–1)
251
+ */
252
+ vec3 hsv(vec3 c) {
253
+ vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
254
+ vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
255
+ return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
256
+ }
257
+
258
+ /**
259
+ * HSL to RGB.
260
+ * Input: vec3(hue 0–1, saturation 0–1, lightness 0–1)
261
+ */
262
+ vec3 hsl(vec3 c) {
263
+ vec3 rgb = clamp(abs(mod(c.x * 6.0 + vec3(0.0, 4.0, 2.0), 6.0) - 3.0) - 1.0, 0.0, 1.0);
264
+ return c.z + c.y * (rgb - 0.5) * (1.0 - abs(2.0 * c.z - 1.0));
265
+ }
266
+
267
+ /**
268
+ * Linear gradient between two colors.
269
+ * t is clamped to 0–1.
270
+ */
271
+ vec3 gradient(vec3 a, vec3 b, float t) {
272
+ return mix(a, b, clamp(t, 0.0, 1.0));
273
+ }
274
+
275
+ /**
276
+ * 3-stop gradient.
277
+ * t=0 → a, t=0.5 → b, t=1 → c
278
+ */
279
+ vec3 gradient3(vec3 a, vec3 b, vec3 c, float t) {
280
+ t = clamp(t, 0.0, 1.0);
281
+ return t < 0.5
282
+ ? mix(a, b, t * 2.0)
283
+ : mix(b, c, (t - 0.5) * 2.0);
284
+ }
285
+
286
+ /**
287
+ * Cosine palette — Inigo Quilez formula.
288
+ * color = a + b * cos(2π(c·t + d))
289
+ * Generates infinite smooth color ramps from 4 vec3 params.
290
+ */
291
+ vec3 palette(vec3 a, vec3 b, vec3 c, vec3 d, float t) {
292
+ return a + b * cos(6.28318 * (c * t + d));
293
+ }
294
+
295
+ /**
296
+ * Banded gradient — 3-zone color mapping with sharp transitions.
297
+ * Uses tent functions instead of linear interpolation.
298
+ * t=0 → b (center), t=1 → a (middle), t=2 → c (outer).
299
+ * sharpness = transition width (2.0 = sharp, 1.0 = soft).
300
+ */
301
+ vec3 bands(vec3 a, vec3 b, vec3 c, float t, float sharpness) {
302
+ float w1 = max(0.0, 1.0 - sharpness * abs(1.0 - t));
303
+ float w2 = max(0.0, 1.0 - sharpness * abs(t));
304
+ float w3 = 1.0 - min(1.0, w1 + w2);
305
+ return a * w1 + b * w2 + c * w3;
306
+ }
307
+
308
+ /**
309
+ * Iridescent — iterative interference color pattern.
310
+ * Generates rainbow-like colors from UV through trigonometric iteration.
311
+ * Creates shimmering, oil-slick-like color fields.
312
+ * time = animation time (pass u_time), speed = animation speed
313
+ */
314
+ vec3 iridescent(vec2 uv, float time, float speed) {
315
+ float d = -time * 0.5 * speed;
316
+ float a = 0.0;
317
+ for (int i = 0; i < 8; i++) {
318
+ a += cos(float(i) - d - a * uv.x);
319
+ d += sin(uv.y * float(i) + a);
320
+ }
321
+ d += time * 0.5 * speed;
322
+ vec3 col = vec3(cos(uv * vec2(d, a)) * 0.6 + 0.4, cos(a + d) * 0.5 + 0.5);
323
+ return cos(col * cos(vec3(d, a, 2.5)) * 0.5 + 0.5);
324
+ }
325
+
326
+ void main() {}
327
+ `,he=`// ─── Time Shapers ──────────────────────────────────────────
328
+ // Convert raw time (u_time) to normalized 0–1 range.
329
+ // Output feeds directly into easing functions.
330
+
331
+ /**
332
+ * Loop — repeating sawtooth 0→1→0→1...
333
+ * duration = cycle length in seconds
334
+ */
335
+ float loop(float t, float duration) {
336
+ return fract(t / duration);
337
+ }
338
+
339
+ /**
340
+ * Pingpong — triangle wave 0→1→0→1...
341
+ * duration = half-cycle length (0→1 takes \`duration\` seconds)
342
+ */
343
+ float pingpong(float t, float duration) {
344
+ float m = mod(t, duration * 2.0);
345
+ return m < duration ? m / duration : 2.0 - m / duration;
346
+ }
347
+
348
+ /**
349
+ * Once — single play 0→1, then stays at 1.
350
+ * duration = animation length in seconds
351
+ * Use with delay: once(u_time - 2.0, 3.0) starts at 2s, takes 3s.
352
+ */
353
+ float once(float t, float duration) {
354
+ return clamp(t / duration, 0.0, 1.0);
355
+ }
356
+
357
+ /**
358
+ * Reverse — flip animation direction.
359
+ * Turns 0→1 into 1→0. Works with any easing or shaper.
360
+ * Usage: reverse(spring(loop(u_time, 2.0))) for spring zoom-in.
361
+ */
362
+ float reverse(float t) {
363
+ return 1.0 - t;
364
+ }
365
+
366
+ // ─── Easing Curves ─────────────────────────────────────────
367
+ // All take t (0–1) and return shaped t (0–1).
368
+ // Compose with time shapers: ease_in(loop(u_time, 2.0))
369
+
370
+ /**
371
+ * Ease in — cubic acceleration. Slow start, fast end.
372
+ */
373
+ float ease_in(float t) {
374
+ return t * t * t;
375
+ }
376
+
377
+ /**
378
+ * Ease out — cubic deceleration. Fast start, slow end.
379
+ */
380
+ float ease_out(float t) {
381
+ float f = 1.0 - t;
382
+ return 1.0 - f * f * f;
383
+ }
384
+
385
+ /**
386
+ * Ease in-out — cubic smooth both ends.
387
+ */
388
+ float ease_in_out(float t) {
389
+ return t < 0.5
390
+ ? 4.0 * t * t * t
391
+ : 1.0 - pow(-2.0 * t + 2.0, 3.0) * 0.5;
392
+ }
393
+
394
+ /**
395
+ * Spring — damped oscillation. Overshoots then settles at 1.
396
+ */
397
+ float spring(float t) {
398
+ return 1.0 - exp(-6.0 * t) * cos(12.0 * t);
399
+ }
400
+
401
+ /**
402
+ * Bounce — bouncing ball landing. Multiple bounces settling at 1.
403
+ */
404
+ float bounce(float t) {
405
+ if (t < 1.0 / 2.75) {
406
+ return 7.5625 * t * t;
407
+ } else if (t < 2.0 / 2.75) {
408
+ t -= 1.5 / 2.75;
409
+ return 7.5625 * t * t + 0.75;
410
+ } else if (t < 2.5 / 2.75) {
411
+ t -= 2.25 / 2.75;
412
+ return 7.5625 * t * t + 0.9375;
413
+ } else {
414
+ t -= 2.625 / 2.75;
415
+ return 7.5625 * t * t + 0.984375;
416
+ }
417
+ }
418
+
419
+ /**
420
+ * Elastic — springy overshoot with oscillation.
421
+ */
422
+ float elastic(float t) {
423
+ return sin(13.0 * 3.14159 * 0.5 * t) * pow(2.0, -10.0 * t) + 1.0;
424
+ }
425
+
426
+ /**
427
+ * Overshoot — goes past 1, then pulls back. Slight rubber-band feel.
428
+ */
429
+ float overshoot(float t) {
430
+ float s = 1.70158;
431
+ float f = 1.0 - t;
432
+ return 1.0 - f * f * (f * (s + 1.0) - s);
433
+ }
434
+
435
+ /**
436
+ * Teleport — barely creeps, then near-instant jump with spring settle.
437
+ * Duration mostly = wait time. Jump happens at ~85% of t.
438
+ * Tiny slow drift → snap → spring overshoot → settle at 1.
439
+ */
440
+ float teleport(float t) {
441
+ float jump = smoothstep(0.8, 0.85, t);
442
+ float creep = pow(t / 0.8, 4.0) * 0.1 * (1.0 - jump);
443
+ float s = max(t - 0.85, 0.0) * 6.667;
444
+ float settle = exp(-5.0 * s) * sin(s * 15.0) * 0.15;
445
+ return creep + jump + settle;
446
+ }
447
+
448
+ void main() {}
449
+ `,de=`#import hash from 'sandbox'
450
+ #import noise from 'sandbox'
451
+ #import fbm from 'sandbox'
452
+ #import voronoi from 'sandbox'
453
+ #import worley from 'sandbox'
454
+
455
+ uniform float u_intensity;
456
+
457
+ // ─── UV Effects ─────────────────────────────────────────────
458
+ // Each function takes UV and returns modified UV.
459
+ // All use u_intensity uniform for configuration.
460
+
461
+ /**
462
+ * Pixelate — blocky mosaic effect.
463
+ * Snaps UV to a grid. Higher intensity = larger pixels.
464
+ * intensity = pixel count along shortest axis (default: 20)
465
+ * @uv-modifier
466
+ */
467
+ vec2 pixelate(vec2 uv, float intensity) {
468
+ float size = length(u_resolution) / (max(intensity, 1.0) * 10.0);
469
+ return floor(uv / size) * size;
470
+ }
471
+
472
+ /**
473
+ * Twist — spiral distortion from center outward.
474
+ * Expects centered UV (use center() first).
475
+ * intensity = twist strength (0.4 = subtle, 1.0 = full spiral)
476
+ * @uv-modifier
477
+ */
478
+ vec2 twist(vec2 uv, float intensity) {
479
+ float dist = length(uv);
480
+ float angle = atan(uv.y, uv.x) - intensity * 20.0 * dist;
481
+ return vec2(cos(angle), sin(angle)) * dist;
482
+ }
483
+
484
+ /**
485
+ * Ripple — concentric wave distortion from center.
486
+ * Expects centered UV (use center() first).
487
+ * Creates water-drop-like rings.
488
+ * intensity = wave amplitude (0.5 = gentle, 2.0 = strong)
489
+ * @uv-modifier
490
+ */
491
+ vec2 ripple(vec2 uv, float intensity) {
492
+ float dist = length(uv);
493
+ float wave = sin(dist * 40.0 - u_time * 3.0) * intensity * 0.02;
494
+ return uv + normalize(uv + 0.001) * wave;
495
+ }
496
+
497
+ /**
498
+ * Fisheye — barrel distortion from center.
499
+ * Expects centered UV (use center() first).
500
+ * Bends space outward like a fisheye lens.
501
+ * intensity = distortion power (0.5 = subtle, 2.0 = extreme)
502
+ * @uv-modifier
503
+ */
504
+ vec2 fisheye(vec2 uv, float intensity) {
505
+ float dist = length(uv);
506
+ float power = pow(dist, intensity) / dist;
507
+ return uv * power;
508
+ }
509
+
510
+ /**
511
+ * Wobble — animated sine wave displacement.
512
+ * Creates a jelly-like horizontal wobble.
513
+ * intensity = wobble amount (1.0 = gentle, 5.0 = wild)
514
+ * @uv-modifier
515
+ */
516
+ vec2 wobble(vec2 uv, float intensity) {
517
+ uv.x += sin(uv.y * 10.0 + u_time * 2.0) * intensity * 0.01;
518
+ uv.y += cos(uv.x * 10.0 + u_time * 2.0) * intensity * 0.01;
519
+ return uv;
520
+ }
521
+
522
+ /**
523
+ * Organic — iterative fluid morph distortion.
524
+ * Creates marble-like flowing patterns.
525
+ * intensity = animation speed (3.0 = default)
526
+ * @uv-modifier
527
+ */
528
+ vec2 organic(vec2 uv, float intensity) {
529
+ float speed = u_time * intensity;
530
+ vec2 acc = vec2(uv.x + uv.y);
531
+
532
+ for (int i = 0; i < 5; i++) {
533
+ acc += sin(max(uv.x, uv.y)) + uv;
534
+ uv += 0.5 * vec2(
535
+ cos(5.1123314 + 0.353 * acc.y + speed * 0.131121),
536
+ sin(acc.x - 0.113 * speed)
537
+ );
538
+ uv -= cos(uv.x + uv.y) - sin(uv.x * 0.711 - uv.y);
539
+ }
540
+
541
+ return uv;
542
+ }
543
+
544
+ /**
545
+ * Glitch — random horizontal line displacement.
546
+ * Creates digital glitch artifact bands.
547
+ * intensity = glitch strength (0.5 = subtle, 3.0 = heavy)
548
+ * @uv-modifier
549
+ */
550
+ vec2 glitch(vec2 uv, float intensity) {
551
+ float line = floor(uv.y * 50.0);
552
+ float shift = hash(vec2(line, floor(u_time * 8.0)));
553
+ shift = step(0.9, shift) * (shift - 0.9) * 10.0;
554
+ uv.x += shift * intensity * 0.1 * u_resolution.x;
555
+ return uv;
556
+ }
557
+
558
+ /**
559
+ * Mirror — reflect UV across a chosen axis.
560
+ * Creates bilateral symmetry.
561
+ * intensity = 0 for horizontal mirror, 1 for vertical mirror
562
+ * @uv-modifier
563
+ */
564
+ vec2 mirror(vec2 uv, float intensity) {
565
+ if (intensity < 0.5) {
566
+ uv.x = abs(uv.x);
567
+ } else {
568
+ uv.y = abs(uv.y);
569
+ }
570
+ return uv;
571
+ }
572
+
573
+ /**
574
+ * Kaleidoscope — repeating angular symmetry.
575
+ * Expects centered UV (use center() first).
576
+ * Creates mandala-like radial repeats.
577
+ * intensity = number of segments (4 = quad, 6 = hex, 8 = octa)
578
+ * @uv-modifier
579
+ */
580
+ vec2 kaleidoscope(vec2 uv, float intensity) {
581
+ float segments = max(intensity, 1.0);
582
+ float angle = atan(uv.y, uv.x);
583
+ float segment_angle = 6.28318 / segments;
584
+ angle = mod(angle, segment_angle);
585
+ angle = abs(angle - segment_angle * 0.5);
586
+ float r = length(uv);
587
+ return vec2(cos(angle), sin(angle)) * r;
588
+ }
589
+
590
+ /**
591
+ * Warp — domain warping using fractal noise.
592
+ * Displaces UV by layered fbm noise for smoke/cloud-like distortion.
593
+ * Animated over time.
594
+ * intensity = warp strength (0.5 = subtle haze, 3.0 = heavy distortion)
595
+ * @uv-modifier
596
+ */
597
+ vec2 warp(vec2 uv, float intensity) {
598
+ vec2 offset = vec2(
599
+ fbm(uv + u_time * 0.3),
600
+ fbm(uv + vec2(5.2, 1.3) + u_time * 0.3)
601
+ );
602
+ return uv + offset * intensity * 0.1;
603
+ }
604
+
605
+ /**
606
+ * Displace — noise-based UV displacement.
607
+ * Shifts UV using smooth value noise for a wavy, heat-haze look.
608
+ * Animated over time.
609
+ * intensity = displacement amount (1.0 = gentle, 5.0 = strong)
610
+ * @uv-modifier
611
+ */
612
+ vec2 displace(vec2 uv, float intensity) {
613
+ float nx = noise(uv * 5.0 + u_time);
614
+ float ny = noise(uv * 5.0 + vec2(3.7, 7.1) + u_time);
615
+ return uv + (vec2(nx, ny) - 0.5) * intensity * 0.05;
616
+ }
617
+
618
+ /**
619
+ * Shatter — voronoi cell-based UV snapping.
620
+ * Snaps UV to nearest cell point, creating a broken-glass look.
621
+ * intensity = cell density (5.0 = large shards, 20.0 = fine fragments)
622
+ * @uv-modifier
623
+ */
624
+ vec2 shatter(vec2 uv, float intensity) {
625
+ return voronoi(uv * intensity) / intensity;
626
+ }
627
+
628
+ /**
629
+ * Cells — cellular distortion using Worley distance.
630
+ * Displaces UV outward from cell edges, like looking through textured glass.
631
+ * intensity = cell scale (3.0 = large bubbles, 15.0 = fine texture)
632
+ * @uv-modifier
633
+ */
634
+ vec2 cells(vec2 uv, float intensity) {
635
+ float dist = worley(uv * intensity);
636
+ vec2 grad = vec2(
637
+ worley(uv * intensity + vec2(0.01, 0.0)) - dist,
638
+ worley(uv * intensity + vec2(0.0, 0.01)) - dist
639
+ );
640
+ return uv + grad * dist * 2.0;
641
+ }
642
+
643
+ void main() {}
644
+ `,me=`#import hash from 'sandbox'
645
+
646
+ uniform float u_intensity;
647
+
648
+ // ─── Color Filters ──────────────────────────────────────────
649
+ // Each function takes a color and returns modified color.
650
+ // All use u_intensity uniform for configuration.
651
+
652
+ /**
653
+ * Contrast — adjust contrast around mid-gray.
654
+ * intensity: 1.0 = original, >1 = more contrast, <1 = flatter
655
+ * @color-modifier
656
+ */
657
+ vec3 contrast(vec3 color, float intensity) {
658
+ return (color - 0.5) * intensity + 0.5;
659
+ }
660
+
661
+ /**
662
+ * Brightness — multiply overall brightness.
663
+ * intensity: 1.0 = original, >1 = brighter, <1 = darker
664
+ * @color-modifier
665
+ */
666
+ vec3 brightness(vec3 color, float intensity) {
667
+ return color * intensity;
668
+ }
669
+
670
+ /**
671
+ * Saturate — adjust color saturation.
672
+ * intensity: 0 = grayscale, 1.0 = original, >1 = oversaturated
673
+ * @color-modifier
674
+ */
675
+ vec3 saturate(vec3 color, float intensity) {
676
+ float gray = dot(color, vec3(0.299, 0.587, 0.114));
677
+ return mix(vec3(gray), color, intensity);
678
+ }
679
+
680
+ /**
681
+ * Posterize — reduce color to N discrete levels per channel.
682
+ * intensity = number of levels (4 = retro, 16 = subtle, 256 = nearly smooth)
683
+ * @color-modifier
684
+ */
685
+ vec3 posterize(vec3 color, float intensity) {
686
+ float levels = max(intensity, 1.0);
687
+ return floor(color * levels + 0.5) / levels;
688
+ }
689
+
690
+ /**
691
+ * Threshold — convert to black and white based on cutoff.
692
+ * intensity = cutoff point (0.5 = balanced, lower = more white)
693
+ * @color-modifier
694
+ */
695
+ vec3 threshold(vec3 color, float intensity) {
696
+ float avg = dot(color, vec3(0.299, 0.587, 0.114));
697
+ return avg > intensity ? vec3(1.0) : vec3(0.0);
698
+ }
699
+
700
+ /**
701
+ * Invert — flip all color channels.
702
+ * intensity: 0.0 = original, 1.0 = fully inverted, 0.5 = mid-gray
703
+ * @color-modifier
704
+ */
705
+ vec3 invert(vec3 color, float intensity) {
706
+ return mix(color, 1.0 - color, intensity);
707
+ }
708
+
709
+ /**
710
+ * Glow — luminance-based bloom, bright areas get amplified.
711
+ * intensity = glow strength (0.5 = subtle, 2.0 = intense)
712
+ * @color-modifier
713
+ */
714
+ vec3 glow(vec3 color, float intensity) {
715
+ float luminance = dot(color, vec3(0.299, 0.587, 0.114));
716
+ return color + color * luminance * intensity;
717
+ }
718
+
719
+ /**
720
+ * Grain — animated film noise overlay.
721
+ * intensity = noise strength (0.1 = subtle, 0.5 = heavy)
722
+ * @color-modifier
723
+ */
724
+ vec3 grain(vec3 color, vec2 uv, float intensity) {
725
+ float n = (hash(uv * 1000.0 + u_time) - 0.5) * intensity;
726
+ return color + n;
727
+ }
728
+
729
+ /**
730
+ * Vignette — darken canvas edges.
731
+ * Applies circular falloff from center.
732
+ * intensity = darkness strength (1.0 = subtle, 2.0 = strong)
733
+ * @color-modifier
734
+ */
735
+ vec3 vignette(vec3 color, vec2 uv, float intensity) {
736
+ vec2 centered = uv / u_resolution - 0.5;
737
+ float dist = length(centered);
738
+ float falloff = 1.0 - smoothstep(0.3, 0.7, dist * intensity);
739
+ return color * falloff;
740
+ }
741
+
742
+ /**
743
+ * Sepia — warm brownish tint like old photographs.
744
+ * intensity: 0.0 = original, 1.0 = full sepia
745
+ * @color-modifier
746
+ */
747
+ vec3 sepia(vec3 color, float intensity) {
748
+ vec3 s;
749
+ s.r = dot(color, vec3(0.393, 0.769, 0.189));
750
+ s.g = dot(color, vec3(0.349, 0.686, 0.168));
751
+ s.b = dot(color, vec3(0.272, 0.534, 0.131));
752
+ return mix(color, s, intensity);
753
+ }
754
+
755
+ /**
756
+ * Gamma — apply gamma correction curve.
757
+ * intensity = gamma value (1.0 = linear, 2.2 = standard sRGB, <1 = brighten darks)
758
+ * @color-modifier
759
+ */
760
+ vec3 gamma(vec3 color, float intensity) {
761
+ return pow(max(color, 0.0), vec3(1.0 / max(intensity, 0.001)));
762
+ }
763
+
764
+ /**
765
+ * Tint — blend color toward a target tint.
766
+ * intensity: 0.0 = original, 1.0 = fully tinted
767
+ * @color-modifier
768
+ */
769
+ vec3 tint(vec3 color, vec3 tintColor, float intensity) {
770
+ return mix(color, color * tintColor, intensity);
771
+ }
772
+
773
+ /**
774
+ * Highlights — add white light to bright areas.
775
+ * Uses max channel brightness so even saturated colors trigger highlights.
776
+ * intensity = highlight strength (0.2 = subtle sheen, 1.0 = strong gloss)
777
+ * @color-modifier
778
+ */
779
+ vec3 highlights(vec3 color, float intensity) {
780
+ float bright = max(color.r, max(color.g, color.b + 0.3));
781
+ return color + max(bright * 5.5 - 4.0, 0.0) * intensity;
782
+ }
783
+
784
+ /**
785
+ * Bayer 8×8 threshold matrix — computed mathematically.
786
+ * Returns threshold value 0–1 for ordered dithering.
787
+ */
788
+ float bayer8(vec2 p) {
789
+ p = mod(floor(p), 8.0);
790
+ float value = 0.0;
791
+ float divisor = 1.0;
792
+ float multiplier = 16.0;
793
+
794
+ for (int i = 0; i < 3; i++) {
795
+ vec2 q = mod(floor(p / divisor), 2.0);
796
+ value += (q.x * 2.0 + q.y * 3.0 - q.x * q.y * 4.0) * multiplier;
797
+ divisor *= 2.0;
798
+ multiplier *= 0.25;
799
+ }
800
+
801
+ return value / 64.0;
802
+ }
803
+
804
+ /**
805
+ * Dither — ordered Bayer 8×8 dithering.
806
+ * Reduces color to discrete levels with a threshold pattern.
807
+ * Use pixelate() on UV before coloring for blocky dither cells.
808
+ * intensity = number of color levels (2 = 1-bit, 4 = retro, 8 = subtle)
809
+ * @color-modifier
810
+ */
811
+ vec3 dither(vec3 color, vec2 uv, float intensity) {
812
+ float levels = max(intensity, 2.0);
813
+ float threshold = bayer8(uv) - 0.5;
814
+ float stepSize = 1.0 / (levels - 1.0);
815
+ color += threshold * stepSize;
816
+ return clamp(floor(color * (levels - 1.0) + 0.5) / (levels - 1.0), 0.0, 1.0);
817
+ }
818
+
819
+ /**
820
+ * Arcade — pixelated Bayer dithering.
821
+ * Combines pixelation and ordered dither for retro 8-bit look.
822
+ * intensity = number of color levels (2 = 1-bit, 4 = retro, 8 = subtle)
823
+ * @color-modifier
824
+ */
825
+ vec3 arcade(vec3 color, vec2 uv, float intensity) {
826
+ vec2 grid = uv * u_resolution * 0.5;
827
+ return dither(color, grid, intensity);
828
+ }
829
+
830
+ void main() {}
831
+ `,w=new J([new v("sandbox",ue),new v("sandbox/colors",fe),new v("sandbox/time",he),new v("sandbox/effects",de,{default:{intensity:{uniform:"u_intensity",default:1}},pixelate:{intensity:{uniform:"u_intensity",default:20}},twist:{intensity:{uniform:"u_intensity",default:1}},ripple:{intensity:{uniform:"u_intensity",default:1}},fisheye:{intensity:{uniform:"u_intensity",default:1}},wobble:{intensity:{uniform:"u_intensity",default:1}},organic:{intensity:{uniform:"u_intensity",default:3}},glitch:{intensity:{uniform:"u_intensity",default:1}},mirror:{intensity:{uniform:"u_intensity",default:0}},kaleidoscope:{intensity:{uniform:"u_intensity",default:6}},zoom:{intensity:{uniform:"u_intensity",default:1}},warp:{intensity:{uniform:"u_intensity",default:1}},displace:{intensity:{uniform:"u_intensity",default:1}},shatter:{intensity:{uniform:"u_intensity",default:10}},cells:{intensity:{uniform:"u_intensity",default:8}},glass:{intensity:{uniform:"u_intensity",default:1}}}),new v("sandbox/filters",me,{default:{intensity:{uniform:"u_intensity",default:1}},posterize:{intensity:{uniform:"u_intensity",default:8}},threshold:{intensity:{uniform:"u_intensity",default:.5}},grain:{intensity:{uniform:"u_intensity",default:.1}},vignette:{intensity:{uniform:"u_intensity",default:1.4}},glow:{intensity:{uniform:"u_intensity",default:.5}},gamma:{intensity:{uniform:"u_intensity",default:2.2}},dither:{intensity:{uniform:"u_intensity",default:4}},highlights:{intensity:{uniform:"u_intensity",default:.5}}})]),y=new J,S=new Map([["u_resolution","vec2"],["u_time","float"],["u_delta","float"],["u_mouse","vec2"],["u_frame","int"]]);class pe{constructor(e){o(this,"gl");o(this,"program",null);o(this,"uniforms",new Map);this.gl=e}attachProgram(e){this.program=e;for(const t of this.uniforms.values())t.invalidateLocation();return this}set(e,t){const n=this.uniforms.get(e);return n?n.setValue(t):this.uniforms.set(e,new T(e,t)),this}setMany(e){for(const[t,n]of Object.entries(e))this.set(t,n);return this}get(e){var t;return(t=this.uniforms.get(e))==null?void 0:t.getValue()}has(e){return this.uniforms.has(e)}delete(e){return this.uniforms.delete(e)}uploadAll(){if(!this.program)return this;for(const e of this.uniforms.values())e.upload(this.gl,this.program);return this}uploadBuiltIns(e,t,n){if(this.set("u_resolution",t),this.set("u_time",e.time),this.set("u_delta",e.delta),this.set("u_mouse",n),this.set("u_frame",e.frame),!this.program)return this;for(const i of S.keys()){const r=this.uniforms.get(i);r&&r.upload(this.gl,this.program)}return this}clear(){this.uniforms.clear()}destroy(){this.uniforms.clear(),this.program=null}keys(){return this.uniforms.keys()}get size(){return this.uniforms.size}}class x{constructor(e,t,n,i){o(this,"name");o(this,"gl");o(this,"texture",null);o(this,"location",null);o(this,"locationResolved",!1);o(this,"source");o(this,"options");o(this,"dynamicOverride");o(this,"needsUpload",!0);o(this,"needsReupload",!1);this.gl=e,this.name=t,this.source=n,this.dynamicOverride=i==null?void 0:i.dynamic,this.options=x.resolveOptions(n,i),this.needsReupload=this.options.dynamic}setSource(e){this.source=e,this.needsUpload=!0,this.needsReupload=this.dynamicOverride??x.isDynamicSource(e)}resolveLocation(e,t){return this.locationResolved||(this.location=e.getUniformLocation(t,this.name),this.locationResolved=!0),this.location}invalidateLocation(){this.location=null,this.locationResolved=!1}upload(e,t){const n=this.gl,i=this.resolveLocation(n,e);if(i!==null){if(!this.texture){if(this.texture=n.createTexture(),!this.texture)return;this.needsUpload=!0}n.activeTexture(n.TEXTURE0+t),n.bindTexture(n.TEXTURE_2D,this.texture),(this.needsUpload||this.needsReupload)&&(this.uploadPixels(),this.needsUpload=!1),n.uniform1i(i,t)}}destroy(){this.texture&&(this.gl.deleteTexture(this.texture),this.texture=null),this.location=null,this.locationResolved=!1}uploadPixels(){const e=this.gl;e.pixelStorei(e.UNPACK_FLIP_Y_WEBGL,this.options.flipY),e.texImage2D(e.TEXTURE_2D,0,e.RGBA,e.RGBA,e.UNSIGNED_BYTE,this.source),this.applyParameters()}applyParameters(){const e=this.gl;e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,x.resolveWrap(e,this.options.wrapS)),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,x.resolveWrap(e,this.options.wrapT)),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,this.options.minFilter==="nearest"?e.NEAREST:e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,this.options.magFilter==="nearest"?e.NEAREST:e.LINEAR)}static resolveWrap(e,t){switch(t){case"repeat":return e.REPEAT;case"mirror":return e.MIRRORED_REPEAT;case"clamp":default:return e.CLAMP_TO_EDGE}}static resolveOptions(e,t){const n=(t==null?void 0:t.wrap)??"clamp";return{wrap:n,wrapS:(t==null?void 0:t.wrapS)??n,wrapT:(t==null?void 0:t.wrapT)??n,minFilter:(t==null?void 0:t.minFilter)??"linear",magFilter:(t==null?void 0:t.magFilter)??"linear",flipY:(t==null?void 0:t.flipY)??!0,dynamic:(t==null?void 0:t.dynamic)??x.isDynamicSource(e)}}static isDynamicSource(e){return e instanceof HTMLVideoElement}}class ve{constructor(e){o(this,"gl");o(this,"program",null);o(this,"textures",new Map);this.gl=e}attachProgram(e){this.program=e;for(const t of this.textures.values())t.invalidateLocation();return this}set(e,t,n){const i=this.textures.get(e);return i?i.setSource(t):this.textures.set(e,new x(this.gl,e,t,n)),this}get(e){return this.textures.get(e)}has(e){return this.textures.has(e)}delete(e){const t=this.textures.get(e);return t?(t.destroy(),this.textures.delete(e)):!1}uploadAll(){if(!this.program)return this;let e=0;for(const t of this.textures.values())t.upload(this.program,e),e++;return this}get size(){return this.textures.size}destroy(){for(const e of this.textures.values())e.destroy();this.textures.clear(),this.program=null}}class C{constructor(){o(this,"hooks",new Map)}id(){return Math.random().toString(36).substring(2,10)}add(e){const t=this.id();return this.hooks.set(t,e),()=>this.remove(t)}remove(e){this.hooks.delete(e)}run(e){for(const[t,n]of this.hooks)try{n(e)===!1&&this.remove(t)}catch(i){throw new K(t,i instanceof Error?i.message:String(i))}}destroy(){this.hooks.clear()}}class L{constructor(e,t){o(this,"canvas");o(this,"gl");o(this,"options");o(this,"onBeforeHooks",new C);o(this,"onAfterHooks",new C);o(this,"_program");o(this,"_geometry");o(this,"_uniforms");o(this,"_textures");o(this,"_clock");o(this,"_resolution",[1,1]);o(this,"_mouse",[0,0]);o(this,"_version",1);o(this,"playing",!1);this.canvas=e,this.options=t,this.gl=this.initContext(),this.enableExtensions(),this._program=new ce(this.gl),this._geometry=k.fullscreenQuad(this.gl),this._uniforms=new pe(this.gl),this._textures=new ve(this.gl),this._clock=new le,this.options.fps&&this._clock.setMaxFps(this.options.fps),this.options.onBeforeRender&&this.onBeforeHooks.add(this.options.onBeforeRender),this.options.onAfterRender&&this.onAfterHooks.add(this.options.onAfterRender),this.onRender=this.onRender.bind(this)}static setup(e,t){const n=new L(e,t);return t.vertex&&t.fragment&&n.shader(t.vertex,t.fragment),t.uniforms&&n._uniforms.setMany(t.uniforms),t.textures&&n.texturesFromSchema(t.textures),y.isEmpty()||n._uniforms.setMany(y.defaults()),n}initContext(){const e={antialias:this.options.antialias,preserveDrawingBuffer:this.options.preserveDrawingBuffer,alpha:!0,depth:!1,stencil:!1},t=this.canvas.getContext("webgl2",e);if(t)return this._version=2,t;const n=this.canvas.getContext("webgl",e);if(n)return this._version=1,n;const i=new V;throw this.options.onError(i),i}enableExtensions(){this.gl.getExtension("OES_standard_derivatives"),this.gl.getExtension("OES_texture_float"),this.gl.getExtension("OES_texture_float_linear"),this._version===1&&this.gl.getExtension("OES_vertex_array_object")}viewport(e,t,n,i){return this.canvas.width=n,this.canvas.height=i,this.gl.viewport(e,t,n,i),this._resolution=[n,i],this}clock(e){return this._clock.setTime(e),this}mouse(e,t){return this._mouse=[e,t],this}uniform(e,t){return this._uniforms.set(e,t),this}uniforms(e){return this._uniforms.setMany(e),this}getUniform(e){return this._uniforms.get(e)}texture(e,t,n){return this._textures.set(e,t,n),this}texturesFromSchema(e){for(const[t,n]of Object.entries(e))if(n instanceof HTMLImageElement||n instanceof HTMLCanvasElement||n instanceof HTMLVideoElement||n instanceof ImageBitmap||n instanceof ImageData||n instanceof OffscreenCanvas)this._textures.set(t,n);else{const{source:i,...r}=n;this._textures.set(t,i,r)}return this}removeTexture(e){return this._textures.delete(e),this}shader(e,t){try{if(y.clear(),e.version()!==t.version())throw new I(e.version(),t.version());this._program.compile(e.source(),t.compile()),this._version=t.version(),this._geometry.linkAttributes(this._program);const n=this._program.getProgram();n&&(this._uniforms.attachProgram(n),this._textures.attachProgram(n));try{this.options.onLoad()}catch(i){throw new Y(i instanceof Error?i.message:String(i))}}catch(n){n instanceof h&&this.options.onError(n)}return this}play(){return this.playing?this:(this.playing=!0,this._clock.start(this.onRender),this)}pause(){if(!this.playing)return this;const e=this._clock.getState();try{this.onBeforeHooks.run(e)}catch(t){t instanceof h&&this.options.onError(t)}this.playing=!1,this._clock.stop();try{this.onAfterHooks.run(e)}catch(t){t instanceof h&&this.options.onError(t)}return this}render(){return this.onRender(this._clock.getState()),this}getContext(){return this.gl}getVersion(){return this._version}getClock(){return this._clock}destroy(){this.pause(),this._clock.destroy(),this._geometry.destroy(),this._program.destroy(),this._uniforms.destroy(),this._textures.destroy(),this.onAfterHooks.destroy(),this.onBeforeHooks.destroy(),y.clear()}onRender(e){const t=this.gl;try{this.onBeforeHooks.run(e)}catch(n){n instanceof h&&this.options.onError(n)}t.clearColor(0,0,0,0),t.clear(t.COLOR_BUFFER_BIT),this._program.use(),this._uniforms.uploadBuiltIns(e,this._resolution,this._mouse),this._uniforms.uploadAll(),this._textures.uploadAll(),this._geometry.bind(),this._geometry.draw();try{this.onAfterHooks.run(e)}catch(n){n instanceof h&&this.options.onError(n)}}}class m extends Q{constructor(e){super(e),S.forEach((t,n)=>{this.requirements.uniforms.set(n,{name:n,type:t,line:0})})}}const A=`#ifdef GL_ES
6
832
  precision mediump float;
7
833
  #endif
8
834
 
@@ -15,7 +841,7 @@ void main() {
15
841
  v_texcoord = a_texcoord;
16
842
  gl_Position = vec4(a_position, 0.0, 1.0);
17
843
  }
18
- `,E=`#ifdef GL_ES
844
+ `,F=`#ifdef GL_ES
19
845
  precision mediump float;
20
846
  #endif
21
847
 
@@ -29,7 +855,7 @@ void main() {
29
855
  vec3 color = vec3(uv.x, uv.y, 0.5 + 0.5 * sin(u_time));
30
856
  gl_FragColor = vec4(color, 1.0);
31
857
  }
32
- `,y=`#version 300 es
858
+ `,O=`#version 300 es
33
859
 
34
860
  in vec2 a_position;
35
861
  in vec2 a_texcoord;
@@ -39,7 +865,7 @@ out vec2 v_texcoord;
39
865
  void main() {
40
866
  v_texcoord = a_texcoord;
41
867
  gl_Position = vec4(a_position, 0.0, 1.0);
42
- }`,V=`#version 300 es
868
+ }`,ge=`#version 300 es
43
869
  precision highp float;
44
870
 
45
871
  uniform vec2 u_resolution;
@@ -53,5 +879,5 @@ void main() {
53
879
  vec2 uv = gl_FragCoord.xy / u_resolution;
54
880
  vec3 color = vec3(uv.x, uv.y, 0.5 + 0.5 * sin(u_time));
55
881
  fragColor = vec4(color, 1.0);
56
- }`;class b{constructor(t,e){r(this,"listeners",[]);r(this,"canvasEl");r(this,"options");r(this,"engine");r(this,"usingCustomVertex",!1);this.canvasEl=t,this.options=this.resolveOptions(e),this.engine=_.setup(this.canvasEl,this.options),this.setupListeners(),this.setViewport(),this.options.autoplay&&this.play()}static create(t,e){return new b(t,e)}resolveOptions(t){const e={vertex:g,fragment:E,autoplay:!0,pauseWhenHidden:!0,dpr:"auto",fps:0,preserveDrawingBuffer:!1,antialias:!0,onError:i=>{console.error("Oops!",i,`
57
- You can handle errors programmatically by providing an onError callback to suppress this log and implement custom fallback behavior.`)},onLoad:()=>{},onBeforeRender:null,onAfterRender:null,uniforms:{}};if(t!=null&&t.vertex&&(this.usingCustomVertex=!0),t!=null&&t.vertex&&!(t!=null&&t.fragment)){const i=a.detectVersion(t.vertex);e.vertex=t.vertex,e.fragment=i===2?V:E}if(t!=null&&t.fragment&&!(t!=null&&t.vertex)){const i=a.detectVersion(t.fragment);e.fragment=t.fragment,e.vertex=i===2?y:g}return{...e,...t}}setupListeners(){this.listeners.push(u.on(window,"resize",()=>{this.setViewport()}),u.on(this.canvasEl,"resize",()=>{this.setViewport()}),(()=>{let t=!1;return u.on(document,"scroll",e=>{this.options.pauseWhenHidden&&(this.isInViewport()?t&&!this.isPlaying()&&(this.play(),t=!1):this.isPlaying()&&(this.pause(),t=!0))})})(),u.on(document,"mousemove",t=>{this.setMouse(t.clientX||t.pageX,t.clientY||t.pageY)}),u.on(document,"touchmove",t=>{t.touches.length>0&&this.setMouse(t.touches[0].clientX,t.touches[0].clientY)}))}destroyListeners(){this.listeners.forEach(t=>t()),this.listeners=[]}setViewport(){const t=this.options.dpr==="auto"?Math.min(2,window.devicePixelRatio||1):this.options.dpr,e=this.canvasEl.clientWidth||this.canvasEl.width||1,i=this.canvasEl.clientHeight||this.canvasEl.height||1;this.engine.viewport(0,0,Math.max(1,Math.floor(e*t)),Math.max(1,Math.floor(i*t)))}isInViewport(){const t=this.canvasEl.getBoundingClientRect();return t.bottom>=0&&t.right>=0&&t.top<=(window.innerHeight||document.documentElement.clientHeight)&&t.left<=(window.innerWidth||document.documentElement.clientWidth)}setMouse(t,e){const i=this.canvasEl.getBoundingClientRect();t>=i.left&&t<=i.right&&e>=i.top&&e<=i.bottom&&this.engine.mouse(t-i.left,e-i.top)}setUniform(t,e){return this.engine.uniform(t,e),this}setUniforms(t){return this.engine.uniforms(t),this}getUniform(t){return this.engine.getUniform(t)}setShader(t,e){return this.options.vertex=t,this.options.fragment=e,this.usingCustomVertex=!0,this.engine.shader(this.options.vertex,this.options.fragment),this}setFragment(t){const e=a.detectVersion(t),i=a.detectVersion(this.options.vertex);return this.options.fragment=t,e!==i&&(this.usingCustomVertex||(this.options.vertex=e===2?y:g)),this.engine.shader(this.options.vertex,this.options.fragment),this}setFps(t){return this.engine.getClock().setMaxFps(t),this}hook(t,e="before"){return e==="before"?this.engine.onBeforeHooks.add(t):this.engine.onAfterHooks.add(t)}play(){return this.engine.play(),this}playAt(t){return this.engine.clock(t),this.engine.play(),this}pause(){return this.engine.pause(),this}pauseAt(t){const e=this.hook(i=>{i.time>=t&&(e(),this.pause())},"after");return this}toggle(){return this.engine.playing?this.pause():this.play(),this}time(t){return this.engine.clock(t),this}render(){return this.engine.render(),this}renderAt(t){return this.engine.clock(t),this.engine.render(),this}isPlaying(){return this.engine.playing}get version(){return this.engine.getVersion()}get canvas(){return this.canvasEl}destroy(){this.destroyListeners(),this.engine.destroy()}}exports.Sandbox=b;exports.SandboxContextError=S;exports.SandboxError=l;exports.SandboxProgramError=d;exports.SandboxShaderCompilationError=f;exports.SandboxShaderVersionMismatchError=L;
882
+ }`;class U{constructor(e,t){o(this,"listeners",[]);o(this,"canvasEl");o(this,"options");o(this,"engine");o(this,"usingCustomVertex",!1);if(this.canvasEl=e,this.options=this.resolveOptions(t),this.engine=L.setup(this.canvasEl,this.options),this.setupListeners(),this.setViewport(),this.options.modules)for(const[n,i]of Object.entries(this.options.modules))this.module(n,i);this.options.autoplay&&this.play()}static create(e,t){return new U(e,t)}static defineModule(e,t,n={}){v.define({name:e,source:t,options:n})}static availableModules(){return w.available()}static compile(e){return new m(e).compile()}resolveOptions(e){const t={vertex:new m(A),fragment:new m(F),autoplay:!0,pauseWhenHidden:!0,dpr:"auto",fps:0,preserveDrawingBuffer:!1,antialias:!0,onError:s=>{console.error("Oops!",s,`
883
+ You can handle errors programmatically by providing an onError callback to suppress this log and implement custom fallback behavior.`)},onLoad:()=>{},onBeforeRender:null,onAfterRender:null,uniforms:{},modules:{},textures:{}};if(e!=null&&e.vertex&&(this.usingCustomVertex=!0),e!=null&&e.vertex&&!(e!=null&&e.fragment)){t.vertex=new m(e.vertex);const s=t.vertex.version();t.fragment=new m(s===2?ge:F)}if(e!=null&&e.fragment&&!(e!=null&&e.vertex)){t.fragment=new m(e.fragment);const s=t.fragment.version();t.vertex=new m(s===2?O:A)}e!=null&&e.vertex&&(e!=null&&e.fragment)&&(t.vertex=new m(e.vertex),t.fragment=new m(e.fragment));const{vertex:n,fragment:i,...r}=e||{};return{...t,...r}}setupListeners(){this.listeners.push(b.on(window,"resize",()=>{this.setViewport()}),b.on(this.canvasEl,"resize",()=>{this.setViewport()}),(()=>{let e=!1;return b.on(document,"scroll",t=>{this.options.pauseWhenHidden&&(this.isInViewport()?e&&!this.isPlaying()&&(this.play(),e=!1):this.isPlaying()&&(this.pause(),e=!0))})})(),b.on(document,"mousemove",e=>{this.setMouse(e.clientX||e.pageX,e.clientY||e.pageY)}),b.on(document,"touchmove",e=>{e.touches.length>0&&this.setMouse(e.touches[0].clientX,e.touches[0].clientY)}))}destroyListeners(){this.listeners.forEach(e=>e()),this.listeners=[]}setViewport(){const e=this.options.dpr==="auto"?Math.min(2,window.devicePixelRatio||1):this.options.dpr,t=this.canvasEl.clientWidth||this.canvasEl.width||1,n=this.canvasEl.clientHeight||this.canvasEl.height||1;this.engine.viewport(0,0,Math.max(1,Math.floor(t*e)),Math.max(1,Math.floor(n*e)))}isInViewport(){const e=this.canvasEl.getBoundingClientRect();return e.bottom>=0&&e.right>=0&&e.top<=(window.innerHeight||document.documentElement.clientHeight)&&e.left<=(window.innerWidth||document.documentElement.clientWidth)}setMouse(e,t){const n=this.canvasEl.getBoundingClientRect();e>=n.left&&e<=n.right&&t>=n.top&&t<=n.bottom&&this.engine.mouse(e-n.left,t-n.top)}setUniform(e,t){return this.engine.uniform(e,t),this}setUniforms(e){return this.engine.uniforms(e),this}getUniform(e){return this.engine.getUniform(e)}setTexture(e,t,n){return this.engine.texture(e,t,n),this}setTextures(e){return this.engine.texturesFromSchema(e),this}removeTexture(e){return this.engine.removeTexture(e),this}setShader(e,t){return this.options.vertex=new m(e),this.options.fragment=new m(t),this.usingCustomVertex=!0,this.engine.shader(this.options.vertex,this.options.fragment),this}setFragment(e){const t=new m(e),n=t.version(),i=this.options.vertex.version();return this.options.fragment=t,n!==i&&(this.usingCustomVertex||(this.options.vertex=new m(n===2?O:A))),this.engine.shader(this.options.vertex,this.options.fragment),this}getFragment(){return this.options.fragment.source()}getVertex(){return this.options.vertex.source()}setFps(e){return this.engine.getClock().setMaxFps(e),this}hook(e,t="before"){return t==="before"?this.engine.onBeforeHooks.add(e):this.engine.onAfterHooks.add(e)}module(e,t){const n=y.resolveOptions(e);if(!n)return console.warn(`Sandbox: Counld not find options for '${e}' function. Make sure you used the correct imported name and the module is currently in use by the shader.`),this;for(const[i,r]of Object.entries(t)){const s=n[i];if(!s){console.warn(`Sandbox: Option '${i}' not found for function '${e}'. Make sure to check available options with Sandbox.availableModules() and provide the correct option name.`);continue}this.setUniform(s.uniform,r)}return this}play(){return this.engine.play(),this}playAt(e){return this.engine.clock(e),this.engine.play(),this}pause(){return this.engine.pause(),this}pauseAt(e){const t=this.hook(n=>{n.time>=e&&(t(),this.pause())},"after");return this}toggle(){return this.engine.playing?this.pause():this.play(),this}time(e){return this.engine.clock(e),this}render(){return this.engine.render(),this}renderAt(e){return this.engine.clock(e),this.engine.render(),this}isPlaying(){return this.engine.playing}get version(){return this.engine.getVersion()}get canvas(){return this.canvasEl}exportAsURL(e="image/png",t){return this.canvas.toDataURL(e,t)}exportAsBlob(e="image/png",t){return new Promise((n,i)=>{this.canvas.toBlob(r=>{r?n(r):i(new Error("Failed to create blob from canvas."))},e,t)})}exportAsImage(e="image/png",t){const n=new Image;return n.src=this.exportAsURL(e,t),n}stream(e){return this.canvasEl.captureStream(e)}destroy(){this.destroyListeners(),this.engine.destroy()}}exports.Sandbox=U;exports.SandboxAttemptedToImportDefaultFunctionError=W;exports.SandboxAttemptedToImportMainFunctionError=G;exports.SandboxContextCreationError=se;exports.SandboxError=h;exports.SandboxForbiddenModuleNameError=z;exports.SandboxGLSLShaderCompilationError=E;exports.SandboxMentionCouldNotBeReplacedError=X;exports.SandboxMentionFunctionNotFoundError=j;exports.SandboxMentionUniformNotFoundError=q;exports.SandboxModuleMethodNotFoundError=N;exports.SandboxModuleNotFoundError=B;exports.SandboxOnHookCallbackError=K;exports.SandboxOnLoadCallbackError=Y;exports.SandboxOverwriteModuleError=H;exports.SandboxProgramError=R;exports.SandboxShaderDuplicateImportNameError=D;exports.SandboxShaderImportSyntaxError=$;exports.SandboxShaderRequirementMismatchError=M;exports.SandboxShaderVersionMismatchError=I;exports.SandboxShaderWithoutFunctionError=P;exports.SandboxTextureCreationError=oe;exports.SandboxTextureUnitLimitError=ae;exports.SandboxWebGLNotSupportedError=V;