shaderpad 1.0.0-beta.37 → 1.0.0-beta.39

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -15,7 +15,6 @@ npm install shaderpad
15
15
  ```typescript
16
16
  import ShaderPad from 'shaderpad';
17
17
 
18
- // Your custom GLSL fragment shader code.
19
18
  const fragmentShaderSrc = `#version 300 es
20
19
  precision highp float;
21
20
 
@@ -35,40 +34,21 @@ void main() {
35
34
  vec2 dotGrid = mod(uv, 50.) - 25.;
36
35
  float dotDist = length(dotGrid);
37
36
  float dot = step(dotDist, 5.);
38
-
39
37
  float cursorDist = distance(uv, u_cursor * u_resolution);
40
38
  float cursor = step(cursorDist, 25. + sin(u_time * 5.) * 5.);
41
-
42
39
  vec3 color = mix(vec3(0., 0., 1.), vec3(1.), dot);
43
40
  color = mix(color, u_cursorColor, cursor);
44
-
45
41
  outColor = vec4(color, 1.);
46
42
  }
47
43
  `;
48
44
 
49
- // Initialize the shader.
50
45
  const shader = new ShaderPad(fragmentShaderSrc /* , options */);
51
-
52
- // Add your own custom uniforms.
53
46
  const getColor = (time: number) =>
54
47
  [time, time + (Math.PI * 2) / 3, time + (Math.PI * 4) / 3].map(x => 1 + Math.sin(x) / 2);
55
48
  shader.initializeUniform('u_cursorColor', 'float', getColor(0));
56
-
57
- // Start the render loop.
58
49
  shader.play(time => {
59
50
  shader.updateUniforms({ u_cursorColor: getColor(time) });
60
51
  });
61
-
62
- // Optionally pause or reset the render loop.
63
- // shader.pause();
64
- // shader.reset();
65
-
66
- // ShaderPad also attaches a throttled resize observer that you can hook into.
67
- // It fires when the canvas size changes visually. If you supplied a custom
68
- // canvas, you may use this to update its `width` and `height` attributes.
69
- // shader.onResize = (width, height) => {
70
- // console.log('Canvas resized:', width, height);
71
- // };
72
52
  ```
73
53
 
74
54
  See the [`examples/` directory](./examples/) for more.
@@ -79,26 +59,26 @@ See the [`examples/` directory](./examples/) for more.
79
59
 
80
60
  #### `initializeUniform(name, type, value, options?)`
81
61
 
82
- Initialize a uniform variable. The uniform must be declared in your fragment shader.
62
+ Initialize a uniform, which must be declared in your shader.
83
63
 
84
64
  ```typescript
85
- // Initialize a float uniform.
86
65
  shader.initializeUniform('u_speed', 'float', 1.5);
87
-
88
- // Initialize a vec3 uniform.
66
+ // Vectors are passed as arrays. This is a vec3:
89
67
  shader.initializeUniform('u_color', 'float', [1.0, 0.5, 0.0]);
68
+ // …but you can also pass an array. This is an array of floats:
69
+ shader.initializeUniform('u_data', 'float', [1.0, 0.5, 0.0], { arrayLength: 3 });
90
70
  ```
91
71
 
92
72
  **Parameters:**
93
73
 
94
- - `name` (string): The name of the uniform as declared in your shader
95
- - `type` ('float' | 'int'): The uniform type
74
+ - `name` (string): Uniform name
75
+ - `type` ('float' | 'int'): Uniform type
96
76
  - `value` (number | number[] | (number | number[])[]): Initial value(s)
97
- - `options` (optional): `{ arrayLength?: number }` - Required for uniform arrays
77
+ - `options` (optional): `{ arrayLength?: number }` - Required for arrays
98
78
 
99
79
  #### `updateUniforms(updates, options?)`
100
80
 
101
- Update one or more uniform values.
81
+ Update uniform values.
102
82
 
103
83
  ```typescript
104
84
  shader.updateUniforms({
@@ -109,7 +89,7 @@ shader.updateUniforms({
109
89
 
110
90
  **Parameters:**
111
91
 
112
- - `updates` (Record<string, number | number[] | (number | number[])[]>): Object mapping uniform names to their new values
92
+ - `updates`: Object mapping uniform names to their new values
113
93
  - `options` (optional): `{ startIndex?: number }` - Starting index for partial array updates
114
94
 
115
95
  #### Uniform arrays
@@ -125,12 +105,8 @@ shader.initializeUniform(
125
105
  [0, 0],
126
106
  [1, 1],
127
107
  [2, 2],
128
- [3, 3],
129
- [4, 4],
130
108
  ],
131
- {
132
- arrayLength: 5,
133
- }
109
+ { arrayLength: 3 }
134
110
  );
135
111
 
136
112
  // Update all elements.
@@ -139,8 +115,6 @@ shader.updateUniforms({
139
115
  [0.1, 0.2],
140
116
  [1.1, 1.2],
141
117
  [2.1, 2.2],
142
- [3.1, 3.2],
143
- [4.1, 4.2],
144
118
  ],
145
119
  });
146
120
 
@@ -178,25 +152,13 @@ shader.updateUniforms(
178
152
 
179
153
  #### `initializeTexture(name, source, options?)`
180
154
 
181
- Initialize a texture from an image, video, canvas element, or typed array.
155
+ Initialize a texture from an image, video, canvas, or typed array.
182
156
 
183
157
  ```typescript
184
- // Initialize a texture from an image.
185
- const img = new Image();
186
- img.src = 'texture.png';
187
- img.onload = () => {
188
- shader.initializeTexture('u_texture', img);
189
- };
190
-
191
- // Initialize a texture from a typed array (Float32Array, Uint8Array, etc.).
192
- const data = new Float32Array(width * height * 4); // RGBA data
158
+ shader.initializeTexture('u_texture', img);
193
159
  shader.initializeTexture(
194
160
  'u_custom',
195
- {
196
- data,
197
- width,
198
- height,
199
- },
161
+ { data: new Float32Array(width * height * 4), width, height },
200
162
  {
201
163
  internalFormat: gl.RGBA32F,
202
164
  type: gl.FLOAT,
@@ -204,27 +166,23 @@ shader.initializeTexture(
204
166
  magFilter: gl.NEAREST,
205
167
  }
206
168
  );
207
-
208
- // Initialize a texture with history (stores previous frames).
209
169
  shader.initializeTexture('u_webcam', videoElement, { history: 30 });
210
-
211
- // Preserve Y orientation for DOM sources (don't flip vertically).
212
170
  shader.initializeTexture('u_canvas', canvasElement, { preserveY: true });
213
171
  ```
214
172
 
215
173
  **Parameters:**
216
174
 
217
175
  - `name` (string): The name of the texture uniform as declared in your shader
218
- - `source` (HTMLImageElement | HTMLVideoElement | HTMLCanvasElement | CustomTexture): The texture source
219
176
  - `options` (optional): Texture options (see below)
177
+ - `source`: Image, video, canvas, or `{ data, width, height }`
220
178
 
221
179
  **Texture Options:**
222
180
 
223
181
  - `history?: number` - Number of previous frames to store (creates a `sampler2DArray`)
224
182
  - `preserveY?: boolean` - For DOM sources only: if `true`, don't flip vertically (default: `false`, flips to match WebGL's bottom-up convention)
225
- - `internalFormat?: number` - WebGL internal format (e.g., `gl.RGBA8`, `gl.RGBA32F`)
226
- - `format?: number` - WebGL format (default: `gl.RGBA`)
227
- - `type?: number` - WebGL data type (default: `gl.UNSIGNED_BYTE` for DOM sources, must be specified for typed arrays)
183
+ - `internalFormat?: number` - Storage format in GPU memory (e.g., `gl.RGBA8`, `gl.RGBA32F`). Defaults to `gl.RGBA8` for 8-bit, or `gl.RGBA32F` if `type` is `gl.FLOAT`
184
+ - `format?: number` - Source data layout (default: `gl.RGBA`). Describes the channels in your input data (e.g., `gl.RGBA`, `gl.RGB`, `gl.R8UI`)
185
+ - `type?: number` - Source data type (default: `gl.UNSIGNED_BYTE` for DOM sources, must be specified for typed arrays). Examples: `gl.UNSIGNED_BYTE`, `gl.FLOAT`
228
186
  - `minFilter?: number` - Minification filter (default: `gl.LINEAR`)
229
187
  - `magFilter?: number` - Magnification filter (default: `gl.LINEAR`)
230
188
  - `wrapS?: number` - Wrap mode for S coordinate (default: `gl.CLAMP_TO_EDGE`)
@@ -232,52 +190,85 @@ shader.initializeTexture('u_canvas', canvasElement, { preserveY: true });
232
190
 
233
191
  **Note:** For typed array sources (`CustomTexture`), you must provide data in bottom-up orientation (WebGL convention). The `preserveY` option is ignored for typed arrays.
234
192
 
235
- #### `updateTextures(updates)`
236
-
237
- Update one or more textures. Useful for updating video textures each frame.
193
+ #### `updateTextures(updates, options?)`
238
194
 
239
195
  ```typescript
196
+ shader.updateTextures({ u_webcam: videoElement, u_overlay: overlayCanvas });
240
197
  shader.updateTextures({
241
- u_webcam: videoElement,
242
- u_overlay: overlayCanvas,
243
- u_custom: {
244
- data: typedArray,
245
- width,
246
- height,
247
- },
248
- });
249
-
250
- // Typed arrays can be partially updated.
251
- shader.updateTextures({
252
- u_custom: {
253
- data: partialData,
254
- width: regionWidth,
255
- height: regionHeight,
256
- isPartial: true,
257
- x: offsetX,
258
- y: offsetY,
259
- },
198
+ u_custom: { data: partialData, width, height, isPartial: true, x: offsetX, y: offsetY },
260
199
  });
200
+ shader.updateTextures({ u_camera: videoElement }, { skipHistoryWrite: true });
261
201
  ```
262
202
 
263
203
  **Parameters:**
264
204
 
265
- - `updates` (Record<string, TextureSource | PartialCustomTexture>): Object mapping texture names to their new sources
205
+ - `updates`: Object mapping texture names to updated sources
206
+ - `options?` (optional): `{ skipHistoryWrite?: boolean }`
266
207
 
267
208
  ### Lifecycle methods
268
209
 
269
- #### `play(callback?)`
210
+ #### `play(onStepComplete?, setStepOptions?)`
270
211
 
271
- Start the render loop. The callback is invoked each frame with the current time and frame number.
212
+ Start the render loop.
272
213
 
273
214
  ```typescript
274
215
  shader.play();
275
- // Can optionally take a callback to invoke each frame.
216
+
217
+ // With per-frame callbacks.
276
218
  shader.play((time, frame) => {
277
219
  shader.updateTextures({ u_webcam: videoElement });
278
220
  });
221
+
222
+ shader.play(null, (time, frame) => {
223
+ // Only save every 10th frame to history.
224
+ return { skipHistoryWrite: frame % 10 === 0 };
225
+ });
226
+ ```
227
+
228
+ **Parameters:**
229
+
230
+ - `onStepComplete?`: `(time: number, frame: number) => void` - Called after each frame
231
+ - `setStepOptions?`: `(time: number, frame: number) => StepOptions | void` - Called before each frame
232
+
233
+ #### `step(time, options?)`
234
+
235
+ Manually advance one frame. Updates `u_time` and `u_frame`, then renders.
236
+
237
+ ```typescript
238
+ shader.step(5.0); // Render at 5 seconds.
279
239
  ```
280
240
 
241
+ **Parameters:**
242
+
243
+ - `time` (number): The current time in seconds
244
+ - `options?` (optional): `StepOptions` - Options to control rendering behavior (see below)
245
+
246
+ #### `draw(options?)`
247
+
248
+ Render without updating uniforms or frame counter.
249
+
250
+ ```typescript
251
+ shader.draw({ skipClear: true });
252
+ ```
253
+
254
+ **Parameters:**
255
+
256
+ - `options?` (optional): `StepOptions` - Options to control rendering behavior (see below)
257
+
258
+ #### `StepOptions`
259
+
260
+ ```typescript
261
+ interface StepOptions {
262
+ skipClear?: boolean; // Skip clearing canvas before rendering
263
+ skipHistoryWrite?: boolean; // Skip writing to history buffers
264
+ }
265
+ ```
266
+
267
+ **Options:**
268
+
269
+ - `skipClear?: boolean` - If `true`, the canvas is not cleared before rendering. Useful for accumulating effects or multi-pass rendering.
270
+ - `skipHistoryWrite?: boolean` - If `true`, history buffers are not updated. Useful when you want to render without affecting the history state.
271
+
281
272
  #### `pause()`, `reset()`, `destroy()`
282
273
 
283
274
  ```typescript
@@ -310,7 +301,7 @@ shader.onResize = (width, height) => {
310
301
 
311
302
  ### history
312
303
 
313
- The `history` option enables framebuffer history, allowing you to access previous frames in your shader. Pass a number to specify how many frames to keep.
304
+ Enable framebuffer history to access previous frames.
314
305
 
315
306
  ```typescript
316
307
  // Store the last 10 frames of shader output.
@@ -322,6 +313,17 @@ const shader = new ShaderPad(fragmentShaderSrc, { history: 10 });
322
313
  // uniform int u_historyFrameOffset;
323
314
  ```
324
315
 
316
+ **High-precision history:** By default, history textures use 8-bit precision (RGBA8). For high-precision rendering, specify `internalFormat` and `type` options. This enables FBO rendering and preserves precision in history textures.
317
+
318
+ ```typescript
319
+ // For 32-bit float precision (requires EXT_color_buffer_float extension):
320
+ const shader = new ShaderPad(fragmentShaderSrc, {
321
+ history: 60,
322
+ internalFormat: gl.RGBA32F,
323
+ type: gl.FLOAT,
324
+ });
325
+ ```
326
+
325
327
  You can also enable history for individual textures:
326
328
 
327
329
  ```typescript
@@ -342,10 +344,10 @@ vec4 historyColor = texture(u_webcam, vec3(v_uv, zIndex));
342
344
 
343
345
  ### debug
344
346
 
345
- The `debug` option controls whether debug logging is enabled. When enabled, ShaderPad will log warnings when uniforms or textures are not found in the shader. Defaults to `true` in development (when `process.env.NODE_ENV !== 'production'`) and `false` in production builds.
347
+ Enable debug logging. Defaults to `true` in development, `false` in production.
346
348
 
347
349
  ```typescript
348
- const shader = new ShaderPad(fragmentShaderSrc, { debug: true }); // Explicitly enable debug logging.
350
+ const shader = new ShaderPad(fragmentShaderSrc, { debug: true });
349
351
  ```
350
352
 
351
353
  ### plugins
@@ -397,6 +399,11 @@ const shader = new ShaderPad(fragmentShaderSrc, {
397
399
  });
398
400
  ```
399
401
 
402
+ **Options:**
403
+
404
+ - `onReady?: () => void` - Callback invoked when initialization is complete and the detection model is loaded
405
+ - `onResults?: (results: FaceLandmarkerResult) => void` - Callback invoked with detection results each frame
406
+
400
407
  **Uniforms:**
401
408
 
402
409
  | Uniform | Type | Description |
@@ -478,6 +485,11 @@ const shader = new ShaderPad(fragmentShaderSrc, {
478
485
  });
479
486
  ```
480
487
 
488
+ **Options:**
489
+
490
+ - `onReady?: () => void` - Callback invoked when initialization is complete and the detection model is loaded
491
+ - `onResults?: (results: PoseLandmarkerResult) => void` - Callback invoked with detection results each frame
492
+
481
493
  **Uniforms:**
482
494
 
483
495
  | Uniform | Type | Description |
@@ -567,6 +579,11 @@ const shader = new ShaderPad(fragmentShaderSrc, {
567
579
  });
568
580
  ```
569
581
 
582
+ **Options:**
583
+
584
+ - `onReady?: () => void` - Callback invoked when initialization is complete and the detection model is loaded
585
+ - `onResults?: (results: HandLandmarkerResult) => void` - Callback invoked with detection results each frame
586
+
570
587
  **Uniforms:**
571
588
 
572
589
  | Uniform | Type | Description |
@@ -638,12 +655,20 @@ const shader = new ShaderPad(fragmentShaderSrc, {
638
655
  modelPath:
639
656
  'https://storage.googleapis.com/mediapipe-models/image_segmenter/selfie_multiclass_256x256/float32/latest/selfie_multiclass_256x256.tflite',
640
657
  outputCategoryMask: true,
658
+ onReady: () => {
659
+ console.log('Selfie multiclass model: loading complete');
660
+ },
641
661
  },
642
662
  }),
643
663
  ],
