shaderpad 1.0.0-alpha.9 → 1.0.0-beta.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -57,8 +57,16 @@ shader.play(time => {
57
57
  shader.updateUniforms({ u_cursorColor: getColor(time) });
58
58
  });
59
59
 
60
- // Optionally pause the render loop.
60
+ // Optionally pause or reset the render loop.
61
61
  // shader.pause();
62
+ // shader.reset();
63
+
64
+ // ShaderPad also attaches a throttled resize observer that you can hook into.
65
+ // It fires when the canvas size changes visually. If you supplied a custom
66
+ // canvas, you may use this to update its `width` and `height` attributes.
67
+ // shader.onResize = (width, height) => {
68
+ // console.log('Canvas resized:', width, height);
69
+ // };
62
70
  ```
63
71
 
64
72
  See the [`examples/` directory](./examples/) for more.
@@ -74,30 +82,49 @@ The `canvas` option allows you to pass in an existing canvas element. If not pro
74
82
  ```typescript
75
83
  const canvas = document.createElement('canvas');
76
84
  const shader = new ShaderPad(fragmentShaderSrc, { canvas });
85
+ shader.onResize = (width, height) => {
86
+ canvas.width = width;
87
+ canvas.height = height;
88
+ };
77
89
  ```
78
90
 
79
- ### history
91
+ ### plugins
80
92
 
81
- ShaderPad supports frame history buffers for effects like motion blur, feedback, and trails:
93
+ ShaderPad supports plugins to add additional functionality.
94
+
95
+ #### history
96
+
97
+ The `history` plugin adds a frame history buffer to the shader. It is useful for effects like motion blur, feedback, and trails.
82
98
 
83
99
  ```typescript
100
+ import ShaderPad, { history } from 'shaderpad';
84
101
  // 2-frame history (eg. for cellular automata).
85
- const shader = new ShaderPad(fragmentShaderSrc, { history: 2 });
102
+ const shader = new ShaderPad(fragmentShaderSrc, { plugins: [history(2)] });
86
103
 
87
104
  // 10-frame history (eg. for motion blur).
88
- const shader = new ShaderPad(fragmentShaderSrc, { history: 10 });
105
+ const shader = new ShaderPad(fragmentShaderSrc, { plugins: [history(10)] });
106
+ ```
107
+
108
+ #### save
109
+
110
+ The `save` plugin adds a `.save()` method to the shader that saves the current frame to a PNG file.
111
+
112
+ ```typescript
113
+ import ShaderPad, { save, WithSave } from 'shaderpad';
114
+ const shader = new ShaderPad(fragmentShaderSrc, { plugins: [save()] }) as WithSave<ShaderPad>;
115
+ shader.save('my-frame');
89
116
  ```
90
117
 
91
118
  ## Included uniforms
92
119
 
93
- | Uniform | Type | Description |
94
- | -------------- | -------------- | -------------------------------------------------- |
95
- | `u_time` | float | The current time in seconds. |
96
- | `u_frame` | int | The current frame number. |
97
- | `u_resolution` | float[2] | The canvas element's dimensions. |
98
- | `u_cursor` | float[4] | Cursor position (x, y) and scroll position (z, w). |
99
- | `u_click` | float[3] | Click position (x, y) and left click state (z). |
100
- | `u_history` | sampler2DArray | Buffer texture of prior frames. |
120
+ | Uniform | Type | Description |
121
+ | -------------- | -------------- | ------------------------------------------------------------------------------- |
122
+ | `u_time` | float | The current time in seconds. |
123
+ | `u_frame` | int | The current frame number. |
124
+ | `u_resolution` | float[2] | The canvas element's dimensions. |
125
+ | `u_cursor` | float[2] | Cursor position (x, y). |
126
+ | `u_click` | float[3] | Click position (x, y) and left click state (z). |
127
+ | `u_history` | sampler2DArray | Buffer texture of prior frames. Only available if the `history` plugin is used. |
101
128
 
102
129
  ## Included varyings
103
130
 
@@ -120,15 +147,13 @@ npm install
120
147
  npm run dev
121
148
  ```
122
149
 
123
- This will launch a local server (powered by Vite). Open the provided URL (usually `http://localhost:5173`) in your browser to view and interact with the examples.
124
-
125
- `examples/index.html` hardcodes the `main.ts` example. To view a different example, change `<script type="module" src="/src/main.ts"></script>` to point to your new example.
150
+ This will launch a local server. Open the provided URL (usually `http://localhost:5173`) in your browser to view and interact with the examples. Use the select box to view a different example.
126
151
 
127
152
  ### Adding an example
128
153
 
129
154
  - Add a new `.ts` file in `examples/src/`.
130
- - Follow the structure of an existing example as a template.
131
- - Change `<script type="module" src="/src/main.ts"></script>` in `examples/index.html` to point to your new example.
155
+ - Follow the structure of an existing example as a template. The example must export an `init` function and a `destroy` function.
156
+ - Add the example to the `demos` array in `examples/src/main.ts`.
132
157
  - If your example needs images or other assets, place them in `examples/public/` and reference them with a relative path.
133
158
 
134
159
  ## License
package/dist/index.d.mts CHANGED
@@ -1,11 +1,40 @@
1
+ declare function history(depth?: number): (shaderPad: ShaderPad, context: PluginContext) => void;
2
+
3
+ declare module '../index' {
4
+ interface ShaderPad {
5
+ save(filename: string): Promise<void>;
6
+ }
7
+ }
8
+ declare function save(): (shaderPad: ShaderPad, context: PluginContext) => void;
9
+ type WithSave<T extends ShaderPad> = T & {
10
+ save(filename: string): Promise<void>;
11
+ };
12
+
13
+ interface Uniform {
14
+ type: 'float' | 'int';
15
+ length: 1 | 2 | 3 | 4;
16
+ location: WebGLUniformLocation;
17
+ }
18
+ interface Texture {
19
+ texture: WebGLTexture;
20
+ unitIndex: number;
21
+ }
22
+ interface PluginContext {
23
+ gl: WebGL2RenderingContext;
24
+ uniforms: Map<string, Uniform>;
25
+ textures: Map<string, Texture>;
26
+ program: WebGLProgram | null;
27
+ canvas: HTMLCanvasElement;
28
+ }
29
+ type Plugin = (shaderPad: ShaderPad, context: PluginContext) => void;
30
+ type LifecycleMethod = 'init' | 'step' | 'destroy' | 'updateResolution' | 'reset';
1
31
  interface Options {
2
32
  canvas?: HTMLCanvasElement | null;
3
- history?: number;
33
+ plugins?: Plugin[];
4
34
  }
