shaderpad 1.0.0-beta.36 → 1.0.0-beta.38

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
@@ -222,9 +222,9 @@ shader.initializeTexture('u_canvas', canvasElement, { preserveY: true });
222
222
 
223
223
  - `history?: number` - Number of previous frames to store (creates a `sampler2DArray`)
224
224
  - `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)
225
+ - `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`
226
+ - `format?: number` - Source data layout (default: `gl.RGBA`). Describes the channels in your input data (e.g., `gl.RGBA`, `gl.RGB`, `gl.R8UI`)
227
+ - `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
228
  - `minFilter?: number` - Minification filter (default: `gl.LINEAR`)
229
229
  - `magFilter?: number` - Magnification filter (default: `gl.LINEAR`)
230
230
  - `wrapS?: number` - Wrap mode for S coordinate (default: `gl.CLAMP_TO_EDGE`)
@@ -322,6 +322,17 @@ const shader = new ShaderPad(fragmentShaderSrc, { history: 10 });
322
322
  // uniform int u_historyFrameOffset;
323
323
  ```
324
324
 
325
+ **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.
326
+
327
+ ```typescript
328
+ // For 32-bit float precision (requires EXT_color_buffer_float extension):
329
+ const shader = new ShaderPad(fragmentShaderSrc, {
330
+ history: 60,
331
+ internalFormat: gl.RGBA32F,
332
+ type: gl.FLOAT,
333
+ });
334
+ ```
335
+
325
336
  You can also enable history for individual textures:
326
337
 
327
338
  ```typescript
@@ -397,6 +408,11 @@ const shader = new ShaderPad(fragmentShaderSrc, {
397
408
  });
398
409
  ```
399
410
 
411
+ **Options:**
412
+
413
+ - `onReady?: () => void` - Callback invoked when initialization is complete and the detection model is loaded
414
+ - `onResults?: (results: FaceLandmarkerResult) => void` - Callback invoked with detection results each frame
415
+
400
416
  **Uniforms:**
401
417
 
402
418
  | Uniform | Type | Description |
@@ -478,6 +494,11 @@ const shader = new ShaderPad(fragmentShaderSrc, {
478
494
  });
479
495
  ```
480
496
 
497
+ **Options:**
498
+
499
+ - `onReady?: () => void` - Callback invoked when initialization is complete and the detection model is loaded
500
+ - `onResults?: (results: PoseLandmarkerResult) => void` - Callback invoked with detection results each frame
501
+
481
502
  **Uniforms:**
482
503
 
483
504
  | Uniform | Type | Description |
@@ -567,6 +588,11 @@ const shader = new ShaderPad(fragmentShaderSrc, {
567
588
  });
568
589
  ```
569
590
 
591
+ **Options:**
592
+
593
+ - `onReady?: () => void` - Callback invoked when initialization is complete and the detection model is loaded
594
+ - `onResults?: (results: HandLandmarkerResult) => void` - Callback invoked with detection results each frame
595
+
570
596
  **Uniforms:**
571
597
 
572
598
  | Uniform | Type | Description |
@@ -638,12 +664,20 @@ const shader = new ShaderPad(fragmentShaderSrc, {
638
664
  modelPath:
639
665
  'https://storage.googleapis.com/mediapipe-models/image_segmenter/selfie_multiclass_256x256/float32/latest/selfie_multiclass_256x256.tflite',
640
666
  outputCategoryMask: true,
667
+ onReady: () => {
668
+ console.log('Selfie multiclass model: loading complete');
669
+ },
641
670
  },
642
671
  }),
643
672
  ],
644
673
  });
645
674
  ```
646
675
 
676
+ **Options:**
677
+
678
+ - `onReady?: () => void` - Callback invoked when initialization is complete and the detection model is loaded
679
+ - `onResults?: (results: ImageSegmenterResult) => void` - Callback invoked with segmentation results each frame
680
+
647
681
  **Uniforms:**
648
682
 
649
683
  | Uniform | Type | Description |
