shaderpad 1.0.0-alpha.3 → 1.0.0-alpha.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -67,6 +67,7 @@ See the [`examples/` directory](./examples/) for more.
67
67
  | ------------- | -------- | ----------------------------------- |
68
68
  | `uUv` | float[2] | The UV coordinates of the fragment. |
69
69
  | `uTime` | float | The current time in seconds. |
70
+ | `uFrame` | int | The current frame number. |
70
71
  | `uResolution` | float[2] | The canvas element’s dimensions. |
71
72
  | `uCursor` | float[2] | The current mouse/cursor position. |
72
73
 
package/dist/index.d.mts CHANGED
@@ -12,6 +12,7 @@ declare class ShaderPad {
12
12
  private animationFrameId;
13
13
  private resizeObserver;
14
14
  private eventListeners;
15
+ private frame;
15
16
  constructor(fragmentShaderSrc: string, canvas?: HTMLCanvasElement | null);
16
17
  private init;
17
18
  private createShader;
@@ -20,7 +21,8 @@ declare class ShaderPad {
20
21
  private addEventListeners;
21
22
  initializeUniform(name: string, type: 'float' | 'int', value: number | number[]): void;
22
23
  updateUniforms(updates: Record<string, number | number[]>): void;
23
- play(callback?: (time: number) => void): void;
24
+ step(time: number): void;
25
+ play(callback?: (time: number, frame: number) => void): void;
24
26
  pause(): void;
25
27
  save(filename: string): void;
26
28
  initializeTexture(name: string, source: HTMLImageElement | HTMLVideoElement): void;
package/dist/index.d.ts CHANGED
@@ -12,6 +12,7 @@ declare class ShaderPad {
12
12
  private animationFrameId;
13
13
  private resizeObserver;
14
14
  private eventListeners;
15
+ private frame;
15
16
  constructor(fragmentShaderSrc: string, canvas?: HTMLCanvasElement | null);
16
17
  private init;
17
18
  private createShader;
@@ -20,7 +21,8 @@ declare class ShaderPad {
20
21
  private addEventListeners;
21
22
  initializeUniform(name: string, type: 'float' | 'int', value: number | number[]): void;
22
23
  updateUniforms(updates: Record<string, number | number[]>): void;
23
- play(callback?: (time: number) => void): void;
24
+ step(time: number): void;
25
+ play(callback?: (time: number, frame: number) => void): void;
24
26
  pause(): void;
25
27
  save(filename: string): void;
26
28
  initializeTexture(name: string, source: HTMLImageElement | HTMLVideoElement): void;
package/dist/index.js CHANGED
@@ -1,9 +1,9 @@
1
- "use strict";var h=Object.defineProperty;var l=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var c=Object.prototype.hasOwnProperty;var u=(s,t)=>{for(var e in t)h(s,e,{get:t[e],enumerable:!0})},d=(s,t,e,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of g(t))!c.call(s,r)&&r!==e&&h(s,r,{get:()=>t[r],enumerable:!(i=l(t,r))||i.enumerable});return s};var m=s=>d(h({},"__esModule",{value:!0}),s);var E={};u(E,{default:()=>v});module.exports=m(E);var f=`
1
+ "use strict";var h=Object.defineProperty;var l=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var c=Object.prototype.hasOwnProperty;var u=(s,t)=>{for(var e in t)h(s,e,{get:t[e],enumerable:!0})},d=(s,t,e,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of g(t))!c.call(s,r)&&r!==e&&h(s,r,{get:()=>t[r],enumerable:!(i=l(t,r))||i.enumerable});return s};var m=s=>d(h({},"__esModule",{value:!0}),s);var p={};u(p,{default:()=>v});module.exports=m(p);var f=`
2
2
  attribute vec2 aPosition;
3
3
  varying vec2 vUv;
4
4
  void main() {
5
5
  vUv = aPosition * 0.5 + 0.5;
6
6
  gl_Position = vec4(aPosition, 0.0, 1.0);
7
7
  }
8
- `,o=class{constructor(t,e=null){this.isInternalCanvas=!1;this.isTouchDevice=!1;this.uniforms=new Map;this.textures=new Map;this.buffer=null;this.program=null;this.eventListeners=new Map;this.canvas=e||document.createElement("canvas"),e||(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("webgl"),this.downloadLink=document.createElement("a"),this.fragmentShaderSrc=t,this.animationFrameId=null,this.resizeObserver=new ResizeObserver(()=>this.resizeCanvas()),this.resizeObserver.observe(this.canvas),this.init(),this.addEventListeners()}init(){let t=f;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.resizeCanvas(),this.gl.useProgram(this.program),this.initializeUniform("uResolution","float",[this.canvas.width,this.canvas.height]),this.initializeUniform("uCursor","float",[.5,.5]),this.initializeUniform("uTime","float",0)}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.canvas.width,this.canvas.height),this.gl.enableVertexAttribArray(t),this.gl.vertexAttribPointer(t,2,this.gl.FLOAT,!1,0,0)}resizeCanvas(){let t=window.devicePixelRatio||1,e=this.canvas.clientWidth*t,i=this.canvas.clientHeight*t,r=getComputedStyle(this.canvas),n=r.width!==`${this.canvas.width}px`&&r.width!=="auto",a=r.height!==`${this.canvas.height}px`&&r.height!=="auto";(!n||!a)&&(this.canvas.style.width=`${this.canvas.clientWidth}px`,this.canvas.style.height=`${this.canvas.clientHeight}px`),(this.canvas.width!==e||this.canvas.height!==i)&&(this.canvas.width=e,this.canvas.height=i,this.gl.viewport(0,0,this.gl.drawingBufferWidth,this.gl.drawingBufferHeight),this.uniforms.has("uResolution")&&this.updateUniforms({uResolution:[this.canvas.width,this.canvas.height]}))}addEventListeners(){let t=(e,i)=>{if(!this.uniforms.has("uCursor"))return;let r=this.canvas.getBoundingClientRect(),n=(e-r.left)/r.width,a=1-(i-r.top)/r.height;this.updateUniforms({uCursor:[n,a]})};this.eventListeners.set("mousemove",e=>{let i=e;this.isTouchDevice||t(i.clientX,i.clientY)}),this.eventListeners.set("touchmove",e=>{let i=e;i.touches.length>0&&t(i.touches[0].clientX,i.touches[0].clientY)}),this.eventListeners.set("touchstart",()=>{this.isTouchDevice=!0}),this.eventListeners.forEach((e,i)=>{this.canvas.addEventListener(i,e)})}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.log(`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 n=i.length;this.uniforms.set(t,{type:e,length:n,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)})}play(t){let e=i=>{i/=1e3,this.gl.clear(this.gl.COLOR_BUFFER_BIT),this.uniforms.has("uTime")&&this.updateUniforms({uTime:i}),t&&t(i),this.gl.drawArrays(this.gl.TRIANGLES,0,6),this.animationFrameId=requestAnimationFrame(e)};this.animationFrameId=requestAnimationFrame(e)}pause(){this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null)}save(t){this.gl.clear(this.gl.COLOR_BUFFER_BIT),this.gl.drawArrays(this.gl.TRIANGLES,0,6);let e=this.canvas.toDataURL();t&&!`${t}`.toLowerCase().endsWith(".png")&&(t=`${t}.png`),this.downloadLink.download=t||"export.png",this.downloadLink.href=e,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;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 n=this.gl.getUniformLocation(this.program,t);n&&this.gl.uniform1i(n,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.resizeObserver.unobserve(this.canvas),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.buffer&&(this.gl.deleteBuffer(this.buffer),this.buffer=null),this.isInternalCanvas&&this.canvas.remove()}},v=o;
8
+ `,o=class{constructor(t,e=null){this.isInternalCanvas=!1;this.isTouchDevice=!1;this.uniforms=new Map;this.textures=new Map;this.buffer=null;this.program=null;this.eventListeners=new Map;this.frame=0;this.canvas=e||document.createElement("canvas"),e||(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("webgl"),this.downloadLink=document.createElement("a"),this.fragmentShaderSrc=t,this.animationFrameId=null,this.resizeObserver=new ResizeObserver(()=>this.resizeCanvas()),this.resizeObserver.observe(this.canvas),this.init(),this.addEventListeners()}init(){let t=f;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.resizeCanvas(),this.gl.useProgram(this.program),this.initializeUniform("uResolution","float",[this.canvas.width,this.canvas.height]),this.initializeUniform("uCursor","float",[.5,.5]),this.initializeUniform("uTime","float",0),this.initializeUniform("uFrame","int",0)}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.canvas.width,this.canvas.height),this.gl.enableVertexAttribArray(t),this.gl.vertexAttribPointer(t,2,this.gl.FLOAT,!1,0,0)}resizeCanvas(){let t=window.devicePixelRatio||1,e=this.canvas.clientWidth*t,i=this.canvas.clientHeight*t,r=getComputedStyle(this.canvas),n=r.width!==`${this.canvas.width}px`&&r.width!=="auto",a=r.height!==`${this.canvas.height}px`&&r.height!=="auto";(!n||!a)&&(this.canvas.style.width=`${this.canvas.clientWidth}px`,this.canvas.style.height=`${this.canvas.clientHeight}px`),(this.canvas.width!==e||this.canvas.height!==i)&&(this.canvas.width=e,this.canvas.height=i,this.gl.viewport(0,0,this.gl.drawingBufferWidth,this.gl.drawingBufferHeight),this.uniforms.has("uResolution")&&this.updateUniforms({uResolution:[this.canvas.width,this.canvas.height]}))}addEventListeners(){let t=(e,i)=>{if(!this.uniforms.has("uCursor"))return;let r=this.canvas.getBoundingClientRect(),n=(e-r.left)/r.width,a=1-(i-r.top)/r.height;this.updateUniforms({uCursor:[n,a]})};this.eventListeners.set("mousemove",e=>{let i=e;this.isTouchDevice||t(i.clientX,i.clientY)}),this.eventListeners.set("touchmove",e=>{let i=e;i.touches.length>0&&t(i.touches[0].clientX,i.touches[0].clientY)}),this.eventListeners.set("touchstart",()=>{this.isTouchDevice=!0}),this.eventListeners.forEach((e,i)=>{this.canvas.addEventListener(i,e)})}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.log(`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 n=i.length;this.uniforms.set(t,{type:e,length:n,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){t/=1e3,this.gl.clear(this.gl.COLOR_BUFFER_BIT),this.uniforms.has("uTime")&&this.updateUniforms({uTime:t}),this.uniforms.has("uFrame")&&this.updateUniforms({uFrame:this.frame}),++this.frame,this.gl.drawArrays(this.gl.TRIANGLES,0,6)}play(t){let e=i=>{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)}save(t){this.gl.clear(this.gl.COLOR_BUFFER_BIT),this.gl.drawArrays(this.gl.TRIANGLES,0,6);let e=this.canvas.toDataURL();t&&!`${t}`.toLowerCase().endsWith(".png")&&(t=`${t}.png`),this.downloadLink.download=t||"export.png",this.downloadLink.href=e,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;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 n=this.gl.getUniformLocation(this.program,t);n&&this.gl.uniform1i(n,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.resizeObserver.unobserve(this.canvas),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.buffer&&(this.gl.deleteBuffer(this.buffer),this.buffer=null),this.isInternalCanvas&&this.canvas.remove()}},v=o;
9
9
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["const defaultVertexShaderSrc = `\nattribute vec2 aPosition;\nvarying vec2 vUv;\nvoid main() {\n vUv = aPosition * 0.5 + 0.5;\n gl_Position = vec4(aPosition, 0.0, 1.0);\n}\n`;\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\nclass ShaderPad {\n\tprivate isInternalCanvas = false;\n\tprivate isTouchDevice = false;\n\tprivate canvas: HTMLCanvasElement;\n\tprivate gl: WebGLRenderingContext;\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 resizeObserver: ResizeObserver;\n\tprivate eventListeners: Map<string, EventListener> = new Map();\n\n\tconstructor(fragmentShaderSrc: string, canvas: HTMLCanvasElement | null = null) {\n\t\tthis.canvas = canvas || document.createElement('canvas');\n\t\tif (!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\t\tthis.gl = this.canvas.getContext('webgl')!;\n\t\tthis.downloadLink = document.createElement('a');\n\t\tthis.fragmentShaderSrc = fragmentShaderSrc;\n\t\tthis.animationFrameId = null;\n\t\tthis.resizeObserver = new ResizeObserver(() => this.resizeCanvas());\n\t\tthis.resizeObserver.observe(this.canvas);\n\t\tthis.init();\n\t\tthis.addEventListeners();\n\t}\n\n\tprivate init() {\n\t\tconst vertexShaderSrc = defaultVertexShaderSrc;\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\t\tthis.resizeCanvas();\n\n\t\tthis.gl.useProgram(this.program);\n\n\t\tthis.initializeUniform('uResolution', 'float', [this.canvas.width, this.canvas.height]);\n\t\tthis.initializeUniform('uCursor', 'float', [0.5, 0.5]);\n\t\tthis.initializeUniform('uTime', 'float', 0);\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.canvas.width, this.canvas.height);\n\t\tthis.gl.enableVertexAttribArray(aPosition);\n\t\tthis.gl.vertexAttribPointer(aPosition, 2, this.gl.FLOAT, false, 0, 0);\n\t}\n\n\tprivate resizeCanvas() {\n\t\tconst pixelRatio = window.devicePixelRatio || 1;\n\t\tconst width = this.canvas.clientWidth * pixelRatio;\n\t\tconst height = this.canvas.clientHeight * pixelRatio;\n\n\t\tconst computedStyle = getComputedStyle(this.canvas);\n\t\tconst hasExplicitWidth = computedStyle.width !== `${this.canvas.width}px` && computedStyle.width !== 'auto';\n\t\tconst hasExplicitHeight = computedStyle.height !== `${this.canvas.height}px` && computedStyle.height !== 'auto';\n\t\tif (!hasExplicitWidth || !hasExplicitHeight) {\n\t\t\tthis.canvas.style.width = `${this.canvas.clientWidth}px`;\n\t\t\tthis.canvas.style.height = `${this.canvas.clientHeight}px`;\n\t\t}\n\n\t\tif (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\tthis.gl.viewport(0, 0, this.gl.drawingBufferWidth, this.gl.drawingBufferHeight);\n\t\t\tif (this.uniforms.has('uResolution')) {\n\t\t\t\tthis.updateUniforms({ uResolution: [this.canvas.width, this.canvas.height] });\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate addEventListeners() {\n\t\tconst updateCursor = (x: number, y: number) => {\n\t\t\tif (!this.uniforms.has('uCursor')) return;\n\t\t\tconst rect = this.canvas.getBoundingClientRect();\n\t\t\tconst cursorX = (x - rect.left) / rect.width;\n\t\t\tconst cursorY = 1 - (y - rect.top) / rect.height; // Flip Y for WebGL\n\t\t\tthis.updateUniforms({ uCursor: [cursorX, cursorY] });\n\t\t};\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\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\t\tthis.eventListeners.set('touchstart', () => {\n\t\t\tthis.isTouchDevice = true;\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\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.log(`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\tplay(callback?: (time: number) => void) {\n\t\tconst renderFrame = (time: number) => {\n\t\t\ttime /= 1000; // Convert from milliseconds to seconds.\n\n\t\t\tthis.gl.clear(this.gl.COLOR_BUFFER_BIT);\n\n\t\t\tif (this.uniforms.has('uTime')) {\n\t\t\t\tthis.updateUniforms({ uTime: time });\n\t\t\t}\n\n\t\t\tif (callback) callback(time);\n\n\t\t\tthis.gl.drawArrays(this.gl.TRIANGLES, 0, 6);\n\t\t\tthis.animationFrameId = requestAnimationFrame(renderFrame);\n\t\t};\n\n\t\tthis.animationFrameId = requestAnimationFrame(renderFrame);\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\tsave(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\tconst image = this.canvas.toDataURL();\n\t\tif (filename && !`${filename}`.toLowerCase().endsWith('.png')) {\n\t\t\tfilename = `${filename}.png`;\n\t\t}\n\t\tthis.downloadLink.download = filename || 'export.png';\n\t\tthis.downloadLink.href = image;\n\t\tthis.downloadLink.click();\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;\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 vUv 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.resizeObserver.unobserve(this.canvas);\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.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","defaultVertexShaderSrc","ShaderPad","fragmentShaderSrc","canvas","vertexShaderSrc","vertexShader","fragmentShader","aPosition","type","source","shader","quadVertices","pixelRatio","width","height","computedStyle","hasExplicitWidth","hasExplicitHeight","updateCursor","x","y","rect","cursorX","cursorY","event","mouseEvent","touchEvent","listener","name","value","location","length","updates","uniform","callback","renderFrame","time","filename","image","texture","unitIndex","uSampler","info"]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["const defaultVertexShaderSrc = `\nattribute vec2 aPosition;\nvarying vec2 vUv;\nvoid main() {\n vUv = aPosition * 0.5 + 0.5;\n gl_Position = vec4(aPosition, 0.0, 1.0);\n}\n`;\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\nclass ShaderPad {\n\tprivate isInternalCanvas = false;\n\tprivate isTouchDevice = false;\n\tprivate canvas: HTMLCanvasElement;\n\tprivate gl: WebGLRenderingContext;\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 resizeObserver: ResizeObserver;\n\tprivate eventListeners: Map<string, EventListener> = new Map();\n\tprivate frame = 0;\n\n\tconstructor(fragmentShaderSrc: string, canvas: HTMLCanvasElement | null = null) {\n\t\tthis.canvas = canvas || document.createElement('canvas');\n\t\tif (!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\t\tthis.gl = this.canvas.getContext('webgl')!;\n\t\tthis.downloadLink = document.createElement('a');\n\t\tthis.fragmentShaderSrc = fragmentShaderSrc;\n\t\tthis.animationFrameId = null;\n\t\tthis.resizeObserver = new ResizeObserver(() => this.resizeCanvas());\n\t\tthis.resizeObserver.observe(this.canvas);\n\t\tthis.init();\n\t\tthis.addEventListeners();\n\t}\n\n\tprivate init() {\n\t\tconst vertexShaderSrc = defaultVertexShaderSrc;\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\t\tthis.resizeCanvas();\n\n\t\tthis.gl.useProgram(this.program);\n\n\t\tthis.initializeUniform('uResolution', 'float', [this.canvas.width, this.canvas.height]);\n\t\tthis.initializeUniform('uCursor', 'float', [0.5, 0.5]);\n\t\tthis.initializeUniform('uTime', 'float', 0);\n\t\tthis.initializeUniform('uFrame', 'int', 0);\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.canvas.width, this.canvas.height);\n\t\tthis.gl.enableVertexAttribArray(aPosition);\n\t\tthis.gl.vertexAttribPointer(aPosition, 2, this.gl.FLOAT, false, 0, 0);\n\t}\n\n\t// TODO: This breaks for `position: fixed; inset: 0` canvases.\n\tprivate resizeCanvas() {\n\t\tconst pixelRatio = window.devicePixelRatio || 1;\n\t\tconst width = this.canvas.clientWidth * pixelRatio;\n\t\tconst height = this.canvas.clientHeight * pixelRatio;\n\n\t\tconst computedStyle = getComputedStyle(this.canvas);\n\t\tconst hasExplicitWidth = computedStyle.width !== `${this.canvas.width}px` && computedStyle.width !== 'auto';\n\t\tconst hasExplicitHeight = computedStyle.height !== `${this.canvas.height}px` && computedStyle.height !== 'auto';\n\t\tif (!hasExplicitWidth || !hasExplicitHeight) {\n\t\t\tthis.canvas.style.width = `${this.canvas.clientWidth}px`;\n\t\t\tthis.canvas.style.height = `${this.canvas.clientHeight}px`;\n\t\t}\n\n\t\tif (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\tthis.gl.viewport(0, 0, this.gl.drawingBufferWidth, this.gl.drawingBufferHeight);\n\t\t\tif (this.uniforms.has('uResolution')) {\n\t\t\t\tthis.updateUniforms({ uResolution: [this.canvas.width, this.canvas.height] });\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate addEventListeners() {\n\t\tconst updateCursor = (x: number, y: number) => {\n\t\t\tif (!this.uniforms.has('uCursor')) return;\n\t\t\tconst rect = this.canvas.getBoundingClientRect();\n\t\t\tconst cursorX = (x - rect.left) / rect.width;\n\t\t\tconst cursorY = 1 - (y - rect.top) / rect.height; // Flip Y for WebGL\n\t\t\tthis.updateUniforms({ uCursor: [cursorX, cursorY] });\n\t\t};\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\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\t\tthis.eventListeners.set('touchstart', () => {\n\t\t\tthis.isTouchDevice = true;\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\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.log(`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\ttime /= 1000; // Convert from milliseconds to seconds.\n\n\t\tthis.gl.clear(this.gl.COLOR_BUFFER_BIT);\n\n\t\tif (this.uniforms.has('uTime')) {\n\t\t\tthis.updateUniforms({ uTime: time });\n\t\t}\n\n\t\tif (this.uniforms.has('uFrame')) {\n\t\t\tthis.updateUniforms({ uFrame: this.frame });\n\t\t}\n\n\t\t++this.frame;\n\t\tthis.gl.drawArrays(this.gl.TRIANGLES, 0, 6);\n\t}\n\n\tplay(callback?: (time: number, frame: number) => void) {\n\t\tconst loop = (time: number) => {\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\tsave(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\tconst image = this.canvas.toDataURL();\n\t\tif (filename && !`${filename}`.toLowerCase().endsWith('.png')) {\n\t\t\tfilename = `${filename}.png`;\n\t\t}\n\t\tthis.downloadLink.download = filename || 'export.png';\n\t\tthis.downloadLink.href = image;\n\t\tthis.downloadLink.click();\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;\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 vUv 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.resizeObserver.unobserve(this.canvas);\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.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","defaultVertexShaderSrc","ShaderPad","fragmentShaderSrc","canvas","vertexShaderSrc","vertexShader","fragmentShader","aPosition","type","source","shader","quadVertices","pixelRatio","width","height","computedStyle","hasExplicitWidth","hasExplicitHeight","updateCursor","x","y","rect","cursorX","cursorY","event","mouseEvent","touchEvent","listener","name","value","location","length","updates","uniform","time","callback","loop","filename","image","texture","unitIndex","uSampler","info"]}
package/dist/index.mjs CHANGED
@@ -5,5 +5,5 @@ void main() {
5
5
  vUv = aPosition * 0.5 + 0.5;
6
6
  gl_Position = vec4(aPosition, 0.0, 1.0);
7
7
  }