644
664
  });
645
665
  ```
646
666
 
667
+ **Options:**
668
+
669
+ - `onReady?: () => void` - Callback invoked when initialization is complete and the detection model is loaded
670
+ - `onResults?: (results: ImageSegmenterResult) => void` - Callback invoked with segmentation results each frame
671
+
647
672
  **Uniforms:**
648
673
 
649
674
  | Uniform | Type | Description |
@@ -0,0 +1,11 @@
1
+ var x=`#version 300 es
2
+ in vec2 aPosition;
3
+ out vec2 v_uv;
4
+ void main() {
5
+ v_uv = aPosition * 0.5 + 0.5;
6
+ gl_Position = vec4(aPosition, 0.0, 1.0);
7
+ }
8
+ `,b=33.333333333333336,m=Symbol("u_history"),d=Symbol("__SHADERPAD_BUFFER");function v(l,e){if(!e?.length)return l;let t=l.split(`
9
+ `),s=t.findLastIndex(i=>{let r=i.trimStart();return r.startsWith("precision ")||r.startsWith("#version ")})+1;return t.splice(s,0,...e),t.join(`
10
+ `)}function T(l){return l instanceof WebGLTexture?{width:0,height:0}:l instanceof HTMLVideoElement?{width:l.videoWidth,height:l.videoHeight}:l instanceof HTMLImageElement?{width:l.naturalWidth??l.width,height:l.naturalHeight??l.height}:{width:l.width,height:l.height}}function f(l){return typeof l=="symbol"?l.description??"":l}var p=class{isInternalCanvas=!1;isTouchDevice=!1;gl;fragmentShaderSrc;uniforms=new Map;textures=new Map;textureUnitPool;buffer=null;program=null;aPositionLocation=0;animationFrameId;resolutionObserver;resizeObserver;resizeTimeout=null;lastResizeTime=-1/0;eventListeners=new Map;frame=0;startTime=0;cursorPosition=[.5,.5];clickPosition=[.5,.5];isMouseDown=!1;canvas;onResize;hooks=new Map;historyDepth=0;textureOptions;debug;intermediateFbo=null;constructor(e,{canvas:t,plugins:s,history:i,debug:r,...n}={}){if(this.canvas=t||document.createElement("canvas"),!t){this.isInternalCanvas=!0;let c=this.canvas;c.style.position="fixed",c.style.inset="0",c.style.height="100dvh",c.style.width="100dvw",document.body.appendChild(c)}if(this.gl=this.canvas.getContext("webgl2",{antialias:!1}),!this.gl)throw new Error("WebGL2 not supported. Please use a browser that supports WebGL2.");this.textureUnitPool={free:[],next:0,max:this.gl.getParameter(this.gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS)},this.textureOptions=n;let{internalFormat:o,type:u}=n;(u===this.gl.FLOAT||u===this.gl.HALF_FLOAT||o===this.gl.RGBA16F||o===this.gl.RGBA32F||o===this.gl.R16F||o===this.gl.R32F||o===this.gl.RG16F||o===this.gl.RG32F)&&!this.gl.getExtension("EXT_color_buffer_float")&&(console.warn("EXT_color_buffer_float not supported, falling back to RGBA8"),delete this.textureOptions?.internalFormat,delete this.textureOptions?.format,delete this.textureOptions?.type),i&&(this.historyDepth=i),this.debug=r??(typeof process<"u"&&!1),this.animationFrameId=null,this.resolutionObserver=new MutationObserver(()=>this.updateResolution()),this.resizeObserver=new ResizeObserver(()=>this.throttledHandleResize());let a=[];if(s){let c={gl:this.gl,uniforms:this.uniforms,textures:this.textures,canvas:this.canvas,reserveTextureUnit:this.reserveTextureUnit.bind(this),releaseTextureUnit:this.releaseTextureUnit.bind(this),injectGLSL:g=>{a.push(g)}};Object.defineProperty(c,"program",{get:()=>this.program,enumerable:!0,configurable:!0}),s.forEach(g=>g(this,c))}this.fragmentShaderSrc=v(e,a),this.init(),this.canvas instanceof HTMLCanvasElement&&this.addEventListeners()}registerHook(e,t){this.hooks.has(e)||this.hooks.set(e,[]),this.hooks.get(e).push(t)}init(){let e=x;if(this.program=this.gl.createProgram(),!this.program)throw new Error("Failed to create WebGL program");let t=this.createShader(this.gl.VERTEX_SHADER,e),s=this.createShader(this.gl.FRAGMENT_SHADER,this.fragmentShaderSrc);if(this.gl.attachShader(this.program,t),this.gl.attachShader(this.program,s),this.gl.linkProgram(this.program),this.gl.deleteShader(t),this.gl.deleteShader(s),!this.gl.getProgramParameter(this.program,this.gl.LINK_STATUS))throw console.error("Program link error:",this.gl.getProgramInfoLog(this.program)),this.gl.deleteProgram(this.program),new Error("Failed to link WebGL program");this.aPositionLocation=this.gl.getAttribLocation(this.program,"aPosition"),this.setupBuffer(),this.gl.useProgram(this.program),this.canvas instanceof HTMLCanvasElement&&(this.resolutionObserver.observe(this.canvas,{attributes:!0,attributeFilter:["width","height"]}),this.resizeObserver.observe(this.canvas)),this.isInternalCanvas||this.updateResolution(),this.initializeUniform("u_cursor","float",this.cursorPosition),this.initializeUniform("u_click","float",[...this.clickPosition,this.isMouseDown?1:0]),this.initializeUniform("u_time","float",0),this.initializeUniform("u_frame","int",0),this.historyDepth>0&&(this._initializeTexture(d,this.canvas,{...this.textureOptions}),this._initializeTexture(m,this.canvas,{history:this.historyDepth,...this.textureOptions}),this.intermediateFbo=this.gl.createFramebuffer()),this.hooks.get("init")?.forEach(i=>i.call(this))}createShader(e,t){let s=this.gl.createShader(e);if(this.gl.shaderSource(s,t),this.gl.compileShader(s),!this.gl.getShaderParameter(s,this.gl.COMPILE_STATUS))throw console.error("Shader compilation failed:",t),console.error(this.gl.getShaderInfoLog(s)),this.gl.deleteShader(s),new Error("Shader compilation failed");return s}setupBuffer(){let e=new Float32Array([-1,-1,1,-1,-1,1,-1,1,1,-1,1,1]);this.buffer=this.gl.createBuffer(),this.gl.bindBuffer(this.gl.ARRAY_BUFFER,this.buffer),this.gl.bufferData(this.gl.ARRAY_BUFFER,e,this.gl.STATIC_DRAW),this.gl.viewport(0,0,this.gl.drawingBufferWidth,this.gl.drawingBufferHeight),this.gl.enableVertexAttribArray(this.aPositionLocation),this.gl.vertexAttribPointer(this.aPositionLocation,2,this.gl.FLOAT,!1,0,0)}throttledHandleResize(){clearTimeout(this.resizeTimeout);let e=performance.now(),t=this.lastResizeTime+b-e;t<=0?(this.lastResizeTime=e,this.handleResize()):this.resizeTimeout=setTimeout(()=>this.throttledHandleResize(),t)}handleResize(){if(!(this.canvas instanceof HTMLCanvasElement))return;let e=window.devicePixelRatio||1,t=this.canvas.clientWidth*e,s=this.canvas.clientHeight*e;this.isInternalCanvas&&(this.canvas.width!==t||this.canvas.height!==s)&&(this.canvas.width=t,this.canvas.height=s),this.onResize?.(t,s)}addEventListeners(){let e=this.canvas,t=(i,r)=>{if(!this.uniforms.has("u_cursor"))return;let n=e.getBoundingClientRect();this.cursorPosition[0]=(i-n.left)/n.width,this.cursorPosition[1]=1-(r-n.top)/n.height,this.updateUniforms({u_cursor:this.cursorPosition})},s=(i,r,n)=>{if(this.uniforms.has("u_click")){if(this.isMouseDown=i,i){let o=e.getBoundingClientRect(),u=r,h=n;this.clickPosition[0]=(u-o.left)/o.width,this.clickPosition[1]=1-(h-o.top)/o.height}this.updateUniforms({u_click:[...this.clickPosition,this.isMouseDown?1:0]})}};this.eventListeners.set("mousemove",i=>{let r=i;this.isTouchDevice||t(r.clientX,r.clientY)}),this.eventListeners.set("mousedown",i=>{let r=i;this.isTouchDevice||r.button===0&&(this.isMouseDown=!0,s(!0,r.clientX,r.clientY))}),this.eventListeners.set("mouseup",i=>{let r=i;this.isTouchDevice||r.button===0&&s(!1)}),this.eventListeners.set("touchmove",i=>{let r=i;r.touches.length>0&&t(r.touches[0].clientX,r.touches[0].clientY)}),this.eventListeners.set("touchstart",i=>{let r=i;this.isTouchDevice=!0,r.touches.length>0&&(t(r.touches[0].clientX,r.touches[0].clientY),s(!0,r.touches[0].clientX,r.touches[0].clientY))}),this.eventListeners.set("touchend",i=>{i.touches.length===0&&s(!1)}),this.eventListeners.forEach((i,r)=>{e.addEventListener(r,i)})}updateResolution(){let e=[this.gl.drawingBufferWidth,this.gl.drawingBufferHeight];this.gl.viewport(0,0,...e),this.uniforms.has("u_resolution")?this.updateUniforms({u_resolution:e}):this.initializeUniform("u_resolution","float",e),this.historyDepth>0&&(this.resizeTexture(m,...e),this.resizeTexture(d,...e)),this.hooks.get("updateResolution")?.forEach(t=>t.call(this))}resizeTexture(e,t,s){let i=this.textures.get(e);if(!i||i.width===t&&i.height===s)return;this.gl.deleteTexture(i.texture),i.width=t,i.height=s;let{texture:r}=this.createTexture(e,i);i.texture=r,i.history&&(i.history.writeIndex=0,this.clearHistoryTextureLayers(i))}reserveTextureUnit(e){let t=this.textures.get(e);if(t)return t.unitIndex;if(this.textureUnitPool.free.length>0)return this.textureUnitPool.free.pop();if(this.textureUnitPool.next>=this.textureUnitPool.max)throw new Error("Exceeded the available texture units for this device.");return this.textureUnitPool.next++}releaseTextureUnit(e){let t=this.textures.get(e);t&&this.textureUnitPool.free.push(t.unitIndex)}resolveTextureOptions(e){let{gl:t}=this,s=e?.type??t.UNSIGNED_BYTE;return{type:s,format:e?.format??t.RGBA,internalFormat:e?.internalFormat??(s===t.FLOAT?t.RGBA32F:s===t.HALF_FLOAT?t.RGBA16F:t.RGBA8),minFilter:e?.minFilter??t.LINEAR,magFilter:e?.magFilter??t.LINEAR,wrapS:e?.wrapS??t.CLAMP_TO_EDGE,wrapT:e?.wrapT??t.CLAMP_TO_EDGE,preserveY:e?.preserveY}}clearHistoryTextureLayers(e){if(!e.history)return;let t=this.gl,{type:s,format:i}=e.options,r=e.width*e.height*4,n=s===t.FLOAT?new Float32Array(r):s===t.HALF_FLOAT?new Uint16Array(r):new Uint8Array(r);t.activeTexture(t.TEXTURE0+e.unitIndex),t.bindTexture(t.TEXTURE_2D_ARRAY,e.texture);for(let o=0;o<e.history.depth;++o)t.texSubImage3D(t.TEXTURE_2D_ARRAY,0,0,0,o,e.width,e.height,1,i,s,n)}initializeUniform(e,t,s,i){let r=i?.arrayLength;if(this.uniforms.has(e))throw new Error(`${e} is already initialized.`);if(t!=="float"&&t!=="int")throw new Error(`Invalid uniform type: ${t}. Expected 'float' or 'int'.`);if(r&&!(Array.isArray(s)&&s.length===r))throw new Error(`${e} array length mismatch: must initialize with ${r} elements.`);let n=this.gl.getUniformLocation(this.program,e);if(!n&&r&&(n=this.gl.getUniformLocation(this.program,`${e}[0]`)),!n){this.log(`${e} not found in fragment shader. Skipping initialization.`);return}let o=r?s[0]:s,u=Array.isArray(o)?o.length:1;this.uniforms.set(e,{type:t,length:u,location:n,arrayLength:r});try{this.updateUniforms({[e]:s})}catch(h){throw this.uniforms.delete(e),h}this.hooks.get("initializeUniform")?.forEach(h=>h.call(this,...arguments))}log(...e){this.debug&&console.debug(...e)}updateUniforms(e,t){this.gl.useProgram(this.program),Object.entries(e).forEach(([s,i])=>{let r=this.uniforms.get(s);if(!r){this.log(`${s} not found in fragment shader. Skipping update.`);return}let n=`uniform${r.length}${r.type.charAt(0)}`;if(r.arrayLength){if(!Array.isArray(i))throw new Error(`${s} is an array, but the value passed to updateUniforms is not an array.`);let o=i.length;if(!o)return;if(o>r.arrayLength)throw new Error(`${s} received ${o} values, but maximum length is ${r.arrayLength}.`);if(i.some(a=>(Array.isArray(a)?a.length:1)!==r.length))throw new Error(`Tried to update ${s} with some elements that are not length ${r.length}.`);let u=new(r.type==="float"?Float32Array:Int32Array)(i.flat()),h=r.location;if(t?.startIndex){let a=this.gl.getUniformLocation(this.program,`${s}[${t.startIndex}]`);if(!a)throw new Error(`${s}[${t.startIndex}] not found in fragment shader. Did you pass an invalid startIndex?`);h=a}this.gl[n+"v"](h,u)}else{if(Array.isArray(i)||(i=[i]),i.length!==r.length)throw new Error(`Invalid uniform value length: ${i.length}. Expected ${r.length}.`);this.gl[n](r.location,...i)}}),this.hooks.get("updateUniforms")?.forEach(s=>s.call(this,...arguments))}createTexture(e,t){let{width:s,height:i}=t,r=t.history?.depth??0,n=this.gl.createTexture();if(!n)throw new Error("Failed to create texture");let o=t.unitIndex;if(typeof o!="number")try{o=this.reserveTextureUnit(e)}catch(c){throw this.gl.deleteTexture(n),c}let u=r>0,h=u?this.gl.TEXTURE_2D_ARRAY:this.gl.TEXTURE_2D,{options:a}=t;return this.gl.activeTexture(this.gl.TEXTURE0+o),this.gl.bindTexture(h,n),this.gl.texParameteri(h,this.gl.TEXTURE_WRAP_S,a.wrapS),this.gl.texParameteri(h,this.gl.TEXTURE_WRAP_T,a.wrapT),this.gl.texParameteri(h,this.gl.TEXTURE_MIN_FILTER,a.minFilter),this.gl.texParameteri(h,this.gl.TEXTURE_MAG_FILTER,a.magFilter),u?this.gl.texStorage3D(h,1,a.internalFormat,s,i,r):e===d&&this.gl.texImage2D(this.gl.TEXTURE_2D,0,a.internalFormat,s,i,0,a.format,a.type,null),{texture:n,unitIndex:o}}_initializeTexture(e,t,s){if(this.textures.has(e))throw new Error(`Texture '${f(e)}' is already initialized.`);let{history:i=0,...r}=s??{},{width:n,height:o}=T(t);if(!n||!o)throw new Error("Texture source must have valid dimensions");let u={width:n,height:o,options:this.resolveTextureOptions(r)};i>0&&(u.history={depth:i,writeIndex:0});let{texture:h,unitIndex:a}=this.createTexture(e,u),c={texture:h,unitIndex:a,...u};i>0&&(this.initializeUniform(`${f(e)}FrameOffset`,"int",0),this.clearHistoryTextureLayers(c)),this.textures.set(e,c),this.updateTexture(e,t);let g=this.gl.getUniformLocation(this.program,f(e));g&&this.gl.uniform1i(g,a)}initializeTexture(e,t,s){this._initializeTexture(e,t,s),this.hooks.get("initializeTexture")?.forEach(i=>i.call(this,...arguments))}updateTextures(e,t){this.hooks.get("updateTextures")?.forEach(s=>s.call(this,...arguments)),Object.entries(e).forEach(([s,i])=>{this.updateTexture(s,i,t)})}updateTexture(e,t,s){let i=this.textures.get(e);if(!i)throw new Error(`Texture '${f(e)}' is not initialized.`);if(t instanceof WebGLTexture){this.gl.activeTexture(this.gl.TEXTURE0+i.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D,t);return}let{width:r,height:n}=T(t);if(!r||!n)return;let o="isPartial"in t&&t.isPartial;o||this.resizeTexture(e,r,n);let h=!("data"in t&&t.data)&&!i.options?.preserveY,a=this.gl.getParameter(this.gl.UNPACK_FLIP_Y_WEBGL);if(i.history){if(this.gl.activeTexture(this.gl.TEXTURE0+i.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D_ARRAY,i.texture),!s?.skipHistoryWrite){this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,h),this.gl.texSubImage3D(this.gl.TEXTURE_2D_ARRAY,0,0,0,i.history.writeIndex,r,n,1,i.options.format,i.options.type,t.data??t),this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,a);let c=`${f(e)}FrameOffset`;this.updateUniforms({[c]:i.history.writeIndex}),i.history.writeIndex=(i.history.writeIndex+1)%i.history.depth}}else this.gl.activeTexture(this.gl.TEXTURE0+i.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D,i.texture),this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,h),o?this.gl.texSubImage2D(this.gl.TEXTURE_2D,0,t.x??0,t.y??0,r,n,i.options.format,i.options.type,t.data):this.gl.texImage2D(this.gl.TEXTURE_2D,0,i.options.internalFormat,r,n,0,i.options.format,i.options.type,t.data??t),this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,a)}draw(e){let t=this.gl,s=t.drawingBufferWidth,i=t.drawingBufferHeight,r=this.textures.get(m),n=this.textures.get(d),o=r&&!e?.skipHistoryWrite;o&&(t.bindFramebuffer(t.FRAMEBUFFER,this.intermediateFbo),t.framebufferTexture2D(t.FRAMEBUFFER,t.COLOR_ATTACHMENT0,t.TEXTURE_2D,n.texture,0)),t.useProgram(this.program),t.bindBuffer(t.ARRAY_BUFFER,this.buffer),t.vertexAttribPointer(this.aPositionLocation,2,t.FLOAT,!1,0,0),t.enableVertexAttribArray(this.aPositionLocation),t.viewport(0,0,s,i),e?.skipClear||t.clear(t.COLOR_BUFFER_BIT),t.drawArrays(t.TRIANGLES,0,6),o&&(t.bindTexture(t.TEXTURE_2D_ARRAY,r.texture),t.copyTexSubImage3D(t.TEXTURE_2D_ARRAY,0,0,0,r.history.writeIndex,0,0,s,i),t.bindFramebuffer(t.READ_FRAMEBUFFER,this.intermediateFbo),t.bindFramebuffer(t.DRAW_FRAMEBUFFER,null),t.blitFramebuffer(0,0,s,i,0,0,s,i,t.COLOR_BUFFER_BIT,t.NEAREST),t.bindFramebuffer(t.FRAMEBUFFER,null))}step(e,t){let s={};this.uniforms.has("u_time")&&(s.u_time=e),this.uniforms.has("u_frame")&&(s.u_frame=this.frame),this.updateUniforms(s),this.hooks.get("step")?.forEach(r=>r.call(this,e,this.frame)),this.draw(t);let i=this.textures.get(m);if(i&&!t?.skipHistoryWrite){let{writeIndex:r,depth:n}=i.history;this.updateUniforms({[`${f(m)}FrameOffset`]:r}),i.history.writeIndex=(r+1)%n}this.hooks.get("afterStep")?.forEach(r=>r.call(this,e,this.frame)),++this.frame}play(e,t){this.pause();let s=i=>{i=(i-this.startTime)/1e3;let r=t?.(i,this.frame)??void 0;this.step(i,r),this.animationFrameId=requestAnimationFrame(s),e?.(i,this.frame)};this.animationFrameId=requestAnimationFrame(s)}pause(){this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null)}reset(){this.frame=0,this.startTime=performance.now(),this.textures.forEach(e=>{e.history&&(e.history.writeIndex=0,this.clearHistoryTextureLayers(e))}),this.hooks.get("reset")?.forEach(e=>e.call(this))}destroy(){this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null),this.resolutionObserver.disconnect(),this.resizeObserver.disconnect(),this.canvas instanceof HTMLCanvasElement&&this.eventListeners.forEach((e,t)=>{this.canvas.removeEventListener(t,e)}),this.program&&this.gl.deleteProgram(this.program),this.intermediateFbo&&(this.gl.deleteFramebuffer(this.intermediateFbo),this.intermediateFbo=null),this.textures.forEach(e=>{this.gl.deleteTexture(e.texture)}),this.textureUnitPool.free=[],this.textureUnitPool.next=0,this.buffer&&(this.gl.deleteBuffer(this.buffer),this.buffer=null),this.hooks.get("destroy")?.forEach(e=>e.call(this)),this.isInternalCanvas&&this.canvas instanceof HTMLCanvasElement&&this.canvas.remove()}},E=p;export{E as a};
11
+ //# sourceMappingURL=chunk-6C6DVCZI.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["const DEFAULT_VERTEX_SHADER_SRC = `#version 300 es\nin vec2 aPosition;\nout vec2 v_uv;\nvoid main() {\n v_uv = aPosition * 0.5 + 0.5;\n gl_Position = vec4(aPosition, 0.0, 1.0);\n}\n`;\nconst RESIZE_THROTTLE_INTERVAL = 1000 / 30;\n\ninterface Uniform {\n\ttype: 'float' | 'int';\n\tlength: 1 | 2 | 3 | 4;\n\tlocation: WebGLUniformLocation;\n\tarrayLength?: number;\n}\n\nexport interface TextureOptions {\n\tinternalFormat?: number;\n\tformat?: number;\n\ttype?: number;\n\tminFilter?: number;\n\tmagFilter?: number;\n\twrapS?: number;\n\twrapT?: number;\n\tpreserveY?: boolean;\n}\ntype ResolvedTextureOptions = Required<Omit<TextureOptions, 'preserveY'>> & Pick<TextureOptions, 'preserveY'>;\n\ninterface Texture {\n\ttexture: WebGLTexture;\n\tunitIndex: number;\n\twidth: number;\n\theight: number;\n\thistory?: {\n\t\tdepth: number;\n\t\twriteIndex: number;\n\t};\n\toptions: ResolvedTextureOptions;\n}\n\nexport interface CustomTexture {\n\tdata: ArrayBufferView | null;\n\twidth: number;\n\theight: number;\n}\n\nexport interface PartialCustomTexture extends CustomTexture {\n\tisPartial?: boolean;\n\tx?: number;\n\ty?: number;\n}\n\nexport type TextureSource =\n\t| HTMLImageElement\n\t| HTMLVideoElement\n\t| HTMLCanvasElement\n\t| OffscreenCanvas\n\t| ImageBitmap\n\t| WebGLTexture\n\t| CustomTexture;\n\n// Custom textures allow partial updates starting from (x, y).\ntype UpdateTextureSource = Exclude<TextureSource, CustomTexture> | PartialCustomTexture;\n\nexport interface PluginContext {\n\tgl: WebGL2RenderingContext;\n\tuniforms: Map<string, Uniform>;\n\ttextures: Map<string | symbol, Texture>;\n\tget program(): WebGLProgram | null;\n\tcanvas: HTMLCanvasElement | OffscreenCanvas;\n\treserveTextureUnit: (name: string | symbol) => number;\n\treleaseTextureUnit: (name: string | symbol) => void;\n\tinjectGLSL: (code: string) => void;\n}\n\ntype Plugin = (shaderPad: ShaderPad, context: PluginContext) => void;\n\ntype LifecycleMethod =\n\t| 'init'\n\t| 'step'\n\t| 'afterStep'\n\t| 'destroy'\n\t| 'updateResolution'\n\t| 'reset'\n\t| 'initializeTexture'\n\t| 'updateTextures'\n\t| 'initializeUniform'\n\t| 'updateUniforms';\n\nexport interface Options extends Exclude<TextureOptions, 'preserveY'> {\n\tcanvas?: HTMLCanvasElement | OffscreenCanvas | null;\n\tplugins?: Plugin[];\n\thistory?: number;\n\tdebug?: boolean;\n}\n\nexport interface StepOptions {\n\tskipClear?: boolean;\n\tskipHistoryWrite?: boolean;\n}\n\ntype TextureUnitPool = {\n\tfree: number[];\n\tnext: number;\n\tmax: number;\n};\n\nconst HISTORY_TEXTURE_KEY = Symbol('u_history');\nconst INTERMEDIATE_TEXTURE_KEY = Symbol('__SHADERPAD_BUFFER');\n\nfunction combineShaderCode(shader: string, injections: string[]): string {\n\tif (!injections?.length) return shader;\n\tconst lines = shader.split('\\n');\n\tconst insertAt =\n\t\tlines.findLastIndex(line => {\n\t\t\tconst trimmed = line.trimStart();\n\t\t\treturn trimmed.startsWith('precision ') || trimmed.startsWith('#version ');\n\t\t}) + 1;\n\tlines.splice(insertAt, 0, ...injections);\n\treturn lines.join('\\n');\n}\n\nfunction getSourceDimensions(source: TextureSource): { width: number; height: number } {\n\tif (source instanceof WebGLTexture) {\n\t\treturn { width: 0, height: 0 }; // Invalid - dimensions not readable.\n\t}\n\tif (source instanceof HTMLVideoElement) {\n\t\treturn { width: source.videoWidth, height: source.videoHeight };\n\t}\n\tif (source instanceof HTMLImageElement) {\n\t\treturn { width: source.naturalWidth ?? source.width, height: source.naturalHeight ?? source.height };\n\t}\n\t// CustomTexture, HTMLCanvasElement, OffscreenCanvas, ImageBitmap.\n\treturn { width: source.width, height: source.height };\n}\n\nfunction stringFrom(name: string | symbol) {\n\treturn typeof name === 'symbol' ? name.description ?? '' : name;\n}\n\nclass ShaderPad {\n\tprivate isInternalCanvas = false;\n\tprivate isTouchDevice = false;\n\tprivate gl: WebGL2RenderingContext;\n\tprivate fragmentShaderSrc: string;\n\tprivate uniforms: Map<string, Uniform> = new Map();\n\tprivate textures: Map<string | symbol, Texture> = new Map();\n\tprivate textureUnitPool: TextureUnitPool;\n\tprivate buffer: WebGLBuffer | null = null;\n\tprivate program: WebGLProgram | null = null;\n\tprivate aPositionLocation = 0;\n\tprivate animationFrameId: number | null;\n\tprivate resolutionObserver: MutationObserver;\n\tprivate resizeObserver: ResizeObserver;\n\tprivate resizeTimeout: ReturnType<typeof setTimeout> = null as unknown as ReturnType<typeof setTimeout>;\n\tprivate lastResizeTime = -Infinity;\n\tprivate eventListeners: Map<string, EventListener> = new Map();\n\tprivate frame = 0;\n\tprivate startTime = 0;\n\tprivate cursorPosition = [0.5, 0.5];\n\tprivate clickPosition = [0.5, 0.5];\n\tprivate isMouseDown = false;\n\tpublic canvas: HTMLCanvasElement | OffscreenCanvas;\n\tpublic onResize?: (width: number, height: number) => void;\n\tprivate hooks: Map<LifecycleMethod, Function[]> = new Map();\n\tprivate historyDepth = 0;\n\tprivate textureOptions: TextureOptions;\n\tprivate debug: boolean;\n\t// WebGL can’t read from and write to the history texture at the same time.\n\t// We write to an intermediate texture then blit to the history texture.\n\tprivate intermediateFbo: WebGLFramebuffer | null = null;\n\n\tconstructor(fragmentShaderSrc: string, { canvas, plugins, history, debug, ...textureOptions }: Options = {}) {\n\t\tthis.canvas = canvas || document.createElement('canvas');\n\t\tif (!canvas) {\n\t\t\tthis.isInternalCanvas = true;\n\t\t\tconst htmlCanvas = this.canvas as HTMLCanvasElement;\n\t\t\thtmlCanvas.style.position = 'fixed';\n\t\t\thtmlCanvas.style.inset = '0';\n\t\t\thtmlCanvas.style.height = '100dvh';\n\t\t\thtmlCanvas.style.width = '100dvw';\n\t\t\tdocument.body.appendChild(htmlCanvas);\n\t\t}\n\n\t\tthis.gl = this.canvas.getContext('webgl2', { antialias: false }) as WebGL2RenderingContext;\n\t\tif (!this.gl) {\n\t\t\tthrow new Error('WebGL2 not supported. Please use a browser that supports WebGL2.');\n\t\t}\n\n\t\tthis.textureUnitPool = {\n\t\t\tfree: [],\n\t\t\tnext: 0,\n\t\t\tmax: this.gl.getParameter(this.gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS),\n\t\t};\n\t\tthis.textureOptions = textureOptions;\n\n\t\tconst { internalFormat, type } = textureOptions;\n\t\tconst isFloatFormat =\n\t\t\ttype === this.gl.FLOAT ||\n\t\t\ttype === this.gl.HALF_FLOAT ||\n\t\t\tinternalFormat === this.gl.RGBA16F ||\n\t\t\tinternalFormat === this.gl.RGBA32F ||\n\t\t\tinternalFormat === this.gl.R16F ||\n\t\t\tinternalFormat === this.gl.R32F ||\n\t\t\tinternalFormat === this.gl.RG16F ||\n\t\t\tinternalFormat === this.gl.RG32F;\n\t\tif (isFloatFormat && !this.gl.getExtension('EXT_color_buffer_float')) {\n\t\t\tconsole.warn('EXT_color_buffer_float not supported, falling back to RGBA8');\n\t\t\tdelete this.textureOptions?.internalFormat;\n\t\t\tdelete this.textureOptions?.format;\n\t\t\tdelete this.textureOptions?.type;\n\t\t}\n\n\t\tif (history) this.historyDepth = history;\n\t\tthis.debug = debug ?? (typeof process !== 'undefined' && process.env.NODE_ENV !== 'production');\n\t\tthis.animationFrameId = null;\n\t\tthis.resolutionObserver = new MutationObserver(() => this.updateResolution());\n\t\tthis.resizeObserver = new ResizeObserver(() => this.throttledHandleResize());\n\n\t\tconst glslInjections: string[] = [];\n\t\tif (plugins) {\n\t\t\tconst context: PluginContext = {\n\t\t\t\tgl: this.gl,\n\t\t\t\tuniforms: this.uniforms,\n\t\t\t\ttextures: this.textures,\n\t\t\t\tcanvas: this.canvas,\n\t\t\t\treserveTextureUnit: this.reserveTextureUnit.bind(this),\n\t\t\t\treleaseTextureUnit: this.releaseTextureUnit.bind(this),\n\t\t\t\tinjectGLSL: (code: string) => {\n\t\t\t\t\tglslInjections.push(code);\n\t\t\t\t},\n\t\t\t} as PluginContext;\n\t\t\t// Define program as a getter so it always returns the current program.\n\t\t\tObject.defineProperty(context, 'program', {\n\t\t\t\tget: () => this.program,\n\t\t\t\tenumerable: true,\n\t\t\t\tconfigurable: true,\n\t\t\t});\n\t\t\tplugins.forEach(plugin => plugin(this, context));\n\t\t}\n\n\t\tthis.fragmentShaderSrc = combineShaderCode(fragmentShaderSrc, glslInjections);\n\t\tthis.init();\n\t\tif (this.canvas instanceof HTMLCanvasElement) {\n\t\t\tthis.addEventListeners();\n\t\t}\n\t}\n\n\tregisterHook(name: LifecycleMethod, fn: Function) {\n\t\tif (!this.hooks.has(name)) {\n\t\t\tthis.hooks.set(name, []);\n\t\t}\n\t\tthis.hooks.get(name)!.push(fn);\n\t}\n\n\tprivate init() {\n\t\tconst vertexShaderSrc = DEFAULT_VERTEX_SHADER_SRC;\n\n\t\tthis.program = this.gl.createProgram();\n\t\tif (!this.program) {\n\t\t\tthrow new Error('Failed to create WebGL program');\n\t\t}\n\t\tconst vertexShader = this.createShader(this.gl.VERTEX_SHADER, vertexShaderSrc);\n\t\tconst fragmentShader = this.createShader(this.gl.FRAGMENT_SHADER, this.fragmentShaderSrc);\n\n\t\tthis.gl.attachShader(this.program, vertexShader);\n\t\tthis.gl.attachShader(this.program, fragmentShader);\n\t\tthis.gl.linkProgram(this.program);\n\t\tthis.gl.deleteShader(vertexShader);\n\t\tthis.gl.deleteShader(fragmentShader);\n\n\t\tif (!this.gl.getProgramParameter(this.program, this.gl.LINK_STATUS)) {\n\t\t\tconsole.error('Program link error:', this.gl.getProgramInfoLog(this.program));\n\t\t\tthis.gl.deleteProgram(this.program);\n\t\t\tthrow new Error('Failed to link WebGL program');\n\t\t}\n\n\t\tthis.aPositionLocation = this.gl.getAttribLocation(this.program, 'aPosition');\n\t\tthis.setupBuffer();\n\n\t\tthis.gl.useProgram(this.program);\n\n\t\tif (this.canvas instanceof HTMLCanvasElement) {\n\t\t\tthis.resolutionObserver.observe(this.canvas, { attributes: true, attributeFilter: ['width', 'height'] });\n\t\t\tthis.resizeObserver.observe(this.canvas);\n\t\t}\n\n\t\tif (!this.isInternalCanvas) {\n\t\t\tthis.updateResolution();\n\t\t}\n\t\tthis.initializeUniform('u_cursor', 'float', this.cursorPosition);\n\t\tthis.initializeUniform('u_click', 'float', [...this.clickPosition, this.isMouseDown ? 1.0 : 0.0]);\n\t\tthis.initializeUniform('u_time', 'float', 0);\n\t\tthis.initializeUniform('u_frame', 'int', 0);\n\n\t\tif (this.historyDepth > 0) {\n\t\t\tthis._initializeTexture(INTERMEDIATE_TEXTURE_KEY, this.canvas, {\n\t\t\t\t...this.textureOptions,\n\t\t\t});\n\t\t\tthis._initializeTexture(HISTORY_TEXTURE_KEY, this.canvas, {\n\t\t\t\thistory: this.historyDepth,\n\t\t\t\t...this.textureOptions,\n\t\t\t});\n\t\t\tthis.intermediateFbo = this.gl.createFramebuffer();\n\t\t}\n\n\t\tthis.hooks.get('init')?.forEach(hook => hook.call(this));\n\t}\n\n\tprivate createShader(type: number, source: string): WebGLShader {\n\t\tconst shader = this.gl.createShader(type)!;\n\t\tthis.gl.shaderSource(shader, source);\n\t\tthis.gl.compileShader(shader);\n\t\tif (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)) {\n\t\t\tconsole.error('Shader compilation failed:', source);\n\t\t\tconsole.error(this.gl.getShaderInfoLog(shader));\n\t\t\tthis.gl.deleteShader(shader);\n\t\t\tthrow new Error('Shader compilation failed');\n\t\t}\n\t\treturn shader;\n\t}\n\n\tprivate setupBuffer() {\n\t\tconst quadVertices = new Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1]);\n\n\t\tthis.buffer = this.gl.createBuffer();\n\t\tthis.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.buffer);\n\t\tthis.gl.bufferData(this.gl.ARRAY_BUFFER, quadVertices, this.gl.STATIC_DRAW);\n\t\tthis.gl.viewport(0, 0, this.gl.drawingBufferWidth, this.gl.drawingBufferHeight);\n\t\tthis.gl.enableVertexAttribArray(this.aPositionLocation);\n\t\tthis.gl.vertexAttribPointer(this.aPositionLocation, 2, this.gl.FLOAT, false, 0, 0);\n\t}\n\n\tprivate throttledHandleResize() {\n\t\tclearTimeout(this.resizeTimeout);\n\t\tconst now = performance.now();\n\t\tconst timeUntilNextResize = this.lastResizeTime + RESIZE_THROTTLE_INTERVAL - now;\n\t\tif (timeUntilNextResize <= 0) {\n\t\t\tthis.lastResizeTime = now;\n\t\t\tthis.handleResize();\n\t\t} else {\n\t\t\tthis.resizeTimeout = setTimeout(() => this.throttledHandleResize(), timeUntilNextResize);\n\t\t}\n\t}\n\n\tprivate handleResize() {\n\t\tif (!(this.canvas instanceof HTMLCanvasElement)) return;\n\t\tconst pixelRatio = window.devicePixelRatio || 1;\n\t\tconst width = this.canvas.clientWidth * pixelRatio;\n\t\tconst height = this.canvas.clientHeight * pixelRatio;\n\t\tif (this.isInternalCanvas && (this.canvas.width !== width || this.canvas.height !== height)) {\n\t\t\tthis.canvas.width = width;\n\t\t\tthis.canvas.height = height;\n\t\t}\n\t\tthis.onResize?.(width, height);\n\t}\n\n\tprivate addEventListeners() {\n\t\tconst htmlCanvas = this.canvas as HTMLCanvasElement;\n\t\tconst updateCursor = (x: number, y: number) => {\n\t\t\tif (!this.uniforms.has('u_cursor')) return;\n\t\t\tconst rect = htmlCanvas.getBoundingClientRect();\n\t\t\tthis.cursorPosition[0] = (x - rect.left) / rect.width;\n\t\t\tthis.cursorPosition[1] = 1 - (y - rect.top) / rect.height; // Flip Y for WebGL\n\t\t\tthis.updateUniforms({ u_cursor: this.cursorPosition });\n\t\t};\n\n\t\tconst updateClick = (isMouseDown: boolean, x?: number, y?: number) => {\n\t\t\tif (!this.uniforms.has('u_click')) return;\n\t\t\tthis.isMouseDown = isMouseDown;\n\t\t\tif (isMouseDown) {\n\t\t\t\tconst rect = htmlCanvas.getBoundingClientRect();\n\t\t\t\tconst xVal = x as number;\n\t\t\t\tconst yVal = y as number;\n\t\t\t\tthis.clickPosition[0] = (xVal - rect.left) / rect.width;\n\t\t\t\tthis.clickPosition[1] = 1 - (yVal - rect.top) / rect.height; // Flip Y for WebGL\n\t\t\t}\n\t\t\tthis.updateUniforms({ u_click: [...this.clickPosition, this.isMouseDown ? 1.0 : 0.0] });\n\t\t};\n\n\t\tthis.eventListeners.set('mousemove', event => {\n\t\t\tconst mouseEvent = event as MouseEvent;\n\t\t\tif (!this.isTouchDevice) {\n\t\t\t\tupdateCursor(mouseEvent.clientX, mouseEvent.clientY);\n\t\t\t}\n\t\t});\n\n\t\tthis.eventListeners.set('mousedown', event => {\n\t\t\tconst mouseEvent = event as MouseEvent;\n\t\t\tif (!this.isTouchDevice) {\n\t\t\t\tif (mouseEvent.button === 0) {\n\t\t\t\t\tthis.isMouseDown = true;\n\t\t\t\t\tupdateClick(true, mouseEvent.clientX, mouseEvent.clientY);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\tthis.eventListeners.set('mouseup', event => {\n\t\t\tconst mouseEvent = event as MouseEvent;\n\t\t\tif (!this.isTouchDevice) {\n\t\t\t\tif (mouseEvent.button === 0) {\n\t\t\t\t\tupdateClick(false);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\tthis.eventListeners.set('touchmove', event => {\n\t\t\tconst touchEvent = event as TouchEvent;\n\t\t\tif (touchEvent.touches.length > 0) {\n\t\t\t\tupdateCursor(touchEvent.touches[0].clientX, touchEvent.touches[0].clientY);\n\t\t\t}\n\t\t});\n\n\t\tthis.eventListeners.set('touchstart', event => {\n\t\t\tconst touchEvent = event as TouchEvent;\n\t\t\tthis.isTouchDevice = true;\n\t\t\tif (touchEvent.touches.length > 0) {\n\t\t\t\tupdateCursor(touchEvent.touches[0].clientX, touchEvent.touches[0].clientY);\n\t\t\t\tupdateClick(true, touchEvent.touches[0].clientX, touchEvent.touches[0].clientY);\n\t\t\t}\n\t\t});\n\n\t\tthis.eventListeners.set('touchend', event => {\n\t\t\tconst touchEvent = event as TouchEvent;\n\t\t\tif (touchEvent.touches.length === 0) {\n\t\t\t\tupdateClick(false);\n\t\t\t}\n\t\t});\n\n\t\tthis.eventListeners.forEach((listener, event) => {\n\t\t\thtmlCanvas.addEventListener(event, listener);\n\t\t});\n\t}\n\n\tprivate updateResolution() {\n\t\tconst resolution: [number, number] = [this.gl.drawingBufferWidth, this.gl.drawingBufferHeight];\n\t\tthis.gl.viewport(0, 0, ...resolution);\n\t\tif (this.uniforms.has('u_resolution')) {\n\t\t\tthis.updateUniforms({ u_resolution: resolution });\n\t\t} else {\n\t\t\tthis.initializeUniform('u_resolution', 'float', resolution);\n\t\t}\n\t\tif (this.historyDepth > 0) {\n\t\t\tthis.resizeTexture(HISTORY_TEXTURE_KEY, ...resolution);\n\t\t\tthis.resizeTexture(INTERMEDIATE_TEXTURE_KEY, ...resolution);\n\t\t}\n\t\tthis.hooks.get('updateResolution')?.forEach(hook => hook.call(this));\n\t}\n\n\tprivate resizeTexture(name: string | symbol, width: number, height: number) {\n\t\tconst info = this.textures.get(name);\n\t\tif (!info || (info.width === width && info.height === height)) return;\n\n\t\tthis.gl.deleteTexture(info.texture);\n\t\tinfo.width = width;\n\t\tinfo.height = height;\n\t\tconst { texture } = this.createTexture(name, info);\n\t\tinfo.texture = texture;\n\t\tif (info.history) {\n\t\t\tinfo.history.writeIndex = 0;\n\t\t\tthis.clearHistoryTextureLayers(info);\n\t\t}\n\t}\n\n\tprivate reserveTextureUnit(name: string | symbol) {\n\t\tconst existing = this.textures.get(name);\n\t\tif (existing) return existing.unitIndex;\n\t\tif (this.textureUnitPool.free.length > 0) return this.textureUnitPool.free.pop()!;\n\t\tif (this.textureUnitPool.next >= this.textureUnitPool.max) {\n\t\t\tthrow new Error('Exceeded the available texture units for this device.');\n\t\t}\n\t\treturn this.textureUnitPool.next++;\n\t}\n\n\tprivate releaseTextureUnit(name: string | symbol) {\n\t\tconst existing = this.textures.get(name);\n\t\tif (existing) {\n\t\t\tthis.textureUnitPool.free.push(existing.unitIndex);\n\t\t}\n\t}\n\n\tprivate resolveTextureOptions(options?: TextureOptions): ResolvedTextureOptions {\n\t\tconst { gl } = this;\n\t\tconst type = options?.type ?? gl.UNSIGNED_BYTE;\n\t\treturn {\n\t\t\ttype,\n\t\t\tformat: options?.format ?? gl.RGBA,\n\t\t\tinternalFormat:\n\t\t\t\toptions?.internalFormat ??\n\t\t\t\t(type === gl.FLOAT ? gl.RGBA32F : type === gl.HALF_FLOAT ? gl.RGBA16F : gl.RGBA8),\n\t\t\tminFilter: options?.minFilter ?? gl.LINEAR,\n\t\t\tmagFilter: options?.magFilter ?? gl.LINEAR,\n\t\t\twrapS: options?.wrapS ?? gl.CLAMP_TO_EDGE,\n\t\t\twrapT: options?.wrapT ?? gl.CLAMP_TO_EDGE,\n\t\t\tpreserveY: options?.preserveY,\n\t\t};\n\t}\n\n\tprivate clearHistoryTextureLayers(textureInfo: Texture): void {\n\t\tif (!textureInfo.history) return;\n\n\t\tconst gl = this.gl;\n\t\tconst { type, format } = textureInfo.options;\n\t\tconst size = textureInfo.width * textureInfo.height * 4;\n\t\tconst transparent =\n\t\t\ttype === gl.FLOAT\n\t\t\t\t? new Float32Array(size)\n\t\t\t\t: type === gl.HALF_FLOAT\n\t\t\t\t? new Uint16Array(size)\n\t\t\t\t: new Uint8Array(size);\n\t\tgl.activeTexture(gl.TEXTURE0 + textureInfo.unitIndex);\n\t\tgl.bindTexture(gl.TEXTURE_2D_ARRAY, textureInfo.texture);\n\t\tfor (let layer = 0; layer < textureInfo.history.depth; ++layer) {\n\t\t\tgl.texSubImage3D(\n\t\t\t\tgl.TEXTURE_2D_ARRAY,\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t\tlayer,\n\t\t\t\ttextureInfo.width,\n\t\t\t\ttextureInfo.height,\n\t\t\t\t1,\n\t\t\t\tformat,\n\t\t\t\ttype,\n\t\t\t\ttransparent\n\t\t\t);\n\t\t}\n\t}\n\n\tinitializeUniform(\n\t\tname: string,\n\t\ttype: 'float' | 'int',\n\t\tvalue: number | number[] | (number | number[])[],\n\t\toptions?: { arrayLength?: number }\n\t) {\n\t\tconst arrayLength = options?.arrayLength;\n\t\tif (this.uniforms.has(name)) {\n\t\t\tthrow new Error(`${name} is already initialized.`);\n\t\t}\n\t\tif (type !== 'float' && type !== 'int') {\n\t\t\tthrow new Error(`Invalid uniform type: ${type}. Expected 'float' or 'int'.`);\n\t\t}\n\t\tif (arrayLength && !(Array.isArray(value) && value.length === arrayLength)) {\n\t\t\tthrow new Error(`${name} array length mismatch: must initialize with ${arrayLength} elements.`);\n\t\t}\n\n\t\tlet location = this.gl.getUniformLocation(this.program!, name);\n\t\tif (!location && arrayLength) {\n\t\t\tlocation = this.gl.getUniformLocation(this.program!, `${name}[0]`);\n\t\t}\n\t\tif (!location) {\n\t\t\tthis.log(`${name} not found in fragment shader. Skipping initialization.`);\n\t\t\treturn;\n\t\t}\n\n\t\tconst probeValue = arrayLength ? (value as number[] | number[][])[0] : value;\n\t\tconst length = Array.isArray(probeValue) ? (probeValue.length as 1 | 2 | 3 | 4) : 1;\n\t\tthis.uniforms.set(name, { type, length, location, arrayLength });\n\n\t\ttry {\n\t\t\tthis.updateUniforms({ [name]: value });\n\t\t} catch (error) {\n\t\t\tthis.uniforms.delete(name);\n\t\t\tthrow error;\n\t\t}\n\t\tthis.hooks.get('initializeUniform')?.forEach(hook => hook.call(this, ...arguments));\n\t}\n\n\tprivate log(...args: any[]) {\n\t\tif (this.debug) console.debug(...args);\n\t}\n\n\tupdateUniforms(\n\t\tupdates: Record<string, number | number[] | (number | number[])[]>,\n\t\toptions?: { startIndex?: number }\n\t) {\n\t\tthis.gl.useProgram(this.program);\n\t\tObject.entries(updates).forEach(([name, value]) => {\n\t\t\tconst uniform = this.uniforms.get(name);\n\t\t\tif (!uniform) {\n\t\t\t\tthis.log(`${name} not found in fragment shader. Skipping update.`);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet glFunctionName = `uniform${uniform.length}${uniform.type.charAt(0)}`; // e.g. uniform1f, uniform3i…\n\t\t\tif (uniform.arrayLength) {\n\t\t\t\tif (!Array.isArray(value)) {\n\t\t\t\t\tthrow new Error(`${name} is an array, but the value passed to updateUniforms is not an array.`);\n\t\t\t\t}\n\t\t\t\tconst nValues = value.length;\n\t\t\t\tif (!nValues) return;\n\t\t\t\tif (nValues > uniform.arrayLength) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`${name} received ${nValues} values, but maximum length is ${uniform.arrayLength}.`\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (value.some(item => (Array.isArray(item) ? item.length : 1) !== uniform.length)) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Tried to update ${name} with some elements that are not length ${uniform.length}.`\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst typedArray = new (uniform.type === 'float' ? Float32Array : Int32Array)(value.flat());\n\t\t\t\tlet location = uniform.location;\n\t\t\t\tif (options?.startIndex) {\n\t\t\t\t\tconst newLocation = this.gl.getUniformLocation(this.program!, `${name}[${options.startIndex}]`);\n\t\t\t\t\tif (!newLocation) {\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t`${name}[${options.startIndex}] not found in fragment shader. Did you pass an invalid startIndex?`\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tlocation = newLocation;\n\t\t\t\t}\n\t\t\t\t(this.gl as any)[glFunctionName + 'v'](location, typedArray);\n\t\t\t} else {\n\t\t\t\tif (!Array.isArray(value)) value = [value];\n\t\t\t\tif (value.length !== uniform.length) {\n\t\t\t\t\tthrow new Error(`Invalid uniform value length: ${value.length}. Expected ${uniform.length}.`);\n\t\t\t\t}\n\t\t\t\t(this.gl as any)[glFunctionName](uniform.location, ...value);\n\t\t\t}\n\t\t});\n\t\tthis.hooks.get('updateUniforms')?.forEach(hook => hook.call(this, ...arguments));\n\t}\n\n\tprivate createTexture(\n\t\tname: string | symbol,\n\t\ttextureInfo: Pick<Texture, 'width' | 'height' | 'history' | 'options'> & { unitIndex?: number }\n\t) {\n\t\tconst { width, height } = textureInfo;\n\t\tconst historyDepth = textureInfo.history?.depth ?? 0;\n\n\t\tconst texture = this.gl.createTexture();\n\t\tif (!texture) {\n\t\t\tthrow new Error('Failed to create texture');\n\t\t}\n\n\t\tlet unitIndex = textureInfo.unitIndex;\n\t\tif (typeof unitIndex !== 'number') {\n\t\t\ttry {\n\t\t\t\tunitIndex = this.reserveTextureUnit(name);\n\t\t\t} catch (error) {\n\t\t\t\tthis.gl.deleteTexture(texture);\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\n\t\tconst hasHistory = historyDepth > 0;\n\t\tconst textureTarget = hasHistory ? this.gl.TEXTURE_2D_ARRAY : this.gl.TEXTURE_2D;\n\t\tconst { options } = textureInfo;\n\t\tthis.gl.activeTexture(this.gl.TEXTURE0 + unitIndex);\n\t\tthis.gl.bindTexture(textureTarget, texture);\n\t\tthis.gl.texParameteri(textureTarget, this.gl.TEXTURE_WRAP_S, options.wrapS);\n\t\tthis.gl.texParameteri(textureTarget, this.gl.TEXTURE_WRAP_T, options.wrapT);\n\t\tthis.gl.texParameteri(textureTarget, this.gl.TEXTURE_MIN_FILTER, options.minFilter);\n\t\tthis.gl.texParameteri(textureTarget, this.gl.TEXTURE_MAG_FILTER, options.magFilter);\n\t\tif (hasHistory) {\n\t\t\tthis.gl.texStorage3D(textureTarget, 1, options.internalFormat, width, height, historyDepth);\n\t\t} else if (name === INTERMEDIATE_TEXTURE_KEY) {\n\t\t\tthis.gl.texImage2D(\n\t\t\t\tthis.gl.TEXTURE_2D,\n\t\t\t\t0,\n\t\t\t\toptions.internalFormat,\n\t\t\t\twidth,\n\t\t\t\theight,\n\t\t\t\t0,\n\t\t\t\toptions.format,\n\t\t\t\toptions.type,\n\t\t\t\tnull\n\t\t\t);\n\t\t}\n\t\treturn { texture, unitIndex };\n\t}\n\n\tprivate _initializeTexture(\n\t\tname: string | symbol,\n\t\tsource: TextureSource,\n\t\toptions?: TextureOptions & { history?: number }\n\t) {\n\t\tif (this.textures.has(name)) {\n\t\t\tthrow new Error(`Texture '${stringFrom(name)}' is already initialized.`);\n\t\t}\n\n\t\tconst { history: historyDepth = 0, ...textureOptions } = options ?? {};\n\t\tconst { width, height } = getSourceDimensions(source);\n\t\tif (!width || !height) {\n\t\t\tthrow new Error(`Texture source must have valid dimensions`);\n\t\t}\n\t\tconst textureInfo: Pick<Texture, 'width' | 'height' | 'history' | 'options'> = {\n\t\t\twidth,\n\t\t\theight,\n\t\t\toptions: this.resolveTextureOptions(textureOptions),\n\t\t};\n\t\tif (historyDepth > 0) {\n\t\t\ttextureInfo.history = { depth: historyDepth, writeIndex: 0 };\n\t\t}\n\t\tconst { texture, unitIndex } = this.createTexture(name, textureInfo);\n\t\tconst completeTextureInfo: Texture = { texture, unitIndex, ...textureInfo };\n\t\tif (historyDepth > 0) {\n\t\t\tthis.initializeUniform(`${stringFrom(name)}FrameOffset`, 'int', 0);\n\t\t\tthis.clearHistoryTextureLayers(completeTextureInfo);\n\t\t}\n\t\tthis.textures.set(name, completeTextureInfo);\n\t\tthis.updateTexture(name, source);\n\n\t\t// Set a uniform to access the texture in the fragment shader.\n\t\tconst uSampler = this.gl.getUniformLocation(this.program!, stringFrom(name));\n\t\tif (uSampler) {\n\t\t\tthis.gl.uniform1i(uSampler, unitIndex);\n\t\t}\n\t}\n\n\tinitializeTexture(name: string, source: TextureSource, options?: TextureOptions & { history?: number }) {\n\t\tthis._initializeTexture(name, source, options);\n\t\tthis.hooks.get('initializeTexture')?.forEach(hook => hook.call(this, ...arguments));\n\t}\n\n\tupdateTextures(updates: Record<string, UpdateTextureSource>, options?: { skipHistoryWrite?: boolean }) {\n\t\tthis.hooks.get('updateTextures')?.forEach(hook => hook.call(this, ...arguments));\n\t\tObject.entries(updates).forEach(([name, source]) => {\n\t\t\tthis.updateTexture(name, source, options);\n\t\t});\n\t}\n\n\tprivate updateTexture(\n\t\tname: string | symbol,\n\t\tsource: UpdateTextureSource,\n\t\toptions?: { skipHistoryWrite?: boolean }\n\t) {\n\t\tconst info = this.textures.get(name);\n\t\tif (!info) throw new Error(`Texture '${stringFrom(name)}' is not initialized.`);\n\n\t\tif (source instanceof WebGLTexture) {\n\t\t\tthis.gl.activeTexture(this.gl.TEXTURE0 + info.unitIndex);\n\t\t\tthis.gl.bindTexture(this.gl.TEXTURE_2D, source);\n\t\t\treturn;\n\t\t}\n\n\t\t// If dimensions changed, recreate the texture with new dimensions.\n\t\tconst { width, height } = getSourceDimensions(source);\n\t\tif (!width || !height) return;\n\n\t\tconst isPartial = 'isPartial' in source && source.isPartial;\n\t\tif (!isPartial) {\n\t\t\tthis.resizeTexture(name, width, height);\n\t\t}\n\n\t\t// UNPACK_FLIP_Y_WEBGL only works for DOM element sources, not typed arrays.\n\t\tconst isTypedArray = 'data' in source && source.data;\n\t\tconst shouldFlipY = !isTypedArray && !info.options?.preserveY;\n\t\tconst previousFlipY = this.gl.getParameter(this.gl.UNPACK_FLIP_Y_WEBGL);\n\n\t\tif (info.history) {\n\t\t\tthis.gl.activeTexture(this.gl.TEXTURE0 + info.unitIndex);\n\t\t\tthis.gl.bindTexture(this.gl.TEXTURE_2D_ARRAY, info.texture);\n\t\t\tif (!options?.skipHistoryWrite) {\n\t\t\t\tthis.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, shouldFlipY);\n\t\t\t\tthis.gl.texSubImage3D(\n\t\t\t\t\tthis.gl.TEXTURE_2D_ARRAY,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\tinfo.history.writeIndex,\n\t\t\t\t\twidth,\n\t\t\t\t\theight,\n\t\t\t\t\t1,\n\t\t\t\t\tinfo.options.format,\n\t\t\t\t\tinfo.options.type,\n\t\t\t\t\t((source as PartialCustomTexture).data ?? (source as Exclude<TextureSource, CustomTexture>)) as any\n\t\t\t\t);\n\t\t\t\tthis.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, previousFlipY);\n\t\t\t\tconst frameOffsetUniformName = `${stringFrom(name)}FrameOffset`;\n\t\t\t\tthis.updateUniforms({ [frameOffsetUniformName]: info.history.writeIndex });\n\t\t\t\tinfo.history.writeIndex = (info.history.writeIndex + 1) % info.history.depth;\n\t\t\t}\n\t\t} else {\n\t\t\tthis.gl.activeTexture(this.gl.TEXTURE0 + info.unitIndex);\n\t\t\tthis.gl.bindTexture(this.gl.TEXTURE_2D, info.texture);\n\t\t\tthis.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, shouldFlipY);\n\n\t\t\tif (isPartial) {\n\t\t\t\tthis.gl.texSubImage2D(\n\t\t\t\t\tthis.gl.TEXTURE_2D,\n\t\t\t\t\t0,\n\t\t\t\t\tsource.x ?? 0,\n\t\t\t\t\tsource.y ?? 0,\n\t\t\t\t\twidth,\n\t\t\t\t\theight,\n\t\t\t\t\tinfo.options.format,\n\t\t\t\t\tinfo.options.type,\n\t\t\t\t\tsource.data\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tthis.gl.texImage2D(\n\t\t\t\t\tthis.gl.TEXTURE_2D,\n\t\t\t\t\t0,\n\t\t\t\t\tinfo.options.internalFormat,\n\t\t\t\t\twidth,\n\t\t\t\t\theight,\n\t\t\t\t\t0,\n\t\t\t\t\tinfo.options.format,\n\t\t\t\t\tinfo.options.type,\n\t\t\t\t\t((source as PartialCustomTexture).data ?? (source as Exclude<TextureSource, CustomTexture>)) as any\n\t\t\t\t);\n\t\t\t}\n\t\t\tthis.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, previousFlipY);\n\t\t}\n\t}\n\n\tdraw(options?: StepOptions) {\n\t\tconst gl = this.gl;\n\t\tconst w = gl.drawingBufferWidth;\n\t\tconst h = gl.drawingBufferHeight;\n\t\tconst historyInfo = this.textures.get(HISTORY_TEXTURE_KEY);\n\t\tconst intermediateInfo = this.textures.get(INTERMEDIATE_TEXTURE_KEY);\n\t\tconst shouldStoreHistory = historyInfo && !options?.skipHistoryWrite;\n\n\t\tif (shouldStoreHistory) {\n\t\t\t// Render to intermediate texture to avoid feedback loop with history texture\n\t\t\tgl.bindFramebuffer(gl.FRAMEBUFFER, this.intermediateFbo);\n\t\t\tgl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, intermediateInfo!.texture, 0);\n\t\t}\n\n\t\tgl.useProgram(this.program);\n\t\tgl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);\n\t\tgl.vertexAttribPointer(this.aPositionLocation, 2, gl.FLOAT, false, 0, 0);\n\t\tgl.enableVertexAttribArray(this.aPositionLocation);\n\t\tgl.viewport(0, 0, w, h);\n\t\tif (!options?.skipClear) gl.clear(gl.COLOR_BUFFER_BIT);\n\t\tgl.drawArrays(gl.TRIANGLES, 0, 6);\n\n\t\tif (shouldStoreHistory) {\n\t\t\t// Copy to history layer\n\t\t\tgl.bindTexture(gl.TEXTURE_2D_ARRAY, historyInfo.texture);\n\t\t\tgl.copyTexSubImage3D(gl.TEXTURE_2D_ARRAY, 0, 0, 0, historyInfo.history!.writeIndex, 0, 0, w, h);\n\n\t\t\t// Blit to screen\n\t\t\tgl.bindFramebuffer(gl.READ_FRAMEBUFFER, this.intermediateFbo);\n\t\t\tgl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null);\n\t\t\tgl.blitFramebuffer(0, 0, w, h, 0, 0, w, h, gl.COLOR_BUFFER_BIT, gl.NEAREST);\n\t\t\tgl.bindFramebuffer(gl.FRAMEBUFFER, null);\n\t\t}\n\t}\n\n\tstep(time: number, options?: StepOptions) {\n\t\tconst updates: Record<string, number> = {};\n\t\tif (this.uniforms.has('u_time')) updates.u_time = time;\n\t\tif (this.uniforms.has('u_frame')) updates.u_frame = this.frame;\n\t\tthis.updateUniforms(updates);\n\t\tthis.hooks.get('step')?.forEach(hook => hook.call(this, time, this.frame));\n\n\t\tthis.draw(options);\n\n\t\tconst historyInfo = this.textures.get(HISTORY_TEXTURE_KEY);\n\t\tif (historyInfo && !options?.skipHistoryWrite) {\n\t\t\tconst { writeIndex, depth } = historyInfo.history!;\n\t\t\tthis.updateUniforms({ [`${stringFrom(HISTORY_TEXTURE_KEY)}FrameOffset`]: writeIndex });\n\t\t\thistoryInfo.history!.writeIndex = (writeIndex + 1) % depth;\n\t\t}\n\n\t\tthis.hooks.get('afterStep')?.forEach(hook => hook.call(this, time, this.frame));\n\t\t++this.frame;\n\t}\n\n\tplay(\n\t\tonStepComplete?: (time: number, frame: number) => void,\n\t\tsetStepOptions?: (time: number, frame: number) => StepOptions | void\n\t) {\n\t\tthis.pause(); // Prevent double play.\n\t\tconst loop = (time: number) => {\n\t\t\ttime = (time - this.startTime) / 1000; // Convert from milliseconds to seconds.\n\t\t\tconst options = setStepOptions?.(time, this.frame) ?? undefined;\n\t\t\tthis.step(time, options);\n\t\t\tthis.animationFrameId = requestAnimationFrame(loop);\n\t\t\tonStepComplete?.(time, this.frame);\n\t\t};\n\t\tthis.animationFrameId = requestAnimationFrame(loop);\n\t}\n\n\tpause() {\n\t\tif (this.animationFrameId) {\n\t\t\tcancelAnimationFrame(this.animationFrameId);\n\t\t\tthis.animationFrameId = null;\n\t\t}\n\t}\n\n\treset() {\n\t\tthis.frame = 0;\n\t\tthis.startTime = performance.now();\n\t\tthis.textures.forEach(texture => {\n\t\t\tif (texture.history) {\n\t\t\t\ttexture.history.writeIndex = 0;\n\t\t\t\tthis.clearHistoryTextureLayers(texture);\n\t\t\t}\n\t\t});\n\t\tthis.hooks.get('reset')?.forEach(hook => hook.call(this));\n\t}\n\n\tdestroy() {\n\t\tif (this.animationFrameId) {\n\t\t\tcancelAnimationFrame(this.animationFrameId);\n\t\t\tthis.animationFrameId = null;\n\t\t}\n\n\t\tthis.resolutionObserver.disconnect();\n\t\tthis.resizeObserver.disconnect();\n\t\tif (this.canvas instanceof HTMLCanvasElement) {\n\t\t\tthis.eventListeners.forEach((listener, event) => {\n\t\t\t\tthis.canvas.removeEventListener(event, listener);\n\t\t\t});\n\t\t}\n\n\t\tif (this.program) {\n\t\t\tthis.gl.deleteProgram(this.program);\n\t\t}\n\n\t\tif (this.intermediateFbo) {\n\t\t\tthis.gl.deleteFramebuffer(this.intermediateFbo);\n\t\t\tthis.intermediateFbo = null;\n\t\t}\n\n\t\tthis.textures.forEach(texture => {\n\t\t\tthis.gl.deleteTexture(texture.texture);\n\t\t});\n\t\tthis.textureUnitPool.free = [];\n\t\tthis.textureUnitPool.next = 0;\n\n\t\tif (this.buffer) {\n\t\t\tthis.gl.deleteBuffer(this.buffer);\n\t\t\tthis.buffer = null;\n\t\t}\n\n\t\tthis.hooks.get('destroy')?.forEach(hook => hook.call(this));\n\n\t\tif (this.isInternalCanvas && this.canvas instanceof HTMLCanvasElement) {\n\t\t\tthis.canvas.remove();\n\t\t}\n\t}\n}\n\nexport default ShaderPad;\n"],"mappings":"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","names":["DEFAULT_VERTEX_SHADER_SRC","RESIZE_THROTTLE_INTERVAL","HISTORY_TEXTURE_KEY","INTERMEDIATE_TEXTURE_KEY","combineShaderCode","shader","injections","lines","insertAt","line","trimmed","getSourceDimensions","source","stringFrom","name","ShaderPad","fragmentShaderSrc","canvas","plugins","history","debug","textureOptions","htmlCanvas","internalFormat","type","glslInjections","context","code","plugin","fn","vertexShaderSrc","vertexShader","fragmentShader","hook","quadVertices","now","timeUntilNextResize","pixelRatio","width","height","updateCursor","x","y","rect","updateClick","isMouseDown","xVal","yVal","event","mouseEvent","touchEvent","listener","resolution","info","texture","existing","options","gl","textureInfo","format","size","transparent","layer","value","arrayLength","location","probeValue","length","error","args","updates","uniform","glFunctionName","nValues","item","typedArray","newLocation","historyDepth","unitIndex","hasHistory","textureTarget","completeTextureInfo","uSampler","isPartial","shouldFlipY","previousFlipY","frameOffsetUniformName","w","h","historyInfo","intermediateInfo","shouldStoreHistory","time","writeIndex","depth","onStepComplete","setStepOptions","loop","index_default"]}
package/dist/index.d.mts CHANGED
@@ -14,6 +14,7 @@ interface TextureOptions {
14
14
  wrapT?: number;
15
15
  preserveY?: boolean;
16
16
  }
