@rosalana/sandbox 0.0.5 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.es.js CHANGED
@@ -1,9 +1,9 @@
1
- var S = Object.defineProperty;
2
- var L = (o, t, e) => t in o ? S(o, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : o[t] = e;
3
- var r = (o, t, e) => L(o, typeof t != "symbol" ? t + "" : t, e);
4
- class l {
5
- constructor(t, e, i, s) {
6
- this.target = t, this.type = e, this.listener = i, this.options = s, this.target.addEventListener(
1
+ var D = Object.defineProperty;
2
+ var N = (u, e, n) => e in u ? D(u, e, { enumerable: !0, configurable: !0, writable: !0, value: n }) : u[e] = n;
3
+ var a = (u, e, n) => N(u, typeof e != "symbol" ? e + "" : e, n);
4
+ class x {
5
+ constructor(e, n, t, i) {
6
+ this.target = e, this.type = n, this.listener = t, this.options = i, this.target.addEventListener(
7
7
  this.type,
8
8
  this.listener,
9
9
  this.options
@@ -16,99 +16,211 @@ class l {
16
16
  this.options
17
17
  );
18
18
  }
19
- static on(t, e, i, s) {
20
- return t.addEventListener(e, i, s), () => t.removeEventListener(e, i, s);
19
+ static on(e, n, t, i) {
20
+ return e.addEventListener(n, t, i), () => e.removeEventListener(n, t, i);
21
+ }
22
+ }
23
+ class h extends Error {
24
+ constructor(n, t) {
25
+ super(n);
26
+ a(this, "name", "SandboxError");
27
+ this.code = t;
21
28
  }
22
29
  }
23
- class u extends Error {
24
- constructor(t, e) {
25
- super(t), this.code = e, this.name = "SandboxError";
30
+ class z extends h {
31
+ constructor() {
32
+ super("WebGL is not supported in this browser.", "CONTEXT_ERROR");
26
33
  }
27
34
  }
28
- class w extends u {
29
- constructor(t) {
30
- const e = t === "not_supported" ? "WebGL is not supported in this browser." : "Failed to create WebGL context. The GPU may be unavailable.";
35
+ class de extends h {
36
+ constructor() {
31
37
  super(
32
- e,
33
- t === "not_supported" ? "WEBGL_NOT_SUPPORTED" : "CONTEXT_CREATION_FAILED"
34
- ), this.name = "SandboxContextError";
38
+ "Failed to create WebGL context. The GPU may be unavailable.",
39
+ "CONTEXT_ERROR"
40
+ );
35
41
  }
36
42
  }
37
- class k extends u {
38
- constructor(t, e) {
43
+ class G extends h {
44
+ constructor(e, n) {
39
45
  super(
40
- `Vertex and fragment shader WebGL versions do not match (${t} vs ${e})`,
41
- "SHADER_VERSION_MISMATCH"
42
- ), this.vertexVersion = t, this.fragmentVersion = e, this.name = "SandboxShaderVersionMismatchError";
46
+ `Vertex and fragment shader WebGL versions do not match (${e} vs ${n})`,
47
+ "VALIDATION_ERROR"
48
+ ), this.vertexVersion = e, this.fragmentVersion = n;
43
49
  }
44
50
  }
45
- class c extends u {
46
- constructor(e, i, s) {
47
- const n = c.parseErrorLines(s), h = n.length > 0 ? ` at line(s): ${n.join(", ")}` : "";
51
+ class _ extends h {
52
+ constructor(n, t, i) {
53
+ const r = _.parseErrorLines(i), s = r.length > 0 ? ` at line(s): ${r.join(", ")}` : "";
48
54
  super(
49
- `${e} shader compilation failed${h}
55
+ `${n} shader compilation failed${s}
50
56
 
51
- ${s}`,
52
- "SHADER_COMPILATION_FAILED"
57
+ ${i}`,
58
+ "SHADER_ERROR"
53
59
  );
54
- /** Line numbers where errors occurred */
55
- r(this, "lines");
56
- this.shaderType = e, this.source = i, this.infoLog = s, this.name = "SandboxShaderCompilationError", this.lines = n;
60
+ a(this, "lines");
61
+ this.shaderType = n, this.source = t, this.infoLog = i, this.lines = r;
57
62
  }
58
- /** Parse error log to extract line numbers */
59
- static parseErrorLines(e) {
60
- const i = [
63
+ static parseErrorLines(n) {
64
+ const t = [
61
65
  /ERROR:\s*\d*:(\d+)/g,
62
- // Chrome/ANGLE: ERROR: 0:15
63
66
  /(\d+):(\d+)\(\d+\):/g,
64
- // Mesa: 0:15(0):
65
67
  /^(\d+):/gm
66
- // Simple: 15:
67
- ], s = /* @__PURE__ */ new Set();
68
- for (const n of i) {
69
- let h;
70
- for (; (h = n.exec(e)) !== null; ) {
71
- const f = parseInt(h[1], 10);
72
- f > 0 && s.add(f);
68
+ ], i = /* @__PURE__ */ new Set();
69
+ for (const r of t) {
70
+ let s;
71
+ for (; (s = r.exec(n)) !== null; ) {
72
+ const o = parseInt(s[1], 10);
73
+ o > 0 && i.add(o);
73
74
  }
74
75
  }
75
- return [...s].sort((n, h) => n - h);
76
+ return [...i].sort((r, s) => r - s);
77
+ }
78
+ }
79
+ class C extends h {
80
+ constructor(e, n, t, i) {
81
+ super(
82
+ `The shader ${e} "${n}" has type "${i}" but expected "${t}"`,
83
+ "SHADER_ERROR"
84
+ ), this.requirement = e, this.name = n, this.expectedType = t, this.actualType = i;
85
+ }
86
+ }
87
+ class W extends h {
88
+ constructor() {
89
+ super("Shader source does not contain any function.", "SHADER_ERROR");
90
+ }
91
+ }
92
+ class q extends h {
93
+ constructor(e, n) {
94
+ super(
95
+ `Syntax error in shader import statement at line ${e}: ${n}`,
96
+ "SHADER_ERROR"
97
+ ), this.line = e, this.details = n;
98
+ }
99
+ }
100
+ class H extends h {
101
+ constructor(e, n) {
102
+ super(
103
+ `Duplicate import name "${e}" found at line ${n}. Each import must have a unique name.`,
104
+ "SHADER_ERROR"
105
+ ), this.name = e, this.line = n;
106
+ }
107
+ }
108
+ class j extends h {
109
+ constructor(e) {
110
+ super(
111
+ `Can not find module '${e}'. Check if it is defined before usage or if the name is correct.`,
112
+ "MODULE_ERROR"
113
+ ), this.moduleName = e;
114
+ }
115
+ }
116
+ class Y extends h {
117
+ constructor(e, n) {
118
+ super(
119
+ `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.`,
120
+ "MODULE_ERROR"
121
+ ), this.moduleName = e, this.methodName = n;
122
+ }
123
+ }
124
+ class K extends h {
125
+ constructor(e) {
126
+ super(
127
+ `Importing 'main' function from module '${e}' is forbidden.`,
128
+ "MODULE_ERROR"
129
+ ), this.moduleName = e;
130
+ }
131
+ }
132
+ class X extends h {
133
+ constructor(e) {
134
+ super(
135
+ `Name 'default' is reserved and cannot be used as a function name in module '${e}'.`,
136
+ "MODULE_ERROR"
137
+ ), this.moduleName = e;
76
138
  }
77
139
  }
78
- class m extends u {
79
- constructor(t) {
140
+ class Q extends h {
141
+ constructor(e) {
142
+ super(
143
+ `Module name '${e}' is not allowed. Module names cannot be 'sandbox' or start with 'sandbox/'.`,
144
+ "MODULE_ERROR"
145
+ ), this.moduleName = e;
146
+ }
147
+ }
148
+ class J extends h {
149
+ constructor(e) {
150
+ super(
151
+ `Module '${e}' is already defined. Overwriting existing modules is not allowed.`,
152
+ "MODULE_ERROR"
153
+ ), this.moduleName = e;
154
+ }
155
+ }
156
+ class Z extends h {
157
+ constructor(e, n, t) {
158
+ super(
159
+ `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.`,
160
+ "MODULE_ERROR"
161
+ ), this.moduleName = e, this.functionName = n, this.uniformName = t;
162
+ }
163
+ }
164
+ class ee extends h {
165
+ constructor(e, n) {
166
+ super(
167
+ `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.`,
168
+ "MODULE_ERROR"
169
+ ), this.functionName = e, this.uniformName = n;
170
+ }
171
+ }
172
+ class ne extends h {
173
+ constructor(e, n) {
174
+ super(
175
+ `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.`,
176
+ "MODULE_ERROR"
177
+ ), this.mentionName = e, this.calledInFunction = n;
178
+ }
179
+ }
180
+ class R extends h {
181
+ constructor(e) {
80
182
  super(`Shader program linking failed
81
183
 
82
- ${t}`, "PROGRAM_LINK_FAILED"), this.infoLog = t, this.name = "SandboxProgramError";
184
+ ${e}`, "PROGRAM_ERROR"), this.infoLog = e;
83
185
  }
84
186
  }
85
- class R {
187
+ class te extends h {
188
+ constructor(e) {
189
+ super(`Error in onLoad callback: ${e}`, "UNKNOWN_ERROR");
190
+ }
191
+ }
192
+ class ie extends h {
193
+ constructor(e, n) {
194
+ super(`Error in onBefore/onAfter hook callback with ID ${e}: ${n}`, "UNKNOWN_ERROR");
195
+ }
196
+ }
197
+ class re {
86
198
  constructor() {
87
199
  /** Total elapsed time in seconds */
88
- r(this, "time", 0);
200
+ a(this, "time", 0);
89
201
  /** Delta time since last frame in seconds */
90
- r(this, "delta", 0);
202
+ a(this, "delta", 0);
91
203
  /** Frame counter */
92
- r(this, "frame", 0);
204
+ a(this, "frame", 0);
93
205
  /** Is clock running */
94
- r(this, "running", !1);
206
+ a(this, "running", !1);
95
207
  /** Smoothed frames per second */
96
- r(this, "fps", 0);
97
- r(this, "startTime", 0);
98
- r(this, "lastTime", 0);
99
- r(this, "rafId", null);
100
- r(this, "callback", null);
101
- r(this, "maxFps", 0);
208
+ a(this, "fps", 0);
209
+ a(this, "startTime", 0);
210
+ a(this, "lastTime", 0);
211
+ a(this, "rafId", null);
212
+ a(this, "callback", null);
213
+ a(this, "maxFps", 0);
102
214
  this.loop = this.loop.bind(this);
103
215
  }
104
216
  /**
105
217
  * Start the animation loop with a render callback.
106
218
  */
107
- start(t) {
219
+ start(e) {
108
220
  if (this.running) return this;
109
- this.callback = t, this.running = !0;
110
- const e = performance.now();
111
- return this.frame === 0 ? this.startTime = e : this.startTime = e - this.time * 1e3, this.lastTime = e, this.rafId = requestAnimationFrame(this.loop), this;
221
+ this.callback = e, this.running = !0;
222
+ const n = performance.now();
223
+ return this.frame === 0 ? this.startTime = n : this.startTime = n - this.time * 1e3, this.lastTime = n, this.rafId = requestAnimationFrame(this.loop), this;
112
224
  }
113
225
  /**
114
226
  * Stop the animation loop.
@@ -139,14 +251,14 @@ class R {
139
251
  * Advance clock by one tick (for single-shot rendering).
140
252
  * Useful when autoplay is disabled.
141
253
  */
142
- tick(t = 0) {
143
- return this.delta = t, this.time += t, this.frame++, this.callback && this.callback(this.getState()), this;
254
+ tick(e = 0) {
255
+ return this.delta = e, this.time += e, this.frame++, this.callback && this.callback(this.getState()), this;
144
256
  }
145
257
  /**
146
258
  * Set time directly (for deterministic rendering).
147
259
  */
148
- setTime(t) {
149
- return this.time = t, this;
260
+ setTime(e) {
261
+ return this.time = e, this;
150
262
  }
151
263
  /**
152
264
  * Cleanup.
@@ -157,46 +269,46 @@ class R {
157
269
  /**
158
270
  * Set maximum frames per second.
159
271
  */
160
- setMaxFps(t) {
161
- return this.maxFps = t, this;
272
+ setMaxFps(e) {
273
+ return this.maxFps = e, this;
162
274
  }
163
275
  /**
164
276
  * Internal animation frame handler.
165
277
  */
166
- loop(t) {
278
+ loop(e) {
167
279
  if (!this.running) return;
168
280
  if (this.maxFps > 0) {
169
- const i = 1e3 / this.maxFps;
170
- if (t - this.lastTime < i) {
281
+ const t = 1e3 / this.maxFps;
282
+ if (e - this.lastTime < t) {
171
283
  this.rafId = requestAnimationFrame(this.loop);
172
284
  return;
173
285
  }
174
286
  }
175
- this.delta = (t - this.lastTime) / 1e3, this.lastTime = t;
176
- const e = this.delta > 0 ? 1 / this.delta : 0;
177
- this.fps = this.fps * 0.95 + e * 0.05, this.time = (t - this.startTime) / 1e3, this.frame++, this.callback && this.callback(this.getState()), this.rafId = requestAnimationFrame(this.loop);
178
- }
179
- }
180
- class p {
181
- constructor(t) {
182
- r(this, "gl");
183
- r(this, "vao", null);
184
- r(this, "vbo", null);
185
- r(this, "ibo", null);
186
- r(this, "vertexCount", 0);
187
- r(this, "indexCount", 0);
188
- r(this, "useIndices", !1);
287
+ this.delta = (e - this.lastTime) / 1e3, this.lastTime = e;
288
+ const n = this.delta > 0 ? 1 / this.delta : 0;
289
+ this.fps = this.fps * 0.95 + n * 0.05, this.time = (e - this.startTime) / 1e3, this.frame++, this.callback && this.callback(this.getState()), this.rafId = requestAnimationFrame(this.loop);
290
+ }
291
+ }
292
+ class A {
293
+ constructor(e) {
294
+ a(this, "gl");
295
+ a(this, "vao", null);
296
+ a(this, "vbo", null);
297
+ a(this, "ibo", null);
298
+ a(this, "vertexCount", 0);
299
+ a(this, "indexCount", 0);
300
+ a(this, "useIndices", !1);
189
301
  // WebGL1 VAO extension (if available)
190
- r(this, "vaoExt", null);
191
- r(this, "isWebGL2");
192
- this.gl = t, this.isWebGL2 = t instanceof WebGL2RenderingContext, this.isWebGL2 || (this.vaoExt = t.getExtension("OES_vertex_array_object"));
302
+ a(this, "vaoExt", null);
303
+ a(this, "isWebGL2");
304
+ this.gl = e, this.isWebGL2 = e instanceof WebGL2RenderingContext, this.isWebGL2 || (this.vaoExt = e.getExtension("OES_vertex_array_object"));
193
305
  }
194
306
  /**
195
307
  * Create a fullscreen quad geometry.
196
308
  * This is the most common use case for shader effects.
197
309
  */
198
- static fullscreenQuad(t) {
199
- const e = new p(t), i = new Float32Array([
310
+ static fullscreenQuad(e) {
311
+ const n = new A(e), t = new Float32Array([
200
312
  // position texcoord
201
313
  -1,
202
314
  -1,
@@ -218,7 +330,7 @@ class p {
218
330
  1,
219
331
  1
220
332
  // top-right
221
- ]), s = new Uint16Array([
333
+ ]), i = new Uint16Array([
222
334
  0,
223
335
  1,
224
336
  2,
@@ -228,33 +340,33 @@ class p {
228
340
  3
229
341
  // second triangle
230
342
  ]);
231
- return e.setup(i, s), e;
343
+ return n.setup(t, i), n;
232
344
  }
233
345
  /**
234
346
  * Setup geometry from vertex and index data.
235
347
  */
236
- setup(t, e) {
237
- const i = this.gl;
238
- return this.createVAO(), this.bindVAO(), this.vbo = i.createBuffer(), i.bindBuffer(i.ARRAY_BUFFER, this.vbo), i.bufferData(i.ARRAY_BUFFER, t, i.STATIC_DRAW), this.vertexCount = t.length / 4, e && (this.ibo = i.createBuffer(), i.bindBuffer(i.ELEMENT_ARRAY_BUFFER, this.ibo), i.bufferData(i.ELEMENT_ARRAY_BUFFER, e, i.STATIC_DRAW), this.indexCount = e.length, this.useIndices = !0), this.unbindVAO(), this;
348
+ setup(e, n) {
349
+ const t = this.gl;
350
+ 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;
239
351
  }
240
352
  /**
241
353
  * Link vertex attributes to shader program.
242
354
  * Call this after compiling shaders.
243
355
  */
244
- linkAttributes(t) {
245
- const e = this.gl;
246
- this.bindVAO(), e.bindBuffer(e.ARRAY_BUFFER, this.vbo);
247
- const i = 4 * Float32Array.BYTES_PER_ELEMENT, s = this.getPositionLocation(t);
248
- s >= 0 && (e.enableVertexAttribArray(s), e.vertexAttribPointer(s, 2, e.FLOAT, !1, i, 0));
249
- const n = this.getTexcoordLocation(t);
250
- return n >= 0 && (e.enableVertexAttribArray(n), e.vertexAttribPointer(
251
- n,
356
+ linkAttributes(e) {
357
+ const n = this.gl;
358
+ this.bindVAO(), n.bindBuffer(n.ARRAY_BUFFER, this.vbo);
359
+ const t = 4 * Float32Array.BYTES_PER_ELEMENT, i = this.getPositionLocation(e);
360
+ i >= 0 && (n.enableVertexAttribArray(i), n.vertexAttribPointer(i, 2, n.FLOAT, !1, t, 0));
361
+ const r = this.getTexcoordLocation(e);
362
+ return r >= 0 && (n.enableVertexAttribArray(r), n.vertexAttribPointer(
363
+ r,
252
364
  2,
253
- e.FLOAT,
365
+ n.FLOAT,
254
366
  !1,
255
- i,
367
+ t,
256
368
  2 * Float32Array.BYTES_PER_ELEMENT
257
- )), this.useIndices && e.bindBuffer(e.ELEMENT_ARRAY_BUFFER, this.ibo), this.unbindVAO(), this;
369
+ )), this.useIndices && n.bindBuffer(n.ELEMENT_ARRAY_BUFFER, this.ibo), this.unbindVAO(), this;
258
370
  }
259
371
  /**
260
372
  * Bind geometry for rendering.
@@ -272,31 +384,31 @@ class p {
272
384
  * Draw the geometry.
273
385
  */
274
386
  draw() {
275
- const t = this.gl;
276
- return this.bindVAO(), this.useIndices ? t.drawElements(t.TRIANGLES, this.indexCount, t.UNSIGNED_SHORT, 0) : t.drawArrays(t.TRIANGLE_STRIP, 0, this.vertexCount), this;
387
+ const e = this.gl;
388
+ return this.bindVAO(), this.useIndices ? e.drawElements(e.TRIANGLES, this.indexCount, e.UNSIGNED_SHORT, 0) : e.drawArrays(e.TRIANGLE_STRIP, 0, this.vertexCount), this;
277
389
  }
278
390
  /**
279
391
  * Cleanup all GPU resources.
280
392
  */
281
393
  destroy() {
282
- const t = this.gl;
283
- this.deleteVAO(), this.vbo && (t.deleteBuffer(this.vbo), this.vbo = null), this.ibo && (t.deleteBuffer(this.ibo), this.ibo = null);
394
+ const e = this.gl;
395
+ this.deleteVAO(), this.vbo && (e.deleteBuffer(this.vbo), this.vbo = null), this.ibo && (e.deleteBuffer(this.ibo), this.ibo = null);
284
396
  }
285
397
  /**
286
398
  * Get position attribute location.
287
399
  * Tries common naming conventions.
288
400
  */
289
- getPositionLocation(t) {
290
- let e = t.getAttribLocation("a_position");
291
- return e >= 0 || (e = t.getAttribLocation("aPosition"), e >= 0) || (e = t.getAttribLocation("position"), e >= 0) ? e : -1;
401
+ getPositionLocation(e) {
402
+ let n = e.getAttribLocation("a_position");
403
+ return n >= 0 || (n = e.getAttribLocation("aPosition"), n >= 0) || (n = e.getAttribLocation("position"), n >= 0) ? n : -1;
292
404
  }
293
405
  /**
294
406
  * Get texcoord attribute location.
295
407
  * Tries common naming conventions.
296
408
  */
297
- getTexcoordLocation(t) {
298
- let e = t.getAttribLocation("a_texcoord");
299
- return e >= 0 || (e = t.getAttribLocation("aTexCoord"), e >= 0) || (e = t.getAttribLocation("texcoord"), e >= 0) || (e = t.getAttribLocation("a_uv"), e >= 0) ? e : -1;
409
+ getTexcoordLocation(e) {
410
+ let n = e.getAttribLocation("a_texcoord");
411
+ return n >= 0 || (n = e.getAttribLocation("aTexCoord"), n >= 0) || (n = e.getAttribLocation("texcoord"), n >= 0) || (n = e.getAttribLocation("a_uv"), n >= 0) ? n : -1;
300
412
  }
301
413
  // ============================================================================
302
414
  // VAO helpers (handle WebGL1 vs WebGL2 differences)
@@ -314,33 +426,21 @@ class p {
314
426
  this.vao && (this.isWebGL2 ? this.gl.deleteVertexArray(this.vao) : this.vaoExt && this.vaoExt.deleteVertexArrayOES(this.vao), this.vao = null);
315
427
  }
316
428
  }
317
- class a {
318
- constructor(t) {
319
- r(this, "gl");
320
- r(this, "program", null);
321
- r(this, "vertexShader", null);
322
- r(this, "fragmentShader", null);
323
- r(this, "version", 1);
324
- this.gl = t;
325
- }
326
- /**
327
- * Detect WebGL version from shader source.
328
- * Looks for "#version 300 es" directive.
329
- */
330
- static detectVersion(t) {
331
- return /^\s*#version\s+300\s+es/m.test(t) ? 2 : 1;
429
+ class se {
430
+ constructor(e) {
431
+ a(this, "gl");
432
+ a(this, "program", null);
433
+ a(this, "vertexShader", null);
434
+ a(this, "fragmentShader", null);
435
+ this.gl = e;
332
436
  }
333
437
  /**
334
438
  * Compile shaders and link program.
335
439
  * @throws ShaderCompilationError if compilation fails
336
440
  * @throws ProgramLinkError if linking fails
337
441
  */
338
- compile(t, e) {
339
- this.destroy();
340
- const i = a.detectVersion(t), s = a.detectVersion(e);
341
- if (i != s)
342
- throw new k(i, s);
343
- return this.version = Math.max(i, s), this.vertexShader = this.compileShader("vertex", t), this.fragmentShader = this.compileShader("fragment", e), this.linkProgram(), this;
442
+ compile(e, n) {
443
+ return this.destroy(), this.vertexShader = this.compileShader("vertex", e), this.fragmentShader = this.compileShader("fragment", n), this.linkProgram(), this;
344
444
  }
345
445
  /**
346
446
  * Bind this program for rendering.
@@ -354,93 +454,87 @@ class a {
354
454
  getProgram() {
355
455
  return this.program;
356
456
  }
357
- /**
358
- * Get detected WebGL version.
359
- */
360
- getVersion() {
361
- return this.version;
362
- }
363
457
  /**
364
458
  * Get attribute location.
365
459
  */
366
- getAttribLocation(t) {
367
- return this.program ? this.gl.getAttribLocation(this.program, t) : -1;
460
+ getAttribLocation(e) {
461
+ return this.program ? this.gl.getAttribLocation(this.program, e) : -1;
368
462
  }
369
463
  /**
370
464
  * Get uniform location.
371
465
  */
372
- getUniformLocation(t) {
373
- return this.program ? this.gl.getUniformLocation(this.program, t) : null;
466
+ getUniformLocation(e) {
467
+ return this.program ? this.gl.getUniformLocation(this.program, e) : null;
374
468
  }
375
469
  /**
376
470
  * Cleanup all GPU resources.
377
471
  */
378
472
  destroy() {
379
- const t = this.gl;
380
- this.program && (this.vertexShader && t.detachShader(this.program, this.vertexShader), this.fragmentShader && t.detachShader(this.program, this.fragmentShader), t.deleteProgram(this.program), this.program = null), this.vertexShader && (t.deleteShader(this.vertexShader), this.vertexShader = null), this.fragmentShader && (t.deleteShader(this.fragmentShader), this.fragmentShader = null);
473
+ const e = this.gl;
474
+ 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);
381
475
  }
382
476
  /**
383
477
  * Compile a single shader.
384
478
  * @throws ShaderCompilationError if compilation fails
385
479
  */
386
- compileShader(t, e) {
387
- const i = this.gl, s = t === "vertex" ? i.VERTEX_SHADER : i.FRAGMENT_SHADER, n = i.createShader(s);
388
- if (!n)
389
- throw new c(
390
- t,
480
+ compileShader(e, n) {
481
+ const t = this.gl, i = e === "vertex" ? t.VERTEX_SHADER : t.FRAGMENT_SHADER, r = t.createShader(i);
482
+ if (!r)
483
+ throw new _(
391
484
  e,
485
+ n,
392
486
  "Failed to create shader object"
393
487
  );
394
- if (i.shaderSource(n, e), i.compileShader(n), !i.getShaderParameter(n, i.COMPILE_STATUS)) {
395
- const f = i.getShaderInfoLog(n) || "Unknown error";
396
- throw i.deleteShader(n), new c(t, e, f);
488
+ if (t.shaderSource(r, n), t.compileShader(r), !t.getShaderParameter(r, t.COMPILE_STATUS)) {
489
+ const o = t.getShaderInfoLog(r) || "Unknown error";
490
+ throw t.deleteShader(r), new _(e, n, o);
397
491
  }
398
- return n;
492
+ return r;
399
493
  }
400
494
  /**
401
495
  * Link vertex and fragment shaders into a program.
402
496
  * @throws ProgramLinkError if linking fails
403
497
  */
404
498
  linkProgram() {
405
- const t = this.gl;
499
+ const e = this.gl;
406
500
  if (!this.vertexShader || !this.fragmentShader)
407
- throw new m("Shaders not compiled");
408
- const e = t.createProgram();
409
- if (!e)
410
- throw new m("Failed to create program object");
411
- if (t.attachShader(e, this.vertexShader), t.attachShader(e, this.fragmentShader), t.linkProgram(e), !t.getProgramParameter(e, t.LINK_STATUS)) {
412
- const s = t.getProgramInfoLog(e) || "Unknown error";
413
- throw t.deleteProgram(e), new m(s);
501
+ throw new R("Shaders not compiled");
502
+ const n = e.createProgram();
503
+ if (!n)
504
+ throw new R("Failed to create program object");
505
+ if (e.attachShader(n, this.vertexShader), e.attachShader(n, this.fragmentShader), e.linkProgram(n), !e.getProgramParameter(n, e.LINK_STATUS)) {
506
+ const i = e.getProgramInfoLog(n) || "Unknown error";
507
+ throw e.deleteProgram(n), new R(i);
414
508
  }
415
- this.program = e;
509
+ this.program = n;
416
510
  }
417
511
  }
418
- class x {
419
- constructor(t, e) {
420
- r(this, "name");
421
- r(this, "method");
422
- r(this, "isArray");
423
- r(this, "isMatrix");
424
- r(this, "location", null);
425
- r(this, "locationResolved", !1);
426
- r(this, "value");
427
- this.name = t, this.value = e;
428
- const i = x.inferMethodInfo(e);
429
- this.method = i.method, this.isArray = i.isArray, this.isMatrix = i.isMatrix;
512
+ class k {
513
+ constructor(e, n) {
514
+ a(this, "name");
515
+ a(this, "method");
516
+ a(this, "isArray");
517
+ a(this, "isMatrix");
518
+ a(this, "location", null);
519
+ a(this, "locationResolved", !1);
520
+ a(this, "value");
521
+ this.name = e, this.value = n;
522
+ const t = k.inferMethodInfo(n);
523
+ this.method = t.method, this.isArray = t.isArray, this.isMatrix = t.isMatrix;
430
524
  }
431
525
  /**
432
526
  * Infer WebGL method and metadata from value type.
433
527
  */
434
- static inferMethodInfo(t) {
435
- if (typeof t == "boolean")
528
+ static inferMethodInfo(e) {
529
+ if (typeof e == "boolean")
436
530
  return { method: "uniform1i", isArray: !1, isMatrix: !1 };
437
- if (typeof t == "number")
531
+ if (typeof e == "number")
438
532
  return { method: "uniform1f", isArray: !1, isMatrix: !1 };
439
- if (!Array.isArray(t))
533
+ if (!Array.isArray(e))
440
534
  return { method: "uniform1f", isArray: !1, isMatrix: !1 };
441
- const e = t.length, i = t[0];
442
- if (Array.isArray(i))
443
- switch (i.length) {
535
+ const n = e.length, t = e[0];
536
+ if (Array.isArray(t))
537
+ switch (t.length) {
444
538
  case 2:
445
539
  return { method: "uniform2fv", isArray: !0, isMatrix: !1 };
446
540
  case 3:
@@ -450,7 +544,7 @@ class x {
450
544
  default:
451
545
  return { method: "uniform1fv", isArray: !0, isMatrix: !1 };
452
546
  }
453
- switch (e) {
547
+ switch (n) {
454
548
  case 2:
455
549
  return { method: "uniform2fv", isArray: !1, isMatrix: !1 };
456
550
  case 3:
@@ -469,8 +563,8 @@ class x {
469
563
  * Resolve and cache uniform location from program.
470
564
  * Returns null if uniform doesn't exist (optimized out by compiler, etc.)
471
565
  */
472
- resolveLocation(t, e) {
473
- return this.locationResolved || (this.location = t.getUniformLocation(e, this.name), this.locationResolved = !0), this.location;
566
+ resolveLocation(e, n) {
567
+ return this.locationResolved || (this.location = e.getUniformLocation(n, this.name), this.locationResolved = !0), this.location;
474
568
  }
475
569
  /**
476
570
  * Invalidate cached location (call when program changes).
@@ -481,8 +575,8 @@ class x {
481
575
  /**
482
576
  * Update value (doesn't upload to GPU until upload() is called).
483
577
  */
484
- setValue(t) {
485
- this.value = t;
578
+ setValue(e) {
579
+ this.value = e;
486
580
  }
487
581
  /**
488
582
  * Get current value.
@@ -495,96 +589,1782 @@ class x {
495
589
  * @param gl - WebGL context
496
590
  * @param program - Current WebGL program (for location resolution)
497
591
  */
498
- upload(t, e) {
499
- const i = this.resolveLocation(t, e);
500
- if (i === null)
592
+ upload(e, n) {
593
+ const t = this.resolveLocation(e, n);
594
+ if (t === null)
501
595
  return;
502
- const s = this.value;
503
- let n;
504
- switch (typeof s == "boolean" ? n = s ? 1 : 0 : typeof s == "number" ? n = s : this.isArray && Array.isArray(s[0]) ? n = new Float32Array(
505
- s.flat()
506
- ) : n = new Float32Array(s), this.method) {
596
+ const i = this.value;
597
+ let r;
598
+ switch (typeof i == "boolean" ? r = i ? 1 : 0 : typeof i == "number" ? r = i : this.isArray && Array.isArray(i[0]) ? r = new Float32Array(
599
+ i.flat()
600
+ ) : r = new Float32Array(i), this.method) {
507
601
  case "uniform1f":
508
- t.uniform1f(i, n);
602
+ e.uniform1f(t, r);
509
603
  break;
510
604
  case "uniform1i":
511
- t.uniform1i(i, n);
605
+ e.uniform1i(t, r);
512
606
  break;
513
607
  case "uniform1fv":
514
- t.uniform1fv(i, n);
608
+ e.uniform1fv(t, r);
515
609
  break;
516
610
  case "uniform2fv":
517
- t.uniform2fv(i, n);
611
+ e.uniform2fv(t, r);
518
612
  break;
519
613
  case "uniform3fv":
520
- t.uniform3fv(i, n);
614
+ e.uniform3fv(t, r);
521
615
  break;
522
616
  case "uniform4fv":
523
- t.uniform4fv(i, n);
617
+ e.uniform4fv(t, r);
524
618
  break;
525
619
  case "uniformMatrix2fv":
526
- t.uniformMatrix2fv(i, !1, n);
620
+ e.uniformMatrix2fv(t, !1, r);
527
621
  break;
528
622
  case "uniformMatrix3fv":
529
- t.uniformMatrix3fv(i, !1, n);
623
+ e.uniformMatrix3fv(t, !1, r);
530
624
  break;
531
625
  case "uniformMatrix4fv":
532
- t.uniformMatrix4fv(i, !1, n);
626
+ e.uniformMatrix4fv(t, !1, r);
627
+ break;
628
+ }
629
+ }
630
+ }
631
+ class w {
632
+ constructor(e) {
633
+ a(this, "parsed", null);
634
+ this.source = e;
635
+ }
636
+ /**
637
+ * Parse the shader source to extract imports, uniforms, functions, and version.
638
+ */
639
+ parse() {
640
+ if (this.parsed) return this.parsed;
641
+ const e = this.detectVersion(), n = this.detectImports(), t = this.detectUniforms(), i = this.detectFunctions(t);
642
+ return this.parsed = {
643
+ version: e,
644
+ imports: n,
645
+ uniforms: t,
646
+ functions: i
647
+ };
648
+ }
649
+ /**
650
+ * Check if the shader source has already been parsed
651
+ */
652
+ isParsed() {
653
+ return this.parsed !== null;
654
+ }
655
+ /**
656
+ * Change the shader source and reset the parsed result
657
+ */
658
+ setSource(e) {
659
+ this.source = e, this.parsed = null;
660
+ }
661
+ /**
662
+ * Get the detected GLSL version from the shader source without parsing the entire shader
663
+ */
664
+ version() {
665
+ return this.detectVersion();
666
+ }
667
+ detectVersion() {
668
+ return /^\s*#version\s+300\s+es/m.test(this.source) ? 2 : 1;
669
+ }
670
+ detectImports() {
671
+ const e = /^[ \t]*#import\s+(\w+)(?:\s+as\s+(\w+))?\s+from\s+["'](.+)["']/gm, n = /^[ \t]*[^\w\s]?import\b/gm, t = [], i = /* @__PURE__ */ new Set();
672
+ let r, s = 1, o = 0;
673
+ for (; (r = e.exec(this.source)) !== null; ) {
674
+ s += (this.source.substring(o, r.index).match(/\n/g) || []).length, o = r.index, i.add(s);
675
+ const f = r[1], c = r[2] || r[1], m = r[3];
676
+ if (t.some((p) => p.alias === c))
677
+ throw new H(c, s);
678
+ t.push({ name: f, alias: c, module: m, line: s });
679
+ }
680
+ let l;
681
+ for (; (l = n.exec(this.source)) !== null; ) {
682
+ const f = (this.source.substring(0, l.index).match(/\n/g) || []).length + 1;
683
+ if (i.has(f)) continue;
684
+ const c = this.source.split(`
685
+ `)[f - 1].trim();
686
+ throw new q(
687
+ f,
688
+ this.diagnoseImport(c)
689
+ );
690
+ }
691
+ return t;
692
+ }
693
+ diagnoseImport(e) {
694
+ const n = e.match(/^([^\w\s])import\b/);
695
+ if (n && n[1] !== "#")
696
+ return `Invalid prefix '${n[1]}'. Expected: #import <function> from '<module>'`;
697
+ if (/^import\b/.test(e))
698
+ return "Missing '#' prefix. Expected: #import <function> from '<module>'";
699
+ if (/^#import\s+from\b/.test(e))
700
+ return "Missing function name. Expected: #import <function> from '<module>'";
701
+ if (/^#import\s+\w+\s*$/.test(e))
702
+ return `Missing 'from' clause. Expected: #import ${e.split(/\s+/)[1]} from '<module>'`;
703
+ if (/^#import\s+\w+\s+as\s*$/.test(e) || /^#import\s+\w+\s+as\s+from\b/.test(e))
704
+ return `Missing alias name after 'as'. Expected: #import ${e.split(/\s+/)[1]} as <alias> from '<module>'`;
705
+ if (/^#import\s+\w+\s+as\s+\w+\s*$/.test(e)) {
706
+ const t = e.split(/\s+/);
707
+ return `Missing 'from' clause. Expected: #import ${t[1]} as ${t[3]} from '<module>'`;
708
+ }
709
+ if (/^#import\s+\w+(?:\s+as\s+\w+)?\s+from\s+\w+/.test(e)) {
710
+ const t = e.match(/from\s+(\S+)/);
711
+ return `Module name must be quoted. Expected: from '${t == null ? void 0 : t[1]}'`;
712
+ }
713
+ return "Invalid syntax. Expected: #import <function> from '<module>'";
714
+ }
715
+ detectUniforms() {
716
+ const e = /^[ \t]*uniform\s+(?:(?:highp|mediump|lowp)\s+)?(\w+)\s+(\w+)(?:\[(\d+)\])?\s*;/gm, n = [];
717
+ let t, i = 1, r = 0;
718
+ for (; (t = e.exec(this.source)) !== null; ) {
719
+ i += (this.source.substring(r, t.index).match(/\n/g) || []).length, r = t.index;
720
+ const s = t[1], o = t[2], l = t[3] ? parseInt(t[3], 10) : void 0;
721
+ n.push({ name: o, type: s, line: i, arrayNum: l });
722
+ }
723
+ return n;
724
+ }
725
+ detectFunctions(e) {
726
+ 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(
727
+ `^[ \\t]*(${t})\\s+(\\w+)\\s*\\(([^)]*)\\)\\s*\\{`,
728
+ "gm"
729
+ );
730
+ let r;
731
+ for (; (r = i.exec(this.source)) !== null; ) {
732
+ 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), p = this.findClosingBrace(this.source, m);
733
+ if (p === -1) continue;
734
+ const g = this.source.slice(m, p + 1), T = this.parseParams(l), I = this.findFunctionCalls(g), P = this.findUniformCalls(g, e), B = this.findMentionCalls(g);
735
+ n.push({
736
+ name: o,
737
+ type: s,
738
+ params: T,
739
+ body: g,
740
+ dependencies: [...I, ...P, ...B],
741
+ line: c
742
+ });
743
+ }
744
+ return n;
745
+ }
746
+ parseParams(e) {
747
+ if (!e.trim()) return [];
748
+ const n = [], t = e.split(",");
749
+ for (const i of t) {
750
+ const r = i.trim();
751
+ if (!r) continue;
752
+ const o = r.replace(/\b(in|out|inout|const|highp|mediump|lowp)\b\s*/g, "").trim().match(/^(\w+)\s+(\w+)(?:\[\d*\])?$/);
753
+ o && n.push({
754
+ type: o[1],
755
+ name: o[2]
756
+ });
757
+ }
758
+ return n;
759
+ }
760
+ findClosingBrace(e, n) {
761
+ let t = 0, i = !1, r = !1, s = !1, o = !1;
762
+ for (let l = n; l < e.length; l++) {
763
+ const f = e[l], c = e[l + 1], m = e[l - 1];
764
+ if (!r && !o && f === "/" && c === "/") {
765
+ s = !0;
766
+ continue;
767
+ }
768
+ if (s && f === `
769
+ `) {
770
+ s = !1;
771
+ continue;
772
+ }
773
+ if (!r && !s && f === "/" && c === "*") {
774
+ o = !0, l++;
775
+ continue;
776
+ }
777
+ if (o && f === "*" && c === "/") {
778
+ o = !1, l++;
779
+ continue;
780
+ }
781
+ if (!(s || o)) {
782
+ if (f === '"' && m !== "\\") {
783
+ r = !r;
784
+ continue;
785
+ }
786
+ if (!r) {
787
+ if (f === "{")
788
+ t++, i = !0;
789
+ else if (f === "}" && (t--, i && t === 0))
790
+ return l;
791
+ }
792
+ }
793
+ }
794
+ return -1;
795
+ }
796
+ findFunctionCalls(e) {
797
+ const n = [], t = /* @__PURE__ */ new Set([
798
+ "if",
799
+ "else",
800
+ "for",
801
+ "while",
802
+ "do",
803
+ "switch",
804
+ "case",
805
+ "return",
806
+ "break",
807
+ "continue",
808
+ "discard"
809
+ ]), i = /\b([a-zA-Z_]\w*)\s*\(/g;
810
+ let r;
811
+ for (; (r = i.exec(e)) !== null; ) {
812
+ const s = r[1];
813
+ t.has(s) || n.push({
814
+ name: s,
815
+ type: "function",
816
+ index: r.index
817
+ });
818
+ }
819
+ return n;
820
+ }
821
+ findUniformCalls(e, n) {
822
+ const t = [];
823
+ for (const i of n) {
824
+ const r = new RegExp(`\\b${i.name}\\b`, "g");
825
+ let s;
826
+ for (; (s = r.exec(e)) !== null; )
827
+ t.push({
828
+ name: i.name,
829
+ type: "uniform",
830
+ index: s.index
831
+ });
832
+ }
833
+ return t;
834
+ }
835
+ findMentionCalls(e) {
836
+ const n = [], t = /@(\w+)\.([a-zA-Z_]\w*)/g;
837
+ let i;
838
+ for (; (i = t.exec(e)) !== null; ) {
839
+ const r = i[1], s = i[2];
840
+ n.push({
841
+ name: `${r}.${s}`,
842
+ type: "mention",
843
+ index: i.index
844
+ });
845
+ }
846
+ return n;
847
+ }
848
+ }
849
+ class F {
850
+ constructor(e) {
851
+ /** Flag to track if the shader has been compiled */
852
+ a(this, "isCompiled", !1);
853
+ /** Original and compiled shader parsers */
854
+ a(this, "original");
855
+ /** Compiled parser will be updated with rewritten source after processing imports */
856
+ a(this, "compiled");
857
+ /** Collected requirements from imports */
858
+ a(this, "requirements", {
859
+ uniforms: /* @__PURE__ */ new Map(),
860
+ functions: /* @__PURE__ */ new Map()
861
+ });
862
+ this.original = new w(e), this.compiled = new w(e);
863
+ }
864
+ /**
865
+ * Detect WebGL version from shader source
866
+ */
867
+ version() {
868
+ return this.original.version();
869
+ }
870
+ /**
871
+ * Get the original source code of the shader
872
+ */
873
+ source() {
874
+ return this.original.source;
875
+ }
876
+ /**
877
+ * Force recompilation of the shader, reprocessing all imports and rewrites
878
+ * It's not necessary to call this manually because the state gets lost whenever the shader is switched out and back in.
879
+ */
880
+ recompile() {
881
+ return this.isCompiled = !1, this.compile();
882
+ }
883
+ /**
884
+ * Compile the shader source, resolving all imports
885
+ */
886
+ compile() {
887
+ 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);
888
+ }
889
+ /**
890
+ * Process all #import directives
891
+ */
892
+ processImports() {
893
+ const e = this.original.parse(), n = e.functions.flatMap((t) => t.dependencies.filter((i) => i.type === "mention").map((i) => ({
894
+ name: i.name.split(".")[0],
895
+ uniform: i.name.split(".")[1]
896
+ })));
897
+ for (const t of e.imports) {
898
+ const i = b.resolve(t.module), r = i.extract(t.name);
899
+ let s = n.filter(
900
+ (l) => l.name === r.function.name
901
+ );
902
+ if (s.length > 0) {
903
+ const l = i.getDefinition().uniforms;
904
+ if (s = s.filter((f) => {
905
+ const c = l.find(
906
+ (m) => m.name === `u_${f.uniform}` || m.name === f.uniform
907
+ );
908
+ if (c) {
909
+ r.dependencies.uniforms.some(
910
+ (p) => p.name === c.name
911
+ ) || r.dependencies.uniforms.push(c);
912
+ const m = n.indexOf(f);
913
+ return m > -1 && n.splice(m, 1), !1;
914
+ }
915
+ return !0;
916
+ }), s.length > 0)
917
+ throw new Z(
918
+ t.module,
919
+ r.function.name,
920
+ s[0].uniform
921
+ );
922
+ }
923
+ const o = i.copy();
924
+ this.processExtraction(r, t.alias, o.options), y.merge(t.module, o);
925
+ }
926
+ if (n.length > 0)
927
+ throw new ee(
928
+ n[0].name,
929
+ n[0].uniform
930
+ );
931
+ }
932
+ /**
933
+ * Process an extraction: rewrite names and collect as requirements
934
+ */
935
+ processExtraction(e, n, t = {}) {
936
+ const i = e.function, r = Math.random().toString(36).substring(2, 8), s = `${n}_${r}`;
937
+ for (let l = e.dependencies.functions.length - 1; l >= 0; l--) {
938
+ const f = e.dependencies.functions[l], c = this.rewriteFunction(f, n, {
939
+ uniforms: e.dependencies.uniforms,
940
+ functions: e.dependencies.functions,
941
+ unique: s
942
+ });
943
+ this.requirements.functions.set(c.name, c);
944
+ }
945
+ const o = this.rewriteFunction(i, n, {
946
+ uniforms: e.dependencies.uniforms,
947
+ functions: e.dependencies.functions,
948
+ rename: !0,
949
+ unique: s
950
+ });
951
+ this.requirements.functions.set(o.name, o);
952
+ for (const l of e.dependencies.uniforms) {
953
+ if (E.has(l.name)) continue;
954
+ const f = {
955
+ ...l,
956
+ name: `${s}_${l.name}${l.arrayNum ? `[${l.arrayNum}]` : ""}`
957
+ };
958
+ if (t[i.name]) {
959
+ const c = Object.entries(t[i.name]).find(
960
+ ([m, p]) => p.uniform === l.name
961
+ );
962
+ c && (c[1].uniform = `${s}_${l.name}`);
963
+ }
964
+ this.requirements.uniforms.set(f.name, f);
965
+ }
966
+ t[i.name] && n !== i.name && (t[n] = t[i.name], delete t[i.name]);
967
+ }
968
+ /**
969
+ * Rewrite a function: namespace all uniform and helper function references
970
+ */
971
+ rewriteFunction(e, n, t = { rename: !1, uniforms: [], functions: [], unique: "" }) {
972
+ const i = new Set(t.uniforms.map((c) => c.name)), r = new Set(t.functions.map((c) => c.name)), s = [], o = t.unique ? t.unique : n;
973
+ for (const c of e.dependencies)
974
+ if (c.index !== void 0)
975
+ if (c.type === "uniform" && i.has(c.name)) {
976
+ if (E.has(c.name)) continue;
977
+ s.push({
978
+ index: c.index,
979
+ oldText: c.name,
980
+ newText: `${o}_${c.name}`
981
+ });
982
+ } else c.type === "function" && r.has(c.name) && s.push({
983
+ index: c.index,
984
+ oldText: c.name,
985
+ newText: `${o}_${c.name}`
986
+ });
987
+ const l = this.applyRewrites(e.body, s), f = t.rename ? n : `${o}_${e.name}`;
988
+ return {
989
+ ...e,
990
+ name: f,
991
+ body: l
992
+ };
993
+ }
994
+ /**
995
+ * Apply rewrite operations to a string, processing from end to start
996
+ */
997
+ applyRewrites(e, n) {
998
+ const t = [...n].sort((r, s) => s.index - r.index);
999
+ let i = e;
1000
+ for (const r of t)
1001
+ i = i.slice(0, r.index) + r.newText + i.slice(r.index + r.oldText.length);
1002
+ return i;
1003
+ }
1004
+ /**
1005
+ * Build the final compiled shader
1006
+ */
1007
+ build() {
1008
+ const e = this.original.parse();
1009
+ let n = this.original.source;
1010
+ n = this.removeImportLines(n, e);
1011
+ const t = this.findInsertionPointForUniforms(n), i = this.generateUniformsCode();
1012
+ i && (n = n.slice(0, t) + i + `
1013
+ ` + n.slice(t));
1014
+ const r = this.findInsertionPointForFunctions(n), s = this.generateFunctionCode();
1015
+ return s && (n = n.slice(0, r) + s + n.slice(r)), n = n.replace(/\n{3,}/g, `
1016
+
1017
+ `), n = this.replaceMentions(n, e), n;
1018
+ }
1019
+ replaceMentions(e, n) {
1020
+ let t = e;
1021
+ const i = n.functions.filter(
1022
+ (r) => r.dependencies.some((s) => s.type === "mention")
1023
+ );
1024
+ for (const r of i) {
1025
+ const s = r.dependencies.filter((o) => o.type === "mention");
1026
+ for (const o of s) {
1027
+ const l = o.name.split("."), f = new RegExp(`\\b${l[0]}_(\\w+)_${l[1]}\\b`, "g"), c = this.requirements.uniforms.keys().find((p) => {
1028
+ var g;
1029
+ return ((g = p.match(f)) == null ? void 0 : g[0]) === p;
1030
+ });
1031
+ if (!c)
1032
+ throw new ne(
1033
+ o.name,
1034
+ r.name
1035
+ );
1036
+ const m = new RegExp(`@\\b${o.name}\\b`, "g");
1037
+ t = t.replace(m, c);
1038
+ }
1039
+ }
1040
+ return t;
1041
+ }
1042
+ /**
1043
+ * Remove #import lines from shader source
1044
+ */
1045
+ removeImportLines(e, n) {
1046
+ const t = e.split(`
1047
+ `), i = new Set(n.imports.map((r) => r.line));
1048
+ return t.filter((r, s) => {
1049
+ const o = i.has(s + 1);
1050
+ if (!o && r.trim() === "" && s > 0) {
1051
+ const l = s - 1;
1052
+ if (i.has(l + 1))
1053
+ return !1;
1054
+ }
1055
+ return !o;
1056
+ }).join(`
1057
+ `);
1058
+ }
1059
+ /**
1060
+ * Find insertion point for uniforms (after existing uniforms)
1061
+ */
1062
+ findInsertionPointForUniforms(e) {
1063
+ const n = new w(e).parse(), t = n.uniforms.find(
1064
+ (o) => o.line === Math.max(...n.uniforms.map((l) => l.line ?? 0))
1065
+ ), i = e.split(`
1066
+ `);
1067
+ let r = 0;
1068
+ if (t && t.line)
1069
+ r = t.line;
1070
+ else
1071
+ for (let o = 0; o < i.length; o++) {
1072
+ const l = i[o].trim();
1073
+ if (l.startsWith("#version")) {
1074
+ r = o + 1;
1075
+ continue;
1076
+ }
1077
+ if (l.startsWith("precision ")) {
1078
+ r = o + 1;
1079
+ continue;
1080
+ }
1081
+ if (l === "" || l.startsWith("//")) {
1082
+ r === o && (r = o + 1);
1083
+ continue;
1084
+ }
533
1085
  break;
1086
+ }
1087
+ let s = 0;
1088
+ for (let o = 0; o < r; o++)
1089
+ s += i[o].length + 1;
1090
+ return s;
1091
+ }
1092
+ findInsertionPointForFunctions(e) {
1093
+ const n = new w(e).parse(), t = n.functions.find(
1094
+ (o) => o.line === Math.min(...n.functions.map((l) => l.line ?? 1 / 0))
1095
+ ), i = e.split(`
1096
+ `);
1097
+ let r = 0;
1098
+ if (t && t.line)
1099
+ r = t.line - 2;
1100
+ else
1101
+ throw new W();
1102
+ let s = 0;
1103
+ for (let o = 0; o < r; o++)
1104
+ s += i[o].length + 1;
1105
+ return s;
1106
+ }
1107
+ /**
1108
+ * Generate GLSL code for uniforms
1109
+ */
1110
+ generateUniformsCode() {
1111
+ const e = [];
1112
+ if (this.requirements.uniforms.size > 0)
1113
+ for (const n of this.checkUniformsPresence())
1114
+ e.push(`uniform ${n.type} ${n.name};`);
1115
+ return e.length === 0 ? "" : e.join(`
1116
+ `) + `
1117
+ `;
1118
+ }
1119
+ /**
1120
+ * Generate GLSL code for functions
1121
+ */
1122
+ generateFunctionCode() {
1123
+ const e = [];
1124
+ if (this.requirements.functions.size > 0)
1125
+ for (const n of this.checkFunctionsPresence()) {
1126
+ const t = n.params.map((i) => `${i.type} ${i.name}`).join(", ");
1127
+ e.push(`
1128
+ ${n.type} ${n.name}(${t}) ${n.body}`);
1129
+ }
1130
+ return e.length === 0 ? "" : e.join(`
1131
+ `) + `
1132
+ `;
1133
+ }
1134
+ /**
1135
+ * Check which required uniforms are missing from the original shader
1136
+ */
1137
+ checkUniformsPresence() {
1138
+ const e = this.original.parse(), n = [], t = this.requirements.uniforms;
1139
+ for (const [i, r] of t) {
1140
+ const s = e.uniforms.find((o) => o.name === i);
1141
+ if (!s) {
1142
+ n.push(r);
1143
+ continue;
1144
+ }
1145
+ if (s.type !== r.type)
1146
+ throw new C(
1147
+ "uniform",
1148
+ i,
1149
+ r.type,
1150
+ s.type
1151
+ );
534
1152
  }
1153
+ return n;
1154
+ }
1155
+ /**
1156
+ * Check which required functions are missing from the original shader
1157
+ */
1158
+ checkFunctionsPresence() {
1159
+ const e = this.original.parse(), n = [], t = this.requirements.functions;
1160
+ for (const [i, r] of t) {
1161
+ const s = e.functions.find((o) => o.name === i);
1162
+ if (!s) {
1163
+ n.push(r);
1164
+ continue;
1165
+ }
1166
+ if (s.type !== r.type)
1167
+ throw new C(
1168
+ "function",
1169
+ i,
1170
+ r.type,
1171
+ s.type
1172
+ );
1173
+ }
1174
+ return n;
1175
+ }
1176
+ }
1177
+ class v extends F {
1178
+ constructor(n, t, i = {}) {
1179
+ super(t);
1180
+ a(this, "name");
1181
+ a(this, "options", {});
1182
+ this.name = n, this.options = this.resolveOptions(i);
1183
+ }
1184
+ resolveOptions(n) {
1185
+ if (!(n != null && n.default)) return n || {};
1186
+ const t = this.original.parse(), i = n.default;
1187
+ for (const r of t.functions)
1188
+ if (!(r.name === "main" || r.name === "default"))
1189
+ if (n[r.name]) {
1190
+ const s = n[r.name];
1191
+ for (const o in i)
1192
+ o in s || (s[o] = i[o]);
1193
+ } else
1194
+ n[r.name] = { ...i };
1195
+ return delete n.default, n || {};
1196
+ }
1197
+ /**
1198
+ * Define a module with given name and source, and register it
1199
+ */
1200
+ static define(n) {
1201
+ const { name: t, source: i, options: r } = n;
1202
+ if (t === "sandbox" || t.startsWith("sandbox/"))
1203
+ throw new Q(t);
1204
+ const s = new v(t, i, r);
1205
+ if (b.has(t))
1206
+ throw new J(t);
1207
+ return b.register(t, s), s;
1208
+ }
1209
+ /**
1210
+ * Resolve a module by name from the registry, throwing an error if not found
1211
+ */
1212
+ static resolve(n) {
1213
+ return b.resolve(n);
1214
+ }
1215
+ /**
1216
+ * Create a copy of the module. To unplug references to the original object.
1217
+ * Used when copying module to the runtime registry to allow independent runtime changes to options without affecting the original module definition.
1218
+ */
1219
+ copy(n = "original") {
1220
+ return new v(
1221
+ this.name,
1222
+ this[n].source,
1223
+ JSON.parse(JSON.stringify(this.options))
1224
+ );
1225
+ }
1226
+ /**
1227
+ * Merge options from another module into this one, without affecting the original module definition.
1228
+ * Used when merging imported modules into the runtime registry.
1229
+ */
1230
+ merge(n) {
1231
+ this.options = this.options || {};
1232
+ const t = this.getDefinition().uniforms.map((i) => i.name);
1233
+ for (const [i, r] of Object.entries(n.options ?? {}))
1234
+ if (!this.options[i]) this.options[i] = r;
1235
+ else
1236
+ for (const [s, o] of Object.entries(r))
1237
+ t.includes(o.uniform) || (this.options[i][s] = o);
1238
+ }
1239
+ /**
1240
+ * Get the module definition
1241
+ */
1242
+ getDefinition() {
1243
+ return this.compile(), {
1244
+ name: this.name,
1245
+ methods: this.compiled.parse().functions.map((n) => n.name).filter((n) => n !== "main" && n !== "default"),
1246
+ uniforms: this.compiled.parse().uniforms.map((n) => ({ name: n.name, type: n.type })),
1247
+ options: this.options
1248
+ };
1249
+ }
1250
+ /**
1251
+ * Extract a method with all its dependencies
1252
+ */
1253
+ extract(n) {
1254
+ if (this.compile(), n === "main")
1255
+ throw new K(this.name);
1256
+ if (n === "default")
1257
+ throw new X(this.name);
1258
+ const t = this.compiled.parse(), i = t.functions.find((o) => o.name === n);
1259
+ if (!i)
1260
+ throw new Y(this.name, n);
1261
+ const r = /* @__PURE__ */ new Map(), s = /* @__PURE__ */ new Map();
1262
+ return this.collectDependencies({
1263
+ current: i,
1264
+ scope: {
1265
+ functions: t.functions,
1266
+ uniforms: t.uniforms
1267
+ },
1268
+ collected: {
1269
+ functions: r,
1270
+ uniforms: s
1271
+ },
1272
+ visited: /* @__PURE__ */ new Set([n])
1273
+ }), {
1274
+ function: i,
1275
+ dependencies: {
1276
+ functions: Array.from(r.values()),
1277
+ uniforms: Array.from(s.values())
1278
+ }
1279
+ };
1280
+ }
1281
+ /**
1282
+ * Recursively collect all function and uniform dependencies
1283
+ */
1284
+ collectDependencies(n) {
1285
+ for (const t of n.current.dependencies)
1286
+ if (t.type === "function") {
1287
+ if (n.visited.has(t.name)) continue;
1288
+ const i = n.scope.functions.find((r) => r.name === t.name);
1289
+ i && (n.visited.add(t.name), n.collected.functions.set(t.name, i), this.collectDependencies({
1290
+ current: i,
1291
+ scope: {
1292
+ functions: n.scope.functions,
1293
+ uniforms: n.scope.uniforms
1294
+ },
1295
+ collected: {
1296
+ functions: n.collected.functions,
1297
+ uniforms: n.collected.uniforms
1298
+ },
1299
+ visited: n.visited
1300
+ }));
1301
+ } else if (t.type === "uniform") {
1302
+ const i = n.scope.uniforms.find(
1303
+ (r) => r.name === t.name
1304
+ );
1305
+ i && !n.collected.uniforms.has(t.name) && n.collected.uniforms.set(t.name, i);
1306
+ }
1307
+ }
1308
+ }
1309
+ class V {
1310
+ constructor(e = []) {
1311
+ a(this, "modules", /* @__PURE__ */ new Map());
1312
+ e.forEach((n) => {
1313
+ this.register(n.name, n);
1314
+ });
1315
+ }
1316
+ /**
1317
+ * Compile all registered modules.
1318
+ */
1319
+ compile() {
1320
+ this.modules.forEach((e) => {
1321
+ e.compile();
1322
+ });
1323
+ }
1324
+ /**
1325
+ * Get the list of available shader modules.
1326
+ */
1327
+ available() {
1328
+ return Array.from(this.modules.values()).map(
1329
+ (e) => e.getDefinition()
1330
+ );
1331
+ }
1332
+ /**
1333
+ * Get the list of uniforms required by the currently registered modules.
1334
+ * This is used to automatically set up the uniforms in the shader based on the modules in use.
1335
+ */
1336
+ defaults() {
1337
+ const e = {};
1338
+ return this.modules.forEach((n) => {
1339
+ const t = n.getDefinition();
1340
+ if (t.options)
1341
+ for (const i in t.options) {
1342
+ const r = t.options[i];
1343
+ for (const s in r) {
1344
+ const o = r[s];
1345
+ o.default !== void 0 && !t.uniforms.map((l) => l.name).includes(o.uniform) && (e[o.uniform] = o.default);
1346
+ }
1347
+ }
1348
+ }), e;
1349
+ }
1350
+ /**
1351
+ * Resolve the options from the module definitions for a given function name.
1352
+ */
1353
+ resolveOptions(e) {
1354
+ for (const n of this.modules.values())
1355
+ if (n.options && n.options[e])
1356
+ return n.options[e];
1357
+ return null;
1358
+ }
1359
+ /**
1360
+ * Register a new module in the registry.
1361
+ */
1362
+ register(e, n) {
1363
+ this.modules.set(e, n);
1364
+ }
1365
+ /**
1366
+ * Merge a module into the registry. If a module with the same name already exists, options will be merged together.
1367
+ */
1368
+ merge(e, n) {
1369
+ if (!this.modules.has(e)) return this.register(e, n);
1370
+ const t = this.modules.get(e);
1371
+ t.merge(n), this.modules.set(e, t);
1372
+ }
1373
+ /**
1374
+ * Resolve a module by name. Throws an error if the module is not found.
1375
+ */
1376
+ resolve(e) {
1377
+ const n = this.modules.get(e);
1378
+ if (!n)
1379
+ throw new j(e);
1380
+ return n;
1381
+ }
1382
+ /**
1383
+ * Check if a module exists in the registry by name.
1384
+ */
1385
+ has(e) {
1386
+ return this.modules.has(e);
1387
+ }
1388
+ /**
1389
+ * Check if the registry is empty (no modules registered).
1390
+ */
1391
+ isEmpty() {
1392
+ return this.modules.size === 0;
535
1393
  }
1394
+ /**
1395
+ * Remove a module from the registry by name.
1396
+ */
1397
+ remove(e) {
1398
+ this.modules.delete(e);
1399
+ }
1400
+ /**
1401
+ * Load multiple modules into the registry at once.
1402
+ */
1403
+ load(e) {
1404
+ e.forEach((n) => {
1405
+ this.register(n.name, n);
1406
+ });
1407
+ }
1408
+ /**
1409
+ * Clear all registered modules from the registry.
1410
+ */
1411
+ clear() {
1412
+ this.modules.clear();
1413
+ }
1414
+ }
1415
+ const oe = `// ─── Constants ──────────────────────────────────────────────
1416
+
1417
+ const float PI = 3.14159265359;
1418
+ const float TAU = 6.28318530718;
1419
+
1420
+ // ─── UV Transforms ──────────────────────────────────────────
1421
+
1422
+ /**
1423
+ * Center UV coordinates — remap to range where (0,0) is canvas center.
1424
+ * Aspect-ratio corrected using resolution length.
1425
+ * @uv-modifier
1426
+ */
1427
+ vec2 center(vec2 uv) {
1428
+ return (uv - 0.5 * u_resolution) / length(u_resolution);
1429
+ }
1430
+
1431
+ /**
1432
+ * Translate UV coordinates by offset.
1433
+ * @uv-modifier
1434
+ */
1435
+ vec2 translate(vec2 uv, vec2 offset) {
1436
+ return uv - offset;
1437
+ }
1438
+
1439
+ /**
1440
+ * Scale UV coordinates by factor around origin.
1441
+ * @uv-modifier
1442
+ */
1443
+ vec2 scale(vec2 uv, float factor) {
1444
+ return uv * factor;
1445
+ }
1446
+
1447
+ /**
1448
+ * Zoom — scale UV with aspect ratio correction.
1449
+ * Expects centered UV (use center() first).
1450
+ * Pushes UV outward/inward from origin.
1451
+ * factor = zoom factor (>1 = zoom in, <1 = zoom out)
1452
+ * @uv-modifier
1453
+ */
1454
+ vec2 zoom(vec2 uv, float factor) {
1455
+ return uv / max(factor, 0.001);
1456
+ }
1457
+
1458
+ /**
1459
+ * Normalize UV to range -1 to 1 with aspect ratio correction.
1460
+ * @uv-modifier
1461
+ */
1462
+ vec2 norm(vec2 uv) {
1463
+ uv *= min(u_resolution.x, u_resolution.y) / length(u_resolution);
1464
+ return uv;
1465
+ }
1466
+
1467
+ /**
1468
+ * Rotate UV coordinates around origin by angle (radians).
1469
+ * @uv-modifier
1470
+ */
1471
+ vec2 rotate(vec2 uv, float angle) {
1472
+ float c = cos(angle);
1473
+ float s = sin(angle);
1474
+ return vec2(uv.x * c - uv.y * s, uv.x * s + uv.y * c);
1475
+ }
1476
+
1477
+ /**
1478
+ * Tile — repeat coordinates in a grid of given size.
1479
+ * @uv-modifier
1480
+ */
1481
+ vec2 tile(vec2 uv, float size) {
1482
+ return fract(uv / size) * size;
1483
+ }
1484
+
1485
+ /**
1486
+ * Cartesian to polar coordinates.
1487
+ * Returns vec2(angle, radius) where angle is -PI to PI.
1488
+ */
1489
+ vec2 polar(vec2 uv) {
1490
+ return vec2(atan(uv.y, uv.x), length(uv));
1491
+ }
1492
+
1493
+ /**
1494
+ * Aspect ratio correction — makes UV square regardless of canvas shape.
1495
+ * @uv-modifier
1496
+ */
1497
+ vec2 aspect(vec2 uv) {
1498
+ return uv * vec2(u_resolution.x / u_resolution.y, 1.0);
1499
+ }
1500
+
1501
+ // ─── Math Utilities ─────────────────────────────────────────
1502
+
1503
+ /**
1504
+ * Remap a value from one range to another.
1505
+ * map(0.5, 0.0, 1.0, -1.0, 1.0) → 0.0
1506
+ */
1507
+ float map(float value, float inMin, float inMax, float outMin, float outMax) {
1508
+ return outMin + (value - inMin) * (outMax - outMin) / (inMax - inMin);
1509
+ }
1510
+
1511
+ // ─── Noise & Random ─────────────────────────────────────────
1512
+
1513
+ /**
1514
+ * Pseudo-random hash from 2D coordinates.
1515
+ * Returns float in 0–1 range.
1516
+ */
1517
+ float hash(vec2 p) {
1518
+ return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);
1519
+ }
1520
+
1521
+ /**
1522
+ * 2D pseudo-random hash.
1523
+ * Returns vec2 in 0–1 range — used for point scattering (worley etc).
1524
+ */
1525
+ vec2 hash2(vec2 p) {
1526
+ p = vec2(dot(p, vec2(127.1, 311.7)), dot(p, vec2(269.5, 183.3)));
1527
+ return fract(sin(p) * 43758.5453123);
1528
+ }
1529
+
1530
+ /**
1531
+ * Smooth value noise — interpolated hash grid.
1532
+ */
1533
+ float noise(vec2 p) {
1534
+ vec2 i = floor(p);
1535
+ vec2 f = fract(p);
1536
+ vec2 u = f * f * (3.0 - 2.0 * f);
1537
+
1538
+ return mix(
1539
+ mix(hash(i), hash(i + vec2(1.0, 0.0)), u.x),
1540
+ mix(hash(i + vec2(0.0, 1.0)), hash(i + vec2(1.0, 1.0)), u.x),
1541
+ u.y
1542
+ );
1543
+ }
1544
+
1545
+ /**
1546
+ * Fractal Brownian Motion — 6 octaves of layered noise.
1547
+ * Returns ~0–1 range. Great for clouds, terrain, organic textures.
1548
+ */
1549
+ float fbm(vec2 p) {
1550
+ float value = 0.0;
1551
+ float amplitude = 0.5;
1552
+
1553
+ for (int i = 0; i < 6; i++) {
1554
+ value += amplitude * noise(p);
1555
+ p *= 2.0;
1556
+ amplitude *= 0.5;
1557
+ }
1558
+
1559
+ return value;
1560
+ }
1561
+
1562
+ /**
1563
+ * Worley (cellular / voronoi) noise.
1564
+ * Returns distance to nearest random cell point.
1565
+ * Great for cells, cracks, organic patterns.
1566
+ */
1567
+ float worley(vec2 p) {
1568
+ vec2 i = floor(p);
1569
+ vec2 f = fract(p);
1570
+ float minDist = 1.0;
1571
+
1572
+ for (int y = -1; y <= 1; y++) {
1573
+ for (int x = -1; x <= 1; x++) {
1574
+ vec2 neighbor = vec2(float(x), float(y));
1575
+ vec2 point = hash2(i + neighbor);
1576
+ float dist = length(neighbor + point - f);
1577
+ minDist = min(minDist, dist);
1578
+ }
1579
+ }
1580
+
1581
+ return minDist;
1582
+ }
1583
+
1584
+ /**
1585
+ * Waves — layered sine wave interference pattern.
1586
+ * Creates clean, regular wave lines like fabric or moiré.
1587
+ * frequency = wave density (5.0 = fabric, 10.0 = fine lines)
1588
+ * Returns 0–1 range.
1589
+ */
1590
+ float waves(vec2 p, float frequency) {
1591
+ return 0.6 + 0.4 * sin(
1592
+ frequency * (p.x + p.y + cos(3.0 * p.x + 5.0 * p.y)) +
1593
+ sin(frequency * 4.0 * (p.x + p.y))
1594
+ );
1595
+ }
1596
+
1597
+ /**
1598
+ * Voronoi cell lookup — returns the position of the nearest cell point.
1599
+ * Same algorithm as worley, but returns the point instead of distance.
1600
+ * Great for UV snapping, cell-based effects.
1601
+ */
1602
+ vec2 voronoi(vec2 p) {
1603
+ vec2 i = floor(p);
1604
+ vec2 f = fract(p);
1605
+ float minDist = 10.0;
1606
+ vec2 nearest = vec2(0.0);
1607
+
1608
+ for (int y = -1; y <= 1; y++) {
1609
+ for (int x = -1; x <= 1; x++) {
1610
+ vec2 neighbor = vec2(float(x), float(y));
1611
+ vec2 point = hash2(i + neighbor);
1612
+ float dist = length(neighbor + point - f);
1613
+ if (dist < minDist) {
1614
+ minDist = dist;
1615
+ nearest = i + neighbor + point;
1616
+ }
1617
+ }
1618
+ }
1619
+
1620
+ return nearest;
1621
+ }
1622
+
1623
+ void main() {}
1624
+ `, ae = `/**
1625
+ * Hex integer to RGB.
1626
+ * Usage: hex(0xFF6600) → orange
1627
+ */
1628
+ vec3 hex(int value) {
1629
+ float v = float(value);
1630
+ float r = floor(v / 65536.0);
1631
+ float g = floor((v - r * 65536.0) / 256.0);
1632
+ float b = v - r * 65536.0 - g * 256.0;
1633
+ return vec3(r, g, b) / 255.0;
1634
+ }
1635
+
1636
+ /**
1637
+ * RGB 0–255 to normalized RGB 0–1.
1638
+ * Usage: rgb255(255.0, 128.0, 0.0) → orange
1639
+ */
1640
+ vec3 rgb255(float r, float g, float b) {
1641
+ return vec3(r, g, b) / 255.0;
1642
+ }
1643
+
1644
+ /**
1645
+ * HSV to RGB.
1646
+ * Input: vec3(hue 0–1, saturation 0–1, value 0–1)
1647
+ */
1648
+ vec3 hsv(vec3 c) {
1649
+ vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
1650
+ vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
1651
+ return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
1652
+ }
1653
+
1654
+ /**
1655
+ * HSL to RGB.
1656
+ * Input: vec3(hue 0–1, saturation 0–1, lightness 0–1)
1657
+ */
1658
+ vec3 hsl(vec3 c) {
1659
+ vec3 rgb = clamp(abs(mod(c.x * 6.0 + vec3(0.0, 4.0, 2.0), 6.0) - 3.0) - 1.0, 0.0, 1.0);
1660
+ return c.z + c.y * (rgb - 0.5) * (1.0 - abs(2.0 * c.z - 1.0));
1661
+ }
1662
+
1663
+ /**
1664
+ * Linear gradient between two colors.
1665
+ * t is clamped to 0–1.
1666
+ */
1667
+ vec3 gradient(vec3 a, vec3 b, float t) {
1668
+ return mix(a, b, clamp(t, 0.0, 1.0));
1669
+ }
1670
+
1671
+ /**
1672
+ * 3-stop gradient.
1673
+ * t=0 → a, t=0.5 → b, t=1 → c
1674
+ */
1675
+ vec3 gradient3(vec3 a, vec3 b, vec3 c, float t) {
1676
+ t = clamp(t, 0.0, 1.0);
1677
+ return t < 0.5
1678
+ ? mix(a, b, t * 2.0)
1679
+ : mix(b, c, (t - 0.5) * 2.0);
1680
+ }
1681
+
1682
+ /**
1683
+ * Cosine palette — Inigo Quilez formula.
1684
+ * color = a + b * cos(2π(c·t + d))
1685
+ * Generates infinite smooth color ramps from 4 vec3 params.
1686
+ */
1687
+ vec3 palette(vec3 a, vec3 b, vec3 c, vec3 d, float t) {
1688
+ return a + b * cos(6.28318 * (c * t + d));
1689
+ }
1690
+
1691
+ /**
1692
+ * Banded gradient — 3-zone color mapping with sharp transitions.
1693
+ * Uses tent functions instead of linear interpolation.
1694
+ * t=0 → b (center), t=1 → a (middle), t=2 → c (outer).
1695
+ * sharpness = transition width (2.0 = sharp, 1.0 = soft).
1696
+ */
1697
+ vec3 bands(vec3 a, vec3 b, vec3 c, float t, float sharpness) {
1698
+ float w1 = max(0.0, 1.0 - sharpness * abs(1.0 - t));
1699
+ float w2 = max(0.0, 1.0 - sharpness * abs(t));
1700
+ float w3 = 1.0 - min(1.0, w1 + w2);
1701
+ return a * w1 + b * w2 + c * w3;
1702
+ }
1703
+
1704
+ /**
1705
+ * Iridescent — iterative interference color pattern.
1706
+ * Generates rainbow-like colors from UV through trigonometric iteration.
1707
+ * Creates shimmering, oil-slick-like color fields.
1708
+ * time = animation time (pass u_time), speed = animation speed
1709
+ */
1710
+ vec3 iridescent(vec2 uv, float time, float speed) {
1711
+ float d = -time * 0.5 * speed;
1712
+ float a = 0.0;
1713
+ for (int i = 0; i < 8; i++) {
1714
+ a += cos(float(i) - d - a * uv.x);
1715
+ d += sin(uv.y * float(i) + a);
1716
+ }
1717
+ d += time * 0.5 * speed;
1718
+ vec3 col = vec3(cos(uv * vec2(d, a)) * 0.6 + 0.4, cos(a + d) * 0.5 + 0.5);
1719
+ return cos(col * cos(vec3(d, a, 2.5)) * 0.5 + 0.5);
1720
+ }
1721
+
1722
+ void main() {}
1723
+ `, le = `// ─── Time Shapers ──────────────────────────────────────────
1724
+ // Convert raw time (u_time) to normalized 0–1 range.
1725
+ // Output feeds directly into easing functions.
1726
+
1727
+ /**
1728
+ * Loop — repeating sawtooth 0→1→0→1...
1729
+ * duration = cycle length in seconds
1730
+ */
1731
+ float loop(float t, float duration) {
1732
+ return fract(t / duration);
1733
+ }
1734
+
1735
+ /**
1736
+ * Pingpong — triangle wave 0→1→0→1...
1737
+ * duration = half-cycle length (0→1 takes \`duration\` seconds)
1738
+ */
1739
+ float pingpong(float t, float duration) {
1740
+ float m = mod(t, duration * 2.0);
1741
+ return m < duration ? m / duration : 2.0 - m / duration;
1742
+ }
1743
+
1744
+ /**
1745
+ * Once — single play 0→1, then stays at 1.
1746
+ * duration = animation length in seconds
1747
+ * Use with delay: once(u_time - 2.0, 3.0) starts at 2s, takes 3s.
1748
+ */
1749
+ float once(float t, float duration) {
1750
+ return clamp(t / duration, 0.0, 1.0);
1751
+ }
1752
+
1753
+ /**
1754
+ * Reverse — flip animation direction.
1755
+ * Turns 0→1 into 1→0. Works with any easing or shaper.
1756
+ * Usage: reverse(spring(loop(u_time, 2.0))) for spring zoom-in.
1757
+ */
1758
+ float reverse(float t) {
1759
+ return 1.0 - t;
1760
+ }
1761
+
1762
+ // ─── Easing Curves ─────────────────────────────────────────
1763
+ // All take t (0–1) and return shaped t (0–1).
1764
+ // Compose with time shapers: ease_in(loop(u_time, 2.0))
1765
+
1766
+ /**
1767
+ * Ease in — cubic acceleration. Slow start, fast end.
1768
+ */
1769
+ float ease_in(float t) {
1770
+ return t * t * t;
1771
+ }
1772
+
1773
+ /**
1774
+ * Ease out — cubic deceleration. Fast start, slow end.
1775
+ */
1776
+ float ease_out(float t) {
1777
+ float f = 1.0 - t;
1778
+ return 1.0 - f * f * f;
1779
+ }
1780
+
1781
+ /**
1782
+ * Ease in-out — cubic smooth both ends.
1783
+ */
1784
+ float ease_in_out(float t) {
1785
+ return t < 0.5
1786
+ ? 4.0 * t * t * t
1787
+ : 1.0 - pow(-2.0 * t + 2.0, 3.0) * 0.5;
1788
+ }
1789
+
1790
+ /**
1791
+ * Spring — damped oscillation. Overshoots then settles at 1.
1792
+ */
1793
+ float spring(float t) {
1794
+ return 1.0 - exp(-6.0 * t) * cos(12.0 * t);
1795
+ }
1796
+
1797
+ /**
1798
+ * Bounce — bouncing ball landing. Multiple bounces settling at 1.
1799
+ */
1800
+ float bounce(float t) {
1801
+ if (t < 1.0 / 2.75) {
1802
+ return 7.5625 * t * t;
1803
+ } else if (t < 2.0 / 2.75) {
1804
+ t -= 1.5 / 2.75;
1805
+ return 7.5625 * t * t + 0.75;
1806
+ } else if (t < 2.5 / 2.75) {
1807
+ t -= 2.25 / 2.75;
1808
+ return 7.5625 * t * t + 0.9375;
1809
+ } else {
1810
+ t -= 2.625 / 2.75;
1811
+ return 7.5625 * t * t + 0.984375;
1812
+ }
1813
+ }
1814
+
1815
+ /**
1816
+ * Elastic — springy overshoot with oscillation.
1817
+ */
1818
+ float elastic(float t) {
1819
+ return sin(13.0 * 3.14159 * 0.5 * t) * pow(2.0, -10.0 * t) + 1.0;
1820
+ }
1821
+
1822
+ /**
1823
+ * Overshoot — goes past 1, then pulls back. Slight rubber-band feel.
1824
+ */
1825
+ float overshoot(float t) {
1826
+ float s = 1.70158;
1827
+ float f = 1.0 - t;
1828
+ return 1.0 - f * f * (f * (s + 1.0) - s);
1829
+ }
1830
+
1831
+ /**
1832
+ * Teleport — barely creeps, then near-instant jump with spring settle.
1833
+ * Duration mostly = wait time. Jump happens at ~85% of t.
1834
+ * Tiny slow drift → snap → spring overshoot → settle at 1.
1835
+ */
1836
+ float teleport(float t) {
1837
+ float jump = smoothstep(0.8, 0.85, t);
1838
+ float creep = pow(t / 0.8, 4.0) * 0.1 * (1.0 - jump);
1839
+ float s = max(t - 0.85, 0.0) * 6.667;
1840
+ float settle = exp(-5.0 * s) * sin(s * 15.0) * 0.15;
1841
+ return creep + jump + settle;
1842
+ }
1843
+
1844
+ void main() {}
1845
+ `, ce = `#import hash from 'sandbox'
1846
+ #import noise from 'sandbox'
1847
+ #import fbm from 'sandbox'
1848
+ #import voronoi from 'sandbox'
1849
+ #import worley from 'sandbox'
1850
+
1851
+ uniform float u_intensity;
1852
+
1853
+ // ─── UV Effects ─────────────────────────────────────────────
1854
+ // Each function takes UV and returns modified UV.
1855
+ // All use u_intensity uniform for configuration.
1856
+
1857
+ /**
1858
+ * Pixelate — blocky mosaic effect.
1859
+ * Snaps UV to a grid. Higher intensity = larger pixels.
1860
+ * intensity = pixel count along shortest axis (default: 20)
1861
+ * @uv-modifier
1862
+ */
1863
+ vec2 pixelate(vec2 uv, float intensity) {
1864
+ float size = length(u_resolution) / (max(intensity, 1.0) * 10.0);
1865
+ return floor(uv / size) * size;
1866
+ }
1867
+
1868
+ /**
1869
+ * Twist — spiral distortion from center outward.
1870
+ * Expects centered UV (use center() first).
1871
+ * intensity = twist strength (0.4 = subtle, 1.0 = full spiral)
1872
+ * @uv-modifier
1873
+ */
1874
+ vec2 twist(vec2 uv, float intensity) {
1875
+ float dist = length(uv);
1876
+ float angle = atan(uv.y, uv.x) - intensity * 20.0 * dist;
1877
+ return vec2(cos(angle), sin(angle)) * dist;
1878
+ }
1879
+
1880
+ /**
1881
+ * Ripple — concentric wave distortion from center.
1882
+ * Expects centered UV (use center() first).
1883
+ * Creates water-drop-like rings.
1884
+ * intensity = wave amplitude (0.5 = gentle, 2.0 = strong)
1885
+ * @uv-modifier
1886
+ */
1887
+ vec2 ripple(vec2 uv, float intensity) {
1888
+ float dist = length(uv);
1889
+ float wave = sin(dist * 40.0 - u_time * 3.0) * intensity * 0.02;
1890
+ return uv + normalize(uv + 0.001) * wave;
1891
+ }
1892
+
1893
+ /**
1894
+ * Fisheye — barrel distortion from center.
1895
+ * Expects centered UV (use center() first).
1896
+ * Bends space outward like a fisheye lens.
1897
+ * intensity = distortion power (0.5 = subtle, 2.0 = extreme)
1898
+ * @uv-modifier
1899
+ */
1900
+ vec2 fisheye(vec2 uv, float intensity) {
1901
+ float dist = length(uv);
1902
+ float power = pow(dist, intensity) / dist;
1903
+ return uv * power;
536
1904
  }
537
- const d = class d {
538
- constructor(t) {
539
- r(this, "gl");
540
- r(this, "program", null);
541
- r(this, "uniforms", /* @__PURE__ */ new Map());
542
- this.gl = t;
1905
+
1906
+ /**
1907
+ * Wobble — animated sine wave displacement.
1908
+ * Creates a jelly-like horizontal wobble.
1909
+ * intensity = wobble amount (1.0 = gentle, 5.0 = wild)
1910
+ * @uv-modifier
1911
+ */
1912
+ vec2 wobble(vec2 uv, float intensity) {
1913
+ uv.x += sin(uv.y * 10.0 + u_time * 2.0) * intensity * 0.01;
1914
+ uv.y += cos(uv.x * 10.0 + u_time * 2.0) * intensity * 0.01;
1915
+ return uv;
1916
+ }
1917
+
1918
+ /**
1919
+ * Organic — iterative fluid morph distortion.
1920
+ * Creates marble-like flowing patterns.
1921
+ * intensity = animation speed (3.0 = default)
1922
+ * @uv-modifier
1923
+ */
1924
+ vec2 organic(vec2 uv, float intensity) {
1925
+ float speed = u_time * intensity;
1926
+ vec2 acc = vec2(uv.x + uv.y);
1927
+
1928
+ for (int i = 0; i < 5; i++) {
1929
+ acc += sin(max(uv.x, uv.y)) + uv;
1930
+ uv += 0.5 * vec2(
1931
+ cos(5.1123314 + 0.353 * acc.y + speed * 0.131121),
1932
+ sin(acc.x - 0.113 * speed)
1933
+ );
1934
+ uv -= cos(uv.x + uv.y) - sin(uv.x * 0.711 - uv.y);
1935
+ }
1936
+
1937
+ return uv;
1938
+ }
1939
+
1940
+ /**
1941
+ * Glitch — random horizontal line displacement.
1942
+ * Creates digital glitch artifact bands.
1943
+ * intensity = glitch strength (0.5 = subtle, 3.0 = heavy)
1944
+ * @uv-modifier
1945
+ */
1946
+ vec2 glitch(vec2 uv, float intensity) {
1947
+ float line = floor(uv.y * 50.0);
1948
+ float shift = hash(vec2(line, floor(u_time * 8.0)));
1949
+ shift = step(0.9, shift) * (shift - 0.9) * 10.0;
1950
+ uv.x += shift * intensity * 0.1 * u_resolution.x;
1951
+ return uv;
1952
+ }
1953
+
1954
+ /**
1955
+ * Mirror — reflect UV across a chosen axis.
1956
+ * Creates bilateral symmetry.
1957
+ * intensity = 0 for horizontal mirror, 1 for vertical mirror
1958
+ * @uv-modifier
1959
+ */
1960
+ vec2 mirror(vec2 uv, float intensity) {
1961
+ if (intensity < 0.5) {
1962
+ uv.x = abs(uv.x);
1963
+ } else {
1964
+ uv.y = abs(uv.y);
1965
+ }
1966
+ return uv;
1967
+ }
1968
+
1969
+ /**
1970
+ * Kaleidoscope — repeating angular symmetry.
1971
+ * Expects centered UV (use center() first).
1972
+ * Creates mandala-like radial repeats.
1973
+ * intensity = number of segments (4 = quad, 6 = hex, 8 = octa)
1974
+ * @uv-modifier
1975
+ */
1976
+ vec2 kaleidoscope(vec2 uv, float intensity) {
1977
+ float segments = max(intensity, 1.0);
1978
+ float angle = atan(uv.y, uv.x);
1979
+ float segment_angle = 6.28318 / segments;
1980
+ angle = mod(angle, segment_angle);
1981
+ angle = abs(angle - segment_angle * 0.5);
1982
+ float r = length(uv);
1983
+ return vec2(cos(angle), sin(angle)) * r;
1984
+ }
1985
+
1986
+ /**
1987
+ * Warp — domain warping using fractal noise.
1988
+ * Displaces UV by layered fbm noise for smoke/cloud-like distortion.
1989
+ * Animated over time.
1990
+ * intensity = warp strength (0.5 = subtle haze, 3.0 = heavy distortion)
1991
+ * @uv-modifier
1992
+ */
1993
+ vec2 warp(vec2 uv, float intensity) {
1994
+ vec2 offset = vec2(
1995
+ fbm(uv + u_time * 0.3),
1996
+ fbm(uv + vec2(5.2, 1.3) + u_time * 0.3)
1997
+ );
1998
+ return uv + offset * intensity * 0.1;
1999
+ }
2000
+
2001
+ /**
2002
+ * Displace — noise-based UV displacement.
2003
+ * Shifts UV using smooth value noise for a wavy, heat-haze look.
2004
+ * Animated over time.
2005
+ * intensity = displacement amount (1.0 = gentle, 5.0 = strong)
2006
+ * @uv-modifier
2007
+ */
2008
+ vec2 displace(vec2 uv, float intensity) {
2009
+ float nx = noise(uv * 5.0 + u_time);
2010
+ float ny = noise(uv * 5.0 + vec2(3.7, 7.1) + u_time);
2011
+ return uv + (vec2(nx, ny) - 0.5) * intensity * 0.05;
2012
+ }
2013
+
2014
+ /**
2015
+ * Shatter — voronoi cell-based UV snapping.
2016
+ * Snaps UV to nearest cell point, creating a broken-glass look.
2017
+ * intensity = cell density (5.0 = large shards, 20.0 = fine fragments)
2018
+ * @uv-modifier
2019
+ */
2020
+ vec2 shatter(vec2 uv, float intensity) {
2021
+ return voronoi(uv * intensity) / intensity;
2022
+ }
2023
+
2024
+ /**
2025
+ * Cells — cellular distortion using Worley distance.
2026
+ * Displaces UV outward from cell edges, like looking through textured glass.
2027
+ * intensity = cell scale (3.0 = large bubbles, 15.0 = fine texture)
2028
+ * @uv-modifier
2029
+ */
2030
+ vec2 cells(vec2 uv, float intensity) {
2031
+ float dist = worley(uv * intensity);
2032
+ vec2 grad = vec2(
2033
+ worley(uv * intensity + vec2(0.01, 0.0)) - dist,
2034
+ worley(uv * intensity + vec2(0.0, 0.01)) - dist
2035
+ );
2036
+ return uv + grad * dist * 2.0;
2037
+ }
2038
+
2039
+ void main() {}
2040
+ `, ue = `#import hash from 'sandbox'
2041
+
2042
+ uniform float u_intensity;
2043
+
2044
+ // ─── Color Filters ──────────────────────────────────────────
2045
+ // Each function takes a color and returns modified color.
2046
+ // All use u_intensity uniform for configuration.
2047
+
2048
+ /**
2049
+ * Contrast — adjust contrast around mid-gray.
2050
+ * intensity: 1.0 = original, >1 = more contrast, <1 = flatter
2051
+ * @color-modifier
2052
+ */
2053
+ vec3 contrast(vec3 color, float intensity) {
2054
+ return (color - 0.5) * intensity + 0.5;
2055
+ }
2056
+
2057
+ /**
2058
+ * Brightness — multiply overall brightness.
2059
+ * intensity: 1.0 = original, >1 = brighter, <1 = darker
2060
+ * @color-modifier
2061
+ */
2062
+ vec3 brightness(vec3 color, float intensity) {
2063
+ return color * intensity;
2064
+ }
2065
+
2066
+ /**
2067
+ * Saturate — adjust color saturation.
2068
+ * intensity: 0 = grayscale, 1.0 = original, >1 = oversaturated
2069
+ * @color-modifier
2070
+ */
2071
+ vec3 saturate(vec3 color, float intensity) {
2072
+ float gray = dot(color, vec3(0.299, 0.587, 0.114));
2073
+ return mix(vec3(gray), color, intensity);
2074
+ }
2075
+
2076
+ /**
2077
+ * Posterize — reduce color to N discrete levels per channel.
2078
+ * intensity = number of levels (4 = retro, 16 = subtle, 256 = nearly smooth)
2079
+ * @color-modifier
2080
+ */
2081
+ vec3 posterize(vec3 color, float intensity) {
2082
+ float levels = max(intensity, 1.0);
2083
+ return floor(color * levels + 0.5) / levels;
2084
+ }
2085
+
2086
+ /**
2087
+ * Threshold — convert to black and white based on cutoff.
2088
+ * intensity = cutoff point (0.5 = balanced, lower = more white)
2089
+ * @color-modifier
2090
+ */
2091
+ vec3 threshold(vec3 color, float intensity) {
2092
+ float avg = dot(color, vec3(0.299, 0.587, 0.114));
2093
+ return avg > intensity ? vec3(1.0) : vec3(0.0);
2094
+ }
2095
+
2096
+ /**
2097
+ * Invert — flip all color channels.
2098
+ * intensity: 0.0 = original, 1.0 = fully inverted, 0.5 = mid-gray
2099
+ * @color-modifier
2100
+ */
2101
+ vec3 invert(vec3 color, float intensity) {
2102
+ return mix(color, 1.0 - color, intensity);
2103
+ }
2104
+
2105
+ /**
2106
+ * Glow — luminance-based bloom, bright areas get amplified.
2107
+ * intensity = glow strength (0.5 = subtle, 2.0 = intense)
2108
+ * @color-modifier
2109
+ */
2110
+ vec3 glow(vec3 color, float intensity) {
2111
+ float luminance = dot(color, vec3(0.299, 0.587, 0.114));
2112
+ return color + color * luminance * intensity;
2113
+ }
2114
+
2115
+ /**
2116
+ * Grain — animated film noise overlay.
2117
+ * intensity = noise strength (0.1 = subtle, 0.5 = heavy)
2118
+ * @color-modifier
2119
+ */
2120
+ vec3 grain(vec3 color, vec2 uv, float intensity) {
2121
+ float n = (hash(uv * 1000.0 + u_time) - 0.5) * intensity;
2122
+ return color + n;
2123
+ }
2124
+
2125
+ /**
2126
+ * Vignette — darken canvas edges.
2127
+ * Applies circular falloff from center.
2128
+ * intensity = darkness strength (1.0 = subtle, 2.0 = strong)
2129
+ * @color-modifier
2130
+ */
2131
+ vec3 vignette(vec3 color, vec2 uv, float intensity) {
2132
+ vec2 centered = uv / u_resolution - 0.5;
2133
+ float dist = length(centered);
2134
+ float falloff = 1.0 - smoothstep(0.3, 0.7, dist * intensity);
2135
+ return color * falloff;
2136
+ }
2137
+
2138
+ /**
2139
+ * Sepia — warm brownish tint like old photographs.
2140
+ * intensity: 0.0 = original, 1.0 = full sepia
2141
+ * @color-modifier
2142
+ */
2143
+ vec3 sepia(vec3 color, float intensity) {
2144
+ vec3 s;
2145
+ s.r = dot(color, vec3(0.393, 0.769, 0.189));
2146
+ s.g = dot(color, vec3(0.349, 0.686, 0.168));
2147
+ s.b = dot(color, vec3(0.272, 0.534, 0.131));
2148
+ return mix(color, s, intensity);
2149
+ }
2150
+
2151
+ /**
2152
+ * Gamma — apply gamma correction curve.
2153
+ * intensity = gamma value (1.0 = linear, 2.2 = standard sRGB, <1 = brighten darks)
2154
+ * @color-modifier
2155
+ */
2156
+ vec3 gamma(vec3 color, float intensity) {
2157
+ return pow(max(color, 0.0), vec3(1.0 / max(intensity, 0.001)));
2158
+ }
2159
+
2160
+ /**
2161
+ * Tint — blend color toward a target tint.
2162
+ * intensity: 0.0 = original, 1.0 = fully tinted
2163
+ * @color-modifier
2164
+ */
2165
+ vec3 tint(vec3 color, vec3 tintColor, float intensity) {
2166
+ return mix(color, color * tintColor, intensity);
2167
+ }
2168
+
2169
+ /**
2170
+ * Highlights — add white light to bright areas.
2171
+ * Uses max channel brightness so even saturated colors trigger highlights.
2172
+ * intensity = highlight strength (0.2 = subtle sheen, 1.0 = strong gloss)
2173
+ * @color-modifier
2174
+ */
2175
+ vec3 highlights(vec3 color, float intensity) {
2176
+ float bright = max(color.r, max(color.g, color.b + 0.3));
2177
+ return color + max(bright * 5.5 - 4.0, 0.0) * intensity;
2178
+ }
2179
+
2180
+ /**
2181
+ * Bayer 8×8 threshold matrix — computed mathematically.
2182
+ * Returns threshold value 0–1 for ordered dithering.
2183
+ */
2184
+ float bayer8(vec2 p) {
2185
+ p = mod(floor(p), 8.0);
2186
+ float value = 0.0;
2187
+ float divisor = 1.0;
2188
+ float multiplier = 16.0;
2189
+
2190
+ for (int i = 0; i < 3; i++) {
2191
+ vec2 q = mod(floor(p / divisor), 2.0);
2192
+ value += (q.x * 2.0 + q.y * 3.0 - q.x * q.y * 4.0) * multiplier;
2193
+ divisor *= 2.0;
2194
+ multiplier *= 0.25;
2195
+ }
2196
+
2197
+ return value / 64.0;
2198
+ }
2199
+
2200
+ /**
2201
+ * Dither — ordered Bayer 8×8 dithering.
2202
+ * Reduces color to discrete levels with a threshold pattern.
2203
+ * Use pixelate() on UV before coloring for blocky dither cells.
2204
+ * intensity = number of color levels (2 = 1-bit, 4 = retro, 8 = subtle)
2205
+ * @color-modifier
2206
+ */
2207
+ vec3 dither(vec3 color, vec2 uv, float intensity) {
2208
+ float levels = max(intensity, 2.0);
2209
+ float threshold = bayer8(uv) - 0.5;
2210
+ float stepSize = 1.0 / (levels - 1.0);
2211
+ color += threshold * stepSize;
2212
+ return clamp(floor(color * (levels - 1.0) + 0.5) / (levels - 1.0), 0.0, 1.0);
2213
+ }
2214
+
2215
+ /**
2216
+ * Arcade — pixelated Bayer dithering.
2217
+ * Combines pixelation and ordered dither for retro 8-bit look.
2218
+ * intensity = number of color levels (2 = 1-bit, 4 = retro, 8 = subtle)
2219
+ * @color-modifier
2220
+ */
2221
+ vec3 arcade(vec3 color, vec2 uv, float intensity) {
2222
+ vec2 grid = uv * u_resolution * 0.5;
2223
+ return dither(color, grid, intensity);
2224
+ }
2225
+
2226
+ void main() {}
2227
+ `, b = new V([
2228
+ new v("sandbox", oe),
2229
+ new v("sandbox/colors", ae),
2230
+ new v("sandbox/time", le),
2231
+ new v("sandbox/effects", ce, {
2232
+ default: {
2233
+ intensity: { uniform: "u_intensity", default: 1 }
2234
+ },
2235
+ pixelate: {
2236
+ intensity: { uniform: "u_intensity", default: 20 }
2237
+ },
2238
+ twist: {
2239
+ intensity: { uniform: "u_intensity", default: 1 }
2240
+ },
2241
+ ripple: {
2242
+ intensity: { uniform: "u_intensity", default: 1 }
2243
+ },
2244
+ fisheye: {
2245
+ intensity: { uniform: "u_intensity", default: 1 }
2246
+ },
2247
+ wobble: {
2248
+ intensity: { uniform: "u_intensity", default: 1 }
2249
+ },
2250
+ organic: {
2251
+ intensity: { uniform: "u_intensity", default: 3 }
2252
+ },
2253
+ glitch: {
2254
+ intensity: { uniform: "u_intensity", default: 1 }
2255
+ },
2256
+ mirror: {
2257
+ intensity: { uniform: "u_intensity", default: 0 }
2258
+ },
2259
+ kaleidoscope: {
2260
+ intensity: { uniform: "u_intensity", default: 6 }
2261
+ },
2262
+ zoom: {
2263
+ intensity: { uniform: "u_intensity", default: 1 }
2264
+ },
2265
+ warp: {
2266
+ intensity: { uniform: "u_intensity", default: 1 }
2267
+ },
2268
+ displace: {
2269
+ intensity: { uniform: "u_intensity", default: 1 }
2270
+ },
2271
+ shatter: {
2272
+ intensity: { uniform: "u_intensity", default: 10 }
2273
+ },
2274
+ cells: {
2275
+ intensity: { uniform: "u_intensity", default: 8 }
2276
+ },
2277
+ glass: {
2278
+ intensity: { uniform: "u_intensity", default: 1 }
2279
+ }
2280
+ }),
2281
+ new v("sandbox/filters", ue, {
2282
+ default: {
2283
+ intensity: { uniform: "u_intensity", default: 1 }
2284
+ },
2285
+ posterize: {
2286
+ intensity: { uniform: "u_intensity", default: 8 }
2287
+ },
2288
+ threshold: {
2289
+ intensity: { uniform: "u_intensity", default: 0.5 }
2290
+ },
2291
+ grain: {
2292
+ intensity: { uniform: "u_intensity", default: 0.1 }
2293
+ },
2294
+ vignette: {
2295
+ intensity: { uniform: "u_intensity", default: 1.4 }
2296
+ },
2297
+ glow: {
2298
+ intensity: { uniform: "u_intensity", default: 0.5 }
2299
+ },
2300
+ gamma: {
2301
+ intensity: { uniform: "u_intensity", default: 2.2 }
2302
+ },
2303
+ dither: {
2304
+ intensity: { uniform: "u_intensity", default: 4 }
2305
+ },
2306
+ highlights: {
2307
+ intensity: { uniform: "u_intensity", default: 0.5 }
2308
+ }
2309
+ })
2310
+ ]), y = new V(), E = /* @__PURE__ */ new Map([
2311
+ ["u_resolution", "vec2"],
2312
+ ["u_time", "float"],
2313
+ ["u_delta", "float"],
2314
+ ["u_mouse", "vec2"],
2315
+ ["u_frame", "int"]
2316
+ ]);
2317
+ class fe {
2318
+ constructor(e) {
2319
+ a(this, "gl");
2320
+ a(this, "program", null);
2321
+ a(this, "uniforms", /* @__PURE__ */ new Map());
2322
+ this.gl = e;
543
2323
  }
544
2324
  /**
545
2325
  * Attach to a WebGL program.
546
2326
  * Invalidates all cached locations since they're program-specific.
547
2327
  */
548
- attachProgram(t) {
549
- this.program = t;
550
- for (const e of this.uniforms.values())
551
- e.invalidateLocation();
2328
+ attachProgram(e) {
2329
+ this.program = e;
2330
+ for (const n of this.uniforms.values())
2331
+ n.invalidateLocation();
552
2332
  return this;
553
2333
  }
554
2334
  /**
555
2335
  * Set a uniform value.
556
2336
  * Creates the uniform if it doesn't exist, updates if it does.
557
2337
  */
558
- set(t, e) {
559
- const i = this.uniforms.get(t);
560
- return i ? i.setValue(e) : this.uniforms.set(t, new x(t, e)), this;
2338
+ set(e, n) {
2339
+ const t = this.uniforms.get(e);
2340
+ return t ? t.setValue(n) : this.uniforms.set(e, new k(e, n)), this;
561
2341
  }
562
2342
  /**
563
2343
  * Set multiple uniforms at once.
564
2344
  */
565
- setMany(t) {
566
- for (const [e, i] of Object.entries(t))
567
- this.set(e, i);
2345
+ setMany(e) {
2346
+ for (const [n, t] of Object.entries(e))
2347
+ this.set(n, t);
568
2348
  return this;
569
2349
  }
570
2350
  /**
571
2351
  * Get current uniform value.
572
2352
  */
573
- get(t) {
574
- var e;
575
- return (e = this.uniforms.get(t)) == null ? void 0 : e.getValue();
2353
+ get(e) {
2354
+ var n;
2355
+ return (n = this.uniforms.get(e)) == null ? void 0 : n.getValue();
576
2356
  }
577
2357
  /**
578
2358
  * Check if uniform exists.
579
2359
  */
580
- has(t) {
581
- return this.uniforms.has(t);
2360
+ has(e) {
2361
+ return this.uniforms.has(e);
582
2362
  }
583
2363
  /**
584
2364
  * Remove a uniform.
585
2365
  */
586
- delete(t) {
587
- return this.uniforms.delete(t);
2366
+ delete(e) {
2367
+ return this.uniforms.delete(e);
588
2368
  }
589
2369
  /**
590
2370
  * Upload all uniforms to GPU.
@@ -593,20 +2373,20 @@ const d = class d {
593
2373
  uploadAll() {
594
2374
  if (!this.program)
595
2375
  return this;
596
- for (const t of this.uniforms.values())
597
- t.upload(this.gl, this.program);
2376
+ for (const e of this.uniforms.values())
2377
+ e.upload(this.gl, this.program);
598
2378
  return this;
599
2379
  }
600
2380
  /**
601
2381
  * Upload only built-in uniforms (u_resolution, u_time, u_delta, u_mouse, u_frame).
602
2382
  * Call this every frame with current values.
603
2383
  */
604
- uploadBuiltIns(t, e, i) {
605
- if (this.set("u_resolution", e), this.set("u_time", t.time), this.set("u_delta", t.delta), this.set("u_mouse", i), this.set("u_frame", t.frame), !this.program)
2384
+ uploadBuiltIns(e, n, t) {
2385
+ 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)
606
2386
  return this;
607
- for (const s of d.BUILT_INS) {
608
- const n = this.uniforms.get(s);
609
- n && n.upload(this.gl, this.program);
2387
+ for (const i of E.keys()) {
2388
+ const r = this.uniforms.get(i);
2389
+ r && r.upload(this.gl, this.program);
610
2390
  }
611
2391
  return this;
612
2392
  }
@@ -634,64 +2414,62 @@ const d = class d {
634
2414
  get size() {
635
2415
  return this.uniforms.size;
636
2416
  }
637
- };
638
- /** Built-in uniform names that are handled automatically */
639
- r(d, "BUILT_INS", /* @__PURE__ */ new Set([
640
- "u_resolution",
641
- "u_time",
642
- "u_delta",
643
- "u_mouse",
644
- "u_frame"
645
- ]));
646
- let v = d;
647
- class b {
2417
+ }
2418
+ class O {
648
2419
  constructor() {
649
- r(this, "hooks", /* @__PURE__ */ new Map());
2420
+ a(this, "hooks", /* @__PURE__ */ new Map());
650
2421
  }
651
2422
  id() {
652
2423
  return Math.random().toString(36).substring(2, 10);
653
2424
  }
654
2425
  /** Add a new hook, returns a removal function */
655
- add(t) {
656
- const e = this.id();
657
- return this.hooks.set(e, t), () => this.remove(e);
2426
+ add(e) {
2427
+ const n = this.id();
2428
+ return this.hooks.set(n, e), () => this.remove(n);
658
2429
  }
659
2430
  /** Remove a hook by its ID */
660
- remove(t) {
661
- this.hooks.delete(t);
2431
+ remove(e) {
2432
+ this.hooks.delete(e);
662
2433
  }
663
2434
  /** Run all hooks with the given state */
664
- run(t) {
665
- for (const [e, i] of this.hooks)
666
- i(t) === !1 && this.remove(e);
2435
+ run(e) {
2436
+ for (const [n, t] of this.hooks)
2437
+ try {
2438
+ t(e) === !1 && this.remove(n);
2439
+ } catch (i) {
2440
+ throw new ie(
2441
+ n,
2442
+ i instanceof Error ? i.message : String(i)
2443
+ );
2444
+ }
667
2445
  }
668
2446
  destroy() {
669
2447
  this.hooks.clear();
670
2448
  }
671
2449
  }
672
- class _ {
673
- constructor(t, e) {
674
- r(this, "canvas");
675
- r(this, "gl");
676
- r(this, "options");
677
- r(this, "onBeforeHooks", new b());
678
- r(this, "onAfterHooks", new b());
679
- r(this, "_program");
680
- r(this, "_geometry");
681
- r(this, "_uniforms");
682
- r(this, "_clock");
683
- r(this, "_resolution", [1, 1]);
684
- r(this, "_mouse", [0, 0]);
685
- r(this, "_version", 1);
686
- r(this, "playing", !1);
687
- this.canvas = t, this.options = e, this.gl = this.initContext(), this.enableExtensions(), this._program = new a(this.gl), this._geometry = p.fullscreenQuad(this.gl), this._uniforms = new v(this.gl), this._clock = new R(), this.options.fps && this._clock.setMaxFps(this.options.fps), this.options.onBeforeRender && this.onBeforeHooks.add(this.options.onBeforeRender), this.options.onAfterRender && this.onAfterHooks.add(this.options.onAfterRender), this.onRender = this.onRender.bind(this);
2450
+ class M {
2451
+ constructor(e, n) {
2452
+ a(this, "canvas");
2453
+ a(this, "gl");
2454
+ a(this, "options");
2455
+ a(this, "onBeforeHooks", new O());
2456
+ a(this, "onAfterHooks", new O());
2457
+ a(this, "_program");
2458
+ a(this, "_geometry");
2459
+ a(this, "_uniforms");
2460
+ a(this, "_clock");
2461
+ a(this, "_resolution", [1, 1]);
2462
+ a(this, "_mouse", [0, 0]);
2463
+ a(this, "_version", 1);
2464
+ a(this, "playing", !1);
2465
+ this.canvas = e, this.options = n, this.gl = this.initContext(), this.enableExtensions(), this._program = new se(this.gl), this._geometry = A.fullscreenQuad(this.gl), this._uniforms = new fe(this.gl), this._clock = new re(), 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);
688
2466
  }
689
2467
  /**
690
2468
  * Factory method to create and setup WebGL instance.
691
2469
  */
692
- static setup(t, e) {
693
- const i = new _(t, e);
694
- return e.vertex && e.fragment && i.shader(e.vertex, e.fragment), e.uniforms && i._uniforms.setMany(e.uniforms), i;
2470
+ static setup(e, n) {
2471
+ const t = new M(e, n);
2472
+ 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;
695
2473
  }
696
2474
  /**
697
2475
  * Initialize WebGL context.
@@ -699,20 +2477,20 @@ class _ {
699
2477
  * Context errors are fatal but still reported via onError.
700
2478
  */
701
2479
  initContext() {
702
- const t = {
2480
+ const e = {
703
2481
  antialias: this.options.antialias,
704
2482
  preserveDrawingBuffer: this.options.preserveDrawingBuffer,
705
2483
  alpha: !0,
706
2484
  depth: !1,
707
2485
  stencil: !1
708
- }, e = this.canvas.getContext("webgl2", t);
709
- if (e)
710
- return this._version = 2, e;
711
- const i = this.canvas.getContext("webgl", t);
712
- if (i)
713
- return this._version = 1, i;
714
- const s = new w("not_supported");
715
- throw this.options.onError(s), s;
2486
+ }, n = this.canvas.getContext("webgl2", e);
2487
+ if (n)
2488
+ return this._version = 2, n;
2489
+ const t = this.canvas.getContext("webgl", e);
2490
+ if (t)
2491
+ return this._version = 1, t;
2492
+ const i = new z();
2493
+ throw this.options.onError(i), i;
716
2494
  }
717
2495
  /**
718
2496
  * Enable useful WebGL extensions.
@@ -723,50 +2501,62 @@ class _ {
723
2501
  /**
724
2502
  * Set viewport dimensions.
725
2503
  */
726
- viewport(t, e, i, s) {
727
- return this.canvas.width = i, this.canvas.height = s, this.gl.viewport(t, e, i, s), this._resolution = [i, s], this;
2504
+ viewport(e, n, t, i) {
2505
+ return this.canvas.width = t, this.canvas.height = i, this.gl.viewport(e, n, t, i), this._resolution = [t, i], this;
728
2506
  }
729
2507
  /**
730
2508
  * Set the clock time
731
2509
  */
732
- clock(t) {
733
- return this._clock.setTime(t), this;
2510
+ clock(e) {
2511
+ return this._clock.setTime(e), this;
734
2512
  }
735
2513
  /**
736
2514
  * Update mouse position.
737
2515
  */
738
- mouse(t, e) {
739
- return this._mouse = [t, e], this;
2516
+ mouse(e, n) {
2517
+ return this._mouse = [e, n], this;
740
2518
  }
741
2519
  /**
742
2520
  * Set a uniform value.
743
2521
  */
744
- uniform(t, e) {
745
- return this._uniforms.set(t, e), this;
2522
+ uniform(e, n) {
2523
+ return this._uniforms.set(e, n), this;
746
2524
  }
747
2525
  /**
748
2526
  * Set multiple uniforms.
749
2527
  */
750
- uniforms(t) {
751
- return this._uniforms.setMany(t), this;
2528
+ uniforms(e) {
2529
+ return this._uniforms.setMany(e), this;
752
2530
  }
753
2531
  /**
754
2532
  * Get current uniform value.
755
2533
  */
756
- getUniform(t) {
757
- return this._uniforms.get(t);
2534
+ getUniform(e) {
2535
+ return this._uniforms.get(e);
758
2536
  }
759
2537
  /**
760
2538
  * Compile and link shaders.
761
2539
  * Errors are handled via onError callback, never thrown.
762
2540
  */
763
- shader(t, e) {
2541
+ shader(e, n) {
764
2542
  try {
765
- this._program.compile(t, e), this._version = this._program.getVersion(), this._geometry.linkAttributes(this._program);
766
- const i = this._program.getProgram();
767
- i && this._uniforms.attachProgram(i), this.options.onLoad();
768
- } catch (i) {
769
- i instanceof u && this.options.onError(i);
2543
+ if (y.clear(), e.version() !== n.version())
2544
+ throw new G(
2545
+ e.version(),
2546
+ n.version()
2547
+ );
2548
+ this._program.compile(e.source(), n.compile()), this._version = n.version(), this._geometry.linkAttributes(this._program);
2549
+ const t = this._program.getProgram();
2550
+ t && this._uniforms.attachProgram(t);
2551
+ try {
2552
+ this.options.onLoad();
2553
+ } catch (i) {
2554
+ throw new te(
2555
+ i instanceof Error ? i.message : String(i)
2556
+ );
2557
+ }
2558
+ } catch (t) {
2559
+ t instanceof h && this.options.onError(t);
770
2560
  }
771
2561
  return this;
772
2562
  }
@@ -781,8 +2571,19 @@ class _ {
781
2571
  */
782
2572
  pause() {
783
2573
  if (!this.playing) return this;
784
- const t = this._clock.getState();
785
- return this.onBeforeHooks.run(t), this.playing = !1, this._clock.stop(), this.onAfterHooks.run(t), this;
2574
+ const e = this._clock.getState();
2575
+ try {
2576
+ this.onBeforeHooks.run(e);
2577
+ } catch (n) {
2578
+ n instanceof h && this.options.onError(n);
2579
+ }
2580
+ this.playing = !1, this._clock.stop();
2581
+ try {
2582
+ this.onAfterHooks.run(e);
2583
+ } catch (n) {
2584
+ n instanceof h && this.options.onError(n);
2585
+ }
2586
+ return this;
786
2587
  }
787
2588
  /**
788
2589
  * Render a single frame.
@@ -812,17 +2613,34 @@ class _ {
812
2613
  * Cleanup all resources.
813
2614
  */
814
2615
  destroy() {
815
- this.pause(), this._clock.destroy(), this._geometry.destroy(), this._program.destroy(), this._uniforms.destroy(), this.onAfterHooks.destroy(), this.onBeforeHooks.destroy();
2616
+ this.pause(), this._clock.destroy(), this._geometry.destroy(), this._program.destroy(), this._uniforms.destroy(), this.onAfterHooks.destroy(), this.onBeforeHooks.destroy(), y.clear();
816
2617
  }
817
2618
  /**
818
2619
  * Internal render callback.
819
2620
  */
820
- onRender(t) {
821
- const e = this.gl;
822
- this.onBeforeHooks.run(t), e.clearColor(0, 0, 0, 0), e.clear(e.COLOR_BUFFER_BIT), this._program.use(), this._uniforms.uploadBuiltIns(t, this._resolution, this._mouse), this._uniforms.uploadAll(), this._geometry.bind(), this._geometry.draw(), this.onAfterHooks.run(t);
2621
+ onRender(e) {
2622
+ const n = this.gl;
2623
+ try {
2624
+ this.onBeforeHooks.run(e);
2625
+ } catch (t) {
2626
+ t instanceof h && this.options.onError(t);
2627
+ }
2628
+ 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();
2629
+ try {
2630
+ this.onAfterHooks.run(e);
2631
+ } catch (t) {
2632
+ t instanceof h && this.options.onError(t);
2633
+ }
2634
+ }
2635
+ }
2636
+ class d extends F {
2637
+ constructor(e) {
2638
+ super(e), E.forEach((n, t) => {
2639
+ this.requirements.uniforms.set(t, { name: t, type: n, line: 0 });
2640
+ });
823
2641
  }
824
2642
  }
825
- const g = `#ifdef GL_ES
2643
+ const S = `#ifdef GL_ES
826
2644
  precision mediump float;
827
2645
  #endif
828
2646
 
@@ -835,7 +2653,7 @@ void main() {
835
2653
  v_texcoord = a_texcoord;
836
2654
  gl_Position = vec4(a_position, 0.0, 1.0);
837
2655
  }
838
- `, A = `#ifdef GL_ES
2656
+ `, L = `#ifdef GL_ES
839
2657
  precision mediump float;
840
2658
  #endif
841
2659
 
@@ -849,7 +2667,7 @@ void main() {
849
2667
  vec3 color = vec3(uv.x, uv.y, 0.5 + 0.5 * sin(u_time));
850
2668
  gl_FragColor = vec4(color, 1.0);
851
2669
  }
852
- `, E = `#version 300 es
2670
+ `, U = `#version 300 es
853
2671
 
854
2672
  in vec2 a_position;
855
2673
  in vec2 a_texcoord;
@@ -859,7 +2677,7 @@ out vec2 v_texcoord;
859
2677
  void main() {
860
2678
  v_texcoord = a_texcoord;
861
2679
  gl_Position = vec4(a_position, 0.0, 1.0);
862
- }`, V = `#version 300 es
2680
+ }`, he = `#version 300 es
863
2681
  precision highp float;
864
2682
 
865
2683
  uniform vec2 u_resolution;
@@ -874,19 +2692,22 @@ void main() {
874
2692
  vec3 color = vec3(uv.x, uv.y, 0.5 + 0.5 * sin(u_time));
875
2693
  fragColor = vec4(color, 1.0);
876
2694
  }`;
877
- class y {
878
- constructor(t, e) {
2695
+ class $ {
2696
+ constructor(e, n) {
879
2697
  /** Active event listeners */
880
- r(this, "listeners", []);
2698
+ a(this, "listeners", []);
881
2699
  /** HTML canvas element */
882
- r(this, "canvasEl");
2700
+ a(this, "canvasEl");
883
2701
  /** Resolved options */
884
- r(this, "options");
2702
+ a(this, "options");
885
2703
  /** WebGL engine */
886
- r(this, "engine");
2704
+ a(this, "engine");
887
2705
  /** User sets custom vertex shader */
888
- r(this, "usingCustomVertex", !1);
889
- this.canvasEl = t, this.options = this.resolveOptions(e), this.engine = _.setup(this.canvasEl, this.options), this.setupListeners(), this.setViewport(), this.options.autoplay && this.play();
2706
+ a(this, "usingCustomVertex", !1);
2707
+ if (this.canvasEl = e, this.options = this.resolveOptions(n), this.engine = M.setup(this.canvasEl, this.options), this.setupListeners(), this.setViewport(), this.options.modules)
2708
+ for (const [t, i] of Object.entries(this.options.modules))
2709
+ this.module(t, i);
2710
+ this.options.autoplay && this.play();
890
2711
  }
891
2712
  /**
892
2713
  * Sandbox - A lightweight WebGL wrapper for shader effects.
@@ -906,23 +2727,49 @@ class y {
906
2727
  * autoplay: true,
907
2728
  * });
908
2729
  */
909
- static create(t, e) {
910
- return new y(t, e);
2730
+ static create(e, n) {
2731
+ return new $(e, n);
911
2732
  }
912
- resolveOptions(t) {
913
- const e = {
914
- vertex: g,
915
- fragment: A,
2733
+ /**
2734
+ * Define a shader module that can be imported in shader source with `#import <function> from "module_name"`.
2735
+ * @example
2736
+ * Sandbox.defineModule("my_module", source, { options });
2737
+ * // Then in shader:
2738
+ * // #import myFunc from "my_module"
2739
+ * // void main() {
2740
+ * // myFunc();
2741
+ * // }
2742
+ */
2743
+ static defineModule(e, n, t = {}) {
2744
+ v.define({ name: e, source: n, options: t });
2745
+ }
2746
+ /**
2747
+ * Get the list of available shader modules that can be used with `#import` in shader source.
2748
+ */
2749
+ static availableModules() {
2750
+ return b.available();
2751
+ }
2752
+ /**
2753
+ * Compile a shader source with Sandbox's shader preprocessor and return the final GLSL code.
2754
+ * This is useful for debugging shader code or precompiling shaders for production use.
2755
+ */
2756
+ static compile(e) {
2757
+ return new d(e).compile();
2758
+ }
2759
+ resolveOptions(e) {
2760
+ const n = {
2761
+ vertex: new d(S),
2762
+ fragment: new d(L),
916
2763
  autoplay: !0,
917
2764
  pauseWhenHidden: !0,
918
2765
  dpr: "auto",
919
2766
  fps: 0,
920
2767
  preserveDrawingBuffer: !1,
921
2768
  antialias: !0,
922
- onError: (i) => {
2769
+ onError: (s) => {
923
2770
  console.error(
924
2771
  "Oops!",
925
- i,
2772
+ s,
926
2773
  `
927
2774
  You can handle errors programmatically by providing an onError callback to suppress this log and implement custom fallback behavior.`
928
2775
  );
@@ -931,64 +2778,69 @@ You can handle errors programmatically by providing an onError callback to suppr
931
2778
  },
932
2779
  onBeforeRender: null,
933
2780
  onAfterRender: null,
934
- uniforms: {}
2781
+ uniforms: {},
2782
+ modules: {}
935
2783
  };
936
- if (t != null && t.vertex && (this.usingCustomVertex = !0), t != null && t.vertex && !(t != null && t.fragment)) {
937
- const i = a.detectVersion(t.vertex);
938
- e.vertex = t.vertex, e.fragment = i === 2 ? V : A;
2784
+ if (e != null && e.vertex && (this.usingCustomVertex = !0), e != null && e.vertex && !(e != null && e.fragment)) {
2785
+ n.vertex = new d(e.vertex);
2786
+ const s = n.vertex.version();
2787
+ n.fragment = new d(s === 2 ? he : L);
939
2788
  }
940
- if (t != null && t.fragment && !(t != null && t.vertex)) {
941
- const i = a.detectVersion(t.fragment);
942
- e.fragment = t.fragment, e.vertex = i === 2 ? E : g;
2789
+ if (e != null && e.fragment && !(e != null && e.vertex)) {
2790
+ n.fragment = new d(e.fragment);
2791
+ const s = n.fragment.version();
2792
+ n.vertex = new d(s === 2 ? U : S);
943
2793
  }
944
- return { ...e, ...t };
2794
+ e != null && e.vertex && (e != null && e.fragment) && (n.vertex = new d(e.vertex), n.fragment = new d(e.fragment));
2795
+ const { vertex: t, fragment: i, ...r } = e || {};
2796
+ return { ...n, ...r };
945
2797
  }
946
2798
  setupListeners() {
947
2799
  this.listeners.push(
948
2800
  // Window resize
949
- l.on(window, "resize", () => {
2801
+ x.on(window, "resize", () => {
950
2802
  this.setViewport();
951
2803
  }),
952
2804
  // Canvas resize
953
- l.on(this.canvasEl, "resize", () => {
2805
+ x.on(this.canvasEl, "resize", () => {
954
2806
  this.setViewport();
955
2807
  }),
956
2808
  // Visibility check on scroll
957
2809
  (() => {
958
- let t = !1;
959
- return l.on(document, "scroll", (e) => {
960
- this.options.pauseWhenHidden && (this.isInViewport() ? t && !this.isPlaying() && (this.play(), t = !1) : this.isPlaying() && (this.pause(), t = !0));
2810
+ let e = !1;
2811
+ return x.on(document, "scroll", (n) => {
2812
+ this.options.pauseWhenHidden && (this.isInViewport() ? e && !this.isPlaying() && (this.play(), e = !1) : this.isPlaying() && (this.pause(), e = !0));
961
2813
  });
962
2814
  })(),
963
2815
  // Mouse tracking
964
- l.on(document, "mousemove", (t) => {
965
- this.setMouse(t.clientX || t.pageX, t.clientY || t.pageY);
2816
+ x.on(document, "mousemove", (e) => {
2817
+ this.setMouse(e.clientX || e.pageX, e.clientY || e.pageY);
966
2818
  }),
967
2819
  // Touch tracking
968
- l.on(document, "touchmove", (t) => {
969
- t.touches.length > 0 && this.setMouse(t.touches[0].clientX, t.touches[0].clientY);
2820
+ x.on(document, "touchmove", (e) => {
2821
+ e.touches.length > 0 && this.setMouse(e.touches[0].clientX, e.touches[0].clientY);
970
2822
  })
971
2823
  );
972
2824
  }
973
2825
  destroyListeners() {
974
- this.listeners.forEach((t) => t()), this.listeners = [];
2826
+ this.listeners.forEach((e) => e()), this.listeners = [];
975
2827
  }
976
2828
  setViewport() {
977
- const t = this.options.dpr === "auto" ? Math.min(2, window.devicePixelRatio || 1) : this.options.dpr, e = this.canvasEl.clientWidth || this.canvasEl.width || 1, i = this.canvasEl.clientHeight || this.canvasEl.height || 1;
2829
+ 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;
978
2830
  this.engine.viewport(
979
2831
  0,
980
2832
  0,
981
- Math.max(1, Math.floor(e * t)),
982
- Math.max(1, Math.floor(i * t))
2833
+ Math.max(1, Math.floor(n * e)),
2834
+ Math.max(1, Math.floor(t * e))
983
2835
  );
984
2836
  }
985
2837
  isInViewport() {
986
- const t = this.canvasEl.getBoundingClientRect();
987
- return t.bottom >= 0 && t.right >= 0 && t.top <= (window.innerHeight || document.documentElement.clientHeight) && t.left <= (window.innerWidth || document.documentElement.clientWidth);
2838
+ const e = this.canvasEl.getBoundingClientRect();
2839
+ return e.bottom >= 0 && e.right >= 0 && e.top <= (window.innerHeight || document.documentElement.clientHeight) && e.left <= (window.innerWidth || document.documentElement.clientWidth);
988
2840
  }
989
- setMouse(t, e) {
990
- const i = this.canvasEl.getBoundingClientRect();
991
- t >= i.left && t <= i.right && e >= i.top && e <= i.bottom && this.engine.mouse(t - i.left, e - i.top);
2841
+ setMouse(e, n) {
2842
+ const t = this.canvasEl.getBoundingClientRect();
2843
+ e >= t.left && e <= t.right && n >= t.top && n <= t.bottom && this.engine.mouse(e - t.left, n - t.top);
992
2844
  }
993
2845
  /**
994
2846
  * Set a single uniform value with type checking.
@@ -997,8 +2849,8 @@ You can handle errors programmatically by providing an onError callback to suppr
997
2849
  * sandbox.setUniform<number>("u_time", 1.5);
998
2850
  * sandbox.setUniform<Vec3[]>("u_colors", [[1, 0, 0], [0, 1, 0]]);
999
2851
  */
1000
- setUniform(t, e) {
1001
- return this.engine.uniform(t, e), this;
2852
+ setUniform(e, n) {
2853
+ return this.engine.uniform(e, n), this;
1002
2854
  }
1003
2855
  /**
1004
2856
  * Set multiple uniforms at once with type checking.
@@ -1014,47 +2866,84 @@ You can handle errors programmatically by providing an onError callback to suppr
1014
2866
  * u_colors: [[1, 0, 0], [0, 1, 0]],
1015
2867
  * });
1016
2868
  */
1017
- setUniforms(t) {
1018
- return this.engine.uniforms(t), this;
2869
+ setUniforms(e) {
2870
+ return this.engine.uniforms(e), this;
1019
2871
  }
1020
2872
  /**
1021
2873
  * Get current uniform value.
1022
2874
  */
1023
- getUniform(t) {
1024
- return this.engine.getUniform(t);
2875
+ getUniform(e) {
2876
+ return this.engine.getUniform(e);
1025
2877
  }
1026
2878
  /**
1027
2879
  * Update shaders.
1028
2880
  * @example
1029
2881
  * sandbox.setShader(vertexSource, fragmentSource);
1030
2882
  */
1031
- setShader(t, e) {
1032
- return this.options.vertex = t, this.options.fragment = e, this.usingCustomVertex = !0, this.engine.shader(this.options.vertex, this.options.fragment), this;
2883
+ setShader(e, n) {
2884
+ return this.options.vertex = new d(e), this.options.fragment = new d(n), this.usingCustomVertex = !0, this.engine.shader(this.options.vertex, this.options.fragment), this;
1033
2885
  }
1034
2886
  /**
1035
2887
  * Update only fragment shader (uses default vertex).
1036
2888
  * @example
1037
2889
  * sandbox.setFragment(fragmentSource);
1038
2890
  */
1039
- setFragment(t) {
1040
- const e = a.detectVersion(t), i = a.detectVersion(this.options.vertex);
1041
- return this.options.fragment = t, e !== i && (this.usingCustomVertex || (this.options.vertex = e === 2 ? E : g)), this.engine.shader(this.options.vertex, this.options.fragment), this;
2891
+ setFragment(e) {
2892
+ const n = new d(e), t = n.version(), i = this.options.vertex.version();
2893
+ return this.options.fragment = n, t !== i && (this.usingCustomVertex || (this.options.vertex = new d(
2894
+ t === 2 ? U : S
2895
+ ))), this.engine.shader(this.options.vertex, this.options.fragment), this;
2896
+ }
2897
+ /**
2898
+ * Get current fragment shader source.
2899
+ */
2900
+ getFragment() {
2901
+ return this.options.fragment.source();
2902
+ }
2903
+ /**
2904
+ * Get current vertex shader source.
2905
+ */
2906
+ getVertex() {
2907
+ return this.options.vertex.source();
1042
2908
  }
1043
2909
  /**
1044
2910
  * Set the max frame rate runtime
1045
- *
2911
+ *
1046
2912
  * @example
1047
2913
  * sandbox.setFps(30); // Limit to 30 FPS
1048
2914
  * sandbox.setFps(0); // Unlimited FPS
1049
2915
  */
1050
- setFps(t) {
1051
- return this.engine.getClock().setMaxFps(t), this;
2916
+ setFps(e) {
2917
+ return this.engine.getClock().setMaxFps(e), this;
1052
2918
  }
1053
2919
  /**
1054
2920
  * Add a runtime render hook.
1055
2921
  */
1056
- hook(t, e = "before") {
1057
- return e === "before" ? this.engine.onBeforeHooks.add(t) : this.engine.onAfterHooks.add(t);
2922
+ hook(e, n = "before") {
2923
+ return n === "before" ? this.engine.onBeforeHooks.add(e) : this.engine.onAfterHooks.add(e);
2924
+ }
2925
+ /**
2926
+ * Runtime configure the module behavior
2927
+ * @example
2928
+ * sandbox.module("my_module", { intensity: 0.5 });
2929
+ */
2930
+ module(e, n) {
2931
+ const t = y.resolveOptions(e);
2932
+ if (!t)
2933
+ return console.warn(
2934
+ `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.`
2935
+ ), this;
2936
+ for (const [i, r] of Object.entries(n)) {
2937
+ const s = t[i];
2938
+ if (!s) {
2939
+ console.warn(
2940
+ `Sandbox: Option '${i}' not found for function '${e}'. Make sure to check available options with Sandbox.availableModules() and provide the correct option name.`
2941
+ );
2942
+ continue;
2943
+ }
2944
+ this.setUniform(s.uniform, r);
2945
+ }
2946
+ return this;
1058
2947
  }
1059
2948
  /**
1060
2949
  * Start animation loop.
@@ -1065,8 +2954,8 @@ You can handle errors programmatically by providing an onError callback to suppr
1065
2954
  /**
1066
2955
  * Start animation loop at specific time (in seconds).
1067
2956
  */
1068
- playAt(t) {
1069
- return this.engine.clock(t), this.engine.play(), this;
2957
+ playAt(e) {
2958
+ return this.engine.clock(e), this.engine.play(), this;
1070
2959
  }
1071
2960
  /**
1072
2961
  * Stop animation loop.
@@ -1077,9 +2966,9 @@ You can handle errors programmatically by providing an onError callback to suppr
1077
2966
  /**
1078
2967
  * Pause animation loop at specific time (in seconds).
1079
2968
  */
1080
- pauseAt(t) {
1081
- const e = this.hook((i) => {
1082
- i.time >= t && (e(), this.pause());
2969
+ pauseAt(e) {
2970
+ const n = this.hook((t) => {
2971
+ t.time >= e && (n(), this.pause());
1083
2972
  }, "after");
1084
2973
  return this;
1085
2974
  }
@@ -1092,8 +2981,8 @@ You can handle errors programmatically by providing an onError callback to suppr
1092
2981
  /**
1093
2982
  * Set current time (in seconds).
1094
2983
  */
1095
- time(t) {
1096
- return this.engine.clock(t), this;
2984
+ time(e) {
2985
+ return this.engine.clock(e), this;
1097
2986
  }
1098
2987
  /**
1099
2988
  * Render a single frame (for static rendering).
@@ -1108,8 +2997,8 @@ You can handle errors programmatically by providing an onError callback to suppr
1108
2997
  * @example
1109
2998
  * sandbox.renderAt(2.5); // Render as if 2.5 seconds elapsed
1110
2999
  */
1111
- renderAt(t) {
1112
- return this.engine.clock(t), this.engine.render(), this;
3000
+ renderAt(e) {
3001
+ return this.engine.clock(e), this.engine.render(), this;
1113
3002
  }
1114
3003
  /**
1115
3004
  * Check if currently playing.
@@ -1141,10 +3030,26 @@ You can handle errors programmatically by providing an onError callback to suppr
1141
3030
  }
1142
3031
  }
1143
3032
  export {
1144
- y as Sandbox,
1145
- w as SandboxContextError,
1146
- u as SandboxError,
1147
- m as SandboxProgramError,
1148
- c as SandboxShaderCompilationError,
1149
- k as SandboxShaderVersionMismatchError
3033
+ $ as Sandbox,
3034
+ X as SandboxAttemptedToImportDefaultFunctionError,
3035
+ K as SandboxAttemptedToImportMainFunctionError,
3036
+ de as SandboxContextCreationError,
3037
+ h as SandboxError,
3038
+ Q as SandboxForbiddenModuleNameError,
3039
+ _ as SandboxGLSLShaderCompilationError,
3040
+ ne as SandboxMentionCouldNotBeReplacedError,
3041
+ ee as SandboxMentionFunctionNotFoundError,
3042
+ Z as SandboxMentionUniformNotFoundError,
3043
+ Y as SandboxModuleMethodNotFoundError,
3044
+ j as SandboxModuleNotFoundError,
3045
+ ie as SandboxOnHookCallbackError,
3046
+ te as SandboxOnLoadCallbackError,
3047
+ J as SandboxOverwriteModuleError,
3048
+ R as SandboxProgramError,
3049
+ H as SandboxShaderDuplicateImportNameError,
3050
+ q as SandboxShaderImportSyntaxError,
3051
+ C as SandboxShaderRequirementMismatchError,
3052
+ G as SandboxShaderVersionMismatchError,
3053
+ W as SandboxShaderWithoutFunctionError,
3054
+ z as SandboxWebGLNotSupportedError
1150
3055
  };