@@ -0,0 +1,11 @@
1
+ var E=`#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(u,e){if(!e?.length)return u;let t=u.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(u){return u instanceof WebGLTexture?{width:0,height:0}:u instanceof HTMLVideoElement?{width:u.videoWidth,height:u.videoHeight}:u instanceof HTMLImageElement?{width:u.naturalWidth??u.width,height:u.naturalHeight??u.height}:{width:u.width,height:u.height}}function f(u){return typeof u=="symbol"?u.description??"":u}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 l=this.canvas;l.style.position="fixed",l.style.inset="0",l.style.height="100dvh",l.style.width="100dvw",document.body.appendChild(l)}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:g}=n;(g===this.gl.FLOAT||g===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 h=[];if(s){let l={gl:this.gl,uniforms:this.uniforms,textures:this.textures,canvas:this.canvas,reserveTextureUnit:this.reserveTextureUnit.bind(this),releaseTextureUnit:this.releaseTextureUnit.bind(this),injectGLSL:c=>{h.push(c)}};Object.defineProperty(l,"program",{get:()=>this.program,enumerable:!0,configurable:!0}),s.forEach(c=>c(this,l))}this.fragmentShaderSrc=v(e,h),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=E;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(),g=r,a=n;this.clickPosition[0]=(g-o.left)/o.width,this.clickPosition[1]=1-(a-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)}clearHistoryTextureLayers(e){if(!e.history)return;let t=this.gl,s=e.options?.type??t.UNSIGNED_BYTE,i=e.width*e.height*4,r=s===t.FLOAT?new Float32Array(i):s===t.HALF_FLOAT?new Uint16Array(i):new Uint8Array(i);t.activeTexture(t.TEXTURE0+e.unitIndex),t.bindTexture(t.TEXTURE_2D_ARRAY,e.texture);for(let n=0;n<e.history.depth;++n)t.texSubImage3D(t.TEXTURE_2D_ARRAY,0,0,0,n,e.width,e.height,1,e.options?.format??t.RGBA,s,r)}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,g=Array.isArray(o)?o.length:1;this.uniforms.set(e,{type:t,length:g,location:n,arrayLength:r});try{this.updateUniforms({[e]:s})}catch(a){throw this.uniforms.delete(e),a}this.hooks.get("initializeUniform")?.forEach(a=>a.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(h=>(Array.isArray(h)?h.length:1)!==r.length))throw new Error(`Tried to update ${s} with some elements that are not length ${r.length}.`);let g=new(r.type==="float"?Float32Array:Int32Array)(i.flat()),a=r.location;if(t?.startIndex){let h=this.gl.getUniformLocation(this.program,`${s}[${t.startIndex}]`);if(!h)throw new Error(`${s}[${t.startIndex}] not found in fragment shader. Did you pass an invalid startIndex?`);a=h}this.gl[n+"v"](a,g)}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(l){throw this.gl.deleteTexture(n),l}let g=r>0,a=g?this.gl.TEXTURE_2D_ARRAY:this.gl.TEXTURE_2D,{options:h}=t;if(this.gl.activeTexture(this.gl.TEXTURE0+o),this.gl.bindTexture(a,n),this.gl.texParameteri(a,this.gl.TEXTURE_WRAP_S,h?.wrapS??this.gl.CLAMP_TO_EDGE),this.gl.texParameteri(a,this.gl.TEXTURE_WRAP_T,h?.wrapT??this.gl.CLAMP_TO_EDGE),this.gl.texParameteri(a,this.gl.TEXTURE_MIN_FILTER,h?.minFilter??this.gl.LINEAR),this.gl.texParameteri(a,this.gl.TEXTURE_MAG_FILTER,h?.magFilter??this.gl.LINEAR),g){let l=h?.type??this.gl.UNSIGNED_BYTE,c=h?.internalFormat??(l===this.gl.FLOAT?this.gl.RGBA32F:this.gl.RGBA8);this.gl.texStorage3D(a,1,c,s,i,r)}return{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 g={width:n,height:o,options:r};i>0&&(g.history={depth:i,writeIndex:0});let{texture:a,unitIndex:h}=this.createTexture(e,g),l={texture:a,unitIndex:h,...g};i>0&&(this.initializeUniform(`${f(e)}FrameOffset`,"int",0),this.clearHistoryTextureLayers(l)),this.textures.set(e,l),this.updateTexture(e,t);let c=this.gl.getUniformLocation(this.program,f(e));c&&this.gl.uniform1i(c,h)}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 g="data"in t&&t.data,a=!g&&!i.options?.preserveY,h=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,a),this.gl.texSubImage3D(this.gl.TEXTURE_2D_ARRAY,0,0,0,i.history.writeIndex,r,n,1,i.options?.format??this.gl.RGBA,i.options?.type??this.gl.UNSIGNED_BYTE,t.data??t),this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,h);let l=`${f(e)}FrameOffset`;this.updateUniforms({[l]: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,a);let l=i.options?.format??this.gl.RGBA,c=i.options?.type??this.gl.UNSIGNED_BYTE;if(o)this.gl.texSubImage2D(this.gl.TEXTURE_2D,0,t.x??0,t.y??0,r,n,l,c,t.data);else{let x=i.options?.internalFormat??(g?c===this.gl.FLOAT?this.gl.RGBA32F:this.gl.RGBA8:this.gl.RGBA);this.gl.texImage2D(this.gl.TEXTURE_2D,0,x,r,n,0,l,c,t.data??t)}this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,h)}}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()}},y=p;export{y as a};
11
+ //# sourceMappingURL=chunk-CRUQQQ46.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}\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?: TextureOptions;\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 clearHistoryTextureLayers(textureInfo: Texture): void {\n\t\tif (!textureInfo.history) return;\n\n\t\tconst gl = this.gl;\n\t\tconst type = textureInfo.options?.type ?? gl.UNSIGNED_BYTE;\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\ttextureInfo.options?.format ?? gl.RGBA,\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 ?? this.gl.CLAMP_TO_EDGE);\n\t\tthis.gl.texParameteri(textureTarget, this.gl.TEXTURE_WRAP_T, options?.wrapT ?? this.gl.CLAMP_TO_EDGE);\n\t\tthis.gl.texParameteri(textureTarget, this.gl.TEXTURE_MIN_FILTER, options?.minFilter ?? this.gl.LINEAR);\n\t\tthis.gl.texParameteri(textureTarget, this.gl.TEXTURE_MAG_FILTER, options?.magFilter ?? this.gl.LINEAR);\n\t\tif (hasHistory) {\n\t\t\tconst type = options?.type ?? this.gl.UNSIGNED_BYTE;\n\t\t\tconst internalFormat =\n\t\t\t\toptions?.internalFormat ?? (type === this.gl.FLOAT ? this.gl.RGBA32F : this.gl.RGBA8);\n\t\t\tthis.gl.texStorage3D(textureTarget, 1, internalFormat, width, height, historyDepth);\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: 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 ?? this.gl.RGBA,\n\t\t\t\t\tinfo.options?.type ?? this.gl.UNSIGNED_BYTE,\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\tconst format = info.options?.format ?? this.gl.RGBA;\n\t\t\tconst type = info.options?.type ?? this.gl.UNSIGNED_BYTE;\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\tformat,\n\t\t\t\t\ttype,\n\t\t\t\t\tsource.data\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tconst internalFormat =\n\t\t\t\t\tinfo.options?.internalFormat ??\n\t\t\t\t\t(isTypedArray ? (type === this.gl.FLOAT ? this.gl.RGBA32F : this.gl.RGBA8) : this.gl.RGBA);\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\tinternalFormat,\n\t\t\t\t\twidth,\n\t\t\t\t\theight,\n\t\t\t\t\t0,\n\t\t\t\t\tformat,\n\t\t\t\t\ttype,\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","textureInfo","gl","size","transparent","layer","value","options","arrayLength","location","probeValue","length","error","args","updates","uniform","glFunctionName","nValues","item","typedArray","newLocation","historyDepth","unitIndex","hasHistory","textureTarget","completeTextureInfo","uSampler","isPartial","isTypedArray","shouldFlipY","previousFlipY","frameOffsetUniformName","format","w","h","historyInfo","intermediateInfo","shouldStoreHistory","time","writeIndex","depth","onStepComplete","setStepOptions","loop","index_default"]}
package/dist/index.d.mts CHANGED
@@ -48,13 +48,17 @@ interface PluginContext {
48
48
  injectGLSL: (code: string) => void;
49
49
  }
50
50
  type Plugin = (shaderPad: ShaderPad, context: PluginContext) => void;
51
- type LifecycleMethod = 'init' | 'step' | 'destroy' | 'updateResolution' | 'reset' | 'initializeTexture' | 'updateTextures' | 'initializeUniform' | 'updateUniforms';
52
- interface Options {
51
+ type LifecycleMethod = 'init' | 'step' | 'afterStep' | 'destroy' | 'updateResolution' | 'reset' | 'initializeTexture' | 'updateTextures' | 'initializeUniform' | 'updateUniforms';
52
+ interface Options extends Exclude<TextureOptions, 'preserveY'> {
53
53
  canvas?: HTMLCanvasElement | OffscreenCanvas | null;
54
54
  plugins?: Plugin[];
55
55
  history?: number;
56
56
  debug?: boolean;
57
57
  }
58
+ interface StepOptions {
59
+ skipClear?: boolean;
60
+ skipHistoryWrite?: boolean;
61
+ }
58
62
  declare class ShaderPad {
59
63
  private isInternalCanvas;
60
64
  private isTouchDevice;
@@ -81,8 +85,10 @@ declare class ShaderPad {
81
85
  onResize?: (width: number, height: number) => void;
82
86
  private hooks;
83
87
  private historyDepth;
88
+ private textureOptions;
84
89
  private debug;
85
- constructor(fragmentShaderSrc: string, options?: Options);
90
+ private intermediateFbo;
91
+ constructor(fragmentShaderSrc: string, { canvas, plugins, history, debug, ...textureOptions }?: Options);
86
92
  registerHook(name: LifecycleMethod, fn: Function): void;
87
93
  private init;
88
94
  private createShader;
@@ -91,6 +97,7 @@ declare class ShaderPad {
91
97
  private handleResize;
92
98
  private addEventListeners;
93
99
  private updateResolution;
100
+ private resizeTexture;
94
101
  private reserveTextureUnit;
95
102
  private releaseTextureUnit;
96
103
  private clearHistoryTextureLayers;
@@ -106,14 +113,16 @@ declare class ShaderPad {
106
113
  initializeTexture(name: string, source: TextureSource, options?: TextureOptions & {
107
114
  history?: number;
108
115
  }): void;
109
- updateTextures(updates: Record<string, UpdateTextureSource>): void;
116
+ updateTextures(updates: Record<string, UpdateTextureSource>, options?: {
117
+ skipHistoryWrite?: boolean;
118
+ }): void;
110
119
  private updateTexture;
111
- draw(clear?: boolean): void;
112
- step(time: number): void;
113
- play(callback?: (time: number, frame: number) => void): void;
120
+ draw(options?: StepOptions): void;
121
+ step(time: number, options?: StepOptions): void;
122
+ play(onStepComplete?: (time: number, frame: number) => void, setStepOptions?: (time: number, frame: number) => StepOptions | void): void;
114
123
  pause(): void;
115
124
  reset(): void;
116
125
  destroy(): void;
117
126
  }
118
127
 
119
- export { type CustomTexture, type Options, type PartialCustomTexture, type PluginContext, type TextureOptions, type TextureSource, ShaderPad as default };
128
+ export { type CustomTexture, type Options, type PartialCustomTexture, type PluginContext, type StepOptions, type TextureOptions, type TextureSource, ShaderPad as default };
package/dist/index.d.ts CHANGED
@@ -48,13 +48,17 @@ interface PluginContext {
48
48
  injectGLSL: (code: string) => void;
49
49
  }
50
50
  type Plugin = (shaderPad: ShaderPad, context: PluginContext) => void;
51
- type LifecycleMethod = 'init' | 'step' | 'destroy' | 'updateResolution' | 'reset' | 'initializeTexture' | 'updateTextures' | 'initializeUniform' | 'updateUniforms';
52
- interface Options {
51
+ type LifecycleMethod = 'init' | 'step' | 'afterStep' | 'destroy' | 'updateResolution' | 'reset' | 'initializeTexture' | 'updateTextures' | 'initializeUniform' | 'updateUniforms';
52
+ interface Options extends Exclude<TextureOptions, 'preserveY'> {
53
53
  canvas?: HTMLCanvasElement | OffscreenCanvas | null;
54
54
  plugins?: Plugin[];
55
55
  history?: number;
56
56
  debug?: boolean;
57
57
  }
58
+ interface StepOptions {
59
+ skipClear?: boolean;
60
+ skipHistoryWrite?: boolean;
61
+ }
58
62
  declare class ShaderPad {
59
63
  private isInternalCanvas;
60
64
  private isTouchDevice;
@@ -81,8 +85,10 @@ declare class ShaderPad {
81
85
  onResize?: (width: number, height: number) => void;
82
86
  private hooks;
83
87
  private historyDepth;
88
+ private textureOptions;
84
89
  private debug;
85
- constructor(fragmentShaderSrc: string, options?: Options);
90
+ private intermediateFbo;
91
+ constructor(fragmentShaderSrc: string, { canvas, plugins, history, debug, ...textureOptions }?: Options);
86
92
  registerHook(name: LifecycleMethod, fn: Function): void;
87
93
  private init;
88
94
  private createShader;
@@ -91,6 +97,7 @@ declare class ShaderPad {
91
97
  private handleResize;
92
98
  private addEventListeners;
93
99
  private updateResolution;
100
+ private resizeTexture;
94
101
  private reserveTextureUnit;
95
102
  private releaseTextureUnit;
96
103
  private clearHistoryTextureLayers;
@@ -106,14 +113,16 @@ declare class ShaderPad {
106
113
  initializeTexture(name: string, source: TextureSource, options?: TextureOptions & {
107
114
  history?: number;
108
115
  }): void;
109
- updateTextures(updates: Record<string, UpdateTextureSource>): void;
116
+ updateTextures(updates: Record<string, UpdateTextureSource>, options?: {
117
+ skipHistoryWrite?: boolean;
118
+ }): void;
110
119
  private updateTexture;
111
- draw(clear?: boolean): void;
112
- step(time: number): void;
113
- play(callback?: (time: number, frame: number) => void): void;
120
+ draw(options?: StepOptions): void;
121
+ step(time: number, options?: StepOptions): void;
122
+ play(onStepComplete?: (time: number, frame: number) => void, setStepOptions?: (time: number, frame: number) => StepOptions | void): void;
114
123
  pause(): void;
115
124
  reset(): void;
116
125
  destroy(): void;
117
126
  }
118
127
 
119
- export { type CustomTexture, type Options, type PartialCustomTexture, type PluginContext, type TextureOptions, type TextureSource, ShaderPad as default };
128
+ export { type CustomTexture, type Options, type PartialCustomTexture, type PluginContext, type StepOptions, type TextureOptions, type TextureSource, ShaderPad as default };
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
- "use strict";var d=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var v=Object.getOwnPropertyNames;var E=Object.prototype.hasOwnProperty;var b=(n,t)=>{for(var e in t)d(n,e,{get:t[e],enumerable:!0})},y=(n,t,e,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of v(t))!E.call(n,r)&&r!==e&&d(n,r,{get:()=>t[r],enumerable:!(i=x(t,r))||i.enumerable});return n};var w=n=>y(d({},"__esModule",{value:!0}),n);var P={};b(P,{default:()=>_});module.exports=w(P);var L=`#version 300 es
1
+ "use strict";var d=Object.defineProperty;var b=Object.getOwnPropertyDescriptor;var v=Object.getOwnPropertyNames;var y=Object.prototype.hasOwnProperty;var R=(a,e)=>{for(var t in e)d(a,t,{get:e[t],enumerable:!0})},w=(a,e,t,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of v(e))!y.call(a,i)&&i!==t&&d(a,i,{get:()=>e[i],enumerable:!(s=b(e,i))||s.enumerable});return a};var L=a=>w(d({},"__esModule",{value:!0}),a);var P={};R(P,{default:()=>U});module.exports=L(P);var F=`#version 300 es
2
2
  in vec2 aPosition;
3
3
  out vec2 v_uv;
4
4
  void main() {
5
5
  v_uv = aPosition * 0.5 + 0.5;
6
6
  gl_Position = vec4(aPosition, 0.0, 1.0);
7
7
  }
8
- `,R=33.333333333333336,f=Symbol("u_history");function U(n,t){if(!t?.length)return n;let e=n.split(`
9
- `),i=e.findLastIndex(r=>{let s=r.trimStart();return s.startsWith("precision ")||s.startsWith("#version ")})+1;return e.splice(i,0,...t),e.join(`
10
- `)}function T(n){return n instanceof WebGLTexture?{width:0,height:0}:n instanceof HTMLVideoElement?{width:n.videoWidth,height:n.videoHeight}:n instanceof HTMLImageElement?{width:n.naturalWidth??n.width,height:n.naturalHeight??n.height}:{width:n.width,height:n.height}}function m(n){return typeof n=="symbol"?n.description??"":n}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;debug;constructor(t,e={}){if(this.canvas=e.canvas||document.createElement("canvas"),!e.canvas){this.isInternalCanvas=!0;let r=this.canvas;r.style.position="fixed",r.style.inset="0",r.style.height="100dvh",r.style.width="100dvw",document.body.appendChild(r)}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.historyDepth=e.history??0,this.debug=e.debug??(typeof process<"u"&&!1),this.animationFrameId=null,this.resolutionObserver=new MutationObserver(()=>this.updateResolution()),this.resizeObserver=new ResizeObserver(()=>this.throttledHandleResize());let i=[];if(e.plugins){let r={gl:this.gl,uniforms:this.uniforms,textures:this.textures,canvas:this.canvas,reserveTextureUnit:this.reserveTextureUnit.bind(this),releaseTextureUnit:this.releaseTextureUnit.bind(this),injectGLSL:s=>{i.push(s)}};Object.defineProperty(r,"program",{get:()=>this.program,enumerable:!0,configurable:!0}),e.plugins.forEach(s=>s(this,r))}this.fragmentShaderSrc=U(t,i),this.init(),this.canvas instanceof HTMLCanvasElement&&this.addEventListeners()}registerHook(t,e){this.hooks.has(t)||this.hooks.set(t,[]),this.hooks.get(t).push(e)}init(){let t=L;if(this.program=this.gl.createProgram(),!this.program)throw new Error("Failed to create WebGL program");let e=this.createShader(this.gl.VERTEX_SHADER,t),i=this.createShader(this.gl.FRAGMENT_SHADER,this.fragmentShaderSrc);if(this.gl.attachShader(this.program,e),this.gl.attachShader(this.program,i),this.gl.linkProgram(this.program),this.gl.deleteShader(e),this.gl.deleteShader(i),!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(f,this.canvas,{history:this.historyDepth}),this.hooks.get("init")?.forEach(r=>r.call(this))}createShader(t,e){let i=this.gl.createShader(t);if(this.gl.shaderSource(i,e),this.gl.compileShader(i),!this.gl.getShaderParameter(i,this.gl.COMPILE_STATUS))throw console.error("Shader compilation failed:",e),console.error(this.gl.getShaderInfoLog(i)),this.gl.deleteShader(i),new Error("Shader compilation failed");return i}setupBuffer(){let t=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,t,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 t=performance.now(),e=this.lastResizeTime+R-t;e<=0?(this.lastResizeTime=t,this.handleResize()):this.resizeTimeout=setTimeout(()=>this.throttledHandleResize(),e)}handleResize(){if(!(this.canvas instanceof HTMLCanvasElement))return;let t=window.devicePixelRatio||1,e=this.canvas.clientWidth*t,i=this.canvas.clientHeight*t;this.isInternalCanvas&&(this.canvas.width!==e||this.canvas.height!==i)&&(this.canvas.width=e,this.canvas.height=i),this.onResize?.(e,i)}addEventListeners(){let t=this.canvas,e=(r,s)=>{if(!this.uniforms.has("u_cursor"))return;let a=t.getBoundingClientRect();this.cursorPosition[0]=(r-a.left)/a.width,this.cursorPosition[1]=1-(s-a.top)/a.height,this.updateUniforms({u_cursor:this.cursorPosition})},i=(r,s,a)=>{if(this.uniforms.has("u_click")){if(this.isMouseDown=r,r){let o=t.getBoundingClientRect(),l=s,u=a;this.clickPosition[0]=(l-o.left)/o.width,this.clickPosition[1]=1-(u-o.top)/o.height}this.updateUniforms({u_click:[...this.clickPosition,this.isMouseDown?1:0]})}};this.eventListeners.set("mousemove",r=>{let s=r;this.isTouchDevice||e(s.clientX,s.clientY)}),this.eventListeners.set("mousedown",r=>{let s=r;this.isTouchDevice||s.button===0&&(this.isMouseDown=!0,i(!0,s.clientX,s.clientY))}),this.eventListeners.set("mouseup",r=>{let s=r;this.isTouchDevice||s.button===0&&i(!1)}),this.eventListeners.set("touchmove",r=>{let s=r;s.touches.length>0&&e(s.touches[0].clientX,s.touches[0].clientY)}),this.eventListeners.set("touchstart",r=>{let s=r;this.isTouchDevice=!0,s.touches.length>0&&(e(s.touches[0].clientX,s.touches[0].clientY),i(!0,s.touches[0].clientX,s.touches[0].clientY))}),this.eventListeners.set("touchend",r=>{r.touches.length===0&&i(!1)}),this.eventListeners.forEach((r,s)=>{t.addEventListener(s,r)})}updateResolution(){let t=[this.gl.drawingBufferWidth,this.gl.drawingBufferHeight];this.gl.viewport(0,0,...t),this.uniforms.has("u_resolution")?this.updateUniforms({u_resolution:t}):this.initializeUniform("u_resolution","float",t),this.hooks.get("updateResolution")?.forEach(e=>e.call(this))}reserveTextureUnit(t){let e=this.textures.get(t);if(e)return e.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(t){let e=this.textures.get(t);e&&this.textureUnitPool.free.push(e.unitIndex)}clearHistoryTextureLayers(t){if(!t.history)return;let e=t.options?.type??this.gl.UNSIGNED_BYTE,i=e===this.gl.FLOAT?new Float32Array(t.width*t.height*4):new Uint8Array(t.width*t.height*4);this.gl.activeTexture(this.gl.TEXTURE0+t.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D_ARRAY,t.texture);for(let r=0;r<t.history.depth;++r)this.gl.texSubImage3D(this.gl.TEXTURE_2D_ARRAY,0,0,0,r,t.width,t.height,1,t.options?.format??this.gl.RGBA,e,i)}initializeUniform(t,e,i,r){let s=r?.arrayLength;if(this.uniforms.has(t))throw new Error(`${t} is already initialized.`);if(e!=="float"&&e!=="int")throw new Error(`Invalid uniform type: ${e}. Expected 'float' or 'int'.`);if(s&&!(Array.isArray(i)&&i.length===s))throw new Error(`${t} array length mismatch: must initialize with ${s} elements.`);let a=this.gl.getUniformLocation(this.program,t);if(!a&&s&&(a=this.gl.getUniformLocation(this.program,`${t}[0]`)),!a){this.log(`${t} not found in fragment shader. Skipping initialization.`);return}let o=s?i[0]:i,l=Array.isArray(o)?o.length:1;this.uniforms.set(t,{type:e,length:l,location:a,arrayLength:s});try{this.updateUniforms({[t]:i})}catch(u){throw this.uniforms.delete(t),u}this.hooks.get("initializeUniform")?.forEach(u=>u.call(this,...arguments))}log(...t){this.debug&&console.debug(...t)}updateUniforms(t,e){this.gl.useProgram(this.program),Object.entries(t).forEach(([i,r])=>{let s=this.uniforms.get(i);if(!s){this.log(`${i} not found in fragment shader. Skipping update.`);return}let a=`uniform${s.length}${s.type.charAt(0)}`;if(s.arrayLength){if(!Array.isArray(r))throw new Error(`${i} is an array, but the value passed to updateUniforms is not an array.`);let o=r.length;if(!o)return;if(o>s.arrayLength)throw new Error(`${i} received ${o} values, but maximum length is ${s.arrayLength}.`);if(r.some(h=>(Array.isArray(h)?h.length:1)!==s.length))throw new Error(`Tried to update ${i} with some elements that are not length ${s.length}.`);let l=new(s.type==="float"?Float32Array:Int32Array)(r.flat()),u=s.location;if(e?.startIndex){let h=this.gl.getUniformLocation(this.program,`${i}[${e.startIndex}]`);if(!h)throw new Error(`${i}[${e.startIndex}] not found in fragment shader. Did you pass an invalid startIndex?`);u=h}this.gl[a+"v"](s.location,l)}else{if(Array.isArray(r)||(r=[r]),r.length!==s.length)throw new Error(`Invalid uniform value length: ${r.length}. Expected ${s.length}.`);this.gl[a](s.location,...r)}}),this.hooks.get("updateUniforms")?.forEach(i=>i.call(this,...arguments))}createTexture(t,e,i){let{width:r,height:s}=e,a=e.history?.depth??0,o=this.gl.createTexture();if(!o)throw new Error("Failed to create texture");let l=i?.unitIndex;if(typeof l!="number")try{l=this.reserveTextureUnit(t)}catch(g){throw this.gl.deleteTexture(o),g}let u=a>0,h=u?this.gl.TEXTURE_2D_ARRAY:this.gl.TEXTURE_2D;if(this.gl.activeTexture(this.gl.TEXTURE0+l),this.gl.bindTexture(h,o),this.gl.texParameteri(h,this.gl.TEXTURE_WRAP_S,i?.wrapS??this.gl.CLAMP_TO_EDGE),this.gl.texParameteri(h,this.gl.TEXTURE_WRAP_T,i?.wrapT??this.gl.CLAMP_TO_EDGE),this.gl.texParameteri(h,this.gl.TEXTURE_MIN_FILTER,i?.minFilter??this.gl.LINEAR),this.gl.texParameteri(h,this.gl.TEXTURE_MAG_FILTER,i?.magFilter??this.gl.LINEAR),u){let g=i?.type??this.gl.UNSIGNED_BYTE,c=i?.internalFormat??(g===this.gl.FLOAT?this.gl.RGBA32F:this.gl.RGBA8);this.gl.texStorage3D(h,1,c,r,s,a)}return{texture:o,unitIndex:l}}_initializeTexture(t,e,i){if(this.textures.has(t))throw new Error(`Texture '${m(t)}' is already initialized.`);let{history:r=0,...s}=i??{},{width:a,height:o}=T(e);if(!a||!o)throw new Error("Texture source must have valid dimensions");let l={width:a,height:o};r>0&&(l.history={depth:r,writeIndex:0});let{texture:u,unitIndex:h}=this.createTexture(t,l,s),g={texture:u,unitIndex:h,...l,options:s};r>0&&(this.initializeUniform(`${m(t)}FrameOffset`,"int",0),this.clearHistoryTextureLayers(g)),this.textures.set(t,g),this.updateTexture(t,e);let c=this.gl.getUniformLocation(this.program,m(t));c&&this.gl.uniform1i(c,h)}initializeTexture(t,e,i){this._initializeTexture(t,e,i),this.hooks.get("initializeTexture")?.forEach(r=>r.call(this,...arguments))}updateTextures(t){this.hooks.get("updateTextures")?.forEach(e=>e.call(this,...arguments)),Object.entries(t).forEach(([e,i])=>{this.updateTexture(e,i)})}updateTexture(t,e){let i=this.textures.get(t);if(!i)throw new Error(`Texture '${m(t)}' is not initialized.`);if(e instanceof WebGLTexture){this.gl.activeTexture(this.gl.TEXTURE0+i.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D,e);return}let{width:r,height:s}=T(e);if(!r||!s)return;let a="isPartial"in e&&e.isPartial;if(!a&&(i.width!==r||i.height!==s)){this.gl.deleteTexture(i.texture),i.width=r,i.height=s;let{texture:h}=this.createTexture(t,i,{...i.options,unitIndex:i.unitIndex});i.texture=h,i.history&&(i.history.writeIndex=0,this.clearHistoryTextureLayers(i))}let o="data"in e&&e.data,l=!o&&!i.options?.preserveY,u=this.gl.getParameter(this.gl.UNPACK_FLIP_Y_WEBGL);if(i.history){let h=t===f;this.gl.activeTexture(this.gl.TEXTURE0+i.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D_ARRAY,i.texture),h?this.gl.copyTexSubImage3D(this.gl.TEXTURE_2D_ARRAY,0,0,0,i.history.writeIndex,0,0,r,s):(this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,l),this.gl.texSubImage3D(this.gl.TEXTURE_2D_ARRAY,0,0,0,i.history.writeIndex,r,s,1,i.options?.format??this.gl.RGBA,i.options?.type??this.gl.UNSIGNED_BYTE,e.data??e),this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,u));let g=`${m(t)}FrameOffset`;this.updateUniforms({[g]: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,l);let h=i.options?.format??this.gl.RGBA,g=i.options?.type??this.gl.UNSIGNED_BYTE;if(a)this.gl.texSubImage2D(this.gl.TEXTURE_2D,0,e.x??0,e.y??0,r,s,h,g,e.data);else{let c=i.options?.internalFormat??(o?g===this.gl.FLOAT?this.gl.RGBA32F:this.gl.RGBA8:this.gl.RGBA);this.gl.texImage2D(this.gl.TEXTURE_2D,0,c,r,s,0,h,g,e.data??e)}this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,u)}}draw(t=!0){let e=this.gl;e.useProgram(this.program),e.bindBuffer(e.ARRAY_BUFFER,this.buffer),e.vertexAttribPointer(this.aPositionLocation,2,e.FLOAT,!1,0,0),e.enableVertexAttribArray(this.aPositionLocation),e.viewport(0,0,e.drawingBufferWidth,e.drawingBufferHeight),t&&e.clear(e.COLOR_BUFFER_BIT),e.drawArrays(e.TRIANGLES,0,6)}step(t){this.uniforms.has("u_time")&&this.updateUniforms({u_time:t}),this.uniforms.has("u_frame")&&this.updateUniforms({u_frame:this.frame}),this.draw(),this.textures.get(f)&&this.updateTexture(f,this.canvas),this.hooks.get("step")?.forEach(e=>e.call(this,t,this.frame)),++this.frame}play(t){this.pause();let e=i=>{i=(i-this.startTime)/1e3,this.step(i),this.animationFrameId=requestAnimationFrame(e),t&&t(i,this.frame)};this.animationFrameId=requestAnimationFrame(e)}pause(){this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null)}reset(){this.frame=0,this.startTime=performance.now(),this.textures.forEach(t=>{t.history&&(t.history.writeIndex=0,this.clearHistoryTextureLayers(t))}),this.hooks.get("reset")?.forEach(t=>t.call(this))}destroy(){this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null),this.resolutionObserver.disconnect(),this.resizeObserver.disconnect(),this.canvas instanceof HTMLCanvasElement&&this.eventListeners.forEach((t,e)=>{this.canvas.removeEventListener(e,t)}),this.program&&this.gl.deleteProgram(this.program),this.textures.forEach(t=>{this.gl.deleteTexture(t.texture)}),this.textureUnitPool.free=[],this.textureUnitPool.next=0,this.buffer&&(this.gl.deleteBuffer(this.buffer),this.buffer=null),this.hooks.get("destroy")?.forEach(t=>t.call(this)),this.isInternalCanvas&&this.canvas instanceof HTMLCanvasElement&&this.canvas.remove()}},_=p;
8
+ `,_=33.333333333333336,m=Symbol("u_history"),p=Symbol("__SHADERPAD_BUFFER");function A(a,e){if(!e?.length)return a;let t=a.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 x(a){return a instanceof WebGLTexture?{width:0,height:0}:a instanceof HTMLVideoElement?{width:a.videoWidth,height:a.videoHeight}:a instanceof HTMLImageElement?{width:a.naturalWidth??a.width,height:a.naturalHeight??a.height}:{width:a.width,height:a.height}}function f(a){return typeof a=="symbol"?a.description??"":a}var T=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 u=this.canvas;u.style.position="fixed",u.style.inset="0",u.style.height="100dvh",u.style.width="100dvw",document.body.appendChild(u)}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:g}=n;(g===this.gl.FLOAT||g===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 l=[];if(s){let u={gl:this.gl,uniforms:this.uniforms,textures:this.textures,canvas:this.canvas,reserveTextureUnit:this.reserveTextureUnit.bind(this),releaseTextureUnit:this.releaseTextureUnit.bind(this),injectGLSL:c=>{l.push(c)}};Object.defineProperty(u,"program",{get:()=>this.program,enumerable:!0,configurable:!0}),s.forEach(c=>c(this,u))}this.fragmentShaderSrc=A(e,l),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=F;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(p,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+_-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(),g=r,h=n;this.clickPosition[0]=(g-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(p,...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)}clearHistoryTextureLayers(e){if(!e.history)return;let t=this.gl,s=e.options?.type??t.UNSIGNED_BYTE,i=e.width*e.height*4,r=s===t.FLOAT?new Float32Array(i):s===t.HALF_FLOAT?new Uint16Array(i):new Uint8Array(i);t.activeTexture(t.TEXTURE0+e.unitIndex),t.bindTexture(t.TEXTURE_2D_ARRAY,e.texture);for(let n=0;n<e.history.depth;++n)t.texSubImage3D(t.TEXTURE_2D_ARRAY,0,0,0,n,e.width,e.height,1,e.options?.format??t.RGBA,s,r)}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,g=Array.isArray(o)?o.length:1;this.uniforms.set(e,{type:t,length:g,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(l=>(Array.isArray(l)?l.length:1)!==r.length))throw new Error(`Tried to update ${s} with some elements that are not length ${r.length}.`);let g=new(r.type==="float"?Float32Array:Int32Array)(i.flat()),h=r.location;if(t?.startIndex){let l=this.gl.getUniformLocation(this.program,`${s}[${t.startIndex}]`);if(!l)throw new Error(`${s}[${t.startIndex}] not found in fragment shader. Did you pass an invalid startIndex?`);h=l}this.gl[n+"v"](h,g)}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(u){throw this.gl.deleteTexture(n),u}let g=r>0,h=g?this.gl.TEXTURE_2D_ARRAY:this.gl.TEXTURE_2D,{options:l}=t;if(this.gl.activeTexture(this.gl.TEXTURE0+o),this.gl.bindTexture(h,n),this.gl.texParameteri(h,this.gl.TEXTURE_WRAP_S,l?.wrapS??this.gl.CLAMP_TO_EDGE),this.gl.texParameteri(h,this.gl.TEXTURE_WRAP_T,l?.wrapT??this.gl.CLAMP_TO_EDGE),this.gl.texParameteri(h,this.gl.TEXTURE_MIN_FILTER,l?.minFilter??this.gl.LINEAR),this.gl.texParameteri(h,this.gl.TEXTURE_MAG_FILTER,l?.magFilter??this.gl.LINEAR),g){let u=l?.type??this.gl.UNSIGNED_BYTE,c=l?.internalFormat??(u===this.gl.FLOAT?this.gl.RGBA32F:this.gl.RGBA8);this.gl.texStorage3D(h,1,c,s,i,r)}return{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}=x(t);if(!n||!o)throw new Error("Texture source must have valid dimensions");let g={width:n,height:o,options:r};i>0&&(g.history={depth:i,writeIndex:0});let{texture:h,unitIndex:l}=this.createTexture(e,g),u={texture:h,unitIndex:l,...g};i>0&&(this.initializeUniform(`${f(e)}FrameOffset`,"int",0),this.clearHistoryTextureLayers(u)),this.textures.set(e,u),this.updateTexture(e,t);let c=this.gl.getUniformLocation(this.program,f(e));c&&this.gl.uniform1i(c,l)}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}=x(t);if(!r||!n)return;let o="isPartial"in t&&t.isPartial;o||this.resizeTexture(e,r,n);let g="data"in t&&t.data,h=!g&&!i.options?.preserveY,l=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??this.gl.RGBA,i.options?.type??this.gl.UNSIGNED_BYTE,t.data??t),this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,l);let u=`${f(e)}FrameOffset`;this.updateUniforms({[u]: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);let u=i.options?.format??this.gl.RGBA,c=i.options?.type??this.gl.UNSIGNED_BYTE;if(o)this.gl.texSubImage2D(this.gl.TEXTURE_2D,0,t.x??0,t.y??0,r,n,u,c,t.data);else{let E=i.options?.internalFormat??(g?c===this.gl.FLOAT?this.gl.RGBA32F:this.gl.RGBA8:this.gl.RGBA);this.gl.texImage2D(this.gl.TEXTURE_2D,0,E,r,n,0,u,c,t.data??t)}this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,l)}}draw(e){let t=this.gl,s=t.drawingBufferWidth,i=t.drawingBufferHeight,r=this.textures.get(m),n=this.textures.get(p),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()}},U=T;
11
11
  //# sourceMappingURL=index.js.map