@rosalana/sandbox 0.1.0 → 0.2.1

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/README.md CHANGED
@@ -38,6 +38,11 @@ It works in both **WebGL1 and WebGL2** contexts, with automatic fallback and det
38
38
  - [Sandbox Shaders](#sandbox-shaders)
39
39
  - [Hooks](#hooks)
40
40
  - [Self-removing hooks](#self-removing-hooks)
41
+ - [Textures](#textures)
42
+ - [Texture options](#texture-options)
43
+ - [Dynamic textures](#dynamic-textures)
44
+ - [Export](#export)
45
+ - [Streaming](#streaming)
41
46
  - [Chaining](#chaining)
42
47
  - [Error handling](#error-handling)
43
48
  - [Vue integration](#vue-integration)
@@ -260,7 +265,10 @@ Sandbox.defineModule("my_gradient", gradientSource, {
260
265
  myFunc: {
261
266
  colors: {
262
267
  uniform: "u_colors",
263
- default: [[1, 0, 0], [0, 0, 1]],
268
+ default: [
269
+ [1, 0, 0],
270
+ [0, 0, 1],
271
+ ],
264
272
  },
265
273
  speed: { uniform: "u_speed", default: 1.0 },
266
274
  },
@@ -276,7 +284,10 @@ Sandbox.defineModule("my_module", source, {
276
284
  default: {
277
285
  colors: {
278
286
  uniform: "u_colors",
279
- default: [[1, 0, 0], [0, 0, 1]],
287
+ default: [
288
+ [1, 0, 0],
289
+ [0, 0, 1],
290
+ ],
280
291
  },
281
292
  speed: { uniform: "u_speed", default: 1.0 },
282
293
  },
@@ -336,6 +347,124 @@ sandbox.hook(({ time }) => {
336
347
 
337
348
  This is how `pauseAt()` works internally — it's hooks all the way down.
338
349
 
350
+ ## Textures
351
+
352
+ Sandbox supports textures as `sampler2D` uniforms. Pass any image, canvas, or video element and Sandbox takes care of the WebGL plumbing — creating the texture, binding it to a texture unit, and setting the sampler uniform.
353
+
354
+ ```ts
355
+ const img = new Image();
356
+ img.src = "photo.jpg";
357
+ img.onload = () => {
358
+ sandbox.setTexture("u_texture", img);
359
+ };
360
+ ```
361
+
362
+ Then sample it in your shader:
363
+
364
+ ```glsl
365
+ uniform sampler2D u_texture;
366
+
367
+ void main() {
368
+ vec4 color = texture2D(u_texture, v_texcoord);
369
+ gl_FragColor = color;
370
+ }
371
+ ```
372
+
373
+ Multiple textures work the same way — each gets its own texture unit automatically:
374
+
375
+ ```ts
376
+ sandbox.setTexture("u_photo", photoImg);
377
+ sandbox.setTexture("u_mask", maskImg);
378
+ ```
379
+
380
+ You can also set textures upfront via options:
381
+
382
+ ```ts
383
+ Sandbox.create(canvas, {
384
+ fragment: shader,
385
+ textures: {
386
+ u_photo: photoImg,
387
+ u_mask: { source: maskImg, wrap: "repeat" },
388
+ },
389
+ });
390
+ ```
391
+
392
+ ### Texture options
393
+
394
+ Each texture accepts optional configuration for wrapping, filtering, and orientation:
395
+
396
+ ```ts
397
+ sandbox.setTexture("u_texture", img, {
398
+ wrap: "repeat", // both axes (default: "clamp")
399
+ minFilter: "nearest", // pixelated look (default: "linear")
400
+ flipY: false, // disable vertical flip (default: true)
401
+ });
402
+ ```
403
+
404
+ | Option | Values | Default |
405
+ | ----------- | ---------------------------------- | ---------- |
406
+ | `wrap` | `"clamp"`, `"repeat"`, `"mirror"` | `"clamp"` |
407
+ | `wrapS` | same (overrides `wrap` for S axis) | `wrap` |
408
+ | `wrapT` | same (overrides `wrap` for T axis) | `wrap` |
409
+ | `minFilter` | `"nearest"`, `"linear"` | `"linear"` |
410
+ | `magFilter` | `"nearest"`, `"linear"` | `"linear"` |
411
+ | `flipY` | `boolean` | `true` |
412
+ | `dynamic` | `boolean` | auto |
413
+
414
+ ### Dynamic textures
415
+
416
+ When you pass a video element, Sandbox automatically re-uploads pixels every frame so the texture stays in sync with playback. This also works for animated canvases — just set `dynamic: true`:
417
+
418
+ ```ts
419
+ // Video — dynamic by default
420
+ sandbox.setTexture("u_video", videoElement);
421
+
422
+ // Animated canvas — opt in
423
+ sandbox.setTexture("u_canvas", canvasElement, { dynamic: true });
424
+ ```
425
+
426
+ To remove a texture and free its GPU memory:
427
+
428
+ ```ts
429
+ sandbox.removeTexture("u_texture");
430
+ ```
431
+
432
+ ## Export
433
+
434
+ Sandbox can export the current frame as an image or blob — useful for saving screenshots, generating thumbnails, or uploading processed images to a server.
435
+
436
+ ```ts
437
+ // Data URL (synchronous)
438
+ const url = sandbox.renderAt(1.5).exportAsURL("image/png");
439
+
440
+ // Blob (async) — perfect for server uploads
441
+ const blob = await sandbox.renderAt(1.5).exportAsBlob("image/jpeg", 0.9);
442
+ await fetch("/upload", { method: "POST", body: blob });
443
+
444
+ // HTMLImageElement
445
+ const img = sandbox.renderAt(1.5).exportAsImage("image/png");
446
+ document.body.appendChild(img);
447
+ ```
448
+
449
+ > [!NOTE]
450
+ > Export methods work reliably after `render()` or `renderAt()`. If you need to capture frames during an active render loop, set `preserveDrawingBuffer: true` in options.
451
+
452
+ ### Streaming
453
+
454
+ For real-time use cases like video calls or recording, Sandbox can expose the canvas as a `MediaStream`:
455
+
456
+ ```ts
457
+ // WebRTC — send shader output to a video call
458
+ const stream = sandbox.stream(30);
459
+ peerConnection.addTrack(stream.getVideoTracks()[0], stream);
460
+
461
+ // Recording — save as video file
462
+ const recorder = new MediaRecorder(sandbox.stream(30));
463
+ recorder.start();
464
+ ```
465
+
466
+ This opens up workflows like **webcam → texture → shader effect → video call** with just a few lines of code.
467
+
339
468
  ## Chaining
340
469
 
341
470
  Every method returns `this`, so you can chain calls for clean, expressive code:
@@ -373,6 +502,7 @@ The error object includes useful details:
373
502
  | `PROGRAM_ERROR` | Shader program linking failed |
374
503
  | `VALIDATION_ERROR` | Vertex/fragment shader version mismatch |
375
504
  | `MODULE_ERROR` | Module not found, method not found, forbidden name, or duplicate definition |
505
+ | `TEXTURE_ERROR` | Texture creation failed or texture unit limit exceeded |
376
506
  | `UNKNOWN_ERROR` | Unexpected error in callbacks (onLoad, hooks) |
377
507
 
378
508
  ## Vue integration
@@ -443,6 +573,7 @@ interface SandboxOptions {
443
573
  onAfterRender?: HookCallback | null;
444
574
  uniforms?: UniformSchema;
445
575
  modules?: Record<string, Record<string, AnyUniformValue>>;
576
+ textures?: TextureSchema;
446
577
  }
447
578
  ```
448
579
 
@@ -462,12 +593,13 @@ interface SandboxOptions {
462
593
  | `onAfterRender` | — | Hook after each frame |
463
594
  | `uniforms` | — | Initial uniform values |
464
595
  | `modules` | — | Configure module options per imported function |
596
+ | `textures` | — | Initial textures to bind to sampler uniforms |
465
597
 
466
598
  ## Limitations (by design)
467
599
 
468
- - No textures (planned for future)
469
600
  - No multi‑pass rendering
470
601
  - No 3D scene graph
602
+ - No custom geometry (fullscreen quad only)
471
603
 
472
604
  If you need a full engine, reach for three.js. For clean shader‑only effects, Sandbox is a joy to use.
473
605
 
@@ -1,4 +1,4 @@
1
- export type SandboxErrorCode = "CONTEXT_ERROR" | "VALIDATION_ERROR" | "PROGRAM_ERROR" | "SHADER_ERROR" | "MODULE_ERROR" | "UNKNOWN_ERROR";
1
+ export type SandboxErrorCode = "CONTEXT_ERROR" | "VALIDATION_ERROR" | "PROGRAM_ERROR" | "SHADER_ERROR" | "MODULE_ERROR" | "TEXTURE_ERROR" | "UNKNOWN_ERROR";
2
2
  export declare class SandboxError extends Error {
3
3
  readonly code: SandboxErrorCode;
4
4
  readonly name: string;
@@ -3,4 +3,5 @@ export * from "./context";
3
3
  export * from "./shader";
4
4
  export * from "./module";
5
5
  export * from "./program";
6
+ export * from "./texture";
6
7
  export * from "./unknown";
@@ -0,0 +1,12 @@
1
+ import { SandboxError } from "./base";
2
+ export declare class SandboxTextureCreationError extends SandboxError {
3
+ readonly textureName: string;
4
+ readonly name = "SandboxTextureCreationError";
5
+ constructor(textureName: string);
6
+ }
7
+ export declare class SandboxTextureUnitLimitError extends SandboxError {
8
+ readonly textureName: string;
9
+ readonly maxUnits: number;
10
+ readonly name = "SandboxTextureUnitLimitError";
11
+ constructor(textureName: string, maxUnits: number);
12
+ }
package/dist/globals.d.ts CHANGED
@@ -5,11 +5,6 @@ import ModuleRegistry from "./tools/module_registry";
5
5
  * This registry will grow when more modules are defined
6
6
  */
7
7
  export declare const modules: ModuleRegistry;
8
- /**
9
- * A global registry of modules that are currently in use by the webGL context.
10
- * This is flushed on every shader switch.
11
- */
12
- export declare const runtime_modules: ModuleRegistry;
13
8
  /**
14
9
  * Global uniforms that are automatically provided by Sandbox.
15
10
  * These uniforms will NOT be renamed during preprocessing.
package/dist/index.cjs.js CHANGED
@@ -1,22 +1,22 @@
1
- "use strict";var te=Object.defineProperty;var ie=(u,e,n)=>e in u?te(u,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):u[e]=n;var a=(u,e,n)=>ie(u,typeof e!="symbol"?e+"":e,n);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});class x{constructor(e,n,t,i){this.target=e,this.type=n,this.listener=t,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,n,t,i){return e.addEventListener(n,t,i),()=>e.removeEventListener(n,t,i)}}class h extends Error{constructor(n,t){super(n);a(this,"name","SandboxError");this.code=t}}class V extends h{constructor(){super("WebGL is not supported in this browser.","CONTEXT_ERROR")}}class re extends h{constructor(){super("Failed to create WebGL context. The GPU may be unavailable.","CONTEXT_ERROR")}}class $ extends h{constructor(e,n){super(`Vertex and fragment shader WebGL versions do not match (${e} vs ${n})`,"VALIDATION_ERROR"),this.vertexVersion=e,this.fragmentVersion=n}}class w extends h{constructor(n,t,i){const r=w.parseErrorLines(i),o=r.length>0?` at line(s): ${r.join(", ")}`:"";super(`${n} shader compilation failed${o}
1
+ "use strict";var ne=Object.defineProperty;var ie=(u,e,t)=>e in u?ne(u,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):u[e]=t;var a=(u,e,t)=>ie(u,typeof e!="symbol"?e+"":e,t);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});class y{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);a(this,"name","SandboxError");this.code=n}}class O extends h{constructor(){super("WebGL is not supported in this browser.","CONTEXT_ERROR")}}class re extends h{constructor(){super("Failed to create WebGL context. The GPU may be unavailable.","CONTEXT_ERROR")}}class V 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 w extends h{constructor(t,n,i){const r=w.parseErrorLines(i),s=r.length>0?` at line(s): ${r.join(", ")}`:"";super(`${t} shader compilation failed${s}
2
2
 
3
- ${i}`,"SHADER_ERROR");a(this,"lines");this.shaderType=n,this.source=t,this.infoLog=i,this.lines=r}static parseErrorLines(n){const t=[/ERROR:\s*\d*:(\d+)/g,/(\d+):(\d+)\(\d+\):/g,/^(\d+):/gm],i=new Set;for(const r of t){let o;for(;(o=r.exec(n))!==null;){const s=parseInt(o[1],10);s>0&&i.add(s)}}return[...i].sort((r,o)=>r-o)}}class A extends h{constructor(e,n,t,i){super(`The shader ${e} "${n}" has type "${i}" but expected "${t}"`,"SHADER_ERROR"),this.requirement=e,this.name=n,this.expectedType=t,this.actualType=i}}class T extends h{constructor(){super("Shader source does not contain any function.","SHADER_ERROR")}}class I extends h{constructor(e,n){super(`Syntax error in shader import statement at line ${e}: ${n}`,"SHADER_ERROR"),this.line=e,this.details=n}}class P extends h{constructor(e,n){super(`Duplicate import name "${e}" found at line ${n}. Each import must have a unique name.`,"SHADER_ERROR"),this.name=e,this.line=n}}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 D extends h{constructor(e,n){super(`Method '${n}' 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=n}}class N extends h{constructor(e){super(`Importing 'main' function from module '${e}' is forbidden.`,"MODULE_ERROR"),this.moduleName=e}}class z 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 G 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 W 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,n,t){super(`Uniform '${t}' mentioned for function '${n}' 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=n,this.uniformName=t}}class H extends h{constructor(e,n){super(`Uniform '${n}' 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=n}}class j extends h{constructor(e,n){super(`Mention '${e}' called in function '${n}' 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=n}}class E extends h{constructor(e){super(`Shader program linking failed
3
+ ${i}`,"SHADER_ERROR");a(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 o=parseInt(s[1],10);o>0&&i.add(o)}}return[...i].sort((r,s)=>r-s)}}class A 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 I extends h{constructor(){super("Shader source does not contain any function.","SHADER_ERROR")}}class P 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 $ 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 D 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 B 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 N extends h{constructor(e){super(`Importing 'main' function from module '${e}' is forbidden.`,"MODULE_ERROR"),this.moduleName=e}}class G 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 W 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 z extends h{constructor(e){super(`Module '${e}' is already defined. Overwriting existing modules is not allowed.`,"MODULE_ERROR"),this.moduleName=e}}class H 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 q 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 j 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 _ extends h{constructor(e){super(`Shader program linking failed
4
4
 
5
- ${e}`,"PROGRAM_ERROR"),this.infoLog=e}}class Y extends h{constructor(e){super(`Error in onLoad callback: ${e}`,"UNKNOWN_ERROR")}}class K extends h{constructor(e,n){super(`Error in onBefore/onAfter hook callback with ID ${e}: ${n}`,"UNKNOWN_ERROR")}}class oe{constructor(){a(this,"time",0);a(this,"delta",0);a(this,"frame",0);a(this,"running",!1);a(this,"fps",0);a(this,"startTime",0);a(this,"lastTime",0);a(this,"rafId",null);a(this,"callback",null);a(this,"maxFps",0);this.loop=this.loop.bind(this)}start(e){if(this.running)return this;this.callback=e,this.running=!0;const n=performance.now();return this.frame===0?this.startTime=n:this.startTime=n-this.time*1e3,this.lastTime=n,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 t=1e3/this.maxFps;if(e-this.lastTime<t){this.rafId=requestAnimationFrame(this.loop);return}}this.delta=(e-this.lastTime)/1e3,this.lastTime=e;const n=this.delta>0?1/this.delta:0;this.fps=this.fps*.95+n*.05,this.time=(e-this.startTime)/1e3,this.frame++,this.callback&&this.callback(this.getState()),this.rafId=requestAnimationFrame(this.loop)}}class k{constructor(e){a(this,"gl");a(this,"vao",null);a(this,"vbo",null);a(this,"ibo",null);a(this,"vertexCount",0);a(this,"indexCount",0);a(this,"useIndices",!1);a(this,"vaoExt",null);a(this,"isWebGL2");this.gl=e,this.isWebGL2=e instanceof WebGL2RenderingContext,this.isWebGL2||(this.vaoExt=e.getExtension("OES_vertex_array_object"))}static fullscreenQuad(e){const n=new k(e),t=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 n.setup(t,i),n}setup(e,n){const t=this.gl;return this.createVAO(),this.bindVAO(),this.vbo=t.createBuffer(),t.bindBuffer(t.ARRAY_BUFFER,this.vbo),t.bufferData(t.ARRAY_BUFFER,e,t.STATIC_DRAW),this.vertexCount=e.length/4,n&&(this.ibo=t.createBuffer(),t.bindBuffer(t.ELEMENT_ARRAY_BUFFER,this.ibo),t.bufferData(t.ELEMENT_ARRAY_BUFFER,n,t.STATIC_DRAW),this.indexCount=n.length,this.useIndices=!0),this.unbindVAO(),this}linkAttributes(e){const n=this.gl;this.bindVAO(),n.bindBuffer(n.ARRAY_BUFFER,this.vbo);const t=4*Float32Array.BYTES_PER_ELEMENT,i=this.getPositionLocation(e);i>=0&&(n.enableVertexAttribArray(i),n.vertexAttribPointer(i,2,n.FLOAT,!1,t,0));const r=this.getTexcoordLocation(e);return r>=0&&(n.enableVertexAttribArray(r),n.vertexAttribPointer(r,2,n.FLOAT,!1,t,2*Float32Array.BYTES_PER_ELEMENT)),this.useIndices&&n.bindBuffer(n.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 n=e.getAttribLocation("a_position");return n>=0||(n=e.getAttribLocation("aPosition"),n>=0)||(n=e.getAttribLocation("position"),n>=0)?n:-1}getTexcoordLocation(e){let n=e.getAttribLocation("a_texcoord");return n>=0||(n=e.getAttribLocation("aTexCoord"),n>=0)||(n=e.getAttribLocation("texcoord"),n>=0)||(n=e.getAttribLocation("a_uv"),n>=0)?n:-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 se{constructor(e){a(this,"gl");a(this,"program",null);a(this,"vertexShader",null);a(this,"fragmentShader",null);this.gl=e}compile(e,n){return this.destroy(),this.vertexShader=this.compileShader("vertex",e),this.fragmentShader=this.compileShader("fragment",n),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,n){const t=this.gl,i=e==="vertex"?t.VERTEX_SHADER:t.FRAGMENT_SHADER,r=t.createShader(i);if(!r)throw new w(e,n,"Failed to create shader object");if(t.shaderSource(r,n),t.compileShader(r),!t.getShaderParameter(r,t.COMPILE_STATUS)){const s=t.getShaderInfoLog(r)||"Unknown error";throw t.deleteShader(r),new w(e,n,s)}return r}linkProgram(){const e=this.gl;if(!this.vertexShader||!this.fragmentShader)throw new E("Shaders not compiled");const n=e.createProgram();if(!n)throw new E("Failed to create program object");if(e.attachShader(n,this.vertexShader),e.attachShader(n,this.fragmentShader),e.linkProgram(n),!e.getProgramParameter(n,e.LINK_STATUS)){const i=e.getProgramInfoLog(n)||"Unknown error";throw e.deleteProgram(n),new E(i)}this.program=n}}class M{constructor(e,n){a(this,"name");a(this,"method");a(this,"isArray");a(this,"isMatrix");a(this,"location",null);a(this,"locationResolved",!1);a(this,"value");this.name=e,this.value=n;const t=M.inferMethodInfo(n);this.method=t.method,this.isArray=t.isArray,this.isMatrix=t.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 n=e.length,t=e[0];if(Array.isArray(t))switch(t.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(n){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,n){return this.locationResolved||(this.location=e.getUniformLocation(n,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,n){const t=this.resolveLocation(e,n);if(t===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(t,r);break;case"uniform1i":e.uniform1i(t,r);break;case"uniform1fv":e.uniform1fv(t,r);break;case"uniform2fv":e.uniform2fv(t,r);break;case"uniform3fv":e.uniform3fv(t,r);break;case"uniform4fv":e.uniform4fv(t,r);break;case"uniformMatrix2fv":e.uniformMatrix2fv(t,!1,r);break;case"uniformMatrix3fv":e.uniformMatrix3fv(t,!1,r);break;case"uniformMatrix4fv":e.uniformMatrix4fv(t,!1,r);break}}}class _{constructor(e){a(this,"parsed",null);this.source=e}parse(){if(this.parsed)return this.parsed;const e=this.detectVersion(),n=this.detectImports(),t=this.detectUniforms(),i=this.detectFunctions(t);return this.parsed={version:e,imports:n,uniforms:t,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,n=/^[ \t]*[^\w\s]?import\b/gm,t=[],i=new Set;let r,o=1,s=0;for(;(r=e.exec(this.source))!==null;){o+=(this.source.substring(s,r.index).match(/\n/g)||[]).length,s=r.index,i.add(o);const f=r[1],c=r[2]||r[1],d=r[3];if(t.some(p=>p.alias===c))throw new P(c,o);t.push({name:f,alias:c,module:d,line:o})}let l;for(;(l=n.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 I(f,this.diagnoseImport(c))}return t}diagnoseImport(e){const n=e.match(/^([^\w\s])import\b/);if(n&&n[1]!=="#")return`Invalid prefix '${n[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 t=e.split(/\s+/);return`Missing 'from' clause. Expected: #import ${t[1]} as ${t[3]} from '<module>'`}if(/^#import\s+\w+(?:\s+as\s+\w+)?\s+from\s+\w+/.test(e)){const t=e.match(/from\s+(\S+)/);return`Module name must be quoted. Expected: from '${t==null?void 0:t[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,n=[];let t,i=1,r=0;for(;(t=e.exec(this.source))!==null;){i+=(this.source.substring(r,t.index).match(/\n/g)||[]).length,r=t.index;const o=t[1],s=t[2],l=t[3]?parseInt(t[3],10):void 0;n.push({name:s,type:o,line:i,arrayNum:l})}return n}detectFunctions(e){const n=[],t="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]*(${t})\\s+(\\w+)\\s*\\(([^)]*)\\)\\s*\\{`,"gm");let r;for(;(r=i.exec(this.source))!==null;){const o=r[1],s=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),J=this.parseParams(l),Z=this.findFunctionCalls(g),ee=this.findUniformCalls(g,e),ne=this.findMentionCalls(g);n.push({name:s,type:o,params:J,body:g,dependencies:[...Z,...ee,...ne],line:c})}return n}parseParams(e){if(!e.trim())return[];const n=[],t=e.split(",");for(const i of t){const r=i.trim();if(!r)continue;const s=r.replace(/\b(in|out|inout|const|highp|mediump|lowp)\b\s*/g,"").trim().match(/^(\w+)\s+(\w+)(?:\[\d*\])?$/);s&&n.push({type:s[1],name:s[2]})}return n}findClosingBrace(e,n){let t=0,i=!1,r=!1,o=!1,s=!1;for(let l=n;l<e.length;l++){const f=e[l],c=e[l+1],d=e[l-1];if(!r&&!s&&f==="/"&&c==="/"){o=!0;continue}if(o&&f===`
7
- `){o=!1;continue}if(!r&&!o&&f==="/"&&c==="*"){s=!0,l++;continue}if(s&&f==="*"&&c==="/"){s=!1,l++;continue}if(!(o||s)){if(f==='"'&&d!=="\\"){r=!r;continue}if(!r){if(f==="{")t++,i=!0;else if(f==="}"&&(t--,i&&t===0))return l}}}return-1}findFunctionCalls(e){const n=[],t=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 o=r[1];t.has(o)||n.push({name:o,type:"function",index:r.index})}return n}findUniformCalls(e,n){const t=[];for(const i of n){const r=new RegExp(`\\b${i.name}\\b`,"g");let o;for(;(o=r.exec(e))!==null;)t.push({name:i.name,type:"uniform",index:o.index})}return t}findMentionCalls(e){const n=[],t=/@(\w+)\.([a-zA-Z_]\w*)/g;let i;for(;(i=t.exec(e))!==null;){const r=i[1],o=i[2];n.push({name:`${r}.${o}`,type:"mention",index:i.index})}return n}}class X{constructor(e){a(this,"isCompiled",!1);a(this,"original");a(this,"compiled");a(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(),n=e.functions.flatMap(t=>t.dependencies.filter(i=>i.type==="mention").map(i=>({name:i.name.split(".")[0],uniform:i.name.split(".")[1]})));for(const t of e.imports){const i=b.resolve(t.module),r=i.extract(t.name);let o=n.filter(l=>l.name===r.function.name);if(o.length>0){const l=i.getDefinition().uniforms;if(o=o.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=n.indexOf(f);return d>-1&&n.splice(d,1),!1}return!0}),o.length>0)throw new q(t.module,r.function.name,o[0].uniform)}const s=i.copy();this.processExtraction(r,t.alias,s.options),y.merge(t.module,s)}if(n.length>0)throw new H(n[0].name,n[0].uniform)}processExtraction(e,n,t={}){const i=e.function,r=Math.random().toString(36).substring(2,8),o=`${n}_${r}`;for(let l=e.dependencies.functions.length-1;l>=0;l--){const f=e.dependencies.functions[l],c=this.rewriteFunction(f,n,{uniforms:e.dependencies.uniforms,functions:e.dependencies.functions,unique:o});this.requirements.functions.set(c.name,c)}const s=this.rewriteFunction(i,n,{uniforms:e.dependencies.uniforms,functions:e.dependencies.functions,rename:!0,unique:o});this.requirements.functions.set(s.name,s);for(const l of e.dependencies.uniforms){if(S.has(l.name))continue;const f={...l,name:`${o}_${l.name}${l.arrayNum?`[${l.arrayNum}]`:""}`};if(t[i.name]){const c=Object.entries(t[i.name]).find(([d,p])=>p.uniform===l.name);c&&(c[1].uniform=`${o}_${l.name}`)}this.requirements.uniforms.set(f.name,f)}t[i.name]&&n!==i.name&&(t[n]=t[i.name],delete t[i.name])}rewriteFunction(e,n,t={rename:!1,uniforms:[],functions:[],unique:""}){const i=new Set(t.uniforms.map(c=>c.name)),r=new Set(t.functions.map(c=>c.name)),o=[],s=t.unique?t.unique:n;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;o.push({index:c.index,oldText:c.name,newText:`${s}_${c.name}`})}else c.type==="function"&&r.has(c.name)&&o.push({index:c.index,oldText:c.name,newText:`${s}_${c.name}`});const l=this.applyRewrites(e.body,o),f=t.rename?n:`${s}_${e.name}`;return{...e,name:f,body:l}}applyRewrites(e,n){const t=[...n].sort((r,o)=>o.index-r.index);let i=e;for(const r of t)i=i.slice(0,r.index)+r.newText+i.slice(r.index+r.oldText.length);return i}build(){const e=this.original.parse();let n=this.original.source;n=this.removeImportLines(n,e);const t=this.findInsertionPointForUniforms(n),i=this.generateUniformsCode();i&&(n=n.slice(0,t)+i+`
8
- `+n.slice(t));const r=this.findInsertionPointForFunctions(n),o=this.generateFunctionCode();return o&&(n=n.slice(0,r)+o+n.slice(r)),n=n.replace(/\n{3,}/g,`
5
+ ${e}`,"PROGRAM_ERROR"),this.infoLog=e}}class se extends h{constructor(t){super(`Failed to create WebGL texture for "${t}".`,"TEXTURE_ERROR");a(this,"name","SandboxTextureCreationError");this.textureName=t}}class oe extends h{constructor(t,n){super(`Cannot bind texture "${t}": all ${n} texture units are in use.`,"TEXTURE_ERROR");a(this,"name","SandboxTextureUnitLimitError");this.textureName=t,this.maxUnits=n}}class X extends h{constructor(e){super(`Error in onLoad callback: ${e}`,"UNKNOWN_ERROR")}}class Y extends h{constructor(e,t){super(`Error in onBefore/onAfter hook callback with ID ${e}: ${t}`,"UNKNOWN_ERROR")}}class ae{constructor(){a(this,"time",0);a(this,"delta",0);a(this,"frame",0);a(this,"running",!1);a(this,"fps",0);a(this,"startTime",0);a(this,"lastTime",0);a(this,"rafId",null);a(this,"callback",null);a(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 M{constructor(e){a(this,"gl");a(this,"vao",null);a(this,"vbo",null);a(this,"ibo",null);a(this,"vertexCount",0);a(this,"indexCount",0);a(this,"useIndices",!1);a(this,"vaoExt",null);a(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 M(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 le{constructor(e){a(this,"gl");a(this,"program",null);a(this,"vertexShader",null);a(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 w(e,t,"Failed to create shader object");if(n.shaderSource(r,t),n.compileShader(r),!n.getShaderParameter(r,n.COMPILE_STATUS)){const o=n.getShaderInfoLog(r)||"Unknown error";throw n.deleteShader(r),new w(e,t,o)}return r}linkProgram(){const e=this.gl;if(!this.vertexShader||!this.fragmentShader)throw new _("Shaders not compiled");const t=e.createProgram();if(!t)throw new _("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 _(i)}this.program=t}}class k{constructor(e,t){a(this,"name");a(this,"method");a(this,"isArray");a(this,"isMatrix");a(this,"location",null);a(this,"locationResolved",!1);a(this,"value");this.name=e,this.value=t;const n=k.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 E{constructor(e){a(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,o=0;for(;(r=e.exec(this.source))!==null;){s+=(this.source.substring(o,r.index).match(/\n/g)||[]).length,o=r.index,i.add(s);const f=r[1],c=r[2]||r[1],m=r[3];if(n.some(d=>d.alias===c))throw new $(c,s);n.push({name:f,alias:c,module:m,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 P(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],o=n[2],l=n[3]?parseInt(n[3],10):void 0;t.push({name:o,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],o=r[2],l=r[3].trim(),f=r.index,c=(this.source.substring(0,f).match(/\n/g)||[]).length+1,m=this.source.indexOf("{",f),d=this.findClosingBrace(this.source,m);if(d===-1)continue;const v=this.source.slice(m,d+1),J=this.parseParams(l),Z=this.findFunctionCalls(v),ee=this.findUniformCalls(v,e),te=this.findMentionCalls(v);t.push({name:o,type:s,params:J,body:v,dependencies:[...Z,...ee,...te],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 o=r.replace(/\b(in|out|inout|const|highp|mediump|lowp)\b\s*/g,"").trim().match(/^(\w+)\s+(\w+)(?:\[\d*\])?$/);o&&t.push({type:o[1],name:o[2]})}return t}findClosingBrace(e,t){let n=0,i=!1,r=!1,s=!1,o=!1;for(let l=t;l<e.length;l++){const f=e[l],c=e[l+1],m=e[l-1];if(!r&&!o&&f==="/"&&c==="/"){s=!0;continue}if(s&&f===`
7
+ `){s=!1;continue}if(!r&&!s&&f==="/"&&c==="*"){o=!0,l++;continue}if(o&&f==="*"&&c==="/"){o=!1,l++;continue}if(!(s||o)){if(f==='"'&&m!=="\\"){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 K{constructor(e){a(this,"isCompiled",!1);a(this,"original");a(this,"compiled");a(this,"requirements",{uniforms:new Map,functions:new Map});this.original=new E(e),this.compiled=new E(e)}version(){return this.original.version()}source(){return this.original.source}recompile(){return this.isCompiled=!1,this.compile()}compile(e){return this.isCompiled?this.compiled.source:(this.original.parse().imports.length>0&&this.processImports(e),this.compiled.setSource(this.build()),this.isCompiled=!0,this.compiled.source)}processImports(e){const t=this.original.parse(),n=t.functions.flatMap(i=>i.dependencies.filter(r=>r.type==="mention").map(r=>({name:r.name.split(".")[0],uniform:r.name.split(".")[1]})));for(const i of t.imports){const r=b.resolve(i.module),s=r.extract(i.name);let o=n.filter(f=>f.name===s.function.name);if(o.length>0){const f=r.getDefinition().uniforms;if(o=o.filter(c=>{const m=f.find(d=>d.name===`u_${c.uniform}`||d.name===c.uniform);if(m){s.dependencies.uniforms.some(v=>v.name===m.name)||s.dependencies.uniforms.push(m);const d=n.indexOf(c);return d>-1&&n.splice(d,1),!1}return!0}),o.length>0)throw new H(i.module,s.function.name,o[0].uniform)}const l=r.copy();this.processExtraction(s,i.alias,l.options),e==null||e.merge(i.module,l)}if(n.length>0)throw new q(n[0].name,n[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 o=this.rewriteFunction(i,t,{uniforms:e.dependencies.uniforms,functions:e.dependencies.functions,rename:!0,unique:s});this.requirements.functions.set(o.name,o);for(const l of e.dependencies.uniforms){if(R.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(([m,d])=>d.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=[],o=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(R.has(c.name))continue;s.push({index:c.index,oldText:c.name,newText:`${o}_${c.name}`})}else c.type==="function"&&r.has(c.name)&&s.push({index:c.index,oldText:c.name,newText:`${o}_${c.name}`});const l=this.applyRewrites(e.body,s),f=n.rename?t:`${o}_${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
9
 
10
- `),n=this.replaceMentions(n,e),n}replaceMentions(e,n){let t=e;const i=n.functions.filter(r=>r.dependencies.some(o=>o.type==="mention"));for(const r of i){const o=r.dependencies.filter(s=>s.type==="mention");for(const s of o){const l=s.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 j(s.name,r.name);const d=new RegExp(`@\\b${s.name}\\b`,"g");t=t.replace(d,c)}}return t}removeImportLines(e,n){const t=e.split(`
11
- `),i=new Set(n.imports.map(r=>r.line));return t.filter((r,o)=>{const s=i.has(o+1);if(!s&&r.trim()===""&&o>0){const l=o-1;if(i.has(l+1))return!1}return!s}).join(`
12
- `)}findInsertionPointForUniforms(e){const n=new _(e).parse(),t=n.uniforms.find(s=>s.line===Math.max(...n.uniforms.map(l=>l.line??0))),i=e.split(`
13
- `);let r=0;if(t&&t.line)r=t.line;else for(let s=0;s<i.length;s++){const l=i[s].trim();if(l.startsWith("#version")){r=s+1;continue}if(l.startsWith("precision ")){r=s+1;continue}if(l===""||l.startsWith("//")){r===s&&(r=s+1);continue}break}let o=0;for(let s=0;s<r;s++)o+=i[s].length+1;return o}findInsertionPointForFunctions(e){const n=new _(e).parse(),t=n.functions.find(s=>s.line===Math.min(...n.functions.map(l=>l.line??1/0))),i=e.split(`
14
- `);let r=0;if(t&&t.line)r=t.line-2;else throw new T;let o=0;for(let s=0;s<r;s++)o+=i[s].length+1;return o}generateUniformsCode(){const e=[];if(this.requirements.uniforms.size>0)for(const n of this.checkUniformsPresence())e.push(`uniform ${n.type} ${n.name};`);return e.length===0?"":e.join(`
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(o=>o.type==="mention");for(const o of s){const l=o.name.split("."),f=new RegExp(`\\b${l[0]}_(\\w+)_${l[1]}\\b`,"g"),c=this.requirements.uniforms.keys().find(d=>{var v;return((v=d.match(f))==null?void 0:v[0])===d});if(!c)throw new j(o.name,r.name);const m=new RegExp(`@\\b${o.name}\\b`,"g");n=n.replace(m,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 o=i.has(s+1);if(!o&&r.trim()===""&&s>0){const l=s-1;if(i.has(l+1))return!1}return!o}).join(`
12
+ `)}findInsertionPointForUniforms(e){const t=new E(e).parse(),n=t.uniforms.find(o=>o.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 o=0;o<i.length;o++){const l=i[o].trim();if(l.startsWith("#version")){r=o+1;continue}if(l.startsWith("precision ")){r=o+1;continue}if(l===""||l.startsWith("//")){r===o&&(r=o+1);continue}break}let s=0;for(let o=0;o<r;o++)s+=i[o].length+1;return s}findInsertionPointForFunctions(e){const t=new E(e).parse(),n=t.functions.find(o=>o.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 I;let s=0;for(let o=0;o<r;o++)s+=i[o].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
15
  `)+`
16
- `}generateFunctionCode(){const e=[];if(this.requirements.functions.size>0)for(const n of this.checkFunctionsPresence()){const t=n.params.map(i=>`${i.type} ${i.name}`).join(", ");e.push(`
17
- ${n.type} ${n.name}(${t}) ${n.body}`)}return e.length===0?"":e.join(`
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
18
  `)+`
19
- `}checkUniformsPresence(){const e=this.original.parse(),n=[],t=this.requirements.uniforms;for(const[i,r]of t){const o=e.uniforms.find(s=>s.name===i);if(!o){n.push(r);continue}if(o.type!==r.type)throw new A("uniform",i,r.type,o.type)}return n}checkFunctionsPresence(){const e=this.original.parse(),n=[],t=this.requirements.functions;for(const[i,r]of t){const o=e.functions.find(s=>s.name===i);if(!o){n.push(r);continue}if(o.type!==r.type)throw new A("function",i,r.type,o.type)}return n}}class v extends X{constructor(n,t,i={}){super(t);a(this,"name");a(this,"options",{});this.name=n,this.options=this.resolveOptions(i)}resolveOptions(n){if(!(n!=null&&n.default))return n||{};const t=this.original.parse(),i=n.default;for(const r of t.functions)if(!(r.name==="main"||r.name==="default"))if(n[r.name]){const o=n[r.name];for(const s in i)s in o||(o[s]=i[s])}else n[r.name]={...i};return delete n.default,n||{}}static define(n){const{name:t,source:i,options:r}=n;if(t==="sandbox"||t.startsWith("sandbox/"))throw new G(t);const o=new v(t,i,r);if(b.has(t))throw new W(t);return b.register(t,o),o}static resolve(n){return b.resolve(n)}copy(n="original"){return new v(this.name,this[n].source,JSON.parse(JSON.stringify(this.options)))}merge(n){this.options=this.options||{};const t=this.getDefinition().uniforms.map(i=>i.name);for(const[i,r]of Object.entries(n.options??{}))if(!this.options[i])this.options[i]=r;else for(const[o,s]of Object.entries(r))t.includes(s.uniform)||(this.options[i][o]=s)}getDefinition(){return this.compile(),{name:this.name,methods:this.compiled.parse().functions.map(n=>n.name).filter(n=>n!=="main"&&n!=="default"),uniforms:this.compiled.parse().uniforms.map(n=>({name:n.name,type:n.type})),options:this.options}}extract(n){if(this.compile(),n==="main")throw new N(this.name);if(n==="default")throw new z(this.name);const t=this.compiled.parse(),i=t.functions.find(s=>s.name===n);if(!i)throw new D(this.name,n);const r=new Map,o=new Map;return this.collectDependencies({current:i,scope:{functions:t.functions,uniforms:t.uniforms},collected:{functions:r,uniforms:o},visited:new Set([n])}),{function:i,dependencies:{functions:Array.from(r.values()),uniforms:Array.from(o.values())}}}collectDependencies(n){for(const t of n.current.dependencies)if(t.type==="function"){if(n.visited.has(t.name))continue;const i=n.scope.functions.find(r=>r.name===t.name);i&&(n.visited.add(t.name),n.collected.functions.set(t.name,i),this.collectDependencies({current:i,scope:{functions:n.scope.functions,uniforms:n.scope.uniforms},collected:{functions:n.collected.functions,uniforms:n.collected.uniforms},visited:n.visited}))}else if(t.type==="uniform"){const i=n.scope.uniforms.find(r=>r.name===t.name);i&&!n.collected.uniforms.has(t.name)&&n.collected.uniforms.set(t.name,i)}}}class Q{constructor(e=[]){a(this,"modules",new Map);e.forEach(n=>{this.register(n.name,n)})}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(n=>{const t=n.getDefinition();if(t.options)for(const i in t.options){const r=t.options[i];for(const o in r){const s=r[o];s.default!==void 0&&!t.uniforms.map(l=>l.name).includes(s.uniform)&&(e[s.uniform]=s.default)}}}),e}resolveOptions(e){for(const n of this.modules.values())if(n.options&&n.options[e])return n.options[e];return null}register(e,n){this.modules.set(e,n)}merge(e,n){if(!this.modules.has(e))return this.register(e,n);const t=this.modules.get(e);t.merge(n),this.modules.set(e,t)}resolve(e){const n=this.modules.get(e);if(!n)throw new B(e);return n}has(e){return this.modules.has(e)}isEmpty(){return this.modules.size===0}remove(e){this.modules.delete(e)}load(e){e.forEach(n=>{this.register(n.name,n)})}clear(){this.modules.clear()}}const ae=`// ─── Constants ──────────────────────────────────────────────
19
+ `}checkUniformsPresence(){const e=this.original.parse(),t=[],n=this.requirements.uniforms;for(const[i,r]of n){const s=e.uniforms.find(o=>o.name===i);if(!s){t.push(r);continue}if(s.type!==r.type)throw new A("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(o=>o.name===i);if(!s){t.push(r);continue}if(s.type!==r.type)throw new A("function",i,r.type,s.type)}return t}}class g extends K{constructor(t,n,i={}){super(n);a(this,"name");a(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 o in i)o in s||(s[o]=i[o])}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 W(n);const s=new g(n,i,r);if(b.has(n))throw new z(n);return b.register(n,s),s}static resolve(t){return b.resolve(t)}copy(t="original"){return new g(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,o]of Object.entries(r))n.includes(o.uniform)||(this.options[i][s]=o)}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 N(this.name);if(t==="default")throw new G(this.name);const n=this.compiled.parse(),i=n.functions.find(o=>o.name===t);if(!i)throw new B(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 Q{constructor(e=[]){a(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 o=r[s];o.default!==void 0&&!n.uniforms.map(l=>l.name).includes(o.uniform)&&(e[o.uniform]=o.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 D(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 ce=`// ─── Constants ──────────────────────────────────────────────
20
20
 
21
21
  const float PI = 3.14159265359;
22
22
  const float TAU = 6.28318530718;
@@ -225,7 +225,7 @@ vec2 voronoi(vec2 p) {
225
225
  }
226
226
 
227
227
  void main() {}
228
- `,le=`/**
228
+ `,ue=`/**
229
229
  * Hex integer to RGB.
230
230
  * Usage: hex(0xFF6600) → orange
231
231
  */
@@ -324,7 +324,7 @@ vec3 iridescent(vec2 uv, float time, float speed) {
324
324
  }
325
325
 
326
326
  void main() {}
327
- `,ce=`// ─── Time Shapers ──────────────────────────────────────────
327
+ `,fe=`// ─── Time Shapers ──────────────────────────────────────────
328
328
  // Convert raw time (u_time) to normalized 0–1 range.
329
329
  // Output feeds directly into easing functions.
330
330
 
@@ -446,7 +446,7 @@ float teleport(float t) {
446
446
  }
447
447
 
448
448
  void main() {}
449
- `,ue=`#import hash from 'sandbox'
449
+ `,he=`#import hash from 'sandbox'
450
450
  #import noise from 'sandbox'
451
451
  #import fbm from 'sandbox'
452
452
  #import voronoi from 'sandbox'
@@ -641,7 +641,7 @@ vec2 cells(vec2 uv, float intensity) {
641
641
  }
642
642
 
643
643
  void main() {}
644
- `,fe=`#import hash from 'sandbox'
644
+ `,de=`#import hash from 'sandbox'
645
645
 
646
646
  uniform float u_intensity;
647
647
 
@@ -828,7 +828,7 @@ vec3 arcade(vec3 color, vec2 uv, float intensity) {
828
828
  }
829
829
 
830
830
  void main() {}
831
- `,b=new Q([new v("sandbox",ae),new v("sandbox/colors",le),new v("sandbox/time",ce),new v("sandbox/effects",ue,{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",fe,{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 Q,S=new Map([["u_resolution","vec2"],["u_time","float"],["u_delta","float"],["u_mouse","vec2"],["u_frame","int"]]);class he{constructor(e){a(this,"gl");a(this,"program",null);a(this,"uniforms",new Map);this.gl=e}attachProgram(e){this.program=e;for(const n of this.uniforms.values())n.invalidateLocation();return this}set(e,n){const t=this.uniforms.get(e);return t?t.setValue(n):this.uniforms.set(e,new M(e,n)),this}setMany(e){for(const[n,t]of Object.entries(e))this.set(n,t);return this}get(e){var n;return(n=this.uniforms.get(e))==null?void 0:n.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,n,t){if(this.set("u_resolution",n),this.set("u_time",e.time),this.set("u_delta",e.delta),this.set("u_mouse",t),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 L{constructor(){a(this,"hooks",new Map)}id(){return Math.random().toString(36).substring(2,10)}add(e){const n=this.id();return this.hooks.set(n,e),()=>this.remove(n)}remove(e){this.hooks.delete(e)}run(e){for(const[n,t]of this.hooks)try{t(e)===!1&&this.remove(n)}catch(i){throw new K(n,i instanceof Error?i.message:String(i))}}destroy(){this.hooks.clear()}}class C{constructor(e,n){a(this,"canvas");a(this,"gl");a(this,"options");a(this,"onBeforeHooks",new L);a(this,"onAfterHooks",new L);a(this,"_program");a(this,"_geometry");a(this,"_uniforms");a(this,"_clock");a(this,"_resolution",[1,1]);a(this,"_mouse",[0,0]);a(this,"_version",1);a(this,"playing",!1);this.canvas=e,this.options=n,this.gl=this.initContext(),this.enableExtensions(),this._program=new se(this.gl),this._geometry=k.fullscreenQuad(this.gl),this._uniforms=new he(this.gl),this._clock=new oe,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,n){const t=new C(e,n);return n.vertex&&n.fragment&&t.shader(n.vertex,n.fragment),n.uniforms&&t._uniforms.setMany(n.uniforms),y.isEmpty()||t._uniforms.setMany(y.defaults()),t}initContext(){const e={antialias:this.options.antialias,preserveDrawingBuffer:this.options.preserveDrawingBuffer,alpha:!0,depth:!1,stencil:!1},n=this.canvas.getContext("webgl2",e);if(n)return this._version=2,n;const t=this.canvas.getContext("webgl",e);if(t)return this._version=1,t;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,n,t,i){return this.canvas.width=t,this.canvas.height=i,this.gl.viewport(e,n,t,i),this._resolution=[t,i],this}clock(e){return this._clock.setTime(e),this}mouse(e,n){return this._mouse=[e,n],this}uniform(e,n){return this._uniforms.set(e,n),this}uniforms(e){return this._uniforms.setMany(e),this}getUniform(e){return this._uniforms.get(e)}shader(e,n){try{if(y.clear(),e.version()!==n.version())throw new $(e.version(),n.version());this._program.compile(e.source(),n.compile()),this._version=n.version(),this._geometry.linkAttributes(this._program);const t=this._program.getProgram();t&&this._uniforms.attachProgram(t);try{this.options.onLoad()}catch(i){throw new Y(i instanceof Error?i.message:String(i))}}catch(t){t instanceof h&&this.options.onError(t)}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(n){n instanceof h&&this.options.onError(n)}this.playing=!1,this._clock.stop();try{this.onAfterHooks.run(e)}catch(n){n instanceof h&&this.options.onError(n)}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.onAfterHooks.destroy(),this.onBeforeHooks.destroy(),y.clear()}onRender(e){const n=this.gl;try{this.onBeforeHooks.run(e)}catch(t){t instanceof h&&this.options.onError(t)}n.clearColor(0,0,0,0),n.clear(n.COLOR_BUFFER_BIT),this._program.use(),this._uniforms.uploadBuiltIns(e,this._resolution,this._mouse),this._uniforms.uploadAll(),this._geometry.bind(),this._geometry.draw();try{this.onAfterHooks.run(e)}catch(t){t instanceof h&&this.options.onError(t)}}}class m extends X{constructor(e){super(e),S.forEach((n,t)=>{this.requirements.uniforms.set(t,{name:t,type:n,line:0})})}}const R=`#ifdef GL_ES
831
+ `,b=new Q([new g("sandbox",ce),new g("sandbox/colors",ue),new g("sandbox/time",fe),new g("sandbox/effects",he,{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 g("sandbox/filters",de,{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}}})]),R=new Map([["u_resolution","vec2"],["u_time","float"],["u_delta","float"],["u_mouse","vec2"],["u_frame","int"]]);class me{constructor(e){a(this,"gl");a(this,"program",null);a(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 k(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 R.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){a(this,"name");a(this,"gl");a(this,"texture",null);a(this,"location",null);a(this,"locationResolved",!1);a(this,"source");a(this,"options");a(this,"dynamicOverride");a(this,"needsUpload",!0);a(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 pe{constructor(e){a(this,"gl");a(this,"program",null);a(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 L{constructor(){a(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 Y(t,i instanceof Error?i.message:String(i))}}destroy(){this.hooks.clear()}}class T{constructor(e,t){a(this,"canvas");a(this,"gl");a(this,"options");a(this,"onBeforeHooks",new L);a(this,"onAfterHooks",new L);a(this,"_program");a(this,"_geometry");a(this,"_uniforms");a(this,"_textures");a(this,"_clock");a(this,"_resolution",[1,1]);a(this,"_mouse",[0,0]);a(this,"_version",1);a(this,"_runtimeModules",new Q);a(this,"playing",!1);this.canvas=e,this.options=t,this.gl=this.initContext(),this.enableExtensions(),this._program=new le(this.gl),this._geometry=M.fullscreenQuad(this.gl),this._uniforms=new me(this.gl),this._textures=new pe(this.gl),this._clock=new ae,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 T(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),n._runtimeModules.isEmpty()||n._uniforms.setMany(n._runtimeModules.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 O;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(this._runtimeModules.clear(),e.version()!==t.version())throw new V(e.version(),t.version());this._program.compile(e.source(),t.compile(this._runtimeModules)),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 X(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}getUsingModules(){return this._runtimeModules}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(),this._runtimeModules.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 p extends K{constructor(e){super(e),R.forEach((t,n)=>{this.requirements.uniforms.set(n,{name:n,type:t,line:0})})}}const S=`#ifdef GL_ES
832
832
  precision mediump float;
833
833
  #endif
834
834
 
@@ -841,7 +841,7 @@ void main() {
841
841
  v_texcoord = a_texcoord;
842
842
  gl_Position = vec4(a_position, 0.0, 1.0);
843
843
  }
844
- `,F=`#ifdef GL_ES
844
+ `,C=`#ifdef GL_ES
845
845
  precision mediump float;
846
846
  #endif
847
847
 
@@ -855,7 +855,7 @@ void main() {
855
855
  vec3 color = vec3(uv.x, uv.y, 0.5 + 0.5 * sin(u_time));
856
856
  gl_FragColor = vec4(color, 1.0);
857
857
  }
858
- `,U=`#version 300 es
858
+ `,F=`#version 300 es
859
859
 
860
860
  in vec2 a_position;
861
861
  in vec2 a_texcoord;
@@ -865,7 +865,7 @@ out vec2 v_texcoord;
865
865
  void main() {
866
866
  v_texcoord = a_texcoord;
867
867
  gl_Position = vec4(a_position, 0.0, 1.0);
868
- }`,de=`#version 300 es
868
+ }`,ve=`#version 300 es
869
869
  precision highp float;
870
870
 
871
871
  uniform vec2 u_resolution;
@@ -879,5 +879,5 @@ void main() {
879
879
  vec2 uv = gl_FragCoord.xy / u_resolution;
880
880
  vec3 color = vec3(uv.x, uv.y, 0.5 + 0.5 * sin(u_time));
881
881
  fragColor = vec4(color, 1.0);
882
- }`;class O{constructor(e,n){a(this,"listeners",[]);a(this,"canvasEl");a(this,"options");a(this,"engine");a(this,"usingCustomVertex",!1);if(this.canvasEl=e,this.options=this.resolveOptions(n),this.engine=C.setup(this.canvasEl,this.options),this.setupListeners(),this.setViewport(),this.options.modules)for(const[t,i]of Object.entries(this.options.modules))this.module(t,i);this.options.autoplay&&this.play()}static create(e,n){return new O(e,n)}static defineModule(e,n,t={}){v.define({name:e,source:n,options:t})}static availableModules(){return b.available()}static compile(e){return new m(e).compile()}resolveOptions(e){const n={vertex:new m(R),fragment:new m(F),autoplay:!0,pauseWhenHidden:!0,dpr:"auto",fps:0,preserveDrawingBuffer:!1,antialias:!0,onError:o=>{console.error("Oops!",o,`
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:{}};if(e!=null&&e.vertex&&(this.usingCustomVertex=!0),e!=null&&e.vertex&&!(e!=null&&e.fragment)){n.vertex=new m(e.vertex);const o=n.vertex.version();n.fragment=new m(o===2?de:F)}if(e!=null&&e.fragment&&!(e!=null&&e.vertex)){n.fragment=new m(e.fragment);const o=n.fragment.version();n.vertex=new m(o===2?U:R)}e!=null&&e.vertex&&(e!=null&&e.fragment)&&(n.vertex=new m(e.vertex),n.fragment=new m(e.fragment));const{vertex:t,fragment:i,...r}=e||{};return{...n,...r}}setupListeners(){this.listeners.push(x.on(window,"resize",()=>{this.setViewport()}),x.on(this.canvasEl,"resize",()=>{this.setViewport()}),(()=>{let e=!1;return x.on(document,"scroll",n=>{this.options.pauseWhenHidden&&(this.isInViewport()?e&&!this.isPlaying()&&(this.play(),e=!1):this.isPlaying()&&(this.pause(),e=!0))})})(),x.on(document,"mousemove",e=>{this.setMouse(e.clientX||e.pageX,e.clientY||e.pageY)}),x.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,n=this.canvasEl.clientWidth||this.canvasEl.width||1,t=this.canvasEl.clientHeight||this.canvasEl.height||1;this.engine.viewport(0,0,Math.max(1,Math.floor(n*e)),Math.max(1,Math.floor(t*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,n){const t=this.canvasEl.getBoundingClientRect();e>=t.left&&e<=t.right&&n>=t.top&&n<=t.bottom&&this.engine.mouse(e-t.left,n-t.top)}setUniform(e,n){return this.engine.uniform(e,n),this}setUniforms(e){return this.engine.uniforms(e),this}getUniform(e){return this.engine.getUniform(e)}setShader(e,n){return this.options.vertex=new m(e),this.options.fragment=new m(n),this.usingCustomVertex=!0,this.engine.shader(this.options.vertex,this.options.fragment),this}setFragment(e){const n=new m(e),t=n.version(),i=this.options.vertex.version();return this.options.fragment=n,t!==i&&(this.usingCustomVertex||(this.options.vertex=new m(t===2?U:R))),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,n="before"){return n==="before"?this.engine.onBeforeHooks.add(e):this.engine.onAfterHooks.add(e)}module(e,n){const t=y.resolveOptions(e);if(!t)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(n)){const o=t[i];if(!o){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(o.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 n=this.hook(t=>{t.time>=e&&(n(),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}destroy(){this.destroyListeners(),this.engine.destroy()}}exports.Sandbox=O;exports.SandboxAttemptedToImportDefaultFunctionError=z;exports.SandboxAttemptedToImportMainFunctionError=N;exports.SandboxContextCreationError=re;exports.SandboxError=h;exports.SandboxForbiddenModuleNameError=G;exports.SandboxGLSLShaderCompilationError=w;exports.SandboxMentionCouldNotBeReplacedError=j;exports.SandboxMentionFunctionNotFoundError=H;exports.SandboxMentionUniformNotFoundError=q;exports.SandboxModuleMethodNotFoundError=D;exports.SandboxModuleNotFoundError=B;exports.SandboxOnHookCallbackError=K;exports.SandboxOnLoadCallbackError=Y;exports.SandboxOverwriteModuleError=W;exports.SandboxProgramError=E;exports.SandboxShaderDuplicateImportNameError=P;exports.SandboxShaderImportSyntaxError=I;exports.SandboxShaderRequirementMismatchError=A;exports.SandboxShaderVersionMismatchError=$;exports.SandboxShaderWithoutFunctionError=T;exports.SandboxWebGLNotSupportedError=V;
882
+ }`;class U{constructor(e,t){a(this,"listeners",[]);a(this,"canvasEl");a(this,"options");a(this,"engine");a(this,"usingCustomVertex",!1);if(this.canvasEl=e,this.options=this.resolveOptions(t),this.engine=T.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={}){g.define({name:e,source:t,options:n})}static availableModules(){return b.available()}static compile(e){return new p(e).compile()}resolveOptions(e){const t={vertex:new p(S),fragment:new p(C),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 p(e.vertex);const s=t.vertex.version();t.fragment=new p(s===2?ve:C)}if(e!=null&&e.fragment&&!(e!=null&&e.vertex)){t.fragment=new p(e.fragment);const s=t.fragment.version();t.vertex=new p(s===2?F:S)}e!=null&&e.vertex&&(e!=null&&e.fragment)&&(t.vertex=new p(e.vertex),t.fragment=new p(e.fragment));const{vertex:n,fragment:i,...r}=e||{};return{...t,...r}}setupListeners(){this.listeners.push(y.on(window,"resize",()=>{this.setViewport()}),y.on(this.canvasEl,"resize",()=>{this.setViewport()}),(()=>{let e=!1;return y.on(document,"scroll",t=>{this.options.pauseWhenHidden&&(this.isInViewport()?e&&!this.isPlaying()&&(this.play(),e=!1):this.isPlaying()&&(this.pause(),e=!0))})})(),y.on(document,"mousemove",e=>{this.setMouse(e.clientX||e.pageX,e.clientY||e.pageY)}),y.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 p(e),this.options.fragment=new p(t),this.usingCustomVertex=!0,this.engine.shader(this.options.vertex,this.options.fragment),this}setFragment(e){const t=new p(e),n=t.version(),i=this.options.vertex.version();return this.options.fragment=t,n!==i&&(this.usingCustomVertex||(this.options.vertex=new p(n===2?F:S))),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 i=this.engine.getUsingModules().resolveOptions(e);if(!i)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[r,s]of Object.entries(t)){const o=i[r];if(!o){console.warn(`Sandbox: Option '${r}' not found for function '${e}'. Make sure to check available options with Sandbox.availableModules() and provide the correct option name.`);continue}this.setUniform(o.uniform,s)}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=G;exports.SandboxAttemptedToImportMainFunctionError=N;exports.SandboxContextCreationError=re;exports.SandboxError=h;exports.SandboxForbiddenModuleNameError=W;exports.SandboxGLSLShaderCompilationError=w;exports.SandboxMentionCouldNotBeReplacedError=j;exports.SandboxMentionFunctionNotFoundError=q;exports.SandboxMentionUniformNotFoundError=H;exports.SandboxModuleMethodNotFoundError=B;exports.SandboxModuleNotFoundError=D;exports.SandboxOnHookCallbackError=Y;exports.SandboxOnLoadCallbackError=X;exports.SandboxOverwriteModuleError=z;exports.SandboxProgramError=_;exports.SandboxShaderDuplicateImportNameError=$;exports.SandboxShaderImportSyntaxError=P;exports.SandboxShaderRequirementMismatchError=A;exports.SandboxShaderVersionMismatchError=V;exports.SandboxShaderWithoutFunctionError=I;exports.SandboxTextureCreationError=se;exports.SandboxTextureUnitLimitError=oe;exports.SandboxWebGLNotSupportedError=O;