17
+ type ResolvedTextureOptions = Required<Omit<TextureOptions, 'preserveY'>> & Pick<TextureOptions, 'preserveY'>;
17
18
  interface Texture {
18
19
  texture: WebGLTexture;
19
20
  unitIndex: number;
@@ -23,7 +24,7 @@ interface Texture {
23
24
  depth: number;
24
25
  writeIndex: number;
25
26
  };
26
- options?: TextureOptions;
27
+ options: ResolvedTextureOptions;
27
28
  }
28
29
  interface CustomTexture {
29
30
  data: ArrayBufferView | null;
@@ -48,13 +49,17 @@ interface PluginContext {
48
49
  injectGLSL: (code: string) => void;
49
50
  }
50
51
  type Plugin = (shaderPad: ShaderPad, context: PluginContext) => void;
51
- type LifecycleMethod = 'init' | 'step' | 'destroy' | 'updateResolution' | 'reset' | 'initializeTexture' | 'updateTextures' | 'initializeUniform' | 'updateUniforms';
52
- interface Options {
52
+ type LifecycleMethod = 'init' | 'step' | 'afterStep' | 'destroy' | 'updateResolution' | 'reset' | 'initializeTexture' | 'updateTextures' | 'initializeUniform' | 'updateUniforms';
53
+ interface Options extends Exclude<TextureOptions, 'preserveY'> {
53
54
  canvas?: HTMLCanvasElement | OffscreenCanvas | null;
54
55
  plugins?: Plugin[];
55
56
  history?: number;
56
57
  debug?: boolean;
57
58
  }
59
+ interface StepOptions {
60
+ skipClear?: boolean;
61
+ skipHistoryWrite?: boolean;
62
+ }
58
63
  declare class ShaderPad {
59
64
  private isInternalCanvas;
60
65
  private isTouchDevice;
@@ -81,8 +86,10 @@ declare class ShaderPad {
81
86
  onResize?: (width: number, height: number) => void;
82
87
  private hooks;
83
88
  private historyDepth;
89
+ private textureOptions;
84
90
  private debug;
85
- constructor(fragmentShaderSrc: string, options?: Options);
91
+ private intermediateFbo;
92
+ constructor(fragmentShaderSrc: string, { canvas, plugins, history, debug, ...textureOptions }?: Options);
86
93
  registerHook(name: LifecycleMethod, fn: Function): void;
87
94
  private init;
88
95
  private createShader;
@@ -91,8 +98,10 @@ declare class ShaderPad {
91
98
  private handleResize;
92
99
  private addEventListeners;
93
100
  private updateResolution;
101
+ private resizeTexture;
94
102
  private reserveTextureUnit;
95
103
  private releaseTextureUnit;
104
+ private resolveTextureOptions;
96
105
  private clearHistoryTextureLayers;
97
106
  initializeUniform(name: string, type: 'float' | 'int', value: number | number[] | (number | number[])[], options?: {
98
107
  arrayLength?: number;
@@ -106,14 +115,16 @@ declare class ShaderPad {
106
115
  initializeTexture(name: string, source: TextureSource, options?: TextureOptions & {
107
116
  history?: number;
108
117
  }): void;
109
- updateTextures(updates: Record<string, UpdateTextureSource>): void;
118
+ updateTextures(updates: Record<string, UpdateTextureSource>, options?: {
119
+ skipHistoryWrite?: boolean;
120
+ }): void;
110
121
  private updateTexture;
111
- draw(clear?: boolean): void;
112
- step(time: number): void;
113
- play(callback?: (time: number, frame: number) => void): void;
122
+ draw(options?: StepOptions): void;
123
+ step(time: number, options?: StepOptions): void;
124
+ play(onStepComplete?: (time: number, frame: number) => void, setStepOptions?: (time: number, frame: number) => StepOptions | void): void;
114
125
  pause(): void;
115
126
  reset(): void;
116
127
  destroy(): void;
117
128
  }
118
129
 
119
- export { type CustomTexture, type Options, type PartialCustomTexture, type PluginContext, type TextureOptions, type TextureSource, ShaderPad as default };
130
+ export { type CustomTexture, type Options, type PartialCustomTexture, type PluginContext, type StepOptions, type TextureOptions, type TextureSource, ShaderPad as default };