5
35
  declare class ShaderPad {
6
36
  private isInternalCanvas;
7
37
  private isTouchDevice;
8
- private canvas;
9
38
  private gl;
10
39
  private downloadLink;
11
40
  private fragmentShaderSrc;
@@ -14,35 +43,38 @@ declare class ShaderPad {
14
43
  private buffer;
15
44
  private program;
16
45
  private animationFrameId;
46
+ private resolutionObserver;
17
47
  private resizeObserver;
18
48
  private resizeTimeout;
19
49
  private lastResizeTime;
20
50
  private eventListeners;
21
51
  private frame;
52
+ private startTime;
22
53
  private cursorPosition;
23
- private scrollX;
24
- private scrollY;
25
54
  private clickPosition;
26
55
  private isMouseDown;
27
- private historyLength;
28
- private historyTexture;
56
+ canvas: HTMLCanvasElement;
57
+ onResize?: (width: number, height: number) => void;
58
+ private hooks;
29
59
  constructor(fragmentShaderSrc: string, options?: Options);
60
+ registerHook(name: LifecycleMethod, fn: Function): void;
30
61
  private init;
31
- private initializeHistoryBuffer;
32
62
  private createShader;
33
63
  private setupBuffer;
34
64
  private throttledHandleResize;
35
65
  private handleResize;
36
66
  private addEventListeners;
67
+ private updateResolution;
37
68
  initializeUniform(name: string, type: 'float' | 'int', value: number | number[]): void;
38
69
  updateUniforms(updates: Record<string, number | number[]>): void;
39
70
  step(time: number): void;
40
71
  play(callback?: (time: number, frame: number) => void): void;
41
72
  pause(): void;
42
- save(filename: string): void;
73
+ reset(): void;
43
74
  initializeTexture(name: string, source: HTMLImageElement | HTMLVideoElement): void;
44
75
  updateTextures(updates: Record<string, HTMLImageElement | HTMLVideoElement>): void;
76
+ save(filename: string): Promise<void>;
45
77
  destroy(): void;
46
78
  }
47
79
 
48
- export { ShaderPad as default };
80
+ export { type PluginContext, type WithSave, ShaderPad as default, history, save };
package/dist/index.d.ts CHANGED
@@ -1,11 +1,40 @@
1
+ declare function history(depth?: number): (shaderPad: ShaderPad, context: PluginContext) => void;
2
+
3
+ declare module '../index' {
4
+ interface ShaderPad {
5
+ save(filename: string): Promise<void>;
6
+ }
7
+ }
8
+ declare function save(): (shaderPad: ShaderPad, context: PluginContext) => void;
9
+ type WithSave<T extends ShaderPad> = T & {
10
+ save(filename: string): Promise<void>;
11
+ };
12
+
13
+ interface Uniform {
14
+ type: 'float' | 'int';
15
+ length: 1 | 2 | 3 | 4;
16
+ location: WebGLUniformLocation;
17
+ }
18
+ interface Texture {
19
+ texture: WebGLTexture;
20
+ unitIndex: number;
21
+ }
22
+ interface PluginContext {
23
+ gl: WebGL2RenderingContext;
24
+ uniforms: Map<string, Uniform>;
25
+ textures: Map<string, Texture>;
26
+ program: WebGLProgram | null;
27
+ canvas: HTMLCanvasElement;
28
+ }
29
+ type Plugin = (shaderPad: ShaderPad, context: PluginContext) => void;
30
+ type LifecycleMethod = 'init' | 'step' | 'destroy' | 'updateResolution' | 'reset';
1
31
  interface Options {
2
32
  canvas?: HTMLCanvasElement | null;
3
- history?: number;
33
+ plugins?: Plugin[];
4
34
  }
5
35
  declare class ShaderPad {
6
36
  private isInternalCanvas;
7
37
  private isTouchDevice;
8
- private canvas;
9
38
  private gl;
10
39
  private downloadLink;
11
40
  private fragmentShaderSrc;
@@ -14,35 +43,38 @@ declare class ShaderPad {
14
43
  private buffer;
15
44
  private program;
16
45
  private animationFrameId;
46
+ private resolutionObserver;
17
47
  private resizeObserver;
18
48
  private resizeTimeout;
19
49
  private lastResizeTime;
20
50
  private eventListeners;
21
51
  private frame;
52
+ private startTime;
22
53
  private cursorPosition;
23
- private scrollX;
24
- private scrollY;
25
54
  private clickPosition;
26
55
  private isMouseDown;
27
- private historyLength;
28
- private historyTexture;
56
+ canvas: HTMLCanvasElement;
57
+ onResize?: (width: number, height: number) => void;
58
+ private hooks;
29
59
  constructor(fragmentShaderSrc: string, options?: Options);
60
+ registerHook(name: LifecycleMethod, fn: Function): void;
30
61
  private init;
31
- private initializeHistoryBuffer;
32
62
  private createShader;
33
63
  private setupBuffer;
34
64
  private throttledHandleResize;
35
65
  private handleResize;
36
66
  private addEventListeners;
67
+ private updateResolution;
37
68
  initializeUniform(name: string, type: 'float' | 'int', value: number | number[]): void;
38
69
  updateUniforms(updates: Record<string, number | number[]>): void;
39
70
  step(time: number): void;
40
71
  play(callback?: (time: number, frame: number) => void): void;
41
72
  pause(): void;
42
- save(filename: string): void;
73
+ reset(): void;
43
74
  initializeTexture(name: string, source: HTMLImageElement | HTMLVideoElement): void;
44
75
  updateTextures(updates: Record<string, HTMLImageElement | HTMLVideoElement>): void;
76
+ save(filename: string): Promise<void>;
45
77
  destroy(): void;
46
78
  }
47
79
 
48
- export { ShaderPad as default };
80
+ export { type PluginContext, type WithSave, ShaderPad as default, history, save };
package/dist/index.js CHANGED
@@ -1,9 +1,9 @@
1
- "use strict";var a=Object.defineProperty;var u=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var m=Object.prototype.hasOwnProperty;var d=(n,t)=>{for(var e in t)a(n,e,{get:t[e],enumerable:!0})},f=(n,t,e,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of g(t))!m.call(n,s)&&s!==e&&a(n,s,{get:()=>t[s],enumerable:!(i=u(t,s))||i.enumerable});return n};var E=n=>f(a({},"__esModule",{value:!0}),n);var p={};d(p,{default:()=>R});module.exports=E(p);var T=`#version 300 es
1
+ "use strict";var u=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var d=Object.getOwnPropertyNames;var m=Object.prototype.hasOwnProperty;var E=(n,e)=>{for(var r in e)u(n,r,{get:e[r],enumerable:!0})},T=(n,e,r,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let t of d(e))!m.call(n,t)&&t!==r&&u(n,t,{get:()=>e[t],enumerable:!(i=f(e,t))||i.enumerable});return n};var v=n=>T(u({},"__esModule",{value:!0}),n);var x={};E(x,{default:()=>_,history:()=>p,save:()=>R});module.exports=v(x);function p(n=2){if(n<2)throw new Error("History depth must be greater than 1");return function(e,r){let i=null,{gl:t,uniforms:s}=r;e.registerHook("init",o),e.registerHook("step",(h,l)=>{let g=l%n;t.activeTexture(t.TEXTURE0),t.bindTexture(t.TEXTURE_2D_ARRAY,i),t.copyTexSubImage3D(t.TEXTURE_2D_ARRAY,0,0,0,g,0,0,t.drawingBufferWidth,t.drawingBufferHeight)}),e.registerHook("updateResolution",()=>{t.deleteTexture(i),o()}),e.registerHook("reset",a),e.registerHook("destroy",()=>{t.deleteTexture(i),i=null});function o(){if(i=t.createTexture(),!i)throw new Error("Failed to create history texture");t.bindTexture(t.TEXTURE_2D_ARRAY,i),t.texParameteri(t.TEXTURE_2D_ARRAY,t.TEXTURE_WRAP_S,t.CLAMP_TO_EDGE),t.texParameteri(t.TEXTURE_2D_ARRAY,t.TEXTURE_WRAP_T,t.CLAMP_TO_EDGE),t.texParameteri(t.TEXTURE_2D_ARRAY,t.TEXTURE_MIN_FILTER,t.NEAREST),t.texParameteri(t.TEXTURE_2D_ARRAY,t.TEXTURE_MAG_FILTER,t.NEAREST),t.texStorage3D(t.TEXTURE_2D_ARRAY,1,t.RGBA8,t.drawingBufferWidth,t.drawingBufferHeight,n),t.activeTexture(t.TEXTURE0),t.bindTexture(t.TEXTURE_2D_ARRAY,i),a(),s.has("u_history")||e.initializeUniform("u_history","int",0)}function a(){t.activeTexture(t.TEXTURE0),t.bindTexture(t.TEXTURE_2D_ARRAY,i);let h=new Uint8Array(t.drawingBufferWidth*t.drawingBufferHeight*4);for(let l=0;l<n;++l)t.texSubImage3D(t.TEXTURE_2D_ARRAY,0,0,0,l,t.drawingBufferWidth,t.drawingBufferHeight,1,t.RGBA,t.UNSIGNED_BYTE,h)}}}function R(){return function(n,e){let{gl:r,canvas:i}=e,t=document.createElement("a");n.save=async function(s){if(r.clear(r.COLOR_BUFFER_BIT),r.drawArrays(r.TRIANGLES,0,6),s&&!`${s}`.toLowerCase().endsWith(".png")&&(s=`${s}.png`),s=s||"export.png","ongesturechange"in window)try{let o=await new Promise(h=>i.toBlob(h,"image/png")),a=new File([o],s,{type:o.type});if(navigator.canShare?.({files:[a]})){await navigator.share({files:[a]});return}}catch(o){console.warn("Web Share API failed:",o)}else t.download=s,t.href=i.toDataURL(),t.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
- `,v=33.333333333333336,o=class{constructor(t,e={}){this.isInternalCanvas=!1;this.isTouchDevice=!1;this.uniforms=new Map;this.textures=new Map;this.buffer=null;this.program=null;this.resizeTimeout=null;this.lastResizeTime=0;this.eventListeners=new Map;this.frame=0;this.cursorPosition=[.5,.5];this.scrollX=0;this.scrollY=0;this.clickPosition=[.5,.5];this.isMouseDown=!1;this.historyTexture=null;if(this.canvas=e.canvas||document.createElement("canvas"),this.historyLength=e.history||0,e.canvas||(this.isInternalCanvas=!0,document.body.appendChild(this.canvas),this.canvas.style.position="fixed",this.canvas.style.inset="0",this.canvas.style.height="100dvh",this.canvas.style.width="100dvw"),this.gl=this.canvas.getContext("webgl2",{antialias:!1}),!this.gl)throw new Error("WebGL2 not supported. Please use a browser that supports WebGL2.");this.downloadLink=document.createElement("a"),this.fragmentShaderSrc=t,this.animationFrameId=null,this.resizeObserver=new ResizeObserver(()=>this.throttledHandleResize()),this.resizeObserver.observe(this.canvas),this.init(),this.addEventListeners()}init(){let t=T;if(this.program=this.gl.createProgram(),!this.program)throw new Error("Failed to create WebGL program");let e=this.createShader(this.gl.VERTEX_SHADER,t),i=this.createShader(this.gl.FRAGMENT_SHADER,this.fragmentShaderSrc);if(this.gl.attachShader(this.program,e),this.gl.attachShader(this.program,i),this.gl.linkProgram(this.program),this.gl.deleteShader(e),this.gl.deleteShader(i),!this.gl.getProgramParameter(this.program,this.gl.LINK_STATUS))throw console.error("Program link error:",this.gl.getProgramInfoLog(this.program)),this.gl.deleteProgram(this.program),new Error("Failed to link WebGL program");let s=this.gl.getAttribLocation(this.program,"aPosition");this.setupBuffer(s),this.handleResize(),this.gl.useProgram(this.program),this.initializeUniform("u_resolution","float",[this.canvas.width,this.canvas.height]),this.initializeUniform("u_cursor","float",[...this.cursorPosition,this.scrollX,this.scrollY]),this.initializeUniform("u_click","float",[...this.clickPosition,this.isMouseDown?1:0]),this.initializeUniform("u_time","float",0),this.initializeUniform("u_frame","int",0),this.historyLength>0&&this.initializeHistoryBuffer()}initializeHistoryBuffer(){let{gl:t}=this;if(this.historyTexture=t.createTexture(),!this.historyTexture)throw new Error("Failed to create history texture");t.bindTexture(t.TEXTURE_2D_ARRAY,this.historyTexture),t.texParameteri(t.TEXTURE_2D_ARRAY,t.TEXTURE_WRAP_S,t.CLAMP_TO_EDGE),t.texParameteri(t.TEXTURE_2D_ARRAY,t.TEXTURE_WRAP_T,t.CLAMP_TO_EDGE),t.texParameteri(t.TEXTURE_2D_ARRAY,t.TEXTURE_MIN_FILTER,t.NEAREST),t.texParameteri(t.TEXTURE_2D_ARRAY,t.TEXTURE_MAG_FILTER,t.NEAREST),t.texStorage3D(t.TEXTURE_2D_ARRAY,1,t.RGBA8,this.canvas.width,this.canvas.height,this.historyLength);let e=new Uint8Array(this.canvas.width*this.canvas.height*4);for(let i=0;i<this.historyLength;++i)t.texSubImage3D(t.TEXTURE_2D_ARRAY,0,0,0,i,this.canvas.width,this.canvas.height,1,t.RGBA,t.UNSIGNED_BYTE,e);t.activeTexture(t.TEXTURE0),t.bindTexture(t.TEXTURE_2D_ARRAY,this.historyTexture),this.uniforms.has("u_history")||this.initializeUniform("u_history","int",0)}createShader(t,e){let i=this.gl.createShader(t);if(this.gl.shaderSource(i,e),this.gl.compileShader(i),!this.gl.getShaderParameter(i,this.gl.COMPILE_STATUS))throw console.error("Shader compilation failed:",e),console.error(this.gl.getShaderInfoLog(i)),this.gl.deleteShader(i),new Error("Shader compilation failed");return i}setupBuffer(t){let e=new Float32Array([-1,-1,1,-1,-1,1,-1,1,1,-1,1,1]);this.buffer=this.gl.createBuffer(),this.gl.bindBuffer(this.gl.ARRAY_BUFFER,this.buffer),this.gl.bufferData(this.gl.ARRAY_BUFFER,e,this.gl.STATIC_DRAW),this.gl.viewport(0,0,this.canvas.width,this.canvas.height),this.gl.enableVertexAttribArray(t),this.gl.vertexAttribPointer(t,2,this.gl.FLOAT,!1,0,0)}throttledHandleResize(){clearTimeout(this.resizeTimeout);let t=performance.now(),e=this.lastResizeTime+v-t;e<=0?(this.lastResizeTime=t,this.handleResize()):this.resizeTimeout=setTimeout(()=>this.throttledHandleResize(),e)}handleResize(){let t=window.devicePixelRatio||1,e=this.canvas.clientWidth*t,i=this.canvas.clientHeight*t,s=getComputedStyle(this.canvas),r=s.width!==`${this.canvas.width}px`&&s.width!=="auto",h=s.height!==`${this.canvas.height}px`&&s.height!=="auto";(!r||!h)&&(this.canvas.style.width=`${this.canvas.clientWidth}px`,this.canvas.style.height=`${this.canvas.clientHeight}px`),(this.canvas.width!==e||this.canvas.height!==i)&&(this.canvas.width=e,this.canvas.height=i,this.gl.viewport(0,0,this.gl.drawingBufferWidth,this.gl.drawingBufferHeight),this.uniforms.has("u_resolution")&&this.updateUniforms({u_resolution:[this.canvas.width,this.canvas.height]}),this.historyLength>0&&this.historyTexture&&(this.gl.deleteTexture(this.historyTexture),this.initializeHistoryBuffer()))}addEventListeners(){let t=(i,s)=>{if(!this.uniforms.has("u_cursor"))return;let r=this.canvas.getBoundingClientRect();this.cursorPosition[0]=(i-r.left)/r.width,this.cursorPosition[1]=1-(s-r.top)/r.height,this.updateUniforms({u_cursor:[this.cursorPosition[0],this.cursorPosition[1],this.scrollX,this.scrollY]})},e=(i,s,r)=>{if(this.uniforms.has("u_click")){if(this.isMouseDown=i,i){let h=this.canvas.getBoundingClientRect(),l=s,c=r;this.clickPosition[0]=(l-h.left)/h.width,this.clickPosition[1]=1-(c-h.top)/h.height}this.updateUniforms({u_click:[this.clickPosition[0],this.clickPosition[1],this.isMouseDown?1:0]})}};this.eventListeners.set("mousemove",i=>{let s=i;this.isTouchDevice||t(s.clientX,s.clientY)}),this.eventListeners.set("mousedown",i=>{let s=i;this.isTouchDevice||s.button===0&&(this.isMouseDown=!0,e(!0,s.clientX,s.clientY))}),this.eventListeners.set("mouseup",i=>{let s=i;this.isTouchDevice||s.button===0&&e(!1)}),this.eventListeners.set("wheel",i=>{let s=i;this.scrollX+=s.deltaX*.01,this.scrollY+=s.deltaY*.01,t(s.clientX,s.clientY)}),this.eventListeners.set("touchmove",i=>{let s=i;s.touches.length>0&&t(s.touches[0].clientX,s.touches[0].clientY)}),this.eventListeners.set("touchstart",i=>{let s=i;this.isTouchDevice=!0,s.touches.length>0&&(e(!0,s.touches[0].clientX,s.touches[0].clientY),t(s.touches[0].clientX,s.touches[0].clientY))}),this.eventListeners.set("touchend",i=>{i.touches.length===0&&e(!1)}),this.eventListeners.forEach((i,s)=>{this.canvas.addEventListener(s,i)})}initializeUniform(t,e,i){if(this.uniforms.has(t))throw new Error(`Uniform '${t}' is already initialized.`);if(e!=="float"&&e!=="int")throw new Error(`Invalid uniform type: ${e}. Expected 'float' or 'int'.`);let s=this.gl.getUniformLocation(this.program,t);if(!s){console.debug(`Uniform ${t} not found in fragment shader. Skipping initialization.`);return}if(Array.isArray(i)||(i=[i]),i.length<1||i.length>4)throw new Error(`Invalid uniform value length: ${i.length}. Expected a length between 1 and 4.`);let r=i.length;this.uniforms.set(t,{type:e,length:r,location:s}),this.updateUniforms({[t]:i})}updateUniforms(t){Object.entries(t).forEach(([e,i])=>{if(!this.uniforms.has(e))throw new Error(`Uniform '${e}' is not initialized.`);let s=this.uniforms.get(e);if(Array.isArray(i)||(i=[i]),i.length!==s.length)throw new Error(`Invalid uniform value length: ${i.length}. Expected ${s.length}.`);this.gl[`uniform${s.length}${s.type.charAt(0)}`](s.location,...i)})}step(t){let e=this.gl;if(this.uniforms.has("u_time")&&this.updateUniforms({u_time:t}),this.uniforms.has("u_frame")&&this.updateUniforms({u_frame:this.frame}),this.historyLength>0){let i=this.frame%this.historyLength;e.bindFramebuffer(e.FRAMEBUFFER,null),e.viewport(0,0,this.canvas.width,this.canvas.height),e.clear(e.COLOR_BUFFER_BIT),e.drawArrays(e.TRIANGLES,0,6),e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D_ARRAY,this.historyTexture),e.copyTexSubImage3D(e.TEXTURE_2D_ARRAY,0,0,0,i,0,0,this.canvas.width,this.canvas.height)}else e.clear(e.COLOR_BUFFER_BIT),e.drawArrays(e.TRIANGLES,0,6);++this.frame}play(t){let e=i=>{i/=1e3,this.step(i),t&&t(i,this.frame),this.animationFrameId=requestAnimationFrame(e)};this.animationFrameId=requestAnimationFrame(e)}pause(){this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null)}save(t){this.gl.clear(this.gl.COLOR_BUFFER_BIT),this.gl.drawArrays(this.gl.TRIANGLES,0,6);let e=this.canvas.toDataURL();t&&!`${t}`.toLowerCase().endsWith(".png")&&(t=`${t}.png`),this.downloadLink.download=t||"export.png",this.downloadLink.href=e,this.downloadLink.click()}initializeTexture(t,e){if(this.textures.has(t))throw new Error(`Texture '${t}' is already initialized.`);let i=this.gl.createTexture();if(!i)throw new Error("Failed to create texture");let s=this.textures.size+1;this.gl.activeTexture(this.gl.TEXTURE0+s),this.gl.bindTexture(this.gl.TEXTURE_2D,i),this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,!0),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_WRAP_S,this.gl.CLAMP_TO_EDGE),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_WRAP_T,this.gl.CLAMP_TO_EDGE),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MIN_FILTER,this.gl.LINEAR),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MAG_FILTER,this.gl.LINEAR),this.textures.set(t,{texture:i,unitIndex:s}),this.updateTextures({[t]:e});let r=this.gl.getUniformLocation(this.program,t);r&&this.gl.uniform1i(r,s)}updateTextures(t){Object.entries(t).forEach(([e,i])=>{let s=this.textures.get(e);if(!s)throw new Error(`Texture '${e}' is not initialized.`);this.gl.activeTexture(this.gl.TEXTURE0+s.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D,s.texture),this.gl.texImage2D(this.gl.TEXTURE_2D,0,this.gl.RGBA,this.gl.RGBA,this.gl.UNSIGNED_BYTE,i)})}destroy(){this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null),this.resizeObserver.unobserve(this.canvas),this.eventListeners.forEach((t,e)=>{this.canvas.removeEventListener(e,t)}),this.program&&this.gl.deleteProgram(this.program),this.textures.forEach(t=>{this.gl.deleteTexture(t.texture)}),this.historyTexture&&(this.gl.deleteTexture(this.historyTexture),this.historyTexture=null),this.buffer&&(this.gl.deleteBuffer(this.buffer),this.buffer=null),this.isInternalCanvas&&this.canvas.remove()}},R=o;
8
+ `,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});
9
9
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["const DEFAULT_VERTEX_SHADER_SRC = `#version 300 es\nin vec2 aPosition;\nout vec2 v_uv;\nvoid main() {\n v_uv = aPosition * 0.5 + 0.5;\n gl_Position = vec4(aPosition, 0.0, 1.0);\n}\n`;\nconst RESIZE_THROTTLE_INTERVAL = 1000 / 30;\n\ninterface Uniform {\n\ttype: 'float' | 'int';\n\tlength: 1 | 2 | 3 | 4;\n\tlocation: WebGLUniformLocation;\n}\n\ninterface Texture {\n\ttexture: WebGLTexture;\n\tunitIndex: number;\n}\n\ninterface Options {\n\tcanvas?: HTMLCanvasElement | null;\n\thistory?: number;\n}\n\nclass ShaderPad {\n\tprivate isInternalCanvas = false;\n\tprivate isTouchDevice = false;\n\tprivate canvas: HTMLCanvasElement;\n\tprivate gl: WebGL2RenderingContext;\n\tprivate downloadLink: HTMLAnchorElement;\n\tprivate fragmentShaderSrc: string;\n\tprivate uniforms: Map<string, Uniform> = new Map();\n\tprivate textures: Map<string, Texture> = new Map();\n\tprivate buffer: WebGLBuffer | null = null;\n\tprivate program: WebGLProgram | null = null;\n\tprivate animationFrameId: number | null;\n\tprivate 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 cursorPosition = [0.5, 0.5];\n\tprivate scrollX = 0;\n\tprivate scrollY = 0;\n\tprivate clickPosition = [0.5, 0.5];\n\tprivate isMouseDown = false;\n\tprivate historyLength: number;\n\tprivate historyTexture: WebGLTexture | null = null;\n\n\tconstructor(fragmentShaderSrc: string, options: Options = {}) {\n\t\tthis.canvas = options.canvas || document.createElement('canvas');\n\t\tthis.historyLength = options.history || 0;\n\t\tif (!options.canvas) {\n\t\t\tthis.isInternalCanvas = true;\n\t\t\tdocument.body.appendChild(this.canvas);\n\t\t\tthis.canvas.style.position = 'fixed';\n\t\t\tthis.canvas.style.inset = '0';\n\t\t\tthis.canvas.style.height = '100dvh';\n\t\t\tthis.canvas.style.width = '100dvw';\n\t\t}\n\n\t\tthis.gl = this.canvas.getContext('webgl2', { antialias: false }) as WebGL2RenderingContext;\n\t\tif (!this.gl) {\n\t\t\tthrow new Error('WebGL2 not supported. Please use a browser that supports WebGL2.');\n\t\t}\n\n\t\tthis.downloadLink = document.createElement('a');\n\t\tthis.fragmentShaderSrc = fragmentShaderSrc;\n\t\tthis.animationFrameId = null;\n\t\tthis.resizeObserver = new ResizeObserver(() => this.throttledHandleResize());\n\t\tthis.resizeObserver.observe(this.canvas);\n\t\tthis.init();\n\t\tthis.addEventListeners();\n\t}\n\n\tprivate init() {\n\t\tconst vertexShaderSrc = 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\t\tthis.handleResize();\n\n\t\tthis.gl.useProgram(this.program);\n\n\t\tthis.initializeUniform('u_resolution', 'float', [this.canvas.width, this.canvas.height]);\n\t\tthis.initializeUniform('u_cursor', 'float', [...this.cursorPosition, this.scrollX, this.scrollY]); // [cursorX, cursorY, scrollX, scrollY]\n\t\tthis.initializeUniform('u_click', 'float', [...this.clickPosition, this.isMouseDown ? 1.0 : 0.0]); // [clickX, clickY, leftClick]\n\t\tthis.initializeUniform('u_time', 'float', 0);\n\t\tthis.initializeUniform('u_frame', 'int', 0);\n\n\t\tif (this.historyLength > 0) {\n\t\t\tthis.initializeHistoryBuffer();\n\t\t}\n\t}\n\n\tprivate initializeHistoryBuffer() {\n\t\tconst { gl } = this;\n\n\t\tthis.historyTexture = gl.createTexture();\n\t\tif (!this.historyTexture) {\n\t\t\tthrow new Error('Failed to create history texture');\n\t\t}\n\n\t\tgl.bindTexture(gl.TEXTURE_2D_ARRAY, this.historyTexture);\n\t\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n\t\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n\t\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_MIN_FILTER, gl.NEAREST);\n\t\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_MAG_FILTER, gl.NEAREST);\n\t\tgl.texStorage3D(gl.TEXTURE_2D_ARRAY, 1, gl.RGBA8, this.canvas.width, this.canvas.height, this.historyLength);\n\n\t\t// Make initial frames transparent.\n\t\tconst transparent = new Uint8Array(this.canvas.width * this.canvas.height * 4); // All zeroes.\n\t\tfor (let layer = 0; layer < this.historyLength; ++layer) {\n\t\t\tgl.texSubImage3D(\n\t\t\t\tgl.TEXTURE_2D_ARRAY,\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t\tlayer,\n\t\t\t\tthis.canvas.width,\n\t\t\t\tthis.canvas.height,\n\t\t\t\t1,\n\t\t\t\tgl.RGBA,\n\t\t\t\tgl.UNSIGNED_BYTE,\n\t\t\t\ttransparent\n\t\t\t);\n\t\t}\n\n\t\tgl.activeTexture(gl.TEXTURE0);\n\t\tgl.bindTexture(gl.TEXTURE_2D_ARRAY, this.historyTexture);\n\n\t\tif (!this.uniforms.has('u_history')) {\n\t\t\tthis.initializeUniform('u_history', 'int', 0);\n\t\t}\n\t}\n\n\tprivate createShader(type: number, source: string): WebGLShader {\n\t\tconst shader = this.gl.createShader(type)!;\n\t\tthis.gl.shaderSource(shader, source);\n\t\tthis.gl.compileShader(shader);\n\t\tif (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)) {\n\t\t\tconsole.error('Shader compilation failed:', source);\n\t\t\tconsole.error(this.gl.getShaderInfoLog(shader));\n\t\t\tthis.gl.deleteShader(shader);\n\t\t\tthrow new Error('Shader compilation failed');\n\t\t}\n\t\treturn shader;\n\t}\n\n\tprivate setupBuffer(aPosition: number) {\n\t\tconst quadVertices = new Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1]);\n\n\t\tthis.buffer = this.gl.createBuffer();\n\t\tthis.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.buffer);\n\t\tthis.gl.bufferData(this.gl.ARRAY_BUFFER, quadVertices, this.gl.STATIC_DRAW);\n\t\tthis.gl.viewport(0, 0, this.canvas.width, this.canvas.height);\n\t\tthis.gl.enableVertexAttribArray(aPosition);\n\t\tthis.gl.vertexAttribPointer(aPosition, 2, this.gl.FLOAT, false, 0, 0);\n\t}\n\n\tprivate 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\t// TODO: This breaks for `position: fixed; inset: 0` canvases.\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\n\t\tconst computedStyle = getComputedStyle(this.canvas);\n\t\tconst hasExplicitWidth = computedStyle.width !== `${this.canvas.width}px` && computedStyle.width !== 'auto';\n\t\tconst hasExplicitHeight = computedStyle.height !== `${this.canvas.height}px` && computedStyle.height !== 'auto';\n\t\tif (!hasExplicitWidth || !hasExplicitHeight) {\n\t\t\tthis.canvas.style.width = `${this.canvas.clientWidth}px`;\n\t\t\tthis.canvas.style.height = `${this.canvas.clientHeight}px`;\n\t\t}\n\n\t\tif (this.canvas.width !== width || this.canvas.height !== height) {\n\t\t\tthis.canvas.width = width;\n\t\t\tthis.canvas.height = height;\n\t\t\tthis.gl.viewport(0, 0, this.gl.drawingBufferWidth, this.gl.drawingBufferHeight);\n\t\t\tif (this.uniforms.has('u_resolution')) {\n\t\t\t\tthis.updateUniforms({ u_resolution: [this.canvas.width, this.canvas.height] });\n\t\t\t}\n\n\t\t\t// Delete and recreate history buffer, since the canvas size won’t be correct anymore.\n\t\t\tif (this.historyLength > 0 && this.historyTexture) {\n\t\t\t\tthis.gl.deleteTexture(this.historyTexture);\n\t\t\t\tthis.initializeHistoryBuffer();\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate addEventListeners() {\n\t\tconst updateCursor = (x: number, y: number) => {\n\t\t\tif (!this.uniforms.has('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({\n\t\t\t\tu_cursor: [this.cursorPosition[0], this.cursorPosition[1], this.scrollX, this.scrollY],\n\t\t\t});\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({\n\t\t\t\tu_click: [this.clickPosition[0], this.clickPosition[1], this.isMouseDown ? 1.0 : 0.0],\n\t\t\t});\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('wheel', event => {\n\t\t\tconst wheelEvent = event as WheelEvent;\n\t\t\tthis.scrollX += wheelEvent.deltaX * 0.01;\n\t\t\tthis.scrollY += wheelEvent.deltaY * 0.01;\n\t\t\tupdateCursor(wheelEvent.clientX, wheelEvent.clientY);\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\tupdateClick(true, touchEvent.touches[0].clientX, touchEvent.touches[0].clientY);\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('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\tinitializeUniform(name: string, type: 'float' | 'int', value: number | number[]) {\n\t\tif (this.uniforms.has(name)) {\n\t\t\tthrow new Error(`Uniform '${name}' is already initialized.`);\n\t\t}\n\n\t\tif (type !== 'float' && type !== 'int') {\n\t\t\tthrow new Error(`Invalid uniform type: ${type}. Expected 'float' or 'int'.`);\n\t\t}\n\n\t\tconst location = this.gl.getUniformLocation(this.program!, name);\n\t\tif (!location) {\n\t\t\tconsole.debug(`Uniform ${name} not found in fragment shader. Skipping initialization.`);\n\t\t\treturn;\n\t\t}\n\n\t\tif (!Array.isArray(value)) {\n\t\t\tvalue = [value];\n\t\t}\n\t\tif (value.length < 1 || value.length > 4) {\n\t\t\tthrow new Error(`Invalid uniform value length: ${value.length}. Expected a length between 1 and 4.`);\n\t\t}\n\n\t\tconst length = value.length as 1 | 2 | 3 | 4;\n\t\tthis.uniforms.set(name, { type, length, location });\n\t\tthis.updateUniforms({ [name]: value });\n\t}\n\n\tupdateUniforms(updates: Record<string, number | number[]>) {\n\t\tObject.entries(updates).forEach(([name, value]: [string, number | number[]]) => {\n\t\t\tif (!this.uniforms.has(name)) {\n\t\t\t\tthrow new Error(`Uniform '${name}' is not initialized.`);\n\t\t\t}\n\n\t\t\tconst uniform = this.uniforms.get(name)!;\n\t\t\tif (!Array.isArray(value)) {\n\t\t\t\tvalue = [value];\n\t\t\t}\n\t\t\tif (value.length !== uniform.length) {\n\t\t\t\tthrow new Error(`Invalid uniform value length: ${value.length}. Expected ${uniform.length}.`);\n\t\t\t}\n\t\t\t(this.gl as any)[`uniform${uniform.length}${uniform.type.charAt(0)}`](uniform.location, ...value);\n\t\t});\n\t}\n\n\tstep(time: number) {\n\t\tconst gl = this.gl;\n\n\t\tif (this.uniforms.has('u_time')) {\n\t\t\tthis.updateUniforms({ u_time: time });\n\t\t}\n\t\tif (this.uniforms.has('u_frame')) {\n\t\t\tthis.updateUniforms({ u_frame: this.frame });\n\t\t}\n\n\t\tif (this.historyLength > 0) {\n\t\t\tconst writeIdx = this.frame % this.historyLength;\n\n\t\t\tgl.bindFramebuffer(gl.FRAMEBUFFER, null);\n\t\t\tgl.viewport(0, 0, this.canvas.width, this.canvas.height);\n\t\t\tgl.clear(gl.COLOR_BUFFER_BIT);\n\t\t\tgl.drawArrays(gl.TRIANGLES, 0, 6);\n\n\t\t\tgl.activeTexture(gl.TEXTURE0);\n\t\t\tgl.bindTexture(gl.TEXTURE_2D_ARRAY, this.historyTexture);\n\t\t\tgl.copyTexSubImage3D(gl.TEXTURE_2D_ARRAY, 0, 0, 0, writeIdx, 0, 0, this.canvas.width, this.canvas.height);\n\t\t} else {\n\t\t\tgl.clear(gl.COLOR_BUFFER_BIT);\n\t\t\tgl.drawArrays(gl.TRIANGLES, 0, 6);\n\t\t}\n\n\t\t++this.frame;\n\t}\n\n\tplay(callback?: (time: number, frame: number) => void) {\n\t\tconst loop = (time: number) => {\n\t\t\ttime /= 1000; // Convert from milliseconds to seconds.\n\t\t\tthis.step(time);\n\t\t\tif (callback) callback(time, this.frame);\n\t\t\tthis.animationFrameId = requestAnimationFrame(loop);\n\t\t};\n\t\tthis.animationFrameId = requestAnimationFrame(loop);\n\t}\n\n\tpause() {\n\t\tif (this.animationFrameId) {\n\t\t\tcancelAnimationFrame(this.animationFrameId);\n\t\t\tthis.animationFrameId = null;\n\t\t}\n\t}\n\n\tsave(filename: string) {\n\t\tthis.gl.clear(this.gl.COLOR_BUFFER_BIT);\n\t\tthis.gl.drawArrays(this.gl.TRIANGLES, 0, 6);\n\n\t\tconst image = this.canvas.toDataURL();\n\t\tif (filename && !`${filename}`.toLowerCase().endsWith('.png')) {\n\t\t\tfilename = `${filename}.png`;\n\t\t}\n\t\tthis.downloadLink.download = filename || 'export.png';\n\t\tthis.downloadLink.href = image;\n\t\tthis.downloadLink.click();\n\t}\n\n\tinitializeTexture(name: string, source: HTMLImageElement | HTMLVideoElement) {\n\t\tif (this.textures.has(name)) {\n\t\t\tthrow new Error(`Texture '${name}' is already initialized.`);\n\t\t}\n\n\t\tconst texture = this.gl.createTexture();\n\t\tif (!texture) {\n\t\t\tthrow new Error('Failed to create texture');\n\t\t}\n\t\tconst unitIndex = this.textures.size + 1; // Start from unit 1 to avoid conflict with history texture at unit 0.\n\t\tthis.gl.activeTexture(this.gl.TEXTURE0 + unitIndex);\n\t\tthis.gl.bindTexture(this.gl.TEXTURE_2D, texture);\n\n\t\t// Flip the texture vertically since v_uv is flipped, and set up filters and wrapping.\n\t\tthis.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, true);\n\t\tthis.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);\n\t\tthis.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);\n\t\tthis.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR);\n\t\tthis.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.LINEAR);\n\n\t\tthis.textures.set(name, { texture, unitIndex });\n\t\tthis.updateTextures({ [name]: source });\n\n\t\tconst uSampler = this.gl.getUniformLocation(this.program!, name);\n\t\tif (uSampler) {\n\t\t\tthis.gl.uniform1i(uSampler, unitIndex);\n\t\t}\n\t}\n\n\tupdateTextures(updates: Record<string, HTMLImageElement | HTMLVideoElement>) {\n\t\tObject.entries(updates).forEach(([name, source]) => {\n\t\t\tconst info = this.textures.get(name);\n\t\t\tif (!info) {\n\t\t\t\tthrow new Error(`Texture '${name}' is not initialized.`);\n\t\t\t}\n\t\t\tthis.gl.activeTexture(this.gl.TEXTURE0 + info.unitIndex);\n\t\t\tthis.gl.bindTexture(this.gl.TEXTURE_2D, info.texture);\n\t\t\tthis.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, this.gl.RGBA, this.gl.UNSIGNED_BYTE, source);\n\t\t});\n\t}\n\n\tdestroy() {\n\t\tif (this.animationFrameId) {\n\t\t\tcancelAnimationFrame(this.animationFrameId);\n\t\t\tthis.animationFrameId = null;\n\t\t}\n\n\t\tthis.resizeObserver.unobserve(this.canvas);\n\t\tthis.eventListeners.forEach((listener, event) => {\n\t\t\tthis.canvas.removeEventListener(event, listener);\n\t\t});\n\n\t\tif (this.program) {\n\t\t\tthis.gl.deleteProgram(this.program);\n\t\t}\n\n\t\tthis.textures.forEach(texture => {\n\t\t\tthis.gl.deleteTexture(texture.texture);\n\t\t});\n\n\t\tif (this.historyTexture) {\n\t\t\tthis.gl.deleteTexture(this.historyTexture);\n\t\t\tthis.historyTexture = null;\n\t\t}\n\n\t\tif (this.buffer) {\n\t\t\tthis.gl.deleteBuffer(this.buffer);\n\t\t\tthis.buffer = null;\n\t\t}\n\n\t\tif (this.isInternalCanvas) {\n\t\t\tthis.canvas.remove();\n\t\t}\n\t}\n}\n\nexport default ShaderPad;\n"],"mappings":"yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,aAAAE,IAAA,eAAAC,EAAAH,GAAA,IAAMI,EAA4B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQ5BC,EAA2B,mBAkB3BC,EAAN,KAAgB,CAyBf,YAAYC,EAA2BC,EAAmB,CAAC,EAAG,CAxB9D,KAAQ,iBAAmB,GAC3B,KAAQ,cAAgB,GAKxB,KAAQ,SAAiC,IAAI,IAC7C,KAAQ,SAAiC,IAAI,IAC7C,KAAQ,OAA6B,KACrC,KAAQ,QAA+B,KAGvC,KAAQ,cAAgC,KACxC,KAAQ,eAAiB,EACzB,KAAQ,eAA6C,IAAI,IACzD,KAAQ,MAAQ,EAChB,KAAQ,eAAiB,CAAC,GAAK,EAAG,EAClC,KAAQ,QAAU,EAClB,KAAQ,QAAU,EAClB,KAAQ,cAAgB,CAAC,GAAK,EAAG,EACjC,KAAQ,YAAc,GAEtB,KAAQ,eAAsC,KAe7C,GAZA,KAAK,OAASA,EAAQ,QAAU,SAAS,cAAc,QAAQ,EAC/D,KAAK,cAAgBA,EAAQ,SAAW,EACnCA,EAAQ,SACZ,KAAK,iBAAmB,GACxB,SAAS,KAAK,YAAY,KAAK,MAAM,EACrC,KAAK,OAAO,MAAM,SAAW,QAC7B,KAAK,OAAO,MAAM,MAAQ,IAC1B,KAAK,OAAO,MAAM,OAAS,SAC3B,KAAK,OAAO,MAAM,MAAQ,UAG3B,KAAK,GAAK,KAAK,OAAO,WAAW,SAAU,CAAE,UAAW,EAAM,CAAC,EAC3D,CAAC,KAAK,GACT,MAAM,IAAI,MAAM,kEAAkE,EAGnF,KAAK,aAAe,SAAS,cAAc,GAAG,EAC9C,KAAK,kBAAoBD,EACzB,KAAK,iBAAmB,KACxB,KAAK,eAAiB,IAAI,eAAe,IAAM,KAAK,sBAAsB,CAAC,EAC3E,KAAK,eAAe,QAAQ,KAAK,MAAM,EACvC,KAAK,KAAK,EACV,KAAK,kBAAkB,CACxB,CAEQ,MAAO,CACd,IAAME,EAAkBL,EAGxB,GADA,KAAK,QAAU,KAAK,GAAG,cAAc,EACjC,CAAC,KAAK,QACT,MAAM,IAAI,MAAM,gCAAgC,EAEjD,IAAMM,EAAe,KAAK,aAAa,KAAK,GAAG,cAAeD,CAAe,EACvEE,EAAiB,KAAK,aAAa,KAAK,GAAG,gBAAiB,KAAK,iBAAiB,EAQxF,GANA,KAAK,GAAG,aAAa,KAAK,QAASD,CAAY,EAC/C,KAAK,GAAG,aAAa,KAAK,QAASC,CAAc,EACjD,KAAK,GAAG,YAAY,KAAK,OAAO,EAChC,KAAK,GAAG,aAAaD,CAAY,EACjC,KAAK,GAAG,aAAaC,CAAc,EAE/B,CAAC,KAAK,GAAG,oBAAoB,KAAK,QAAS,KAAK,GAAG,WAAW,EACjE,cAAQ,MAAM,sBAAuB,KAAK,GAAG,kBAAkB,KAAK,OAAO,CAAC,EAC5E,KAAK,GAAG,cAAc,KAAK,OAAO,EAC5B,IAAI,MAAM,8BAA8B,EAG/C,IAAMC,EAAY,KAAK,GAAG,kBAAkB,KAAK,QAAS,WAAW,EACrE,KAAK,YAAYA,CAAS,EAC1B,KAAK,aAAa,EAElB,KAAK,GAAG,WAAW,KAAK,OAAO,EAE/B,KAAK,kBAAkB,eAAgB,QAAS,CAAC,KAAK,OAAO,MAAO,KAAK,OAAO,MAAM,CAAC,EACvF,KAAK,kBAAkB,WAAY,QAAS,CAAC,GAAG,KAAK,eAAgB,KAAK,QAAS,KAAK,OAAO,CAAC,EAChG,KAAK,kBAAkB,UAAW,QAAS,CAAC,GAAG,KAAK,cAAe,KAAK,YAAc,EAAM,CAAG,CAAC,EAChG,KAAK,kBAAkB,SAAU,QAAS,CAAC,EAC3C,KAAK,kBAAkB,UAAW,MAAO,CAAC,EAEtC,KAAK,cAAgB,GACxB,KAAK,wBAAwB,CAE/B,CAEQ,yBAA0B,CACjC,GAAM,CAAE,GAAAC,CAAG,EAAI,KAGf,GADA,KAAK,eAAiBA,EAAG,cAAc,EACnC,CAAC,KAAK,eACT,MAAM,IAAI,MAAM,kCAAkC,EAGnDA,EAAG,YAAYA,EAAG,iBAAkB,KAAK,cAAc,EACvDA,EAAG,cAAcA,EAAG,iBAAkBA,EAAG,eAAgBA,EAAG,aAAa,EACzEA,EAAG,cAAcA,EAAG,iBAAkBA,EAAG,eAAgBA,EAAG,aAAa,EACzEA,EAAG,cAAcA,EAAG,iBAAkBA,EAAG,mBAAoBA,EAAG,OAAO,EACvEA,EAAG,cAAcA,EAAG,iBAAkBA,EAAG,mBAAoBA,EAAG,OAAO,EACvEA,EAAG,aAAaA,EAAG,iBAAkB,EAAGA,EAAG,MAAO,KAAK,OAAO,MAAO,KAAK,OAAO,OAAQ,KAAK,aAAa,EAG3G,IAAMC,EAAc,IAAI,WAAW,KAAK,OAAO,MAAQ,KAAK,OAAO,OAAS,CAAC,EAC7E,QAASC,EAAQ,EAAGA,EAAQ,KAAK,cAAe,EAAEA,EACjDF,EAAG,cACFA,EAAG,iBACH,EACA,EACA,EACAE,EACA,KAAK,OAAO,MACZ,KAAK,OAAO,OACZ,EACAF,EAAG,KACHA,EAAG,cACHC,CACD,EAGDD,EAAG,cAAcA,EAAG,QAAQ,EAC5BA,EAAG,YAAYA,EAAG,iBAAkB,KAAK,cAAc,EAElD,KAAK,SAAS,IAAI,WAAW,GACjC,KAAK,kBAAkB,YAAa,MAAO,CAAC,CAE9C,CAEQ,aAAaG,EAAcC,EAA6B,CAC/D,IAAMC,EAAS,KAAK,GAAG,aAAaF,CAAI,EAGxC,GAFA,KAAK,GAAG,aAAaE,EAAQD,CAAM,EACnC,KAAK,GAAG,cAAcC,CAAM,EACxB,CAAC,KAAK,GAAG,mBAAmBA,EAAQ,KAAK,GAAG,cAAc,EAC7D,cAAQ,MAAM,6BAA8BD,CAAM,EAClD,QAAQ,MAAM,KAAK,GAAG,iBAAiBC,CAAM,CAAC,EAC9C,KAAK,GAAG,aAAaA,CAAM,EACrB,IAAI,MAAM,2BAA2B,EAE5C,OAAOA,CACR,CAEQ,YAAYN,EAAmB,CACtC,IAAMO,EAAe,IAAI,aAAa,CAAC,GAAI,GAAI,EAAG,GAAI,GAAI,EAAG,GAAI,EAAG,EAAG,GAAI,EAAG,CAAC,CAAC,EAEhF,KAAK,OAAS,KAAK,GAAG,aAAa,EACnC,KAAK,GAAG,WAAW,KAAK,GAAG,aAAc,KAAK,MAAM,EACpD,KAAK,GAAG,WAAW,KAAK,GAAG,aAAcA,EAAc,KAAK,GAAG,WAAW,EAC1E,KAAK,GAAG,SAAS,EAAG,EAAG,KAAK,OAAO,MAAO,KAAK,OAAO,MAAM,EAC5D,KAAK,GAAG,wBAAwBP,CAAS,EACzC,KAAK,GAAG,oBAAoBA,EAAW,EAAG,KAAK,GAAG,MAAO,GAAO,EAAG,CAAC,CACrE,CAEQ,uBAAwB,CAC/B,aAAa,KAAK,aAAa,EAC/B,IAAMQ,EAAM,YAAY,IAAI,EACtBC,EAAsB,KAAK,eAAiBhB,EAA2Be,EACzEC,GAAuB,GAC1B,KAAK,eAAiBD,EACtB,KAAK,aAAa,GAElB,KAAK,cAAgB,WAAW,IAAM,KAAK,sBAAsB,EAAGC,CAAmB,CAEzF,CAGQ,cAAe,CACtB,IAAMC,EAAa,OAAO,kBAAoB,EACxCC,EAAQ,KAAK,OAAO,YAAcD,EAClCE,EAAS,KAAK,OAAO,aAAeF,EAEpCG,EAAgB,iBAAiB,KAAK,MAAM,EAC5CC,EAAmBD,EAAc,QAAU,GAAG,KAAK,OAAO,KAAK,MAAQA,EAAc,QAAU,OAC/FE,EAAoBF,EAAc,SAAW,GAAG,KAAK,OAAO,MAAM,MAAQA,EAAc,SAAW,QACrG,CAACC,GAAoB,CAACC,KACzB,KAAK,OAAO,MAAM,MAAQ,GAAG,KAAK,OAAO,WAAW,KACpD,KAAK,OAAO,MAAM,OAAS,GAAG,KAAK,OAAO,YAAY,OAGnD,KAAK,OAAO,QAAUJ,GAAS,KAAK,OAAO,SAAWC,KACzD,KAAK,OAAO,MAAQD,EACpB,KAAK,OAAO,OAASC,EACrB,KAAK,GAAG,SAAS,EAAG,EAAG,KAAK,GAAG,mBAAoB,KAAK,GAAG,mBAAmB,EAC1E,KAAK,SAAS,IAAI,cAAc,GACnC,KAAK,eAAe,CAAE,aAAc,CAAC,KAAK,OAAO,MAAO,KAAK,OAAO,MAAM,CAAE,CAAC,EAI1E,KAAK,cAAgB,GAAK,KAAK,iBAClC,KAAK,GAAG,cAAc,KAAK,cAAc,EACzC,KAAK,wBAAwB,GAGhC,CAEQ,mBAAoB,CAC3B,IAAMI,EAAe,CAACC,EAAWC,IAAc,CAC9C,GAAI,CAAC,KAAK,SAAS,IAAI,UAAU,EAAG,OACpC,IAAMC,EAAO,KAAK,OAAO,sBAAsB,EAC/C,KAAK,eAAe,CAAC,GAAKF,EAAIE,EAAK,MAAQA,EAAK,MAChD,KAAK,eAAe,CAAC,EAAI,GAAKD,EAAIC,EAAK,KAAOA,EAAK,OACnD,KAAK,eAAe,CACnB,SAAU,CAAC,KAAK,eAAe,CAAC,EAAG,KAAK,eAAe,CAAC,EAAG,KAAK,QAAS,KAAK,OAAO,CACtF,CAAC,CACF,EAEMC,EAAc,CAACC,EAAsBJ,EAAYC,IAAe,CACrE,GAAK,KAAK,SAAS,IAAI,SAAS,EAEhC,IADA,KAAK,YAAcG,EACfA,EAAa,CAChB,IAAMF,EAAO,KAAK,OAAO,sBAAsB,EACzCG,EAAOL,EACPM,EAAOL,EACb,KAAK,cAAc,CAAC,GAAKI,EAAOH,EAAK,MAAQA,EAAK,MAClD,KAAK,cAAc,CAAC,EAAI,GAAKI,EAAOJ,EAAK,KAAOA,EAAK,MACtD,CACA,KAAK,eAAe,CACnB,QAAS,CAAC,KAAK,cAAc,CAAC,EAAG,KAAK,cAAc,CAAC,EAAG,KAAK,YAAc,EAAM,CAAG,CACrF,CAAC,EACF,EAEA,KAAK,eAAe,IAAI,YAAaK,GAAS,CAC7C,IAAMC,EAAaD,EACd,KAAK,eACTR,EAAaS,EAAW,QAASA,EAAW,OAAO,CAErD,CAAC,EAED,KAAK,eAAe,IAAI,YAAaD,GAAS,CAC7C,IAAMC,EAAaD,EACd,KAAK,eACLC,EAAW,SAAW,IACzB,KAAK,YAAc,GACnBL,EAAY,GAAMK,EAAW,QAASA,EAAW,OAAO,EAG3D,CAAC,EAED,KAAK,eAAe,IAAI,UAAWD,GAAS,CAC3C,IAAMC,EAAaD,EACd,KAAK,eACLC,EAAW,SAAW,GACzBL,EAAY,EAAK,CAGpB,CAAC,EAED,KAAK,eAAe,IAAI,QAASI,GAAS,CACzC,IAAME,EAAaF,EACnB,KAAK,SAAWE,EAAW,OAAS,IACpC,KAAK,SAAWA,EAAW,OAAS,IACpCV,EAAaU,EAAW,QAASA,EAAW,OAAO,CACpD,CAAC,EAED,KAAK,eAAe,IAAI,YAAaF,GAAS,CAC7C,IAAMG,EAAaH,EACfG,EAAW,QAAQ,OAAS,GAC/BX,EAAaW,EAAW,QAAQ,CAAC,EAAE,QAASA,EAAW,QAAQ,CAAC,EAAE,OAAO,CAE3E,CAAC,EAED,KAAK,eAAe,IAAI,aAAcH,GAAS,CAC9C,IAAMG,EAAaH,EACnB,KAAK,cAAgB,GACjBG,EAAW,QAAQ,OAAS,IAC/BP,EAAY,GAAMO,EAAW,QAAQ,CAAC,EAAE,QAASA,EAAW,QAAQ,CAAC,EAAE,OAAO,EAC9EX,EAAaW,EAAW,QAAQ,CAAC,EAAE,QAASA,EAAW,QAAQ,CAAC,EAAE,OAAO,EAE3E,CAAC,EAED,KAAK,eAAe,IAAI,WAAYH,GAAS,CACzBA,EACJ,QAAQ,SAAW,GACjCJ,EAAY,EAAK,CAEnB,CAAC,EAED,KAAK,eAAe,QAAQ,CAACQ,EAAUJ,IAAU,CAChD,KAAK,OAAO,iBAAiBA,EAAOI,CAAQ,CAC7C,CAAC,CACF,CAEA,kBAAkBC,EAAczB,EAAuB0B,EAA0B,CAChF,GAAI,KAAK,SAAS,IAAID,CAAI,EACzB,MAAM,IAAI,MAAM,YAAYA,CAAI,2BAA2B,EAG5D,GAAIzB,IAAS,SAAWA,IAAS,MAChC,MAAM,IAAI,MAAM,yBAAyBA,CAAI,8BAA8B,EAG5E,IAAM2B,EAAW,KAAK,GAAG,mBAAmB,KAAK,QAAUF,CAAI,EAC/D,GAAI,CAACE,EAAU,CACd,QAAQ,MAAM,WAAWF,CAAI,yDAAyD,EACtF,MACD,CAKA,GAHK,MAAM,QAAQC,CAAK,IACvBA,EAAQ,CAACA,CAAK,GAEXA,EAAM,OAAS,GAAKA,EAAM,OAAS,EACtC,MAAM,IAAI,MAAM,iCAAiCA,EAAM,MAAM,sCAAsC,EAGpG,IAAME,EAASF,EAAM,OACrB,KAAK,SAAS,IAAID,EAAM,CAAE,KAAAzB,EAAM,OAAA4B,EAAQ,SAAAD,CAAS,CAAC,EAClD,KAAK,eAAe,CAAE,CAACF,CAAI,EAAGC,CAAM,CAAC,CACtC,CAEA,eAAeG,EAA4C,CAC1D,OAAO,QAAQA,CAAO,EAAE,QAAQ,CAAC,CAACJ,EAAMC,CAAK,IAAmC,CAC/E,GAAI,CAAC,KAAK,SAAS,IAAID,CAAI,EAC1B,MAAM,IAAI,MAAM,YAAYA,CAAI,uBAAuB,EAGxD,IAAMK,EAAU,KAAK,SAAS,IAAIL,CAAI,EAItC,GAHK,MAAM,QAAQC,CAAK,IACvBA,EAAQ,CAACA,CAAK,GAEXA,EAAM,SAAWI,EAAQ,OAC5B,MAAM,IAAI,MAAM,iCAAiCJ,EAAM,MAAM,cAAcI,EAAQ,MAAM,GAAG,EAE5F,KAAK,GAAW,UAAUA,EAAQ,MAAM,GAAGA,EAAQ,KAAK,OAAO,CAAC,CAAC,EAAE,EAAEA,EAAQ,SAAU,GAAGJ,CAAK,CACjG,CAAC,CACF,CAEA,KAAKK,EAAc,CAClB,IAAMlC,EAAK,KAAK,GAShB,GAPI,KAAK,SAAS,IAAI,QAAQ,GAC7B,KAAK,eAAe,CAAE,OAAQkC,CAAK,CAAC,EAEjC,KAAK,SAAS,IAAI,SAAS,GAC9B,KAAK,eAAe,CAAE,QAAS,KAAK,KAAM,CAAC,EAGxC,KAAK,cAAgB,EAAG,CAC3B,IAAMC,EAAW,KAAK,MAAQ,KAAK,cAEnCnC,EAAG,gBAAgBA,EAAG,YAAa,IAAI,EACvCA,EAAG,SAAS,EAAG,EAAG,KAAK,OAAO,MAAO,KAAK,OAAO,MAAM,EACvDA,EAAG,MAAMA,EAAG,gBAAgB,EAC5BA,EAAG,WAAWA,EAAG,UAAW,EAAG,CAAC,EAEhCA,EAAG,cAAcA,EAAG,QAAQ,EAC5BA,EAAG,YAAYA,EAAG,iBAAkB,KAAK,cAAc,EACvDA,EAAG,kBAAkBA,EAAG,iBAAkB,EAAG,EAAG,EAAGmC,EAAU,EAAG,EAAG,KAAK,OAAO,MAAO,KAAK,OAAO,MAAM,CACzG,MACCnC,EAAG,MAAMA,EAAG,gBAAgB,EAC5BA,EAAG,WAAWA,EAAG,UAAW,EAAG,CAAC,EAGjC,EAAE,KAAK,KACR,CAEA,KAAKoC,EAAkD,CACtD,IAAMC,EAAQH,GAAiB,CAC9BA,GAAQ,IACR,KAAK,KAAKA,CAAI,EACVE,GAAUA,EAASF,EAAM,KAAK,KAAK,EACvC,KAAK,iBAAmB,sBAAsBG,CAAI,CACnD,EACA,KAAK,iBAAmB,sBAAsBA,CAAI,CACnD,CAEA,OAAQ,CACH,KAAK,mBACR,qBAAqB,KAAK,gBAAgB,EAC1C,KAAK,iBAAmB,KAE1B,CAEA,KAAKC,EAAkB,CACtB,KAAK,GAAG,MAAM,KAAK,GAAG,gBAAgB,EACtC,KAAK,GAAG,WAAW,KAAK,GAAG,UAAW,EAAG,CAAC,EAE1C,IAAMC,EAAQ,KAAK,OAAO,UAAU,EAChCD,GAAY,CAAC,GAAGA,CAAQ,GAAG,YAAY,EAAE,SAAS,MAAM,IAC3DA,EAAW,GAAGA,CAAQ,QAEvB,KAAK,aAAa,SAAWA,GAAY,aACzC,KAAK,aAAa,KAAOC,EACzB,KAAK,aAAa,MAAM,CACzB,CAEA,kBAAkBX,EAAcxB,EAA6C,CAC5E,GAAI,KAAK,SAAS,IAAIwB,CAAI,EACzB,MAAM,IAAI,MAAM,YAAYA,CAAI,2BAA2B,EAG5D,IAAMY,EAAU,KAAK,GAAG,cAAc,EACtC,GAAI,CAACA,EACJ,MAAM,IAAI,MAAM,0BAA0B,EAE3C,IAAMC,EAAY,KAAK,SAAS,KAAO,EACvC,KAAK,GAAG,cAAc,KAAK,GAAG,SAAWA,CAAS,EAClD,KAAK,GAAG,YAAY,KAAK,GAAG,WAAYD,CAAO,EAG/C,KAAK,GAAG,YAAY,KAAK,GAAG,oBAAqB,EAAI,EACrD,KAAK,GAAG,cAAc,KAAK,GAAG,WAAY,KAAK,GAAG,eAAgB,KAAK,GAAG,aAAa,EACvF,KAAK,GAAG,cAAc,KAAK,GAAG,WAAY,KAAK,GAAG,eAAgB,KAAK,GAAG,aAAa,EACvF,KAAK,GAAG,cAAc,KAAK,GAAG,WAAY,KAAK,GAAG,mBAAoB,KAAK,GAAG,MAAM,EACpF,KAAK,GAAG,cAAc,KAAK,GAAG,WAAY,KAAK,GAAG,mBAAoB,KAAK,GAAG,MAAM,EAEpF,KAAK,SAAS,IAAIZ,EAAM,CAAE,QAAAY,EAAS,UAAAC,CAAU,CAAC,EAC9C,KAAK,eAAe,CAAE,CAACb,CAAI,EAAGxB,CAAO,CAAC,EAEtC,IAAMsC,EAAW,KAAK,GAAG,mBAAmB,KAAK,QAAUd,CAAI,EAC3Dc,GACH,KAAK,GAAG,UAAUA,EAAUD,CAAS,CAEvC,CAEA,eAAeT,EAA8D,CAC5E,OAAO,QAAQA,CAAO,EAAE,QAAQ,CAAC,CAACJ,EAAMxB,CAAM,IAAM,CACnD,IAAMuC,EAAO,KAAK,SAAS,IAAIf,CAAI,EACnC,GAAI,CAACe,EACJ,MAAM,IAAI,MAAM,YAAYf,CAAI,uBAAuB,EAExD,KAAK,GAAG,cAAc,KAAK,GAAG,SAAWe,EAAK,SAAS,EACvD,KAAK,GAAG,YAAY,KAAK,GAAG,WAAYA,EAAK,OAAO,EACpD,KAAK,GAAG,WAAW,KAAK,GAAG,WAAY,EAAG,KAAK,GAAG,KAAM,KAAK,GAAG,KAAM,KAAK,GAAG,cAAevC,CAAM,CACpG,CAAC,CACF,CAEA,SAAU,CACL,KAAK,mBACR,qBAAqB,KAAK,gBAAgB,EAC1C,KAAK,iBAAmB,MAGzB,KAAK,eAAe,UAAU,KAAK,MAAM,EACzC,KAAK,eAAe,QAAQ,CAACuB,EAAUJ,IAAU,CAChD,KAAK,OAAO,oBAAoBA,EAAOI,CAAQ,CAChD,CAAC,EAEG,KAAK,SACR,KAAK,GAAG,cAAc,KAAK,OAAO,EAGnC,KAAK,SAAS,QAAQa,GAAW,CAChC,KAAK,GAAG,cAAcA,EAAQ,OAAO,CACtC,CAAC,EAEG,KAAK,iBACR,KAAK,GAAG,cAAc,KAAK,cAAc,EACzC,KAAK,eAAiB,MAGnB,KAAK,SACR,KAAK,GAAG,aAAa,KAAK,MAAM,EAChC,KAAK,OAAS,MAGX,KAAK,kBACR,KAAK,OAAO,OAAO,CAErB,CACD,EAEOnD,EAAQI","names":["index_exports","__export","index_default","__toCommonJS","DEFAULT_VERTEX_SHADER_SRC","RESIZE_THROTTLE_INTERVAL","ShaderPad","fragmentShaderSrc","options","vertexShaderSrc","vertexShader","fragmentShader","aPosition","gl","transparent","layer","type","source","shader","quadVertices","now","timeUntilNextResize","pixelRatio","width","height","computedStyle","hasExplicitWidth","hasExplicitHeight","updateCursor","x","y","rect","updateClick","isMouseDown","xVal","yVal","event","mouseEvent","wheelEvent","touchEvent","listener","name","value","location","length","updates","uniform","time","writeIdx","callback","loop","filename","image","texture","unitIndex","uSampler","info"]}
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":"yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,aAAAE,EAAA,YAAAC,EAAA,SAAAC,IAAA,eAAAC,EAAAL,GCEO,SAASM,EAAQC,EAAgB,EAAG,CAC1C,GAAIA,EAAQ,EACX,MAAM,IAAI,MAAM,sCAAsC,EAGvD,OAAO,SAAUC,EAAsBC,EAAwB,CAC9D,IAAIC,EAAsC,KACpC,CAAE,GAAAC,EAAI,SAAAC,CAAS,EAAIH,EAEzBD,EAAU,aAAa,OAAQK,CAAuB,EACtDL,EAAU,aAAa,OAAQ,CAACM,EAAeC,IAAkB,CAChE,IAAMC,EAAWD,EAAQR,EAEzBI,EAAG,cAAcA,EAAG,QAAQ,EAC5BA,EAAG,YAAYA,EAAG,iBAAkBD,CAAc,EAClDC,EAAG,kBACFA,EAAG,iBACH,EACA,EACA,EACAK,EACA,EACA,EACAL,EAAG,mBACHA,EAAG,mBACJ,CACD,CAAC,EACDH,EAAU,aAAa,mBAAoB,IAAM,CAChDG,EAAG,cAAcD,CAAc,EAC/BG,EAAwB,CACzB,CAAC,EACDL,EAAU,aAAa,QAASS,CAAY,EAC5CT,EAAU,aAAa,UAAW,IAAM,CACvCG,EAAG,cAAcD,CAAc,EAC/BA,EAAiB,IAClB,CAAC,EAED,SAASG,GAA0B,CAElC,GADAH,EAAiBC,EAAG,cAAc,EAC9B,CAACD,EACJ,MAAM,IAAI,MAAM,kCAAkC,EAEnDC,EAAG,YAAYA,EAAG,iBAAkBD,CAAc,EAClDC,EAAG,cAAcA,EAAG,iBAAkBA,EAAG,eAAgBA,EAAG,aAAa,EACzEA,EAAG,cAAcA,EAAG,iBAAkBA,EAAG,eAAgBA,EAAG,aAAa,EACzEA,EAAG,cAAcA,EAAG,iBAAkBA,EAAG,mBAAoBA,EAAG,OAAO,EACvEA,EAAG,cAAcA,EAAG,iBAAkBA,EAAG,mBAAoBA,EAAG,OAAO,EACvEA,EAAG,aAAaA,EAAG,iBAAkB,EAAGA,EAAG,MAAOA,EAAG,mBAAoBA,EAAG,oBAAqBJ,CAAK,EACtGI,EAAG,cAAcA,EAAG,QAAQ,EAC5BA,EAAG,YAAYA,EAAG,iBAAkBD,CAAc,EAElDO,EAAa,EAERL,EAAS,IAAI,WAAW,GAC5BJ,EAAU,kBAAkB,YAAa,MAAO,CAAC,CAEnD,CAEA,SAASS,GAAe,CACvBN,EAAG,cAAcA,EAAG,QAAQ,EAC5BA,EAAG,YAAYA,EAAG,iBAAkBD,CAAc,EAClD,IAAMQ,EAAc,IAAI,WAAWP,EAAG,mBAAqBA,EAAG,oBAAsB,CAAC,EACrF,QAASQ,EAAQ,EAAGA,EAAQZ,EAAO,EAAEY,EACpCR,EAAG,cACFA,EAAG,iBACH,EACA,EACA,EACAQ,EACAR,EAAG,mBACHA,EAAG,oBACH,EACAA,EAAG,KACHA,EAAG,cACHO,CACD,CAEF,CACD,CACD,CCzEO,SAASE,GAAO,CACtB,OAAO,SAAUC,EAAsBC,EAAwB,CAC9D,GAAM,CAAE,GAAAC,EAAI,OAAAC,CAAO,EAAIF,EACjBG,EAAe,SAAS,cAAc,GAAG,EAE9CJ,EAAkB,KAAO,eAAgBK,EAAkB,CAQ3D,GAPAH,EAAG,MAAMA,EAAG,gBAAgB,EAC5BA,EAAG,WAAWA,EAAG,UAAW,EAAG,CAAC,EAE5BG,GAAY,CAAC,GAAGA,CAAQ,GAAG,YAAY,EAAE,SAAS,MAAM,IAC3DA,EAAW,GAAGA,CAAQ,QAEvBA,EAAWA,GAAY,aACnB,oBAAqB,OAExB,GAAI,CACH,IAAMC,EAAa,MAAM,IAAI,QAAQC,GACpCJ,EAAO,OAAOI,EAAyB,WAAW,CACnD,EACMC,EAAO,IAAI,KAAK,CAACF,CAAI,EAAGD,EAAU,CAAE,KAAMC,EAAK,IAAK,CAAC,EAE3D,GAAI,UAAU,WAAW,CAAE,MAAO,CAACE,CAAI,CAAE,CAAC,EAAG,CAC5C,MAAM,UAAU,MAAM,CAAE,MAAO,CAACA,CAAI,CAAE,CAAC,EACvC,MACD,CACD,OAASC,EAAO,CACf,QAAQ,KAAK,wBAAyBA,CAAK,CAC5C,MAGAL,EAAa,SAAWC,EACxBD,EAAa,KAAOD,EAAO,UAAU,EACrCC,EAAa,MAAM,CAErB,CACD,CACD,CF5CA,IAAMM,EAA4B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQ5BC,EAA2B,IAAO,GA8BlCC,EAAN,KAAgB,CAyBf,YAAYC,EAA2BC,EAAmB,CAAC,EAAG,CAxB9D,KAAQ,iBAAmB,GAC3B,KAAQ,cAAgB,GAIxB,KAAQ,SAAiC,IAAI,IAC7C,KAAQ,SAAiC,IAAI,IAC7C,KAAQ,OAA6B,KACrC,KAAQ,QAA+B,KAIvC,KAAQ,cAAgC,KACxC,KAAQ,eAAiB,EACzB,KAAQ,eAA6C,IAAI,IACzD,KAAQ,MAAQ,EAChB,KAAQ,UAAY,EACpB,KAAQ,eAAiB,CAAC,GAAK,EAAG,EAClC,KAAQ,cAAgB,CAAC,GAAK,EAAG,EACjC,KAAQ,YAAc,GAGtB,KAAQ,MAA0C,IAAI,IAcrD,GAXA,KAAK,OAASA,EAAQ,QAAU,SAAS,cAAc,QAAQ,EAC1DA,EAAQ,SACZ,KAAK,iBAAmB,GACxB,SAAS,KAAK,YAAY,KAAK,MAAM,EACrC,KAAK,OAAO,MAAM,SAAW,QAC7B,KAAK,OAAO,MAAM,MAAQ,IAC1B,KAAK,OAAO,MAAM,OAAS,SAC3B,KAAK,OAAO,MAAM,MAAQ,UAG3B,KAAK,GAAK,KAAK,OAAO,WAAW,SAAU,CAAE,UAAW,EAAM,CAAC,EAC3D,CAAC,KAAK,GACT,MAAM,IAAI,MAAM,kEAAkE,EASnF,GANA,KAAK,aAAe,SAAS,cAAc,GAAG,EAC9C,KAAK,kBAAoBD,EACzB,KAAK,iBAAmB,KACxB,KAAK,mBAAqB,IAAI,iBAAiB,IAAM,KAAK,iBAAiB,CAAC,EAC5E,KAAK,eAAiB,IAAI,eAAe,IAAM,KAAK,sBAAsB,CAAC,EAEvEC,EAAQ,QAAS,CACpB,IAAMC,EAAyB,CAC9B,GAAI,KAAK,GACT,SAAU,KAAK,SACf,SAAU,KAAK,SACf,QAAS,KAAK,QACd,OAAQ,KAAK,MACd,EACAD,EAAQ,QAAQ,QAAQE,GAAUA,EAAO,KAAMD,CAAO,CAAC,CACxD,CACA,KAAK,KAAK,EACV,KAAK,kBAAkB,CACxB,CAEA,aAAaE,EAAuBC,EAAc,CAC5C,KAAK,MAAM,IAAID,CAAI,GACvB,KAAK,MAAM,IAAIA,EAAM,CAAC,CAAC,EAExB,KAAK,MAAM,IAAIA,CAAI,EAAG,KAAKC,CAAE,CAC9B,CAEQ,MAAO,CACd,IAAMC,EAAkBT,EAGxB,GADA,KAAK,QAAU,KAAK,GAAG,cAAc,EACjC,CAAC,KAAK,QACT,MAAM,IAAI,MAAM,gCAAgC,EAEjD,IAAMU,EAAe,KAAK,aAAa,KAAK,GAAG,cAAeD,CAAe,EACvEE,EAAiB,KAAK,aAAa,KAAK,GAAG,gBAAiB,KAAK,iBAAiB,EAQxF,GANA,KAAK,GAAG,aAAa,KAAK,QAASD,CAAY,EAC/C,KAAK,GAAG,aAAa,KAAK,QAASC,CAAc,EACjD,KAAK,GAAG,YAAY,KAAK,OAAO,EAChC,KAAK,GAAG,aAAaD,CAAY,EACjC,KAAK,GAAG,aAAaC,CAAc,EAE/B,CAAC,KAAK,GAAG,oBAAoB,KAAK,QAAS,KAAK,GAAG,WAAW,EACjE,cAAQ,MAAM,sBAAuB,KAAK,GAAG,kBAAkB,KAAK,OAAO,CAAC,EAC5E,KAAK,GAAG,cAAc,KAAK,OAAO,EAC5B,IAAI,MAAM,8BAA8B,EAG/C,IAAMC,EAAY,KAAK,GAAG,kBAAkB,KAAK,QAAS,WAAW,EACrE,KAAK,YAAYA,CAAS,EAE1B,KAAK,GAAG,WAAW,KAAK,OAAO,EAE/B,KAAK,mBAAmB,QAAQ,KAAK,OAAQ,CAAE,WAAY,GAAM,gBAAiB,CAAC,QAAS,QAAQ,CAAE,CAAC,EACvG,KAAK,eAAe,QAAQ,KAAK,MAAM,EAElC,KAAK,kBACT,KAAK,iBAAiB,EAEvB,KAAK,kBAAkB,WAAY,QAAS,KAAK,cAAc,EAC/D,KAAK,kBAAkB,UAAW,QAAS,CAAC,GAAG,KAAK,cAAe,KAAK,YAAc,EAAM,CAAG,CAAC,EAChG,KAAK,kBAAkB,SAAU,QAAS,CAAC,EAC3C,KAAK,kBAAkB,UAAW,MAAO,CAAC,EAE1C,KAAK,MAAM,IAAI,MAAM,GAAG,QAAQC,GAAQA,EAAK,KAAK,IAAI,CAAC,CACxD,CAEQ,aAAaC,EAAcC,EAA6B,CAC/D,IAAMC,EAAS,KAAK,GAAG,aAAaF,CAAI,EAGxC,GAFA,KAAK,GAAG,aAAaE,EAAQD,CAAM,EACnC,KAAK,GAAG,cAAcC,CAAM,EACxB,CAAC,KAAK,GAAG,mBAAmBA,EAAQ,KAAK,GAAG,cAAc,EAC7D,cAAQ,MAAM,6BAA8BD,CAAM,EAClD,QAAQ,MAAM,KAAK,GAAG,iBAAiBC,CAAM,CAAC,EAC9C,KAAK,GAAG,aAAaA,CAAM,EACrB,IAAI,MAAM,2BAA2B,EAE5C,OAAOA,CACR,CAEQ,YAAYJ,EAAmB,CACtC,IAAMK,EAAe,IAAI,aAAa,CAAC,GAAI,GAAI,EAAG,GAAI,GAAI,EAAG,GAAI,EAAG,EAAG,GAAI,EAAG,CAAC,CAAC,EAEhF,KAAK,OAAS,KAAK,GAAG,aAAa,EACnC,KAAK,GAAG,WAAW,KAAK,GAAG,aAAc,KAAK,MAAM,EACpD,KAAK,GAAG,WAAW,KAAK,GAAG,aAAcA,EAAc,KAAK,GAAG,WAAW,EAC1E,KAAK,GAAG,SAAS,EAAG,EAAG,KAAK,GAAG,mBAAoB,KAAK,GAAG,mBAAmB,EAC9E,KAAK,GAAG,wBAAwBL,CAAS,EACzC,KAAK,GAAG,oBAAoBA,EAAW,EAAG,KAAK,GAAG,MAAO,GAAO,EAAG,CAAC,CACrE,CAEQ,uBAAwB,CAC/B,aAAa,KAAK,aAAa,EAC/B,IAAMM,EAAM,YAAY,IAAI,EACtBC,EAAsB,KAAK,eAAiBlB,EAA2BiB,EACzEC,GAAuB,GAC1B,KAAK,eAAiBD,EACtB,KAAK,aAAa,GAElB,KAAK,cAAgB,WAAW,IAAM,KAAK,sBAAsB,EAAGC,CAAmB,CAEzF,CAEQ,cAAe,CACtB,IAAMC,EAAa,OAAO,kBAAoB,EACxCC,EAAQ,KAAK,OAAO,YAAcD,EAClCE,EAAS,KAAK,OAAO,aAAeF,EACtC,KAAK,mBAAqB,KAAK,OAAO,QAAUC,GAAS,KAAK,OAAO,SAAWC,KACnF,KAAK,OAAO,MAAQD,EACpB,KAAK,OAAO,OAASC,GAEtB,KAAK,WAAWD,EAAOC,CAAM,CAC9B,CAEQ,mBAAoB,CAC3B,IAAMC,EAAe,CAACC,EAAWC,IAAc,CAC9C,GAAI,CAAC,KAAK,SAAS,IAAI,UAAU,EAAG,OACpC,IAAMC,EAAO,KAAK,OAAO,sBAAsB,EAC/C,KAAK,eAAe,CAAC,GAAKF,EAAIE,EAAK,MAAQA,EAAK,MAChD,KAAK,eAAe,CAAC,EAAI,GAAKD,EAAIC,EAAK,KAAOA,EAAK,OACnD,KAAK,eAAe,CAAE,SAAU,KAAK,cAAe,CAAC,CACtD,EAEMC,EAAc,CAACC,EAAsBJ,EAAYC,IAAe,CACrE,GAAK,KAAK,SAAS,IAAI,SAAS,EAEhC,IADA,KAAK,YAAcG,EACfA,EAAa,CAChB,IAAMF,EAAO,KAAK,OAAO,sBAAsB,EACzCG,EAAOL,EACPM,EAAOL,EACb,KAAK,cAAc,CAAC,GAAKI,EAAOH,EAAK,MAAQA,EAAK,MAClD,KAAK,cAAc,CAAC,EAAI,GAAKI,EAAOJ,EAAK,KAAOA,EAAK,MACtD,CACA,KAAK,eAAe,CAAE,QAAS,CAAC,GAAG,KAAK,cAAe,KAAK,YAAc,EAAM,CAAG,CAAE,CAAC,EACvF,EAEA,KAAK,eAAe,IAAI,YAAaK,GAAS,CAC7C,IAAMC,EAAaD,EACd,KAAK,eACTR,EAAaS,EAAW,QAASA,EAAW,OAAO,CAErD,CAAC,EAED,KAAK,eAAe,IAAI,YAAaD,GAAS,CAC7C,IAAMC,EAAaD,EACd,KAAK,eACLC,EAAW,SAAW,IACzB,KAAK,YAAc,GACnBL,EAAY,GAAMK,EAAW,QAASA,EAAW,OAAO,EAG3D,CAAC,EAED,KAAK,eAAe,IAAI,UAAWD,GAAS,CAC3C,IAAMC,EAAaD,EACd,KAAK,eACLC,EAAW,SAAW,GACzBL,EAAY,EAAK,CAGpB,CAAC,EAED,KAAK,eAAe,IAAI,YAAaI,GAAS,CAC7C,IAAME,EAAaF,EACfE,EAAW,QAAQ,OAAS,GAC/BV,EAAaU,EAAW,QAAQ,CAAC,EAAE,QAASA,EAAW,QAAQ,CAAC,EAAE,OAAO,CAE3E,CAAC,EAED,KAAK,eAAe,IAAI,aAAcF,GAAS,CAC9C,IAAME,EAAaF,EACnB,KAAK,cAAgB,GACjBE,EAAW,QAAQ,OAAS,IAC/BV,EAAaU,EAAW,QAAQ,CAAC,EAAE,QAASA,EAAW,QAAQ,CAAC,EAAE,OAAO,EACzEN,EAAY,GAAMM,EAAW,QAAQ,CAAC,EAAE,QAASA,EAAW,QAAQ,CAAC,EAAE,OAAO,EAEhF,CAAC,EAED,KAAK,eAAe,IAAI,WAAYF,GAAS,CACzBA,EACJ,QAAQ,SAAW,GACjCJ,EAAY,EAAK,CAEnB,CAAC,EAED,KAAK,eAAe,QAAQ,CAACO,EAAUH,IAAU,CAChD,KAAK,OAAO,iBAAiBA,EAAOG,CAAQ,CAC7C,CAAC,CACF,CAEQ,kBAAmB,CAC1B,IAAMb,EAAQ,KAAK,GAAG,mBAChBC,EAAS,KAAK,GAAG,oBACvB,KAAK,GAAG,SAAS,EAAG,EAAGD,EAAOC,CAAM,EAChC,KAAK,SAAS,IAAI,cAAc,EACnC,KAAK,eAAe,CAAE,aAAc,CAACD,EAAOC,CAAM,CAAE,CAAC,EAErD,KAAK,kBAAkB,eAAgB,QAAS,CAACD,EAAOC,CAAM,CAAC,EAGhE,KAAK,MAAM,IAAI,kBAAkB,GAAG,QAAQT,GAAQA,EAAK,KAAK,IAAI,CAAC,CACpE,CAEA,kBAAkBN,EAAcO,EAAuBqB,EAA0B,CAChF,GAAI,KAAK,SAAS,IAAI5B,CAAI,EACzB,MAAM,IAAI,MAAM,YAAYA,CAAI,2BAA2B,EAG5D,GAAIO,IAAS,SAAWA,IAAS,MAChC,MAAM,IAAI,MAAM,yBAAyBA,CAAI,8BAA8B,EAG5E,IAAMsB,EAAW,KAAK,GAAG,mBAAmB,KAAK,QAAU7B,CAAI,EAC/D,GAAI,CAAC6B,EAAU,CACd,QAAQ,MAAM,WAAW7B,CAAI,yDAAyD,EACtF,MACD,CAKA,GAHK,MAAM,QAAQ4B,CAAK,IACvBA,EAAQ,CAACA,CAAK,GAEXA,EAAM,OAAS,GAAKA,EAAM,OAAS,EACtC,MAAM,IAAI,MAAM,iCAAiCA,EAAM,MAAM,sCAAsC,EAGpG,IAAME,EAASF,EAAM,OACrB,KAAK,SAAS,IAAI5B,EAAM,CAAE,KAAAO,EAAM,OAAAuB,EAAQ,SAAAD,CAAS,CAAC,EAClD,KAAK,eAAe,CAAE,CAAC7B,CAAI,EAAG4B,CAAM,CAAC,CACtC,CAEA,eAAeG,EAA4C,CAC1D,OAAO,QAAQA,CAAO,EAAE,QAAQ,CAAC,CAAC/B,EAAM4B,CAAK,IAAmC,CAC/E,GAAI,CAAC,KAAK,SAAS,IAAI5B,CAAI,EAC1B,MAAM,IAAI,MAAM,YAAYA,CAAI,uBAAuB,EAGxD,IAAMgC,EAAU,KAAK,SAAS,IAAIhC,CAAI,EAItC,GAHK,MAAM,QAAQ4B,CAAK,IACvBA,EAAQ,CAACA,CAAK,GAEXA,EAAM,SAAWI,EAAQ,OAC5B,MAAM,IAAI,MAAM,iCAAiCJ,EAAM,MAAM,cAAcI,EAAQ,MAAM,GAAG,EAE5F,KAAK,GAAW,UAAUA,EAAQ,MAAM,GAAGA,EAAQ,KAAK,OAAO,CAAC,CAAC,EAAE,EAAEA,EAAQ,SAAU,GAAGJ,CAAK,CACjG,CAAC,CACF,CAEA,KAAKK,EAAc,CAClB,IAAMC,EAAK,KAAK,GAEZ,KAAK,SAAS,IAAI,QAAQ,GAC7B,KAAK,eAAe,CAAE,OAAQD,CAAK,CAAC,EAEjC,KAAK,SAAS,IAAI,SAAS,GAC9B,KAAK,eAAe,CAAE,QAAS,KAAK,KAAM,CAAC,EAG5CC,EAAG,MAAMA,EAAG,gBAAgB,EAC5BA,EAAG,WAAWA,EAAG,UAAW,EAAG,CAAC,EAEhC,KAAK,MAAM,IAAI,MAAM,GAAG,QAAQ5B,GAAQA,EAAK,KAAK,KAAM2B,EAAM,KAAK,KAAK,CAAC,EAEzE,EAAE,KAAK,KACR,CAEA,KAAKE,EAAkD,CACtD,KAAK,MAAM,EACX,IAAMC,EAAQH,GAAiB,CAC9BA,GAAQA,EAAO,KAAK,WAAa,IACjC,KAAK,KAAKA,CAAI,EACd,KAAK,iBAAmB,sBAAsBG,CAAI,EAC9CD,GAAUA,EAASF,EAAM,KAAK,KAAK,CACxC,EACA,KAAK,iBAAmB,sBAAsBG,CAAI,CACnD,CAEA,OAAQ,CACH,KAAK,mBACR,qBAAqB,KAAK,gBAAgB,EAC1C,KAAK,iBAAmB,KAE1B,CAEA,OAAQ,CACP,KAAK,MAAQ,EACb,KAAK,UAAY,YAAY,IAAI,EACjC,KAAK,MAAM,IAAI,OAAO,GAAG,QAAQ9B,GAAQA,EAAK,KAAK,IAAI,CAAC,CACzD,CAEA,kBAAkBN,EAAcQ,EAA6C,CAC5E,GAAI,KAAK,SAAS,IAAIR,CAAI,EACzB,MAAM,IAAI,MAAM,YAAYA,CAAI,2BAA2B,EAG5D,IAAMqC,EAAU,KAAK,GAAG,cAAc,EACtC,GAAI,CAACA,EACJ,MAAM,IAAI,MAAM,0BAA0B,EAE3C,IAAMC,EAAY,KAAK,SAAS,KAAO,EACvC,KAAK,GAAG,cAAc,KAAK,GAAG,SAAWA,CAAS,EAClD,KAAK,GAAG,YAAY,KAAK,GAAG,WAAYD,CAAO,EAG/C,KAAK,GAAG,YAAY,KAAK,GAAG,oBAAqB,EAAI,EACrD,KAAK,GAAG,cAAc,KAAK,GAAG,WAAY,KAAK,GAAG,eAAgB,KAAK,GAAG,aAAa,EACvF,KAAK,GAAG,cAAc,KAAK,GAAG,WAAY,KAAK,GAAG,eAAgB,KAAK,GAAG,aAAa,EACvF,KAAK,GAAG,cAAc,KAAK,GAAG,WAAY,KAAK,GAAG,mBAAoB,KAAK,GAAG,MAAM,EACpF,KAAK,GAAG,cAAc,KAAK,GAAG,WAAY,KAAK,GAAG,mBAAoB,KAAK,GAAG,MAAM,EAEpF,KAAK,SAAS,IAAIrC,EAAM,CAAE,QAAAqC,EAAS,UAAAC,CAAU,CAAC,EAC9C,KAAK,eAAe,CAAE,CAACtC,CAAI,EAAGQ,CAAO,CAAC,EAEtC,IAAM+B,EAAW,KAAK,GAAG,mBAAmB,KAAK,QAAUvC,CAAI,EAC3DuC,GACH,KAAK,GAAG,UAAUA,EAAUD,CAAS,CAEvC,CAEA,eAAeP,EAA8D,CAC5E,OAAO,QAAQA,CAAO,EAAE,QAAQ,CAAC,CAAC/B,EAAMQ,CAAM,IAAM,CACnD,IAAMgC,EAAO,KAAK,SAAS,IAAIxC,CAAI,EACnC,GAAI,CAACwC,EACJ,MAAM,IAAI,MAAM,YAAYxC,CAAI,uBAAuB,EAExD,KAAK,GAAG,cAAc,KAAK,GAAG,SAAWwC,EAAK,SAAS,EACvD,KAAK,GAAG,YAAY,KAAK,GAAG,WAAYA,EAAK,OAAO,EACpD,KAAK,GAAG,WAAW,KAAK,GAAG,WAAY,EAAG,KAAK,GAAG,KAAM,KAAK,GAAG,KAAM,KAAK,GAAG,cAAehC,CAAM,CACpG,CAAC,CACF,CAEA,MAAM,KAAKiC,EAAkB,CAQ5B,GAPA,KAAK,GAAG,MAAM,KAAK,GAAG,gBAAgB,EACtC,KAAK,GAAG,WAAW,KAAK,GAAG,UAAW,EAAG,CAAC,EAEtCA,GAAY,CAAC,GAAGA,CAAQ,GAAG,YAAY,EAAE,SAAS,MAAM,IAC3DA,EAAW,GAAGA,CAAQ,QAEvBA,EAAWA,GAAY,aACnB,oBAAqB,OAExB,GAAI,CACH,IAAMC,EAAa,MAAM,IAAI,QAAQC,GACpC,KAAK,OAAO,OAAOA,EAAyB,WAAW,CACxD,EACMC,EAAO,IAAI,KAAK,CAACF,CAAI,EAAGD,EAAU,CAAE,KAAMC,EAAK,IAAK,CAAC,EAE3D,GAAI,UAAU,WAAW,CAAE,MAAO,CAACE,CAAI,CAAE,CAAC,EAAG,CAC5C,MAAM,UAAU,MAAM,CAAE,MAAO,CAACA,CAAI,CAAE,CAAC,EACvC,MACD,CACD,OAASC,EAAO,CACf,QAAQ,KAAK,wBAAyBA,CAAK,CAC5C,MAGA,KAAK,aAAa,SAAWJ,EAC7B,KAAK,aAAa,KAAO,KAAK,OAAO,UAAU,EAC/C,KAAK,aAAa,MAAM,CAE1B,CAEA,SAAU,CACL,KAAK,mBACR,qBAAqB,KAAK,gBAAgB,EAC1C,KAAK,iBAAmB,MAGzB,KAAK,mBAAmB,WAAW,EACnC,KAAK,eAAe,WAAW,EAC/B,KAAK,eAAe,QAAQ,CAACd,EAAUH,IAAU,CAChD,KAAK,OAAO,oBAAoBA,EAAOG,CAAQ,CAChD,CAAC,EAEG,KAAK,SACR,KAAK,GAAG,cAAc,KAAK,OAAO,EAGnC,KAAK,SAAS,QAAQU,GAAW,CAChC,KAAK,GAAG,cAAcA,EAAQ,OAAO,CACtC,CAAC,EAEG,KAAK,SACR,KAAK,GAAG,aAAa,KAAK,MAAM,EAChC,KAAK,OAAS,MAGf,KAAK,MAAM,IAAI,SAAS,GAAG,QAAQ/B,GAAQA,EAAK,KAAK,IAAI,CAAC,EAEtD,KAAK,kBACR,KAAK,OAAO,OAAO,CAErB,CACD,EAGOwC,EAAQnD","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"]}
package/dist/index.mjs CHANGED
@@ -1,9 +1,9 @@
1
- var l=`#version 300 es
1
+ function d(o=2){if(o<2)throw new Error("History depth must be greater than 1");return function(i,r){let e=null,{gl:t,uniforms:s}=r;i.registerHook("init",n),i.registerHook("step",(h,l)=>{let c=l%o;t.activeTexture(t.TEXTURE0),t.bindTexture(t.TEXTURE_2D_ARRAY,e),t.copyTexSubImage3D(t.TEXTURE_2D_ARRAY,0,0,0,c,0,0,t.drawingBufferWidth,t.drawingBufferHeight)}),i.registerHook("updateResolution",()=>{t.deleteTexture(e),n()}),i.registerHook("reset",a),i.registerHook("destroy",()=>{t.deleteTexture(e),e=null});function n(){if(e=t.createTexture(),!e)throw new Error("Failed to create history texture");t.bindTexture(t.TEXTURE_2D_ARRAY,e),t.texParameteri(t.TEXTURE_2D_ARRAY,t.TEXTURE_WRAP_S,t.CLAMP_TO_EDGE),t.texParameteri(t.TEXTURE_2D_ARRAY,t.TEXTURE_WRAP_T,t.CLAMP_TO_EDGE),t.texParameteri(t.TEXTURE_2D_ARRAY,t.TEXTURE_MIN_FILTER,t.NEAREST),t.texParameteri(t.TEXTURE_2D_ARRAY,t.TEXTURE_MAG_FILTER,t.NEAREST),t.texStorage3D(t.TEXTURE_2D_ARRAY,1,t.RGBA8,t.drawingBufferWidth,t.drawingBufferHeight,o),t.activeTexture(t.TEXTURE0),t.bindTexture(t.TEXTURE_2D_ARRAY,e),a(),s.has("u_history")||i.initializeUniform("u_history","int",0)}function a(){t.activeTexture(t.TEXTURE0),t.bindTexture(t.TEXTURE_2D_ARRAY,e);let h=new Uint8Array(t.drawingBufferWidth*t.drawingBufferHeight*4);for(let l=0;l<o;++l)t.texSubImage3D(t.TEXTURE_2D_ARRAY,0,0,0,l,t.drawingBufferWidth,t.drawingBufferHeight,1,t.RGBA,t.UNSIGNED_BYTE,h)}}}function E(){return function(o,i){let{gl:r,canvas:e}=i,t=document.createElement("a");o.save=async function(s){if(r.clear(r.COLOR_BUFFER_BIT),r.drawArrays(r.TRIANGLES,0,6),s&&!`${s}`.toLowerCase().endsWith(".png")&&(s=`${s}.png`),s=s||"export.png","ongesturechange"in window)try{let n=await new Promise(h=>e.toBlob(h,"image/png")),a=new File([n],s,{type:n.type});if(navigator.canShare?.({files:[a]})){await navigator.share({files:[a]});return}}catch(n){console.warn("Web Share API failed:",n)}else t.download=s,t.href=e.toDataURL(),t.click()}}}var g=`#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
- `,c=33.333333333333336,h=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.cursorPosition=[.5,.5];this.scrollX=0;this.scrollY=0;this.clickPosition=[.5,.5];this.isMouseDown=!1;this.historyTexture=null;if(this.canvas=i.canvas||document.createElement("canvas"),this.historyLength=i.history||0,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.");this.downloadLink=document.createElement("a"),this.fragmentShaderSrc=t,this.animationFrameId=null,this.resizeObserver=new ResizeObserver(()=>this.throttledHandleResize()),this.resizeObserver.observe(this.canvas),this.init(),this.addEventListeners()}init(){let t=l;if(this.program=this.gl.createProgram(),!this.program)throw new Error("Failed to create WebGL program");let 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 s=this.gl.getAttribLocation(this.program,"aPosition");this.setupBuffer(s),this.handleResize(),this.gl.useProgram(this.program),this.initializeUniform("u_resolution","float",[this.canvas.width,this.canvas.height]),this.initializeUniform("u_cursor","float",[...this.cursorPosition,this.scrollX,this.scrollY]),this.initializeUniform("u_click","float",[...this.clickPosition,this.isMouseDown?1:0]),this.initializeUniform("u_time","float",0),this.initializeUniform("u_frame","int",0),this.historyLength>0&&this.initializeHistoryBuffer()}initializeHistoryBuffer(){let{gl:t}=this;if(this.historyTexture=t.createTexture(),!this.historyTexture)throw new Error("Failed to create history texture");t.bindTexture(t.TEXTURE_2D_ARRAY,this.historyTexture),t.texParameteri(t.TEXTURE_2D_ARRAY,t.TEXTURE_WRAP_S,t.CLAMP_TO_EDGE),t.texParameteri(t.TEXTURE_2D_ARRAY,t.TEXTURE_WRAP_T,t.CLAMP_TO_EDGE),t.texParameteri(t.TEXTURE_2D_ARRAY,t.TEXTURE_MIN_FILTER,t.NEAREST),t.texParameteri(t.TEXTURE_2D_ARRAY,t.TEXTURE_MAG_FILTER,t.NEAREST),t.texStorage3D(t.TEXTURE_2D_ARRAY,1,t.RGBA8,this.canvas.width,this.canvas.height,this.historyLength);let i=new Uint8Array(this.canvas.width*this.canvas.height*4);for(let e=0;e<this.historyLength;++e)t.texSubImage3D(t.TEXTURE_2D_ARRAY,0,0,0,e,this.canvas.width,this.canvas.height,1,t.RGBA,t.UNSIGNED_BYTE,i);t.activeTexture(t.TEXTURE0),t.bindTexture(t.TEXTURE_2D_ARRAY,this.historyTexture),this.uniforms.has("u_history")||this.initializeUniform("u_history","int",0)}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.canvas.width,this.canvas.height),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+c-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,s=getComputedStyle(this.canvas),r=s.width!==`${this.canvas.width}px`&&s.width!=="auto",n=s.height!==`${this.canvas.height}px`&&s.height!=="auto";(!r||!n)&&(this.canvas.style.width=`${this.canvas.clientWidth}px`,this.canvas.style.height=`${this.canvas.clientHeight}px`),(this.canvas.width!==i||this.canvas.height!==e)&&(this.canvas.width=i,this.canvas.height=e,this.gl.viewport(0,0,this.gl.drawingBufferWidth,this.gl.drawingBufferHeight),this.uniforms.has("u_resolution")&&this.updateUniforms({u_resolution:[this.canvas.width,this.canvas.height]}),this.historyLength>0&&this.historyTexture&&(this.gl.deleteTexture(this.historyTexture),this.initializeHistoryBuffer()))}addEventListeners(){let t=(e,s)=>{if(!this.uniforms.has("u_cursor"))return;let r=this.canvas.getBoundingClientRect();this.cursorPosition[0]=(e-r.left)/r.width,this.cursorPosition[1]=1-(s-r.top)/r.height,this.updateUniforms({u_cursor:[this.cursorPosition[0],this.cursorPosition[1],this.scrollX,this.scrollY]})},i=(e,s,r)=>{if(this.uniforms.has("u_click")){if(this.isMouseDown=e,e){let n=this.canvas.getBoundingClientRect(),a=s,o=r;this.clickPosition[0]=(a-n.left)/n.width,this.clickPosition[1]=1-(o-n.top)/n.height}this.updateUniforms({u_click:[this.clickPosition[0],this.clickPosition[1],this.isMouseDown?1:0]})}};this.eventListeners.set("mousemove",e=>{let s=e;this.isTouchDevice||t(s.clientX,s.clientY)}),this.eventListeners.set("mousedown",e=>{let s=e;this.isTouchDevice||s.button===0&&(this.isMouseDown=!0,i(!0,s.clientX,s.clientY))}),this.eventListeners.set("mouseup",e=>{let s=e;this.isTouchDevice||s.button===0&&i(!1)}),this.eventListeners.set("wheel",e=>{let s=e;this.scrollX+=s.deltaX*.01,this.scrollY+=s.deltaY*.01,t(s.clientX,s.clientY)}),this.eventListeners.set("touchmove",e=>{let s=e;s.touches.length>0&&t(s.touches[0].clientX,s.touches[0].clientY)}),this.eventListeners.set("touchstart",e=>{let s=e;this.isTouchDevice=!0,s.touches.length>0&&(i(!0,s.touches[0].clientX,s.touches[0].clientY),t(s.touches[0].clientX,s.touches[0].clientY))}),this.eventListeners.set("touchend",e=>{e.touches.length===0&&i(!1)}),this.eventListeners.forEach((e,s)=>{this.canvas.addEventListener(s,e)})}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 s=this.gl.getUniformLocation(this.program,t);if(!s){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 r=e.length;this.uniforms.set(t,{type:i,length:r,location:s}),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 s=this.uniforms.get(i);if(Array.isArray(e)||(e=[e]),e.length!==s.length)throw new Error(`Invalid uniform value length: ${e.length}. Expected ${s.length}.`);this.gl[`uniform${s.length}${s.type.charAt(0)}`](s.location,...e)})}step(t){let i=this.gl;if(this.uniforms.has("u_time")&&this.updateUniforms({u_time:t}),this.uniforms.has("u_frame")&&this.updateUniforms({u_frame:this.frame}),this.historyLength>0){let e=this.frame%this.historyLength;i.bindFramebuffer(i.FRAMEBUFFER,null),i.viewport(0,0,this.canvas.width,this.canvas.height),i.clear(i.COLOR_BUFFER_BIT),i.drawArrays(i.TRIANGLES,0,6),i.activeTexture(i.TEXTURE0),i.bindTexture(i.TEXTURE_2D_ARRAY,this.historyTexture),i.copyTexSubImage3D(i.TEXTURE_2D_ARRAY,0,0,0,e,0,0,this.canvas.width,this.canvas.height)}else i.clear(i.COLOR_BUFFER_BIT),i.drawArrays(i.TRIANGLES,0,6);++this.frame}play(t){let i=e=>{e/=1e3,this.step(e),t&&t(e,this.frame),this.animationFrameId=requestAnimationFrame(i)};this.animationFrameId=requestAnimationFrame(i)}pause(){this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null)}save(t){this.gl.clear(this.gl.COLOR_BUFFER_BIT),this.gl.drawArrays(this.gl.TRIANGLES,0,6);let i=this.canvas.toDataURL();t&&!`${t}`.toLowerCase().endsWith(".png")&&(t=`${t}.png`),this.downloadLink.download=t||"export.png",this.downloadLink.href=i,this.downloadLink.click()}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 s=this.textures.size+1;this.gl.activeTexture(this.gl.TEXTURE0+s),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:s}),this.updateTextures({[t]:i});let r=this.gl.getUniformLocation(this.program,t);r&&this.gl.uniform1i(r,s)}updateTextures(t){Object.entries(t).forEach(([i,e])=>{let s=this.textures.get(i);if(!s)throw new Error(`Texture '${i}' is not initialized.`);this.gl.activeTexture(this.gl.TEXTURE0+s.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D,s.texture),this.gl.texImage2D(this.gl.TEXTURE_2D,0,this.gl.RGBA,this.gl.RGBA,this.gl.UNSIGNED_BYTE,e)})}destroy(){this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null),this.resizeObserver.unobserve(this.canvas),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.historyTexture&&(this.gl.deleteTexture(this.historyTexture),this.historyTexture=null),this.buffer&&(this.gl.deleteBuffer(this.buffer),this.buffer=null),this.isInternalCanvas&&this.canvas.remove()}},g=h;export{g as default};
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};
9
9
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["const DEFAULT_VERTEX_SHADER_SRC = `#version 300 es\nin vec2 aPosition;\nout vec2 v_uv;\nvoid main() {\n v_uv = aPosition * 0.5 + 0.5;\n gl_Position = vec4(aPosition, 0.0, 1.0);\n}\n`;\nconst RESIZE_THROTTLE_INTERVAL = 1000 / 30;\n\ninterface Uniform {\n\ttype: 'float' | 'int';\n\tlength: 1 | 2 | 3 | 4;\n\tlocation: WebGLUniformLocation;\n}\n\ninterface Texture {\n\ttexture: WebGLTexture;\n\tunitIndex: number;\n}\n\ninterface Options {\n\tcanvas?: HTMLCanvasElement | null;\n\thistory?: number;\n}\n\nclass ShaderPad {\n\tprivate isInternalCanvas = false;\n\tprivate isTouchDevice = false;\n\tprivate canvas: HTMLCanvasElement;\n\tprivate gl: WebGL2RenderingContext;\n\tprivate downloadLink: HTMLAnchorElement;\n\tprivate fragmentShaderSrc: string;\n\tprivate uniforms: Map<string, Uniform> = new Map();\n\tprivate textures: Map<string, Texture> = new Map();\n\tprivate buffer: WebGLBuffer | null = null;\n\tprivate program: WebGLProgram | null = null;\n\tprivate animationFrameId: number | null;\n\tprivate 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 cursorPosition = [0.5, 0.5];\n\tprivate scrollX = 0;\n\tprivate scrollY = 0;\n\tprivate clickPosition = [0.5, 0.5];\n\tprivate isMouseDown = false;\n\tprivate historyLength: number;\n\tprivate historyTexture: WebGLTexture | null = null;\n\n\tconstructor(fragmentShaderSrc: string, options: Options = {}) {\n\t\tthis.canvas = options.canvas || document.createElement('canvas');\n\t\tthis.historyLength = options.history || 0;\n\t\tif (!options.canvas) {\n\t\t\tthis.isInternalCanvas = true;\n\t\t\tdocument.body.appendChild(this.canvas);\n\t\t\tthis.canvas.style.position = 'fixed';\n\t\t\tthis.canvas.style.inset = '0';\n\t\t\tthis.canvas.style.height = '100dvh';\n\t\t\tthis.canvas.style.width = '100dvw';\n\t\t}\n\n\t\tthis.gl = this.canvas.getContext('webgl2', { antialias: false }) as WebGL2RenderingContext;\n\t\tif (!this.gl) {\n\t\t\tthrow new Error('WebGL2 not supported. Please use a browser that supports WebGL2.');\n\t\t}\n\n\t\tthis.downloadLink = document.createElement('a');\n\t\tthis.fragmentShaderSrc = fragmentShaderSrc;\n\t\tthis.animationFrameId = null;\n\t\tthis.resizeObserver = new ResizeObserver(() => this.throttledHandleResize());\n\t\tthis.resizeObserver.observe(this.canvas);\n\t\tthis.init();\n\t\tthis.addEventListeners();\n\t}\n\n\tprivate init() {\n\t\tconst vertexShaderSrc = 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\t\tthis.handleResize();\n\n\t\tthis.gl.useProgram(this.program);\n\n\t\tthis.initializeUniform('u_resolution', 'float', [this.canvas.width, this.canvas.height]);\n\t\tthis.initializeUniform('u_cursor', 'float', [...this.cursorPosition, this.scrollX, this.scrollY]); // [cursorX, cursorY, scrollX, scrollY]\n\t\tthis.initializeUniform('u_click', 'float', [...this.clickPosition, this.isMouseDown ? 1.0 : 0.0]); // [clickX, clickY, leftClick]\n\t\tthis.initializeUniform('u_time', 'float', 0);\n\t\tthis.initializeUniform('u_frame', 'int', 0);\n\n\t\tif (this.historyLength > 0) {\n\t\t\tthis.initializeHistoryBuffer();\n\t\t}\n\t}\n\n\tprivate initializeHistoryBuffer() {\n\t\tconst { gl } = this;\n\n\t\tthis.historyTexture = gl.createTexture();\n\t\tif (!this.historyTexture) {\n\t\t\tthrow new Error('Failed to create history texture');\n\t\t}\n\n\t\tgl.bindTexture(gl.TEXTURE_2D_ARRAY, this.historyTexture);\n\t\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n\t\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n\t\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_MIN_FILTER, gl.NEAREST);\n\t\tgl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_MAG_FILTER, gl.NEAREST);\n\t\tgl.texStorage3D(gl.TEXTURE_2D_ARRAY, 1, gl.RGBA8, this.canvas.width, this.canvas.height, this.historyLength);\n\n\t\t// Make initial frames transparent.\n\t\tconst transparent = new Uint8Array(this.canvas.width * this.canvas.height * 4); // All zeroes.\n\t\tfor (let layer = 0; layer < this.historyLength; ++layer) {\n\t\t\tgl.texSubImage3D(\n\t\t\t\tgl.TEXTURE_2D_ARRAY,\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t\tlayer,\n\t\t\t\tthis.canvas.width,\n\t\t\t\tthis.canvas.height,\n\t\t\t\t1,\n\t\t\t\tgl.RGBA,\n\t\t\t\tgl.UNSIGNED_BYTE,\n\t\t\t\ttransparent\n\t\t\t);\n\t\t}\n\n\t\tgl.activeTexture(gl.TEXTURE0);\n\t\tgl.bindTexture(gl.TEXTURE_2D_ARRAY, this.historyTexture);\n\n\t\tif (!this.uniforms.has('u_history')) {\n\t\t\tthis.initializeUniform('u_history', 'int', 0);\n\t\t}\n\t}\n\n\tprivate createShader(type: number, source: string): WebGLShader {\n\t\tconst shader = this.gl.createShader(type)!;\n\t\tthis.gl.shaderSource(shader, source);\n\t\tthis.gl.compileShader(shader);\n\t\tif (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)) {\n\t\t\tconsole.error('Shader compilation failed:', source);\n\t\t\tconsole.error(this.gl.getShaderInfoLog(shader));\n\t\t\tthis.gl.deleteShader(shader);\n\t\t\tthrow new Error('Shader compilation failed');\n\t\t}\n\t\treturn shader;\n\t}\n\n\tprivate setupBuffer(aPosition: number) {\n\t\tconst quadVertices = new Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1]);\n\n\t\tthis.buffer = this.gl.createBuffer();\n\t\tthis.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.buffer);\n\t\tthis.gl.bufferData(this.gl.ARRAY_BUFFER, quadVertices, this.gl.STATIC_DRAW);\n\t\tthis.gl.viewport(0, 0, this.canvas.width, this.canvas.height);\n\t\tthis.gl.enableVertexAttribArray(aPosition);\n\t\tthis.gl.vertexAttribPointer(aPosition, 2, this.gl.FLOAT, false, 0, 0);\n\t}\n\n\tprivate 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\t// TODO: This breaks for `position: fixed; inset: 0` canvases.\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\n\t\tconst computedStyle = getComputedStyle(this.canvas);\n\t\tconst hasExplicitWidth = computedStyle.width !== `${this.canvas.width}px` && computedStyle.width !== 'auto';\n\t\tconst hasExplicitHeight = computedStyle.height !== `${this.canvas.height}px` && computedStyle.height !== 'auto';\n\t\tif (!hasExplicitWidth || !hasExplicitHeight) {\n\t\t\tthis.canvas.style.width = `${this.canvas.clientWidth}px`;\n\t\t\tthis.canvas.style.height = `${this.canvas.clientHeight}px`;\n\t\t}\n\n\t\tif (this.canvas.width !== width || this.canvas.height !== height) {\n\t\t\tthis.canvas.width = width;\n\t\t\tthis.canvas.height = height;\n\t\t\tthis.gl.viewport(0, 0, this.gl.drawingBufferWidth, this.gl.drawingBufferHeight);\n\t\t\tif (this.uniforms.has('u_resolution')) {\n\t\t\t\tthis.updateUniforms({ u_resolution: [this.canvas.width, this.canvas.height] });\n\t\t\t}\n\n\t\t\t// Delete and recreate history buffer, since the canvas size won’t be correct anymore.\n\t\t\tif (this.historyLength > 0 && this.historyTexture) {\n\t\t\t\tthis.gl.deleteTexture(this.historyTexture);\n\t\t\t\tthis.initializeHistoryBuffer();\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate addEventListeners() {\n\t\tconst updateCursor = (x: number, y: number) => {\n\t\t\tif (!this.uniforms.has('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({\n\t\t\t\tu_cursor: [this.cursorPosition[0], this.cursorPosition[1], this.scrollX, this.scrollY],\n\t\t\t});\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({\n\t\t\t\tu_click: [this.clickPosition[0], this.clickPosition[1], this.isMouseDown ? 1.0 : 0.0],\n\t\t\t});\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('wheel', event => {\n\t\t\tconst wheelEvent = event as WheelEvent;\n\t\t\tthis.scrollX += wheelEvent.deltaX * 0.01;\n\t\t\tthis.scrollY += wheelEvent.deltaY * 0.01;\n\t\t\tupdateCursor(wheelEvent.clientX, wheelEvent.clientY);\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\tupdateClick(true, touchEvent.touches[0].clientX, touchEvent.touches[0].clientY);\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('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\tinitializeUniform(name: string, type: 'float' | 'int', value: number | number[]) {\n\t\tif (this.uniforms.has(name)) {\n\t\t\tthrow new Error(`Uniform '${name}' is already initialized.`);\n\t\t}\n\n\t\tif (type !== 'float' && type !== 'int') {\n\t\t\tthrow new Error(`Invalid uniform type: ${type}. Expected 'float' or 'int'.`);\n\t\t}\n\n\t\tconst location = this.gl.getUniformLocation(this.program!, name);\n\t\tif (!location) {\n\t\t\tconsole.debug(`Uniform ${name} not found in fragment shader. Skipping initialization.`);\n\t\t\treturn;\n\t\t}\n\n\t\tif (!Array.isArray(value)) {\n\t\t\tvalue = [value];\n\t\t}\n\t\tif (value.length < 1 || value.length > 4) {\n\t\t\tthrow new Error(`Invalid uniform value length: ${value.length}. Expected a length between 1 and 4.`);\n\t\t}\n\n\t\tconst length = value.length as 1 | 2 | 3 | 4;\n\t\tthis.uniforms.set(name, { type, length, location });\n\t\tthis.updateUniforms({ [name]: value });\n\t}\n\n\tupdateUniforms(updates: Record<string, number | number[]>) {\n\t\tObject.entries(updates).forEach(([name, value]: [string, number | number[]]) => {\n\t\t\tif (!this.uniforms.has(name)) {\n\t\t\t\tthrow new Error(`Uniform '${name}' is not initialized.`);\n\t\t\t}\n\n\t\t\tconst uniform = this.uniforms.get(name)!;\n\t\t\tif (!Array.isArray(value)) {\n\t\t\t\tvalue = [value];\n\t\t\t}\n\t\t\tif (value.length !== uniform.length) {\n\t\t\t\tthrow new Error(`Invalid uniform value length: ${value.length}. Expected ${uniform.length}.`);\n\t\t\t}\n\t\t\t(this.gl as any)[`uniform${uniform.length}${uniform.type.charAt(0)}`](uniform.location, ...value);\n\t\t});\n\t}\n\n\tstep(time: number) {\n\t\tconst gl = this.gl;\n\n\t\tif (this.uniforms.has('u_time')) {\n\t\t\tthis.updateUniforms({ u_time: time });\n\t\t}\n\t\tif (this.uniforms.has('u_frame')) {\n\t\t\tthis.updateUniforms({ u_frame: this.frame });\n\t\t}\n\n\t\tif (this.historyLength > 0) {\n\t\t\tconst writeIdx = this.frame % this.historyLength;\n\n\t\t\tgl.bindFramebuffer(gl.FRAMEBUFFER, null);\n\t\t\tgl.viewport(0, 0, this.canvas.width, this.canvas.height);\n\t\t\tgl.clear(gl.COLOR_BUFFER_BIT);\n\t\t\tgl.drawArrays(gl.TRIANGLES, 0, 6);\n\n\t\t\tgl.activeTexture(gl.TEXTURE0);\n\t\t\tgl.bindTexture(gl.TEXTURE_2D_ARRAY, this.historyTexture);\n\t\t\tgl.copyTexSubImage3D(gl.TEXTURE_2D_ARRAY, 0, 0, 0, writeIdx, 0, 0, this.canvas.width, this.canvas.height);\n\t\t} else {\n\t\t\tgl.clear(gl.COLOR_BUFFER_BIT);\n\t\t\tgl.drawArrays(gl.TRIANGLES, 0, 6);\n\t\t}\n\n\t\t++this.frame;\n\t}\n\n\tplay(callback?: (time: number, frame: number) => void) {\n\t\tconst loop = (time: number) => {\n\t\t\ttime /= 1000; // Convert from milliseconds to seconds.\n\t\t\tthis.step(time);\n\t\t\tif (callback) callback(time, this.frame);\n\t\t\tthis.animationFrameId = requestAnimationFrame(loop);\n\t\t};\n\t\tthis.animationFrameId = requestAnimationFrame(loop);\n\t}\n\n\tpause() {\n\t\tif (this.animationFrameId) {\n\t\t\tcancelAnimationFrame(this.animationFrameId);\n\t\t\tthis.animationFrameId = null;\n\t\t}\n\t}\n\n\tsave(filename: string) {\n\t\tthis.gl.clear(this.gl.COLOR_BUFFER_BIT);\n\t\tthis.gl.drawArrays(this.gl.TRIANGLES, 0, 6);\n\n\t\tconst image = this.canvas.toDataURL();\n\t\tif (filename && !`${filename}`.toLowerCase().endsWith('.png')) {\n\t\t\tfilename = `${filename}.png`;\n\t\t}\n\t\tthis.downloadLink.download = filename || 'export.png';\n\t\tthis.downloadLink.href = image;\n\t\tthis.downloadLink.click();\n\t}\n\n\tinitializeTexture(name: string, source: HTMLImageElement | HTMLVideoElement) {\n\t\tif (this.textures.has(name)) {\n\t\t\tthrow new Error(`Texture '${name}' is already initialized.`);\n\t\t}\n\n\t\tconst texture = this.gl.createTexture();\n\t\tif (!texture) {\n\t\t\tthrow new Error('Failed to create texture');\n\t\t}\n\t\tconst unitIndex = this.textures.size + 1; // Start from unit 1 to avoid conflict with history texture at unit 0.\n\t\tthis.gl.activeTexture(this.gl.TEXTURE0 + unitIndex);\n\t\tthis.gl.bindTexture(this.gl.TEXTURE_2D, texture);\n\n\t\t// Flip the texture vertically since v_uv is flipped, and set up filters and wrapping.\n\t\tthis.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, true);\n\t\tthis.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);\n\t\tthis.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);\n\t\tthis.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR);\n\t\tthis.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.LINEAR);\n\n\t\tthis.textures.set(name, { texture, unitIndex });\n\t\tthis.updateTextures({ [name]: source });\n\n\t\tconst uSampler = this.gl.getUniformLocation(this.program!, name);\n\t\tif (uSampler) {\n\t\t\tthis.gl.uniform1i(uSampler, unitIndex);\n\t\t}\n\t}\n\n\tupdateTextures(updates: Record<string, HTMLImageElement | HTMLVideoElement>) {\n\t\tObject.entries(updates).forEach(([name, source]) => {\n\t\t\tconst info = this.textures.get(name);\n\t\t\tif (!info) {\n\t\t\t\tthrow new Error(`Texture '${name}' is not initialized.`);\n\t\t\t}\n\t\t\tthis.gl.activeTexture(this.gl.TEXTURE0 + info.unitIndex);\n\t\t\tthis.gl.bindTexture(this.gl.TEXTURE_2D, info.texture);\n\t\t\tthis.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, this.gl.RGBA, this.gl.UNSIGNED_BYTE, source);\n\t\t});\n\t}\n\n\tdestroy() {\n\t\tif (this.animationFrameId) {\n\t\t\tcancelAnimationFrame(this.animationFrameId);\n\t\t\tthis.animationFrameId = null;\n\t\t}\n\n\t\tthis.resizeObserver.unobserve(this.canvas);\n\t\tthis.eventListeners.forEach((listener, event) => {\n\t\t\tthis.canvas.removeEventListener(event, listener);\n\t\t});\n\n\t\tif (this.program) {\n\t\t\tthis.gl.deleteProgram(this.program);\n\t\t}\n\n\t\tthis.textures.forEach(texture => {\n\t\t\tthis.gl.deleteTexture(texture.texture);\n\t\t});\n\n\t\tif (this.historyTexture) {\n\t\t\tthis.gl.deleteTexture(this.historyTexture);\n\t\t\tthis.historyTexture = null;\n\t\t}\n\n\t\tif (this.buffer) {\n\t\t\tthis.gl.deleteBuffer(this.buffer);\n\t\t\tthis.buffer = null;\n\t\t}\n\n\t\tif (this.isInternalCanvas) {\n\t\t\tthis.canvas.remove();\n\t\t}\n\t}\n}\n\nexport default ShaderPad;\n"],"mappings":"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","names":["DEFAULT_VERTEX_SHADER_SRC","RESIZE_THROTTLE_INTERVAL","ShaderPad","fragmentShaderSrc","options","vertexShaderSrc","vertexShader","fragmentShader","aPosition","gl","transparent","layer","type","source","shader","quadVertices","now","timeUntilNextResize","pixelRatio","width","height","computedStyle","hasExplicitWidth","hasExplicitHeight","updateCursor","x","y","rect","updateClick","isMouseDown","xVal","yVal","event","mouseEvent","wheelEvent","touchEvent","listener","name","value","location","length","updates","uniform","time","writeIdx","callback","loop","filename","image","texture","unitIndex","uSampler","info","index_default"]}
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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shaderpad",
3
- "version": "1.0.0-alpha.9",
3
+ "version": "1.0.0-beta.17",
4
4
  "description": "A lightweight, dependency-free library to reduce boilerplate when writing fragment shaders.",
5
5
  "keywords": [
6
6
  "shaders",