8
- `,a=class{constructor(i,e=null){this.isInternalCanvas=!1;this.isTouchDevice=!1;this.uniforms=new Map;this.textures=new Map;this.buffer=null;this.program=null;this.eventListeners=new Map;this.canvas=e||document.createElement("canvas"),e||(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("webgl"),this.downloadLink=document.createElement("a"),this.fragmentShaderSrc=i,this.animationFrameId=null,this.resizeObserver=new ResizeObserver(()=>this.resizeCanvas()),this.resizeObserver.observe(this.canvas),this.init(),this.addEventListeners()}init(){let i=h;if(this.program=this.gl.createProgram(),!this.program)throw new Error("Failed to create WebGL program");let e=this.createShader(this.gl.VERTEX_SHADER,i),t=this.createShader(this.gl.FRAGMENT_SHADER,this.fragmentShaderSrc);if(this.gl.attachShader(this.program,e),this.gl.attachShader(this.program,t),this.gl.linkProgram(this.program),this.gl.deleteShader(e),this.gl.deleteShader(t),!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.resizeCanvas(),this.gl.useProgram(this.program),this.initializeUniform("uResolution","float",[this.canvas.width,this.canvas.height]),this.initializeUniform("uCursor","float",[.5,.5]),this.initializeUniform("uTime","float",0)}createShader(i,e){let t=this.gl.createShader(i);if(this.gl.shaderSource(t,e),this.gl.compileShader(t),!this.gl.getShaderParameter(t,this.gl.COMPILE_STATUS))throw console.error("Shader compilation failed:",e),console.error(this.gl.getShaderInfoLog(t)),this.gl.deleteShader(t),new Error("Shader compilation failed");return t}setupBuffer(i){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.canvas.width,this.canvas.height),this.gl.enableVertexAttribArray(i),this.gl.vertexAttribPointer(i,2,this.gl.FLOAT,!1,0,0)}resizeCanvas(){let i=window.devicePixelRatio||1,e=this.canvas.clientWidth*i,t=this.canvas.clientHeight*i,r=getComputedStyle(this.canvas),s=r.width!==`${this.canvas.width}px`&&r.width!=="auto",n=r.height!==`${this.canvas.height}px`&&r.height!=="auto";(!s||!n)&&(this.canvas.style.width=`${this.canvas.clientWidth}px`,this.canvas.style.height=`${this.canvas.clientHeight}px`),(this.canvas.width!==e||this.canvas.height!==t)&&(this.canvas.width=e,this.canvas.height=t,this.gl.viewport(0,0,this.gl.drawingBufferWidth,this.gl.drawingBufferHeight),this.uniforms.has("uResolution")&&this.updateUniforms({uResolution:[this.canvas.width,this.canvas.height]}))}addEventListeners(){let i=(e,t)=>{if(!this.uniforms.has("uCursor"))return;let r=this.canvas.getBoundingClientRect(),s=(e-r.left)/r.width,n=1-(t-r.top)/r.height;this.updateUniforms({uCursor:[s,n]})};this.eventListeners.set("mousemove",e=>{let t=e;this.isTouchDevice||i(t.clientX,t.clientY)}),this.eventListeners.set("touchmove",e=>{let t=e;t.touches.length>0&&i(t.touches[0].clientX,t.touches[0].clientY)}),this.eventListeners.set("touchstart",()=>{this.isTouchDevice=!0}),this.eventListeners.forEach((e,t)=>{this.canvas.addEventListener(t,e)})}initializeUniform(i,e,t){if(this.uniforms.has(i))throw new Error(`Uniform '${i}' 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,i);if(!r){console.log(`Uniform ${i} not found in fragment shader. Skipping initialization.`);return}if(Array.isArray(t)||(t=[t]),t.length<1||t.length>4)throw new Error(`Invalid uniform value length: ${t.length}. Expected a length between 1 and 4.`);let s=t.length;this.uniforms.set(i,{type:e,length:s,location:r}),this.updateUniforms({[i]:t})}updateUniforms(i){Object.entries(i).forEach(([e,t])=>{if(!this.uniforms.has(e))throw new Error(`Uniform '${e}' is not initialized.`);let r=this.uniforms.get(e);if(Array.isArray(t)||(t=[t]),t.length!==r.length)throw new Error(`Invalid uniform value length: ${t.length}. Expected ${r.length}.`);this.gl[`uniform${r.length}${r.type.charAt(0)}`](r.location,...t)})}play(i){let e=t=>{t/=1e3,this.gl.clear(this.gl.COLOR_BUFFER_BIT),this.uniforms.has("uTime")&&this.updateUniforms({uTime:t}),i&&i(t),this.gl.drawArrays(this.gl.TRIANGLES,0,6),this.animationFrameId=requestAnimationFrame(e)};this.animationFrameId=requestAnimationFrame(e)}pause(){this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null)}save(i){this.gl.clear(this.gl.COLOR_BUFFER_BIT),this.gl.drawArrays(this.gl.TRIANGLES,0,6);let e=this.canvas.toDataURL();i&&!`${i}`.toLowerCase().endsWith(".png")&&(i=`${i}.png`),this.downloadLink.download=i||"export.png",this.downloadLink.href=e,this.downloadLink.click()}initializeTexture(i,e){if(this.textures.has(i))throw new Error(`Texture '${i}' is already initialized.`);let t=this.gl.createTexture();if(!t)throw new Error("Failed to create texture");let r=this.textures.size;this.gl.activeTexture(this.gl.TEXTURE0+r),this.gl.bindTexture(this.gl.TEXTURE_2D,t),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(i,{texture:t,unitIndex:r}),this.updateTextures({[i]:e});let s=this.gl.getUniformLocation(this.program,i);s&&this.gl.uniform1i(s,r)}updateTextures(i){Object.entries(i).forEach(([e,t])=>{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,t)})}destroy(){this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null),this.resizeObserver.unobserve(this.canvas),this.eventListeners.forEach((i,e)=>{this.canvas.removeEventListener(e,i)}),this.program&&this.gl.deleteProgram(this.program),this.textures.forEach(i=>{this.gl.deleteTexture(i.texture)}),this.buffer&&(this.gl.deleteBuffer(this.buffer),this.buffer=null),this.isInternalCanvas&&this.canvas.remove()}},l=a;export{l as default};
8
+ `,a=class{constructor(i,e=null){this.isInternalCanvas=!1;this.isTouchDevice=!1;this.uniforms=new Map;this.textures=new Map;this.buffer=null;this.program=null;this.eventListeners=new Map;this.frame=0;this.canvas=e||document.createElement("canvas"),e||(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("webgl"),this.downloadLink=document.createElement("a"),this.fragmentShaderSrc=i,this.animationFrameId=null,this.resizeObserver=new ResizeObserver(()=>this.resizeCanvas()),this.resizeObserver.observe(this.canvas),this.init(),this.addEventListeners()}init(){let i=h;if(this.program=this.gl.createProgram(),!this.program)throw new Error("Failed to create WebGL program");let e=this.createShader(this.gl.VERTEX_SHADER,i),t=this.createShader(this.gl.FRAGMENT_SHADER,this.fragmentShaderSrc);if(this.gl.attachShader(this.program,e),this.gl.attachShader(this.program,t),this.gl.linkProgram(this.program),this.gl.deleteShader(e),this.gl.deleteShader(t),!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.resizeCanvas(),this.gl.useProgram(this.program),this.initializeUniform("uResolution","float",[this.canvas.width,this.canvas.height]),this.initializeUniform("uCursor","float",[.5,.5]),this.initializeUniform("uTime","float",0),this.initializeUniform("uFrame","int",0)}createShader(i,e){let t=this.gl.createShader(i);if(this.gl.shaderSource(t,e),this.gl.compileShader(t),!this.gl.getShaderParameter(t,this.gl.COMPILE_STATUS))throw console.error("Shader compilation failed:",e),console.error(this.gl.getShaderInfoLog(t)),this.gl.deleteShader(t),new Error("Shader compilation failed");return t}setupBuffer(i){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.canvas.width,this.canvas.height),this.gl.enableVertexAttribArray(i),this.gl.vertexAttribPointer(i,2,this.gl.FLOAT,!1,0,0)}resizeCanvas(){let i=window.devicePixelRatio||1,e=this.canvas.clientWidth*i,t=this.canvas.clientHeight*i,r=getComputedStyle(this.canvas),s=r.width!==`${this.canvas.width}px`&&r.width!=="auto",n=r.height!==`${this.canvas.height}px`&&r.height!=="auto";(!s||!n)&&(this.canvas.style.width=`${this.canvas.clientWidth}px`,this.canvas.style.height=`${this.canvas.clientHeight}px`),(this.canvas.width!==e||this.canvas.height!==t)&&(this.canvas.width=e,this.canvas.height=t,this.gl.viewport(0,0,this.gl.drawingBufferWidth,this.gl.drawingBufferHeight),this.uniforms.has("uResolution")&&this.updateUniforms({uResolution:[this.canvas.width,this.canvas.height]}))}addEventListeners(){let i=(e,t)=>{if(!this.uniforms.has("uCursor"))return;let r=this.canvas.getBoundingClientRect(),s=(e-r.left)/r.width,n=1-(t-r.top)/r.height;this.updateUniforms({uCursor:[s,n]})};this.eventListeners.set("mousemove",e=>{let t=e;this.isTouchDevice||i(t.clientX,t.clientY)}),this.eventListeners.set("touchmove",e=>{let t=e;t.touches.length>0&&i(t.touches[0].clientX,t.touches[0].clientY)}),this.eventListeners.set("touchstart",()=>{this.isTouchDevice=!0}),this.eventListeners.forEach((e,t)=>{this.canvas.addEventListener(t,e)})}initializeUniform(i,e,t){if(this.uniforms.has(i))throw new Error(`Uniform '${i}' 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,i);if(!r){console.log(`Uniform ${i} not found in fragment shader. Skipping initialization.`);return}if(Array.isArray(t)||(t=[t]),t.length<1||t.length>4)throw new Error(`Invalid uniform value length: ${t.length}. Expected a length between 1 and 4.`);let s=t.length;this.uniforms.set(i,{type:e,length:s,location:r}),this.updateUniforms({[i]:t})}updateUniforms(i){Object.entries(i).forEach(([e,t])=>{if(!this.uniforms.has(e))throw new Error(`Uniform '${e}' is not initialized.`);let r=this.uniforms.get(e);if(Array.isArray(t)||(t=[t]),t.length!==r.length)throw new Error(`Invalid uniform value length: ${t.length}. Expected ${r.length}.`);this.gl[`uniform${r.length}${r.type.charAt(0)}`](r.location,...t)})}step(i){i/=1e3,this.gl.clear(this.gl.COLOR_BUFFER_BIT),this.uniforms.has("uTime")&&this.updateUniforms({uTime:i}),this.uniforms.has("uFrame")&&this.updateUniforms({uFrame:this.frame}),++this.frame,this.gl.drawArrays(this.gl.TRIANGLES,0,6)}play(i){let e=t=>{this.step(t),i&&i(t,this.frame),this.animationFrameId=requestAnimationFrame(e)};this.animationFrameId=requestAnimationFrame(e)}pause(){this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null)}save(i){this.gl.clear(this.gl.COLOR_BUFFER_BIT),this.gl.drawArrays(this.gl.TRIANGLES,0,6);let e=this.canvas.toDataURL();i&&!`${i}`.toLowerCase().endsWith(".png")&&(i=`${i}.png`),this.downloadLink.download=i||"export.png",this.downloadLink.href=e,this.downloadLink.click()}initializeTexture(i,e){if(this.textures.has(i))throw new Error(`Texture '${i}' is already initialized.`);let t=this.gl.createTexture();if(!t)throw new Error("Failed to create texture");let r=this.textures.size;this.gl.activeTexture(this.gl.TEXTURE0+r),this.gl.bindTexture(this.gl.TEXTURE_2D,t),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(i,{texture:t,unitIndex:r}),this.updateTextures({[i]:e});let s=this.gl.getUniformLocation(this.program,i);s&&this.gl.uniform1i(s,r)}updateTextures(i){Object.entries(i).forEach(([e,t])=>{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,t)})}destroy(){this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null),this.resizeObserver.unobserve(this.canvas),this.eventListeners.forEach((i,e)=>{this.canvas.removeEventListener(e,i)}),this.program&&this.gl.deleteProgram(this.program),this.textures.forEach(i=>{this.gl.deleteTexture(i.texture)}),this.buffer&&(this.gl.deleteBuffer(this.buffer),this.buffer=null),this.isInternalCanvas&&this.canvas.remove()}},l=a;export{l as default};
9
9
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["const defaultVertexShaderSrc = `\nattribute vec2 aPosition;\nvarying vec2 vUv;\nvoid main() {\n vUv = aPosition * 0.5 + 0.5;\n gl_Position = vec4(aPosition, 0.0, 1.0);\n}\n`;\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\nclass ShaderPad {\n\tprivate isInternalCanvas = false;\n\tprivate isTouchDevice = false;\n\tprivate canvas: HTMLCanvasElement;\n\tprivate gl: WebGLRenderingContext;\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 resizeObserver: ResizeObserver;\n\tprivate eventListeners: Map<string, EventListener> = new Map();\n\n\tconstructor(fragmentShaderSrc: string, canvas: HTMLCanvasElement | null = null) {\n\t\tthis.canvas = canvas || document.createElement('canvas');\n\t\tif (!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\t\tthis.gl = this.canvas.getContext('webgl')!;\n\t\tthis.downloadLink = document.createElement('a');\n\t\tthis.fragmentShaderSrc = fragmentShaderSrc;\n\t\tthis.animationFrameId = null;\n\t\tthis.resizeObserver = new ResizeObserver(() => this.resizeCanvas());\n\t\tthis.resizeObserver.observe(this.canvas);\n\t\tthis.init();\n\t\tthis.addEventListeners();\n\t}\n\n\tprivate init() {\n\t\tconst vertexShaderSrc = defaultVertexShaderSrc;\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\t\tthis.resizeCanvas();\n\n\t\tthis.gl.useProgram(this.program);\n\n\t\tthis.initializeUniform('uResolution', 'float', [this.canvas.width, this.canvas.height]);\n\t\tthis.initializeUniform('uCursor', 'float', [0.5, 0.5]);\n\t\tthis.initializeUniform('uTime', 'float', 0);\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.canvas.width, this.canvas.height);\n\t\tthis.gl.enableVertexAttribArray(aPosition);\n\t\tthis.gl.vertexAttribPointer(aPosition, 2, this.gl.FLOAT, false, 0, 0);\n\t}\n\n\tprivate resizeCanvas() {\n\t\tconst pixelRatio = window.devicePixelRatio || 1;\n\t\tconst width = this.canvas.clientWidth * pixelRatio;\n\t\tconst height = this.canvas.clientHeight * pixelRatio;\n\n\t\tconst computedStyle = getComputedStyle(this.canvas);\n\t\tconst hasExplicitWidth = computedStyle.width !== `${this.canvas.width}px` && computedStyle.width !== 'auto';\n\t\tconst hasExplicitHeight = computedStyle.height !== `${this.canvas.height}px` && computedStyle.height !== 'auto';\n\t\tif (!hasExplicitWidth || !hasExplicitHeight) {\n\t\t\tthis.canvas.style.width = `${this.canvas.clientWidth}px`;\n\t\t\tthis.canvas.style.height = `${this.canvas.clientHeight}px`;\n\t\t}\n\n\t\tif (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\tthis.gl.viewport(0, 0, this.gl.drawingBufferWidth, this.gl.drawingBufferHeight);\n\t\t\tif (this.uniforms.has('uResolution')) {\n\t\t\t\tthis.updateUniforms({ uResolution: [this.canvas.width, this.canvas.height] });\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate addEventListeners() {\n\t\tconst updateCursor = (x: number, y: number) => {\n\t\t\tif (!this.uniforms.has('uCursor')) return;\n\t\t\tconst rect = this.canvas.getBoundingClientRect();\n\t\t\tconst cursorX = (x - rect.left) / rect.width;\n\t\t\tconst cursorY = 1 - (y - rect.top) / rect.height; // Flip Y for WebGL\n\t\t\tthis.updateUniforms({ uCursor: [cursorX, cursorY] });\n\t\t};\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\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\t\tthis.eventListeners.set('touchstart', () => {\n\t\t\tthis.isTouchDevice = true;\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\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.log(`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\tplay(callback?: (time: number) => void) {\n\t\tconst renderFrame = (time: number) => {\n\t\t\ttime /= 1000; // Convert from milliseconds to seconds.\n\n\t\t\tthis.gl.clear(this.gl.COLOR_BUFFER_BIT);\n\n\t\t\tif (this.uniforms.has('uTime')) {\n\t\t\t\tthis.updateUniforms({ uTime: time });\n\t\t\t}\n\n\t\t\tif (callback) callback(time);\n\n\t\t\tthis.gl.drawArrays(this.gl.TRIANGLES, 0, 6);\n\t\t\tthis.animationFrameId = requestAnimationFrame(renderFrame);\n\t\t};\n\n\t\tthis.animationFrameId = requestAnimationFrame(renderFrame);\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\tsave(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\tconst image = this.canvas.toDataURL();\n\t\tif (filename && !`${filename}`.toLowerCase().endsWith('.png')) {\n\t\t\tfilename = `${filename}.png`;\n\t\t}\n\t\tthis.downloadLink.download = filename || 'export.png';\n\t\tthis.downloadLink.href = image;\n\t\tthis.downloadLink.click();\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;\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 vUv 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.resizeObserver.unobserve(this.canvas);\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.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":["defaultVertexShaderSrc","ShaderPad","fragmentShaderSrc","canvas","vertexShaderSrc","vertexShader","fragmentShader","aPosition","type","source","shader","quadVertices","pixelRatio","width","height","computedStyle","hasExplicitWidth","hasExplicitHeight","updateCursor","x","y","rect","cursorX","cursorY","event","mouseEvent","touchEvent","listener","name","value","location","length","updates","uniform","callback","renderFrame","time","filename","image","texture","unitIndex","uSampler","info","index_default"]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["const defaultVertexShaderSrc = `\nattribute vec2 aPosition;\nvarying vec2 vUv;\nvoid main() {\n vUv = aPosition * 0.5 + 0.5;\n gl_Position = vec4(aPosition, 0.0, 1.0);\n}\n`;\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\nclass ShaderPad {\n\tprivate isInternalCanvas = false;\n\tprivate isTouchDevice = false;\n\tprivate canvas: HTMLCanvasElement;\n\tprivate gl: WebGLRenderingContext;\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 resizeObserver: ResizeObserver;\n\tprivate eventListeners: Map<string, EventListener> = new Map();\n\tprivate frame = 0;\n\n\tconstructor(fragmentShaderSrc: string, canvas: HTMLCanvasElement | null = null) {\n\t\tthis.canvas = canvas || document.createElement('canvas');\n\t\tif (!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\t\tthis.gl = this.canvas.getContext('webgl')!;\n\t\tthis.downloadLink = document.createElement('a');\n\t\tthis.fragmentShaderSrc = fragmentShaderSrc;\n\t\tthis.animationFrameId = null;\n\t\tthis.resizeObserver = new ResizeObserver(() => this.resizeCanvas());\n\t\tthis.resizeObserver.observe(this.canvas);\n\t\tthis.init();\n\t\tthis.addEventListeners();\n\t}\n\n\tprivate init() {\n\t\tconst vertexShaderSrc = defaultVertexShaderSrc;\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\t\tthis.resizeCanvas();\n\n\t\tthis.gl.useProgram(this.program);\n\n\t\tthis.initializeUniform('uResolution', 'float', [this.canvas.width, this.canvas.height]);\n\t\tthis.initializeUniform('uCursor', 'float', [0.5, 0.5]);\n\t\tthis.initializeUniform('uTime', 'float', 0);\n\t\tthis.initializeUniform('uFrame', 'int', 0);\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.canvas.width, this.canvas.height);\n\t\tthis.gl.enableVertexAttribArray(aPosition);\n\t\tthis.gl.vertexAttribPointer(aPosition, 2, this.gl.FLOAT, false, 0, 0);\n\t}\n\n\t// TODO: This breaks for `position: fixed; inset: 0` canvases.\n\tprivate resizeCanvas() {\n\t\tconst pixelRatio = window.devicePixelRatio || 1;\n\t\tconst width = this.canvas.clientWidth * pixelRatio;\n\t\tconst height = this.canvas.clientHeight * pixelRatio;\n\n\t\tconst computedStyle = getComputedStyle(this.canvas);\n\t\tconst hasExplicitWidth = computedStyle.width !== `${this.canvas.width}px` && computedStyle.width !== 'auto';\n\t\tconst hasExplicitHeight = computedStyle.height !== `${this.canvas.height}px` && computedStyle.height !== 'auto';\n\t\tif (!hasExplicitWidth || !hasExplicitHeight) {\n\t\t\tthis.canvas.style.width = `${this.canvas.clientWidth}px`;\n\t\t\tthis.canvas.style.height = `${this.canvas.clientHeight}px`;\n\t\t}\n\n\t\tif (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\tthis.gl.viewport(0, 0, this.gl.drawingBufferWidth, this.gl.drawingBufferHeight);\n\t\t\tif (this.uniforms.has('uResolution')) {\n\t\t\t\tthis.updateUniforms({ uResolution: [this.canvas.width, this.canvas.height] });\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate addEventListeners() {\n\t\tconst updateCursor = (x: number, y: number) => {\n\t\t\tif (!this.uniforms.has('uCursor')) return;\n\t\t\tconst rect = this.canvas.getBoundingClientRect();\n\t\t\tconst cursorX = (x - rect.left) / rect.width;\n\t\t\tconst cursorY = 1 - (y - rect.top) / rect.height; // Flip Y for WebGL\n\t\t\tthis.updateUniforms({ uCursor: [cursorX, cursorY] });\n\t\t};\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\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\t\tthis.eventListeners.set('touchstart', () => {\n\t\t\tthis.isTouchDevice = true;\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\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.log(`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\ttime /= 1000; // Convert from milliseconds to seconds.\n\n\t\tthis.gl.clear(this.gl.COLOR_BUFFER_BIT);\n\n\t\tif (this.uniforms.has('uTime')) {\n\t\t\tthis.updateUniforms({ uTime: time });\n\t\t}\n\n\t\tif (this.uniforms.has('uFrame')) {\n\t\t\tthis.updateUniforms({ uFrame: this.frame });\n\t\t}\n\n\t\t++this.frame;\n\t\tthis.gl.drawArrays(this.gl.TRIANGLES, 0, 6);\n\t}\n\n\tplay(callback?: (time: number, frame: number) => void) {\n\t\tconst loop = (time: number) => {\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\tsave(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\tconst image = this.canvas.toDataURL();\n\t\tif (filename && !`${filename}`.toLowerCase().endsWith('.png')) {\n\t\t\tfilename = `${filename}.png`;\n\t\t}\n\t\tthis.downloadLink.download = filename || 'export.png';\n\t\tthis.downloadLink.href = image;\n\t\tthis.downloadLink.click();\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;\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 vUv 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.resizeObserver.unobserve(this.canvas);\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.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":["defaultVertexShaderSrc","ShaderPad","fragmentShaderSrc","canvas","vertexShaderSrc","vertexShader","fragmentShader","aPosition","type","source","shader","quadVertices","pixelRatio","width","height","computedStyle","hasExplicitWidth","hasExplicitHeight","updateCursor","x","y","rect","cursorX","cursorY","event","mouseEvent","touchEvent","listener","name","value","location","length","updates","uniform","time","callback","loop","filename","image","texture","unitIndex","uSampler","info","index_default"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shaderpad",
3
- "version": "1.0.0-alpha.3",
3
+ "version": "1.0.0-alpha.4",
4
4
  "description": "A lightweight, dependency-free library to reduce boilerplate when writing fragment shaders.",
5
5
  "keywords": [
6
6
  "shaders",