shaderpad 1.0.0-beta.41 → 1.0.0-beta.42

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.
Files changed (52) hide show
  1. package/README.md +116 -56
  2. package/dist/chunk-5CBGNOA3.mjs +10 -0
  3. package/dist/chunk-5CBGNOA3.mjs.map +1 -0
  4. package/dist/chunk-JRSBIGBN.mjs +7 -0
  5. package/dist/chunk-JRSBIGBN.mjs.map +1 -0
  6. package/dist/index.d.mts +2 -1
  7. package/dist/index.d.ts +2 -1
  8. package/dist/index.js +4 -4
  9. package/dist/index.js.map +1 -1
  10. package/dist/index.mjs +1 -1
  11. package/dist/plugins/face.d.mts +1 -0
  12. package/dist/plugins/face.d.ts +1 -0
  13. package/dist/plugins/face.js +53 -76
  14. package/dist/plugins/face.js.map +1 -1
  15. package/dist/plugins/face.mjs +51 -79
  16. package/dist/plugins/face.mjs.map +1 -1
  17. package/dist/plugins/hands.d.mts +1 -0
  18. package/dist/plugins/hands.d.ts +1 -0
  19. package/dist/plugins/hands.js +20 -16
  20. package/dist/plugins/hands.js.map +1 -1
  21. package/dist/plugins/hands.mjs +15 -16
  22. package/dist/plugins/hands.mjs.map +1 -1
  23. package/dist/plugins/helpers.js +1 -1
  24. package/dist/plugins/helpers.js.map +1 -1
  25. package/dist/plugins/helpers.mjs +1 -1
  26. package/dist/plugins/helpers.mjs.map +1 -1
  27. package/dist/plugins/mediapipe-common.d.mts +18 -0
  28. package/dist/plugins/mediapipe-common.d.ts +18 -0
  29. package/dist/plugins/mediapipe-common.js +7 -0
  30. package/dist/plugins/mediapipe-common.js.map +1 -0
  31. package/dist/plugins/mediapipe-common.mjs +2 -0
  32. package/dist/plugins/mediapipe-common.mjs.map +1 -0
  33. package/dist/plugins/pose.d.mts +1 -0
  34. package/dist/plugins/pose.d.ts +1 -0
  35. package/dist/plugins/pose.js +54 -49
  36. package/dist/plugins/pose.js.map +1 -1
  37. package/dist/plugins/pose.mjs +46 -46
  38. package/dist/plugins/pose.mjs.map +1 -1
  39. package/dist/plugins/save.d.mts +1 -1
  40. package/dist/plugins/save.d.ts +1 -1
  41. package/dist/plugins/save.js +1 -1
  42. package/dist/plugins/save.js.map +1 -1
  43. package/dist/plugins/save.mjs.map +1 -1
  44. package/dist/plugins/segmenter.d.mts +1 -0
  45. package/dist/plugins/segmenter.d.ts +1 -0
  46. package/dist/plugins/segmenter.js +16 -11
  47. package/dist/plugins/segmenter.js.map +1 -1
  48. package/dist/plugins/segmenter.mjs +10 -10
  49. package/dist/plugins/segmenter.mjs.map +1 -1
  50. package/package.json +1 -1
  51. package/dist/chunk-A3XQBYSC.mjs +0 -10
  52. package/dist/chunk-A3XQBYSC.mjs.map +0 -1
package/README.md CHANGED
@@ -280,7 +280,54 @@ shader.destroy(); // Clean up resources.
280
280
  ### Properties
281
281
 
282
282
  - `canvas` (HTMLCanvasElement): The canvas element used for rendering
283
- - `onResize?: (width: number, height: number) => void`: Callback fired when the canvas is resized
283
+
284
+ ### Event Listeners
285
+
286
+ #### `on(event, callback)`
287
+
288
+ Register a callback for a lifecycle event.
289
+
290
+ ```typescript
291
+ shader.on('resize', (width, height) => {
292
+ console.log(`Canvas resized to ${width}x${height}`);
293
+ });
294
+ ```
295
+
296
+ **Parameters:**
297
+
298
+ - `event` (string): The event name
299
+ - `callback` (Function): The callback function
300
+
301
+ #### `off(event, callback)`
302
+
303
+ Remove a previously registered callback.
304
+
305
+ **Parameters:**
306
+
307
+ - `event` (string): The event name
308
+ - `callback` (Function): The callback function to remove
309
+
310
+ #### Available Events
311
+
312
+ | Event | Callback Arguments | Description |
313
+ | ------------------- | --------------------------------------- | ------------------------------------------------ |
314
+ | `init` | none | Fired after initialization is complete |
315
+ | `resize` | `(width: number, height: number)` | Fired when the canvas element is resized |
316
+ | `updateResolution` | `(width: number, height: number)` | Fired when the drawing buffer resolution changes |
317
+ | `play` | none | Fired when the render loop starts |
318
+ | `pause` | none | Fired when the render loop is paused |
319
+ | `reset` | none | Fired when the shader is reset |
320
+ | `destroy` | none | Fired when the shader is destroyed |
321
+ | `beforeStep` | `(time: number, options?: StepOptions)` | Fired before each render step |
322
+ | `afterStep` | `(time: number, options?: StepOptions)` | Fired after each render step |
323
+ | `beforeDraw` | `(options?: StepOptions)` | Fired before each draw call |
324
+ | `afterDraw` | `(options?: StepOptions)` | Fired after each draw call |
325
+ | `initializeTexture` | `(name, source, options?)` | Fired after a texture is initialized |
326
+ | `initializeUniform` | `(name, type, value, options?)` | Fired after a uniform is initialized |
327
+ | `updateTextures` | `(updates, options?)` | Fired after textures are updated |
328
+ | `updateUniforms` | `(updates, options?)` | Fired after uniforms are updated |
329
+
330
+ Plugins may emit additional namespaced events (e.g., `face:ready`, `pose:results`).
284
331
 
285
332
  ## Options
286
333
 
@@ -293,10 +340,10 @@ The `canvas` option allows you to pass in an existing canvas element. If not pro
293
340
  ```typescript
294
341
  const canvas = document.createElement('canvas');
295
342
  const shader = new ShaderPad(fragmentShaderSrc, { canvas });
296
- shader.onResize = (width, height) => {
343
+ shader.on('resize', (width, height) => {
297
344
  canvas.width = width;
298
345
  canvas.height = height;
299
- };
346
+ });
300
347
  ```
301
348
 
302
349
  ### history
@@ -352,19 +399,15 @@ const shader = new ShaderPad(fragmentShaderSrc, { debug: true });
352
399
 
353
400
  ### plugins
354
401
 
355
- ShaderPad supports plugins to add additional functionality. Plugins are imported from separate paths to keep bundle sizes small.
402
+ ShaderPad adds additional functionality through plugins, which keeps bundle sizes small.
356
403
 
357
404
  #### helpers
358
405
 
359
406
  The `helpers` plugin provides convenience functions and constants. See [helpers.glsl](./src/plugins/helpers.glsl) for the implementation.
360
407
 
361
408
  ```typescript
362
- import ShaderPad from 'shaderpad';
363
409
  import helpers from 'shaderpad/plugins/helpers';
364
-
365
- const shader = new ShaderPad(fragmentShaderSrc, {
366
- plugins: [helpers()],
367
- });
410
+ const shader = new ShaderPad(fragmentShaderSrc, { plugins: [helpers()] });
368
411
  ```
369
412
 
370
413
  **Note:** The `helpers` plugin automatically injects the `u_resolution` uniform into your shader. Do not declare it yourself.
