shaderpad 1.0.0-beta.17 → 1.0.0-beta.18
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 +8 -6
- package/dist/index.d.mts +14 -3
- package/dist/index.d.ts +14 -3
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -94,15 +94,17 @@ ShaderPad supports plugins to add additional functionality.
|
|
|
94
94
|
|
|
95
95
|
#### history
|
|
96
96
|
|
|
97
|
-
The `history` plugin
|
|
97
|
+
The `history` plugin can capture both the framebuffer output and texture history. The plugin argument controls how many frames to keep for the framebuffer (defaults to `1`).
|
|
98
98
|
|
|
99
99
|
```typescript
|
|
100
|
-
import ShaderPad, { history } from 'shaderpad';
|
|
101
|
-
// 2-frame history (eg. for cellular automata).
|
|
102
|
-
const shader = new ShaderPad(fragmentShaderSrc, { plugins: [history(2)] });
|
|
100
|
+
import ShaderPad, { history, WithHistory } from 'shaderpad';
|
|
103
101
|
|
|
104
|
-
// 10
|
|
105
|
-
const
|
|
102
|
+
// Store the last 10 frames of shader output.
|
|
103
|
+
const shaderWithOutputHistory = new ShaderPad(fragmentShaderSrc, { plugins: [history(10)] });
|
|
104
|
+
|
|
105
|
+
// Store the last 30 webcam frames.
|
|
106
|
+
const shader = new ShaderPad(fragmentShaderSrc, { plugins: [history()] }) as WithHistory<ShaderPad>;
|
|
107
|
+
shader.initializeTexture('u_webcam', videoElement, 30);
|
|
106
108
|
```
|
|
107
109
|
|
|
108
110
|
#### save
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
type WithHistory<T extends ShaderPad> = T & {
|
|
2
|
+
initializeTexture(name: string, source: HTMLImageElement | HTMLVideoElement, historyDepth?: number): void;
|
|
3
|
+
};
|
|
4
|
+
declare function history(framebufferDepth?: number): (shaderPad: ShaderPad, context: PluginContext) => void;
|
|
2
5
|
|
|
3
6
|
declare module '../index' {
|
|
4
7
|
interface ShaderPad {
|
|
@@ -18,13 +21,18 @@ interface Uniform {
|
|
|
18
21
|
interface Texture {
|
|
19
22
|
texture: WebGLTexture;
|
|
20
23
|
unitIndex: number;
|
|
24
|
+
historyDepth?: number;
|
|
25
|
+
writeIndex?: number;
|
|
21
26
|
}
|
|
27
|
+
type TextureSource = HTMLImageElement | HTMLVideoElement;
|
|
22
28
|
interface PluginContext {
|
|
23
29
|
gl: WebGL2RenderingContext;
|
|
24
30
|
uniforms: Map<string, Uniform>;
|
|
25
31
|
textures: Map<string, Texture>;
|
|
26
|
-
program: WebGLProgram | null;
|
|
32
|
+
get program(): WebGLProgram | null;
|
|
27
33
|
canvas: HTMLCanvasElement;
|
|
34
|
+
reserveTextureUnit: (name: string) => number;
|
|
35
|
+
releaseTextureUnit: (name: string) => void;
|
|
28
36
|
}
|
|
29
37
|
type Plugin = (shaderPad: ShaderPad, context: PluginContext) => void;
|
|
30
38
|
type LifecycleMethod = 'init' | 'step' | 'destroy' | 'updateResolution' | 'reset';
|
|
@@ -40,6 +48,7 @@ declare class ShaderPad {
|
|
|
40
48
|
private fragmentShaderSrc;
|
|
41
49
|
private uniforms;
|
|
42
50
|
private textures;
|
|
51
|
+
private textureUnitPool;
|
|
43
52
|
private buffer;
|
|
44
53
|
private program;
|
|
45
54
|
private animationFrameId;
|
|
@@ -75,6 +84,8 @@ declare class ShaderPad {
|
|
|
75
84
|
updateTextures(updates: Record<string, HTMLImageElement | HTMLVideoElement>): void;
|
|
76
85
|
save(filename: string): Promise<void>;
|
|
77
86
|
destroy(): void;
|
|
87
|
+
private reserveTextureUnit;
|
|
88
|
+
private releaseTextureUnit;
|
|
78
89
|
}
|
|
79
90
|
|
|
80
|
-
export { type PluginContext, type WithSave, ShaderPad as default, history, save };
|
|
91
|
+
export { type PluginContext, type TextureSource, type WithHistory, type WithSave, ShaderPad as default, history, save };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
type WithHistory<T extends ShaderPad> = T & {
|
|
2
|
+
initializeTexture(name: string, source: HTMLImageElement | HTMLVideoElement, historyDepth?: number): void;
|
|
3
|
+
};
|
|
4
|
+
declare function history(framebufferDepth?: number): (shaderPad: ShaderPad, context: PluginContext) => void;
|
|
2
5
|
|
|
3
6
|
declare module '../index' {
|
|
4
7
|
interface ShaderPad {
|
|
@@ -18,13 +21,18 @@ interface Uniform {
|
|
|
18
21
|
interface Texture {
|
|
19
22
|
texture: WebGLTexture;
|
|
20
23
|
unitIndex: number;
|
|
24
|
+
historyDepth?: number;
|
|
25
|
+
writeIndex?: number;
|
|
21
26
|
}
|
|
27
|
+
type TextureSource = HTMLImageElement | HTMLVideoElement;
|
|
22
28
|
interface PluginContext {
|
|
23
29
|
gl: WebGL2RenderingContext;
|
|
24
30
|
uniforms: Map<string, Uniform>;
|
|
25
31
|
textures: Map<string, Texture>;
|
|
26
|
-
program: WebGLProgram | null;
|
|
32
|
+
get program(): WebGLProgram | null;
|
|
27
33
|
canvas: HTMLCanvasElement;
|
|
34
|
+
reserveTextureUnit: (name: string) => number;
|
|
35
|
+
releaseTextureUnit: (name: string) => void;
|
|
28
36
|
}
|
|
29
37
|
type Plugin = (shaderPad: ShaderPad, context: PluginContext) => void;
|
|
30
38
|
type LifecycleMethod = 'init' | 'step' | 'destroy' | 'updateResolution' | 'reset';
|
|
@@ -40,6 +48,7 @@ declare class ShaderPad {
|
|
|
40
48
|
private fragmentShaderSrc;
|
|
41
49
|
private uniforms;
|
|
42
50
|
private textures;
|
|
51
|
+
private textureUnitPool;
|
|
43
52
|
private buffer;
|
|
44
53
|
private program;
|
|
45
54
|
private animationFrameId;
|
|
@@ -75,6 +84,8 @@ declare class ShaderPad {
|
|
|
75
84
|
updateTextures(updates: Record<string, HTMLImageElement | HTMLVideoElement>): void;
|
|
76
85
|
save(filename: string): Promise<void>;
|
|
77
86
|
destroy(): void;
|
|
87
|
+
private reserveTextureUnit;
|
|
88
|
+
private releaseTextureUnit;
|
|
78
89
|
}
|
|
79
90
|
|
|
80
|
-
export { type PluginContext, type WithSave, ShaderPad as default, history, save };
|
|
91
|
+
export { type PluginContext, type TextureSource, type WithHistory, type WithSave, ShaderPad as default, history, save };
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var p=Object.defineProperty;var U=Object.getOwnPropertyDescriptor;var A=Object.getOwnPropertyNames;var L=Object.prototype.hasOwnProperty;var P=(s,t)=>{for(var i in t)p(s,i,{get:t[i],enumerable:!0})},I=(s,t,i,e)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of A(t))!L.call(s,r)&&r!==i&&p(s,r,{get:()=>t[r],enumerable:!(e=U(t,r))||e.enumerable});return s};var S=s=>I(p({},"__esModule",{value:!0}),s);var C={};P(C,{default:()=>F,history:()=>y,save:()=>D});module.exports=S(C);function R(s){let t=s,i=s,e=t.videoWidth||i.naturalWidth||i.width,r=t.videoHeight||i.naturalHeight||i.height;return{width:e,height:r}}function _(s,t,i,e){let r=new Uint8Array(t*i*4);for(let n=0;n<e;++n)s.texSubImage3D(s.TEXTURE_2D_ARRAY,0,0,0,n,t,i,1,s.RGBA,s.UNSIGNED_BYTE,r)}function b(s,t,i,e){let r=s.createTexture();if(!r)throw new Error("Failed to create history texture");return s.activeTexture(s.TEXTURE0),s.bindTexture(s.TEXTURE_2D_ARRAY,r),s.texParameteri(s.TEXTURE_2D_ARRAY,s.TEXTURE_WRAP_S,s.CLAMP_TO_EDGE),s.texParameteri(s.TEXTURE_2D_ARRAY,s.TEXTURE_WRAP_T,s.CLAMP_TO_EDGE),s.texParameteri(s.TEXTURE_2D_ARRAY,s.TEXTURE_MIN_FILTER,s.LINEAR),s.texParameteri(s.TEXTURE_2D_ARRAY,s.TEXTURE_MAG_FILTER,s.LINEAR),s.texStorage3D(s.TEXTURE_2D_ARRAY,1,s.RGBA8,i,e,t),_(s,i,e,t),r}function y(s=1){return function(t,i){let{gl:e,uniforms:r,textures:n,reserveTextureUnit:a}=i,c=t,T=t.initializeTexture.bind(t),w=t.updateTextures.bind(t),u=null;if(s>1){let o=function(){u=b(e,s,e.drawingBufferWidth,e.drawingBufferHeight),r.has("u_history")||t.initializeUniform("u_history","int",0)},l=function(){u&&(e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D_ARRAY,u),_(e,e.drawingBufferWidth,e.drawingBufferHeight,s))};var W=o,G=l;t.registerHook("init",o),t.registerHook("step",(d,h)=>{if(!u)return;let f=h%s;e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D_ARRAY,u),e.copyTexSubImage3D(e.TEXTURE_2D_ARRAY,0,0,0,f,0,0,e.drawingBufferWidth,e.drawingBufferHeight)}),t.registerHook("updateResolution",()=>{u&&e.deleteTexture(u),o()}),t.registerHook("reset",l)}t.registerHook("reset",()=>{n.forEach(o=>{o.historyDepth&&o.historyDepth>1&&o.writeIndex!==void 0&&(o.writeIndex=0)})}),c.initializeTexture=function(o,l,d=1){let{width:h,height:f}=R(l);if(!h||!f)throw new Error("Texture source must have valid dimensions");let m=Math.floor(d);if(m<=1)return T(o,l);if(n.has(o))throw new Error(`Texture '${o}' is already initialized.`);let g,E=null;try{if(g=a(o),E=b(e,m,h,f),e.activeTexture(e.TEXTURE0+g),e.bindTexture(e.TEXTURE_2D_ARRAY,E),e.pixelStorei(e.UNPACK_FLIP_Y_WEBGL,!0),e.texParameteri(e.TEXTURE_2D_ARRAY,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D_ARRAY,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D_ARRAY,e.TEXTURE_MIN_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_2D_ARRAY,e.TEXTURE_MAG_FILTER,e.LINEAR),i.program){let x=e.getUniformLocation(i.program,o);x&&e.uniform1i(x,g)}n.set(o,{texture:E,unitIndex:g,historyDepth:m,writeIndex:0}),c.updateTextures({[o]:l})}catch(x){throw E&&e.deleteTexture(E),g!==void 0&&i.releaseTextureUnit(o),x}},c.updateTextures=function(o){Object.entries(o).forEach(([l,d])=>{let h=n.get(l);if(!h||!h.historyDepth||h.historyDepth<=1)return w({[l]:d});let{width:f,height:m}=R(d),g=h.writeIndex??0;e.activeTexture(e.TEXTURE0+h.unitIndex),e.bindTexture(e.TEXTURE_2D_ARRAY,h.texture),e.texSubImage3D(e.TEXTURE_2D_ARRAY,0,0,0,g,f,m,1,e.RGBA,e.UNSIGNED_BYTE,d),h.writeIndex=(g+1)%h.historyDepth})},t.registerHook("destroy",()=>{u&&e.deleteTexture(u)})}}function D(){return function(s,t){let{gl:i,canvas:e}=t,r=document.createElement("a");s.save=async function(n){if(i.clear(i.COLOR_BUFFER_BIT),i.drawArrays(i.TRIANGLES,0,6),n&&!`${n}`.toLowerCase().endsWith(".png")&&(n=`${n}.png`),n=n||"export.png","ongesturechange"in window)try{let a=await new Promise(T=>e.toBlob(T,"image/png")),c=new File([a],n,{type:a.type});if(navigator.canShare?.({files:[c]})){await navigator.share({files:[c]});return}}catch(a){console.warn("Web Share API failed:",a)}else r.download=n,r.href=e.toDataURL(),r.click()}}}var M=`#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
|
-
`,b=1e3/30,c=class{constructor(e,r={}){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.hooks=new Map;if(this.canvas=r.canvas||document.createElement("canvas"),r.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.");if(this.downloadLink=document.createElement("a"),this.fragmentShaderSrc=e,this.animationFrameId=null,this.resolutionObserver=new MutationObserver(()=>this.updateResolution()),this.resizeObserver=new ResizeObserver(()=>this.throttledHandleResize()),r.plugins){let i={gl:this.gl,uniforms:this.uniforms,textures:this.textures,program:this.program,canvas:this.canvas};r.plugins.forEach(t=>t(this,i))}this.init(),this.addEventListeners()}registerHook(e,r){this.hooks.has(e)||this.hooks.set(e,[]),this.hooks.get(e).push(r)}init(){let e=w;if(this.program=this.gl.createProgram(),!this.program)throw new Error("Failed to create WebGL program");let r=this.createShader(this.gl.VERTEX_SHADER,e),i=this.createShader(this.gl.FRAGMENT_SHADER,this.fragmentShaderSrc);if(this.gl.attachShader(this.program,r),this.gl.attachShader(this.program,i),this.gl.linkProgram(this.program),this.gl.deleteShader(r),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 t=this.gl.getAttribLocation(this.program,"aPosition");this.setupBuffer(t),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.hooks.get("init")?.forEach(s=>s.call(this))}createShader(e,r){let i=this.gl.createShader(e);if(this.gl.shaderSource(i,r),this.gl.compileShader(i),!this.gl.getShaderParameter(i,this.gl.COMPILE_STATUS))throw console.error("Shader compilation failed:",r),console.error(this.gl.getShaderInfoLog(i)),this.gl.deleteShader(i),new Error("Shader compilation failed");return i}setupBuffer(e){let r=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,r,this.gl.STATIC_DRAW),this.gl.viewport(0,0,this.gl.drawingBufferWidth,this.gl.drawingBufferHeight),this.gl.enableVertexAttribArray(e),this.gl.vertexAttribPointer(e,2,this.gl.FLOAT,!1,0,0)}throttledHandleResize(){clearTimeout(this.resizeTimeout);let e=performance.now(),r=this.lastResizeTime+b-e;r<=0?(this.lastResizeTime=e,this.handleResize()):this.resizeTimeout=setTimeout(()=>this.throttledHandleResize(),r)}handleResize(){let e=window.devicePixelRatio||1,r=this.canvas.clientWidth*e,i=this.canvas.clientHeight*e;this.isInternalCanvas&&(this.canvas.width!==r||this.canvas.height!==i)&&(this.canvas.width=r,this.canvas.height=i),this.onResize?.(r,i)}addEventListeners(){let e=(i,t)=>{if(!this.uniforms.has("u_cursor"))return;let s=this.canvas.getBoundingClientRect();this.cursorPosition[0]=(i-s.left)/s.width,this.cursorPosition[1]=1-(t-s.top)/s.height,this.updateUniforms({u_cursor:this.cursorPosition})},r=(i,t,s)=>{if(this.uniforms.has("u_click")){if(this.isMouseDown=i,i){let o=this.canvas.getBoundingClientRect(),a=t,h=s;this.clickPosition[0]=(a-o.left)/o.width,this.clickPosition[1]=1-(h-o.top)/o.height}this.updateUniforms({u_click:[...this.clickPosition,this.isMouseDown?1:0]})}};this.eventListeners.set("mousemove",i=>{let t=i;this.isTouchDevice||e(t.clientX,t.clientY)}),this.eventListeners.set("mousedown",i=>{let t=i;this.isTouchDevice||t.button===0&&(this.isMouseDown=!0,r(!0,t.clientX,t.clientY))}),this.eventListeners.set("mouseup",i=>{let t=i;this.isTouchDevice||t.button===0&&r(!1)}),this.eventListeners.set("touchmove",i=>{let t=i;t.touches.length>0&&e(t.touches[0].clientX,t.touches[0].clientY)}),this.eventListeners.set("touchstart",i=>{let t=i;this.isTouchDevice=!0,t.touches.length>0&&(e(t.touches[0].clientX,t.touches[0].clientY),r(!0,t.touches[0].clientX,t.touches[0].clientY))}),this.eventListeners.set("touchend",i=>{i.touches.length===0&&r(!1)}),this.eventListeners.forEach((i,t)=>{this.canvas.addEventListener(t,i)})}updateResolution(){let e=this.gl.drawingBufferWidth,r=this.gl.drawingBufferHeight;this.gl.viewport(0,0,e,r),this.uniforms.has("u_resolution")?this.updateUniforms({u_resolution:[e,r]}):this.initializeUniform("u_resolution","float",[e,r]),this.hooks.get("updateResolution")?.forEach(i=>i.call(this))}initializeUniform(e,r,i){if(this.uniforms.has(e))throw new Error(`Uniform '${e}' is already initialized.`);if(r!=="float"&&r!=="int")throw new Error(`Invalid uniform type: ${r}. Expected 'float' or 'int'.`);let t=this.gl.getUniformLocation(this.program,e);if(!t){console.debug(`Uniform ${e} 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(e,{type:r,length:s,location:t}),this.updateUniforms({[e]:i})}updateUniforms(e){Object.entries(e).forEach(([r,i])=>{if(!this.uniforms.has(r))throw new Error(`Uniform '${r}' is not initialized.`);let t=this.uniforms.get(r);if(Array.isArray(i)||(i=[i]),i.length!==t.length)throw new Error(`Invalid uniform value length: ${i.length}. Expected ${t.length}.`);this.gl[`uniform${t.length}${t.type.charAt(0)}`](t.location,...i)})}step(e){let r=this.gl;this.uniforms.has("u_time")&&this.updateUniforms({u_time:e}),this.uniforms.has("u_frame")&&this.updateUniforms({u_frame:this.frame}),r.clear(r.COLOR_BUFFER_BIT),r.drawArrays(r.TRIANGLES,0,6),this.hooks.get("step")?.forEach(i=>i.call(this,e,this.frame)),++this.frame}play(e){this.pause();let r=i=>{i=(i-this.startTime)/1e3,this.step(i),this.animationFrameId=requestAnimationFrame(r),e&&e(i,this.frame)};this.animationFrameId=requestAnimationFrame(r)}pause(){this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null)}reset(){this.frame=0,this.startTime=performance.now(),this.hooks.get("reset")?.forEach(e=>e.call(this))}initializeTexture(e,r){if(this.textures.has(e))throw new Error(`Texture '${e}' is already initialized.`);let i=this.gl.createTexture();if(!i)throw new Error("Failed to create texture");let t=this.textures.size+1;this.gl.activeTexture(this.gl.TEXTURE0+t),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(e,{texture:i,unitIndex:t}),this.updateTextures({[e]:r});let s=this.gl.getUniformLocation(this.program,e);s&&this.gl.uniform1i(s,t)}updateTextures(e){Object.entries(e).forEach(([r,i])=>{let t=this.textures.get(r);if(!t)throw new Error(`Texture '${r}' is not initialized.`);this.gl.activeTexture(this.gl.TEXTURE0+t.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D,t.texture),this.gl.texImage2D(this.gl.TEXTURE_2D,0,this.gl.RGBA,this.gl.RGBA,this.gl.UNSIGNED_BYTE,i)})}async save(e){if(this.gl.clear(this.gl.COLOR_BUFFER_BIT),this.gl.drawArrays(this.gl.TRIANGLES,0,6),e&&!`${e}`.toLowerCase().endsWith(".png")&&(e=`${e}.png`),e=e||"export.png","ongesturechange"in window)try{let r=await new Promise(t=>this.canvas.toBlob(t,"image/png")),i=new File([r],e,{type:r.type});if(navigator.canShare?.({files:[i]})){await navigator.share({files:[i]});return}}catch(r){console.warn("Web Share API failed:",r)}else this.downloadLink.download=e,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((e,r)=>{this.canvas.removeEventListener(r,e)}),this.program&&this.gl.deleteProgram(this.program),this.textures.forEach(e=>{this.gl.deleteTexture(e.texture)}),this.buffer&&(this.gl.deleteBuffer(this.buffer),this.buffer=null),this.hooks.get("destroy")?.forEach(e=>e.call(this)),this.isInternalCanvas&&this.canvas.remove()}},_=c;0&&(module.exports={history,save});
|
|
8
|
+
`,X=1e3/30,v=class{constructor(t,i={}){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.hooks=new Map;if(this.canvas=i.canvas||document.createElement("canvas"),i.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.");if(this.textureUnitPool={free:[],next:1,max:this.gl.getParameter(this.gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS)},this.downloadLink=document.createElement("a"),this.fragmentShaderSrc=t,this.animationFrameId=null,this.resolutionObserver=new MutationObserver(()=>this.updateResolution()),this.resizeObserver=new ResizeObserver(()=>this.throttledHandleResize()),i.plugins){let e={gl:this.gl,uniforms:this.uniforms,textures:this.textures,canvas:this.canvas,reserveTextureUnit:this.reserveTextureUnit.bind(this),releaseTextureUnit:this.releaseTextureUnit.bind(this)};Object.defineProperty(e,"program",{get:()=>this.program,enumerable:!0,configurable:!0}),i.plugins.forEach(r=>r(this,e))}this.init(),this.addEventListeners()}registerHook(t,i){this.hooks.has(t)||this.hooks.set(t,[]),this.hooks.get(t).push(i)}init(){let t=M;if(this.program=this.gl.createProgram(),!this.program)throw new Error("Failed to create WebGL program");let i=this.createShader(this.gl.VERTEX_SHADER,t),e=this.createShader(this.gl.FRAGMENT_SHADER,this.fragmentShaderSrc);if(this.gl.attachShader(this.program,i),this.gl.attachShader(this.program,e),this.gl.linkProgram(this.program),this.gl.deleteShader(i),this.gl.deleteShader(e),!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.hooks.get("init")?.forEach(n=>n.call(this))}createShader(t,i){let e=this.gl.createShader(t);if(this.gl.shaderSource(e,i),this.gl.compileShader(e),!this.gl.getShaderParameter(e,this.gl.COMPILE_STATUS))throw console.error("Shader compilation failed:",i),console.error(this.gl.getShaderInfoLog(e)),this.gl.deleteShader(e),new Error("Shader compilation failed");return e}setupBuffer(t){let i=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,i,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(),i=this.lastResizeTime+X-t;i<=0?(this.lastResizeTime=t,this.handleResize()):this.resizeTimeout=setTimeout(()=>this.throttledHandleResize(),i)}handleResize(){let t=window.devicePixelRatio||1,i=this.canvas.clientWidth*t,e=this.canvas.clientHeight*t;this.isInternalCanvas&&(this.canvas.width!==i||this.canvas.height!==e)&&(this.canvas.width=i,this.canvas.height=e),this.onResize?.(i,e)}addEventListeners(){let t=(e,r)=>{if(!this.uniforms.has("u_cursor"))return;let n=this.canvas.getBoundingClientRect();this.cursorPosition[0]=(e-n.left)/n.width,this.cursorPosition[1]=1-(r-n.top)/n.height,this.updateUniforms({u_cursor:this.cursorPosition})},i=(e,r,n)=>{if(this.uniforms.has("u_click")){if(this.isMouseDown=e,e){let a=this.canvas.getBoundingClientRect(),c=r,T=n;this.clickPosition[0]=(c-a.left)/a.width,this.clickPosition[1]=1-(T-a.top)/a.height}this.updateUniforms({u_click:[...this.clickPosition,this.isMouseDown?1:0]})}};this.eventListeners.set("mousemove",e=>{let r=e;this.isTouchDevice||t(r.clientX,r.clientY)}),this.eventListeners.set("mousedown",e=>{let r=e;this.isTouchDevice||r.button===0&&(this.isMouseDown=!0,i(!0,r.clientX,r.clientY))}),this.eventListeners.set("mouseup",e=>{let r=e;this.isTouchDevice||r.button===0&&i(!1)}),this.eventListeners.set("touchmove",e=>{let r=e;r.touches.length>0&&t(r.touches[0].clientX,r.touches[0].clientY)}),this.eventListeners.set("touchstart",e=>{let r=e;this.isTouchDevice=!0,r.touches.length>0&&(t(r.touches[0].clientX,r.touches[0].clientY),i(!0,r.touches[0].clientX,r.touches[0].clientY))}),this.eventListeners.set("touchend",e=>{e.touches.length===0&&i(!1)}),this.eventListeners.forEach((e,r)=>{this.canvas.addEventListener(r,e)})}updateResolution(){let t=this.gl.drawingBufferWidth,i=this.gl.drawingBufferHeight;this.gl.viewport(0,0,t,i),this.uniforms.has("u_resolution")?this.updateUniforms({u_resolution:[t,i]}):this.initializeUniform("u_resolution","float",[t,i]),this.hooks.get("updateResolution")?.forEach(e=>e.call(this))}initializeUniform(t,i,e){if(this.uniforms.has(t))throw new Error(`Uniform '${t}' is already initialized.`);if(i!=="float"&&i!=="int")throw new Error(`Invalid uniform type: ${i}. 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(e)||(e=[e]),e.length<1||e.length>4)throw new Error(`Invalid uniform value length: ${e.length}. Expected a length between 1 and 4.`);let n=e.length;this.uniforms.set(t,{type:i,length:n,location:r}),this.updateUniforms({[t]:e})}updateUniforms(t){Object.entries(t).forEach(([i,e])=>{if(!this.uniforms.has(i))throw new Error(`Uniform '${i}' is not initialized.`);let r=this.uniforms.get(i);if(Array.isArray(e)||(e=[e]),e.length!==r.length)throw new Error(`Invalid uniform value length: ${e.length}. Expected ${r.length}.`);this.gl[`uniform${r.length}${r.type.charAt(0)}`](r.location,...e)})}step(t){let i=this.gl;this.uniforms.has("u_time")&&this.updateUniforms({u_time:t}),this.uniforms.has("u_frame")&&this.updateUniforms({u_frame:this.frame}),i.clear(i.COLOR_BUFFER_BIT),i.drawArrays(i.TRIANGLES,0,6),this.hooks.get("step")?.forEach(e=>e.call(this,t,this.frame)),++this.frame}play(t){this.pause();let i=e=>{e=(e-this.startTime)/1e3,this.step(e),this.animationFrameId=requestAnimationFrame(i),t&&t(e,this.frame)};this.animationFrameId=requestAnimationFrame(i)}pause(){this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null)}reset(){this.frame=0,this.startTime=performance.now(),this.hooks.get("reset")?.forEach(t=>t.call(this))}initializeTexture(t,i){if(this.textures.has(t))throw new Error(`Texture '${t}' is already initialized.`);let e=this.gl.createTexture();if(!e)throw new Error("Failed to create texture");let r;try{r=this.reserveTextureUnit(t)}catch(a){throw this.gl.deleteTexture(e),a}this.gl.activeTexture(this.gl.TEXTURE0+r),this.gl.bindTexture(this.gl.TEXTURE_2D,e),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:e,unitIndex:r}),this.updateTextures({[t]:i});let n=this.gl.getUniformLocation(this.program,t);n&&this.gl.uniform1i(n,r)}updateTextures(t){Object.entries(t).forEach(([i,e])=>{let r=this.textures.get(i);if(!r)throw new Error(`Texture '${i}' 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,e)})}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 i=await new Promise(r=>this.canvas.toBlob(r,"image/png")),e=new File([i],t,{type:i.type});if(navigator.canShare?.({files:[e]})){await navigator.share({files:[e]});return}}catch(i){console.warn("Web Share API failed:",i)}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,i)=>{this.canvas.removeEventListener(i,t)}),this.program&&this.gl.deleteProgram(this.program),this.textures.forEach(t=>{this.gl.deleteTexture(t.texture)}),this.textureUnitPool.free=[],this.textureUnitPool.next=1,this.buffer&&(this.gl.deleteBuffer(this.buffer),this.buffer=null),this.hooks.get("destroy")?.forEach(t=>t.call(this)),this.isInternalCanvas&&this.canvas.remove()}reserveTextureUnit(t){if(!t)throw new Error("Texture unit name must be provided.");let i=this.textures.get(t);if(i)return i.unitIndex;let e;if(this.textureUnitPool.free.length>0)e=this.textureUnitPool.free.pop();else{if(e=this.textureUnitPool.next,e>=this.textureUnitPool.max)throw new Error("Exceeded the available texture units for this device.");this.textureUnitPool.next+=1}return e}releaseTextureUnit(t){let i=this.textures.get(t);if(!i)return;let e=i.unitIndex;e>0&&this.textureUnitPool.free.push(e)}},F=v;0&&(module.exports={history,save});
|
|
9
9
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/plugins/history.ts","../src/plugins/save.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\nexport interface PluginContext {\n\tgl: WebGL2RenderingContext;\n\tuniforms: Map<string, Uniform>;\n\ttextures: Map<string, Texture>;\n\tprogram: WebGLProgram | null;\n\tcanvas: HTMLCanvasElement;\n}\n\ntype Plugin = (shaderPad: ShaderPad, context: PluginContext) => void;\n\ntype LifecycleMethod = 'init' | 'step' | 'destroy' | 'updateResolution' | 'reset';\n\ninterface Options {\n\tcanvas?: HTMLCanvasElement | null;\n\tplugins?: Plugin[];\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\tpublic canvas: HTMLCanvasElement;\n\tpublic onResize?: (width: number, height: number) => void;\n\tprivate hooks: Map<LifecycleMethod, Function[]> = new Map();\n\n\tconstructor(fragmentShaderSrc: string, options: Options = {}) {\n\t\tthis.canvas = options.canvas || document.createElement('canvas');\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\tif (options.plugins) {\n\t\t\tconst context: PluginContext = {\n\t\t\t\tgl: this.gl,\n\t\t\t\tuniforms: this.uniforms,\n\t\t\t\ttextures: this.textures,\n\t\t\t\tprogram: this.program,\n\t\t\t\tcanvas: this.canvas,\n\t\t\t};\n\t\t\toptions.plugins.forEach(plugin => plugin(this, context));\n\t\t}\n\t\tthis.init();\n\t\tthis.addEventListeners();\n\t}\n\n\tregisterHook(name: LifecycleMethod, fn: Function) {\n\t\tif (!this.hooks.has(name)) {\n\t\t\tthis.hooks.set(name, []);\n\t\t}\n\t\tthis.hooks.get(name)!.push(fn);\n\t}\n\n\tprivate init() {\n\t\tconst vertexShaderSrc = DEFAULT_VERTEX_SHADER_SRC;\n\n\t\tthis.program = this.gl.createProgram();\n\t\tif (!this.program) {\n\t\t\tthrow new Error('Failed to create WebGL program');\n\t\t}\n\t\tconst vertexShader = this.createShader(this.gl.VERTEX_SHADER, vertexShaderSrc);\n\t\tconst fragmentShader = this.createShader(this.gl.FRAGMENT_SHADER, this.fragmentShaderSrc);\n\n\t\tthis.gl.attachShader(this.program, vertexShader);\n\t\tthis.gl.attachShader(this.program, fragmentShader);\n\t\tthis.gl.linkProgram(this.program);\n\t\tthis.gl.deleteShader(vertexShader);\n\t\tthis.gl.deleteShader(fragmentShader);\n\n\t\tif (!this.gl.getProgramParameter(this.program, this.gl.LINK_STATUS)) {\n\t\t\tconsole.error('Program link error:', this.gl.getProgramInfoLog(this.program));\n\t\t\tthis.gl.deleteProgram(this.program);\n\t\t\tthrow new Error('Failed to link WebGL program');\n\t\t}\n\n\t\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\n\t\tthis.hooks.get('init')?.forEach(hook => hook.call(this));\n\t}\n\n\tprivate createShader(type: number, source: string): WebGLShader {\n\t\tconst shader = this.gl.createShader(type)!;\n\t\tthis.gl.shaderSource(shader, source);\n\t\tthis.gl.compileShader(shader);\n\t\tif (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)) {\n\t\t\tconsole.error('Shader compilation failed:', source);\n\t\t\tconsole.error(this.gl.getShaderInfoLog(shader));\n\t\t\tthis.gl.deleteShader(shader);\n\t\t\tthrow new Error('Shader compilation failed');\n\t\t}\n\t\treturn shader;\n\t}\n\n\tprivate setupBuffer(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\tthis.hooks.get('updateResolution')?.forEach(hook => hook.call(this));\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\tgl.clear(gl.COLOR_BUFFER_BIT);\n\t\tgl.drawArrays(gl.TRIANGLES, 0, 6);\n\n\t\tthis.hooks.get('step')?.forEach(hook => hook.call(this, time, this.frame));\n\n\t\t++this.frame;\n\t}\n\n\tplay(callback?: (time: number, frame: number) => void) {\n\t\tthis.pause(); // Prevent double play.\n\t\tconst loop = (time: number) => {\n\t\t\ttime = (time - this.startTime) / 1000; // Convert from milliseconds to seconds.\n\t\t\tthis.step(time);\n\t\t\tthis.animationFrameId = requestAnimationFrame(loop);\n\t\t\tif (callback) callback(time, this.frame);\n\t\t};\n\t\tthis.animationFrameId = requestAnimationFrame(loop);\n\t}\n\n\tpause() {\n\t\tif (this.animationFrameId) {\n\t\t\tcancelAnimationFrame(this.animationFrameId);\n\t\t\tthis.animationFrameId = null;\n\t\t}\n\t}\n\n\treset() {\n\t\tthis.frame = 0;\n\t\tthis.startTime = performance.now();\n\t\tthis.hooks.get('reset')?.forEach(hook => hook.call(this));\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.buffer) {\n\t\t\tthis.gl.deleteBuffer(this.buffer);\n\t\t\tthis.buffer = null;\n\t\t}\n\n\t\tthis.hooks.get('destroy')?.forEach(hook => hook.call(this));\n\n\t\tif (this.isInternalCanvas) {\n\t\t\tthis.canvas.remove();\n\t\t}\n\t}\n}\n\nexport * from './plugins';\nexport default ShaderPad;\n","import ShaderPad, { PluginContext } from '../index';\n\nexport function history(depth: number = 2) {\n\tif (depth < 2) {\n\t\tthrow new Error('History depth must be greater than 1');\n\t}\n\n\treturn function (shaderPad: ShaderPad, context: PluginContext) {\n\t\tlet historyTexture: WebGLTexture | null = null;\n\t\tconst { gl, uniforms } = context;\n\n\t\tshaderPad.registerHook('init', initializeHistoryBuffer);\n\t\tshaderPad.registerHook('step', (_time: number, frame: number) => {\n\t\t\tconst writeIdx = frame % depth;\n\n\t\t\tgl.activeTexture(gl.TEXTURE0);\n\t\t\tgl.bindTexture(gl.TEXTURE_2D_ARRAY, 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\tgl.drawingBufferWidth,\n\t\t\t\tgl.drawingBufferHeight\n\t\t\t);\n\t\t});\n\t\tshaderPad.registerHook('updateResolution', () => {\n\t\t\tgl.deleteTexture(historyTexture);\n\t\t\tinitializeHistoryBuffer();\n\t\t});\n\t\tshaderPad.registerHook('reset', clearHistory);\n\t\tshaderPad.registerHook('destroy', () => {\n\t\t\tgl.deleteTexture(historyTexture);\n\t\t\thistoryTexture = null;\n\t\t});\n\n\t\tfunction initializeHistoryBuffer() {\n\t\t\thistoryTexture = gl.createTexture();\n\t\t\tif (!historyTexture) {\n\t\t\t\tthrow new Error('Failed to create history texture');\n\t\t\t}\n\t\t\tgl.bindTexture(gl.TEXTURE_2D_ARRAY, historyTexture);\n\t\t\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n\t\t\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n\t\t\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_MIN_FILTER, gl.NEAREST);\n\t\t\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_MAG_FILTER, gl.NEAREST);\n\t\t\tgl.texStorage3D(gl.TEXTURE_2D_ARRAY, 1, gl.RGBA8, gl.drawingBufferWidth, gl.drawingBufferHeight, depth);\n\t\t\tgl.activeTexture(gl.TEXTURE0);\n\t\t\tgl.bindTexture(gl.TEXTURE_2D_ARRAY, historyTexture);\n\n\t\t\tclearHistory();\n\n\t\t\tif (!uniforms.has('u_history')) {\n\t\t\t\tshaderPad.initializeUniform('u_history', 'int', 0);\n\t\t\t}\n\t\t}\n\n\t\tfunction clearHistory() {\n\t\t\tgl.activeTexture(gl.TEXTURE0);\n\t\t\tgl.bindTexture(gl.TEXTURE_2D_ARRAY, historyTexture);\n\t\t\tconst transparent = new Uint8Array(gl.drawingBufferWidth * gl.drawingBufferHeight * 4);\n\t\t\tfor (let layer = 0; layer < depth; ++layer) {\n\t\t\t\tgl.texSubImage3D(\n\t\t\t\t\tgl.TEXTURE_2D_ARRAY,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\tlayer,\n\t\t\t\t\tgl.drawingBufferWidth,\n\t\t\t\t\tgl.drawingBufferHeight,\n\t\t\t\t\t1,\n\t\t\t\t\tgl.RGBA,\n\t\t\t\t\tgl.UNSIGNED_BYTE,\n\t\t\t\t\ttransparent\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t};\n}\n","import ShaderPad, { PluginContext } from '../index';\n\ndeclare module '../index' {\n\tinterface ShaderPad {\n\t\tsave(filename: string): Promise<void>;\n\t}\n}\n\nexport function save() {\n\treturn function (shaderPad: ShaderPad, context: PluginContext) {\n\t\tconst { gl, canvas } = context;\n\t\tconst downloadLink = document.createElement('a');\n\n\t\t(shaderPad as any).save = async function (filename: string) {\n\t\t\tgl.clear(gl.COLOR_BUFFER_BIT);\n\t\t\tgl.drawArrays(gl.TRIANGLES, 0, 6);\n\n\t\t\tif (filename && !`${filename}`.toLowerCase().endsWith('.png')) {\n\t\t\t\tfilename = `${filename}.png`;\n\t\t\t}\n\t\t\tfilename = filename || 'export.png';\n\t\t\tif ('ongesturechange' in window) {\n\t\t\t\t// Mobile.\n\t\t\t\ttry {\n\t\t\t\t\tconst blob: Blob = await new Promise(resolve =>\n\t\t\t\t\t\tcanvas.toBlob(resolve as BlobCallback, 'image/png')\n\t\t\t\t\t);\n\t\t\t\t\tconst file = new File([blob], filename, { type: blob.type });\n\n\t\t\t\t\tif (navigator.canShare?.({ files: [file] })) {\n\t\t\t\t\t\tawait navigator.share({ files: [file] });\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconsole.warn('Web Share API failed:', error);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Desktop.\n\t\t\t\tdownloadLink.download = filename;\n\t\t\t\tdownloadLink.href = canvas.toDataURL();\n\t\t\t\tdownloadLink.click();\n\t\t\t}\n\t\t};\n\t};\n}\n\n// Type helper.\nexport type WithSave<T extends ShaderPad> = T & {\n\tsave(filename: string): Promise<void>;\n};\n"],"mappings":"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","names":["index_exports","__export","index_default","history","save","__toCommonJS","history","depth","shaderPad","context","historyTexture","gl","uniforms","initializeHistoryBuffer","_time","frame","writeIdx","clearHistory","transparent","layer","save","shaderPad","context","gl","canvas","downloadLink","filename","blob","resolve","file","error","DEFAULT_VERTEX_SHADER_SRC","RESIZE_THROTTLE_INTERVAL","ShaderPad","fragmentShaderSrc","options","context","plugin","name","fn","vertexShaderSrc","vertexShader","fragmentShader","aPosition","hook","type","source","shader","quadVertices","now","timeUntilNextResize","pixelRatio","width","height","updateCursor","x","y","rect","updateClick","isMouseDown","xVal","yVal","event","mouseEvent","touchEvent","listener","value","location","length","updates","uniform","time","gl","callback","loop","texture","unitIndex","uSampler","info","filename","blob","resolve","file","error","index_default"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/plugins/history.ts","../src/plugins/save.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\thistoryDepth?: number;\n\twriteIndex?: number;\n}\n\nexport type TextureSource = HTMLImageElement | HTMLVideoElement;\n\nexport interface PluginContext {\n\tgl: WebGL2RenderingContext;\n\tuniforms: Map<string, Uniform>;\n\ttextures: Map<string, Texture>;\n\tget program(): WebGLProgram | null;\n\tcanvas: HTMLCanvasElement;\n\treserveTextureUnit: (name: string) => number;\n\treleaseTextureUnit: (name: string) => void;\n}\n\ntype Plugin = (shaderPad: ShaderPad, context: PluginContext) => void;\n\ntype LifecycleMethod = 'init' | 'step' | 'destroy' | 'updateResolution' | 'reset';\n\ninterface Options {\n\tcanvas?: HTMLCanvasElement | null;\n\tplugins?: Plugin[];\n}\n\ntype TextureUnitPool = {\n\tfree: number[];\n\tnext: number;\n\tmax: 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 textureUnitPool: TextureUnitPool;\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\tpublic canvas: HTMLCanvasElement;\n\tpublic onResize?: (width: number, height: number) => void;\n\tprivate hooks: Map<LifecycleMethod, Function[]> = new Map();\n\n\tconstructor(fragmentShaderSrc: string, options: Options = {}) {\n\t\tthis.canvas = options.canvas || document.createElement('canvas');\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.textureUnitPool = {\n\t\t\tfree: [],\n\t\t\tnext: 1, // Start from unit 1 to avoid conflict with history texture at unit 0.\n\t\t\tmax: this.gl.getParameter(this.gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS),\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\tif (options.plugins) {\n\t\t\tconst context: PluginContext = {\n\t\t\t\tgl: this.gl,\n\t\t\t\tuniforms: this.uniforms,\n\t\t\t\ttextures: this.textures,\n\t\t\t\tcanvas: this.canvas,\n\t\t\t\treserveTextureUnit: this.reserveTextureUnit.bind(this),\n\t\t\t\treleaseTextureUnit: this.releaseTextureUnit.bind(this),\n\t\t\t} as PluginContext;\n\t\t\t// Define program as a getter so it always returns the current program.\n\t\t\tObject.defineProperty(context, 'program', {\n\t\t\t\tget: () => this.program,\n\t\t\t\tenumerable: true,\n\t\t\t\tconfigurable: true,\n\t\t\t});\n\t\t\toptions.plugins.forEach(plugin => plugin(this, context));\n\t\t}\n\t\tthis.init();\n\t\tthis.addEventListeners();\n\t}\n\n\tregisterHook(name: LifecycleMethod, fn: Function) {\n\t\tif (!this.hooks.has(name)) {\n\t\t\tthis.hooks.set(name, []);\n\t\t}\n\t\tthis.hooks.get(name)!.push(fn);\n\t}\n\n\tprivate init() {\n\t\tconst vertexShaderSrc = DEFAULT_VERTEX_SHADER_SRC;\n\n\t\tthis.program = this.gl.createProgram();\n\t\tif (!this.program) {\n\t\t\tthrow new Error('Failed to create WebGL program');\n\t\t}\n\t\tconst vertexShader = this.createShader(this.gl.VERTEX_SHADER, vertexShaderSrc);\n\t\tconst fragmentShader = this.createShader(this.gl.FRAGMENT_SHADER, this.fragmentShaderSrc);\n\n\t\tthis.gl.attachShader(this.program, vertexShader);\n\t\tthis.gl.attachShader(this.program, fragmentShader);\n\t\tthis.gl.linkProgram(this.program);\n\t\tthis.gl.deleteShader(vertexShader);\n\t\tthis.gl.deleteShader(fragmentShader);\n\n\t\tif (!this.gl.getProgramParameter(this.program, this.gl.LINK_STATUS)) {\n\t\t\tconsole.error('Program link error:', this.gl.getProgramInfoLog(this.program));\n\t\t\tthis.gl.deleteProgram(this.program);\n\t\t\tthrow new Error('Failed to link WebGL program');\n\t\t}\n\n\t\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\n\t\tthis.hooks.get('init')?.forEach(hook => hook.call(this));\n\t}\n\n\tprivate createShader(type: number, source: string): WebGLShader {\n\t\tconst shader = this.gl.createShader(type)!;\n\t\tthis.gl.shaderSource(shader, source);\n\t\tthis.gl.compileShader(shader);\n\t\tif (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)) {\n\t\t\tconsole.error('Shader compilation failed:', source);\n\t\t\tconsole.error(this.gl.getShaderInfoLog(shader));\n\t\t\tthis.gl.deleteShader(shader);\n\t\t\tthrow new Error('Shader compilation failed');\n\t\t}\n\t\treturn shader;\n\t}\n\n\tprivate setupBuffer(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\tthis.hooks.get('updateResolution')?.forEach(hook => hook.call(this));\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\tgl.clear(gl.COLOR_BUFFER_BIT);\n\t\tgl.drawArrays(gl.TRIANGLES, 0, 6);\n\n\t\tthis.hooks.get('step')?.forEach(hook => hook.call(this, time, this.frame));\n\n\t\t++this.frame;\n\t}\n\n\tplay(callback?: (time: number, frame: number) => void) {\n\t\tthis.pause(); // Prevent double play.\n\t\tconst loop = (time: number) => {\n\t\t\ttime = (time - this.startTime) / 1000; // Convert from milliseconds to seconds.\n\t\t\tthis.step(time);\n\t\t\tthis.animationFrameId = requestAnimationFrame(loop);\n\t\t\tif (callback) callback(time, this.frame);\n\t\t};\n\t\tthis.animationFrameId = requestAnimationFrame(loop);\n\t}\n\n\tpause() {\n\t\tif (this.animationFrameId) {\n\t\t\tcancelAnimationFrame(this.animationFrameId);\n\t\t\tthis.animationFrameId = null;\n\t\t}\n\t}\n\n\treset() {\n\t\tthis.frame = 0;\n\t\tthis.startTime = performance.now();\n\t\tthis.hooks.get('reset')?.forEach(hook => hook.call(this));\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\tlet unitIndex: number;\n\t\ttry {\n\t\t\tunitIndex = this.reserveTextureUnit(name);\n\t\t} catch (error) {\n\t\t\tthis.gl.deleteTexture(texture);\n\t\t\tthrow error;\n\t\t}\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 during upload to match WebGL's coordinate system.\n\t\t// WebGL uses bottom-left origin, while images/videos use top-left origin.\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\t\tthis.textureUnitPool.free = [];\n\t\tthis.textureUnitPool.next = 1;\n\n\t\tif (this.buffer) {\n\t\t\tthis.gl.deleteBuffer(this.buffer);\n\t\t\tthis.buffer = null;\n\t\t}\n\n\t\tthis.hooks.get('destroy')?.forEach(hook => hook.call(this));\n\n\t\tif (this.isInternalCanvas) {\n\t\t\tthis.canvas.remove();\n\t\t}\n\t}\n\n\t// TODO: Review these two.\n\tprivate reserveTextureUnit(name: string) {\n\t\tif (!name) {\n\t\t\tthrow new Error('Texture unit name must be provided.');\n\t\t}\n\t\tconst existing = this.textures.get(name);\n\t\tif (existing) {\n\t\t\treturn existing.unitIndex;\n\t\t}\n\t\tlet unit: number;\n\t\tif (this.textureUnitPool.free.length > 0) {\n\t\t\tunit = this.textureUnitPool.free.pop()!;\n\t\t} else {\n\t\t\tunit = this.textureUnitPool.next;\n\t\t\tif (unit >= this.textureUnitPool.max) {\n\t\t\t\tthrow new Error('Exceeded the available texture units for this device.');\n\t\t\t}\n\t\t\tthis.textureUnitPool.next += 1;\n\t\t}\n\t\treturn unit;\n\t}\n\n\tprivate releaseTextureUnit(name: string) {\n\t\tconst existing = this.textures.get(name);\n\t\tif (!existing) {\n\t\t\treturn;\n\t\t}\n\t\tconst unit = existing.unitIndex;\n\t\tif (unit > 0) {\n\t\t\tthis.textureUnitPool.free.push(unit);\n\t\t}\n\t}\n}\n\nexport * from './plugins';\nexport default ShaderPad;\n","import ShaderPad, { PluginContext, TextureSource } from '../index';\n\nexport type WithHistory<T extends ShaderPad> = T & {\n\tinitializeTexture(name: string, source: HTMLImageElement | HTMLVideoElement, historyDepth?: number): void;\n};\n\nfunction getSourceDimensions(source: TextureSource) {\n\tconst video = source as HTMLVideoElement;\n\tconst image = source as HTMLImageElement;\n\tconst width = video.videoWidth || image.naturalWidth || image.width;\n\tconst height = video.videoHeight || image.naturalHeight || image.height;\n\treturn { width, height };\n}\n\nfunction clearHistoryTextureLayers(gl: WebGL2RenderingContext, width: number, height: number, depth: number): void {\n\tconst transparent = new Uint8Array(width * height * 4);\n\tfor (let layer = 0; layer < depth; ++layer) {\n\t\tgl.texSubImage3D(gl.TEXTURE_2D_ARRAY, 0, 0, 0, layer, width, height, 1, gl.RGBA, gl.UNSIGNED_BYTE, transparent);\n\t}\n}\n\nfunction createHistoryTexture(gl: WebGL2RenderingContext, depth: number, width: number, height: number): WebGLTexture {\n\tconst texture = gl.createTexture();\n\tif (!texture) {\n\t\tthrow new Error('Failed to create history texture');\n\t}\n\tgl.activeTexture(gl.TEXTURE0);\n\tgl.bindTexture(gl.TEXTURE_2D_ARRAY, texture);\n\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_MIN_FILTER, gl.LINEAR);\n\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_MAG_FILTER, gl.LINEAR);\n\tgl.texStorage3D(gl.TEXTURE_2D_ARRAY, 1, gl.RGBA8, width, height, depth);\n\tclearHistoryTextureLayers(gl, width, height, depth);\n\treturn texture;\n}\n\nexport function history(framebufferDepth: number = 1) {\n\treturn function (shaderPad: ShaderPad, context: PluginContext) {\n\t\tconst { gl, uniforms, textures, reserveTextureUnit } = context;\n\t\tconst shaderPadWithHistory = shaderPad as WithHistory<ShaderPad>;\n\n\t\tconst originalInitializeTexture = shaderPad.initializeTexture.bind(shaderPad);\n\t\tconst originalUpdateTextures = shaderPad.updateTextures.bind(shaderPad);\n\n\t\tlet framebufferHistoryTexture: WebGLTexture | null = null;\n\t\tconst shouldTrackFramebuffer = framebufferDepth > 1;\n\t\tif (shouldTrackFramebuffer) {\n\t\t\tfunction initializeFramebufferHistory() {\n\t\t\t\tframebufferHistoryTexture = createHistoryTexture(\n\t\t\t\t\tgl,\n\t\t\t\t\tframebufferDepth,\n\t\t\t\t\tgl.drawingBufferWidth,\n\t\t\t\t\tgl.drawingBufferHeight\n\t\t\t\t);\n\n\t\t\t\tif (!uniforms.has('u_history')) {\n\t\t\t\t\tshaderPad.initializeUniform('u_history', 'int', 0);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfunction clearFramebufferHistory() {\n\t\t\t\tif (!framebufferHistoryTexture) return;\n\t\t\t\tgl.activeTexture(gl.TEXTURE0);\n\t\t\t\tgl.bindTexture(gl.TEXTURE_2D_ARRAY, framebufferHistoryTexture);\n\t\t\t\tclearHistoryTextureLayers(gl, gl.drawingBufferWidth, gl.drawingBufferHeight, framebufferDepth);\n\t\t\t}\n\n\t\t\tshaderPad.registerHook('init', initializeFramebufferHistory);\n\t\t\tshaderPad.registerHook('step', (_time: number, frame: number) => {\n\t\t\t\tif (!framebufferHistoryTexture) return;\n\t\t\t\tconst writeIdx = frame % framebufferDepth;\n\t\t\t\tgl.activeTexture(gl.TEXTURE0);\n\t\t\t\tgl.bindTexture(gl.TEXTURE_2D_ARRAY, framebufferHistoryTexture);\n\t\t\t\tgl.copyTexSubImage3D(\n\t\t\t\t\tgl.TEXTURE_2D_ARRAY,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\twriteIdx,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\tgl.drawingBufferWidth,\n\t\t\t\t\tgl.drawingBufferHeight\n\t\t\t\t);\n\t\t\t});\n\t\t\tshaderPad.registerHook('updateResolution', () => {\n\t\t\t\tif (framebufferHistoryTexture) {\n\t\t\t\t\tgl.deleteTexture(framebufferHistoryTexture);\n\t\t\t\t}\n\t\t\t\tinitializeFramebufferHistory();\n\t\t\t});\n\t\t\tshaderPad.registerHook('reset', clearFramebufferHistory);\n\t\t}\n\t\tshaderPad.registerHook('reset', () => {\n\t\t\ttextures.forEach(textureInfo => {\n\t\t\t\tif (textureInfo.historyDepth && textureInfo.historyDepth > 1 && textureInfo.writeIndex !== undefined) {\n\t\t\t\t\ttextureInfo.writeIndex = 0;\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\tshaderPadWithHistory.initializeTexture = function (\n\t\t\tname: string,\n\t\t\tsource: TextureSource,\n\t\t\thistoryDepth: number = 1\n\t\t) {\n\t\t\tconst { width, height } = getSourceDimensions(source);\n\t\t\tif (!width || !height) {\n\t\t\t\tthrow new Error(`Texture source must have valid dimensions`);\n\t\t\t}\n\n\t\t\tconst depth = Math.floor(historyDepth);\n\t\t\tif (depth <= 1) {\n\t\t\t\treturn originalInitializeTexture(name, source);\n\t\t\t}\n\n\t\t\tif (textures.has(name)) {\n\t\t\t\tthrow new Error(`Texture '${name}' is already initialized.`);\n\t\t\t}\n\n\t\t\tlet unitIndex: number | undefined;\n\t\t\tlet texture: WebGLTexture | null = null;\n\t\t\ttry {\n\t\t\t\tunitIndex = reserveTextureUnit(name);\n\t\t\t\ttexture = createHistoryTexture(gl, depth, width, height);\n\t\t\t\tgl.activeTexture(gl.TEXTURE0 + unitIndex);\n\t\t\t\tgl.bindTexture(gl.TEXTURE_2D_ARRAY, texture);\n\n\t\t\t\t// Flip the texture vertically during upload to match WebGL's coordinate system.\n\t\t\t\t// WebGL uses bottom-left origin, while images/videos use top-left origin.\n\t\t\t\tgl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);\n\t\t\t\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n\t\t\t\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n\t\t\t\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_MIN_FILTER, gl.LINEAR);\n\t\t\t\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_MAG_FILTER, gl.LINEAR);\n\n\t\t\t\tif (context.program) {\n\t\t\t\t\tconst uSampler = gl.getUniformLocation(context.program, name);\n\t\t\t\t\tif (uSampler) {\n\t\t\t\t\t\tgl.uniform1i(uSampler, unitIndex);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ttextures.set(name, {\n\t\t\t\t\ttexture,\n\t\t\t\t\tunitIndex,\n\t\t\t\t\thistoryDepth: depth,\n\t\t\t\t\twriteIndex: 0,\n\t\t\t\t});\n\n\t\t\t\tshaderPadWithHistory.updateTextures({ [name]: source });\n\t\t\t} catch (error) {\n\t\t\t\tif (texture) gl.deleteTexture(texture);\n\t\t\t\tif (unitIndex !== undefined) {\n\t\t\t\t\tcontext.releaseTextureUnit(name);\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t};\n\n\t\tshaderPadWithHistory.updateTextures = function (updates) {\n\t\t\tObject.entries(updates).forEach(([name, source]) => {\n\t\t\t\tconst textureInfo = textures.get(name);\n\t\t\t\tif (!textureInfo || !textureInfo.historyDepth || textureInfo.historyDepth <= 1) {\n\t\t\t\t\treturn originalUpdateTextures({ [name]: source });\n\t\t\t\t}\n\n\t\t\t\tconst { width, height } = getSourceDimensions(source);\n\t\t\t\tconst writeIndex = textureInfo.writeIndex ?? 0;\n\t\t\t\tgl.activeTexture(gl.TEXTURE0 + textureInfo.unitIndex);\n\t\t\t\tgl.bindTexture(gl.TEXTURE_2D_ARRAY, textureInfo.texture);\n\t\t\t\tgl.texSubImage3D(\n\t\t\t\t\tgl.TEXTURE_2D_ARRAY,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\twriteIndex,\n\t\t\t\t\twidth,\n\t\t\t\t\theight,\n\t\t\t\t\t1,\n\t\t\t\t\tgl.RGBA,\n\t\t\t\t\tgl.UNSIGNED_BYTE,\n\t\t\t\t\tsource\n\t\t\t\t);\n\t\t\t\ttextureInfo.writeIndex = (writeIndex + 1) % textureInfo.historyDepth;\n\t\t\t});\n\t\t};\n\n\t\tshaderPad.registerHook('destroy', () => {\n\t\t\tif (framebufferHistoryTexture) {\n\t\t\t\tgl.deleteTexture(framebufferHistoryTexture);\n\t\t\t}\n\t\t});\n\t};\n}\n","import ShaderPad, { PluginContext } from '../index';\n\ndeclare module '../index' {\n\tinterface ShaderPad {\n\t\tsave(filename: string): Promise<void>;\n\t}\n}\n\nexport function save() {\n\treturn function (shaderPad: ShaderPad, context: PluginContext) {\n\t\tconst { gl, canvas } = context;\n\t\tconst downloadLink = document.createElement('a');\n\n\t\t(shaderPad as any).save = async function (filename: string) {\n\t\t\tgl.clear(gl.COLOR_BUFFER_BIT);\n\t\t\tgl.drawArrays(gl.TRIANGLES, 0, 6);\n\n\t\t\tif (filename && !`${filename}`.toLowerCase().endsWith('.png')) {\n\t\t\t\tfilename = `${filename}.png`;\n\t\t\t}\n\t\t\tfilename = filename || 'export.png';\n\t\t\tif ('ongesturechange' in window) {\n\t\t\t\t// Mobile.\n\t\t\t\ttry {\n\t\t\t\t\tconst blob: Blob = await new Promise(resolve =>\n\t\t\t\t\t\tcanvas.toBlob(resolve as BlobCallback, 'image/png')\n\t\t\t\t\t);\n\t\t\t\t\tconst file = new File([blob], filename, { type: blob.type });\n\n\t\t\t\t\tif (navigator.canShare?.({ files: [file] })) {\n\t\t\t\t\t\tawait navigator.share({ files: [file] });\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconsole.warn('Web Share API failed:', error);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Desktop.\n\t\t\t\tdownloadLink.download = filename;\n\t\t\t\tdownloadLink.href = canvas.toDataURL();\n\t\t\t\tdownloadLink.click();\n\t\t\t}\n\t\t};\n\t};\n}\n\n// Type helper.\nexport type WithSave<T extends ShaderPad> = T & {\n\tsave(filename: string): Promise<void>;\n};\n"],"mappings":"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","names":["index_exports","__export","index_default","history","save","__toCommonJS","getSourceDimensions","source","video","image","width","height","clearHistoryTextureLayers","gl","depth","transparent","layer","createHistoryTexture","texture","history","framebufferDepth","shaderPad","context","uniforms","textures","reserveTextureUnit","shaderPadWithHistory","originalInitializeTexture","originalUpdateTextures","framebufferHistoryTexture","initializeFramebufferHistory","clearFramebufferHistory","_time","frame","writeIdx","textureInfo","name","historyDepth","unitIndex","uSampler","error","updates","writeIndex","save","shaderPad","context","gl","canvas","downloadLink","filename","blob","resolve","file","error","DEFAULT_VERTEX_SHADER_SRC","RESIZE_THROTTLE_INTERVAL","ShaderPad","fragmentShaderSrc","options","context","plugin","name","fn","vertexShaderSrc","vertexShader","fragmentShader","aPosition","hook","type","source","shader","quadVertices","now","timeUntilNextResize","pixelRatio","width","height","updateCursor","x","y","rect","updateClick","isMouseDown","xVal","yVal","event","mouseEvent","touchEvent","listener","value","location","length","updates","uniform","time","gl","callback","loop","texture","unitIndex","error","uSampler","info","filename","blob","resolve","file","existing","unit","index_default"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
function
|
|
1
|
+
function v(s){let t=s,i=s,e=t.videoWidth||i.naturalWidth||i.width,r=t.videoHeight||i.naturalHeight||i.height;return{width:e,height:r}}function b(s,t,i,e){let r=new Uint8Array(t*i*4);for(let n=0;n<e;++n)s.texSubImage3D(s.TEXTURE_2D_ARRAY,0,0,0,n,t,i,1,s.RGBA,s.UNSIGNED_BYTE,r)}function R(s,t,i,e){let r=s.createTexture();if(!r)throw new Error("Failed to create history texture");return s.activeTexture(s.TEXTURE0),s.bindTexture(s.TEXTURE_2D_ARRAY,r),s.texParameteri(s.TEXTURE_2D_ARRAY,s.TEXTURE_WRAP_S,s.CLAMP_TO_EDGE),s.texParameteri(s.TEXTURE_2D_ARRAY,s.TEXTURE_WRAP_T,s.CLAMP_TO_EDGE),s.texParameteri(s.TEXTURE_2D_ARRAY,s.TEXTURE_MIN_FILTER,s.LINEAR),s.texParameteri(s.TEXTURE_2D_ARRAY,s.TEXTURE_MAG_FILTER,s.LINEAR),s.texStorage3D(s.TEXTURE_2D_ARRAY,1,s.RGBA8,i,e,t),b(s,i,e,t),r}function I(s=1){return function(t,i){let{gl:e,uniforms:r,textures:n,reserveTextureUnit:a}=i,c=t,T=t.initializeTexture.bind(t),_=t.updateTextures.bind(t),u=null;if(s>1){let o=function(){u=R(e,s,e.drawingBufferWidth,e.drawingBufferHeight),r.has("u_history")||t.initializeUniform("u_history","int",0)},l=function(){u&&(e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D_ARRAY,u),b(e,e.drawingBufferWidth,e.drawingBufferHeight,s))};var L=o,P=l;t.registerHook("init",o),t.registerHook("step",(d,h)=>{if(!u)return;let f=h%s;e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D_ARRAY,u),e.copyTexSubImage3D(e.TEXTURE_2D_ARRAY,0,0,0,f,0,0,e.drawingBufferWidth,e.drawingBufferHeight)}),t.registerHook("updateResolution",()=>{u&&e.deleteTexture(u),o()}),t.registerHook("reset",l)}t.registerHook("reset",()=>{n.forEach(o=>{o.historyDepth&&o.historyDepth>1&&o.writeIndex!==void 0&&(o.writeIndex=0)})}),c.initializeTexture=function(o,l,d=1){let{width:h,height:f}=v(l);if(!h||!f)throw new Error("Texture source must have valid dimensions");let m=Math.floor(d);if(m<=1)return T(o,l);if(n.has(o))throw new Error(`Texture '${o}' is already initialized.`);let g,E=null;try{if(g=a(o),E=R(e,m,h,f),e.activeTexture(e.TEXTURE0+g),e.bindTexture(e.TEXTURE_2D_ARRAY,E),e.pixelStorei(e.UNPACK_FLIP_Y_WEBGL,!0),e.texParameteri(e.TEXTURE_2D_ARRAY,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D_ARRAY,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D_ARRAY,e.TEXTURE_MIN_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_2D_ARRAY,e.TEXTURE_MAG_FILTER,e.LINEAR),i.program){let x=e.getUniformLocation(i.program,o);x&&e.uniform1i(x,g)}n.set(o,{texture:E,unitIndex:g,historyDepth:m,writeIndex:0}),c.updateTextures({[o]:l})}catch(x){throw E&&e.deleteTexture(E),g!==void 0&&i.releaseTextureUnit(o),x}},c.updateTextures=function(o){Object.entries(o).forEach(([l,d])=>{let h=n.get(l);if(!h||!h.historyDepth||h.historyDepth<=1)return _({[l]:d});let{width:f,height:m}=v(d),g=h.writeIndex??0;e.activeTexture(e.TEXTURE0+h.unitIndex),e.bindTexture(e.TEXTURE_2D_ARRAY,h.texture),e.texSubImage3D(e.TEXTURE_2D_ARRAY,0,0,0,g,f,m,1,e.RGBA,e.UNSIGNED_BYTE,d),h.writeIndex=(g+1)%h.historyDepth})},t.registerHook("destroy",()=>{u&&e.deleteTexture(u)})}}function y(){return function(s,t){let{gl:i,canvas:e}=t,r=document.createElement("a");s.save=async function(n){if(i.clear(i.COLOR_BUFFER_BIT),i.drawArrays(i.TRIANGLES,0,6),n&&!`${n}`.toLowerCase().endsWith(".png")&&(n=`${n}.png`),n=n||"export.png","ongesturechange"in window)try{let a=await new Promise(T=>e.toBlob(T,"image/png")),c=new File([a],n,{type:a.type});if(navigator.canShare?.({files:[c]})){await navigator.share({files:[c]});return}}catch(a){console.warn("Web Share API failed:",a)}else r.download=n,r.href=e.toDataURL(),r.click()}}}var w=`#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
|
-
`,f=1e3/30,u=class{constructor(i,r={}){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.hooks=new Map;if(this.canvas=r.canvas||document.createElement("canvas"),r.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.");if(this.downloadLink=document.createElement("a"),this.fragmentShaderSrc=i,this.animationFrameId=null,this.resolutionObserver=new MutationObserver(()=>this.updateResolution()),this.resizeObserver=new ResizeObserver(()=>this.throttledHandleResize()),r.plugins){let e={gl:this.gl,uniforms:this.uniforms,textures:this.textures,program:this.program,canvas:this.canvas};r.plugins.forEach(t=>t(this,e))}this.init(),this.addEventListeners()}registerHook(i,r){this.hooks.has(i)||this.hooks.set(i,[]),this.hooks.get(i).push(r)}init(){let i=g;if(this.program=this.gl.createProgram(),!this.program)throw new Error("Failed to create WebGL program");let r=this.createShader(this.gl.VERTEX_SHADER,i),e=this.createShader(this.gl.FRAGMENT_SHADER,this.fragmentShaderSrc);if(this.gl.attachShader(this.program,r),this.gl.attachShader(this.program,e),this.gl.linkProgram(this.program),this.gl.deleteShader(r),this.gl.deleteShader(e),!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 t=this.gl.getAttribLocation(this.program,"aPosition");this.setupBuffer(t),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.hooks.get("init")?.forEach(s=>s.call(this))}createShader(i,r){let e=this.gl.createShader(i);if(this.gl.shaderSource(e,r),this.gl.compileShader(e),!this.gl.getShaderParameter(e,this.gl.COMPILE_STATUS))throw console.error("Shader compilation failed:",r),console.error(this.gl.getShaderInfoLog(e)),this.gl.deleteShader(e),new Error("Shader compilation failed");return e}setupBuffer(i){let r=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,r,this.gl.STATIC_DRAW),this.gl.viewport(0,0,this.gl.drawingBufferWidth,this.gl.drawingBufferHeight),this.gl.enableVertexAttribArray(i),this.gl.vertexAttribPointer(i,2,this.gl.FLOAT,!1,0,0)}throttledHandleResize(){clearTimeout(this.resizeTimeout);let i=performance.now(),r=this.lastResizeTime+f-i;r<=0?(this.lastResizeTime=i,this.handleResize()):this.resizeTimeout=setTimeout(()=>this.throttledHandleResize(),r)}handleResize(){let i=window.devicePixelRatio||1,r=this.canvas.clientWidth*i,e=this.canvas.clientHeight*i;this.isInternalCanvas&&(this.canvas.width!==r||this.canvas.height!==e)&&(this.canvas.width=r,this.canvas.height=e),this.onResize?.(r,e)}addEventListeners(){let i=(e,t)=>{if(!this.uniforms.has("u_cursor"))return;let s=this.canvas.getBoundingClientRect();this.cursorPosition[0]=(e-s.left)/s.width,this.cursorPosition[1]=1-(t-s.top)/s.height,this.updateUniforms({u_cursor:this.cursorPosition})},r=(e,t,s)=>{if(this.uniforms.has("u_click")){if(this.isMouseDown=e,e){let n=this.canvas.getBoundingClientRect(),a=t,h=s;this.clickPosition[0]=(a-n.left)/n.width,this.clickPosition[1]=1-(h-n.top)/n.height}this.updateUniforms({u_click:[...this.clickPosition,this.isMouseDown?1:0]})}};this.eventListeners.set("mousemove",e=>{let t=e;this.isTouchDevice||i(t.clientX,t.clientY)}),this.eventListeners.set("mousedown",e=>{let t=e;this.isTouchDevice||t.button===0&&(this.isMouseDown=!0,r(!0,t.clientX,t.clientY))}),this.eventListeners.set("mouseup",e=>{let t=e;this.isTouchDevice||t.button===0&&r(!1)}),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",e=>{let t=e;this.isTouchDevice=!0,t.touches.length>0&&(i(t.touches[0].clientX,t.touches[0].clientY),r(!0,t.touches[0].clientX,t.touches[0].clientY))}),this.eventListeners.set("touchend",e=>{e.touches.length===0&&r(!1)}),this.eventListeners.forEach((e,t)=>{this.canvas.addEventListener(t,e)})}updateResolution(){let i=this.gl.drawingBufferWidth,r=this.gl.drawingBufferHeight;this.gl.viewport(0,0,i,r),this.uniforms.has("u_resolution")?this.updateUniforms({u_resolution:[i,r]}):this.initializeUniform("u_resolution","float",[i,r]),this.hooks.get("updateResolution")?.forEach(e=>e.call(this))}initializeUniform(i,r,e){if(this.uniforms.has(i))throw new Error(`Uniform '${i}' is already initialized.`);if(r!=="float"&&r!=="int")throw new Error(`Invalid uniform type: ${r}. Expected 'float' or 'int'.`);let t=this.gl.getUniformLocation(this.program,i);if(!t){console.debug(`Uniform ${i} not found in fragment shader. Skipping initialization.`);return}if(Array.isArray(e)||(e=[e]),e.length<1||e.length>4)throw new Error(`Invalid uniform value length: ${e.length}. Expected a length between 1 and 4.`);let s=e.length;this.uniforms.set(i,{type:r,length:s,location:t}),this.updateUniforms({[i]:e})}updateUniforms(i){Object.entries(i).forEach(([r,e])=>{if(!this.uniforms.has(r))throw new Error(`Uniform '${r}' is not initialized.`);let t=this.uniforms.get(r);if(Array.isArray(e)||(e=[e]),e.length!==t.length)throw new Error(`Invalid uniform value length: ${e.length}. Expected ${t.length}.`);this.gl[`uniform${t.length}${t.type.charAt(0)}`](t.location,...e)})}step(i){let r=this.gl;this.uniforms.has("u_time")&&this.updateUniforms({u_time:i}),this.uniforms.has("u_frame")&&this.updateUniforms({u_frame:this.frame}),r.clear(r.COLOR_BUFFER_BIT),r.drawArrays(r.TRIANGLES,0,6),this.hooks.get("step")?.forEach(e=>e.call(this,i,this.frame)),++this.frame}play(i){this.pause();let r=e=>{e=(e-this.startTime)/1e3,this.step(e),this.animationFrameId=requestAnimationFrame(r),i&&i(e,this.frame)};this.animationFrameId=requestAnimationFrame(r)}pause(){this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null)}reset(){this.frame=0,this.startTime=performance.now(),this.hooks.get("reset")?.forEach(i=>i.call(this))}initializeTexture(i,r){if(this.textures.has(i))throw new Error(`Texture '${i}' is already initialized.`);let e=this.gl.createTexture();if(!e)throw new Error("Failed to create texture");let t=this.textures.size+1;this.gl.activeTexture(this.gl.TEXTURE0+t),this.gl.bindTexture(this.gl.TEXTURE_2D,e),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:e,unitIndex:t}),this.updateTextures({[i]:r});let s=this.gl.getUniformLocation(this.program,i);s&&this.gl.uniform1i(s,t)}updateTextures(i){Object.entries(i).forEach(([r,e])=>{let t=this.textures.get(r);if(!t)throw new Error(`Texture '${r}' is not initialized.`);this.gl.activeTexture(this.gl.TEXTURE0+t.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D,t.texture),this.gl.texImage2D(this.gl.TEXTURE_2D,0,this.gl.RGBA,this.gl.RGBA,this.gl.UNSIGNED_BYTE,e)})}async save(i){if(this.gl.clear(this.gl.COLOR_BUFFER_BIT),this.gl.drawArrays(this.gl.TRIANGLES,0,6),i&&!`${i}`.toLowerCase().endsWith(".png")&&(i=`${i}.png`),i=i||"export.png","ongesturechange"in window)try{let r=await new Promise(t=>this.canvas.toBlob(t,"image/png")),e=new File([r],i,{type:r.type});if(navigator.canShare?.({files:[e]})){await navigator.share({files:[e]});return}}catch(r){console.warn("Web Share API failed:",r)}else this.downloadLink.download=i,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((i,r)=>{this.canvas.removeEventListener(r,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.hooks.get("destroy")?.forEach(i=>i.call(this)),this.isInternalCanvas&&this.canvas.remove()}},w=u;export{w as default,d as history,E as save};
|
|
8
|
+
`,U=1e3/30,p=class{constructor(t,i={}){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.hooks=new Map;if(this.canvas=i.canvas||document.createElement("canvas"),i.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.");if(this.textureUnitPool={free:[],next:1,max:this.gl.getParameter(this.gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS)},this.downloadLink=document.createElement("a"),this.fragmentShaderSrc=t,this.animationFrameId=null,this.resolutionObserver=new MutationObserver(()=>this.updateResolution()),this.resizeObserver=new ResizeObserver(()=>this.throttledHandleResize()),i.plugins){let e={gl:this.gl,uniforms:this.uniforms,textures:this.textures,canvas:this.canvas,reserveTextureUnit:this.reserveTextureUnit.bind(this),releaseTextureUnit:this.releaseTextureUnit.bind(this)};Object.defineProperty(e,"program",{get:()=>this.program,enumerable:!0,configurable:!0}),i.plugins.forEach(r=>r(this,e))}this.init(),this.addEventListeners()}registerHook(t,i){this.hooks.has(t)||this.hooks.set(t,[]),this.hooks.get(t).push(i)}init(){let t=w;if(this.program=this.gl.createProgram(),!this.program)throw new Error("Failed to create WebGL program");let i=this.createShader(this.gl.VERTEX_SHADER,t),e=this.createShader(this.gl.FRAGMENT_SHADER,this.fragmentShaderSrc);if(this.gl.attachShader(this.program,i),this.gl.attachShader(this.program,e),this.gl.linkProgram(this.program),this.gl.deleteShader(i),this.gl.deleteShader(e),!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.hooks.get("init")?.forEach(n=>n.call(this))}createShader(t,i){let e=this.gl.createShader(t);if(this.gl.shaderSource(e,i),this.gl.compileShader(e),!this.gl.getShaderParameter(e,this.gl.COMPILE_STATUS))throw console.error("Shader compilation failed:",i),console.error(this.gl.getShaderInfoLog(e)),this.gl.deleteShader(e),new Error("Shader compilation failed");return e}setupBuffer(t){let i=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,i,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(),i=this.lastResizeTime+U-t;i<=0?(this.lastResizeTime=t,this.handleResize()):this.resizeTimeout=setTimeout(()=>this.throttledHandleResize(),i)}handleResize(){let t=window.devicePixelRatio||1,i=this.canvas.clientWidth*t,e=this.canvas.clientHeight*t;this.isInternalCanvas&&(this.canvas.width!==i||this.canvas.height!==e)&&(this.canvas.width=i,this.canvas.height=e),this.onResize?.(i,e)}addEventListeners(){let t=(e,r)=>{if(!this.uniforms.has("u_cursor"))return;let n=this.canvas.getBoundingClientRect();this.cursorPosition[0]=(e-n.left)/n.width,this.cursorPosition[1]=1-(r-n.top)/n.height,this.updateUniforms({u_cursor:this.cursorPosition})},i=(e,r,n)=>{if(this.uniforms.has("u_click")){if(this.isMouseDown=e,e){let a=this.canvas.getBoundingClientRect(),c=r,T=n;this.clickPosition[0]=(c-a.left)/a.width,this.clickPosition[1]=1-(T-a.top)/a.height}this.updateUniforms({u_click:[...this.clickPosition,this.isMouseDown?1:0]})}};this.eventListeners.set("mousemove",e=>{let r=e;this.isTouchDevice||t(r.clientX,r.clientY)}),this.eventListeners.set("mousedown",e=>{let r=e;this.isTouchDevice||r.button===0&&(this.isMouseDown=!0,i(!0,r.clientX,r.clientY))}),this.eventListeners.set("mouseup",e=>{let r=e;this.isTouchDevice||r.button===0&&i(!1)}),this.eventListeners.set("touchmove",e=>{let r=e;r.touches.length>0&&t(r.touches[0].clientX,r.touches[0].clientY)}),this.eventListeners.set("touchstart",e=>{let r=e;this.isTouchDevice=!0,r.touches.length>0&&(t(r.touches[0].clientX,r.touches[0].clientY),i(!0,r.touches[0].clientX,r.touches[0].clientY))}),this.eventListeners.set("touchend",e=>{e.touches.length===0&&i(!1)}),this.eventListeners.forEach((e,r)=>{this.canvas.addEventListener(r,e)})}updateResolution(){let t=this.gl.drawingBufferWidth,i=this.gl.drawingBufferHeight;this.gl.viewport(0,0,t,i),this.uniforms.has("u_resolution")?this.updateUniforms({u_resolution:[t,i]}):this.initializeUniform("u_resolution","float",[t,i]),this.hooks.get("updateResolution")?.forEach(e=>e.call(this))}initializeUniform(t,i,e){if(this.uniforms.has(t))throw new Error(`Uniform '${t}' is already initialized.`);if(i!=="float"&&i!=="int")throw new Error(`Invalid uniform type: ${i}. 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(e)||(e=[e]),e.length<1||e.length>4)throw new Error(`Invalid uniform value length: ${e.length}. Expected a length between 1 and 4.`);let n=e.length;this.uniforms.set(t,{type:i,length:n,location:r}),this.updateUniforms({[t]:e})}updateUniforms(t){Object.entries(t).forEach(([i,e])=>{if(!this.uniforms.has(i))throw new Error(`Uniform '${i}' is not initialized.`);let r=this.uniforms.get(i);if(Array.isArray(e)||(e=[e]),e.length!==r.length)throw new Error(`Invalid uniform value length: ${e.length}. Expected ${r.length}.`);this.gl[`uniform${r.length}${r.type.charAt(0)}`](r.location,...e)})}step(t){let i=this.gl;this.uniforms.has("u_time")&&this.updateUniforms({u_time:t}),this.uniforms.has("u_frame")&&this.updateUniforms({u_frame:this.frame}),i.clear(i.COLOR_BUFFER_BIT),i.drawArrays(i.TRIANGLES,0,6),this.hooks.get("step")?.forEach(e=>e.call(this,t,this.frame)),++this.frame}play(t){this.pause();let i=e=>{e=(e-this.startTime)/1e3,this.step(e),this.animationFrameId=requestAnimationFrame(i),t&&t(e,this.frame)};this.animationFrameId=requestAnimationFrame(i)}pause(){this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null)}reset(){this.frame=0,this.startTime=performance.now(),this.hooks.get("reset")?.forEach(t=>t.call(this))}initializeTexture(t,i){if(this.textures.has(t))throw new Error(`Texture '${t}' is already initialized.`);let e=this.gl.createTexture();if(!e)throw new Error("Failed to create texture");let r;try{r=this.reserveTextureUnit(t)}catch(a){throw this.gl.deleteTexture(e),a}this.gl.activeTexture(this.gl.TEXTURE0+r),this.gl.bindTexture(this.gl.TEXTURE_2D,e),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:e,unitIndex:r}),this.updateTextures({[t]:i});let n=this.gl.getUniformLocation(this.program,t);n&&this.gl.uniform1i(n,r)}updateTextures(t){Object.entries(t).forEach(([i,e])=>{let r=this.textures.get(i);if(!r)throw new Error(`Texture '${i}' 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,e)})}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 i=await new Promise(r=>this.canvas.toBlob(r,"image/png")),e=new File([i],t,{type:i.type});if(navigator.canShare?.({files:[e]})){await navigator.share({files:[e]});return}}catch(i){console.warn("Web Share API failed:",i)}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,i)=>{this.canvas.removeEventListener(i,t)}),this.program&&this.gl.deleteProgram(this.program),this.textures.forEach(t=>{this.gl.deleteTexture(t.texture)}),this.textureUnitPool.free=[],this.textureUnitPool.next=1,this.buffer&&(this.gl.deleteBuffer(this.buffer),this.buffer=null),this.hooks.get("destroy")?.forEach(t=>t.call(this)),this.isInternalCanvas&&this.canvas.remove()}reserveTextureUnit(t){if(!t)throw new Error("Texture unit name must be provided.");let i=this.textures.get(t);if(i)return i.unitIndex;let e;if(this.textureUnitPool.free.length>0)e=this.textureUnitPool.free.pop();else{if(e=this.textureUnitPool.next,e>=this.textureUnitPool.max)throw new Error("Exceeded the available texture units for this device.");this.textureUnitPool.next+=1}return e}releaseTextureUnit(t){let i=this.textures.get(t);if(!i)return;let e=i.unitIndex;e>0&&this.textureUnitPool.free.push(e)}},C=p;export{C as default,I as history,y as save};
|
|
9
9
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/plugins/history.ts","../src/plugins/save.ts","../src/index.ts"],"sourcesContent":["import ShaderPad, { PluginContext } from '../index';\n\nexport function history(depth: number = 2) {\n\tif (depth < 2) {\n\t\tthrow new Error('History depth must be greater than 1');\n\t}\n\n\treturn function (shaderPad: ShaderPad, context: PluginContext) {\n\t\tlet historyTexture: WebGLTexture | null = null;\n\t\tconst { gl, uniforms } = context;\n\n\t\tshaderPad.registerHook('init', initializeHistoryBuffer);\n\t\tshaderPad.registerHook('step', (_time: number, frame: number) => {\n\t\t\tconst writeIdx = frame % depth;\n\n\t\t\tgl.activeTexture(gl.TEXTURE0);\n\t\t\tgl.bindTexture(gl.TEXTURE_2D_ARRAY, 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\tgl.drawingBufferWidth,\n\t\t\t\tgl.drawingBufferHeight\n\t\t\t);\n\t\t});\n\t\tshaderPad.registerHook('updateResolution', () => {\n\t\t\tgl.deleteTexture(historyTexture);\n\t\t\tinitializeHistoryBuffer();\n\t\t});\n\t\tshaderPad.registerHook('reset', clearHistory);\n\t\tshaderPad.registerHook('destroy', () => {\n\t\t\tgl.deleteTexture(historyTexture);\n\t\t\thistoryTexture = null;\n\t\t});\n\n\t\tfunction initializeHistoryBuffer() {\n\t\t\thistoryTexture = gl.createTexture();\n\t\t\tif (!historyTexture) {\n\t\t\t\tthrow new Error('Failed to create history texture');\n\t\t\t}\n\t\t\tgl.bindTexture(gl.TEXTURE_2D_ARRAY, historyTexture);\n\t\t\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n\t\t\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n\t\t\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_MIN_FILTER, gl.NEAREST);\n\t\t\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_MAG_FILTER, gl.NEAREST);\n\t\t\tgl.texStorage3D(gl.TEXTURE_2D_ARRAY, 1, gl.RGBA8, gl.drawingBufferWidth, gl.drawingBufferHeight, depth);\n\t\t\tgl.activeTexture(gl.TEXTURE0);\n\t\t\tgl.bindTexture(gl.TEXTURE_2D_ARRAY, historyTexture);\n\n\t\t\tclearHistory();\n\n\t\t\tif (!uniforms.has('u_history')) {\n\t\t\t\tshaderPad.initializeUniform('u_history', 'int', 0);\n\t\t\t}\n\t\t}\n\n\t\tfunction clearHistory() {\n\t\t\tgl.activeTexture(gl.TEXTURE0);\n\t\t\tgl.bindTexture(gl.TEXTURE_2D_ARRAY, historyTexture);\n\t\t\tconst transparent = new Uint8Array(gl.drawingBufferWidth * gl.drawingBufferHeight * 4);\n\t\t\tfor (let layer = 0; layer < depth; ++layer) {\n\t\t\t\tgl.texSubImage3D(\n\t\t\t\t\tgl.TEXTURE_2D_ARRAY,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\tlayer,\n\t\t\t\t\tgl.drawingBufferWidth,\n\t\t\t\t\tgl.drawingBufferHeight,\n\t\t\t\t\t1,\n\t\t\t\t\tgl.RGBA,\n\t\t\t\t\tgl.UNSIGNED_BYTE,\n\t\t\t\t\ttransparent\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t};\n}\n","import ShaderPad, { PluginContext } from '../index';\n\ndeclare module '../index' {\n\tinterface ShaderPad {\n\t\tsave(filename: string): Promise<void>;\n\t}\n}\n\nexport function save() {\n\treturn function (shaderPad: ShaderPad, context: PluginContext) {\n\t\tconst { gl, canvas } = context;\n\t\tconst downloadLink = document.createElement('a');\n\n\t\t(shaderPad as any).save = async function (filename: string) {\n\t\t\tgl.clear(gl.COLOR_BUFFER_BIT);\n\t\t\tgl.drawArrays(gl.TRIANGLES, 0, 6);\n\n\t\t\tif (filename && !`${filename}`.toLowerCase().endsWith('.png')) {\n\t\t\t\tfilename = `${filename}.png`;\n\t\t\t}\n\t\t\tfilename = filename || 'export.png';\n\t\t\tif ('ongesturechange' in window) {\n\t\t\t\t// Mobile.\n\t\t\t\ttry {\n\t\t\t\t\tconst blob: Blob = await new Promise(resolve =>\n\t\t\t\t\t\tcanvas.toBlob(resolve as BlobCallback, 'image/png')\n\t\t\t\t\t);\n\t\t\t\t\tconst file = new File([blob], filename, { type: blob.type });\n\n\t\t\t\t\tif (navigator.canShare?.({ files: [file] })) {\n\t\t\t\t\t\tawait navigator.share({ files: [file] });\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconsole.warn('Web Share API failed:', error);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Desktop.\n\t\t\t\tdownloadLink.download = filename;\n\t\t\t\tdownloadLink.href = canvas.toDataURL();\n\t\t\t\tdownloadLink.click();\n\t\t\t}\n\t\t};\n\t};\n}\n\n// Type helper.\nexport type WithSave<T extends ShaderPad> = T & {\n\tsave(filename: string): Promise<void>;\n};\n","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\nexport interface PluginContext {\n\tgl: WebGL2RenderingContext;\n\tuniforms: Map<string, Uniform>;\n\ttextures: Map<string, Texture>;\n\tprogram: WebGLProgram | null;\n\tcanvas: HTMLCanvasElement;\n}\n\ntype Plugin = (shaderPad: ShaderPad, context: PluginContext) => void;\n\ntype LifecycleMethod = 'init' | 'step' | 'destroy' | 'updateResolution' | 'reset';\n\ninterface Options {\n\tcanvas?: HTMLCanvasElement | null;\n\tplugins?: Plugin[];\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\tpublic canvas: HTMLCanvasElement;\n\tpublic onResize?: (width: number, height: number) => void;\n\tprivate hooks: Map<LifecycleMethod, Function[]> = new Map();\n\n\tconstructor(fragmentShaderSrc: string, options: Options = {}) {\n\t\tthis.canvas = options.canvas || document.createElement('canvas');\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\tif (options.plugins) {\n\t\t\tconst context: PluginContext = {\n\t\t\t\tgl: this.gl,\n\t\t\t\tuniforms: this.uniforms,\n\t\t\t\ttextures: this.textures,\n\t\t\t\tprogram: this.program,\n\t\t\t\tcanvas: this.canvas,\n\t\t\t};\n\t\t\toptions.plugins.forEach(plugin => plugin(this, context));\n\t\t}\n\t\tthis.init();\n\t\tthis.addEventListeners();\n\t}\n\n\tregisterHook(name: LifecycleMethod, fn: Function) {\n\t\tif (!this.hooks.has(name)) {\n\t\t\tthis.hooks.set(name, []);\n\t\t}\n\t\tthis.hooks.get(name)!.push(fn);\n\t}\n\n\tprivate init() {\n\t\tconst vertexShaderSrc = DEFAULT_VERTEX_SHADER_SRC;\n\n\t\tthis.program = this.gl.createProgram();\n\t\tif (!this.program) {\n\t\t\tthrow new Error('Failed to create WebGL program');\n\t\t}\n\t\tconst vertexShader = this.createShader(this.gl.VERTEX_SHADER, vertexShaderSrc);\n\t\tconst fragmentShader = this.createShader(this.gl.FRAGMENT_SHADER, this.fragmentShaderSrc);\n\n\t\tthis.gl.attachShader(this.program, vertexShader);\n\t\tthis.gl.attachShader(this.program, fragmentShader);\n\t\tthis.gl.linkProgram(this.program);\n\t\tthis.gl.deleteShader(vertexShader);\n\t\tthis.gl.deleteShader(fragmentShader);\n\n\t\tif (!this.gl.getProgramParameter(this.program, this.gl.LINK_STATUS)) {\n\t\t\tconsole.error('Program link error:', this.gl.getProgramInfoLog(this.program));\n\t\t\tthis.gl.deleteProgram(this.program);\n\t\t\tthrow new Error('Failed to link WebGL program');\n\t\t}\n\n\t\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\n\t\tthis.hooks.get('init')?.forEach(hook => hook.call(this));\n\t}\n\n\tprivate createShader(type: number, source: string): WebGLShader {\n\t\tconst shader = this.gl.createShader(type)!;\n\t\tthis.gl.shaderSource(shader, source);\n\t\tthis.gl.compileShader(shader);\n\t\tif (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)) {\n\t\t\tconsole.error('Shader compilation failed:', source);\n\t\t\tconsole.error(this.gl.getShaderInfoLog(shader));\n\t\t\tthis.gl.deleteShader(shader);\n\t\t\tthrow new Error('Shader compilation failed');\n\t\t}\n\t\treturn shader;\n\t}\n\n\tprivate setupBuffer(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\tthis.hooks.get('updateResolution')?.forEach(hook => hook.call(this));\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\tgl.clear(gl.COLOR_BUFFER_BIT);\n\t\tgl.drawArrays(gl.TRIANGLES, 0, 6);\n\n\t\tthis.hooks.get('step')?.forEach(hook => hook.call(this, time, this.frame));\n\n\t\t++this.frame;\n\t}\n\n\tplay(callback?: (time: number, frame: number) => void) {\n\t\tthis.pause(); // Prevent double play.\n\t\tconst loop = (time: number) => {\n\t\t\ttime = (time - this.startTime) / 1000; // Convert from milliseconds to seconds.\n\t\t\tthis.step(time);\n\t\t\tthis.animationFrameId = requestAnimationFrame(loop);\n\t\t\tif (callback) callback(time, this.frame);\n\t\t};\n\t\tthis.animationFrameId = requestAnimationFrame(loop);\n\t}\n\n\tpause() {\n\t\tif (this.animationFrameId) {\n\t\t\tcancelAnimationFrame(this.animationFrameId);\n\t\t\tthis.animationFrameId = null;\n\t\t}\n\t}\n\n\treset() {\n\t\tthis.frame = 0;\n\t\tthis.startTime = performance.now();\n\t\tthis.hooks.get('reset')?.forEach(hook => hook.call(this));\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.buffer) {\n\t\t\tthis.gl.deleteBuffer(this.buffer);\n\t\t\tthis.buffer = null;\n\t\t}\n\n\t\tthis.hooks.get('destroy')?.forEach(hook => hook.call(this));\n\n\t\tif (this.isInternalCanvas) {\n\t\t\tthis.canvas.remove();\n\t\t}\n\t}\n}\n\nexport * from './plugins';\nexport default ShaderPad;\n"],"mappings":"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","names":["history","depth","shaderPad","context","historyTexture","gl","uniforms","initializeHistoryBuffer","_time","frame","writeIdx","clearHistory","transparent","layer","save","shaderPad","context","gl","canvas","downloadLink","filename","blob","resolve","file","error","DEFAULT_VERTEX_SHADER_SRC","RESIZE_THROTTLE_INTERVAL","ShaderPad","fragmentShaderSrc","options","context","plugin","name","fn","vertexShaderSrc","vertexShader","fragmentShader","aPosition","hook","type","source","shader","quadVertices","now","timeUntilNextResize","pixelRatio","width","height","updateCursor","x","y","rect","updateClick","isMouseDown","xVal","yVal","event","mouseEvent","touchEvent","listener","value","location","length","updates","uniform","time","gl","callback","loop","texture","unitIndex","uSampler","info","filename","blob","resolve","file","error","index_default"]}
|
|
1
|
+
{"version":3,"sources":["../src/plugins/history.ts","../src/plugins/save.ts","../src/index.ts"],"sourcesContent":["import ShaderPad, { PluginContext, TextureSource } from '../index';\n\nexport type WithHistory<T extends ShaderPad> = T & {\n\tinitializeTexture(name: string, source: HTMLImageElement | HTMLVideoElement, historyDepth?: number): void;\n};\n\nfunction getSourceDimensions(source: TextureSource) {\n\tconst video = source as HTMLVideoElement;\n\tconst image = source as HTMLImageElement;\n\tconst width = video.videoWidth || image.naturalWidth || image.width;\n\tconst height = video.videoHeight || image.naturalHeight || image.height;\n\treturn { width, height };\n}\n\nfunction clearHistoryTextureLayers(gl: WebGL2RenderingContext, width: number, height: number, depth: number): void {\n\tconst transparent = new Uint8Array(width * height * 4);\n\tfor (let layer = 0; layer < depth; ++layer) {\n\t\tgl.texSubImage3D(gl.TEXTURE_2D_ARRAY, 0, 0, 0, layer, width, height, 1, gl.RGBA, gl.UNSIGNED_BYTE, transparent);\n\t}\n}\n\nfunction createHistoryTexture(gl: WebGL2RenderingContext, depth: number, width: number, height: number): WebGLTexture {\n\tconst texture = gl.createTexture();\n\tif (!texture) {\n\t\tthrow new Error('Failed to create history texture');\n\t}\n\tgl.activeTexture(gl.TEXTURE0);\n\tgl.bindTexture(gl.TEXTURE_2D_ARRAY, texture);\n\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_MIN_FILTER, gl.LINEAR);\n\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_MAG_FILTER, gl.LINEAR);\n\tgl.texStorage3D(gl.TEXTURE_2D_ARRAY, 1, gl.RGBA8, width, height, depth);\n\tclearHistoryTextureLayers(gl, width, height, depth);\n\treturn texture;\n}\n\nexport function history(framebufferDepth: number = 1) {\n\treturn function (shaderPad: ShaderPad, context: PluginContext) {\n\t\tconst { gl, uniforms, textures, reserveTextureUnit } = context;\n\t\tconst shaderPadWithHistory = shaderPad as WithHistory<ShaderPad>;\n\n\t\tconst originalInitializeTexture = shaderPad.initializeTexture.bind(shaderPad);\n\t\tconst originalUpdateTextures = shaderPad.updateTextures.bind(shaderPad);\n\n\t\tlet framebufferHistoryTexture: WebGLTexture | null = null;\n\t\tconst shouldTrackFramebuffer = framebufferDepth > 1;\n\t\tif (shouldTrackFramebuffer) {\n\t\t\tfunction initializeFramebufferHistory() {\n\t\t\t\tframebufferHistoryTexture = createHistoryTexture(\n\t\t\t\t\tgl,\n\t\t\t\t\tframebufferDepth,\n\t\t\t\t\tgl.drawingBufferWidth,\n\t\t\t\t\tgl.drawingBufferHeight\n\t\t\t\t);\n\n\t\t\t\tif (!uniforms.has('u_history')) {\n\t\t\t\t\tshaderPad.initializeUniform('u_history', 'int', 0);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfunction clearFramebufferHistory() {\n\t\t\t\tif (!framebufferHistoryTexture) return;\n\t\t\t\tgl.activeTexture(gl.TEXTURE0);\n\t\t\t\tgl.bindTexture(gl.TEXTURE_2D_ARRAY, framebufferHistoryTexture);\n\t\t\t\tclearHistoryTextureLayers(gl, gl.drawingBufferWidth, gl.drawingBufferHeight, framebufferDepth);\n\t\t\t}\n\n\t\t\tshaderPad.registerHook('init', initializeFramebufferHistory);\n\t\t\tshaderPad.registerHook('step', (_time: number, frame: number) => {\n\t\t\t\tif (!framebufferHistoryTexture) return;\n\t\t\t\tconst writeIdx = frame % framebufferDepth;\n\t\t\t\tgl.activeTexture(gl.TEXTURE0);\n\t\t\t\tgl.bindTexture(gl.TEXTURE_2D_ARRAY, framebufferHistoryTexture);\n\t\t\t\tgl.copyTexSubImage3D(\n\t\t\t\t\tgl.TEXTURE_2D_ARRAY,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\twriteIdx,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\tgl.drawingBufferWidth,\n\t\t\t\t\tgl.drawingBufferHeight\n\t\t\t\t);\n\t\t\t});\n\t\t\tshaderPad.registerHook('updateResolution', () => {\n\t\t\t\tif (framebufferHistoryTexture) {\n\t\t\t\t\tgl.deleteTexture(framebufferHistoryTexture);\n\t\t\t\t}\n\t\t\t\tinitializeFramebufferHistory();\n\t\t\t});\n\t\t\tshaderPad.registerHook('reset', clearFramebufferHistory);\n\t\t}\n\t\tshaderPad.registerHook('reset', () => {\n\t\t\ttextures.forEach(textureInfo => {\n\t\t\t\tif (textureInfo.historyDepth && textureInfo.historyDepth > 1 && textureInfo.writeIndex !== undefined) {\n\t\t\t\t\ttextureInfo.writeIndex = 0;\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\tshaderPadWithHistory.initializeTexture = function (\n\t\t\tname: string,\n\t\t\tsource: TextureSource,\n\t\t\thistoryDepth: number = 1\n\t\t) {\n\t\t\tconst { width, height } = getSourceDimensions(source);\n\t\t\tif (!width || !height) {\n\t\t\t\tthrow new Error(`Texture source must have valid dimensions`);\n\t\t\t}\n\n\t\t\tconst depth = Math.floor(historyDepth);\n\t\t\tif (depth <= 1) {\n\t\t\t\treturn originalInitializeTexture(name, source);\n\t\t\t}\n\n\t\t\tif (textures.has(name)) {\n\t\t\t\tthrow new Error(`Texture '${name}' is already initialized.`);\n\t\t\t}\n\n\t\t\tlet unitIndex: number | undefined;\n\t\t\tlet texture: WebGLTexture | null = null;\n\t\t\ttry {\n\t\t\t\tunitIndex = reserveTextureUnit(name);\n\t\t\t\ttexture = createHistoryTexture(gl, depth, width, height);\n\t\t\t\tgl.activeTexture(gl.TEXTURE0 + unitIndex);\n\t\t\t\tgl.bindTexture(gl.TEXTURE_2D_ARRAY, texture);\n\n\t\t\t\t// Flip the texture vertically during upload to match WebGL's coordinate system.\n\t\t\t\t// WebGL uses bottom-left origin, while images/videos use top-left origin.\n\t\t\t\tgl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);\n\t\t\t\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n\t\t\t\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n\t\t\t\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_MIN_FILTER, gl.LINEAR);\n\t\t\t\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_MAG_FILTER, gl.LINEAR);\n\n\t\t\t\tif (context.program) {\n\t\t\t\t\tconst uSampler = gl.getUniformLocation(context.program, name);\n\t\t\t\t\tif (uSampler) {\n\t\t\t\t\t\tgl.uniform1i(uSampler, unitIndex);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ttextures.set(name, {\n\t\t\t\t\ttexture,\n\t\t\t\t\tunitIndex,\n\t\t\t\t\thistoryDepth: depth,\n\t\t\t\t\twriteIndex: 0,\n\t\t\t\t});\n\n\t\t\t\tshaderPadWithHistory.updateTextures({ [name]: source });\n\t\t\t} catch (error) {\n\t\t\t\tif (texture) gl.deleteTexture(texture);\n\t\t\t\tif (unitIndex !== undefined) {\n\t\t\t\t\tcontext.releaseTextureUnit(name);\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t};\n\n\t\tshaderPadWithHistory.updateTextures = function (updates) {\n\t\t\tObject.entries(updates).forEach(([name, source]) => {\n\t\t\t\tconst textureInfo = textures.get(name);\n\t\t\t\tif (!textureInfo || !textureInfo.historyDepth || textureInfo.historyDepth <= 1) {\n\t\t\t\t\treturn originalUpdateTextures({ [name]: source });\n\t\t\t\t}\n\n\t\t\t\tconst { width, height } = getSourceDimensions(source);\n\t\t\t\tconst writeIndex = textureInfo.writeIndex ?? 0;\n\t\t\t\tgl.activeTexture(gl.TEXTURE0 + textureInfo.unitIndex);\n\t\t\t\tgl.bindTexture(gl.TEXTURE_2D_ARRAY, textureInfo.texture);\n\t\t\t\tgl.texSubImage3D(\n\t\t\t\t\tgl.TEXTURE_2D_ARRAY,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\twriteIndex,\n\t\t\t\t\twidth,\n\t\t\t\t\theight,\n\t\t\t\t\t1,\n\t\t\t\t\tgl.RGBA,\n\t\t\t\t\tgl.UNSIGNED_BYTE,\n\t\t\t\t\tsource\n\t\t\t\t);\n\t\t\t\ttextureInfo.writeIndex = (writeIndex + 1) % textureInfo.historyDepth;\n\t\t\t});\n\t\t};\n\n\t\tshaderPad.registerHook('destroy', () => {\n\t\t\tif (framebufferHistoryTexture) {\n\t\t\t\tgl.deleteTexture(framebufferHistoryTexture);\n\t\t\t}\n\t\t});\n\t};\n}\n","import ShaderPad, { PluginContext } from '../index';\n\ndeclare module '../index' {\n\tinterface ShaderPad {\n\t\tsave(filename: string): Promise<void>;\n\t}\n}\n\nexport function save() {\n\treturn function (shaderPad: ShaderPad, context: PluginContext) {\n\t\tconst { gl, canvas } = context;\n\t\tconst downloadLink = document.createElement('a');\n\n\t\t(shaderPad as any).save = async function (filename: string) {\n\t\t\tgl.clear(gl.COLOR_BUFFER_BIT);\n\t\t\tgl.drawArrays(gl.TRIANGLES, 0, 6);\n\n\t\t\tif (filename && !`${filename}`.toLowerCase().endsWith('.png')) {\n\t\t\t\tfilename = `${filename}.png`;\n\t\t\t}\n\t\t\tfilename = filename || 'export.png';\n\t\t\tif ('ongesturechange' in window) {\n\t\t\t\t// Mobile.\n\t\t\t\ttry {\n\t\t\t\t\tconst blob: Blob = await new Promise(resolve =>\n\t\t\t\t\t\tcanvas.toBlob(resolve as BlobCallback, 'image/png')\n\t\t\t\t\t);\n\t\t\t\t\tconst file = new File([blob], filename, { type: blob.type });\n\n\t\t\t\t\tif (navigator.canShare?.({ files: [file] })) {\n\t\t\t\t\t\tawait navigator.share({ files: [file] });\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconsole.warn('Web Share API failed:', error);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Desktop.\n\t\t\t\tdownloadLink.download = filename;\n\t\t\t\tdownloadLink.href = canvas.toDataURL();\n\t\t\t\tdownloadLink.click();\n\t\t\t}\n\t\t};\n\t};\n}\n\n// Type helper.\nexport type WithSave<T extends ShaderPad> = T & {\n\tsave(filename: string): Promise<void>;\n};\n","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\thistoryDepth?: number;\n\twriteIndex?: number;\n}\n\nexport type TextureSource = HTMLImageElement | HTMLVideoElement;\n\nexport interface PluginContext {\n\tgl: WebGL2RenderingContext;\n\tuniforms: Map<string, Uniform>;\n\ttextures: Map<string, Texture>;\n\tget program(): WebGLProgram | null;\n\tcanvas: HTMLCanvasElement;\n\treserveTextureUnit: (name: string) => number;\n\treleaseTextureUnit: (name: string) => void;\n}\n\ntype Plugin = (shaderPad: ShaderPad, context: PluginContext) => void;\n\ntype LifecycleMethod = 'init' | 'step' | 'destroy' | 'updateResolution' | 'reset';\n\ninterface Options {\n\tcanvas?: HTMLCanvasElement | null;\n\tplugins?: Plugin[];\n}\n\ntype TextureUnitPool = {\n\tfree: number[];\n\tnext: number;\n\tmax: 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 textureUnitPool: TextureUnitPool;\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\tpublic canvas: HTMLCanvasElement;\n\tpublic onResize?: (width: number, height: number) => void;\n\tprivate hooks: Map<LifecycleMethod, Function[]> = new Map();\n\n\tconstructor(fragmentShaderSrc: string, options: Options = {}) {\n\t\tthis.canvas = options.canvas || document.createElement('canvas');\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.textureUnitPool = {\n\t\t\tfree: [],\n\t\t\tnext: 1, // Start from unit 1 to avoid conflict with history texture at unit 0.\n\t\t\tmax: this.gl.getParameter(this.gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS),\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\tif (options.plugins) {\n\t\t\tconst context: PluginContext = {\n\t\t\t\tgl: this.gl,\n\t\t\t\tuniforms: this.uniforms,\n\t\t\t\ttextures: this.textures,\n\t\t\t\tcanvas: this.canvas,\n\t\t\t\treserveTextureUnit: this.reserveTextureUnit.bind(this),\n\t\t\t\treleaseTextureUnit: this.releaseTextureUnit.bind(this),\n\t\t\t} as PluginContext;\n\t\t\t// Define program as a getter so it always returns the current program.\n\t\t\tObject.defineProperty(context, 'program', {\n\t\t\t\tget: () => this.program,\n\t\t\t\tenumerable: true,\n\t\t\t\tconfigurable: true,\n\t\t\t});\n\t\t\toptions.plugins.forEach(plugin => plugin(this, context));\n\t\t}\n\t\tthis.init();\n\t\tthis.addEventListeners();\n\t}\n\n\tregisterHook(name: LifecycleMethod, fn: Function) {\n\t\tif (!this.hooks.has(name)) {\n\t\t\tthis.hooks.set(name, []);\n\t\t}\n\t\tthis.hooks.get(name)!.push(fn);\n\t}\n\n\tprivate init() {\n\t\tconst vertexShaderSrc = DEFAULT_VERTEX_SHADER_SRC;\n\n\t\tthis.program = this.gl.createProgram();\n\t\tif (!this.program) {\n\t\t\tthrow new Error('Failed to create WebGL program');\n\t\t}\n\t\tconst vertexShader = this.createShader(this.gl.VERTEX_SHADER, vertexShaderSrc);\n\t\tconst fragmentShader = this.createShader(this.gl.FRAGMENT_SHADER, this.fragmentShaderSrc);\n\n\t\tthis.gl.attachShader(this.program, vertexShader);\n\t\tthis.gl.attachShader(this.program, fragmentShader);\n\t\tthis.gl.linkProgram(this.program);\n\t\tthis.gl.deleteShader(vertexShader);\n\t\tthis.gl.deleteShader(fragmentShader);\n\n\t\tif (!this.gl.getProgramParameter(this.program, this.gl.LINK_STATUS)) {\n\t\t\tconsole.error('Program link error:', this.gl.getProgramInfoLog(this.program));\n\t\t\tthis.gl.deleteProgram(this.program);\n\t\t\tthrow new Error('Failed to link WebGL program');\n\t\t}\n\n\t\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\n\t\tthis.hooks.get('init')?.forEach(hook => hook.call(this));\n\t}\n\n\tprivate createShader(type: number, source: string): WebGLShader {\n\t\tconst shader = this.gl.createShader(type)!;\n\t\tthis.gl.shaderSource(shader, source);\n\t\tthis.gl.compileShader(shader);\n\t\tif (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)) {\n\t\t\tconsole.error('Shader compilation failed:', source);\n\t\t\tconsole.error(this.gl.getShaderInfoLog(shader));\n\t\t\tthis.gl.deleteShader(shader);\n\t\t\tthrow new Error('Shader compilation failed');\n\t\t}\n\t\treturn shader;\n\t}\n\n\tprivate setupBuffer(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\tthis.hooks.get('updateResolution')?.forEach(hook => hook.call(this));\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\tgl.clear(gl.COLOR_BUFFER_BIT);\n\t\tgl.drawArrays(gl.TRIANGLES, 0, 6);\n\n\t\tthis.hooks.get('step')?.forEach(hook => hook.call(this, time, this.frame));\n\n\t\t++this.frame;\n\t}\n\n\tplay(callback?: (time: number, frame: number) => void) {\n\t\tthis.pause(); // Prevent double play.\n\t\tconst loop = (time: number) => {\n\t\t\ttime = (time - this.startTime) / 1000; // Convert from milliseconds to seconds.\n\t\t\tthis.step(time);\n\t\t\tthis.animationFrameId = requestAnimationFrame(loop);\n\t\t\tif (callback) callback(time, this.frame);\n\t\t};\n\t\tthis.animationFrameId = requestAnimationFrame(loop);\n\t}\n\n\tpause() {\n\t\tif (this.animationFrameId) {\n\t\t\tcancelAnimationFrame(this.animationFrameId);\n\t\t\tthis.animationFrameId = null;\n\t\t}\n\t}\n\n\treset() {\n\t\tthis.frame = 0;\n\t\tthis.startTime = performance.now();\n\t\tthis.hooks.get('reset')?.forEach(hook => hook.call(this));\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\tlet unitIndex: number;\n\t\ttry {\n\t\t\tunitIndex = this.reserveTextureUnit(name);\n\t\t} catch (error) {\n\t\t\tthis.gl.deleteTexture(texture);\n\t\t\tthrow error;\n\t\t}\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 during upload to match WebGL's coordinate system.\n\t\t// WebGL uses bottom-left origin, while images/videos use top-left origin.\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\t\tthis.textureUnitPool.free = [];\n\t\tthis.textureUnitPool.next = 1;\n\n\t\tif (this.buffer) {\n\t\t\tthis.gl.deleteBuffer(this.buffer);\n\t\t\tthis.buffer = null;\n\t\t}\n\n\t\tthis.hooks.get('destroy')?.forEach(hook => hook.call(this));\n\n\t\tif (this.isInternalCanvas) {\n\t\t\tthis.canvas.remove();\n\t\t}\n\t}\n\n\t// TODO: Review these two.\n\tprivate reserveTextureUnit(name: string) {\n\t\tif (!name) {\n\t\t\tthrow new Error('Texture unit name must be provided.');\n\t\t}\n\t\tconst existing = this.textures.get(name);\n\t\tif (existing) {\n\t\t\treturn existing.unitIndex;\n\t\t}\n\t\tlet unit: number;\n\t\tif (this.textureUnitPool.free.length > 0) {\n\t\t\tunit = this.textureUnitPool.free.pop()!;\n\t\t} else {\n\t\t\tunit = this.textureUnitPool.next;\n\t\t\tif (unit >= this.textureUnitPool.max) {\n\t\t\t\tthrow new Error('Exceeded the available texture units for this device.');\n\t\t\t}\n\t\t\tthis.textureUnitPool.next += 1;\n\t\t}\n\t\treturn unit;\n\t}\n\n\tprivate releaseTextureUnit(name: string) {\n\t\tconst existing = this.textures.get(name);\n\t\tif (!existing) {\n\t\t\treturn;\n\t\t}\n\t\tconst unit = existing.unitIndex;\n\t\tif (unit > 0) {\n\t\t\tthis.textureUnitPool.free.push(unit);\n\t\t}\n\t}\n}\n\nexport * from './plugins';\nexport default ShaderPad;\n"],"mappings":"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","names":["getSourceDimensions","source","video","image","width","height","clearHistoryTextureLayers","gl","depth","transparent","layer","createHistoryTexture","texture","history","framebufferDepth","shaderPad","context","uniforms","textures","reserveTextureUnit","shaderPadWithHistory","originalInitializeTexture","originalUpdateTextures","framebufferHistoryTexture","initializeFramebufferHistory","clearFramebufferHistory","_time","frame","writeIdx","textureInfo","name","historyDepth","unitIndex","uSampler","error","updates","writeIndex","save","shaderPad","context","gl","canvas","downloadLink","filename","blob","resolve","file","error","DEFAULT_VERTEX_SHADER_SRC","RESIZE_THROTTLE_INTERVAL","ShaderPad","fragmentShaderSrc","options","context","plugin","name","fn","vertexShaderSrc","vertexShader","fragmentShader","aPosition","hook","type","source","shader","quadVertices","now","timeUntilNextResize","pixelRatio","width","height","updateCursor","x","y","rect","updateClick","isMouseDown","xVal","yVal","event","mouseEvent","touchEvent","listener","value","location","length","updates","uniform","time","gl","callback","loop","texture","unitIndex","error","uSampler","info","filename","blob","resolve","file","existing","unit","index_default"]}
|