shaderpad 1.0.0-alpha.13 → 1.0.0-alpha.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -5,7 +5,6 @@ interface Options {
|
|
|
5
5
|
declare class ShaderPad {
|
|
6
6
|
private isInternalCanvas;
|
|
7
7
|
private isTouchDevice;
|
|
8
|
-
private canvas;
|
|
9
8
|
private gl;
|
|
10
9
|
private downloadLink;
|
|
11
10
|
private fragmentShaderSrc;
|
|
@@ -26,6 +25,7 @@ declare class ShaderPad {
|
|
|
26
25
|
private isMouseDown;
|
|
27
26
|
private historyLength;
|
|
28
27
|
private historyTexture;
|
|
28
|
+
canvas: HTMLCanvasElement;
|
|
29
29
|
onResize?: (width: number, height: number) => void;
|
|
30
30
|
constructor(fragmentShaderSrc: string, options?: Options);
|
|
31
31
|
private init;
|
|
@@ -43,9 +43,9 @@ declare class ShaderPad {
|
|
|
43
43
|
play(callback?: (time: number, frame: number) => void): void;
|
|
44
44
|
pause(): void;
|
|
45
45
|
reset(): void;
|
|
46
|
-
save(filename: string): Promise<void>;
|
|
47
46
|
initializeTexture(name: string, source: HTMLImageElement | HTMLVideoElement): void;
|
|
48
47
|
updateTextures(updates: Record<string, HTMLImageElement | HTMLVideoElement>): void;
|
|
48
|
+
save(filename: string): Promise<void>;
|
|
49
49
|
destroy(): void;
|
|
50
50
|
}
|
|
51
51
|
|
package/dist/index.d.ts
CHANGED
|
@@ -5,7 +5,6 @@ interface Options {
|
|
|
5
5
|
declare class ShaderPad {
|
|
6
6
|
private isInternalCanvas;
|
|
7
7
|
private isTouchDevice;
|
|
8
|
-
private canvas;
|
|
9
8
|
private gl;
|
|
10
9
|
private downloadLink;
|
|
11
10
|
private fragmentShaderSrc;
|
|
@@ -26,6 +25,7 @@ declare class ShaderPad {
|
|
|
26
25
|
private isMouseDown;
|
|
27
26
|
private historyLength;
|
|
28
27
|
private historyTexture;
|
|
28
|
+
canvas: HTMLCanvasElement;
|
|
29
29
|
onResize?: (width: number, height: number) => void;
|
|
30
30
|
constructor(fragmentShaderSrc: string, options?: Options);
|
|
31
31
|
private init;
|
|
@@ -43,9 +43,9 @@ declare class ShaderPad {
|
|
|
43
43
|
play(callback?: (time: number, frame: number) => void): void;
|
|
44
44
|
pause(): void;
|
|
45
45
|
reset(): void;
|
|
46
|
-
save(filename: string): Promise<void>;
|
|
47
46
|
initializeTexture(name: string, source: HTMLImageElement | HTMLVideoElement): void;
|
|
48
47
|
updateTextures(updates: Record<string, HTMLImageElement | HTMLVideoElement>): void;
|
|
48
|
+
save(filename: string): Promise<void>;
|
|
49
49
|
destroy(): void;
|
|
50
50
|
}
|
|
51
51
|
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
"use strict";var h=Object.defineProperty;var g=Object.getOwnPropertyDescriptor;var c=Object.getOwnPropertyNames;var f=Object.prototype.hasOwnProperty;var d=(n,t)=>{for(var e in t)h(n,e,{get:t[e],enumerable:!0})},m=(n,t,e,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let
|
|
1
|
+
"use strict";var h=Object.defineProperty;var g=Object.getOwnPropertyDescriptor;var c=Object.getOwnPropertyNames;var f=Object.prototype.hasOwnProperty;var d=(n,t)=>{for(var e in t)h(n,e,{get:t[e],enumerable:!0})},m=(n,t,e,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of c(t))!f.call(n,s)&&s!==e&&h(n,s,{get:()=>t[s],enumerable:!(i=g(t,s))||i.enumerable});return n};var T=n=>m(h({},"__esModule",{value:!0}),n);var p={};d(p,{default:()=>R});module.exports=T(p);var E=`#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
|
-
`,v=33.333333333333336,o=class{constructor(t,e={}){this.isInternalCanvas=!1;this.isTouchDevice=!1;this.uniforms=new Map;this.textures=new Map;this.buffer=null;this.program=null;this.resizeTimeout=null;this.lastResizeTime=0;this.eventListeners=new Map;this.frame=0;this.startTime=0;this.cursorPosition=[.5,.5];this.clickPosition=[.5,.5];this.isMouseDown=!1;this.historyTexture=null;if(this.canvas=e.canvas||document.createElement("canvas"),this.historyLength=e.history||0,e.canvas||(this.isInternalCanvas=!0,document.body.appendChild(this.canvas),this.canvas.style.position="fixed",this.canvas.style.inset="0",this.canvas.style.height="100dvh",this.canvas.style.width="100dvw"),this.gl=this.canvas.getContext("webgl2",{antialias:!1}),!this.gl)throw new Error("WebGL2 not supported. Please use a browser that supports WebGL2.");this.downloadLink=document.createElement("a"),this.fragmentShaderSrc=t,this.animationFrameId=null,this.resolutionObserver=new MutationObserver(()=>this.updateResolution()),this.resizeObserver=new ResizeObserver(()=>this.throttledHandleResize()),this.init(),this.addEventListeners()}init(){let t=E;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");let r=this.gl.getAttribLocation(this.program,"aPosition");this.setupBuffer(r),this.gl.useProgram(this.program),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.historyLength>0&&this.initializeHistoryBuffer()}initializeHistoryBuffer(){let{gl:t}=this;if(this.historyTexture=t.createTexture(),!this.historyTexture)throw new Error("Failed to create history texture");t.bindTexture(t.TEXTURE_2D_ARRAY,this.historyTexture),t.texParameteri(t.TEXTURE_2D_ARRAY,t.TEXTURE_WRAP_S,t.CLAMP_TO_EDGE),t.texParameteri(t.TEXTURE_2D_ARRAY,t.TEXTURE_WRAP_T,t.CLAMP_TO_EDGE),t.texParameteri(t.TEXTURE_2D_ARRAY,t.TEXTURE_MIN_FILTER,t.NEAREST),t.texParameteri(t.TEXTURE_2D_ARRAY,t.TEXTURE_MAG_FILTER,t.NEAREST),t.texStorage3D(t.TEXTURE_2D_ARRAY,1,t.RGBA8,this.gl.drawingBufferWidth,this.gl.drawingBufferHeight,this.historyLength),t.activeTexture(t.TEXTURE0),t.bindTexture(t.TEXTURE_2D_ARRAY,this.historyTexture),this.clearHistory(),this.uniforms.has("u_history")||this.initializeUniform("u_history","int",0)}clearHistory(){let t=new Uint8Array(this.gl.drawingBufferWidth*this.gl.drawingBufferHeight*4);for(let e=0;e<this.historyLength;++e)this.gl.texSubImage3D(this.gl.TEXTURE_2D_ARRAY,0,0,0,e,this.gl.drawingBufferWidth,this.gl.drawingBufferHeight,1,this.gl.RGBA,this.gl.UNSIGNED_BYTE,t)}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(t){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(t),this.gl.vertexAttribPointer(t,2,this.gl.FLOAT,!1,0,0)}throttledHandleResize(){clearTimeout(this.resizeTimeout);let t=performance.now(),e=this.lastResizeTime+v-t;e<=0?(this.lastResizeTime=t,this.handleResize()):this.resizeTimeout=setTimeout(()=>this.throttledHandleResize(),e)}handleResize(){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=(i,r)=>{if(!this.uniforms.has("u_cursor"))return;let s=this.canvas.getBoundingClientRect();this.cursorPosition[0]=(i-s.left)/s.width,this.cursorPosition[1]=1-(r-s.top)/s.height,this.updateUniforms({u_cursor:this.cursorPosition})},e=(i,r,s)=>{if(this.uniforms.has("u_click")){if(this.isMouseDown=i,i){let a=this.canvas.getBoundingClientRect(),l=r,u=s;this.clickPosition[0]=(l-a.left)/a.width,this.clickPosition[1]=1-(u-a.top)/a.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,e(!0,r.clientX,r.clientY))}),this.eventListeners.set("mouseup",i=>{let r=i;this.isTouchDevice||r.button===0&&e(!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),e(!0,r.touches[0].clientX,r.touches[0].clientY))}),this.eventListeners.set("touchend",i=>{i.touches.length===0&&e(!1)}),this.eventListeners.forEach((i,r)=>{this.canvas.addEventListener(r,i)})}updateResolution(){let t=this.gl.drawingBufferWidth,e=this.gl.drawingBufferHeight;this.gl.viewport(0,0,t,e),this.uniforms.has("u_resolution")?this.updateUniforms({u_resolution:[t,e]}):this.initializeUniform("u_resolution","float",[t,e]),this.historyLength>0&&this.historyTexture&&(this.gl.deleteTexture(this.historyTexture),this.initializeHistoryBuffer())}initializeUniform(t,e,i){if(this.uniforms.has(t))throw new Error(`Uniform '${t}' is already initialized.`);if(e!=="float"&&e!=="int")throw new Error(`Invalid uniform type: ${e}. Expected 'float' or 'int'.`);let r=this.gl.getUniformLocation(this.program,t);if(!r){console.debug(`Uniform ${t} not found in fragment shader. Skipping initialization.`);return}if(Array.isArray(i)||(i=[i]),i.length<1||i.length>4)throw new Error(`Invalid uniform value length: ${i.length}. Expected a length between 1 and 4.`);let s=i.length;this.uniforms.set(t,{type:e,length:s,location:r}),this.updateUniforms({[t]:i})}updateUniforms(t){Object.entries(t).forEach(([e,i])=>{if(!this.uniforms.has(e))throw new Error(`Uniform '${e}' is not initialized.`);let r=this.uniforms.get(e);if(Array.isArray(i)||(i=[i]),i.length!==r.length)throw new Error(`Invalid uniform value length: ${i.length}. Expected ${r.length}.`);this.gl[`uniform${r.length}${r.type.charAt(0)}`](r.location,...i)})}step(t){let e=this.gl;if(this.uniforms.has("u_time")&&this.updateUniforms({u_time:t}),this.uniforms.has("u_frame")&&this.updateUniforms({u_frame:this.frame}),this.historyLength>0){let i=this.frame%this.historyLength;e.bindFramebuffer(e.FRAMEBUFFER,null),e.viewport(0,0,this.gl.drawingBufferWidth,this.gl.drawingBufferHeight),e.clear(e.COLOR_BUFFER_BIT),e.drawArrays(e.TRIANGLES,0,6),e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D_ARRAY,this.historyTexture),e.copyTexSubImage3D(e.TEXTURE_2D_ARRAY,0,0,0,i,0,0,this.gl.drawingBufferWidth,this.gl.drawingBufferHeight)}else e.clear(e.COLOR_BUFFER_BIT),e.drawArrays(e.TRIANGLES,0,6);++this.frame}play(t){let e=i=>{i=(i-this.startTime)/1e3,this.step(i),t&&t(i,this.frame),this.animationFrameId=requestAnimationFrame(e)};this.animationFrameId=requestAnimationFrame(e)}pause(){this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null)}reset(){this.frame=0,this.startTime=performance.now(),this.clearHistory()}async save(t){if(this.gl.clear(this.gl.COLOR_BUFFER_BIT),this.gl.drawArrays(this.gl.TRIANGLES,0,6),t&&!`${t}`.toLowerCase().endsWith(".png")&&(t=`${t}.png`),t=t||"export.png",navigator.canShare?.()&&/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent))try{let e=await new Promise(r=>this.canvas.toBlob(r,"image/png")),i=new File([e],t,{type:"image/png"});if(navigator.canShare({files:[i]})){await navigator.share({files:[i],title:t,text:"Exported image"});return}}catch(e){console.warn("Web Share API failed:",e)}else this.downloadLink.download=t,this.downloadLink.href=this.canvas.toDataURL(),this.downloadLink.click()}initializeTexture(t,e){if(this.textures.has(t))throw new Error(`Texture '${t}' is already initialized.`);let i=this.gl.createTexture();if(!i)throw new Error("Failed to create texture");let r=this.textures.size+1;this.gl.activeTexture(this.gl.TEXTURE0+r),this.gl.bindTexture(this.gl.TEXTURE_2D,i),this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,!0),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_WRAP_S,this.gl.CLAMP_TO_EDGE),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_WRAP_T,this.gl.CLAMP_TO_EDGE),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MIN_FILTER,this.gl.LINEAR),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MAG_FILTER,this.gl.LINEAR),this.textures.set(t,{texture:i,unitIndex:r}),this.updateTextures({[t]:e});let s=this.gl.getUniformLocation(this.program,t);s&&this.gl.uniform1i(s,r)}updateTextures(t){Object.entries(t).forEach(([e,i])=>{let r=this.textures.get(e);if(!r)throw new Error(`Texture '${e}' is not initialized.`);this.gl.activeTexture(this.gl.TEXTURE0+r.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D,r.texture),this.gl.texImage2D(this.gl.TEXTURE_2D,0,this.gl.RGBA,this.gl.RGBA,this.gl.UNSIGNED_BYTE,i)})}destroy(){this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null),this.resolutionObserver.disconnect(),this.resizeObserver.disconnect(),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.historyTexture&&(this.gl.deleteTexture(this.historyTexture),this.historyTexture=null),this.buffer&&(this.gl.deleteBuffer(this.buffer),this.buffer=null),this.isInternalCanvas&&this.canvas.remove()}},R=o;
|
|
8
|
+
`,v=33.333333333333336,o=class{constructor(t,e={}){this.isInternalCanvas=!1;this.isTouchDevice=!1;this.uniforms=new Map;this.textures=new Map;this.buffer=null;this.program=null;this.resizeTimeout=null;this.lastResizeTime=0;this.eventListeners=new Map;this.frame=0;this.startTime=0;this.cursorPosition=[.5,.5];this.clickPosition=[.5,.5];this.isMouseDown=!1;this.historyTexture=null;if(this.canvas=e.canvas||document.createElement("canvas"),this.historyLength=e.history||0,e.canvas||(this.isInternalCanvas=!0,document.body.appendChild(this.canvas),this.canvas.style.position="fixed",this.canvas.style.inset="0",this.canvas.style.height="100dvh",this.canvas.style.width="100dvw"),this.gl=this.canvas.getContext("webgl2",{antialias:!1}),!this.gl)throw new Error("WebGL2 not supported. Please use a browser that supports WebGL2.");this.downloadLink=document.createElement("a"),this.fragmentShaderSrc=t,this.animationFrameId=null,this.resolutionObserver=new MutationObserver(()=>this.updateResolution()),this.resizeObserver=new ResizeObserver(()=>this.throttledHandleResize()),this.init(),this.addEventListeners()}init(){let t=E;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");let s=this.gl.getAttribLocation(this.program,"aPosition");this.setupBuffer(s),this.gl.useProgram(this.program),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.historyLength>0&&this.initializeHistoryBuffer()}initializeHistoryBuffer(){let{gl:t}=this;if(this.historyTexture=t.createTexture(),!this.historyTexture)throw new Error("Failed to create history texture");t.bindTexture(t.TEXTURE_2D_ARRAY,this.historyTexture),t.texParameteri(t.TEXTURE_2D_ARRAY,t.TEXTURE_WRAP_S,t.CLAMP_TO_EDGE),t.texParameteri(t.TEXTURE_2D_ARRAY,t.TEXTURE_WRAP_T,t.CLAMP_TO_EDGE),t.texParameteri(t.TEXTURE_2D_ARRAY,t.TEXTURE_MIN_FILTER,t.NEAREST),t.texParameteri(t.TEXTURE_2D_ARRAY,t.TEXTURE_MAG_FILTER,t.NEAREST),t.texStorage3D(t.TEXTURE_2D_ARRAY,1,t.RGBA8,this.gl.drawingBufferWidth,this.gl.drawingBufferHeight,this.historyLength),t.activeTexture(t.TEXTURE0),t.bindTexture(t.TEXTURE_2D_ARRAY,this.historyTexture),this.clearHistory(),this.uniforms.has("u_history")||this.initializeUniform("u_history","int",0)}clearHistory(){let t=new Uint8Array(this.gl.drawingBufferWidth*this.gl.drawingBufferHeight*4);for(let e=0;e<this.historyLength;++e)this.gl.texSubImage3D(this.gl.TEXTURE_2D_ARRAY,0,0,0,e,this.gl.drawingBufferWidth,this.gl.drawingBufferHeight,1,this.gl.RGBA,this.gl.UNSIGNED_BYTE,t)}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(t){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(t),this.gl.vertexAttribPointer(t,2,this.gl.FLOAT,!1,0,0)}throttledHandleResize(){clearTimeout(this.resizeTimeout);let t=performance.now(),e=this.lastResizeTime+v-t;e<=0?(this.lastResizeTime=t,this.handleResize()):this.resizeTimeout=setTimeout(()=>this.throttledHandleResize(),e)}handleResize(){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=(i,s)=>{if(!this.uniforms.has("u_cursor"))return;let r=this.canvas.getBoundingClientRect();this.cursorPosition[0]=(i-r.left)/r.width,this.cursorPosition[1]=1-(s-r.top)/r.height,this.updateUniforms({u_cursor:this.cursorPosition})},e=(i,s,r)=>{if(this.uniforms.has("u_click")){if(this.isMouseDown=i,i){let a=this.canvas.getBoundingClientRect(),l=s,u=r;this.clickPosition[0]=(l-a.left)/a.width,this.clickPosition[1]=1-(u-a.top)/a.height}this.updateUniforms({u_click:[...this.clickPosition,this.isMouseDown?1:0]})}};this.eventListeners.set("mousemove",i=>{let s=i;this.isTouchDevice||t(s.clientX,s.clientY)}),this.eventListeners.set("mousedown",i=>{let s=i;this.isTouchDevice||s.button===0&&(this.isMouseDown=!0,e(!0,s.clientX,s.clientY))}),this.eventListeners.set("mouseup",i=>{let s=i;this.isTouchDevice||s.button===0&&e(!1)}),this.eventListeners.set("touchmove",i=>{let s=i;s.touches.length>0&&t(s.touches[0].clientX,s.touches[0].clientY)}),this.eventListeners.set("touchstart",i=>{let s=i;this.isTouchDevice=!0,s.touches.length>0&&(t(s.touches[0].clientX,s.touches[0].clientY),e(!0,s.touches[0].clientX,s.touches[0].clientY))}),this.eventListeners.set("touchend",i=>{i.touches.length===0&&e(!1)}),this.eventListeners.forEach((i,s)=>{this.canvas.addEventListener(s,i)})}updateResolution(){let t=this.gl.drawingBufferWidth,e=this.gl.drawingBufferHeight;this.gl.viewport(0,0,t,e),this.uniforms.has("u_resolution")?this.updateUniforms({u_resolution:[t,e]}):this.initializeUniform("u_resolution","float",[t,e]),this.historyLength>0&&this.historyTexture&&(this.gl.deleteTexture(this.historyTexture),this.initializeHistoryBuffer())}initializeUniform(t,e,i){if(this.uniforms.has(t))throw new Error(`Uniform '${t}' is already initialized.`);if(e!=="float"&&e!=="int")throw new Error(`Invalid uniform type: ${e}. Expected 'float' or 'int'.`);let s=this.gl.getUniformLocation(this.program,t);if(!s){console.debug(`Uniform ${t} not found in fragment shader. Skipping initialization.`);return}if(Array.isArray(i)||(i=[i]),i.length<1||i.length>4)throw new Error(`Invalid uniform value length: ${i.length}. Expected a length between 1 and 4.`);let r=i.length;this.uniforms.set(t,{type:e,length:r,location:s}),this.updateUniforms({[t]:i})}updateUniforms(t){Object.entries(t).forEach(([e,i])=>{if(!this.uniforms.has(e))throw new Error(`Uniform '${e}' is not initialized.`);let s=this.uniforms.get(e);if(Array.isArray(i)||(i=[i]),i.length!==s.length)throw new Error(`Invalid uniform value length: ${i.length}. Expected ${s.length}.`);this.gl[`uniform${s.length}${s.type.charAt(0)}`](s.location,...i)})}step(t){let e=this.gl;if(this.uniforms.has("u_time")&&this.updateUniforms({u_time:t}),this.uniforms.has("u_frame")&&this.updateUniforms({u_frame:this.frame}),this.historyLength>0){let i=this.frame%this.historyLength;e.bindFramebuffer(e.FRAMEBUFFER,null),e.viewport(0,0,this.gl.drawingBufferWidth,this.gl.drawingBufferHeight),e.clear(e.COLOR_BUFFER_BIT),e.drawArrays(e.TRIANGLES,0,6),e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D_ARRAY,this.historyTexture),e.copyTexSubImage3D(e.TEXTURE_2D_ARRAY,0,0,0,i,0,0,this.gl.drawingBufferWidth,this.gl.drawingBufferHeight)}else e.clear(e.COLOR_BUFFER_BIT),e.drawArrays(e.TRIANGLES,0,6);++this.frame}play(t){let e=i=>{i=(i-this.startTime)/1e3,this.step(i),t&&t(i,this.frame),this.animationFrameId=requestAnimationFrame(e)};this.animationFrameId=requestAnimationFrame(e)}pause(){this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null)}reset(){this.frame=0,this.startTime=performance.now(),this.clearHistory()}initializeTexture(t,e){if(this.textures.has(t))throw new Error(`Texture '${t}' is already initialized.`);let i=this.gl.createTexture();if(!i)throw new Error("Failed to create texture");let s=this.textures.size+1;this.gl.activeTexture(this.gl.TEXTURE0+s),this.gl.bindTexture(this.gl.TEXTURE_2D,i),this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,!0),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_WRAP_S,this.gl.CLAMP_TO_EDGE),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_WRAP_T,this.gl.CLAMP_TO_EDGE),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MIN_FILTER,this.gl.LINEAR),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MAG_FILTER,this.gl.LINEAR),this.textures.set(t,{texture:i,unitIndex:s}),this.updateTextures({[t]:e});let r=this.gl.getUniformLocation(this.program,t);r&&this.gl.uniform1i(r,s)}updateTextures(t){Object.entries(t).forEach(([e,i])=>{let s=this.textures.get(e);if(!s)throw new Error(`Texture '${e}' is not initialized.`);this.gl.activeTexture(this.gl.TEXTURE0+s.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D,s.texture),this.gl.texImage2D(this.gl.TEXTURE_2D,0,this.gl.RGBA,this.gl.RGBA,this.gl.UNSIGNED_BYTE,i)})}async save(t){if(this.gl.clear(this.gl.COLOR_BUFFER_BIT),this.gl.drawArrays(this.gl.TRIANGLES,0,6),t&&!`${t}`.toLowerCase().endsWith(".png")&&(t=`${t}.png`),t=t||"export.png","ongesturechange"in window)try{let e=await new Promise(s=>this.canvas.toBlob(s,"image/png")),i=new File([e],t,{type:e.type});if(navigator.canShare?.({files:[i]})){await navigator.share({files:[i]});return}}catch(e){console.warn("Web Share API failed:",e)}else this.downloadLink.download=t,this.downloadLink.href=this.canvas.toDataURL(),this.downloadLink.click()}destroy(){this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null),this.resolutionObserver.disconnect(),this.resizeObserver.disconnect(),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.historyTexture&&(this.gl.deleteTexture(this.historyTexture),this.historyTexture=null),this.buffer&&(this.gl.deleteBuffer(this.buffer),this.buffer=null),this.isInternalCanvas&&this.canvas.remove()}},R=o;
|
|
9
9
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +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}\n\ninterface Texture {\n\ttexture: WebGLTexture;\n\tunitIndex: number;\n}\n\ninterface Options {\n\tcanvas?: HTMLCanvasElement | null;\n\thistory?: number;\n}\n\nclass ShaderPad {\n\tprivate isInternalCanvas = false;\n\tprivate isTouchDevice = false;\n\tprivate canvas: HTMLCanvasElement;\n\tprivate gl: WebGL2RenderingContext;\n\tprivate downloadLink: HTMLAnchorElement;\n\tprivate fragmentShaderSrc: string;\n\tprivate uniforms: Map<string, Uniform> = new Map();\n\tprivate textures: Map<string, Texture> = new Map();\n\tprivate buffer: WebGLBuffer | null = null;\n\tprivate program: WebGLProgram | null = null;\n\tprivate animationFrameId: number | null;\n\tprivate resolutionObserver: MutationObserver;\n\tprivate resizeObserver: ResizeObserver;\n\tprivate resizeTimeout: NodeJS.Timeout = null as unknown as NodeJS.Timeout;\n\tprivate lastResizeTime = 0;\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\tprivate historyLength: number;\n\tprivate historyTexture: WebGLTexture | null = null;\n\tpublic onResize?: (width: number, height: number) => void;\n\n\tconstructor(fragmentShaderSrc: string, options: Options = {}) {\n\t\tthis.canvas = options.canvas || document.createElement('canvas');\n\t\tthis.historyLength = options.history || 0;\n\t\tif (!options.canvas) {\n\t\t\tthis.isInternalCanvas = true;\n\t\t\tdocument.body.appendChild(this.canvas);\n\t\t\tthis.canvas.style.position = 'fixed';\n\t\t\tthis.canvas.style.inset = '0';\n\t\t\tthis.canvas.style.height = '100dvh';\n\t\t\tthis.canvas.style.width = '100dvw';\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.downloadLink = document.createElement('a');\n\t\tthis.fragmentShaderSrc = fragmentShaderSrc;\n\t\tthis.animationFrameId = null;\n\t\tthis.resolutionObserver = new MutationObserver(() => this.updateResolution());\n\t\tthis.resizeObserver = new ResizeObserver(() => this.throttledHandleResize());\n\n\t\tthis.init();\n\t\tthis.addEventListeners();\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\tconst aPosition = this.gl.getAttribLocation(this.program, 'aPosition');\n\t\tthis.setupBuffer(aPosition);\n\n\t\tthis.gl.useProgram(this.program);\n\n\t\tthis.resolutionObserver.observe(this.canvas, { attributes: true, attributeFilter: ['width', 'height'] });\n\t\tthis.resizeObserver.observe(this.canvas);\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\t\tif (this.historyLength > 0) {\n\t\t\tthis.initializeHistoryBuffer();\n\t\t}\n\t}\n\n\tprivate initializeHistoryBuffer() {\n\t\tconst { gl } = this;\n\n\t\tthis.historyTexture = gl.createTexture();\n\t\tif (!this.historyTexture) {\n\t\t\tthrow new Error('Failed to create history texture');\n\t\t}\n\n\t\tgl.bindTexture(gl.TEXTURE_2D_ARRAY, this.historyTexture);\n\t\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n\t\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n\t\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_MIN_FILTER, gl.NEAREST);\n\t\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_MAG_FILTER, gl.NEAREST);\n\t\tgl.texStorage3D(\n\t\t\tgl.TEXTURE_2D_ARRAY,\n\t\t\t1,\n\t\t\tgl.RGBA8,\n\t\t\tthis.gl.drawingBufferWidth,\n\t\t\tthis.gl.drawingBufferHeight,\n\t\t\tthis.historyLength\n\t\t);\n\t\tgl.activeTexture(gl.TEXTURE0);\n\t\tgl.bindTexture(gl.TEXTURE_2D_ARRAY, this.historyTexture);\n\n\t\tthis.clearHistory();\n\n\t\tif (!this.uniforms.has('u_history')) {\n\t\t\tthis.initializeUniform('u_history', 'int', 0);\n\t\t}\n\t}\n\n\tprivate clearHistory() {\n\t\tconst transparent = new Uint8Array(this.gl.drawingBufferWidth * this.gl.drawingBufferHeight * 4); // All zeroes.\n\t\tfor (let layer = 0; layer < this.historyLength; ++layer) {\n\t\t\tthis.gl.texSubImage3D(\n\t\t\t\tthis.gl.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\tthis.gl.drawingBufferWidth,\n\t\t\t\tthis.gl.drawingBufferHeight,\n\t\t\t\t1,\n\t\t\t\tthis.gl.RGBA,\n\t\t\t\tthis.gl.UNSIGNED_BYTE,\n\t\t\t\ttransparent\n\t\t\t);\n\t\t}\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(aPosition: number) {\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(aPosition);\n\t\tthis.gl.vertexAttribPointer(aPosition, 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\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 updateCursor = (x: number, y: number) => {\n\t\t\tif (!this.uniforms.has('u_cursor')) return;\n\t\t\tconst rect = this.canvas.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 = this.canvas.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\tthis.canvas.addEventListener(event, listener);\n\t\t});\n\t}\n\n\tprivate updateResolution() {\n\t\tconst width = this.gl.drawingBufferWidth;\n\t\tconst height = this.gl.drawingBufferHeight;\n\t\tthis.gl.viewport(0, 0, width, height);\n\t\tif (this.uniforms.has('u_resolution')) {\n\t\t\tthis.updateUniforms({ u_resolution: [width, height] });\n\t\t} else {\n\t\t\tthis.initializeUniform('u_resolution', 'float', [width, height]);\n\t\t}\n\n\t\t// Delete and recreate history buffer, since the canvas size won’t be correct anymore.\n\t\tif (this.historyLength > 0 && this.historyTexture) {\n\t\t\tthis.gl.deleteTexture(this.historyTexture);\n\t\t\tthis.initializeHistoryBuffer();\n\t\t}\n\t}\n\n\tinitializeUniform(name: string, type: 'float' | 'int', value: number | number[]) {\n\t\tif (this.uniforms.has(name)) {\n\t\t\tthrow new Error(`Uniform '${name}' is already initialized.`);\n\t\t}\n\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\n\t\tconst location = this.gl.getUniformLocation(this.program!, name);\n\t\tif (!location) {\n\t\t\tconsole.debug(`Uniform ${name} not found in fragment shader. Skipping initialization.`);\n\t\t\treturn;\n\t\t}\n\n\t\tif (!Array.isArray(value)) {\n\t\t\tvalue = [value];\n\t\t}\n\t\tif (value.length < 1 || value.length > 4) {\n\t\t\tthrow new Error(`Invalid uniform value length: ${value.length}. Expected a length between 1 and 4.`);\n\t\t}\n\n\t\tconst length = value.length as 1 | 2 | 3 | 4;\n\t\tthis.uniforms.set(name, { type, length, location });\n\t\tthis.updateUniforms({ [name]: value });\n\t}\n\n\tupdateUniforms(updates: Record<string, number | number[]>) {\n\t\tObject.entries(updates).forEach(([name, value]: [string, number | number[]]) => {\n\t\t\tif (!this.uniforms.has(name)) {\n\t\t\t\tthrow new Error(`Uniform '${name}' is not initialized.`);\n\t\t\t}\n\n\t\t\tconst uniform = this.uniforms.get(name)!;\n\t\t\tif (!Array.isArray(value)) {\n\t\t\t\tvalue = [value];\n\t\t\t}\n\t\t\tif (value.length !== uniform.length) {\n\t\t\t\tthrow new Error(`Invalid uniform value length: ${value.length}. Expected ${uniform.length}.`);\n\t\t\t}\n\t\t\t(this.gl as any)[`uniform${uniform.length}${uniform.type.charAt(0)}`](uniform.location, ...value);\n\t\t});\n\t}\n\n\tstep(time: number) {\n\t\tconst gl = this.gl;\n\n\t\tif (this.uniforms.has('u_time')) {\n\t\t\tthis.updateUniforms({ u_time: time });\n\t\t}\n\t\tif (this.uniforms.has('u_frame')) {\n\t\t\tthis.updateUniforms({ u_frame: this.frame });\n\t\t}\n\n\t\tif (this.historyLength > 0) {\n\t\t\tconst writeIdx = this.frame % this.historyLength;\n\n\t\t\tgl.bindFramebuffer(gl.FRAMEBUFFER, null);\n\t\t\tgl.viewport(0, 0, this.gl.drawingBufferWidth, this.gl.drawingBufferHeight);\n\t\t\tgl.clear(gl.COLOR_BUFFER_BIT);\n\t\t\tgl.drawArrays(gl.TRIANGLES, 0, 6);\n\n\t\t\tgl.activeTexture(gl.TEXTURE0);\n\t\t\tgl.bindTexture(gl.TEXTURE_2D_ARRAY, this.historyTexture);\n\t\t\tgl.copyTexSubImage3D(\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\twriteIdx,\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t\tthis.gl.drawingBufferWidth,\n\t\t\t\tthis.gl.drawingBufferHeight\n\t\t\t);\n\t\t} else {\n\t\t\tgl.clear(gl.COLOR_BUFFER_BIT);\n\t\t\tgl.drawArrays(gl.TRIANGLES, 0, 6);\n\t\t}\n\n\t\t++this.frame;\n\t}\n\n\tplay(callback?: (time: number, frame: number) => void) {\n\t\tconst loop = (time: number) => {\n\t\t\ttime = (time - this.startTime) / 1000; // Convert from milliseconds to seconds.\n\t\t\tthis.step(time);\n\t\t\tif (callback) callback(time, this.frame);\n\t\t\tthis.animationFrameId = requestAnimationFrame(loop);\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.clearHistory();\n\t}\n\n\tasync save(filename: string) {\n\t\tthis.gl.clear(this.gl.COLOR_BUFFER_BIT);\n\t\tthis.gl.drawArrays(this.gl.TRIANGLES, 0, 6);\n\n\t\tif (filename && !`${filename}`.toLowerCase().endsWith('.png')) {\n\t\t\tfilename = `${filename}.png`;\n\t\t}\n\t\tfilename = filename || 'export.png';\n\n\t\tif (\n\t\t\tnavigator.canShare?.() &&\n\t\t\t/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)\n\t\t) {\n\t\t\ttry {\n\t\t\t\tconst blob: Blob = await new Promise(resolve =>\n\t\t\t\t\tthis.canvas.toBlob(resolve as BlobCallback, 'image/png')\n\t\t\t\t);\n\t\t\t\tconst file = new File([blob], filename, { type: 'image/png' });\n\n\t\t\t\tif (navigator.canShare({ files: [file] })) {\n\t\t\t\t\tawait navigator.share({\n\t\t\t\t\t\tfiles: [file],\n\t\t\t\t\t\ttitle: filename,\n\t\t\t\t\t\ttext: 'Exported image',\n\t\t\t\t\t});\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconsole.warn('Web Share API failed:', error);\n\t\t\t}\n\t\t} else {\n\t\t\tthis.downloadLink.download = filename;\n\t\t\tthis.downloadLink.href = this.canvas.toDataURL();\n\t\t\tthis.downloadLink.click();\n\t\t}\n\t}\n\n\tinitializeTexture(name: string, source: HTMLImageElement | HTMLVideoElement) {\n\t\tif (this.textures.has(name)) {\n\t\t\tthrow new Error(`Texture '${name}' is already initialized.`);\n\t\t}\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\t\tconst unitIndex = this.textures.size + 1; // Start from unit 1 to avoid conflict with history texture at unit 0.\n\t\tthis.gl.activeTexture(this.gl.TEXTURE0 + unitIndex);\n\t\tthis.gl.bindTexture(this.gl.TEXTURE_2D, texture);\n\n\t\t// Flip the texture vertically since v_uv is flipped, and set up filters and wrapping.\n\t\tthis.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, true);\n\t\tthis.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);\n\t\tthis.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);\n\t\tthis.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR);\n\t\tthis.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.LINEAR);\n\n\t\tthis.textures.set(name, { texture, unitIndex });\n\t\tthis.updateTextures({ [name]: source });\n\n\t\tconst uSampler = this.gl.getUniformLocation(this.program!, name);\n\t\tif (uSampler) {\n\t\t\tthis.gl.uniform1i(uSampler, unitIndex);\n\t\t}\n\t}\n\n\tupdateTextures(updates: Record<string, HTMLImageElement | HTMLVideoElement>) {\n\t\tObject.entries(updates).forEach(([name, source]) => {\n\t\t\tconst info = this.textures.get(name);\n\t\t\tif (!info) {\n\t\t\t\tthrow new Error(`Texture '${name}' is not initialized.`);\n\t\t\t}\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.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, this.gl.RGBA, this.gl.UNSIGNED_BYTE, source);\n\t\t});\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\tthis.eventListeners.forEach((listener, event) => {\n\t\t\tthis.canvas.removeEventListener(event, listener);\n\t\t});\n\n\t\tif (this.program) {\n\t\t\tthis.gl.deleteProgram(this.program);\n\t\t}\n\n\t\tthis.textures.forEach(texture => {\n\t\t\tthis.gl.deleteTexture(texture.texture);\n\t\t});\n\n\t\tif (this.historyTexture) {\n\t\t\tthis.gl.deleteTexture(this.historyTexture);\n\t\t\tthis.historyTexture = null;\n\t\t}\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\tif (this.isInternalCanvas) {\n\t\t\tthis.canvas.remove();\n\t\t}\n\t}\n}\n\nexport default ShaderPad;\n"],"mappings":"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","names":["index_exports","__export","index_default","__toCommonJS","DEFAULT_VERTEX_SHADER_SRC","RESIZE_THROTTLE_INTERVAL","ShaderPad","fragmentShaderSrc","options","vertexShaderSrc","vertexShader","fragmentShader","aPosition","gl","transparent","layer","type","source","shader","quadVertices","now","timeUntilNextResize","pixelRatio","width","height","updateCursor","x","y","rect","updateClick","isMouseDown","xVal","yVal","event","mouseEvent","touchEvent","listener","name","value","location","length","updates","uniform","time","writeIdx","callback","loop","filename","blob","resolve","file","error","texture","unitIndex","uSampler","info"]}
|
|
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}\n\ninterface Texture {\n\ttexture: WebGLTexture;\n\tunitIndex: number;\n}\n\ninterface Options {\n\tcanvas?: HTMLCanvasElement | null;\n\thistory?: number;\n}\n\nclass ShaderPad {\n\tprivate isInternalCanvas = false;\n\tprivate isTouchDevice = false;\n\tprivate gl: WebGL2RenderingContext;\n\tprivate downloadLink: HTMLAnchorElement;\n\tprivate fragmentShaderSrc: string;\n\tprivate uniforms: Map<string, Uniform> = new Map();\n\tprivate textures: Map<string, Texture> = new Map();\n\tprivate buffer: WebGLBuffer | null = null;\n\tprivate program: WebGLProgram | null = null;\n\tprivate animationFrameId: number | null;\n\tprivate resolutionObserver: MutationObserver;\n\tprivate resizeObserver: ResizeObserver;\n\tprivate resizeTimeout: NodeJS.Timeout = null as unknown as NodeJS.Timeout;\n\tprivate lastResizeTime = 0;\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\tprivate historyLength: number;\n\tprivate historyTexture: WebGLTexture | null = null;\n\tpublic canvas: HTMLCanvasElement;\n\tpublic onResize?: (width: number, height: number) => void;\n\n\tconstructor(fragmentShaderSrc: string, options: Options = {}) {\n\t\tthis.canvas = options.canvas || document.createElement('canvas');\n\t\tthis.historyLength = options.history || 0;\n\t\tif (!options.canvas) {\n\t\t\tthis.isInternalCanvas = true;\n\t\t\tdocument.body.appendChild(this.canvas);\n\t\t\tthis.canvas.style.position = 'fixed';\n\t\t\tthis.canvas.style.inset = '0';\n\t\t\tthis.canvas.style.height = '100dvh';\n\t\t\tthis.canvas.style.width = '100dvw';\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.downloadLink = document.createElement('a');\n\t\tthis.fragmentShaderSrc = fragmentShaderSrc;\n\t\tthis.animationFrameId = null;\n\t\tthis.resolutionObserver = new MutationObserver(() => this.updateResolution());\n\t\tthis.resizeObserver = new ResizeObserver(() => this.throttledHandleResize());\n\n\t\tthis.init();\n\t\tthis.addEventListeners();\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\tconst aPosition = this.gl.getAttribLocation(this.program, 'aPosition');\n\t\tthis.setupBuffer(aPosition);\n\n\t\tthis.gl.useProgram(this.program);\n\n\t\tthis.resolutionObserver.observe(this.canvas, { attributes: true, attributeFilter: ['width', 'height'] });\n\t\tthis.resizeObserver.observe(this.canvas);\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\t\tif (this.historyLength > 0) {\n\t\t\tthis.initializeHistoryBuffer();\n\t\t}\n\t}\n\n\tprivate initializeHistoryBuffer() {\n\t\tconst { gl } = this;\n\n\t\tthis.historyTexture = gl.createTexture();\n\t\tif (!this.historyTexture) {\n\t\t\tthrow new Error('Failed to create history texture');\n\t\t}\n\n\t\tgl.bindTexture(gl.TEXTURE_2D_ARRAY, this.historyTexture);\n\t\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n\t\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n\t\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_MIN_FILTER, gl.NEAREST);\n\t\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_MAG_FILTER, gl.NEAREST);\n\t\tgl.texStorage3D(\n\t\t\tgl.TEXTURE_2D_ARRAY,\n\t\t\t1,\n\t\t\tgl.RGBA8,\n\t\t\tthis.gl.drawingBufferWidth,\n\t\t\tthis.gl.drawingBufferHeight,\n\t\t\tthis.historyLength\n\t\t);\n\t\tgl.activeTexture(gl.TEXTURE0);\n\t\tgl.bindTexture(gl.TEXTURE_2D_ARRAY, this.historyTexture);\n\n\t\tthis.clearHistory();\n\n\t\tif (!this.uniforms.has('u_history')) {\n\t\t\tthis.initializeUniform('u_history', 'int', 0);\n\t\t}\n\t}\n\n\tprivate clearHistory() {\n\t\tconst transparent = new Uint8Array(this.gl.drawingBufferWidth * this.gl.drawingBufferHeight * 4); // All zeroes.\n\t\tfor (let layer = 0; layer < this.historyLength; ++layer) {\n\t\t\tthis.gl.texSubImage3D(\n\t\t\t\tthis.gl.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\tthis.gl.drawingBufferWidth,\n\t\t\t\tthis.gl.drawingBufferHeight,\n\t\t\t\t1,\n\t\t\t\tthis.gl.RGBA,\n\t\t\t\tthis.gl.UNSIGNED_BYTE,\n\t\t\t\ttransparent\n\t\t\t);\n\t\t}\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(aPosition: number) {\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(aPosition);\n\t\tthis.gl.vertexAttribPointer(aPosition, 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\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 updateCursor = (x: number, y: number) => {\n\t\t\tif (!this.uniforms.has('u_cursor')) return;\n\t\t\tconst rect = this.canvas.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 = this.canvas.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\tthis.canvas.addEventListener(event, listener);\n\t\t});\n\t}\n\n\tprivate updateResolution() {\n\t\tconst width = this.gl.drawingBufferWidth;\n\t\tconst height = this.gl.drawingBufferHeight;\n\t\tthis.gl.viewport(0, 0, width, height);\n\t\tif (this.uniforms.has('u_resolution')) {\n\t\t\tthis.updateUniforms({ u_resolution: [width, height] });\n\t\t} else {\n\t\t\tthis.initializeUniform('u_resolution', 'float', [width, height]);\n\t\t}\n\n\t\t// Delete and recreate history buffer, since the canvas size won’t be correct anymore.\n\t\tif (this.historyLength > 0 && this.historyTexture) {\n\t\t\tthis.gl.deleteTexture(this.historyTexture);\n\t\t\tthis.initializeHistoryBuffer();\n\t\t}\n\t}\n\n\tinitializeUniform(name: string, type: 'float' | 'int', value: number | number[]) {\n\t\tif (this.uniforms.has(name)) {\n\t\t\tthrow new Error(`Uniform '${name}' is already initialized.`);\n\t\t}\n\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\n\t\tconst location = this.gl.getUniformLocation(this.program!, name);\n\t\tif (!location) {\n\t\t\tconsole.debug(`Uniform ${name} not found in fragment shader. Skipping initialization.`);\n\t\t\treturn;\n\t\t}\n\n\t\tif (!Array.isArray(value)) {\n\t\t\tvalue = [value];\n\t\t}\n\t\tif (value.length < 1 || value.length > 4) {\n\t\t\tthrow new Error(`Invalid uniform value length: ${value.length}. Expected a length between 1 and 4.`);\n\t\t}\n\n\t\tconst length = value.length as 1 | 2 | 3 | 4;\n\t\tthis.uniforms.set(name, { type, length, location });\n\t\tthis.updateUniforms({ [name]: value });\n\t}\n\n\tupdateUniforms(updates: Record<string, number | number[]>) {\n\t\tObject.entries(updates).forEach(([name, value]: [string, number | number[]]) => {\n\t\t\tif (!this.uniforms.has(name)) {\n\t\t\t\tthrow new Error(`Uniform '${name}' is not initialized.`);\n\t\t\t}\n\n\t\t\tconst uniform = this.uniforms.get(name)!;\n\t\t\tif (!Array.isArray(value)) {\n\t\t\t\tvalue = [value];\n\t\t\t}\n\t\t\tif (value.length !== uniform.length) {\n\t\t\t\tthrow new Error(`Invalid uniform value length: ${value.length}. Expected ${uniform.length}.`);\n\t\t\t}\n\t\t\t(this.gl as any)[`uniform${uniform.length}${uniform.type.charAt(0)}`](uniform.location, ...value);\n\t\t});\n\t}\n\n\tstep(time: number) {\n\t\tconst gl = this.gl;\n\n\t\tif (this.uniforms.has('u_time')) {\n\t\t\tthis.updateUniforms({ u_time: time });\n\t\t}\n\t\tif (this.uniforms.has('u_frame')) {\n\t\t\tthis.updateUniforms({ u_frame: this.frame });\n\t\t}\n\n\t\tif (this.historyLength > 0) {\n\t\t\tconst writeIdx = this.frame % this.historyLength;\n\n\t\t\tgl.bindFramebuffer(gl.FRAMEBUFFER, null);\n\t\t\tgl.viewport(0, 0, this.gl.drawingBufferWidth, this.gl.drawingBufferHeight);\n\t\t\tgl.clear(gl.COLOR_BUFFER_BIT);\n\t\t\tgl.drawArrays(gl.TRIANGLES, 0, 6);\n\n\t\t\tgl.activeTexture(gl.TEXTURE0);\n\t\t\tgl.bindTexture(gl.TEXTURE_2D_ARRAY, this.historyTexture);\n\t\t\tgl.copyTexSubImage3D(\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\twriteIdx,\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t\tthis.gl.drawingBufferWidth,\n\t\t\t\tthis.gl.drawingBufferHeight\n\t\t\t);\n\t\t} else {\n\t\t\tgl.clear(gl.COLOR_BUFFER_BIT);\n\t\t\tgl.drawArrays(gl.TRIANGLES, 0, 6);\n\t\t}\n\n\t\t++this.frame;\n\t}\n\n\tplay(callback?: (time: number, frame: number) => void) {\n\t\tconst loop = (time: number) => {\n\t\t\ttime = (time - this.startTime) / 1000; // Convert from milliseconds to seconds.\n\t\t\tthis.step(time);\n\t\t\tif (callback) callback(time, this.frame);\n\t\t\tthis.animationFrameId = requestAnimationFrame(loop);\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.clearHistory();\n\t}\n\n\tinitializeTexture(name: string, source: HTMLImageElement | HTMLVideoElement) {\n\t\tif (this.textures.has(name)) {\n\t\t\tthrow new Error(`Texture '${name}' is already initialized.`);\n\t\t}\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\t\tconst unitIndex = this.textures.size + 1; // Start from unit 1 to avoid conflict with history texture at unit 0.\n\t\tthis.gl.activeTexture(this.gl.TEXTURE0 + unitIndex);\n\t\tthis.gl.bindTexture(this.gl.TEXTURE_2D, texture);\n\n\t\t// Flip the texture vertically since v_uv is flipped, and set up filters and wrapping.\n\t\tthis.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, true);\n\t\tthis.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);\n\t\tthis.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);\n\t\tthis.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR);\n\t\tthis.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.LINEAR);\n\n\t\tthis.textures.set(name, { texture, unitIndex });\n\t\tthis.updateTextures({ [name]: source });\n\n\t\tconst uSampler = this.gl.getUniformLocation(this.program!, name);\n\t\tif (uSampler) {\n\t\t\tthis.gl.uniform1i(uSampler, unitIndex);\n\t\t}\n\t}\n\n\tupdateTextures(updates: Record<string, HTMLImageElement | HTMLVideoElement>) {\n\t\tObject.entries(updates).forEach(([name, source]) => {\n\t\t\tconst info = this.textures.get(name);\n\t\t\tif (!info) {\n\t\t\t\tthrow new Error(`Texture '${name}' is not initialized.`);\n\t\t\t}\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.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, this.gl.RGBA, this.gl.UNSIGNED_BYTE, source);\n\t\t});\n\t}\n\n\tasync save(filename: string) {\n\t\tthis.gl.clear(this.gl.COLOR_BUFFER_BIT);\n\t\tthis.gl.drawArrays(this.gl.TRIANGLES, 0, 6);\n\n\t\tif (filename && !`${filename}`.toLowerCase().endsWith('.png')) {\n\t\t\tfilename = `${filename}.png`;\n\t\t}\n\t\tfilename = filename || 'export.png';\n\t\tif ('ongesturechange' in window) {\n\t\t\t// Mobile.\n\t\t\ttry {\n\t\t\t\tconst blob: Blob = await new Promise(resolve =>\n\t\t\t\t\tthis.canvas.toBlob(resolve as BlobCallback, 'image/png')\n\t\t\t\t);\n\t\t\t\tconst file = new File([blob], filename, { type: blob.type });\n\n\t\t\t\tif (navigator.canShare?.({ files: [file] })) {\n\t\t\t\t\tawait navigator.share({ files: [file] });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconsole.warn('Web Share API failed:', error);\n\t\t\t}\n\t\t} else {\n\t\t\t// Desktop.\n\t\t\tthis.downloadLink.download = filename;\n\t\t\tthis.downloadLink.href = this.canvas.toDataURL();\n\t\t\tthis.downloadLink.click();\n\t\t}\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\tthis.eventListeners.forEach((listener, event) => {\n\t\t\tthis.canvas.removeEventListener(event, listener);\n\t\t});\n\n\t\tif (this.program) {\n\t\t\tthis.gl.deleteProgram(this.program);\n\t\t}\n\n\t\tthis.textures.forEach(texture => {\n\t\t\tthis.gl.deleteTexture(texture.texture);\n\t\t});\n\n\t\tif (this.historyTexture) {\n\t\t\tthis.gl.deleteTexture(this.historyTexture);\n\t\t\tthis.historyTexture = null;\n\t\t}\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\tif (this.isInternalCanvas) {\n\t\t\tthis.canvas.remove();\n\t\t}\n\t}\n}\n\nexport default ShaderPad;\n"],"mappings":"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","names":["index_exports","__export","index_default","__toCommonJS","DEFAULT_VERTEX_SHADER_SRC","RESIZE_THROTTLE_INTERVAL","ShaderPad","fragmentShaderSrc","options","vertexShaderSrc","vertexShader","fragmentShader","aPosition","gl","transparent","layer","type","source","shader","quadVertices","now","timeUntilNextResize","pixelRatio","width","height","updateCursor","x","y","rect","updateClick","isMouseDown","xVal","yVal","event","mouseEvent","touchEvent","listener","name","value","location","length","updates","uniform","time","writeIdx","callback","loop","texture","unitIndex","uSampler","info","filename","blob","resolve","file","error"]}
|
package/dist/index.mjs
CHANGED
|
@@ -5,5 +5,5 @@ void main() {
|
|
|
5
5
|
v_uv = aPosition * 0.5 + 0.5;
|
|
6
6
|
gl_Position = vec4(aPosition, 0.0, 1.0);
|
|
7
7
|
}
|
|
8
|
-
`,u=33.333333333333336,a=class{constructor(t,e={}){this.isInternalCanvas=!1;this.isTouchDevice=!1;this.uniforms=new Map;this.textures=new Map;this.buffer=null;this.program=null;this.resizeTimeout=null;this.lastResizeTime=0;this.eventListeners=new Map;this.frame=0;this.startTime=0;this.cursorPosition=[.5,.5];this.clickPosition=[.5,.5];this.isMouseDown=!1;this.historyTexture=null;if(this.canvas=e.canvas||document.createElement("canvas"),this.historyLength=e.history||0,e.canvas||(this.isInternalCanvas=!0,document.body.appendChild(this.canvas),this.canvas.style.position="fixed",this.canvas.style.inset="0",this.canvas.style.height="100dvh",this.canvas.style.width="100dvw"),this.gl=this.canvas.getContext("webgl2",{antialias:!1}),!this.gl)throw new Error("WebGL2 not supported. Please use a browser that supports WebGL2.");this.downloadLink=document.createElement("a"),this.fragmentShaderSrc=t,this.animationFrameId=null,this.resolutionObserver=new MutationObserver(()=>this.updateResolution()),this.resizeObserver=new ResizeObserver(()=>this.throttledHandleResize()),this.init(),this.addEventListeners()}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");let r=this.gl.getAttribLocation(this.program,"aPosition");this.setupBuffer(r),this.gl.useProgram(this.program),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.historyLength>0&&this.initializeHistoryBuffer()}initializeHistoryBuffer(){let{gl:t}=this;if(this.historyTexture=t.createTexture(),!this.historyTexture)throw new Error("Failed to create history texture");t.bindTexture(t.TEXTURE_2D_ARRAY,this.historyTexture),t.texParameteri(t.TEXTURE_2D_ARRAY,t.TEXTURE_WRAP_S,t.CLAMP_TO_EDGE),t.texParameteri(t.TEXTURE_2D_ARRAY,t.TEXTURE_WRAP_T,t.CLAMP_TO_EDGE),t.texParameteri(t.TEXTURE_2D_ARRAY,t.TEXTURE_MIN_FILTER,t.NEAREST),t.texParameteri(t.TEXTURE_2D_ARRAY,t.TEXTURE_MAG_FILTER,t.NEAREST),t.texStorage3D(t.TEXTURE_2D_ARRAY,1,t.RGBA8,this.gl.drawingBufferWidth,this.gl.drawingBufferHeight,this.historyLength),t.activeTexture(t.TEXTURE0),t.bindTexture(t.TEXTURE_2D_ARRAY,this.historyTexture),this.clearHistory(),this.uniforms.has("u_history")||this.initializeUniform("u_history","int",0)}clearHistory(){let t=new Uint8Array(this.gl.drawingBufferWidth*this.gl.drawingBufferHeight*4);for(let e=0;e<this.historyLength;++e)this.gl.texSubImage3D(this.gl.TEXTURE_2D_ARRAY,0,0,0,e,this.gl.drawingBufferWidth,this.gl.drawingBufferHeight,1,this.gl.RGBA,this.gl.UNSIGNED_BYTE,t)}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(t){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(t),this.gl.vertexAttribPointer(t,2,this.gl.FLOAT,!1,0,0)}throttledHandleResize(){clearTimeout(this.resizeTimeout);let t=performance.now(),e=this.lastResizeTime+u-t;e<=0?(this.lastResizeTime=t,this.handleResize()):this.resizeTimeout=setTimeout(()=>this.throttledHandleResize(),e)}handleResize(){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=(i,r)=>{if(!this.uniforms.has("u_cursor"))return;let s=this.canvas.getBoundingClientRect();this.cursorPosition[0]=(i-s.left)/s.width,this.cursorPosition[1]=1-(r-s.top)/s.height,this.updateUniforms({u_cursor:this.cursorPosition})},e=(i,r,s)=>{if(this.uniforms.has("u_click")){if(this.isMouseDown=i,i){let n=this.canvas.getBoundingClientRect(),h=r,o=s;this.clickPosition[0]=(h-n.left)/n.width,this.clickPosition[1]=1-(o-n.top)/n.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,e(!0,r.clientX,r.clientY))}),this.eventListeners.set("mouseup",i=>{let r=i;this.isTouchDevice||r.button===0&&e(!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),e(!0,r.touches[0].clientX,r.touches[0].clientY))}),this.eventListeners.set("touchend",i=>{i.touches.length===0&&e(!1)}),this.eventListeners.forEach((i,r)=>{this.canvas.addEventListener(r,i)})}updateResolution(){let t=this.gl.drawingBufferWidth,e=this.gl.drawingBufferHeight;this.gl.viewport(0,0,t,e),this.uniforms.has("u_resolution")?this.updateUniforms({u_resolution:[t,e]}):this.initializeUniform("u_resolution","float",[t,e]),this.historyLength>0&&this.historyTexture&&(this.gl.deleteTexture(this.historyTexture),this.initializeHistoryBuffer())}initializeUniform(t,e,i){if(this.uniforms.has(t))throw new Error(`Uniform '${t}' is already initialized.`);if(e!=="float"&&e!=="int")throw new Error(`Invalid uniform type: ${e}. Expected 'float' or 'int'.`);let r=this.gl.getUniformLocation(this.program,t);if(!r){console.debug(`Uniform ${t} not found in fragment shader. Skipping initialization.`);return}if(Array.isArray(i)||(i=[i]),i.length<1||i.length>4)throw new Error(`Invalid uniform value length: ${i.length}. Expected a length between 1 and 4.`);let s=i.length;this.uniforms.set(t,{type:e,length:s,location:r}),this.updateUniforms({[t]:i})}updateUniforms(t){Object.entries(t).forEach(([e,i])=>{if(!this.uniforms.has(e))throw new Error(`Uniform '${e}' is not initialized.`);let r=this.uniforms.get(e);if(Array.isArray(i)||(i=[i]),i.length!==r.length)throw new Error(`Invalid uniform value length: ${i.length}. Expected ${r.length}.`);this.gl[`uniform${r.length}${r.type.charAt(0)}`](r.location,...i)})}step(t){let e=this.gl;if(this.uniforms.has("u_time")&&this.updateUniforms({u_time:t}),this.uniforms.has("u_frame")&&this.updateUniforms({u_frame:this.frame}),this.historyLength>0){let i=this.frame%this.historyLength;e.bindFramebuffer(e.FRAMEBUFFER,null),e.viewport(0,0,this.gl.drawingBufferWidth,this.gl.drawingBufferHeight),e.clear(e.COLOR_BUFFER_BIT),e.drawArrays(e.TRIANGLES,0,6),e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D_ARRAY,this.historyTexture),e.copyTexSubImage3D(e.TEXTURE_2D_ARRAY,0,0,0,i,0,0,this.gl.drawingBufferWidth,this.gl.drawingBufferHeight)}else e.clear(e.COLOR_BUFFER_BIT),e.drawArrays(e.TRIANGLES,0,6);++this.frame}play(t){let e=i=>{i=(i-this.startTime)/1e3,this.step(i),t&&t(i,this.frame),this.animationFrameId=requestAnimationFrame(e)};this.animationFrameId=requestAnimationFrame(e)}pause(){this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null)}reset(){this.frame=0,this.startTime=performance.now(),this.clearHistory()}async save(t){if(this.gl.clear(this.gl.COLOR_BUFFER_BIT),this.gl.drawArrays(this.gl.TRIANGLES,0,6),t&&!`${t}`.toLowerCase().endsWith(".png")&&(t=`${t}.png`),t=t||"export.png",navigator.canShare?.()&&/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent))try{let e=await new Promise(r=>this.canvas.toBlob(r,"image/png")),i=new File([e],t,{type:"image/png"});if(navigator.canShare({files:[i]})){await navigator.share({files:[i],title:t,text:"Exported image"});return}}catch(e){console.warn("Web Share API failed:",e)}else this.downloadLink.download=t,this.downloadLink.href=this.canvas.toDataURL(),this.downloadLink.click()}initializeTexture(t,e){if(this.textures.has(t))throw new Error(`Texture '${t}' is already initialized.`);let i=this.gl.createTexture();if(!i)throw new Error("Failed to create texture");let r=this.textures.size+1;this.gl.activeTexture(this.gl.TEXTURE0+r),this.gl.bindTexture(this.gl.TEXTURE_2D,i),this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,!0),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_WRAP_S,this.gl.CLAMP_TO_EDGE),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_WRAP_T,this.gl.CLAMP_TO_EDGE),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MIN_FILTER,this.gl.LINEAR),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MAG_FILTER,this.gl.LINEAR),this.textures.set(t,{texture:i,unitIndex:r}),this.updateTextures({[t]:e});let s=this.gl.getUniformLocation(this.program,t);s&&this.gl.uniform1i(s,r)}updateTextures(t){Object.entries(t).forEach(([e,i])=>{let r=this.textures.get(e);if(!r)throw new Error(`Texture '${e}' is not initialized.`);this.gl.activeTexture(this.gl.TEXTURE0+r.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D,r.texture),this.gl.texImage2D(this.gl.TEXTURE_2D,0,this.gl.RGBA,this.gl.RGBA,this.gl.UNSIGNED_BYTE,i)})}destroy(){this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null),this.resolutionObserver.disconnect(),this.resizeObserver.disconnect(),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.historyTexture&&(this.gl.deleteTexture(this.historyTexture),this.historyTexture=null),this.buffer&&(this.gl.deleteBuffer(this.buffer),this.buffer=null),this.isInternalCanvas&&this.canvas.remove()}},c=a;export{c as default};
|
|
8
|
+
`,u=33.333333333333336,a=class{constructor(t,e={}){this.isInternalCanvas=!1;this.isTouchDevice=!1;this.uniforms=new Map;this.textures=new Map;this.buffer=null;this.program=null;this.resizeTimeout=null;this.lastResizeTime=0;this.eventListeners=new Map;this.frame=0;this.startTime=0;this.cursorPosition=[.5,.5];this.clickPosition=[.5,.5];this.isMouseDown=!1;this.historyTexture=null;if(this.canvas=e.canvas||document.createElement("canvas"),this.historyLength=e.history||0,e.canvas||(this.isInternalCanvas=!0,document.body.appendChild(this.canvas),this.canvas.style.position="fixed",this.canvas.style.inset="0",this.canvas.style.height="100dvh",this.canvas.style.width="100dvw"),this.gl=this.canvas.getContext("webgl2",{antialias:!1}),!this.gl)throw new Error("WebGL2 not supported. Please use a browser that supports WebGL2.");this.downloadLink=document.createElement("a"),this.fragmentShaderSrc=t,this.animationFrameId=null,this.resolutionObserver=new MutationObserver(()=>this.updateResolution()),this.resizeObserver=new ResizeObserver(()=>this.throttledHandleResize()),this.init(),this.addEventListeners()}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");let s=this.gl.getAttribLocation(this.program,"aPosition");this.setupBuffer(s),this.gl.useProgram(this.program),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.historyLength>0&&this.initializeHistoryBuffer()}initializeHistoryBuffer(){let{gl:t}=this;if(this.historyTexture=t.createTexture(),!this.historyTexture)throw new Error("Failed to create history texture");t.bindTexture(t.TEXTURE_2D_ARRAY,this.historyTexture),t.texParameteri(t.TEXTURE_2D_ARRAY,t.TEXTURE_WRAP_S,t.CLAMP_TO_EDGE),t.texParameteri(t.TEXTURE_2D_ARRAY,t.TEXTURE_WRAP_T,t.CLAMP_TO_EDGE),t.texParameteri(t.TEXTURE_2D_ARRAY,t.TEXTURE_MIN_FILTER,t.NEAREST),t.texParameteri(t.TEXTURE_2D_ARRAY,t.TEXTURE_MAG_FILTER,t.NEAREST),t.texStorage3D(t.TEXTURE_2D_ARRAY,1,t.RGBA8,this.gl.drawingBufferWidth,this.gl.drawingBufferHeight,this.historyLength),t.activeTexture(t.TEXTURE0),t.bindTexture(t.TEXTURE_2D_ARRAY,this.historyTexture),this.clearHistory(),this.uniforms.has("u_history")||this.initializeUniform("u_history","int",0)}clearHistory(){let t=new Uint8Array(this.gl.drawingBufferWidth*this.gl.drawingBufferHeight*4);for(let e=0;e<this.historyLength;++e)this.gl.texSubImage3D(this.gl.TEXTURE_2D_ARRAY,0,0,0,e,this.gl.drawingBufferWidth,this.gl.drawingBufferHeight,1,this.gl.RGBA,this.gl.UNSIGNED_BYTE,t)}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(t){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(t),this.gl.vertexAttribPointer(t,2,this.gl.FLOAT,!1,0,0)}throttledHandleResize(){clearTimeout(this.resizeTimeout);let t=performance.now(),e=this.lastResizeTime+u-t;e<=0?(this.lastResizeTime=t,this.handleResize()):this.resizeTimeout=setTimeout(()=>this.throttledHandleResize(),e)}handleResize(){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=(i,s)=>{if(!this.uniforms.has("u_cursor"))return;let r=this.canvas.getBoundingClientRect();this.cursorPosition[0]=(i-r.left)/r.width,this.cursorPosition[1]=1-(s-r.top)/r.height,this.updateUniforms({u_cursor:this.cursorPosition})},e=(i,s,r)=>{if(this.uniforms.has("u_click")){if(this.isMouseDown=i,i){let n=this.canvas.getBoundingClientRect(),h=s,o=r;this.clickPosition[0]=(h-n.left)/n.width,this.clickPosition[1]=1-(o-n.top)/n.height}this.updateUniforms({u_click:[...this.clickPosition,this.isMouseDown?1:0]})}};this.eventListeners.set("mousemove",i=>{let s=i;this.isTouchDevice||t(s.clientX,s.clientY)}),this.eventListeners.set("mousedown",i=>{let s=i;this.isTouchDevice||s.button===0&&(this.isMouseDown=!0,e(!0,s.clientX,s.clientY))}),this.eventListeners.set("mouseup",i=>{let s=i;this.isTouchDevice||s.button===0&&e(!1)}),this.eventListeners.set("touchmove",i=>{let s=i;s.touches.length>0&&t(s.touches[0].clientX,s.touches[0].clientY)}),this.eventListeners.set("touchstart",i=>{let s=i;this.isTouchDevice=!0,s.touches.length>0&&(t(s.touches[0].clientX,s.touches[0].clientY),e(!0,s.touches[0].clientX,s.touches[0].clientY))}),this.eventListeners.set("touchend",i=>{i.touches.length===0&&e(!1)}),this.eventListeners.forEach((i,s)=>{this.canvas.addEventListener(s,i)})}updateResolution(){let t=this.gl.drawingBufferWidth,e=this.gl.drawingBufferHeight;this.gl.viewport(0,0,t,e),this.uniforms.has("u_resolution")?this.updateUniforms({u_resolution:[t,e]}):this.initializeUniform("u_resolution","float",[t,e]),this.historyLength>0&&this.historyTexture&&(this.gl.deleteTexture(this.historyTexture),this.initializeHistoryBuffer())}initializeUniform(t,e,i){if(this.uniforms.has(t))throw new Error(`Uniform '${t}' is already initialized.`);if(e!=="float"&&e!=="int")throw new Error(`Invalid uniform type: ${e}. Expected 'float' or 'int'.`);let s=this.gl.getUniformLocation(this.program,t);if(!s){console.debug(`Uniform ${t} not found in fragment shader. Skipping initialization.`);return}if(Array.isArray(i)||(i=[i]),i.length<1||i.length>4)throw new Error(`Invalid uniform value length: ${i.length}. Expected a length between 1 and 4.`);let r=i.length;this.uniforms.set(t,{type:e,length:r,location:s}),this.updateUniforms({[t]:i})}updateUniforms(t){Object.entries(t).forEach(([e,i])=>{if(!this.uniforms.has(e))throw new Error(`Uniform '${e}' is not initialized.`);let s=this.uniforms.get(e);if(Array.isArray(i)||(i=[i]),i.length!==s.length)throw new Error(`Invalid uniform value length: ${i.length}. Expected ${s.length}.`);this.gl[`uniform${s.length}${s.type.charAt(0)}`](s.location,...i)})}step(t){let e=this.gl;if(this.uniforms.has("u_time")&&this.updateUniforms({u_time:t}),this.uniforms.has("u_frame")&&this.updateUniforms({u_frame:this.frame}),this.historyLength>0){let i=this.frame%this.historyLength;e.bindFramebuffer(e.FRAMEBUFFER,null),e.viewport(0,0,this.gl.drawingBufferWidth,this.gl.drawingBufferHeight),e.clear(e.COLOR_BUFFER_BIT),e.drawArrays(e.TRIANGLES,0,6),e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D_ARRAY,this.historyTexture),e.copyTexSubImage3D(e.TEXTURE_2D_ARRAY,0,0,0,i,0,0,this.gl.drawingBufferWidth,this.gl.drawingBufferHeight)}else e.clear(e.COLOR_BUFFER_BIT),e.drawArrays(e.TRIANGLES,0,6);++this.frame}play(t){let e=i=>{i=(i-this.startTime)/1e3,this.step(i),t&&t(i,this.frame),this.animationFrameId=requestAnimationFrame(e)};this.animationFrameId=requestAnimationFrame(e)}pause(){this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null)}reset(){this.frame=0,this.startTime=performance.now(),this.clearHistory()}initializeTexture(t,e){if(this.textures.has(t))throw new Error(`Texture '${t}' is already initialized.`);let i=this.gl.createTexture();if(!i)throw new Error("Failed to create texture");let s=this.textures.size+1;this.gl.activeTexture(this.gl.TEXTURE0+s),this.gl.bindTexture(this.gl.TEXTURE_2D,i),this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,!0),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_WRAP_S,this.gl.CLAMP_TO_EDGE),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_WRAP_T,this.gl.CLAMP_TO_EDGE),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MIN_FILTER,this.gl.LINEAR),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MAG_FILTER,this.gl.LINEAR),this.textures.set(t,{texture:i,unitIndex:s}),this.updateTextures({[t]:e});let r=this.gl.getUniformLocation(this.program,t);r&&this.gl.uniform1i(r,s)}updateTextures(t){Object.entries(t).forEach(([e,i])=>{let s=this.textures.get(e);if(!s)throw new Error(`Texture '${e}' is not initialized.`);this.gl.activeTexture(this.gl.TEXTURE0+s.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D,s.texture),this.gl.texImage2D(this.gl.TEXTURE_2D,0,this.gl.RGBA,this.gl.RGBA,this.gl.UNSIGNED_BYTE,i)})}async save(t){if(this.gl.clear(this.gl.COLOR_BUFFER_BIT),this.gl.drawArrays(this.gl.TRIANGLES,0,6),t&&!`${t}`.toLowerCase().endsWith(".png")&&(t=`${t}.png`),t=t||"export.png","ongesturechange"in window)try{let e=await new Promise(s=>this.canvas.toBlob(s,"image/png")),i=new File([e],t,{type:e.type});if(navigator.canShare?.({files:[i]})){await navigator.share({files:[i]});return}}catch(e){console.warn("Web Share API failed:",e)}else this.downloadLink.download=t,this.downloadLink.href=this.canvas.toDataURL(),this.downloadLink.click()}destroy(){this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null),this.resolutionObserver.disconnect(),this.resizeObserver.disconnect(),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.historyTexture&&(this.gl.deleteTexture(this.historyTexture),this.historyTexture=null),this.buffer&&(this.gl.deleteBuffer(this.buffer),this.buffer=null),this.isInternalCanvas&&this.canvas.remove()}},c=a;export{c as default};
|
|
9
9
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +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}\n\ninterface Texture {\n\ttexture: WebGLTexture;\n\tunitIndex: number;\n}\n\ninterface Options {\n\tcanvas?: HTMLCanvasElement | null;\n\thistory?: number;\n}\n\nclass ShaderPad {\n\tprivate isInternalCanvas = false;\n\tprivate isTouchDevice = false;\n\tprivate canvas: HTMLCanvasElement;\n\tprivate gl: WebGL2RenderingContext;\n\tprivate downloadLink: HTMLAnchorElement;\n\tprivate fragmentShaderSrc: string;\n\tprivate uniforms: Map<string, Uniform> = new Map();\n\tprivate textures: Map<string, Texture> = new Map();\n\tprivate buffer: WebGLBuffer | null = null;\n\tprivate program: WebGLProgram | null = null;\n\tprivate animationFrameId: number | null;\n\tprivate resolutionObserver: MutationObserver;\n\tprivate resizeObserver: ResizeObserver;\n\tprivate resizeTimeout: NodeJS.Timeout = null as unknown as NodeJS.Timeout;\n\tprivate lastResizeTime = 0;\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\tprivate historyLength: number;\n\tprivate historyTexture: WebGLTexture | null = null;\n\tpublic onResize?: (width: number, height: number) => void;\n\n\tconstructor(fragmentShaderSrc: string, options: Options = {}) {\n\t\tthis.canvas = options.canvas || document.createElement('canvas');\n\t\tthis.historyLength = options.history || 0;\n\t\tif (!options.canvas) {\n\t\t\tthis.isInternalCanvas = true;\n\t\t\tdocument.body.appendChild(this.canvas);\n\t\t\tthis.canvas.style.position = 'fixed';\n\t\t\tthis.canvas.style.inset = '0';\n\t\t\tthis.canvas.style.height = '100dvh';\n\t\t\tthis.canvas.style.width = '100dvw';\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.downloadLink = document.createElement('a');\n\t\tthis.fragmentShaderSrc = fragmentShaderSrc;\n\t\tthis.animationFrameId = null;\n\t\tthis.resolutionObserver = new MutationObserver(() => this.updateResolution());\n\t\tthis.resizeObserver = new ResizeObserver(() => this.throttledHandleResize());\n\n\t\tthis.init();\n\t\tthis.addEventListeners();\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\tconst aPosition = this.gl.getAttribLocation(this.program, 'aPosition');\n\t\tthis.setupBuffer(aPosition);\n\n\t\tthis.gl.useProgram(this.program);\n\n\t\tthis.resolutionObserver.observe(this.canvas, { attributes: true, attributeFilter: ['width', 'height'] });\n\t\tthis.resizeObserver.observe(this.canvas);\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\t\tif (this.historyLength > 0) {\n\t\t\tthis.initializeHistoryBuffer();\n\t\t}\n\t}\n\n\tprivate initializeHistoryBuffer() {\n\t\tconst { gl } = this;\n\n\t\tthis.historyTexture = gl.createTexture();\n\t\tif (!this.historyTexture) {\n\t\t\tthrow new Error('Failed to create history texture');\n\t\t}\n\n\t\tgl.bindTexture(gl.TEXTURE_2D_ARRAY, this.historyTexture);\n\t\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n\t\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n\t\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_MIN_FILTER, gl.NEAREST);\n\t\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_MAG_FILTER, gl.NEAREST);\n\t\tgl.texStorage3D(\n\t\t\tgl.TEXTURE_2D_ARRAY,\n\t\t\t1,\n\t\t\tgl.RGBA8,\n\t\t\tthis.gl.drawingBufferWidth,\n\t\t\tthis.gl.drawingBufferHeight,\n\t\t\tthis.historyLength\n\t\t);\n\t\tgl.activeTexture(gl.TEXTURE0);\n\t\tgl.bindTexture(gl.TEXTURE_2D_ARRAY, this.historyTexture);\n\n\t\tthis.clearHistory();\n\n\t\tif (!this.uniforms.has('u_history')) {\n\t\t\tthis.initializeUniform('u_history', 'int', 0);\n\t\t}\n\t}\n\n\tprivate clearHistory() {\n\t\tconst transparent = new Uint8Array(this.gl.drawingBufferWidth * this.gl.drawingBufferHeight * 4); // All zeroes.\n\t\tfor (let layer = 0; layer < this.historyLength; ++layer) {\n\t\t\tthis.gl.texSubImage3D(\n\t\t\t\tthis.gl.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\tthis.gl.drawingBufferWidth,\n\t\t\t\tthis.gl.drawingBufferHeight,\n\t\t\t\t1,\n\t\t\t\tthis.gl.RGBA,\n\t\t\t\tthis.gl.UNSIGNED_BYTE,\n\t\t\t\ttransparent\n\t\t\t);\n\t\t}\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(aPosition: number) {\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(aPosition);\n\t\tthis.gl.vertexAttribPointer(aPosition, 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\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 updateCursor = (x: number, y: number) => {\n\t\t\tif (!this.uniforms.has('u_cursor')) return;\n\t\t\tconst rect = this.canvas.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 = this.canvas.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\tthis.canvas.addEventListener(event, listener);\n\t\t});\n\t}\n\n\tprivate updateResolution() {\n\t\tconst width = this.gl.drawingBufferWidth;\n\t\tconst height = this.gl.drawingBufferHeight;\n\t\tthis.gl.viewport(0, 0, width, height);\n\t\tif (this.uniforms.has('u_resolution')) {\n\t\t\tthis.updateUniforms({ u_resolution: [width, height] });\n\t\t} else {\n\t\t\tthis.initializeUniform('u_resolution', 'float', [width, height]);\n\t\t}\n\n\t\t// Delete and recreate history buffer, since the canvas size won’t be correct anymore.\n\t\tif (this.historyLength > 0 && this.historyTexture) {\n\t\t\tthis.gl.deleteTexture(this.historyTexture);\n\t\t\tthis.initializeHistoryBuffer();\n\t\t}\n\t}\n\n\tinitializeUniform(name: string, type: 'float' | 'int', value: number | number[]) {\n\t\tif (this.uniforms.has(name)) {\n\t\t\tthrow new Error(`Uniform '${name}' is already initialized.`);\n\t\t}\n\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\n\t\tconst location = this.gl.getUniformLocation(this.program!, name);\n\t\tif (!location) {\n\t\t\tconsole.debug(`Uniform ${name} not found in fragment shader. Skipping initialization.`);\n\t\t\treturn;\n\t\t}\n\n\t\tif (!Array.isArray(value)) {\n\t\t\tvalue = [value];\n\t\t}\n\t\tif (value.length < 1 || value.length > 4) {\n\t\t\tthrow new Error(`Invalid uniform value length: ${value.length}. Expected a length between 1 and 4.`);\n\t\t}\n\n\t\tconst length = value.length as 1 | 2 | 3 | 4;\n\t\tthis.uniforms.set(name, { type, length, location });\n\t\tthis.updateUniforms({ [name]: value });\n\t}\n\n\tupdateUniforms(updates: Record<string, number | number[]>) {\n\t\tObject.entries(updates).forEach(([name, value]: [string, number | number[]]) => {\n\t\t\tif (!this.uniforms.has(name)) {\n\t\t\t\tthrow new Error(`Uniform '${name}' is not initialized.`);\n\t\t\t}\n\n\t\t\tconst uniform = this.uniforms.get(name)!;\n\t\t\tif (!Array.isArray(value)) {\n\t\t\t\tvalue = [value];\n\t\t\t}\n\t\t\tif (value.length !== uniform.length) {\n\t\t\t\tthrow new Error(`Invalid uniform value length: ${value.length}. Expected ${uniform.length}.`);\n\t\t\t}\n\t\t\t(this.gl as any)[`uniform${uniform.length}${uniform.type.charAt(0)}`](uniform.location, ...value);\n\t\t});\n\t}\n\n\tstep(time: number) {\n\t\tconst gl = this.gl;\n\n\t\tif (this.uniforms.has('u_time')) {\n\t\t\tthis.updateUniforms({ u_time: time });\n\t\t}\n\t\tif (this.uniforms.has('u_frame')) {\n\t\t\tthis.updateUniforms({ u_frame: this.frame });\n\t\t}\n\n\t\tif (this.historyLength > 0) {\n\t\t\tconst writeIdx = this.frame % this.historyLength;\n\n\t\t\tgl.bindFramebuffer(gl.FRAMEBUFFER, null);\n\t\t\tgl.viewport(0, 0, this.gl.drawingBufferWidth, this.gl.drawingBufferHeight);\n\t\t\tgl.clear(gl.COLOR_BUFFER_BIT);\n\t\t\tgl.drawArrays(gl.TRIANGLES, 0, 6);\n\n\t\t\tgl.activeTexture(gl.TEXTURE0);\n\t\t\tgl.bindTexture(gl.TEXTURE_2D_ARRAY, this.historyTexture);\n\t\t\tgl.copyTexSubImage3D(\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\twriteIdx,\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t\tthis.gl.drawingBufferWidth,\n\t\t\t\tthis.gl.drawingBufferHeight\n\t\t\t);\n\t\t} else {\n\t\t\tgl.clear(gl.COLOR_BUFFER_BIT);\n\t\t\tgl.drawArrays(gl.TRIANGLES, 0, 6);\n\t\t}\n\n\t\t++this.frame;\n\t}\n\n\tplay(callback?: (time: number, frame: number) => void) {\n\t\tconst loop = (time: number) => {\n\t\t\ttime = (time - this.startTime) / 1000; // Convert from milliseconds to seconds.\n\t\t\tthis.step(time);\n\t\t\tif (callback) callback(time, this.frame);\n\t\t\tthis.animationFrameId = requestAnimationFrame(loop);\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.clearHistory();\n\t}\n\n\tasync save(filename: string) {\n\t\tthis.gl.clear(this.gl.COLOR_BUFFER_BIT);\n\t\tthis.gl.drawArrays(this.gl.TRIANGLES, 0, 6);\n\n\t\tif (filename && !`${filename}`.toLowerCase().endsWith('.png')) {\n\t\t\tfilename = `${filename}.png`;\n\t\t}\n\t\tfilename = filename || 'export.png';\n\n\t\tif (\n\t\t\tnavigator.canShare?.() &&\n\t\t\t/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)\n\t\t) {\n\t\t\ttry {\n\t\t\t\tconst blob: Blob = await new Promise(resolve =>\n\t\t\t\t\tthis.canvas.toBlob(resolve as BlobCallback, 'image/png')\n\t\t\t\t);\n\t\t\t\tconst file = new File([blob], filename, { type: 'image/png' });\n\n\t\t\t\tif (navigator.canShare({ files: [file] })) {\n\t\t\t\t\tawait navigator.share({\n\t\t\t\t\t\tfiles: [file],\n\t\t\t\t\t\ttitle: filename,\n\t\t\t\t\t\ttext: 'Exported image',\n\t\t\t\t\t});\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconsole.warn('Web Share API failed:', error);\n\t\t\t}\n\t\t} else {\n\t\t\tthis.downloadLink.download = filename;\n\t\t\tthis.downloadLink.href = this.canvas.toDataURL();\n\t\t\tthis.downloadLink.click();\n\t\t}\n\t}\n\n\tinitializeTexture(name: string, source: HTMLImageElement | HTMLVideoElement) {\n\t\tif (this.textures.has(name)) {\n\t\t\tthrow new Error(`Texture '${name}' is already initialized.`);\n\t\t}\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\t\tconst unitIndex = this.textures.size + 1; // Start from unit 1 to avoid conflict with history texture at unit 0.\n\t\tthis.gl.activeTexture(this.gl.TEXTURE0 + unitIndex);\n\t\tthis.gl.bindTexture(this.gl.TEXTURE_2D, texture);\n\n\t\t// Flip the texture vertically since v_uv is flipped, and set up filters and wrapping.\n\t\tthis.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, true);\n\t\tthis.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);\n\t\tthis.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);\n\t\tthis.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR);\n\t\tthis.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.LINEAR);\n\n\t\tthis.textures.set(name, { texture, unitIndex });\n\t\tthis.updateTextures({ [name]: source });\n\n\t\tconst uSampler = this.gl.getUniformLocation(this.program!, name);\n\t\tif (uSampler) {\n\t\t\tthis.gl.uniform1i(uSampler, unitIndex);\n\t\t}\n\t}\n\n\tupdateTextures(updates: Record<string, HTMLImageElement | HTMLVideoElement>) {\n\t\tObject.entries(updates).forEach(([name, source]) => {\n\t\t\tconst info = this.textures.get(name);\n\t\t\tif (!info) {\n\t\t\t\tthrow new Error(`Texture '${name}' is not initialized.`);\n\t\t\t}\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.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, this.gl.RGBA, this.gl.UNSIGNED_BYTE, source);\n\t\t});\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\tthis.eventListeners.forEach((listener, event) => {\n\t\t\tthis.canvas.removeEventListener(event, listener);\n\t\t});\n\n\t\tif (this.program) {\n\t\t\tthis.gl.deleteProgram(this.program);\n\t\t}\n\n\t\tthis.textures.forEach(texture => {\n\t\t\tthis.gl.deleteTexture(texture.texture);\n\t\t});\n\n\t\tif (this.historyTexture) {\n\t\t\tthis.gl.deleteTexture(this.historyTexture);\n\t\t\tthis.historyTexture = null;\n\t\t}\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\tif (this.isInternalCanvas) {\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","ShaderPad","fragmentShaderSrc","options","vertexShaderSrc","vertexShader","fragmentShader","aPosition","gl","transparent","layer","type","source","shader","quadVertices","now","timeUntilNextResize","pixelRatio","width","height","updateCursor","x","y","rect","updateClick","isMouseDown","xVal","yVal","event","mouseEvent","touchEvent","listener","name","value","location","length","updates","uniform","time","writeIdx","callback","loop","filename","blob","resolve","file","error","texture","unitIndex","uSampler","info","index_default"]}
|
|
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}\n\ninterface Texture {\n\ttexture: WebGLTexture;\n\tunitIndex: number;\n}\n\ninterface Options {\n\tcanvas?: HTMLCanvasElement | null;\n\thistory?: number;\n}\n\nclass ShaderPad {\n\tprivate isInternalCanvas = false;\n\tprivate isTouchDevice = false;\n\tprivate gl: WebGL2RenderingContext;\n\tprivate downloadLink: HTMLAnchorElement;\n\tprivate fragmentShaderSrc: string;\n\tprivate uniforms: Map<string, Uniform> = new Map();\n\tprivate textures: Map<string, Texture> = new Map();\n\tprivate buffer: WebGLBuffer | null = null;\n\tprivate program: WebGLProgram | null = null;\n\tprivate animationFrameId: number | null;\n\tprivate resolutionObserver: MutationObserver;\n\tprivate resizeObserver: ResizeObserver;\n\tprivate resizeTimeout: NodeJS.Timeout = null as unknown as NodeJS.Timeout;\n\tprivate lastResizeTime = 0;\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\tprivate historyLength: number;\n\tprivate historyTexture: WebGLTexture | null = null;\n\tpublic canvas: HTMLCanvasElement;\n\tpublic onResize?: (width: number, height: number) => void;\n\n\tconstructor(fragmentShaderSrc: string, options: Options = {}) {\n\t\tthis.canvas = options.canvas || document.createElement('canvas');\n\t\tthis.historyLength = options.history || 0;\n\t\tif (!options.canvas) {\n\t\t\tthis.isInternalCanvas = true;\n\t\t\tdocument.body.appendChild(this.canvas);\n\t\t\tthis.canvas.style.position = 'fixed';\n\t\t\tthis.canvas.style.inset = '0';\n\t\t\tthis.canvas.style.height = '100dvh';\n\t\t\tthis.canvas.style.width = '100dvw';\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.downloadLink = document.createElement('a');\n\t\tthis.fragmentShaderSrc = fragmentShaderSrc;\n\t\tthis.animationFrameId = null;\n\t\tthis.resolutionObserver = new MutationObserver(() => this.updateResolution());\n\t\tthis.resizeObserver = new ResizeObserver(() => this.throttledHandleResize());\n\n\t\tthis.init();\n\t\tthis.addEventListeners();\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\tconst aPosition = this.gl.getAttribLocation(this.program, 'aPosition');\n\t\tthis.setupBuffer(aPosition);\n\n\t\tthis.gl.useProgram(this.program);\n\n\t\tthis.resolutionObserver.observe(this.canvas, { attributes: true, attributeFilter: ['width', 'height'] });\n\t\tthis.resizeObserver.observe(this.canvas);\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\t\tif (this.historyLength > 0) {\n\t\t\tthis.initializeHistoryBuffer();\n\t\t}\n\t}\n\n\tprivate initializeHistoryBuffer() {\n\t\tconst { gl } = this;\n\n\t\tthis.historyTexture = gl.createTexture();\n\t\tif (!this.historyTexture) {\n\t\t\tthrow new Error('Failed to create history texture');\n\t\t}\n\n\t\tgl.bindTexture(gl.TEXTURE_2D_ARRAY, this.historyTexture);\n\t\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n\t\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n\t\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_MIN_FILTER, gl.NEAREST);\n\t\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_MAG_FILTER, gl.NEAREST);\n\t\tgl.texStorage3D(\n\t\t\tgl.TEXTURE_2D_ARRAY,\n\t\t\t1,\n\t\t\tgl.RGBA8,\n\t\t\tthis.gl.drawingBufferWidth,\n\t\t\tthis.gl.drawingBufferHeight,\n\t\t\tthis.historyLength\n\t\t);\n\t\tgl.activeTexture(gl.TEXTURE0);\n\t\tgl.bindTexture(gl.TEXTURE_2D_ARRAY, this.historyTexture);\n\n\t\tthis.clearHistory();\n\n\t\tif (!this.uniforms.has('u_history')) {\n\t\t\tthis.initializeUniform('u_history', 'int', 0);\n\t\t}\n\t}\n\n\tprivate clearHistory() {\n\t\tconst transparent = new Uint8Array(this.gl.drawingBufferWidth * this.gl.drawingBufferHeight * 4); // All zeroes.\n\t\tfor (let layer = 0; layer < this.historyLength; ++layer) {\n\t\t\tthis.gl.texSubImage3D(\n\t\t\t\tthis.gl.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\tthis.gl.drawingBufferWidth,\n\t\t\t\tthis.gl.drawingBufferHeight,\n\t\t\t\t1,\n\t\t\t\tthis.gl.RGBA,\n\t\t\t\tthis.gl.UNSIGNED_BYTE,\n\t\t\t\ttransparent\n\t\t\t);\n\t\t}\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(aPosition: number) {\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(aPosition);\n\t\tthis.gl.vertexAttribPointer(aPosition, 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\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 updateCursor = (x: number, y: number) => {\n\t\t\tif (!this.uniforms.has('u_cursor')) return;\n\t\t\tconst rect = this.canvas.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 = this.canvas.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\tthis.canvas.addEventListener(event, listener);\n\t\t});\n\t}\n\n\tprivate updateResolution() {\n\t\tconst width = this.gl.drawingBufferWidth;\n\t\tconst height = this.gl.drawingBufferHeight;\n\t\tthis.gl.viewport(0, 0, width, height);\n\t\tif (this.uniforms.has('u_resolution')) {\n\t\t\tthis.updateUniforms({ u_resolution: [width, height] });\n\t\t} else {\n\t\t\tthis.initializeUniform('u_resolution', 'float', [width, height]);\n\t\t}\n\n\t\t// Delete and recreate history buffer, since the canvas size won’t be correct anymore.\n\t\tif (this.historyLength > 0 && this.historyTexture) {\n\t\t\tthis.gl.deleteTexture(this.historyTexture);\n\t\t\tthis.initializeHistoryBuffer();\n\t\t}\n\t}\n\n\tinitializeUniform(name: string, type: 'float' | 'int', value: number | number[]) {\n\t\tif (this.uniforms.has(name)) {\n\t\t\tthrow new Error(`Uniform '${name}' is already initialized.`);\n\t\t}\n\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\n\t\tconst location = this.gl.getUniformLocation(this.program!, name);\n\t\tif (!location) {\n\t\t\tconsole.debug(`Uniform ${name} not found in fragment shader. Skipping initialization.`);\n\t\t\treturn;\n\t\t}\n\n\t\tif (!Array.isArray(value)) {\n\t\t\tvalue = [value];\n\t\t}\n\t\tif (value.length < 1 || value.length > 4) {\n\t\t\tthrow new Error(`Invalid uniform value length: ${value.length}. Expected a length between 1 and 4.`);\n\t\t}\n\n\t\tconst length = value.length as 1 | 2 | 3 | 4;\n\t\tthis.uniforms.set(name, { type, length, location });\n\t\tthis.updateUniforms({ [name]: value });\n\t}\n\n\tupdateUniforms(updates: Record<string, number | number[]>) {\n\t\tObject.entries(updates).forEach(([name, value]: [string, number | number[]]) => {\n\t\t\tif (!this.uniforms.has(name)) {\n\t\t\t\tthrow new Error(`Uniform '${name}' is not initialized.`);\n\t\t\t}\n\n\t\t\tconst uniform = this.uniforms.get(name)!;\n\t\t\tif (!Array.isArray(value)) {\n\t\t\t\tvalue = [value];\n\t\t\t}\n\t\t\tif (value.length !== uniform.length) {\n\t\t\t\tthrow new Error(`Invalid uniform value length: ${value.length}. Expected ${uniform.length}.`);\n\t\t\t}\n\t\t\t(this.gl as any)[`uniform${uniform.length}${uniform.type.charAt(0)}`](uniform.location, ...value);\n\t\t});\n\t}\n\n\tstep(time: number) {\n\t\tconst gl = this.gl;\n\n\t\tif (this.uniforms.has('u_time')) {\n\t\t\tthis.updateUniforms({ u_time: time });\n\t\t}\n\t\tif (this.uniforms.has('u_frame')) {\n\t\t\tthis.updateUniforms({ u_frame: this.frame });\n\t\t}\n\n\t\tif (this.historyLength > 0) {\n\t\t\tconst writeIdx = this.frame % this.historyLength;\n\n\t\t\tgl.bindFramebuffer(gl.FRAMEBUFFER, null);\n\t\t\tgl.viewport(0, 0, this.gl.drawingBufferWidth, this.gl.drawingBufferHeight);\n\t\t\tgl.clear(gl.COLOR_BUFFER_BIT);\n\t\t\tgl.drawArrays(gl.TRIANGLES, 0, 6);\n\n\t\t\tgl.activeTexture(gl.TEXTURE0);\n\t\t\tgl.bindTexture(gl.TEXTURE_2D_ARRAY, this.historyTexture);\n\t\t\tgl.copyTexSubImage3D(\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\twriteIdx,\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t\tthis.gl.drawingBufferWidth,\n\t\t\t\tthis.gl.drawingBufferHeight\n\t\t\t);\n\t\t} else {\n\t\t\tgl.clear(gl.COLOR_BUFFER_BIT);\n\t\t\tgl.drawArrays(gl.TRIANGLES, 0, 6);\n\t\t}\n\n\t\t++this.frame;\n\t}\n\n\tplay(callback?: (time: number, frame: number) => void) {\n\t\tconst loop = (time: number) => {\n\t\t\ttime = (time - this.startTime) / 1000; // Convert from milliseconds to seconds.\n\t\t\tthis.step(time);\n\t\t\tif (callback) callback(time, this.frame);\n\t\t\tthis.animationFrameId = requestAnimationFrame(loop);\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.clearHistory();\n\t}\n\n\tinitializeTexture(name: string, source: HTMLImageElement | HTMLVideoElement) {\n\t\tif (this.textures.has(name)) {\n\t\t\tthrow new Error(`Texture '${name}' is already initialized.`);\n\t\t}\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\t\tconst unitIndex = this.textures.size + 1; // Start from unit 1 to avoid conflict with history texture at unit 0.\n\t\tthis.gl.activeTexture(this.gl.TEXTURE0 + unitIndex);\n\t\tthis.gl.bindTexture(this.gl.TEXTURE_2D, texture);\n\n\t\t// Flip the texture vertically since v_uv is flipped, and set up filters and wrapping.\n\t\tthis.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, true);\n\t\tthis.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);\n\t\tthis.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);\n\t\tthis.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR);\n\t\tthis.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.LINEAR);\n\n\t\tthis.textures.set(name, { texture, unitIndex });\n\t\tthis.updateTextures({ [name]: source });\n\n\t\tconst uSampler = this.gl.getUniformLocation(this.program!, name);\n\t\tif (uSampler) {\n\t\t\tthis.gl.uniform1i(uSampler, unitIndex);\n\t\t}\n\t}\n\n\tupdateTextures(updates: Record<string, HTMLImageElement | HTMLVideoElement>) {\n\t\tObject.entries(updates).forEach(([name, source]) => {\n\t\t\tconst info = this.textures.get(name);\n\t\t\tif (!info) {\n\t\t\t\tthrow new Error(`Texture '${name}' is not initialized.`);\n\t\t\t}\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.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, this.gl.RGBA, this.gl.UNSIGNED_BYTE, source);\n\t\t});\n\t}\n\n\tasync save(filename: string) {\n\t\tthis.gl.clear(this.gl.COLOR_BUFFER_BIT);\n\t\tthis.gl.drawArrays(this.gl.TRIANGLES, 0, 6);\n\n\t\tif (filename && !`${filename}`.toLowerCase().endsWith('.png')) {\n\t\t\tfilename = `${filename}.png`;\n\t\t}\n\t\tfilename = filename || 'export.png';\n\t\tif ('ongesturechange' in window) {\n\t\t\t// Mobile.\n\t\t\ttry {\n\t\t\t\tconst blob: Blob = await new Promise(resolve =>\n\t\t\t\t\tthis.canvas.toBlob(resolve as BlobCallback, 'image/png')\n\t\t\t\t);\n\t\t\t\tconst file = new File([blob], filename, { type: blob.type });\n\n\t\t\t\tif (navigator.canShare?.({ files: [file] })) {\n\t\t\t\t\tawait navigator.share({ files: [file] });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconsole.warn('Web Share API failed:', error);\n\t\t\t}\n\t\t} else {\n\t\t\t// Desktop.\n\t\t\tthis.downloadLink.download = filename;\n\t\t\tthis.downloadLink.href = this.canvas.toDataURL();\n\t\t\tthis.downloadLink.click();\n\t\t}\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\tthis.eventListeners.forEach((listener, event) => {\n\t\t\tthis.canvas.removeEventListener(event, listener);\n\t\t});\n\n\t\tif (this.program) {\n\t\t\tthis.gl.deleteProgram(this.program);\n\t\t}\n\n\t\tthis.textures.forEach(texture => {\n\t\t\tthis.gl.deleteTexture(texture.texture);\n\t\t});\n\n\t\tif (this.historyTexture) {\n\t\t\tthis.gl.deleteTexture(this.historyTexture);\n\t\t\tthis.historyTexture = null;\n\t\t}\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\tif (this.isInternalCanvas) {\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","ShaderPad","fragmentShaderSrc","options","vertexShaderSrc","vertexShader","fragmentShader","aPosition","gl","transparent","layer","type","source","shader","quadVertices","now","timeUntilNextResize","pixelRatio","width","height","updateCursor","x","y","rect","updateClick","isMouseDown","xVal","yVal","event","mouseEvent","touchEvent","listener","name","value","location","length","updates","uniform","time","writeIdx","callback","loop","texture","unitIndex","uSampler","info","filename","blob","resolve","file","error","index_default"]}
|