@@ -374,9 +417,7 @@ const shader = new ShaderPad(fragmentShaderSrc, {
374
417
  The `save` plugin adds a `.save()` method to the shader that saves the current frame to a PNG file. It works on desktop and mobile.
375
418
 
376
419
  ```typescript
377
- import ShaderPad from 'shaderpad';
378
420
  import save, { WithSave } from 'shaderpad/plugins/save';
379
-
380
421
  const shader = new ShaderPad(fragmentShaderSrc, { plugins: [save()] }) as WithSave<ShaderPad>;
381
422
  shader.save('filename', 'Optional mobile share text');
382
423
  ```
@@ -386,36 +427,36 @@ shader.save('filename', 'Optional mobile share text');
386
427
  The `face` plugin uses [MediaPipe](https://ai.google.dev/edge/mediapipe/solutions/vision/face_landmarker) to detect faces in video or image textures.
387
428
 
388
429
  ```typescript
389
- import ShaderPad from 'shaderpad';
390
430
  import face from 'shaderpad/plugins/face';
391
-
392
431
  const shader = new ShaderPad(fragmentShaderSrc, {
393
- plugins: [
394
- face({
395
- textureName: 'u_webcam',
396
- options: { maxFaces: 3 },
397
- }),
398
- ],
432
+ plugins: [face({ textureName: 'u_webcam', options: { maxFaces: 3 } })],
399
433
  });
400
434
  ```
401
435
 
402
436
  **Options:**
403
437
 
404
- - `onReady?: () => void` - Callback invoked when initialization is complete and the detection model is loaded
405
- - `onResults?: (results: FaceLandmarkerResult) => void` - Callback invoked with detection results each frame
438
+ - `maxFaces?: number` - Maximum faces to detect (default: 1)
439
+ - `history?: number` - Frames of history to store for landmarks and mask textures
440
+
441
+ **Events:**
442
+
443
+ | Event | Callback Arguments | Description |
444
+ | ------------- | -------------------------------- | ---------------------------------------- |
445
+ | `face:ready` | none | Fired when the detection model is loaded |
446
+ | `face:result` | `(result: FaceLandmarkerResult)` | Fired with detection results each frame |
406
447
 
407
448
  **Uniforms:**
408
449
 
409
- | Uniform | Type | Description |
410
- | -------------------- | --------- | --------------------------------------------------------------------------- |
411
- | `u_maxFaces` | int | Maximum number of faces to detect |
412
- | `u_nFaces` | int | Current number of detected faces |
413
- | `u_faceLandmarksTex` | sampler2D | Raw landmark data texture (use `faceLandmark()` to access) |
414
- | `u_faceMask` | sampler2D | Face mask texture (R: region type, G: confidence, B: normalized face index) |
450
+ | Uniform | Type | Description |
451
+ | -------------------- | ----------------------------- | --------------------------------------------------------------------------- |
452
+ | `u_maxFaces` | int | Maximum number of faces to detect |
453
+ | `u_nFaces` | int | Current number of detected faces |
454
+ | `u_faceLandmarksTex` | sampler2D (or sampler2DArray) | Raw landmark data texture (use `faceLandmark()` to access) |
455
+ | `u_faceMask` | sampler2D (or sampler2DArray) | Face mask texture (R: region type, G: confidence, B: normalized face index) |
415
456
 
416
457
  **Helper functions:**
417
458
 
418
- All region functions return `vec2(confidence, faceIndex)`. faceIndex is 0-indexed (-1 = no face).
459
+ All region functions return `vec2(confidence, faceIndex)`. faceIndex is 0-indexed (-1 = no face). When `history` is enabled, all functions accept an optional `int framesAgo` parameter.
419
460
 
420
461
  - `faceLandmark(int faceIndex, int landmarkIndex) -> vec4` - Returns landmark data as `vec4(x, y, z, visibility)`. Use `vec2(faceLandmark(...))` to get just the screen position.
421
462
  - `leftEyebrowAt(vec2 pos) -> vec2` - Returns `vec2(1.0, faceIndex)` if position is in left eyebrow, `vec2(0.0, -1.0)` otherwise.
@@ -477,9 +518,7 @@ for (int i = 0; i < u_nFaces; ++i) {
477
518
  The `pose` plugin uses [MediaPipe Pose Landmarker](https://ai.google.dev/edge/mediapipe/solutions/vision/pose_landmarker) to expose a flat array of 2D landmarks. Each pose contributes 39 landmarks (33 standard + 6 custom), enumerated below.
478
519
 
479
520
  ```typescript
480
- import ShaderPad from 'shaderpad';
481
521
  import pose from 'shaderpad/plugins/pose';
482
-
483
522
  const shader = new ShaderPad(fragmentShaderSrc, {
484
523
  plugins: [pose({ textureName: 'u_video', options: { maxPoses: 3 } })],
485
524
  });
@@ -487,20 +526,29 @@ const shader = new ShaderPad(fragmentShaderSrc, {
487
526
 
488
527
  **Options:**
489
528
 
490
- - `onReady?: () => void` - Callback invoked when initialization is complete and the detection model is loaded
491
- - `onResults?: (results: PoseLandmarkerResult) => void` - Callback invoked with detection results each frame
529
+ - `maxPoses?: number` - Maximum poses to detect (default: 1)
530
+ - `history?: number` - Frames of history to store for landmarks and mask textures
531
+
532
+ **Events:**
533
+
534
+ | Event | Callback Arguments | Description |
535
+ | ------------- | -------------------------------- | ---------------------------------------- |
536
+ | `pose:ready` | none | Fired when the detection model is loaded |
537
+ | `pose:result` | `(result: PoseLandmarkerResult)` | Fired with detection results each frame |
492
538
 
493
539
  **Uniforms:**
494
540
 
495
- | Uniform | Type | Description |
496
- | -------------------- | --------- | ----------------------------------------------------------------------------- |
497
- | `u_maxPoses` | int | Maximum number of poses to track |
498
- | `u_nPoses` | int | Current number of detected poses |
499
- | `u_poseLandmarksTex` | sampler2D | Raw landmark data texture (RGBA: x, y, z, visibility) |
500
- | `u_poseMask` | sampler2D | Pose mask texture (R: body detected, G: confidence, B: normalized pose index) |
541
+ | Uniform | Type | Description |
542
+ | -------------------- | ----------------------------- | ----------------------------------------------------------------------------- |
543
+ | `u_maxPoses` | int | Maximum number of poses to track |
544
+ | `u_nPoses` | int | Current number of detected poses |
545
+ | `u_poseLandmarksTex` | sampler2D (or sampler2DArray) | Raw landmark data texture (RGBA: x, y, z, visibility) |
546
+ | `u_poseMask` | sampler2D (or sampler2DArray) | Pose mask texture (R: body detected, G: confidence, B: normalized pose index) |
501
547
 
502
548
  **Helper functions:**
503
549
 
550
+ When `history` is enabled, all functions accept an optional `int framesAgo` parameter.
551
+
504
552
  - `poseLandmark(int poseIndex, int landmarkIndex) -> vec4` - Returns landmark data as `vec4(x, y, z, visibility)`. Use `vec2(poseLandmark(...))` to get just the screen position.
505
553
  - `poseAt(vec2 pos) -> vec2` - Returns `vec2(confidence, poseIndex)`. poseIndex is 0-indexed (-1 = no pose), confidence is the segmentation confidence.
506
554
  - `inPose(vec2 pos) -> float` - Returns `1.0` if position is in any pose, `0.0` otherwise.
@@ -571,9 +619,7 @@ for (int i = 0; i < u_maxPoses; ++i) {
571
619
  The `hands` plugin uses [MediaPipe Hand Landmarker](https://ai.google.dev/edge/mediapipe/solutions/vision/hand_landmarker) to expose a flat array of 2D landmarks. Each hand contributes 22 landmarks, enumerated below.
572
620
 
573
621
  ```typescript
574
- import ShaderPad from 'shaderpad';
575
622
  import hands from 'shaderpad/plugins/hands';
576
-
577
623
  const shader = new ShaderPad(fragmentShaderSrc, {
578
624
  plugins: [hands({ textureName: 'u_video', options: { maxHands: 2 } })],
579
625
  });
@@ -581,19 +627,28 @@ const shader = new ShaderPad(fragmentShaderSrc, {
581
627
 
582
628
  **Options:**
583
629
 
584
- - `onReady?: () => void` - Callback invoked when initialization is complete and the detection model is loaded
585
- - `onResults?: (results: HandLandmarkerResult) => void` - Callback invoked with detection results each frame
630
+ - `maxHands?: number` - Maximum hands to detect (default: 2)
631
+ - `history?: number` - Frames of history to store for landmarks texture
632
+
633
+ **Events:**
634
+
635
+ | Event | Callback Arguments | Description |
636
+ | -------------- | -------------------------------- | ---------------------------------------- |
637
+ | `hands:ready` | none | Fired when the detection model is loaded |
638
+ | `hands:result` | `(result: HandLandmarkerResult)` | Fired with detection results each frame |
586
639
 
587
640
  **Uniforms:**
588
641
 
589
- | Uniform | Type | Description |
590
- | -------------------- | --------- | ----------------------------------------------------- |
591
- | `u_maxHands` | int | Maximum number of hands to track |
592
- | `u_nHands` | int | Current number of detected hands |
593
- | `u_handLandmarksTex` | sampler2D | Raw landmark data texture (RGBA: x, y, z, handedness) |
642
+ | Uniform | Type | Description |
643
+ | -------------------- | ----------------------------- | ----------------------------------------------------- |
644
+ | `u_maxHands` | int | Maximum number of hands to track |
645
+ | `u_nHands` | int | Current number of detected hands |
646
+ | `u_handLandmarksTex` | sampler2D (or sampler2DArray) | Raw landmark data texture (RGBA: x, y, z, handedness) |
594
647
 
595
648
  **Helper functions:**
596
649
 
650
+ When `history` is enabled, all functions accept an optional `int framesAgo` parameter.
651
+
597
652
  - `handLandmark(int handIndex, int landmarkIndex) -> vec4` - Returns landmark data as `vec4(x, y, z, handedness)`. Use `vec2(handLandmark(...))` to get just the screen position. Handedness: 0.0 = left hand, 1.0 = right hand.
598
653
  - `isRightHand(int handIndex) -> float` - Returns 1.0 if the hand is a right hand, 0.0 if left.
599
654
  - `isLeftHand(int handIndex) -> float` - Returns 1.0 if the hand is a left hand, 0.0 if right.
@@ -655,9 +710,6 @@ const shader = new ShaderPad(fragmentShaderSrc, {
655
710
  modelPath:
656
711
  'https://storage.googleapis.com/mediapipe-models/image_segmenter/selfie_multiclass_256x256/float32/latest/selfie_multiclass_256x256.tflite',
657
712
  outputCategoryMask: true,
658
- onReady: () => {
659
- console.log('Selfie multiclass model: loading complete');
660
- },
661
713
  },
662
714
  }),
663
715
  ],
@@ -666,18 +718,26 @@ const shader = new ShaderPad(fragmentShaderSrc, {
666
718
 
667
719
  **Options:**
668
720
 
669
- - `onReady?: () => void` - Callback invoked when initialization is complete and the detection model is loaded
670
- - `onResults?: (results: ImageSegmenterResult) => void` - Callback invoked with segmentation results each frame
721
+ - `history?: number` - Frames of history to store for mask texture
722
+
723
+ **Events:**
724
+
725
+ | Event | Callback Arguments | Description |
726
+ | ------------------ | -------------------------------- | ------------------------------------------- |
727
+ | `segmenter:ready` | none | Fired when the segmentation model is loaded |
728
+ | `segmenter:result` | `(result: ImageSegmenterResult)` | Fired with segmentation results each frame |
671
729
 
672
730
  **Uniforms:**
673
731
 
674
- | Uniform | Type | Description |
675
- | ----------------- | --------- | ----------------------------------------------------------------------- |
676
- | `u_segmentMask` | sampler2D | Segment mask texture (R: normalized category, G: confidence, B: unused) |
677
- | `u_numCategories` | int | Number of segmentation categories (including background) |
732
+ | Uniform | Type | Description |
733
+ | ----------------- | ----------------------------- | ----------------------------------------------------------------------- |
734
+ | `u_segmentMask` | sampler2D (or sampler2DArray) | Segment mask texture (R: normalized category, G: confidence, B: unused) |
735
+ | `u_numCategories` | int | Number of segmentation categories (including background) |
678
736
 
679
737
  **Helper functions:**
680
738
 
739
+ When `history` is enabled, all functions accept an optional `int framesAgo` parameter.
740
+
681
741
  - `segmentAt(vec2 pos) -> vec2` - Returns `vec2(confidence, categoryIndex)`. categoryIndex is 0-indexed (-1 = background). confidence is the segmentation confidence (0-1).
682
742
 
683
743
  **Example usage:**
@@ -0,0 +1,10 @@
1
+ var F=`#version 300 es
2
+ in vec2 aPosition;
3
+ out vec2 v_uv;
4
+ void main() {
5
+ v_uv = aPosition * 0.5 + 0.5;
6
+ gl_Position = vec4(aPosition, 0.0, 1.0);
7
+ }`,w=33.333333333333336,L=new Float32Array([-1,-1,1,-1,-1,1,-1,1,1,-1,1,1]),v=Symbol("u_history"),b=Symbol("__SHADERPAD_BUFFER");function A(a,e){if(!e?.length)return a;let t=a.split(`
8
+ `),s=t.findLastIndex(i=>{let r=i.trimStart();return r.startsWith("precision ")||r.startsWith("#version ")})+1;return t.splice(s,0,...e),t.join(`
9
+ `)}function y(a){return a instanceof WebGLTexture?{width:0,height:0}:a instanceof E?{width:a.canvas.width,height:a.canvas.height}:a instanceof HTMLVideoElement?{width:a.videoWidth,height:a.videoHeight}:a instanceof HTMLImageElement?{width:a.naturalWidth??a.width,height:a.naturalHeight??a.height}:{width:a.width,height:a.height}}function x(a){return typeof a=="symbol"?a.description??"":a}var E=class a{isInternalCanvas=!1;isTouchDevice=!1;gl;uniforms=new Map;textures=new Map;textureUnitPool;buffer=null;program=null;aPositionLocation=0;animationFrameId;resolutionObserver;resizeObserver;resizeTimeout=null;lastResizeTime=-1/0;eventListeners=new Map;frame=0;startTime=0;cursorPosition=[.5,.5];clickPosition=[.5,.5];isMouseDown=!1;canvas;hooks=new Map;historyDepth=0;textureOptions;debug;intermediateFbo=null;constructor(e,{canvas:t,plugins:s,history:i,debug:r,...o}={}){if(this.canvas=t||document.createElement("canvas"),!t){this.isInternalCanvas=!0;let f=this.canvas;f.style.position="fixed",f.style.inset="0",f.style.height="100dvh",f.style.width="100dvw",document.body.appendChild(f)}if(this.canvas instanceof OffscreenCanvas){let f=d=>{let g=Object.getOwnPropertyDescriptor(OffscreenCanvas.prototype,d);Object.defineProperty(this.canvas,d,{get:()=>g.get.call(this.canvas),set:R=>{g.set.call(this.canvas,R),this.updateResolution()},configurable:g.configurable,enumerable:g.enumerable})};f("width"),f("height")}let n=this.canvas.getContext("webgl2",{antialias:!1});if(!n)throw new Error("WebGL2 not supported. Please use a browser that supports WebGL2.");this.gl=n,this.textureUnitPool={free:[],next:0,max:n.getParameter(n.MAX_COMBINED_TEXTURE_IMAGE_UNITS)},this.textureOptions=o;let{internalFormat:h,type:c}=o;(c===n.FLOAT||c===n.HALF_FLOAT||h===n.RGBA16F||h===n.RGBA32F||h===n.R16F||h===n.R32F||h===n.RG16F||h===n.RG32F)&&!n.getExtension("EXT_color_buffer_float")&&(console.warn("EXT_color_buffer_float not supported, falling back to RGBA8"),delete this.textureOptions?.internalFormat,delete this.textureOptions?.format,delete this.textureOptions?.type),i&&(this.historyDepth=i),this.debug=r??(typeof process<"u"&&!1),this.animationFrameId=null,this.resolutionObserver=new MutationObserver(()=>this.updateResolution()),this.resizeObserver=new ResizeObserver(()=>this.throttledHandleResize());let m=[];s&&s.forEach(f=>f(this,{gl:n,canvas:this.canvas,injectGLSL:d=>{m.push(d)},emitHook:this.emitHook.bind(this)}));let u=this.gl.createProgram();if(!u)throw new Error("Failed to create WebGL program");this.program=u;let p=this.createShader(this.gl.VERTEX_SHADER,F),T=this.createShader(n.FRAGMENT_SHADER,A(e,m));if(n.attachShader(u,p),n.attachShader(u,T),n.linkProgram(u),n.deleteShader(p),n.deleteShader(T),!n.getProgramParameter(u,n.LINK_STATUS))throw console.error("Program link error:",n.getProgramInfoLog(u)),n.deleteProgram(u),new Error("Failed to link WebGL program");this.aPositionLocation=n.getAttribLocation(u,"aPosition"),this.buffer=n.createBuffer(),n.bindBuffer(n.ARRAY_BUFFER,this.buffer),n.bufferData(n.ARRAY_BUFFER,L,n.STATIC_DRAW),n.viewport(0,0,n.drawingBufferWidth,n.drawingBufferHeight),n.enableVertexAttribArray(this.aPositionLocation),n.vertexAttribPointer(this.aPositionLocation,2,n.FLOAT,!1,0,0),n.useProgram(u),this.canvas instanceof HTMLCanvasElement&&(this.resolutionObserver.observe(this.canvas,{attributes:!0,attributeFilter:["width","height"]}),this.resizeObserver.observe(this.canvas)),this.isInternalCanvas||this.updateResolution(),this.initializeUniform("u_cursor","float",this.cursorPosition),this.initializeUniform("u_click","float",[...this.clickPosition,this.isMouseDown?1:0]),this.initializeUniform("u_time","float",0),this.initializeUniform("u_frame","int",0),this._initializeTexture(b,this.canvas,{...this.textureOptions}),this.intermediateFbo=n.createFramebuffer(),this.historyDepth>0&&this._initializeTexture(v,this.canvas,{history:this.historyDepth,...this.textureOptions}),this.canvas instanceof HTMLCanvasElement&&this.addEventListeners(),this.emitHook("init")}emitHook(e,...t){this.hooks.get(e)?.forEach(s=>s.call(this,...t))}on(e,t){this.hooks.has(e)||this.hooks.set(e,[]),this.hooks.get(e).push(t)}off(e,t){let s=this.hooks.get(e);s&&s.splice(s.indexOf(t),1)}createShader(e,t){let s=this.gl.createShader(e);if(this.gl.shaderSource(s,t),this.gl.compileShader(s),!this.gl.getShaderParameter(s,this.gl.COMPILE_STATUS))throw console.error("Shader compilation failed:",t),console.error(this.gl.getShaderInfoLog(s)),this.gl.deleteShader(s),new Error("Shader compilation failed");return s}throttledHandleResize(){clearTimeout(this.resizeTimeout);let e=performance.now(),t=this.lastResizeTime+w-e;t<=0?(this.lastResizeTime=e,this.handleResize()):this.resizeTimeout=setTimeout(()=>this.throttledHandleResize(),t)}handleResize(){if(!(this.canvas instanceof HTMLCanvasElement))return;let e=window.devicePixelRatio||1,t=this.canvas.clientWidth*e,s=this.canvas.clientHeight*e;this.isInternalCanvas&&(this.canvas.width!==t||this.canvas.height!==s)&&(this.canvas.width=t,this.canvas.height=s),this.emitHook("resize",t,s)}addEventListeners(){let e=this.canvas,t=(i,r)=>{if(!this.uniforms.has("u_cursor"))return;let o=e.getBoundingClientRect();this.cursorPosition[0]=(i-o.left)/o.width,this.cursorPosition[1]=1-(r-o.top)/o.height,this.updateUniforms({u_cursor:this.cursorPosition})},s=(i,r,o)=>{if(this.uniforms.has("u_click")){if(this.isMouseDown=i,i){let n=e.getBoundingClientRect(),h=r,c=o;this.clickPosition[0]=(h-n.left)/n.width,this.clickPosition[1]=1-(c-n.top)/n.height}this.updateUniforms({u_click:[...this.clickPosition,this.isMouseDown?1:0]})}};this.eventListeners.set("mousemove",i=>{let r=i;this.isTouchDevice||t(r.clientX,r.clientY)}),this.eventListeners.set("mousedown",i=>{let r=i;this.isTouchDevice||r.button===0&&(this.isMouseDown=!0,s(!0,r.clientX,r.clientY))}),this.eventListeners.set("mouseup",i=>{let r=i;this.isTouchDevice||r.button===0&&s(!1)}),this.eventListeners.set("touchmove",i=>{let r=i;r.touches.length>0&&t(r.touches[0].clientX,r.touches[0].clientY)}),this.eventListeners.set("touchstart",i=>{let r=i;this.isTouchDevice=!0,r.touches.length>0&&(t(r.touches[0].clientX,r.touches[0].clientY),s(!0,r.touches[0].clientX,r.touches[0].clientY))}),this.eventListeners.set("touchend",i=>{i.touches.length===0&&s(!1)}),this.eventListeners.forEach((i,r)=>{e.addEventListener(r,i)})}updateResolution(){let e=[this.gl.drawingBufferWidth,this.gl.drawingBufferHeight];this.gl.viewport(0,0,...e),this.uniforms.has("u_resolution")?this.updateUniforms({u_resolution:e}):this.initializeUniform("u_resolution","float",e),this.resizeTexture(b,...e),this.historyDepth>0&&this.resizeTexture(v,...e),this.emitHook("updateResolution",...e)}resizeTexture(e,t,s){let i=this.textures.get(e);if(!i||i.width===t&&i.height===s)return;this.gl.deleteTexture(i.texture),i.width=t,i.height=s;let{texture:r}=this.createTexture(e,i);i.texture=r,i.history&&(i.history.writeIndex=0,this.clearHistoryTextureLayers(i))}reserveTextureUnit(e){let t=this.textures.get(e);if(t)return t.unitIndex;if(this.textureUnitPool.free.length>0)return this.textureUnitPool.free.pop();if(this.textureUnitPool.next>=this.textureUnitPool.max)throw new Error("Exceeded the available texture units for this device.");return this.textureUnitPool.next++}releaseTextureUnit(e){let t=this.textures.get(e);t&&this.textureUnitPool.free.push(t.unitIndex)}resolveTextureOptions(e){let{gl:t}=this,s=e?.type??t.UNSIGNED_BYTE;return{type:s,format:e?.format??t.RGBA,internalFormat:e?.internalFormat??(s===t.FLOAT?t.RGBA32F:s===t.HALF_FLOAT?t.RGBA16F:t.RGBA8),minFilter:e?.minFilter??t.LINEAR,magFilter:e?.magFilter??t.LINEAR,wrapS:e?.wrapS??t.CLAMP_TO_EDGE,wrapT:e?.wrapT??t.CLAMP_TO_EDGE,preserveY:e?.preserveY}}getPixelArray(e,t){return e===this.gl.FLOAT?new Float32Array(t):e===this.gl.HALF_FLOAT?new Uint16Array(t):new Uint8Array(t)}clearHistoryTextureLayers(e){if(!e.history)return;let t=this.gl,{type:s,format:i}=e.options,r=this.getPixelArray(s,e.width*e.height*4);t.activeTexture(t.TEXTURE0+e.unitIndex),t.bindTexture(t.TEXTURE_2D_ARRAY,e.texture);for(let o=0;o<e.history.depth;++o)t.texSubImage3D(t.TEXTURE_2D_ARRAY,0,0,0,o,e.width,e.height,1,i,s,r)}initializeUniform(e,t,s,i){let r=i?.arrayLength;if(this.uniforms.has(e))throw new Error(`${e} is already initialized.`);if(t!=="float"&&t!=="int")throw new Error(`Invalid uniform type: ${t}. Expected 'float' or 'int'.`);if(r&&!(Array.isArray(s)&&s.length===r))throw new Error(`${e} array length mismatch: must initialize with ${r} elements.`);let o=this.gl.getUniformLocation(this.program,e);if(!o&&r&&(o=this.gl.getUniformLocation(this.program,`${e}[0]`)),!o){this.log(`${e} not in shader. Skipping initialization.`);return}let n=r?s[0]:s,h=Array.isArray(n)?n.length:1;this.uniforms.set(e,{type:t,length:h,location:o,arrayLength:r});try{this.updateUniforms({[e]:s})}catch(c){throw this.uniforms.delete(e),c}this.emitHook("initializeUniform",...arguments)}log(...e){this.debug&&console.debug(...e)}updateUniforms(e,t){this.gl.useProgram(this.program),Object.entries(e).forEach(([s,i])=>{let r=this.uniforms.get(s);if(!r){this.log(`${s} not in shader. Skipping update.`);return}let o=`uniform${r.length}${r.type.charAt(0)}`;if(r.arrayLength){if(!Array.isArray(i))throw new Error(`${s} is an array, but the value passed to updateUniforms is not an array.`);let n=i.length;if(!n)return;if(n>r.arrayLength)throw new Error(`${s} received ${n} values, but maximum length is ${r.arrayLength}.`);if(i.some(l=>(Array.isArray(l)?l.length:1)!==r.length))throw new Error(`Tried to update ${s} with some elements that are not length ${r.length}.`);let h=new(r.type==="float"?Float32Array:Int32Array)(i.flat()),c=r.location;if(t?.startIndex){let l=this.gl.getUniformLocation(this.program,`${s}[${t.startIndex}]`);if(!l)throw new Error(`${s}[${t.startIndex}] not in shader. Did you pass an invalid startIndex?`);c=l}this.gl[o+"v"](c,h)}else{if(Array.isArray(i)||(i=[i]),i.length!==r.length)throw new Error(`Invalid uniform value length: ${i.length}. Expected ${r.length}.`);this.gl[o](r.location,...i)}}),this.emitHook("updateUniforms",...arguments)}createTexture(e,t){let{width:s,height:i}=t,r=t.history?.depth??0,o=this.gl.createTexture();if(!o)throw new Error("Failed to create texture");let n=t.unitIndex;if(typeof n!="number")try{n=this.reserveTextureUnit(e)}catch(m){throw this.gl.deleteTexture(o),m}let h=r>0,c=h?this.gl.TEXTURE_2D_ARRAY:this.gl.TEXTURE_2D,{options:l}=t;return this.gl.activeTexture(this.gl.TEXTURE0+n),this.gl.bindTexture(c,o),this.gl.texParameteri(c,this.gl.TEXTURE_WRAP_S,l.wrapS),this.gl.texParameteri(c,this.gl.TEXTURE_WRAP_T,l.wrapT),this.gl.texParameteri(c,this.gl.TEXTURE_MIN_FILTER,l.minFilter),this.gl.texParameteri(c,this.gl.TEXTURE_MAG_FILTER,l.magFilter),h?this.gl.texStorage3D(c,1,l.internalFormat,s,i,r):e===b&&this.gl.texImage2D(this.gl.TEXTURE_2D,0,l.internalFormat,s,i,0,l.format,l.type,null),{texture:o,unitIndex:n}}_initializeTexture(e,t,s){if(this.textures.has(e))throw new Error(`Texture '${x(e)}' is already initialized.`);let{history:i=0,...r}=s??{},{width:o,height:n}=y(t);if(!o||!n)throw new Error("Texture source must have valid dimensions");let h={width:o,height:n,options:this.resolveTextureOptions(r)};i>0&&(h.history={depth:i,writeIndex:0});let{texture:c,unitIndex:l}=this.createTexture(e,h),m={texture:c,unitIndex:l,...h};i>0&&(this.initializeUniform(`${x(e)}FrameOffset`,"int",0),this.clearHistoryTextureLayers(m)),this.textures.set(e,m),this.updateTexture(e,t);let u=this.gl.getUniformLocation(this.program,x(e));u&&this.gl.uniform1i(u,l)}initializeTexture(e,t,s){this._initializeTexture(e,t,s),this.emitHook("initializeTexture",...arguments)}updateTextures(e,t){Object.entries(e).forEach(([s,i])=>{this.updateTexture(s,i,t)}),this.emitHook("updateTextures",...arguments)}updateTexture(e,t,s){let i=this.textures.get(e);if(!i)throw new Error(`Texture '${x(e)}' is not initialized.`);if(t instanceof WebGLTexture){this.gl.activeTexture(this.gl.TEXTURE0+i.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D,t);return}let r=t;if(t instanceof a){let u=t.textures.get(b);if(t.gl===this.gl){this.gl.activeTexture(this.gl.TEXTURE0+i.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D,u.texture);return}let{width:p,height:T,options:{format:f,type:d}}=u,g=this.getPixelArray(d,p*T*4);t.gl.bindFramebuffer(t.gl.FRAMEBUFFER,t.intermediateFbo),t.gl.readPixels(0,0,p,T,f,d,g),t.gl.bindFramebuffer(t.gl.FRAMEBUFFER,null),r={data:g,width:p,height:T}}let{width:o,height:n}=y(r);if(!o||!n)return;let h="isPartial"in r&&r.isPartial;h||this.resizeTexture(e,o,n);let l=!("data"in r&&r.data)&&!i.options?.preserveY,m=this.gl.getParameter(this.gl.UNPACK_FLIP_Y_WEBGL);if(i.history){if(this.gl.activeTexture(this.gl.TEXTURE0+i.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D_ARRAY,i.texture),!s?.skipHistoryWrite){this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,l),this.gl.texSubImage3D(this.gl.TEXTURE_2D_ARRAY,0,0,0,i.history.writeIndex,o,n,1,i.options.format,i.options.type,r.data??r),this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,m);let u=`${x(e)}FrameOffset`;this.updateUniforms({[u]:i.history.writeIndex}),i.history.writeIndex=(i.history.writeIndex+1)%i.history.depth}}else{if(this.gl.activeTexture(this.gl.TEXTURE0+i.unitIndex),this.gl.bindTexture(this.gl.TEXTURE_2D,i.texture),this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,l),h){let u=r;this.gl.texSubImage2D(this.gl.TEXTURE_2D,0,u.x??0,u.y??0,o,n,i.options.format,i.options.type,u.data)}else this.gl.texImage2D(this.gl.TEXTURE_2D,0,i.options.internalFormat,o,n,0,i.options.format,i.options.type,r.data??r);this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,m)}}draw(e){this.emitHook("beforeDraw",...arguments);let t=this.gl,s=t.drawingBufferWidth,i=t.drawingBufferHeight,r=this.textures.get(b);t.bindFramebuffer(t.FRAMEBUFFER,this.intermediateFbo),t.framebufferTexture2D(t.FRAMEBUFFER,t.COLOR_ATTACHMENT0,t.TEXTURE_2D,r.texture,0),t.useProgram(this.program),t.bindBuffer(t.ARRAY_BUFFER,this.buffer),t.vertexAttribPointer(this.aPositionLocation,2,t.FLOAT,!1,0,0),t.enableVertexAttribArray(this.aPositionLocation),t.viewport(0,0,s,i),e?.skipClear||t.clear(t.COLOR_BUFFER_BIT),t.drawArrays(t.TRIANGLES,0,6);let o=this.textures.get(v);o&&!e?.skipHistoryWrite&&(t.bindTexture(t.TEXTURE_2D_ARRAY,o.texture),t.copyTexSubImage3D(t.TEXTURE_2D_ARRAY,0,0,0,o.history.writeIndex,0,0,s,i)),t.bindFramebuffer(t.READ_FRAMEBUFFER,this.intermediateFbo),t.bindFramebuffer(t.DRAW_FRAMEBUFFER,null),t.blitFramebuffer(0,0,s,i,0,0,s,i,t.COLOR_BUFFER_BIT,t.NEAREST),t.bindFramebuffer(t.FRAMEBUFFER,null),this.emitHook("afterDraw",...arguments)}step(e,t){this.emitHook("beforeStep",...arguments);let s={};this.uniforms.has("u_time")&&(s.u_time=e),this.uniforms.has("u_frame")&&(s.u_frame=this.frame),this.updateUniforms(s),this.draw(t);let i=this.textures.get(v);if(i&&!t?.skipHistoryWrite){let{writeIndex:r,depth:o}=i.history;this.updateUniforms({[`${x(v)}FrameOffset`]:r}),i.history.writeIndex=(r+1)%o}++this.frame,this.emitHook("afterStep",...arguments)}play(e,t){this.pause();let s=i=>{i=(i-this.startTime)/1e3;let r=t?.(i,this.frame)??void 0;this.step(i,r),this.animationFrameId=requestAnimationFrame(s),e?.(i,this.frame)};this.animationFrameId=requestAnimationFrame(s),this.emitHook("play")}pause(){this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null),this.emitHook("pause")}reset(){this.frame=0,this.startTime=performance.now(),this.textures.forEach(e=>{e.history&&(e.history.writeIndex=0,this.clearHistoryTextureLayers(e))}),this.emitHook("reset")}destroy(){this.emitHook("destroy"),this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null),this.resolutionObserver.disconnect(),this.resizeObserver.disconnect(),this.canvas instanceof HTMLCanvasElement&&this.eventListeners.forEach((e,t)=>{this.canvas.removeEventListener(t,e)}),this.program&&this.gl.deleteProgram(this.program),this.intermediateFbo&&(this.gl.deleteFramebuffer(this.intermediateFbo),this.intermediateFbo=null),this.textures.forEach(e=>{this.gl.deleteTexture(e.texture)}),this.textureUnitPool.free=[],this.textureUnitPool.next=0,this.buffer&&(this.gl.deleteBuffer(this.buffer),this.buffer=null),this.isInternalCanvas&&this.canvas instanceof HTMLCanvasElement&&this.canvas.remove()}},_=E;export{_ as a};
10
+ //# sourceMappingURL=chunk-5CBGNOA3.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["const DEFAULT_VERTEX_SHADER_SRC = `#version 300 es\nin vec2 aPosition;\nout vec2 v_uv;\nvoid main() {\n v_uv = aPosition * 0.5 + 0.5;\n gl_Position = vec4(aPosition, 0.0, 1.0);\n}`;\nconst RESIZE_THROTTLE_INTERVAL = 1000 / 30;\nconst QUAD_VERTICES = new Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1]);\n\ninterface Uniform {\n\ttype: 'float' | 'int';\n\tlength: 1 | 2 | 3 | 4;\n\tlocation: WebGLUniformLocation;\n\tarrayLength?: number;\n}\n\nexport interface TextureOptions {\n\tinternalFormat?: number;\n\tformat?: number;\n\ttype?: number;\n\tminFilter?: number;\n\tmagFilter?: number;\n\twrapS?: number;\n\twrapT?: number;\n\tpreserveY?: boolean;\n}\ntype ResolvedTextureOptions = Required<Omit<TextureOptions, 'preserveY'>> & Pick<TextureOptions, 'preserveY'>;\n\ninterface Texture {\n\ttexture: WebGLTexture;\n\tunitIndex: number;\n\twidth: number;\n\theight: number;\n\thistory?: {\n\t\tdepth: number;\n\t\twriteIndex: number;\n\t};\n\toptions: ResolvedTextureOptions;\n}\n\nexport interface CustomTexture {\n\tdata: ArrayBufferView | null;\n\twidth: number;\n\theight: number;\n}\n\nexport interface PartialCustomTexture extends CustomTexture {\n\tisPartial?: boolean;\n\tx?: number;\n\ty?: number;\n}\n\nexport type TextureSource =\n\t| HTMLImageElement\n\t| HTMLVideoElement\n\t| HTMLCanvasElement\n\t| OffscreenCanvas\n\t| ImageBitmap\n\t| WebGLTexture\n\t| CustomTexture\n\t| ShaderPad;\n\n// Custom textures allow partial updates starting from (x, y).\ntype UpdateTextureSource = Exclude<TextureSource, CustomTexture> | PartialCustomTexture;\n\nexport interface PluginContext {\n\tgl: WebGL2RenderingContext;\n\tcanvas: HTMLCanvasElement | OffscreenCanvas;\n\tinjectGLSL: (code: string) => void;\n\temitHook: (name: LifecycleMethod, ...args: any[]) => void;\n}\n\ntype Plugin = (shaderPad: ShaderPad, context: PluginContext) => void;\n\ntype LifecycleMethod =\n\t| 'init'\n\t| 'initializeTexture'\n\t| 'initializeUniform'\n\t| 'updateTextures'\n\t| 'updateUniforms'\n\t| 'beforeStep'\n\t| 'afterStep'\n\t| 'beforeDraw'\n\t| 'afterDraw'\n\t| 'updateResolution'\n\t| 'resize'\n\t| 'play'\n\t| 'pause'\n\t| 'reset'\n\t| 'destroy'\n\t| `${string}:${string}`;\n\nexport interface Options extends Exclude<TextureOptions, 'preserveY'> {\n\tcanvas?: HTMLCanvasElement | OffscreenCanvas | null;\n\tplugins?: Plugin[];\n\thistory?: number;\n\tdebug?: boolean;\n}\n\nexport interface StepOptions {\n\tskipClear?: boolean;\n\tskipHistoryWrite?: boolean;\n}\n\ntype TextureUnitPool = {\n\tfree: number[];\n\tnext: number;\n\tmax: number;\n};\n\nconst HISTORY_TEXTURE_KEY = Symbol('u_history');\nconst INTERMEDIATE_TEXTURE_KEY = Symbol('__SHADERPAD_BUFFER');\n\nfunction combineShaderCode(shader: string, injections: string[]): string {\n\tif (!injections?.length) return shader;\n\tconst lines = shader.split('\\n');\n\tconst insertAt =\n\t\tlines.findLastIndex(line => {\n\t\t\tconst trimmed = line.trimStart();\n\t\t\treturn trimmed.startsWith('precision ') || trimmed.startsWith('#version ');\n\t\t}) + 1;\n\tlines.splice(insertAt, 0, ...injections);\n\treturn lines.join('\\n');\n}\n\nfunction getSourceDimensions(source: TextureSource): { width: number; height: number } {\n\tif (source instanceof WebGLTexture) {\n\t\treturn { width: 0, height: 0 }; // Invalid - dimensions not readable.\n\t}\n\tif (source instanceof ShaderPad) {\n\t\treturn { width: source.canvas.width, height: source.canvas.height };\n\t}\n\tif (source instanceof HTMLVideoElement) {\n\t\treturn { width: source.videoWidth, height: source.videoHeight };\n\t}\n\tif (source instanceof HTMLImageElement) {\n\t\treturn { width: source.naturalWidth ?? source.width, height: source.naturalHeight ?? source.height };\n\t}\n\t// CustomTexture, HTMLCanvasElement, OffscreenCanvas, ImageBitmap.\n\treturn { width: source.width, height: source.height };\n}\n\nfunction stringFrom(name: string | symbol) {\n\treturn typeof name === 'symbol' ? name.description ?? '' : name;\n}\n\nclass ShaderPad {\n\tprivate isInternalCanvas = false;\n\tprivate isTouchDevice = false;\n\tprivate gl: WebGL2RenderingContext;\n\tprivate uniforms: Map<string, Uniform> = new Map();\n\tprivate textures: Map<string | symbol, Texture> = new Map();\n\tprivate textureUnitPool: TextureUnitPool;\n\tprivate buffer: WebGLBuffer | null = null;\n\tprivate program: WebGLProgram | null = null;\n\tprivate aPositionLocation = 0;\n\tprivate animationFrameId: number | null;\n\tprivate resolutionObserver: MutationObserver;\n\tprivate resizeObserver: ResizeObserver;\n\tprivate resizeTimeout: ReturnType<typeof setTimeout> = null as unknown as ReturnType<typeof setTimeout>;\n\tprivate lastResizeTime = -Infinity;\n\tprivate eventListeners: Map<string, EventListener> = new Map();\n\tprivate frame = 0;\n\tprivate startTime = 0;\n\tprivate cursorPosition = [0.5, 0.5];\n\tprivate clickPosition = [0.5, 0.5];\n\tprivate isMouseDown = false;\n\tpublic canvas: HTMLCanvasElement | OffscreenCanvas;\n\tprivate hooks: Map<LifecycleMethod, Function[]> = new Map();\n\tprivate historyDepth = 0;\n\tprivate textureOptions: TextureOptions;\n\tprivate debug: boolean;\n\t// WebGL can’t read from and write to the history texture at the same time.\n\t// We write to an intermediate texture then blit to the history texture.\n\tprivate intermediateFbo: WebGLFramebuffer | null = null;\n\n\tconstructor(fragmentShaderSrc: string, { canvas, plugins, history, debug, ...textureOptions }: Options = {}) {\n\t\tthis.canvas = canvas || document.createElement('canvas');\n\t\tif (!canvas) {\n\t\t\tthis.isInternalCanvas = true;\n\t\t\tconst htmlCanvas = this.canvas as HTMLCanvasElement;\n\t\t\thtmlCanvas.style.position = 'fixed';\n\t\t\thtmlCanvas.style.inset = '0';\n\t\t\thtmlCanvas.style.height = '100dvh';\n\t\t\thtmlCanvas.style.width = '100dvw';\n\t\t\tdocument.body.appendChild(htmlCanvas);\n\t\t}\n\t\tif (this.canvas instanceof OffscreenCanvas) {\n\t\t\tconst wrapDimension = (dimension: 'width' | 'height') => {\n\t\t\t\tconst descriptor = Object.getOwnPropertyDescriptor(OffscreenCanvas.prototype, dimension)!;\n\t\t\t\tObject.defineProperty(this.canvas, dimension, {\n\t\t\t\t\tget: () => descriptor.get!.call(this.canvas),\n\t\t\t\t\tset: v => {\n\t\t\t\t\t\tdescriptor.set!.call(this.canvas, v);\n\t\t\t\t\t\tthis.updateResolution();\n\t\t\t\t\t},\n\t\t\t\t\tconfigurable: descriptor.configurable,\n\t\t\t\t\tenumerable: descriptor.enumerable,\n\t\t\t\t});\n\t\t\t};\n\t\t\twrapDimension('width');\n\t\t\twrapDimension('height');\n\t\t}\n\n\t\tconst gl = this.canvas.getContext('webgl2', { antialias: false }) as WebGL2RenderingContext;\n\t\tif (!gl) {\n\t\t\tthrow new Error('WebGL2 not supported. Please use a browser that supports WebGL2.');\n\t\t}\n\t\tthis.gl = gl;\n\n\t\tthis.textureUnitPool = {\n\t\t\tfree: [],\n\t\t\tnext: 0,\n\t\t\tmax: gl.getParameter(gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS),\n\t\t};\n\t\tthis.textureOptions = textureOptions;\n\n\t\tconst { internalFormat, type } = textureOptions;\n\t\tconst isFloatFormat =\n\t\t\ttype === gl.FLOAT ||\n\t\t\ttype === gl.HALF_FLOAT ||\n\t\t\tinternalFormat === gl.RGBA16F ||\n\t\t\tinternalFormat === gl.RGBA32F ||\n\t\t\tinternalFormat === gl.R16F ||\n\t\t\tinternalFormat === gl.R32F ||\n\t\t\tinternalFormat === gl.RG16F ||\n\t\t\tinternalFormat === gl.RG32F;\n\t\tif (isFloatFormat && !gl.getExtension('EXT_color_buffer_float')) {\n\t\t\tconsole.warn('EXT_color_buffer_float not supported, falling back to RGBA8');\n\t\t\tdelete this.textureOptions?.internalFormat;\n\t\t\tdelete this.textureOptions?.format;\n\t\t\tdelete this.textureOptions?.type;\n\t\t}\n\n\t\tif (history) this.historyDepth = history;\n\t\tthis.debug = debug ?? (typeof process !== 'undefined' && process.env.NODE_ENV !== 'production');\n\t\tthis.animationFrameId = null;\n\t\tthis.resolutionObserver = new MutationObserver(() => this.updateResolution());\n\t\tthis.resizeObserver = new ResizeObserver(() => this.throttledHandleResize());\n\n\t\tconst glslInjections: string[] = [];\n\t\tif (plugins) {\n\t\t\tplugins.forEach(plugin =>\n\t\t\t\tplugin(this, {\n\t\t\t\t\tgl,\n\t\t\t\t\tcanvas: this.canvas,\n\t\t\t\t\tinjectGLSL: (code: string) => {\n\t\t\t\t\t\tglslInjections.push(code);\n\t\t\t\t\t},\n\t\t\t\t\temitHook: this.emitHook.bind(this),\n\t\t\t\t})\n\t\t\t);\n\t\t}\n\n\t\tconst program = this.gl.createProgram();\n\t\tif (!program) {\n\t\t\tthrow new Error('Failed to create WebGL program');\n\t\t}\n\t\tthis.program = program;\n\n\t\tconst vertexShader = this.createShader(this.gl.VERTEX_SHADER, DEFAULT_VERTEX_SHADER_SRC);\n\t\tconst fragmentShader = this.createShader(\n\t\t\tgl.FRAGMENT_SHADER,\n\t\t\tcombineShaderCode(fragmentShaderSrc, glslInjections)\n\t\t);\n\t\tgl.attachShader(program, vertexShader);\n\t\tgl.attachShader(program, fragmentShader);\n\t\tgl.linkProgram(program);\n\t\tgl.deleteShader(vertexShader);\n\t\tgl.deleteShader(fragmentShader);\n\n\t\tif (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n\t\t\tconsole.error('Program link error:', gl.getProgramInfoLog(program));\n\t\t\tgl.deleteProgram(program);\n\t\t\tthrow new Error('Failed to link WebGL program');\n\t\t}\n\n\t\tthis.aPositionLocation = gl.getAttribLocation(program, 'aPosition');\n\t\tthis.buffer = gl.createBuffer();\n\t\tgl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);\n\t\tgl.bufferData(gl.ARRAY_BUFFER, QUAD_VERTICES, gl.STATIC_DRAW);\n\t\tgl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);\n\t\tgl.enableVertexAttribArray(this.aPositionLocation);\n\t\tgl.vertexAttribPointer(this.aPositionLocation, 2, gl.FLOAT, false, 0, 0);\n\n\t\tgl.useProgram(program);\n\n\t\tif (this.canvas instanceof HTMLCanvasElement) {\n\t\t\tthis.resolutionObserver.observe(this.canvas, { attributes: true, attributeFilter: ['width', 'height'] });\n\t\t\tthis.resizeObserver.observe(this.canvas);\n\t\t}\n\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._initializeTexture(INTERMEDIATE_TEXTURE_KEY, this.canvas, {\n\t\t\t...this.textureOptions,\n\t\t});\n\t\tthis.intermediateFbo = gl.createFramebuffer();\n\n\t\tif (this.historyDepth > 0) {\n\t\t\tthis._initializeTexture(HISTORY_TEXTURE_KEY, this.canvas, {\n\t\t\t\thistory: this.historyDepth,\n\t\t\t\t...this.textureOptions,\n\t\t\t});\n\t\t}\n\t\tif (this.canvas instanceof HTMLCanvasElement) {\n\t\t\tthis.addEventListeners();\n\t\t}\n\t\tthis.emitHook('init');\n\t}\n\n\tprivate emitHook(name: LifecycleMethod, ...args: any[]) {\n\t\tthis.hooks.get(name)?.forEach(hook => hook.call(this, ...args));\n\t}\n\n\ton(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\toff(name: LifecycleMethod, fn: Function) {\n\t\tconst hooks = this.hooks.get(name);\n\t\tif (hooks) {\n\t\t\thooks.splice(hooks.indexOf(fn), 1);\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 throttledHandleResize() {\n\t\tclearTimeout(this.resizeTimeout);\n\t\tconst now = performance.now();\n\t\tconst timeUntilNextResize = this.lastResizeTime + RESIZE_THROTTLE_INTERVAL - now;\n\t\tif (timeUntilNextResize <= 0) {\n\t\t\tthis.lastResizeTime = now;\n\t\t\tthis.handleResize();\n\t\t} else {\n\t\t\tthis.resizeTimeout = setTimeout(() => this.throttledHandleResize(), timeUntilNextResize);\n\t\t}\n\t}\n\n\tprivate handleResize() {\n\t\tif (!(this.canvas instanceof HTMLCanvasElement)) return;\n\t\tconst pixelRatio = window.devicePixelRatio || 1;\n\t\tconst width = this.canvas.clientWidth * pixelRatio;\n\t\tconst height = this.canvas.clientHeight * pixelRatio;\n\t\tif (this.isInternalCanvas && (this.canvas.width !== width || this.canvas.height !== height)) {\n\t\t\tthis.canvas.width = width;\n\t\t\tthis.canvas.height = height;\n\t\t}\n\t\tthis.emitHook('resize', width, height);\n\t}\n\n\tprivate addEventListeners() {\n\t\tconst htmlCanvas = this.canvas as HTMLCanvasElement;\n\t\tconst updateCursor = (x: number, y: number) => {\n\t\t\tif (!this.uniforms.has('u_cursor')) return;\n\t\t\tconst rect = htmlCanvas.getBoundingClientRect();\n\t\t\tthis.cursorPosition[0] = (x - rect.left) / rect.width;\n\t\t\tthis.cursorPosition[1] = 1 - (y - rect.top) / rect.height; // Flip Y for WebGL\n\t\t\tthis.updateUniforms({ u_cursor: this.cursorPosition });\n\t\t};\n\n\t\tconst updateClick = (isMouseDown: boolean, x?: number, y?: number) => {\n\t\t\tif (!this.uniforms.has('u_click')) return;\n\t\t\tthis.isMouseDown = isMouseDown;\n\t\t\tif (isMouseDown) {\n\t\t\t\tconst rect = htmlCanvas.getBoundingClientRect();\n\t\t\t\tconst xVal = x as number;\n\t\t\t\tconst yVal = y as number;\n\t\t\t\tthis.clickPosition[0] = (xVal - rect.left) / rect.width;\n\t\t\t\tthis.clickPosition[1] = 1 - (yVal - rect.top) / rect.height; // Flip Y for WebGL\n\t\t\t}\n\t\t\tthis.updateUniforms({ u_click: [...this.clickPosition, this.isMouseDown ? 1.0 : 0.0] });\n\t\t};\n\n\t\tthis.eventListeners.set('mousemove', event => {\n\t\t\tconst mouseEvent = event as MouseEvent;\n\t\t\tif (!this.isTouchDevice) {\n\t\t\t\tupdateCursor(mouseEvent.clientX, mouseEvent.clientY);\n\t\t\t}\n\t\t});\n\n\t\tthis.eventListeners.set('mousedown', event => {\n\t\t\tconst mouseEvent = event as MouseEvent;\n\t\t\tif (!this.isTouchDevice) {\n\t\t\t\tif (mouseEvent.button === 0) {\n\t\t\t\t\tthis.isMouseDown = true;\n\t\t\t\t\tupdateClick(true, mouseEvent.clientX, mouseEvent.clientY);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\tthis.eventListeners.set('mouseup', event => {\n\t\t\tconst mouseEvent = event as MouseEvent;\n\t\t\tif (!this.isTouchDevice) {\n\t\t\t\tif (mouseEvent.button === 0) {\n\t\t\t\t\tupdateClick(false);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\tthis.eventListeners.set('touchmove', event => {\n\t\t\tconst touchEvent = event as TouchEvent;\n\t\t\tif (touchEvent.touches.length > 0) {\n\t\t\t\tupdateCursor(touchEvent.touches[0].clientX, touchEvent.touches[0].clientY);\n\t\t\t}\n\t\t});\n\n\t\tthis.eventListeners.set('touchstart', event => {\n\t\t\tconst touchEvent = event as TouchEvent;\n\t\t\tthis.isTouchDevice = true;\n\t\t\tif (touchEvent.touches.length > 0) {\n\t\t\t\tupdateCursor(touchEvent.touches[0].clientX, touchEvent.touches[0].clientY);\n\t\t\t\tupdateClick(true, touchEvent.touches[0].clientX, touchEvent.touches[0].clientY);\n\t\t\t}\n\t\t});\n\n\t\tthis.eventListeners.set('touchend', event => {\n\t\t\tconst touchEvent = event as TouchEvent;\n\t\t\tif (touchEvent.touches.length === 0) {\n\t\t\t\tupdateClick(false);\n\t\t\t}\n\t\t});\n\n\t\tthis.eventListeners.forEach((listener, event) => {\n\t\t\thtmlCanvas.addEventListener(event, listener);\n\t\t});\n\t}\n\n\tprivate updateResolution() {\n\t\tconst resolution: [number, number] = [this.gl.drawingBufferWidth, this.gl.drawingBufferHeight];\n\t\tthis.gl.viewport(0, 0, ...resolution);\n\t\tif (this.uniforms.has('u_resolution')) {\n\t\t\tthis.updateUniforms({ u_resolution: resolution });\n\t\t} else {\n\t\t\tthis.initializeUniform('u_resolution', 'float', resolution);\n\t\t}\n\t\tthis.resizeTexture(INTERMEDIATE_TEXTURE_KEY, ...resolution);\n\t\tif (this.historyDepth > 0) {\n\t\t\tthis.resizeTexture(HISTORY_TEXTURE_KEY, ...resolution);\n\t\t}\n\t\tthis.emitHook('updateResolution', ...resolution);\n\t}\n\n\tprivate resizeTexture(name: string | symbol, width: number, height: number) {\n\t\tconst info = this.textures.get(name);\n\t\tif (!info || (info.width === width && info.height === height)) return;\n\n\t\tthis.gl.deleteTexture(info.texture);\n\t\tinfo.width = width;\n\t\tinfo.height = height;\n\t\tconst { texture } = this.createTexture(name, info);\n\t\tinfo.texture = texture;\n\t\tif (info.history) {\n\t\t\tinfo.history.writeIndex = 0;\n\t\t\tthis.clearHistoryTextureLayers(info);\n\t\t}\n\t}\n\n\tprivate reserveTextureUnit(name: string | symbol) {\n\t\tconst existing = this.textures.get(name);\n\t\tif (existing) return existing.unitIndex;\n\t\tif (this.textureUnitPool.free.length > 0) return this.textureUnitPool.free.pop()!;\n\t\tif (this.textureUnitPool.next >= this.textureUnitPool.max) {\n\t\t\tthrow new Error('Exceeded the available texture units for this device.');\n\t\t}\n\t\treturn this.textureUnitPool.next++;\n\t}\n\n\tprivate releaseTextureUnit(name: string | symbol) {\n\t\tconst existing = this.textures.get(name);\n\t\tif (existing) {\n\t\t\tthis.textureUnitPool.free.push(existing.unitIndex);\n\t\t}\n\t}\n\n\tprivate resolveTextureOptions(options?: TextureOptions): ResolvedTextureOptions {\n\t\tconst { gl } = this;\n\t\tconst type = options?.type ?? gl.UNSIGNED_BYTE;\n\t\treturn {\n\t\t\ttype,\n\t\t\tformat: options?.format ?? gl.RGBA,\n\t\t\tinternalFormat:\n\t\t\t\toptions?.internalFormat ??\n\t\t\t\t(type === gl.FLOAT ? gl.RGBA32F : type === gl.HALF_FLOAT ? gl.RGBA16F : gl.RGBA8),\n\t\t\tminFilter: options?.minFilter ?? gl.LINEAR,\n\t\t\tmagFilter: options?.magFilter ?? gl.LINEAR,\n\t\t\twrapS: options?.wrapS ?? gl.CLAMP_TO_EDGE,\n\t\t\twrapT: options?.wrapT ?? gl.CLAMP_TO_EDGE,\n\t\t\tpreserveY: options?.preserveY,\n\t\t};\n\t}\n\n\tprivate getPixelArray(type: number, size: number): ArrayBufferView {\n\t\treturn type === this.gl.FLOAT\n\t\t\t? new Float32Array(size)\n\t\t\t: type === this.gl.HALF_FLOAT\n\t\t\t? new Uint16Array(size)\n\t\t\t: new Uint8Array(size);\n\t}\n\n\tprivate clearHistoryTextureLayers(textureInfo: Texture): void {\n\t\tif (!textureInfo.history) return;\n\n\t\tconst gl = this.gl;\n\t\tconst { type, format } = textureInfo.options;\n\t\tconst transparent = this.getPixelArray(type, textureInfo.width * textureInfo.height * 4);\n\t\tgl.activeTexture(gl.TEXTURE0 + textureInfo.unitIndex);\n\t\tgl.bindTexture(gl.TEXTURE_2D_ARRAY, textureInfo.texture);\n\t\tfor (let layer = 0; layer < textureInfo.history.depth; ++layer) {\n\t\t\tgl.texSubImage3D(\n\t\t\t\tgl.TEXTURE_2D_ARRAY,\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t\tlayer,\n\t\t\t\ttextureInfo.width,\n\t\t\t\ttextureInfo.height,\n\t\t\t\t1,\n\t\t\t\tformat,\n\t\t\t\ttype,\n\t\t\t\ttransparent\n\t\t\t);\n\t\t}\n\t}\n\n\tinitializeUniform(\n\t\tname: string,\n\t\ttype: 'float' | 'int',\n\t\tvalue: number | number[] | (number | number[])[],\n\t\toptions?: { arrayLength?: number }\n\t) {\n\t\tconst arrayLength = options?.arrayLength;\n\t\tif (this.uniforms.has(name)) {\n\t\t\tthrow new Error(`${name} is already initialized.`);\n\t\t}\n\t\tif (type !== 'float' && type !== 'int') {\n\t\t\tthrow new Error(`Invalid uniform type: ${type}. Expected 'float' or 'int'.`);\n\t\t}\n\t\tif (arrayLength && !(Array.isArray(value) && value.length === arrayLength)) {\n\t\t\tthrow new Error(`${name} array length mismatch: must initialize with ${arrayLength} elements.`);\n\t\t}\n\n\t\tlet location = this.gl.getUniformLocation(this.program!, name);\n\t\tif (!location && arrayLength) {\n\t\t\tlocation = this.gl.getUniformLocation(this.program!, `${name}[0]`);\n\t\t}\n\t\tif (!location) {\n\t\t\tthis.log(`${name} not in shader. Skipping initialization.`);\n\t\t\treturn;\n\t\t}\n\n\t\tconst probeValue = arrayLength ? (value as number[] | number[][])[0] : value;\n\t\tconst length = Array.isArray(probeValue) ? (probeValue.length as 1 | 2 | 3 | 4) : 1;\n\t\tthis.uniforms.set(name, { type, length, location, arrayLength });\n\n\t\ttry {\n\t\t\tthis.updateUniforms({ [name]: value });\n\t\t} catch (error) {\n\t\t\tthis.uniforms.delete(name);\n\t\t\tthrow error;\n\t\t}\n\t\tthis.emitHook('initializeUniform', ...arguments);\n\t}\n\n\tprivate log(...args: any[]) {\n\t\tif (this.debug) console.debug(...args);\n\t}\n\n\tupdateUniforms(\n\t\tupdates: Record<string, number | number[] | (number | number[])[]>,\n\t\toptions?: { startIndex?: number }\n\t) {\n\t\tthis.gl.useProgram(this.program);\n\t\tObject.entries(updates).forEach(([name, newValue]) => {\n\t\t\tconst uniform = this.uniforms.get(name);\n\t\t\tif (!uniform) {\n\t\t\t\tthis.log(`${name} not in shader. Skipping update.`);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet glFunctionName = `uniform${uniform.length}${uniform.type.charAt(0)}`; // e.g. uniform1f, uniform3i…\n\t\t\tif (uniform.arrayLength) {\n\t\t\t\tif (!Array.isArray(newValue)) {\n\t\t\t\t\tthrow new Error(`${name} is an array, but the value passed to updateUniforms is not an array.`);\n\t\t\t\t}\n\t\t\t\tconst nValues = newValue.length;\n\t\t\t\tif (!nValues) return;\n\t\t\t\tif (nValues > uniform.arrayLength) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`${name} received ${nValues} values, but maximum length is ${uniform.arrayLength}.`\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (newValue.some(item => (Array.isArray(item) ? item.length : 1) !== uniform.length)) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Tried to update ${name} with some elements that are not length ${uniform.length}.`\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst typedArray = new (uniform.type === 'float' ? Float32Array : Int32Array)(newValue.flat());\n\t\t\t\tlet location = uniform.location;\n\t\t\t\tif (options?.startIndex) {\n\t\t\t\t\tconst newLocation = this.gl.getUniformLocation(this.program!, `${name}[${options.startIndex}]`);\n\t\t\t\t\tif (!newLocation) {\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t`${name}[${options.startIndex}] not in shader. Did you pass an invalid startIndex?`\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tlocation = newLocation;\n\t\t\t\t}\n\t\t\t\t(this.gl as any)[glFunctionName + 'v'](location, typedArray);\n\t\t\t} else {\n\t\t\t\tif (!Array.isArray(newValue)) newValue = [newValue];\n\t\t\t\tif (newValue.length !== uniform.length) {\n\t\t\t\t\tthrow new Error(`Invalid uniform value length: ${newValue.length}. Expected ${uniform.length}.`);\n\t\t\t\t}\n\t\t\t\t(this.gl as any)[glFunctionName](uniform.location, ...newValue);\n\t\t\t}\n\t\t});\n\t\tthis.emitHook('updateUniforms', ...arguments);\n\t}\n\n\tprivate createTexture(\n\t\tname: string | symbol,\n\t\ttextureInfo: Pick<Texture, 'width' | 'height' | 'history' | 'options'> & { unitIndex?: number }\n\t) {\n\t\tconst { width, height } = textureInfo;\n\t\tconst historyDepth = textureInfo.history?.depth ?? 0;\n\n\t\tconst texture = this.gl.createTexture();\n\t\tif (!texture) {\n\t\t\tthrow new Error('Failed to create texture');\n\t\t}\n\n\t\tlet unitIndex = textureInfo.unitIndex;\n\t\tif (typeof unitIndex !== 'number') {\n\t\t\ttry {\n\t\t\t\tunitIndex = this.reserveTextureUnit(name);\n\t\t\t} catch (error) {\n\t\t\t\tthis.gl.deleteTexture(texture);\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\n\t\tconst hasHistory = historyDepth > 0;\n\t\tconst textureTarget = hasHistory ? this.gl.TEXTURE_2D_ARRAY : this.gl.TEXTURE_2D;\n\t\tconst { options } = textureInfo;\n\t\tthis.gl.activeTexture(this.gl.TEXTURE0 + unitIndex);\n\t\tthis.gl.bindTexture(textureTarget, texture);\n\t\tthis.gl.texParameteri(textureTarget, this.gl.TEXTURE_WRAP_S, options.wrapS);\n\t\tthis.gl.texParameteri(textureTarget, this.gl.TEXTURE_WRAP_T, options.wrapT);\n\t\tthis.gl.texParameteri(textureTarget, this.gl.TEXTURE_MIN_FILTER, options.minFilter);\n\t\tthis.gl.texParameteri(textureTarget, this.gl.TEXTURE_MAG_FILTER, options.magFilter);\n\t\tif (hasHistory) {\n\t\t\tthis.gl.texStorage3D(textureTarget, 1, options.internalFormat, width, height, historyDepth);\n\t\t} else if (name === INTERMEDIATE_TEXTURE_KEY) {\n\t\t\tthis.gl.texImage2D(\n\t\t\t\tthis.gl.TEXTURE_2D,\n\t\t\t\t0,\n\t\t\t\toptions.internalFormat,\n\t\t\t\twidth,\n\t\t\t\theight,\n\t\t\t\t0,\n\t\t\t\toptions.format,\n\t\t\t\toptions.type,\n\t\t\t\tnull\n\t\t\t);\n\t\t}\n\t\treturn { texture, unitIndex };\n\t}\n\n\tprivate _initializeTexture(\n\t\tname: string | symbol,\n\t\tsource: TextureSource,\n\t\toptions?: TextureOptions & { history?: number }\n\t) {\n\t\tif (this.textures.has(name)) {\n\t\t\tthrow new Error(`Texture '${stringFrom(name)}' is already initialized.`);\n\t\t}\n\n\t\tconst { history: historyDepth = 0, ...textureOptions } = options ?? {};\n\t\tconst { width, height } = getSourceDimensions(source);\n\t\tif (!width || !height) {\n\t\t\tthrow new Error(`Texture source must have valid dimensions`);\n\t\t}\n\t\tconst textureInfo: Pick<Texture, 'width' | 'height' | 'history' | 'options'> = {\n\t\t\twidth,\n\t\t\theight,\n\t\t\toptions: this.resolveTextureOptions(textureOptions),\n\t\t};\n\t\tif (historyDepth > 0) {\n\t\t\ttextureInfo.history = { depth: historyDepth, writeIndex: 0 };\n\t\t}\n\t\tconst { texture, unitIndex } = this.createTexture(name, textureInfo);\n\t\tconst completeTextureInfo: Texture = { texture, unitIndex, ...textureInfo };\n\t\tif (historyDepth > 0) {\n\t\t\tthis.initializeUniform(`${stringFrom(name)}FrameOffset`, 'int', 0);\n\t\t\tthis.clearHistoryTextureLayers(completeTextureInfo);\n\t\t}\n\t\tthis.textures.set(name, completeTextureInfo);\n\t\tthis.updateTexture(name, source);\n\n\t\t// Set a uniform to access the texture in the fragment shader.\n\t\tconst uSampler = this.gl.getUniformLocation(this.program!, stringFrom(name));\n\t\tif (uSampler) {\n\t\t\tthis.gl.uniform1i(uSampler, unitIndex);\n\t\t}\n\t}\n\n\tinitializeTexture(name: string, source: TextureSource, options?: TextureOptions & { history?: number }) {\n\t\tthis._initializeTexture(name, source, options);\n\t\tthis.emitHook('initializeTexture', ...arguments);\n\t}\n\n\tupdateTextures(updates: Record<string, UpdateTextureSource>, options?: { skipHistoryWrite?: boolean }) {\n\t\tObject.entries(updates).forEach(([name, source]) => {\n\t\t\tthis.updateTexture(name, source, options);\n\t\t});\n\t\tthis.emitHook('updateTextures', ...arguments);\n\t}\n\n\tprivate updateTexture(\n\t\tname: string | symbol,\n\t\tsource: UpdateTextureSource,\n\t\toptions?: { skipHistoryWrite?: boolean }\n\t) {\n\t\tconst info = this.textures.get(name);\n\t\tif (!info) throw new Error(`Texture '${stringFrom(name)}' is not initialized.`);\n\n\t\tif (source instanceof WebGLTexture) {\n\t\t\tthis.gl.activeTexture(this.gl.TEXTURE0 + info.unitIndex);\n\t\t\tthis.gl.bindTexture(this.gl.TEXTURE_2D, source);\n\t\t\treturn;\n\t\t}\n\n\t\tlet nonShaderPadSource = source as Exclude<UpdateTextureSource, ShaderPad>;\n\t\tif (source instanceof ShaderPad) {\n\t\t\tconst sourceIntermediateInfo = source.textures.get(INTERMEDIATE_TEXTURE_KEY)!;\n\n\t\t\tif (source.gl === this.gl) {\n\t\t\t\tthis.gl.activeTexture(this.gl.TEXTURE0 + info.unitIndex);\n\t\t\t\tthis.gl.bindTexture(this.gl.TEXTURE_2D, sourceIntermediateInfo.texture);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Different contexts - transfer via readPixels to preserve precision.\n\t\t\tconst {\n\t\t\t\twidth,\n\t\t\t\theight,\n\t\t\t\toptions: { format, type },\n\t\t\t} = sourceIntermediateInfo;\n\t\t\tconst pixels = this.getPixelArray(type, width * height * 4);\n\t\t\tsource.gl.bindFramebuffer(source.gl.FRAMEBUFFER, source.intermediateFbo);\n\t\t\tsource.gl.readPixels(0, 0, width, height, format, type, pixels);\n\t\t\tsource.gl.bindFramebuffer(source.gl.FRAMEBUFFER, null);\n\t\t\tnonShaderPadSource = { data: pixels, width, height };\n\t\t}\n\n\t\t// If dimensions changed, recreate the texture with new dimensions.\n\t\tconst { width, height } = getSourceDimensions(nonShaderPadSource);\n\t\tif (!width || !height) return;\n\n\t\tconst isPartial = 'isPartial' in nonShaderPadSource && nonShaderPadSource.isPartial;\n\t\tif (!isPartial) {\n\t\t\tthis.resizeTexture(name, width, height);\n\t\t}\n\n\t\t// UNPACK_FLIP_Y_WEBGL only works for DOM element sources, not typed arrays.\n\t\tconst isTypedArray = 'data' in nonShaderPadSource && nonShaderPadSource.data;\n\t\tconst shouldFlipY = !isTypedArray && !info.options?.preserveY;\n\t\tconst previousFlipY = this.gl.getParameter(this.gl.UNPACK_FLIP_Y_WEBGL);\n\n\t\tif (info.history) {\n\t\t\tthis.gl.activeTexture(this.gl.TEXTURE0 + info.unitIndex);\n\t\t\tthis.gl.bindTexture(this.gl.TEXTURE_2D_ARRAY, info.texture);\n\t\t\tif (!options?.skipHistoryWrite) {\n\t\t\t\tthis.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, shouldFlipY);\n\t\t\t\tthis.gl.texSubImage3D(\n\t\t\t\t\tthis.gl.TEXTURE_2D_ARRAY,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\tinfo.history.writeIndex,\n\t\t\t\t\twidth,\n\t\t\t\t\theight,\n\t\t\t\t\t1,\n\t\t\t\t\tinfo.options.format,\n\t\t\t\t\tinfo.options.type,\n\t\t\t\t\t((nonShaderPadSource as PartialCustomTexture).data ??\n\t\t\t\t\t\t(nonShaderPadSource as Exclude<TextureSource, CustomTexture | ShaderPad>)) as any\n\t\t\t\t);\n\t\t\t\tthis.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, previousFlipY);\n\t\t\t\tconst frameOffsetUniformName = `${stringFrom(name)}FrameOffset`;\n\t\t\t\tthis.updateUniforms({ [frameOffsetUniformName]: info.history.writeIndex });\n\t\t\t\tinfo.history.writeIndex = (info.history.writeIndex + 1) % info.history.depth;\n\t\t\t}\n\t\t} else {\n\t\t\tthis.gl.activeTexture(this.gl.TEXTURE0 + info.unitIndex);\n\t\t\tthis.gl.bindTexture(this.gl.TEXTURE_2D, info.texture);\n\t\t\tthis.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, shouldFlipY);\n\n\t\t\tif (isPartial) {\n\t\t\t\tconst partialSource = nonShaderPadSource as PartialCustomTexture;\n\t\t\t\tthis.gl.texSubImage2D(\n\t\t\t\t\tthis.gl.TEXTURE_2D,\n\t\t\t\t\t0,\n\t\t\t\t\tpartialSource.x ?? 0,\n\t\t\t\t\tpartialSource.y ?? 0,\n\t\t\t\t\twidth,\n\t\t\t\t\theight,\n\t\t\t\t\tinfo.options.format,\n\t\t\t\t\tinfo.options.type,\n\t\t\t\t\tpartialSource.data\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tthis.gl.texImage2D(\n\t\t\t\t\tthis.gl.TEXTURE_2D,\n\t\t\t\t\t0,\n\t\t\t\t\tinfo.options.internalFormat,\n\t\t\t\t\twidth,\n\t\t\t\t\theight,\n\t\t\t\t\t0,\n\t\t\t\t\tinfo.options.format,\n\t\t\t\t\tinfo.options.type,\n\t\t\t\t\t((nonShaderPadSource as PartialCustomTexture).data ??\n\t\t\t\t\t\t(nonShaderPadSource as Exclude<TextureSource, CustomTexture | ShaderPad>)) as any\n\t\t\t\t);\n\t\t\t}\n\t\t\tthis.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, previousFlipY);\n\t\t}\n\t}\n\n\tdraw(options?: StepOptions) {\n\t\tthis.emitHook('beforeDraw', ...arguments);\n\t\tconst gl = this.gl;\n\t\tconst w = gl.drawingBufferWidth;\n\t\tconst h = gl.drawingBufferHeight;\n\t\tconst intermediateInfo = this.textures.get(INTERMEDIATE_TEXTURE_KEY)!;\n\t\tgl.bindFramebuffer(gl.FRAMEBUFFER, this.intermediateFbo);\n\t\tgl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, intermediateInfo.texture, 0);\n\n\t\tgl.useProgram(this.program);\n\t\tgl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);\n\t\tgl.vertexAttribPointer(this.aPositionLocation, 2, gl.FLOAT, false, 0, 0);\n\t\tgl.enableVertexAttribArray(this.aPositionLocation);\n\t\tgl.viewport(0, 0, w, h);\n\t\tif (!options?.skipClear) gl.clear(gl.COLOR_BUFFER_BIT);\n\t\tgl.drawArrays(gl.TRIANGLES, 0, 6);\n\n\t\tconst historyInfo = this.textures.get(HISTORY_TEXTURE_KEY);\n\t\tif (historyInfo && !options?.skipHistoryWrite) {\n\t\t\tgl.bindTexture(gl.TEXTURE_2D_ARRAY, historyInfo.texture);\n\t\t\tgl.copyTexSubImage3D(gl.TEXTURE_2D_ARRAY, 0, 0, 0, historyInfo.history!.writeIndex, 0, 0, w, h);\n\t\t}\n\n\t\tgl.bindFramebuffer(gl.READ_FRAMEBUFFER, this.intermediateFbo);\n\t\tgl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null);\n\t\tgl.blitFramebuffer(0, 0, w, h, 0, 0, w, h, gl.COLOR_BUFFER_BIT, gl.NEAREST);\n\t\tgl.bindFramebuffer(gl.FRAMEBUFFER, null);\n\t\tthis.emitHook('afterDraw', ...arguments);\n\t}\n\n\tstep(time: number, options?: StepOptions) {\n\t\tthis.emitHook('beforeStep', ...arguments);\n\t\tconst updates: Record<string, number> = {};\n\t\tif (this.uniforms.has('u_time')) updates.u_time = time;\n\t\tif (this.uniforms.has('u_frame')) updates.u_frame = this.frame;\n\t\tthis.updateUniforms(updates);\n\t\tthis.draw(options);\n\t\tconst historyInfo = this.textures.get(HISTORY_TEXTURE_KEY);\n\t\tif (historyInfo && !options?.skipHistoryWrite) {\n\t\t\tconst { writeIndex, depth } = historyInfo.history!;\n\t\t\tthis.updateUniforms({ [`${stringFrom(HISTORY_TEXTURE_KEY)}FrameOffset`]: writeIndex });\n\t\t\thistoryInfo.history!.writeIndex = (writeIndex + 1) % depth;\n\t\t}\n\t\t++this.frame;\n\t\tthis.emitHook('afterStep', ...arguments);\n\t}\n\n\tplay(\n\t\tonStepComplete?: (time: number, frame: number) => void,\n\t\tsetStepOptions?: (time: number, frame: number) => StepOptions | void\n\t) {\n\t\tthis.pause(); // Prevent double play.\n\t\tconst loop = (time: number) => {\n\t\t\ttime = (time - this.startTime) / 1000; // Convert from milliseconds to seconds.\n\t\t\tconst options = setStepOptions?.(time, this.frame) ?? undefined;\n\t\t\tthis.step(time, options);\n\t\t\tthis.animationFrameId = requestAnimationFrame(loop);\n\t\t\tonStepComplete?.(time, this.frame);\n\t\t};\n\t\tthis.animationFrameId = requestAnimationFrame(loop);\n\t\tthis.emitHook('play');\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\tthis.emitHook('pause');\n\t}\n\n\treset() {\n\t\tthis.frame = 0;\n\t\tthis.startTime = performance.now();\n\t\tthis.textures.forEach(texture => {\n\t\t\tif (texture.history) {\n\t\t\t\ttexture.history.writeIndex = 0;\n\t\t\t\tthis.clearHistoryTextureLayers(texture);\n\t\t\t}\n\t\t});\n\t\tthis.emitHook('reset');\n\t}\n\n\tdestroy() {\n\t\tthis.emitHook('destroy');\n\t\tif (this.animationFrameId) {\n\t\t\tcancelAnimationFrame(this.animationFrameId);\n\t\t\tthis.animationFrameId = null;\n\t\t}\n\n\t\tthis.resolutionObserver.disconnect();\n\t\tthis.resizeObserver.disconnect();\n\t\tif (this.canvas instanceof HTMLCanvasElement) {\n\t\t\tthis.eventListeners.forEach((listener, event) => {\n\t\t\t\tthis.canvas.removeEventListener(event, listener);\n\t\t\t});\n\t\t}\n\n\t\tif (this.program) {\n\t\t\tthis.gl.deleteProgram(this.program);\n\t\t}\n\n\t\tif (this.intermediateFbo) {\n\t\t\tthis.gl.deleteFramebuffer(this.intermediateFbo);\n\t\t\tthis.intermediateFbo = null;\n\t\t}\n\n\t\tthis.textures.forEach(texture => {\n\t\t\tthis.gl.deleteTexture(texture.texture);\n\t\t});\n\t\tthis.textureUnitPool.free = [];\n\t\tthis.textureUnitPool.next = 0;\n\n\t\tif (this.buffer) {\n\t\t\tthis.gl.deleteBuffer(this.buffer);\n\t\t\tthis.buffer = null;\n\t\t}\n\n\t\tif (this.isInternalCanvas && this.canvas instanceof HTMLCanvasElement) {\n\t\t\tthis.canvas.remove();\n\t\t}\n\t}\n}\n\nexport default ShaderPad;\n"],"mappings":"AAAA,IAAMA,EAA4B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAO5BC,EAA2B,mBAC3BC,EAAgB,IAAI,aAAa,CAAC,GAAI,GAAI,EAAG,GAAI,GAAI,EAAG,GAAI,EAAG,EAAG,GAAI,EAAG,CAAC,CAAC,EAuG3EC,EAAsB,OAAO,WAAW,EACxCC,EAA2B,OAAO,oBAAoB,EAE5D,SAASC,EAAkBC,EAAgBC,EAA8B,CACxE,GAAI,CAACA,GAAY,OAAQ,OAAOD,EAChC,IAAME,EAAQF,EAAO,MAAM;AAAA,CAAI,EACzBG,EACLD,EAAM,cAAcE,GAAQ,CAC3B,IAAMC,EAAUD,EAAK,UAAU,EAC/B,OAAOC,EAAQ,WAAW,YAAY,GAAKA,EAAQ,WAAW,WAAW,CAC1E,CAAC,EAAI,EACN,OAAAH,EAAM,OAAOC,EAAU,EAAG,GAAGF,CAAU,EAChCC,EAAM,KAAK;AAAA,CAAI,CACvB,CAEA,SAASI,EAAoBC,EAA0D,CACtF,OAAIA,aAAkB,aACd,CAAE,MAAO,EAAG,OAAQ,CAAE,EAE1BA,aAAkBC,EACd,CAAE,MAAOD,EAAO,OAAO,MAAO,OAAQA,EAAO,OAAO,MAAO,EAE/DA,aAAkB,iBACd,CAAE,MAAOA,EAAO,WAAY,OAAQA,EAAO,WAAY,EAE3DA,aAAkB,iBACd,CAAE,MAAOA,EAAO,cAAgBA,EAAO,MAAO,OAAQA,EAAO,eAAiBA,EAAO,MAAO,EAG7F,CAAE,MAAOA,EAAO,MAAO,OAAQA,EAAO,MAAO,CACrD,CAEA,SAASE,EAAWC,EAAuB,CAC1C,OAAO,OAAOA,GAAS,SAAWA,EAAK,aAAe,GAAKA,CAC5D,CAEA,IAAMF,EAAN,MAAMG,CAAU,CACP,iBAAmB,GACnB,cAAgB,GAChB,GACA,SAAiC,IAAI,IACrC,SAA0C,IAAI,IAC9C,gBACA,OAA6B,KAC7B,QAA+B,KAC/B,kBAAoB,EACpB,iBACA,mBACA,eACA,cAA+C,KAC/C,eAAiB,KACjB,eAA6C,IAAI,IACjD,MAAQ,EACR,UAAY,EACZ,eAAiB,CAAC,GAAK,EAAG,EAC1B,cAAgB,CAAC,GAAK,EAAG,EACzB,YAAc,GACf,OACC,MAA0C,IAAI,IAC9C,aAAe,EACf,eACA,MAGA,gBAA2C,KAEnD,YAAYC,EAA2B,CAAE,OAAAC,EAAQ,QAAAC,EAAS,QAAAC,EAAS,MAAAC,EAAO,GAAGC,CAAe,EAAa,CAAC,EAAG,CAE5G,GADA,KAAK,OAASJ,GAAU,SAAS,cAAc,QAAQ,EACnD,CAACA,EAAQ,CACZ,KAAK,iBAAmB,GACxB,IAAMK,EAAa,KAAK,OACxBA,EAAW,MAAM,SAAW,QAC5BA,EAAW,MAAM,MAAQ,IACzBA,EAAW,MAAM,OAAS,SAC1BA,EAAW,MAAM,MAAQ,SACzB,SAAS,KAAK,YAAYA,CAAU,CACrC,CACA,GAAI,KAAK,kBAAkB,gBAAiB,CAC3C,IAAMC,EAAiBC,GAAkC,CACxD,IAAMC,EAAa,OAAO,yBAAyB,gBAAgB,UAAWD,CAAS,EACvF,OAAO,eAAe,KAAK,OAAQA,EAAW,CAC7C,IAAK,IAAMC,EAAW,IAAK,KAAK,KAAK,MAAM,EAC3C,IAAKC,GAAK,CACTD,EAAW,IAAK,KAAK,KAAK,OAAQC,CAAC,EACnC,KAAK,iBAAiB,CACvB,EACA,aAAcD,EAAW,aACzB,WAAYA,EAAW,UACxB,CAAC,CACF,EACAF,EAAc,OAAO,EACrBA,EAAc,QAAQ,CACvB,CAEA,IAAMI,EAAK,KAAK,OAAO,WAAW,SAAU,CAAE,UAAW,EAAM,CAAC,EAChE,GAAI,CAACA,EACJ,MAAM,IAAI,MAAM,kEAAkE,EAEnF,KAAK,GAAKA,EAEV,KAAK,gBAAkB,CACtB,KAAM,CAAC,EACP,KAAM,EACN,IAAKA,EAAG,aAAaA,EAAG,gCAAgC,CACzD,EACA,KAAK,eAAiBN,EAEtB,GAAM,CAAE,eAAAO,EAAgB,KAAAC,CAAK,EAAIR,GAEhCQ,IAASF,EAAG,OACZE,IAASF,EAAG,YACZC,IAAmBD,EAAG,SACtBC,IAAmBD,EAAG,SACtBC,IAAmBD,EAAG,MACtBC,IAAmBD,EAAG,MACtBC,IAAmBD,EAAG,OACtBC,IAAmBD,EAAG,QACF,CAACA,EAAG,aAAa,wBAAwB,IAC7D,QAAQ,KAAK,6DAA6D,EAC1E,OAAO,KAAK,gBAAgB,eAC5B,OAAO,KAAK,gBAAgB,OAC5B,OAAO,KAAK,gBAAgB,MAGzBR,IAAS,KAAK,aAAeA,GACjC,KAAK,MAAQC,IAAU,OAAO,QAAY,KAAe,IACzD,KAAK,iBAAmB,KACxB,KAAK,mBAAqB,IAAI,iBAAiB,IAAM,KAAK,iBAAiB,CAAC,EAC5E,KAAK,eAAiB,IAAI,eAAe,IAAM,KAAK,sBAAsB,CAAC,EAE3E,IAAMU,EAA2B,CAAC,EAC9BZ,GACHA,EAAQ,QAAQa,GACfA,EAAO,KAAM,CACZ,GAAAJ,EACA,OAAQ,KAAK,OACb,WAAaK,GAAiB,CAC7BF,EAAe,KAAKE,CAAI,CACzB,EACA,SAAU,KAAK,SAAS,KAAK,IAAI,CAClC,CAAC,CACF,EAGD,IAAMC,EAAU,KAAK,GAAG,cAAc,EACtC,GAAI,CAACA,EACJ,MAAM,IAAI,MAAM,gCAAgC,EAEjD,KAAK,QAAUA,EAEf,IAAMC,EAAe,KAAK,aAAa,KAAK,GAAG,cAAepC,CAAyB,EACjFqC,EAAiB,KAAK,aAC3BR,EAAG,gBACHxB,EAAkBa,EAAmBc,CAAc,CACpD,EAOA,GANAH,EAAG,aAAaM,EAASC,CAAY,EACrCP,EAAG,aAAaM,EAASE,CAAc,EACvCR,EAAG,YAAYM,CAAO,EACtBN,EAAG,aAAaO,CAAY,EAC5BP,EAAG,aAAaQ,CAAc,EAE1B,CAACR,EAAG,oBAAoBM,EAASN,EAAG,WAAW,EAClD,cAAQ,MAAM,sBAAuBA,EAAG,kBAAkBM,CAAO,CAAC,EAClEN,EAAG,cAAcM,CAAO,EAClB,IAAI,MAAM,8BAA8B,EAG/C,KAAK,kBAAoBN,EAAG,kBAAkBM,EAAS,WAAW,EAClE,KAAK,OAASN,EAAG,aAAa,EAC9BA,EAAG,WAAWA,EAAG,aAAc,KAAK,MAAM,EAC1CA,EAAG,WAAWA,EAAG,aAAc3B,EAAe2B,EAAG,WAAW,EAC5DA,EAAG,SAAS,EAAG,EAAGA,EAAG,mBAAoBA,EAAG,mBAAmB,EAC/DA,EAAG,wBAAwB,KAAK,iBAAiB,EACjDA,EAAG,oBAAoB,KAAK,kBAAmB,EAAGA,EAAG,MAAO,GAAO,EAAG,CAAC,EAEvEA,EAAG,WAAWM,CAAO,EAEjB,KAAK,kBAAkB,oBAC1B,KAAK,mBAAmB,QAAQ,KAAK,OAAQ,CAAE,WAAY,GAAM,gBAAiB,CAAC,QAAS,QAAQ,CAAE,CAAC,EACvG,KAAK,eAAe,QAAQ,KAAK,MAAM,GAEnC,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,mBAAmB/B,EAA0B,KAAK,OAAQ,CAC9D,GAAG,KAAK,cACT,CAAC,EACD,KAAK,gBAAkByB,EAAG,kBAAkB,EAExC,KAAK,aAAe,GACvB,KAAK,mBAAmB1B,EAAqB,KAAK,OAAQ,CACzD,QAAS,KAAK,aACd,GAAG,KAAK,cACT,CAAC,EAEE,KAAK,kBAAkB,mBAC1B,KAAK,kBAAkB,EAExB,KAAK,SAAS,MAAM,CACrB,CAEQ,SAASa,KAA0BsB,EAAa,CACvD,KAAK,MAAM,IAAItB,CAAI,GAAG,QAAQuB,GAAQA,EAAK,KAAK,KAAM,GAAGD,CAAI,CAAC,CAC/D,CAEA,GAAGtB,EAAuBwB,EAAc,CAClC,KAAK,MAAM,IAAIxB,CAAI,GACvB,KAAK,MAAM,IAAIA,EAAM,CAAC,CAAC,EAExB,KAAK,MAAM,IAAIA,CAAI,EAAG,KAAKwB,CAAE,CAC9B,CAEA,IAAIxB,EAAuBwB,EAAc,CACxC,IAAMC,EAAQ,KAAK,MAAM,IAAIzB,CAAI,EAC7ByB,GACHA,EAAM,OAAOA,EAAM,QAAQD,CAAE,EAAG,CAAC,CAEnC,CAEQ,aAAaT,EAAclB,EAA6B,CAC/D,IAAMP,EAAS,KAAK,GAAG,aAAayB,CAAI,EAGxC,GAFA,KAAK,GAAG,aAAazB,EAAQO,CAAM,EACnC,KAAK,GAAG,cAAcP,CAAM,EACxB,CAAC,KAAK,GAAG,mBAAmBA,EAAQ,KAAK,GAAG,cAAc,EAC7D,cAAQ,MAAM,6BAA8BO,CAAM,EAClD,QAAQ,MAAM,KAAK,GAAG,iBAAiBP,CAAM,CAAC,EAC9C,KAAK,GAAG,aAAaA,CAAM,EACrB,IAAI,MAAM,2BAA2B,EAE5C,OAAOA,CACR,CAEQ,uBAAwB,CAC/B,aAAa,KAAK,aAAa,EAC/B,IAAMoC,EAAM,YAAY,IAAI,EACtBC,EAAsB,KAAK,eAAiB1C,EAA2ByC,EACzEC,GAAuB,GAC1B,KAAK,eAAiBD,EACtB,KAAK,aAAa,GAElB,KAAK,cAAgB,WAAW,IAAM,KAAK,sBAAsB,EAAGC,CAAmB,CAEzF,CAEQ,cAAe,CACtB,GAAI,EAAE,KAAK,kBAAkB,mBAAoB,OACjD,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,SAAS,SAAUD,EAAOC,CAAM,CACtC,CAEQ,mBAAoB,CAC3B,IAAMtB,EAAa,KAAK,OAClBuB,EAAe,CAACC,EAAWC,IAAc,CAC9C,GAAI,CAAC,KAAK,SAAS,IAAI,UAAU,EAAG,OACpC,IAAMC,EAAO1B,EAAW,sBAAsB,EAC9C,KAAK,eAAe,CAAC,GAAKwB,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,EAAO1B,EAAW,sBAAsB,EACxC6B,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/B,EAAW,iBAAiB+B,EAAOG,CAAQ,CAC5C,CAAC,CACF,CAEQ,kBAAmB,CAC1B,IAAMC,EAA+B,CAAC,KAAK,GAAG,mBAAoB,KAAK,GAAG,mBAAmB,EAC7F,KAAK,GAAG,SAAS,EAAG,EAAG,GAAGA,CAAU,EAChC,KAAK,SAAS,IAAI,cAAc,EACnC,KAAK,eAAe,CAAE,aAAcA,CAAW,CAAC,EAEhD,KAAK,kBAAkB,eAAgB,QAASA,CAAU,EAE3D,KAAK,cAAcvD,EAA0B,GAAGuD,CAAU,EACtD,KAAK,aAAe,GACvB,KAAK,cAAcxD,EAAqB,GAAGwD,CAAU,EAEtD,KAAK,SAAS,mBAAoB,GAAGA,CAAU,CAChD,CAEQ,cAAc3C,EAAuB6B,EAAeC,EAAgB,CAC3E,IAAMc,EAAO,KAAK,SAAS,IAAI5C,CAAI,EACnC,GAAI,CAAC4C,GAASA,EAAK,QAAUf,GAASe,EAAK,SAAWd,EAAS,OAE/D,KAAK,GAAG,cAAcc,EAAK,OAAO,EAClCA,EAAK,MAAQf,EACbe,EAAK,OAASd,EACd,GAAM,CAAE,QAAAe,CAAQ,EAAI,KAAK,cAAc7C,EAAM4C,CAAI,EACjDA,EAAK,QAAUC,EACXD,EAAK,UACRA,EAAK,QAAQ,WAAa,EAC1B,KAAK,0BAA0BA,CAAI,EAErC,CAEQ,mBAAmB5C,EAAuB,CACjD,IAAM8C,EAAW,KAAK,SAAS,IAAI9C,CAAI,EACvC,GAAI8C,EAAU,OAAOA,EAAS,UAC9B,GAAI,KAAK,gBAAgB,KAAK,OAAS,EAAG,OAAO,KAAK,gBAAgB,KAAK,IAAI,EAC/E,GAAI,KAAK,gBAAgB,MAAQ,KAAK,gBAAgB,IACrD,MAAM,IAAI,MAAM,uDAAuD,EAExE,OAAO,KAAK,gBAAgB,MAC7B,CAEQ,mBAAmB9C,EAAuB,CACjD,IAAM8C,EAAW,KAAK,SAAS,IAAI9C,CAAI,EACnC8C,GACH,KAAK,gBAAgB,KAAK,KAAKA,EAAS,SAAS,CAEnD,CAEQ,sBAAsBC,EAAkD,CAC/E,GAAM,CAAE,GAAAlC,CAAG,EAAI,KACTE,EAAOgC,GAAS,MAAQlC,EAAG,cACjC,MAAO,CACN,KAAAE,EACA,OAAQgC,GAAS,QAAUlC,EAAG,KAC9B,eACCkC,GAAS,iBACRhC,IAASF,EAAG,MAAQA,EAAG,QAAUE,IAASF,EAAG,WAAaA,EAAG,QAAUA,EAAG,OAC5E,UAAWkC,GAAS,WAAalC,EAAG,OACpC,UAAWkC,GAAS,WAAalC,EAAG,OACpC,MAAOkC,GAAS,OAASlC,EAAG,cAC5B,MAAOkC,GAAS,OAASlC,EAAG,cAC5B,UAAWkC,GAAS,SACrB,CACD,CAEQ,cAAchC,EAAciC,EAA+B,CAClE,OAAOjC,IAAS,KAAK,GAAG,MACrB,IAAI,aAAaiC,CAAI,EACrBjC,IAAS,KAAK,GAAG,WACjB,IAAI,YAAYiC,CAAI,EACpB,IAAI,WAAWA,CAAI,CACvB,CAEQ,0BAA0BC,EAA4B,CAC7D,GAAI,CAACA,EAAY,QAAS,OAE1B,IAAMpC,EAAK,KAAK,GACV,CAAE,KAAAE,EAAM,OAAAmC,CAAO,EAAID,EAAY,QAC/BE,EAAc,KAAK,cAAcpC,EAAMkC,EAAY,MAAQA,EAAY,OAAS,CAAC,EACvFpC,EAAG,cAAcA,EAAG,SAAWoC,EAAY,SAAS,EACpDpC,EAAG,YAAYA,EAAG,iBAAkBoC,EAAY,OAAO,EACvD,QAASG,EAAQ,EAAGA,EAAQH,EAAY,QAAQ,MAAO,EAAEG,EACxDvC,EAAG,cACFA,EAAG,iBACH,EACA,EACA,EACAuC,EACAH,EAAY,MACZA,EAAY,OACZ,EACAC,EACAnC,EACAoC,CACD,CAEF,CAEA,kBACCnD,EACAe,EACAsC,EACAN,EACC,CACD,IAAMO,EAAcP,GAAS,YAC7B,GAAI,KAAK,SAAS,IAAI/C,CAAI,EACzB,MAAM,IAAI,MAAM,GAAGA,CAAI,0BAA0B,EAElD,GAAIe,IAAS,SAAWA,IAAS,MAChC,MAAM,IAAI,MAAM,yBAAyBA,CAAI,8BAA8B,EAE5E,GAAIuC,GAAe,EAAE,MAAM,QAAQD,CAAK,GAAKA,EAAM,SAAWC,GAC7D,MAAM,IAAI,MAAM,GAAGtD,CAAI,gDAAgDsD,CAAW,YAAY,EAG/F,IAAIC,EAAW,KAAK,GAAG,mBAAmB,KAAK,QAAUvD,CAAI,EAI7D,GAHI,CAACuD,GAAYD,IAChBC,EAAW,KAAK,GAAG,mBAAmB,KAAK,QAAU,GAAGvD,CAAI,KAAK,GAE9D,CAACuD,EAAU,CACd,KAAK,IAAI,GAAGvD,CAAI,0CAA0C,EAC1D,MACD,CAEA,IAAMwD,EAAaF,EAAeD,EAAgC,CAAC,EAAIA,EACjEI,EAAS,MAAM,QAAQD,CAAU,EAAKA,EAAW,OAA2B,EAClF,KAAK,SAAS,IAAIxD,EAAM,CAAE,KAAAe,EAAM,OAAA0C,EAAQ,SAAAF,EAAU,YAAAD,CAAY,CAAC,EAE/D,GAAI,CACH,KAAK,eAAe,CAAE,CAACtD,CAAI,EAAGqD,CAAM,CAAC,CACtC,OAASK,EAAO,CACf,WAAK,SAAS,OAAO1D,CAAI,EACnB0D,CACP,CACA,KAAK,SAAS,oBAAqB,GAAG,SAAS,CAChD,CAEQ,OAAOpC,EAAa,CACvB,KAAK,OAAO,QAAQ,MAAM,GAAGA,CAAI,CACtC,CAEA,eACCqC,EACAZ,EACC,CACD,KAAK,GAAG,WAAW,KAAK,OAAO,EAC/B,OAAO,QAAQY,CAAO,EAAE,QAAQ,CAAC,CAAC3D,EAAM4D,CAAQ,IAAM,CACrD,IAAMC,EAAU,KAAK,SAAS,IAAI7D,CAAI,EACtC,GAAI,CAAC6D,EAAS,CACb,KAAK,IAAI,GAAG7D,CAAI,kCAAkC,EAClD,MACD,CAEA,IAAI8D,EAAiB,UAAUD,EAAQ,MAAM,GAAGA,EAAQ,KAAK,OAAO,CAAC,CAAC,GACtE,GAAIA,EAAQ,YAAa,CACxB,GAAI,CAAC,MAAM,QAAQD,CAAQ,EAC1B,MAAM,IAAI,MAAM,GAAG5D,CAAI,uEAAuE,EAE/F,IAAM+D,EAAUH,EAAS,OACzB,GAAI,CAACG,EAAS,OACd,GAAIA,EAAUF,EAAQ,YACrB,MAAM,IAAI,MACT,GAAG7D,CAAI,aAAa+D,CAAO,kCAAkCF,EAAQ,WAAW,GACjF,EAED,GAAID,EAAS,KAAKI,IAAS,MAAM,QAAQA,CAAI,EAAIA,EAAK,OAAS,KAAOH,EAAQ,MAAM,EACnF,MAAM,IAAI,MACT,mBAAmB7D,CAAI,2CAA2C6D,EAAQ,MAAM,GACjF,EAED,IAAMI,EAAa,IAAKJ,EAAQ,OAAS,QAAU,aAAe,YAAYD,EAAS,KAAK,CAAC,EACzFL,EAAWM,EAAQ,SACvB,GAAId,GAAS,WAAY,CACxB,IAAMmB,EAAc,KAAK,GAAG,mBAAmB,KAAK,QAAU,GAAGlE,CAAI,IAAI+C,EAAQ,UAAU,GAAG,EAC9F,GAAI,CAACmB,EACJ,MAAM,IAAI,MACT,GAAGlE,CAAI,IAAI+C,EAAQ,UAAU,sDAC9B,EAEDQ,EAAWW,CACZ,CACC,KAAK,GAAWJ,EAAiB,GAAG,EAAEP,EAAUU,CAAU,CAC5D,KAAO,CAEN,GADK,MAAM,QAAQL,CAAQ,IAAGA,EAAW,CAACA,CAAQ,GAC9CA,EAAS,SAAWC,EAAQ,OAC/B,MAAM,IAAI,MAAM,iCAAiCD,EAAS,MAAM,cAAcC,EAAQ,MAAM,GAAG,EAE/F,KAAK,GAAWC,CAAc,EAAED,EAAQ,SAAU,GAAGD,CAAQ,CAC/D,CACD,CAAC,EACD,KAAK,SAAS,iBAAkB,GAAG,SAAS,CAC7C,CAEQ,cACP5D,EACAiD,EACC,CACD,GAAM,CAAE,MAAApB,EAAO,OAAAC,CAAO,EAAImB,EACpBkB,EAAelB,EAAY,SAAS,OAAS,EAE7CJ,EAAU,KAAK,GAAG,cAAc,EACtC,GAAI,CAACA,EACJ,MAAM,IAAI,MAAM,0BAA0B,EAG3C,IAAIuB,EAAYnB,EAAY,UAC5B,GAAI,OAAOmB,GAAc,SACxB,GAAI,CACHA,EAAY,KAAK,mBAAmBpE,CAAI,CACzC,OAAS0D,EAAO,CACf,WAAK,GAAG,cAAcb,CAAO,EACvBa,CACP,CAGD,IAAMW,EAAaF,EAAe,EAC5BG,EAAgBD,EAAa,KAAK,GAAG,iBAAmB,KAAK,GAAG,WAChE,CAAE,QAAAtB,CAAQ,EAAIE,EACpB,YAAK,GAAG,cAAc,KAAK,GAAG,SAAWmB,CAAS,EAClD,KAAK,GAAG,YAAYE,EAAezB,CAAO,EAC1C,KAAK,GAAG,cAAcyB,EAAe,KAAK,GAAG,eAAgBvB,EAAQ,KAAK,EAC1E,KAAK,GAAG,cAAcuB,EAAe,KAAK,GAAG,eAAgBvB,EAAQ,KAAK,EAC1E,KAAK,GAAG,cAAcuB,EAAe,KAAK,GAAG,mBAAoBvB,EAAQ,SAAS,EAClF,KAAK,GAAG,cAAcuB,EAAe,KAAK,GAAG,mBAAoBvB,EAAQ,SAAS,EAC9EsB,EACH,KAAK,GAAG,aAAaC,EAAe,EAAGvB,EAAQ,eAAgBlB,EAAOC,EAAQqC,CAAY,EAChFnE,IAASZ,GACnB,KAAK,GAAG,WACP,KAAK,GAAG,WACR,EACA2D,EAAQ,eACRlB,EACAC,EACA,EACAiB,EAAQ,OACRA,EAAQ,KACR,IACD,EAEM,CAAE,QAAAF,EAAS,UAAAuB,CAAU,CAC7B,CAEQ,mBACPpE,EACAH,EACAkD,EACC,CACD,GAAI,KAAK,SAAS,IAAI/C,CAAI,EACzB,MAAM,IAAI,MAAM,YAAYD,EAAWC,CAAI,CAAC,2BAA2B,EAGxE,GAAM,CAAE,QAASmE,EAAe,EAAG,GAAG5D,CAAe,EAAIwC,GAAW,CAAC,EAC/D,CAAE,MAAAlB,EAAO,OAAAC,CAAO,EAAIlC,EAAoBC,CAAM,EACpD,GAAI,CAACgC,GAAS,CAACC,EACd,MAAM,IAAI,MAAM,2CAA2C,EAE5D,IAAMmB,EAAyE,CAC9E,MAAApB,EACA,OAAAC,EACA,QAAS,KAAK,sBAAsBvB,CAAc,CACnD,EACI4D,EAAe,IAClBlB,EAAY,QAAU,CAAE,MAAOkB,EAAc,WAAY,CAAE,GAE5D,GAAM,CAAE,QAAAtB,EAAS,UAAAuB,CAAU,EAAI,KAAK,cAAcpE,EAAMiD,CAAW,EAC7DsB,EAA+B,CAAE,QAAA1B,EAAS,UAAAuB,EAAW,GAAGnB,CAAY,EACtEkB,EAAe,IAClB,KAAK,kBAAkB,GAAGpE,EAAWC,CAAI,CAAC,cAAe,MAAO,CAAC,EACjE,KAAK,0BAA0BuE,CAAmB,GAEnD,KAAK,SAAS,IAAIvE,EAAMuE,CAAmB,EAC3C,KAAK,cAAcvE,EAAMH,CAAM,EAG/B,IAAM2E,EAAW,KAAK,GAAG,mBAAmB,KAAK,QAAUzE,EAAWC,CAAI,CAAC,EACvEwE,GACH,KAAK,GAAG,UAAUA,EAAUJ,CAAS,CAEvC,CAEA,kBAAkBpE,EAAcH,EAAuBkD,EAAiD,CACvG,KAAK,mBAAmB/C,EAAMH,EAAQkD,CAAO,EAC7C,KAAK,SAAS,oBAAqB,GAAG,SAAS,CAChD,CAEA,eAAeY,EAA8CZ,EAA0C,CACtG,OAAO,QAAQY,CAAO,EAAE,QAAQ,CAAC,CAAC3D,EAAMH,CAAM,IAAM,CACnD,KAAK,cAAcG,EAAMH,EAAQkD,CAAO,CACzC,CAAC,EACD,KAAK,SAAS,iBAAkB,GAAG,SAAS,CAC7C,CAEQ,cACP/C,EACAH,EACAkD,EACC,CACD,IAAMH,EAAO,KAAK,SAAS,IAAI5C,CAAI,EACnC,GAAI,CAAC4C,EAAM,MAAM,IAAI,MAAM,YAAY7C,EAAWC,CAAI,CAAC,uBAAuB,EAE9E,GAAIH,aAAkB,aAAc,CACnC,KAAK,GAAG,cAAc,KAAK,GAAG,SAAW+C,EAAK,SAAS,EACvD,KAAK,GAAG,YAAY,KAAK,GAAG,WAAY/C,CAAM,EAC9C,MACD,CAEA,IAAI4E,EAAqB5E,EACzB,GAAIA,aAAkBI,EAAW,CAChC,IAAMyE,EAAyB7E,EAAO,SAAS,IAAIT,CAAwB,EAE3E,GAAIS,EAAO,KAAO,KAAK,GAAI,CAC1B,KAAK,GAAG,cAAc,KAAK,GAAG,SAAW+C,EAAK,SAAS,EACvD,KAAK,GAAG,YAAY,KAAK,GAAG,WAAY8B,EAAuB,OAAO,EACtE,MACD,CAGA,GAAM,CACL,MAAA7C,EACA,OAAAC,EACA,QAAS,CAAE,OAAAoB,EAAQ,KAAAnC,CAAK,CACzB,EAAI2D,EACEC,EAAS,KAAK,cAAc5D,EAAMc,EAAQC,EAAS,CAAC,EAC1DjC,EAAO,GAAG,gBAAgBA,EAAO,GAAG,YAAaA,EAAO,eAAe,EACvEA,EAAO,GAAG,WAAW,EAAG,EAAGgC,EAAOC,EAAQoB,EAAQnC,EAAM4D,CAAM,EAC9D9E,EAAO,GAAG,gBAAgBA,EAAO,GAAG,YAAa,IAAI,EACrD4E,EAAqB,CAAE,KAAME,EAAQ,MAAA9C,EAAO,OAAAC,CAAO,CACpD,CAGA,GAAM,CAAE,MAAAD,EAAO,OAAAC,CAAO,EAAIlC,EAAoB6E,CAAkB,EAChE,GAAI,CAAC5C,GAAS,CAACC,EAAQ,OAEvB,IAAM8C,EAAY,cAAeH,GAAsBA,EAAmB,UACrEG,GACJ,KAAK,cAAc5E,EAAM6B,EAAOC,CAAM,EAKvC,IAAM+C,EAAc,EADC,SAAUJ,GAAsBA,EAAmB,OACnC,CAAC7B,EAAK,SAAS,UAC9CkC,EAAgB,KAAK,GAAG,aAAa,KAAK,GAAG,mBAAmB,EAEtE,GAAIlC,EAAK,SAGR,GAFA,KAAK,GAAG,cAAc,KAAK,GAAG,SAAWA,EAAK,SAAS,EACvD,KAAK,GAAG,YAAY,KAAK,GAAG,iBAAkBA,EAAK,OAAO,EACtD,CAACG,GAAS,iBAAkB,CAC/B,KAAK,GAAG,YAAY,KAAK,GAAG,oBAAqB8B,CAAW,EAC5D,KAAK,GAAG,cACP,KAAK,GAAG,iBACR,EACA,EACA,EACAjC,EAAK,QAAQ,WACbf,EACAC,EACA,EACAc,EAAK,QAAQ,OACbA,EAAK,QAAQ,KACX6B,EAA4C,MAC5CA,CACH,EACA,KAAK,GAAG,YAAY,KAAK,GAAG,oBAAqBK,CAAa,EAC9D,IAAMC,EAAyB,GAAGhF,EAAWC,CAAI,CAAC,cAClD,KAAK,eAAe,CAAE,CAAC+E,CAAsB,EAAGnC,EAAK,QAAQ,UAAW,CAAC,EACzEA,EAAK,QAAQ,YAAcA,EAAK,QAAQ,WAAa,GAAKA,EAAK,QAAQ,KACxE,MACM,CAKN,GAJA,KAAK,GAAG,cAAc,KAAK,GAAG,SAAWA,EAAK,SAAS,EACvD,KAAK,GAAG,YAAY,KAAK,GAAG,WAAYA,EAAK,OAAO,EACpD,KAAK,GAAG,YAAY,KAAK,GAAG,oBAAqBiC,CAAW,EAExDD,EAAW,CACd,IAAMI,EAAgBP,EACtB,KAAK,GAAG,cACP,KAAK,GAAG,WACR,EACAO,EAAc,GAAK,EACnBA,EAAc,GAAK,EACnBnD,EACAC,EACAc,EAAK,QAAQ,OACbA,EAAK,QAAQ,KACboC,EAAc,IACf,CACD,MACC,KAAK,GAAG,WACP,KAAK,GAAG,WACR,EACApC,EAAK,QAAQ,eACbf,EACAC,EACA,EACAc,EAAK,QAAQ,OACbA,EAAK,QAAQ,KACX6B,EAA4C,MAC5CA,CACH,EAED,KAAK,GAAG,YAAY,KAAK,GAAG,oBAAqBK,CAAa,CAC/D,CACD,CAEA,KAAK/B,EAAuB,CAC3B,KAAK,SAAS,aAAc,GAAG,SAAS,EACxC,IAAMlC,EAAK,KAAK,GACVoE,EAAIpE,EAAG,mBACPqE,EAAIrE,EAAG,oBACPsE,EAAmB,KAAK,SAAS,IAAI/F,CAAwB,EACnEyB,EAAG,gBAAgBA,EAAG,YAAa,KAAK,eAAe,EACvDA,EAAG,qBAAqBA,EAAG,YAAaA,EAAG,kBAAmBA,EAAG,WAAYsE,EAAiB,QAAS,CAAC,EAExGtE,EAAG,WAAW,KAAK,OAAO,EAC1BA,EAAG,WAAWA,EAAG,aAAc,KAAK,MAAM,EAC1CA,EAAG,oBAAoB,KAAK,kBAAmB,EAAGA,EAAG,MAAO,GAAO,EAAG,CAAC,EACvEA,EAAG,wBAAwB,KAAK,iBAAiB,EACjDA,EAAG,SAAS,EAAG,EAAGoE,EAAGC,CAAC,EACjBnC,GAAS,WAAWlC,EAAG,MAAMA,EAAG,gBAAgB,EACrDA,EAAG,WAAWA,EAAG,UAAW,EAAG,CAAC,EAEhC,IAAMuE,EAAc,KAAK,SAAS,IAAIjG,CAAmB,EACrDiG,GAAe,CAACrC,GAAS,mBAC5BlC,EAAG,YAAYA,EAAG,iBAAkBuE,EAAY,OAAO,EACvDvE,EAAG,kBAAkBA,EAAG,iBAAkB,EAAG,EAAG,EAAGuE,EAAY,QAAS,WAAY,EAAG,EAAGH,EAAGC,CAAC,GAG/FrE,EAAG,gBAAgBA,EAAG,iBAAkB,KAAK,eAAe,EAC5DA,EAAG,gBAAgBA,EAAG,iBAAkB,IAAI,EAC5CA,EAAG,gBAAgB,EAAG,EAAGoE,EAAGC,EAAG,EAAG,EAAGD,EAAGC,EAAGrE,EAAG,iBAAkBA,EAAG,OAAO,EAC1EA,EAAG,gBAAgBA,EAAG,YAAa,IAAI,EACvC,KAAK,SAAS,YAAa,GAAG,SAAS,CACxC,CAEA,KAAKwE,EAActC,EAAuB,CACzC,KAAK,SAAS,aAAc,GAAG,SAAS,EACxC,IAAMY,EAAkC,CAAC,EACrC,KAAK,SAAS,IAAI,QAAQ,IAAGA,EAAQ,OAAS0B,GAC9C,KAAK,SAAS,IAAI,SAAS,IAAG1B,EAAQ,QAAU,KAAK,OACzD,KAAK,eAAeA,CAAO,EAC3B,KAAK,KAAKZ,CAAO,EACjB,IAAMqC,EAAc,KAAK,SAAS,IAAIjG,CAAmB,EACzD,GAAIiG,GAAe,CAACrC,GAAS,iBAAkB,CAC9C,GAAM,CAAE,WAAAuC,EAAY,MAAAC,CAAM,EAAIH,EAAY,QAC1C,KAAK,eAAe,CAAE,CAAC,GAAGrF,EAAWZ,CAAmB,CAAC,aAAa,EAAGmG,CAAW,CAAC,EACrFF,EAAY,QAAS,YAAcE,EAAa,GAAKC,CACtD,CACA,EAAE,KAAK,MACP,KAAK,SAAS,YAAa,GAAG,SAAS,CACxC,CAEA,KACCC,EACAC,EACC,CACD,KAAK,MAAM,EACX,IAAMC,EAAQL,GAAiB,CAC9BA,GAAQA,EAAO,KAAK,WAAa,IACjC,IAAMtC,EAAU0C,IAAiBJ,EAAM,KAAK,KAAK,GAAK,OACtD,KAAK,KAAKA,EAAMtC,CAAO,EACvB,KAAK,iBAAmB,sBAAsB2C,CAAI,EAClDF,IAAiBH,EAAM,KAAK,KAAK,CAClC,EACA,KAAK,iBAAmB,sBAAsBK,CAAI,EAClD,KAAK,SAAS,MAAM,CACrB,CAEA,OAAQ,CACH,KAAK,mBACR,qBAAqB,KAAK,gBAAgB,EAC1C,KAAK,iBAAmB,MAEzB,KAAK,SAAS,OAAO,CACtB,CAEA,OAAQ,CACP,KAAK,MAAQ,EACb,KAAK,UAAY,YAAY,IAAI,EACjC,KAAK,SAAS,QAAQ7C,GAAW,CAC5BA,EAAQ,UACXA,EAAQ,QAAQ,WAAa,EAC7B,KAAK,0BAA0BA,CAAO,EAExC,CAAC,EACD,KAAK,SAAS,OAAO,CACtB,CAEA,SAAU,CACT,KAAK,SAAS,SAAS,EACnB,KAAK,mBACR,qBAAqB,KAAK,gBAAgB,EAC1C,KAAK,iBAAmB,MAGzB,KAAK,mBAAmB,WAAW,EACnC,KAAK,eAAe,WAAW,EAC3B,KAAK,kBAAkB,mBAC1B,KAAK,eAAe,QAAQ,CAACH,EAAUH,IAAU,CAChD,KAAK,OAAO,oBAAoBA,EAAOG,CAAQ,CAChD,CAAC,EAGE,KAAK,SACR,KAAK,GAAG,cAAc,KAAK,OAAO,EAG/B,KAAK,kBACR,KAAK,GAAG,kBAAkB,KAAK,eAAe,EAC9C,KAAK,gBAAkB,MAGxB,KAAK,SAAS,QAAQG,GAAW,CAChC,KAAK,GAAG,cAAcA,EAAQ,OAAO,CACtC,CAAC,EACD,KAAK,gBAAgB,KAAO,CAAC,EAC7B,KAAK,gBAAgB,KAAO,EAExB,KAAK,SACR,KAAK,GAAG,aAAa,KAAK,MAAM,EAChC,KAAK,OAAS,MAGX,KAAK,kBAAoB,KAAK,kBAAkB,mBACnD,KAAK,OAAO,OAAO,CAErB,CACD,EAEO8C,EAAQ7F","names":["DEFAULT_VERTEX_SHADER_SRC","RESIZE_THROTTLE_INTERVAL","QUAD_VERTICES","HISTORY_TEXTURE_KEY","INTERMEDIATE_TEXTURE_KEY","combineShaderCode","shader","injections","lines","insertAt","line","trimmed","getSourceDimensions","source","ShaderPad","stringFrom","name","_ShaderPad","fragmentShaderSrc","canvas","plugins","history","debug","textureOptions","htmlCanvas","wrapDimension","dimension","descriptor","v","gl","internalFormat","type","glslInjections","plugin","code","program","vertexShader","fragmentShader","args","hook","fn","hooks","now","timeUntilNextResize","pixelRatio","width","height","updateCursor","x","y","rect","updateClick","isMouseDown","xVal","yVal","event","mouseEvent","touchEvent","listener","resolution","info","texture","existing","options","size","textureInfo","format","transparent","layer","value","arrayLength","location","probeValue","length","error","updates","newValue","uniform","glFunctionName","nValues","item","typedArray","newLocation","historyDepth","unitIndex","hasHistory","textureTarget","completeTextureInfo","uSampler","nonShaderPadSource","sourceIntermediateInfo","pixels","isPartial","shouldFlipY","previousFlipY","frameOffsetUniformName","partialSource","w","h","intermediateInfo","historyInfo","time","writeIndex","depth","onStepComplete","setStepOptions","loop","index_default"]}
@@ -0,0 +1,7 @@
1
+ var y={data:new Uint8Array(4),width:1,height:1};function h(n){return n instanceof HTMLVideoElement||n instanceof HTMLImageElement||n instanceof HTMLCanvasElement||n instanceof OffscreenCanvas}function $(n){return JSON.stringify(n,Object.keys(n).sort())}function M(n,c,a,i,t=0){let e=1/0,r=-1/0,s=1/0,o=-1/0,m=0,g=0;for(let p of a){let u=(t+c*i+p)*4,l=n[u],x=n[u+1];e=Math.min(e,l),r=Math.max(r,l),s=Math.min(s,x),o=Math.max(o,x),m+=n[u+2],g+=n[u+3]}return[(e+r)/2,(s+o)/2,m/a.length,g/a.length]}var f=null;function b(){return f||(f=import("@mediapipe/tasks-vision").then(({FilesetResolver:n})=>n.forVisionTasks("https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.22-rc.20250304/wasm"))),f}function d(n){return{historyParams:n?", framesAgo":"",fn:n?(i,t,e,r)=>{let s=e.replace(/\w+ /g,""),o=e?`${e}, int framesAgo`:"int framesAgo",m=s?`${s}, 0`:"0";return`${i} ${t}(${o}) {
2
+ ${r}
3
+ }
4
+ ${i} ${t}(${e}) { return ${t}(${m}); }`}:(i,t,e,r)=>`${i} ${t}(${e}) {
5
+ ${r}
6
+ }`}}export{y as a,h as b,$ as c,M as d,b as e,d as f};
7
+ //# sourceMappingURL=chunk-JRSBIGBN.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/plugins/mediapipe-common.ts"],"sourcesContent":["import { TextureSource } from '..';\n\nexport const dummyTexture = { data: new Uint8Array(4), width: 1, height: 1 };\n\nexport type MediaPipeSource = HTMLVideoElement | HTMLImageElement | HTMLCanvasElement | OffscreenCanvas;\n\nexport function isMediaPipeSource(source: TextureSource): source is MediaPipeSource {\n\treturn (\n\t\tsource instanceof HTMLVideoElement ||\n\t\tsource instanceof HTMLImageElement ||\n\t\tsource instanceof HTMLCanvasElement ||\n\t\tsource instanceof OffscreenCanvas\n\t);\n}\n\nexport function hashOptions(options: object): string {\n\treturn JSON.stringify(options, Object.keys(options).sort());\n}\n\nexport function calculateBoundingBoxCenter(\n\tdata: Float32Array,\n\tentityIdx: number,\n\tlandmarkIndices: readonly number[] | number[],\n\tlandmarkCount: number,\n\toffset: number = 0\n): [number, number, number, number] {\n\tlet minX = Infinity,\n\t\tmaxX = -Infinity,\n\t\tminY = Infinity,\n\t\tmaxY = -Infinity,\n\t\tavgZ = 0,\n\t\tavgVisibility = 0;\n\n\tfor (const idx of landmarkIndices) {\n\t\tconst dataIdx = (offset + entityIdx * landmarkCount + idx) * 4;\n\t\tconst x = data[dataIdx];\n\t\tconst y = data[dataIdx + 1];\n\t\tminX = Math.min(minX, x);\n\t\tmaxX = Math.max(maxX, x);\n\t\tminY = Math.min(minY, y);\n\t\tmaxY = Math.max(maxY, y);\n\t\tavgZ += data[dataIdx + 2];\n\t\tavgVisibility += data[dataIdx + 3];\n\t}\n\n\treturn [\n\t\t(minX + maxX) / 2,\n\t\t(minY + maxY) / 2,\n\t\tavgZ / landmarkIndices.length,\n\t\tavgVisibility / landmarkIndices.length,\n\t];\n}\n\nlet filesetPromise: Promise<any> | null = null;\nexport function getSharedFileset(): Promise<any> {\n\tif (!filesetPromise) {\n\t\tfilesetPromise = import('@mediapipe/tasks-vision').then(({ FilesetResolver }) =>\n\t\t\tFilesetResolver.forVisionTasks(\n\t\t\t\t`https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@${__MEDIAPIPE_TASKS_VISION_VERSION__}/wasm`\n\t\t\t)\n\t\t);\n\t}\n\treturn filesetPromise;\n}\n\nexport function generateGLSLFn(history: number | undefined) {\n\tconst historyParams = history ? ', framesAgo' : '';\n\tconst fn = history\n\t\t? (returnType: string, name: string, args: string, body: string) => {\n\t\t\t\tconst argsOnly = args.replace(/\\w+ /g, '');\n\t\t\t\tconst historyArgs = args ? `${args}, int framesAgo` : 'int framesAgo';\n\t\t\t\tconst callArgs = argsOnly ? `${argsOnly}, 0` : '0';\n\t\t\t\treturn `${returnType} ${name}(${historyArgs}) {\\n${body}\\n}\n${returnType} ${name}(${args}) { return ${name}(${callArgs}); }`;\n\t\t }\n\t\t: (returnType: string, name: string, args: string, body: string) =>\n\t\t\t\t`${returnType} ${name}(${args}) {\\n${body}\\n}`;\n\treturn { historyParams, fn };\n}\n"],"mappings":"AAEO,IAAMA,EAAe,CAAE,KAAM,IAAI,WAAW,CAAC,EAAG,MAAO,EAAG,OAAQ,CAAE,EAIpE,SAASC,EAAkBC,EAAkD,CACnF,OACCA,aAAkB,kBAClBA,aAAkB,kBAClBA,aAAkB,mBAClBA,aAAkB,eAEpB,CAEO,SAASC,EAAYC,EAAyB,CACpD,OAAO,KAAK,UAAUA,EAAS,OAAO,KAAKA,CAAO,EAAE,KAAK,CAAC,CAC3D,CAEO,SAASC,EACfC,EACAC,EACAC,EACAC,EACAC,EAAiB,EACkB,CACnC,IAAIC,EAAO,IACVC,EAAO,KACPC,EAAO,IACPC,EAAO,KACPC,EAAO,EACPC,EAAgB,EAEjB,QAAWC,KAAOT,EAAiB,CAClC,IAAMU,GAAWR,EAASH,EAAYE,EAAgBQ,GAAO,EACvDE,EAAIb,EAAKY,CAAO,EAChBE,EAAId,EAAKY,EAAU,CAAC,EAC1BP,EAAO,KAAK,IAAIA,EAAMQ,CAAC,EACvBP,EAAO,KAAK,IAAIA,EAAMO,CAAC,EACvBN,EAAO,KAAK,IAAIA,EAAMO,CAAC,EACvBN,EAAO,KAAK,IAAIA,EAAMM,CAAC,EACvBL,GAAQT,EAAKY,EAAU,CAAC,EACxBF,GAAiBV,EAAKY,EAAU,CAAC,CAClC,CAEA,MAAO,EACLP,EAAOC,GAAQ,GACfC,EAAOC,GAAQ,EAChBC,EAAOP,EAAgB,OACvBQ,EAAgBR,EAAgB,MACjC,CACD,CAEA,IAAIa,EAAsC,KACnC,SAASC,GAAiC,CAChD,OAAKD,IACJA,EAAiB,OAAO,yBAAyB,EAAE,KAAK,CAAC,CAAE,gBAAAE,CAAgB,IAC1EA,EAAgB,eACf,+EACD,CACD,GAEMF,CACR,CAEO,SAASG,EAAeC,EAA6B,CAY3D,MAAO,CAAE,cAXaA,EAAU,cAAgB,GAWxB,GAVbA,EACR,CAACC,EAAoBC,EAAcC,EAAcC,IAAiB,CAClE,IAAMC,EAAWF,EAAK,QAAQ,QAAS,EAAE,EACnCG,EAAcH,EAAO,GAAGA,CAAI,kBAAoB,gBAChDI,EAAWF,EAAW,GAAGA,CAAQ,MAAQ,IAC/C,MAAO,GAAGJ,CAAU,IAAIC,CAAI,IAAII,CAAW;AAAA,EAAQF,CAAI;AAAA;AAAA,EACzDH,CAAU,IAAIC,CAAI,IAAIC,CAAI,cAAcD,CAAI,IAAIK,CAAQ,MACtD,EACA,CAACN,EAAoBC,EAAcC,EAAcC,IACjD,GAAGH,CAAU,IAAIC,CAAI,IAAIC,CAAI;AAAA,EAAQC,CAAI;AAAA,EACjB,CAC5B","names":["dummyTexture","isMediaPipeSource","source","hashOptions","options","calculateBoundingBoxCenter","data","entityIdx","landmarkIndices","landmarkCount","offset","minX","maxX","minY","maxY","avgZ","avgVisibility","idx","dataIdx","x","y","filesetPromise","getSharedFileset","FilesetResolver","generateGLSLFn","history","returnType","name","args","body","argsOnly","historyArgs","callArgs"]}
package/dist/index.d.mts CHANGED
@@ -18,7 +18,7 @@ interface PartialCustomTexture extends CustomTexture {
18
18
  x?: number;
19
19
  y?: number;
20
20
  }
21
- type TextureSource = HTMLImageElement | HTMLVideoElement | HTMLCanvasElement | OffscreenCanvas | ImageBitmap | WebGLTexture | CustomTexture;
21
+ type TextureSource = HTMLImageElement | HTMLVideoElement | HTMLCanvasElement | OffscreenCanvas | ImageBitmap | WebGLTexture | CustomTexture | ShaderPad;
22
22
  type UpdateTextureSource = Exclude<TextureSource, CustomTexture> | PartialCustomTexture;
23
23
  interface PluginContext {
24
24
  gl: WebGL2RenderingContext;
@@ -78,6 +78,7 @@ declare class ShaderPad {
78
78
  private reserveTextureUnit;
79
79
  private releaseTextureUnit;
80
80
  private resolveTextureOptions;
81
+ private getPixelArray;
81
82
  private clearHistoryTextureLayers;
82
83
  initializeUniform(name: string, type: 'float' | 'int', value: number | number[] | (number | number[])[], options?: {
83
84
  arrayLength?: number;
package/dist/index.d.ts CHANGED
@@ -18,7 +18,7 @@ interface PartialCustomTexture extends CustomTexture {
18
18
  x?: number;
19
19
  y?: number;
20
20
  }
21
- type TextureSource = HTMLImageElement | HTMLVideoElement | HTMLCanvasElement | OffscreenCanvas | ImageBitmap | WebGLTexture | CustomTexture;
21
+ type TextureSource = HTMLImageElement | HTMLVideoElement | HTMLCanvasElement | OffscreenCanvas | ImageBitmap | WebGLTexture | CustomTexture | ShaderPad;
22
22
  type UpdateTextureSource = Exclude<TextureSource, CustomTexture> | PartialCustomTexture;
23
23
  interface PluginContext {
24
24
  gl: WebGL2RenderingContext;
@@ -78,6 +78,7 @@ declare class ShaderPad {
78
78
  private reserveTextureUnit;
79
79
  private releaseTextureUnit;
80
80
  private resolveTextureOptions;
81
+ private getPixelArray;
81
82
  private clearHistoryTextureLayers;
82
83
  initializeUniform(name: string, type: 'float' | 'int', value: number | number[] | (number | number[])[], options?: {
83
84
  arrayLength?: number;