@paper-design/shaders 0.0.0-canary.55a3ef1 → 0.0.0-canary.5bfd3e7

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 (37) hide show
  1. package/dist/html-in-canvas.d.ts +35 -0
  2. package/dist/html-in-canvas.js +79 -0
  3. package/dist/html-in-canvas.js.map +7 -0
  4. package/dist/index.d.ts +1 -0
  5. package/dist/index.js +2 -0
  6. package/dist/index.js.map +2 -2
  7. package/dist/shader-mount.d.ts +12 -1
  8. package/dist/shader-mount.js +119 -25
  9. package/dist/shader-mount.js.map +2 -2
  10. package/dist/shaders/fluted-glass.d.ts +7 -4
  11. package/dist/shaders/fluted-glass.js +23 -23
  12. package/dist/shaders/fluted-glass.js.map +2 -2
  13. package/dist/shaders/halftone-cmyk.d.ts +7 -4
  14. package/dist/shaders/halftone-cmyk.js +35 -11
  15. package/dist/shaders/halftone-cmyk.js.map +2 -2
  16. package/dist/shaders/halftone-dots.d.ts +7 -4
  17. package/dist/shaders/halftone-dots.js +32 -8
  18. package/dist/shaders/halftone-dots.js.map +2 -2
  19. package/dist/shaders/image-dithering.d.ts +6 -4
  20. package/dist/shaders/image-dithering.js +37 -27
  21. package/dist/shaders/image-dithering.js.map +2 -2
  22. package/dist/shaders/lens-distortion.d.ts +5 -2
  23. package/dist/shaders/lens-distortion.js +26 -12
  24. package/dist/shaders/lens-distortion.js.map +2 -2
  25. package/dist/shaders/paper-texture.d.ts +49 -45
  26. package/dist/shaders/paper-texture.js +64 -41
  27. package/dist/shaders/paper-texture.js.map +2 -2
  28. package/dist/shaders/water.d.ts +8 -4
  29. package/dist/shaders/water.js +19 -6
  30. package/dist/shaders/water.js.map +2 -2
  31. package/dist/vertex-shader.d.ts +1 -1
  32. package/dist/vertex-shader.js +21 -18
  33. package/dist/vertex-shader.js.map +2 -2
  34. package/package.json +1 -1
  35. package/dist/shaders/paper-texture---.d.ts +0 -11
  36. package/dist/shaders/paper-texture---.js +0 -509
  37. package/dist/shaders/paper-texture---.js.map +0 -7
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Experimental HTML-in-canvas support (https://github.com/WICG/html-in-canvas),
3
+ * available in Chromium behind `chrome://flags/#canvas-draw-element`. Older Chromium versions opt the canvas in with
4
+ * `layoutsubtree` instead of `content="drawable"`, so the canvas gets both.
5
+ *
6
+ * An HTML element passed as a texture uniform is moved into the shader canvas and drawn 1:1 where it's laid out:
7
+ *
8
+ * <div data-paper-shader>
9
+ * <canvas content="drawable" layoutsubtree>
10
+ * <div drawable>…</div>
11
+ * </canvas>
12
+ * </div>
13
+ *
14
+ * React renders this markup itself, since it can't let its nodes be moved, and the shader adopts that canvas.
15
+ *
16
+ * The HTML texture always matches the canvas size, so shaders sample it like any canvas-sized texture: a resize
17
+ * captures the HTML again right away instead of waiting for the next paint.
18
+ */
19
+ export interface DrawableCanvasElement extends HTMLCanvasElement {
20
+ requestPaint(): void;
21
+ updateElementGeometry(element: Element, options?: {
22
+ canvasTransform?: DOMMatrixInit;
23
+ }): void;
24
+ }
25
+ export declare function isHtmlInCanvasSupported(): boolean;
26
+ /** `<img>` stays a static image uniform. nodeType instead of `instanceof` works across iframes */
27
+ export declare function isHtmlUniform(value: unknown): value is HTMLElement;
28
+ export declare function findReactCanvas(values: unknown[], parentElement: Element): DrawableCanvasElement | null;
29
+ /** Moves the element into the canvas, returns a function that puts it back */
30
+ export declare function attachHtml(canvas: DrawableCanvasElement, element: HTMLElement): () => void;
31
+ /**
32
+ * Captures the element into the bound texture, sized to the canvas drawing buffer. The texture is only reallocated
33
+ * (and so cleared) when its size or the drawn area changes; returns that layout to pass back in next time
34
+ */
35
+ export declare function drawHtml(gl: WebGL2RenderingContext, canvas: DrawableCanvasElement, element: HTMLElement, lastLayout?: string): string;
@@ -0,0 +1,79 @@
1
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * *
2
+ * Paper Shaders *
3
+ * https://github.com/paper-design/shaders *
4
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * */
5
+
6
+ function isHtmlInCanvasSupported() {
7
+ return typeof HTMLCanvasElement !== "undefined" && "requestPaint" in HTMLCanvasElement.prototype && typeof WebGL2RenderingContext !== "undefined" && "texElementSubImage2D" in WebGL2RenderingContext.prototype;
8
+ }
9
+ function isHtmlUniform(value) {
10
+ return typeof value === "object" && value !== null && value.nodeType === 1 && value.tagName !== "IMG";
11
+ }
12
+ function findReactCanvas(values, parentElement) {
13
+ for (const value of values) {
14
+ const canvas = isHtmlUniform(value) ? value.parentElement : null;
15
+ if (canvas?.tagName === "CANVAS" && canvas.parentElement === parentElement) {
16
+ return canvas;
17
+ }
18
+ }
19
+ return null;
20
+ }
21
+ function attachHtml(canvas, element) {
22
+ if (element.parentElement === canvas) {
23
+ return () => {
24
+ };
25
+ }
26
+ const parent = element.parentNode;
27
+ const nextSibling = element.nextSibling;
28
+ canvas.setAttribute("content", "drawable");
29
+ canvas.setAttribute("layoutsubtree", "");
30
+ element.setAttribute("drawable", "");
31
+ canvas.append(element);
32
+ return () => {
33
+ element.removeAttribute("drawable");
34
+ if (parent) {
35
+ parent.insertBefore(element, nextSibling?.parentNode === parent ? nextSibling : null);
36
+ } else {
37
+ element.remove();
38
+ }
39
+ };
40
+ }
41
+ function drawHtml(gl, canvas, element, lastLayout) {
42
+ const width = Math.max(1, canvas.width);
43
+ const height = Math.max(1, canvas.height);
44
+ const scaleX = width / Math.max(1, canvas.clientWidth);
45
+ const scaleY = height / Math.max(1, canvas.clientHeight);
46
+ const left = element.offsetLeft;
47
+ const top = element.offsetTop;
48
+ const visibleLeft = Math.max(0, left);
49
+ const visibleTop = Math.max(0, top);
50
+ const visibleRight = Math.min(canvas.clientWidth, left + element.offsetWidth);
51
+ const visibleBottom = Math.min(canvas.clientHeight, top + element.offsetHeight);
52
+ const x0 = Math.round(visibleLeft * scaleX);
53
+ const y0 = Math.round(visibleTop * scaleY);
54
+ const x1 = Math.min(width, Math.round(visibleRight * scaleX));
55
+ const y1 = Math.min(height, Math.round(visibleBottom * scaleY));
56
+ const layout = `${width}x${height} ${x0},${y0},${x1},${y1}`;
57
+ if (layout !== lastLayout) {
58
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA8, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
59
+ }
60
+ if (x1 > x0 && y1 > y0) {
61
+ gl.texElementSubImage2D(gl.TEXTURE_2D, 0, x0, y0, element, {
62
+ sx: visibleLeft - left,
63
+ sy: visibleTop - top,
64
+ swidth: visibleRight - visibleLeft,
65
+ sheight: visibleBottom - visibleTop,
66
+ width: x1 - x0,
67
+ height: y1 - y0
68
+ });
69
+ }
70
+ return layout;
71
+ }
72
+ export {
73
+ attachHtml,
74
+ drawHtml,
75
+ findReactCanvas,
76
+ isHtmlInCanvasSupported,
77
+ isHtmlUniform
78
+ };
79
+ //# sourceMappingURL=html-in-canvas.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/html-in-canvas.ts"],
4
+ "sourcesContent": ["/**\n * Experimental HTML-in-canvas support (https://github.com/WICG/html-in-canvas),\n * available in Chromium behind `chrome://flags/#canvas-draw-element`. Older Chromium versions opt the canvas in with\n * `layoutsubtree` instead of `content=\"drawable\"`, so the canvas gets both.\n *\n * An HTML element passed as a texture uniform is moved into the shader canvas and drawn 1:1 where it's laid out:\n *\n * <div data-paper-shader>\n * <canvas content=\"drawable\" layoutsubtree>\n * <div drawable>\u2026</div>\n * </canvas>\n * </div>\n *\n * React renders this markup itself, since it can't let its nodes be moved, and the shader adopts that canvas.\n *\n * The HTML texture always matches the canvas size, so shaders sample it like any canvas-sized texture: a resize\n * captures the HTML again right away instead of waiting for the next paint.\n */\n\nexport interface DrawableCanvasElement extends HTMLCanvasElement {\n requestPaint(): void;\n updateElementGeometry(element: Element, options?: { canvasTransform?: DOMMatrixInit }): void;\n}\n\ninterface DrawableCanvasWebGL2Context extends WebGL2RenderingContext {\n texElementSubImage2D(\n target: GLenum,\n level: GLint,\n xoffset: GLint,\n yoffset: GLint,\n element: Element,\n config?: { width?: number; height?: number; sx?: number; sy?: number; swidth?: number; sheight?: number }\n ): void;\n}\n\nexport function isHtmlInCanvasSupported(): boolean {\n return (\n typeof HTMLCanvasElement !== 'undefined' &&\n 'requestPaint' in HTMLCanvasElement.prototype &&\n typeof WebGL2RenderingContext !== 'undefined' &&\n 'texElementSubImage2D' in WebGL2RenderingContext.prototype\n );\n}\n\n/** `<img>` stays a static image uniform. nodeType instead of `instanceof` works across iframes */\nexport function isHtmlUniform(value: unknown): value is HTMLElement {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as Node).nodeType === 1 &&\n (value as Element).tagName !== 'IMG'\n );\n}\n\nexport function findReactCanvas(values: unknown[], parentElement: Element): DrawableCanvasElement | null {\n for (const value of values) {\n const canvas = isHtmlUniform(value) ? value.parentElement : null;\n if (canvas?.tagName === 'CANVAS' && canvas.parentElement === parentElement) {\n return canvas as DrawableCanvasElement;\n }\n }\n return null;\n}\n\n/** Moves the element into the canvas, returns a function that puts it back */\nexport function attachHtml(canvas: DrawableCanvasElement, element: HTMLElement): () => void {\n if (element.parentElement === canvas) {\n return () => {};\n }\n\n const parent = element.parentNode;\n const nextSibling = element.nextSibling;\n canvas.setAttribute('content', 'drawable');\n canvas.setAttribute('layoutsubtree', '');\n element.setAttribute('drawable', '');\n canvas.append(element);\n\n return () => {\n element.removeAttribute('drawable');\n if (parent) {\n parent.insertBefore(element, nextSibling?.parentNode === parent ? nextSibling : null);\n } else {\n element.remove();\n }\n };\n}\n\n/**\n * Captures the element into the bound texture, sized to the canvas drawing buffer. The texture is only reallocated\n * (and so cleared) when its size or the drawn area changes; returns that layout to pass back in next time\n */\nexport function drawHtml(\n gl: WebGL2RenderingContext,\n canvas: DrawableCanvasElement,\n element: HTMLElement,\n lastLayout?: string\n): string {\n const width = Math.max(1, canvas.width);\n const height = Math.max(1, canvas.height);\n const scaleX = width / Math.max(1, canvas.clientWidth);\n const scaleY = height / Math.max(1, canvas.clientHeight);\n\n const left = element.offsetLeft;\n const top = element.offsetTop;\n const visibleLeft = Math.max(0, left);\n const visibleTop = Math.max(0, top);\n const visibleRight = Math.min(canvas.clientWidth, left + element.offsetWidth);\n const visibleBottom = Math.min(canvas.clientHeight, top + element.offsetHeight);\n const x0 = Math.round(visibleLeft * scaleX);\n const y0 = Math.round(visibleTop * scaleY);\n const x1 = Math.min(width, Math.round(visibleRight * scaleX));\n const y1 = Math.min(height, Math.round(visibleBottom * scaleY));\n\n const layout = `${width}x${height} ${x0},${y0},${x1},${y1}`;\n if (layout !== lastLayout) {\n gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA8, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);\n }\n\n if (x1 > x0 && y1 > y0) {\n (gl as DrawableCanvasWebGL2Context).texElementSubImage2D(gl.TEXTURE_2D, 0, x0, y0, element, {\n sx: visibleLeft - left,\n sy: visibleTop - top,\n swidth: visibleRight - visibleLeft,\n sheight: visibleBottom - visibleTop,\n width: x1 - x0,\n height: y1 - y0,\n });\n }\n\n return layout;\n}\n"],
5
+ "mappings": ";;;;;AAmCO,SAAS,0BAAmC;AACjD,SACE,OAAO,sBAAsB,eAC7B,kBAAkB,kBAAkB,aACpC,OAAO,2BAA2B,eAClC,0BAA0B,uBAAuB;AAErD;AAGO,SAAS,cAAc,OAAsC;AAClE,SACE,OAAO,UAAU,YACjB,UAAU,QACT,MAAe,aAAa,KAC5B,MAAkB,YAAY;AAEnC;AAEO,SAAS,gBAAgB,QAAmB,eAAsD;AACvG,aAAW,SAAS,QAAQ;AAC1B,UAAM,SAAS,cAAc,KAAK,IAAI,MAAM,gBAAgB;AAC5D,QAAI,QAAQ,YAAY,YAAY,OAAO,kBAAkB,eAAe;AAC1E,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAGO,SAAS,WAAW,QAA+B,SAAkC;AAC1F,MAAI,QAAQ,kBAAkB,QAAQ;AACpC,WAAO,MAAM;AAAA,IAAC;AAAA,EAChB;AAEA,QAAM,SAAS,QAAQ;AACvB,QAAM,cAAc,QAAQ;AAC5B,SAAO,aAAa,WAAW,UAAU;AACzC,SAAO,aAAa,iBAAiB,EAAE;AACvC,UAAQ,aAAa,YAAY,EAAE;AACnC,SAAO,OAAO,OAAO;AAErB,SAAO,MAAM;AACX,YAAQ,gBAAgB,UAAU;AAClC,QAAI,QAAQ;AACV,aAAO,aAAa,SAAS,aAAa,eAAe,SAAS,cAAc,IAAI;AAAA,IACtF,OAAO;AACL,cAAQ,OAAO;AAAA,IACjB;AAAA,EACF;AACF;AAMO,SAAS,SACd,IACA,QACA,SACA,YACQ;AACR,QAAM,QAAQ,KAAK,IAAI,GAAG,OAAO,KAAK;AACtC,QAAM,SAAS,KAAK,IAAI,GAAG,OAAO,MAAM;AACxC,QAAM,SAAS,QAAQ,KAAK,IAAI,GAAG,OAAO,WAAW;AACrD,QAAM,SAAS,SAAS,KAAK,IAAI,GAAG,OAAO,YAAY;AAEvD,QAAM,OAAO,QAAQ;AACrB,QAAM,MAAM,QAAQ;AACpB,QAAM,cAAc,KAAK,IAAI,GAAG,IAAI;AACpC,QAAM,aAAa,KAAK,IAAI,GAAG,GAAG;AAClC,QAAM,eAAe,KAAK,IAAI,OAAO,aAAa,OAAO,QAAQ,WAAW;AAC5E,QAAM,gBAAgB,KAAK,IAAI,OAAO,cAAc,MAAM,QAAQ,YAAY;AAC9E,QAAM,KAAK,KAAK,MAAM,cAAc,MAAM;AAC1C,QAAM,KAAK,KAAK,MAAM,aAAa,MAAM;AACzC,QAAM,KAAK,KAAK,IAAI,OAAO,KAAK,MAAM,eAAe,MAAM,CAAC;AAC5D,QAAM,KAAK,KAAK,IAAI,QAAQ,KAAK,MAAM,gBAAgB,MAAM,CAAC;AAE9D,QAAM,SAAS,GAAG,KAAK,IAAI,MAAM,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE;AACzD,MAAI,WAAW,YAAY;AACzB,OAAG,WAAW,GAAG,YAAY,GAAG,GAAG,OAAO,OAAO,QAAQ,GAAG,GAAG,MAAM,GAAG,eAAe,IAAI;AAAA,EAC7F;AAEA,MAAI,KAAK,MAAM,KAAK,IAAI;AACtB,IAAC,GAAmC,qBAAqB,GAAG,YAAY,GAAG,IAAI,IAAI,SAAS;AAAA,MAC1F,IAAI,cAAc;AAAA,MAClB,IAAI,aAAa;AAAA,MACjB,QAAQ,eAAe;AAAA,MACvB,SAAS,gBAAgB;AAAA,MACzB,OAAO,KAAK;AAAA,MACZ,QAAQ,KAAK;AAAA,IACf,CAAC;AAAA,EACH;AAEA,SAAO;AACT;",
6
+ "names": []
7
+ }
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  /** The core Shader Mount class. Pass it a parent element and a fragment shader to get started. */
2
2
  export { ShaderMount, isPaperShaderElement } from './shader-mount.js';
3
+ export { isHtmlInCanvasSupported } from './html-in-canvas.js';
3
4
  export type { PaperShaderElement, ShaderMotionParams, ShaderMountUniforms, ShaderPreset, ImageShaderPreset, } from './shader-mount.js';
4
5
  /** Shader sizing options and uniforms */
5
6
  export { defaultObjectSizing, defaultPatternSizing, ShaderFitOptions, type ShaderFit, type ShaderSizingParams, type ShaderSizingUniforms, } from './shader-sizing.js';
package/dist/index.js CHANGED
@@ -4,6 +4,7 @@
4
4
  * * * * * * * * * * * * * * * * * * * * * * * * * * * */
5
5
 
6
6
  import { ShaderMount, isPaperShaderElement } from "./shader-mount.js";
7
+ import { isHtmlInCanvasSupported } from "./html-in-canvas.js";
7
8
  import {
8
9
  defaultObjectSizing,
9
10
  defaultPatternSizing,
@@ -156,6 +157,7 @@ export {
156
157
  heatmapFragmentShader,
157
158
  heatmapMeta,
158
159
  imageDitheringFragmentShader,
160
+ isHtmlInCanvasSupported,
159
161
  isPaperShaderElement,
160
162
  lensDistortionFragmentShader,
161
163
  lensDistortionMeta,
package/dist/index.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/index.ts"],
4
- "sourcesContent": ["/** The core Shader Mount class. Pass it a parent element and a fragment shader to get started. */\nexport { ShaderMount, isPaperShaderElement } from './shader-mount.js';\nexport type {\n PaperShaderElement,\n ShaderMotionParams,\n ShaderMountUniforms,\n ShaderPreset,\n ImageShaderPreset,\n} from './shader-mount.js';\n\n/** Shader sizing options and uniforms */\nexport {\n defaultObjectSizing,\n defaultPatternSizing,\n ShaderFitOptions,\n type ShaderFit,\n type ShaderSizingParams,\n type ShaderSizingUniforms,\n} from './shader-sizing.js';\n\n/** A flowing interplay of color spots, moving along distinct trajectories and transformed by organic distortion */\nexport {\n meshGradientFragmentShader,\n meshGradientMeta,\n type MeshGradientParams,\n type MeshGradientUniforms,\n} from './shaders/mesh-gradient.js';\n\n/** Radial multi-colored gradient shaped with layered noise for a natural, smoky aesthetic */\nexport {\n smokeRingMeta,\n smokeRingFragmentShader,\n type SmokeRingParams,\n type SmokeRingUniforms,\n} from './shaders/smoke-ring.js';\n\n/** A glowing, web-like structure of fluid lines and soft intersections. Great for creating atmospheric, organic-yet-futuristic visuals */\nexport { neuroNoiseFragmentShader, type NeuroNoiseParams, type NeuroNoiseUniforms } from './shaders/neuro-noise.js';\n\n/** Animated multi-color dots pattern with each dot orbiting around its cell center. Supports up to 40 colors and various shape and motion controls. Great for playful, dynamic backgrounds and UI textures */\nexport {\n dotOrbitMeta,\n dotOrbitFragmentShader,\n type DotOrbitParams,\n type DotOrbitUniforms,\n} from './shaders/dot-orbit.js';\n\n/** Static grid pattern made of circles, diamonds, squares or triangles */\nexport {\n dotGridFragmentShader,\n DotGridShapes,\n type DotGridShape,\n type DotGridParams,\n type DotGridUniforms,\n} from './shaders/dot-grid.js';\n\n/** A multi-color gradient mapped into smooth, animated curves, delivering a sleek, futuristic visual */\nexport {\n simplexNoiseMeta,\n simplexNoiseFragmentShader,\n type SimplexNoiseParams,\n type SimplexNoiseUniforms,\n} from './shaders/simplex-noise.js';\n\n/** Up to 20 gooey blobs moving around the center and merging into smooth organic shapes */\nexport {\n metaballsMeta,\n metaballsFragmentShader,\n type MetaballsParams,\n type MetaballsUniforms,\n} from './shaders/metaballs.js';\n\n/** Animated 3D Perlin noise with exposed controls */\nexport { perlinNoiseFragmentShader, type PerlinNoiseParams, type PerlinNoiseUniforms } from './shaders/perlin-noise.js';\n\n/** Anti-aliased animated Voronoi pattern with smooth and customizable edges */\nexport { voronoiMeta, voronoiFragmentShader, type VoronoiParams, type VoronoiUniforms } from './shaders/voronoi.js';\n\n/** Static line pattern configurable into textures ranging from sharp zigzags to smooth flowing waves */\nexport { wavesFragmentShader, type WavesParams, type WavesUniforms } from './shaders/waves.js';\n\n/** Animated color fields warped by noise and swirls, applied over base patterns (checks, stripes, or split edge). Blends up to 10 colors with adjustable distribution, softness, distortion, and swirl. Great for fluid, smoky, or marbled effects */\nexport {\n warpMeta,\n warpFragmentShader,\n WarpPatterns,\n type WarpParams,\n type WarpUniforms,\n type WarpPattern,\n} from './shaders/warp.js';\n\n/** Animated rays of light radiating from the center, blended with up to 5 colors. The rays are adjustable by size, density, brightness and center glow. Great for dramatic backgrounds, logo reveals, and VFX like energy bursts or sun shafts */\nexport { godRaysMeta, godRaysFragmentShader, type GodRaysParams, type GodRaysUniforms } from './shaders/god-rays.js';\n\n/** A single-colored animated spiral that morphs across a wide range of shapes - from crisp, thin-lined geometry to flowing whirlpool forms and wavy, abstract rings */\nexport { spiralFragmentShader, type SpiralParams, type SpiralUniforms } from './shaders/spiral.js';\n\n/** Animated bands of color twisting and bending, producing spirals, arcs, and flowing circular patterns */\nexport { swirlMeta, swirlFragmentShader, type SwirlParams, type SwirlUniforms } from './shaders/swirl.js';\n\n/** Animated 2-color dithering over with multiple pattern sources (noise, warp, dots, waves, ripple, swirl, sphere) */\nexport {\n ditheringFragmentShader,\n DitheringShapes,\n DitheringTypes,\n type DitheringParams,\n type DitheringUniforms,\n type DitheringShape,\n type DitheringType,\n} from './shaders/dithering.js';\n\n/** Multi-color gradients with grainy, noise-textured distortion available in 7 animated abstract forms */\nexport {\n grainGradientFragmentShader,\n grainGradientMeta,\n GrainGradientShapes,\n type GrainGradientParams,\n type GrainGradientUniforms,\n type GrainGradientShape,\n} from './shaders/grain-gradient.js';\n\n/** Luminous trails of color merging into a glowing gradient frame */\nexport {\n pulsingBorderMeta,\n pulsingBorderFragmentShader,\n PulsingBorderAspectRatios,\n type PulsingBorderParams,\n type PulsingBorderUniforms,\n type PulsingBorderAspectRatio,\n} from './shaders/pulsing-border.js';\n\n/** Glowing translucent 3D panels rotating around a central axis */\nexport {\n colorPanelsFragmentShader,\n colorPanelsMeta,\n type ColorPanelsParams,\n type ColorPanelsUniforms,\n} from './shaders/color-panels.js';\n\n/** Multi-point mesh gradients with up to 10 color spots, enhanced by two-direction warping, adjustable blend sharpness, and grain controls. Perfect for elegant wallpapers and atmospheric backdrops */\nexport {\n staticMeshGradientFragmentShader,\n staticMeshGradientMeta,\n type StaticMeshGradientParams,\n type StaticMeshGradientUniforms,\n} from './shaders/static-mesh-gradient.js';\n\n/** Radial gradient with up to 10 blended colors, featuring advanced focal point control, shape distortion, and grain effects */\nexport {\n staticRadialGradientFragmentShader,\n staticRadialGradientMeta,\n type StaticRadialGradientParams,\n type StaticRadialGradientUniforms,\n} from './shaders/static-radial-gradient.js';\n\n/** A static texture built from multiple noise layers, usable for a realistic paper and cardboard surfaces or generating abstract patterns. Can be used as a image filter or as a texture */\nexport {\n paperTextureFragmentShader,\n paperTextureMeta,\n type PaperTextureParams,\n type PaperTextureUniforms,\n} from './shaders/paper-texture.js';\n\n/** Water-like surface distortion with natural caustic realism. Works as an image filter or animated texture without image */\nexport { waterFragmentShader, type WaterParams, type WaterUniforms } from './shaders/water.js';\n\n/** Fluted glass image filter transforms an image into streaked, ribbed distortions, giving a mix of clarity and obscurity */\nexport {\n flutedGlassFragmentShader,\n GlassDistortionShapes,\n GlassGridShapes,\n type GlassDistortionShape,\n type GlassGridShape,\n type FlutedGlassParams,\n type FlutedGlassUniforms,\n} from './shaders/fluted-glass.js';\n\n/** A dithering image filter with support for 4 dithering modes and multiple color palettes (2-color, 3-color, and multicolor options, using either predefined colors or ones sampled directly from the original image) */\nexport {\n imageDitheringFragmentShader,\n type ImageDitheringParams,\n type ImageDitheringUniforms,\n} from './shaders/image-dithering.js';\n\n/** Lens Distortion image filter that separates an image into shifting color layers, recreating the chromatic aberration of a lens, and warps the image geometry with barrel or pincushion curvature */\nexport {\n lensDistortionFragmentShader,\n lensDistortionMeta,\n type LensDistortionParams,\n type LensDistortionUniforms,\n} from './shaders/lens-distortion.js';\n\n/** A glowing gradient of colors flowing through an input image. The effect creates a smoothly animated wave of intensity across the image */\nexport {\n heatmapMeta,\n heatmapFragmentShader,\n toProcessedHeatmap,\n type HeatmapParams,\n type HeatmapUniforms,\n} from './shaders/heatmap.js';\n\n/** Futuristic liquid metal material applied to uploaded logo or one of pre-defined abstract shape */\nexport {\n liquidMetalFragmentShader,\n LiquidMetalShapes,\n toProcessedLiquidMetal,\n type LiquidMetalShape,\n type LiquidMetalParams,\n type LiquidMetalUniforms,\n} from './shaders/liquid-metal.js';\n\n/** A halftone-dot image filter featuring customizable grids, color palettes, and dot styles */\nexport {\n HalftoneDotsTypes,\n HalftoneDotsGrids,\n halftoneDotsFragmentShader,\n type HalftoneDotsParams,\n type HalftoneDotsUniforms,\n type HalftoneDotsType,\n type HalftoneDotsGrid,\n} from './shaders/halftone-dots.js';\n\n/** A halftone CMYK classic algo */\nexport {\n HalftoneCmykTypes,\n halftoneCmykFragmentShader,\n type HalftoneCmykParams,\n type HalftoneCmykUniforms,\n type HalftoneCmykType,\n} from './shaders/halftone-cmyk.js';\n\n/** Animated color fields running around a glassy logo shape */\nexport {\n gemSmokeMeta,\n gemSmokeFragmentShader,\n toProcessedGemSmoke,\n GemSmokeShapes,\n type GemSmokeShape,\n type GemSmokeParams,\n type GemSmokeUniforms,\n} from './shaders/gem-smoke.js';\n\n// ----- Utils ----- //\nexport { getShaderColorFromString } from './get-shader-color-from-string.js';\nexport { getShaderNoiseTexture } from './get-shader-noise-texture.js';\nexport { emptyPixel } from './empty-pixel.js';\n"],
5
- "mappings": ";;;;;AACA,SAAS,aAAa,4BAA4B;AAUlD;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAGP,SAAS,gCAAgF;AAGzF;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,OAIK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAGP,SAAS,iCAAmF;AAG5F,SAAS,aAAa,6BAAuE;AAG7F,SAAS,2BAAiE;AAG1E;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AAGP,SAAS,aAAa,6BAAuE;AAG7F,SAAS,4BAAoE;AAG7E,SAAS,WAAW,2BAAiE;AAGrF;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAKK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAGP,SAAS,2BAAiE;AAG1E;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAKK;AAGP;AAAA,EACE;AAAA,OAGK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAKK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,OAIK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AAGP,SAAS,gCAAgC;AACzC,SAAS,6BAA6B;AACtC,SAAS,kBAAkB;",
4
+ "sourcesContent": ["/** The core Shader Mount class. Pass it a parent element and a fragment shader to get started. */\nexport { ShaderMount, isPaperShaderElement } from './shader-mount.js';\nexport { isHtmlInCanvasSupported } from './html-in-canvas.js';\nexport type {\n PaperShaderElement,\n ShaderMotionParams,\n ShaderMountUniforms,\n ShaderPreset,\n ImageShaderPreset,\n} from './shader-mount.js';\n\n/** Shader sizing options and uniforms */\nexport {\n defaultObjectSizing,\n defaultPatternSizing,\n ShaderFitOptions,\n type ShaderFit,\n type ShaderSizingParams,\n type ShaderSizingUniforms,\n} from './shader-sizing.js';\n\n/** A flowing interplay of color spots, moving along distinct trajectories and transformed by organic distortion */\nexport {\n meshGradientFragmentShader,\n meshGradientMeta,\n type MeshGradientParams,\n type MeshGradientUniforms,\n} from './shaders/mesh-gradient.js';\n\n/** Radial multi-colored gradient shaped with layered noise for a natural, smoky aesthetic */\nexport {\n smokeRingMeta,\n smokeRingFragmentShader,\n type SmokeRingParams,\n type SmokeRingUniforms,\n} from './shaders/smoke-ring.js';\n\n/** A glowing, web-like structure of fluid lines and soft intersections. Great for creating atmospheric, organic-yet-futuristic visuals */\nexport { neuroNoiseFragmentShader, type NeuroNoiseParams, type NeuroNoiseUniforms } from './shaders/neuro-noise.js';\n\n/** Animated multi-color dots pattern with each dot orbiting around its cell center. Supports up to 40 colors and various shape and motion controls. Great for playful, dynamic backgrounds and UI textures */\nexport {\n dotOrbitMeta,\n dotOrbitFragmentShader,\n type DotOrbitParams,\n type DotOrbitUniforms,\n} from './shaders/dot-orbit.js';\n\n/** Static grid pattern made of circles, diamonds, squares or triangles */\nexport {\n dotGridFragmentShader,\n DotGridShapes,\n type DotGridShape,\n type DotGridParams,\n type DotGridUniforms,\n} from './shaders/dot-grid.js';\n\n/** A multi-color gradient mapped into smooth, animated curves, delivering a sleek, futuristic visual */\nexport {\n simplexNoiseMeta,\n simplexNoiseFragmentShader,\n type SimplexNoiseParams,\n type SimplexNoiseUniforms,\n} from './shaders/simplex-noise.js';\n\n/** Up to 20 gooey blobs moving around the center and merging into smooth organic shapes */\nexport {\n metaballsMeta,\n metaballsFragmentShader,\n type MetaballsParams,\n type MetaballsUniforms,\n} from './shaders/metaballs.js';\n\n/** Animated 3D Perlin noise with exposed controls */\nexport { perlinNoiseFragmentShader, type PerlinNoiseParams, type PerlinNoiseUniforms } from './shaders/perlin-noise.js';\n\n/** Anti-aliased animated Voronoi pattern with smooth and customizable edges */\nexport { voronoiMeta, voronoiFragmentShader, type VoronoiParams, type VoronoiUniforms } from './shaders/voronoi.js';\n\n/** Static line pattern configurable into textures ranging from sharp zigzags to smooth flowing waves */\nexport { wavesFragmentShader, type WavesParams, type WavesUniforms } from './shaders/waves.js';\n\n/** Animated color fields warped by noise and swirls, applied over base patterns (checks, stripes, or split edge). Blends up to 10 colors with adjustable distribution, softness, distortion, and swirl. Great for fluid, smoky, or marbled effects */\nexport {\n warpMeta,\n warpFragmentShader,\n WarpPatterns,\n type WarpParams,\n type WarpUniforms,\n type WarpPattern,\n} from './shaders/warp.js';\n\n/** Animated rays of light radiating from the center, blended with up to 5 colors. The rays are adjustable by size, density, brightness and center glow. Great for dramatic backgrounds, logo reveals, and VFX like energy bursts or sun shafts */\nexport { godRaysMeta, godRaysFragmentShader, type GodRaysParams, type GodRaysUniforms } from './shaders/god-rays.js';\n\n/** A single-colored animated spiral that morphs across a wide range of shapes - from crisp, thin-lined geometry to flowing whirlpool forms and wavy, abstract rings */\nexport { spiralFragmentShader, type SpiralParams, type SpiralUniforms } from './shaders/spiral.js';\n\n/** Animated bands of color twisting and bending, producing spirals, arcs, and flowing circular patterns */\nexport { swirlMeta, swirlFragmentShader, type SwirlParams, type SwirlUniforms } from './shaders/swirl.js';\n\n/** Animated 2-color dithering over with multiple pattern sources (noise, warp, dots, waves, ripple, swirl, sphere) */\nexport {\n ditheringFragmentShader,\n DitheringShapes,\n DitheringTypes,\n type DitheringParams,\n type DitheringUniforms,\n type DitheringShape,\n type DitheringType,\n} from './shaders/dithering.js';\n\n/** Multi-color gradients with grainy, noise-textured distortion available in 7 animated abstract forms */\nexport {\n grainGradientFragmentShader,\n grainGradientMeta,\n GrainGradientShapes,\n type GrainGradientParams,\n type GrainGradientUniforms,\n type GrainGradientShape,\n} from './shaders/grain-gradient.js';\n\n/** Luminous trails of color merging into a glowing gradient frame */\nexport {\n pulsingBorderMeta,\n pulsingBorderFragmentShader,\n PulsingBorderAspectRatios,\n type PulsingBorderParams,\n type PulsingBorderUniforms,\n type PulsingBorderAspectRatio,\n} from './shaders/pulsing-border.js';\n\n/** Glowing translucent 3D panels rotating around a central axis */\nexport {\n colorPanelsFragmentShader,\n colorPanelsMeta,\n type ColorPanelsParams,\n type ColorPanelsUniforms,\n} from './shaders/color-panels.js';\n\n/** Multi-point mesh gradients with up to 10 color spots, enhanced by two-direction warping, adjustable blend sharpness, and grain controls. Perfect for elegant wallpapers and atmospheric backdrops */\nexport {\n staticMeshGradientFragmentShader,\n staticMeshGradientMeta,\n type StaticMeshGradientParams,\n type StaticMeshGradientUniforms,\n} from './shaders/static-mesh-gradient.js';\n\n/** Radial gradient with up to 10 blended colors, featuring advanced focal point control, shape distortion, and grain effects */\nexport {\n staticRadialGradientFragmentShader,\n staticRadialGradientMeta,\n type StaticRadialGradientParams,\n type StaticRadialGradientUniforms,\n} from './shaders/static-radial-gradient.js';\n\n/** A static texture built from multiple noise layers, usable for a realistic paper and cardboard surfaces or generating abstract patterns. Can be used as a image filter or as a texture */\nexport {\n paperTextureFragmentShader,\n paperTextureMeta,\n type PaperTextureParams,\n type PaperTextureUniforms,\n} from './shaders/paper-texture.js';\n\n/** Water-like surface distortion with natural caustic realism. Works as an image filter or animated texture without image */\nexport { waterFragmentShader, type WaterParams, type WaterUniforms } from './shaders/water.js';\n\n/** Fluted glass image filter transforms an image into streaked, ribbed distortions, giving a mix of clarity and obscurity */\nexport {\n flutedGlassFragmentShader,\n GlassDistortionShapes,\n GlassGridShapes,\n type GlassDistortionShape,\n type GlassGridShape,\n type FlutedGlassParams,\n type FlutedGlassUniforms,\n} from './shaders/fluted-glass.js';\n\n/** A dithering image filter with support for 4 dithering modes and multiple color palettes (2-color, 3-color, and multicolor options, using either predefined colors or ones sampled directly from the original image) */\nexport {\n imageDitheringFragmentShader,\n type ImageDitheringParams,\n type ImageDitheringUniforms,\n} from './shaders/image-dithering.js';\n\n/** Lens Distortion image filter that separates an image into shifting color layers, recreating the chromatic aberration of a lens, and warps the image geometry with barrel or pincushion curvature */\nexport {\n lensDistortionFragmentShader,\n lensDistortionMeta,\n type LensDistortionParams,\n type LensDistortionUniforms,\n} from './shaders/lens-distortion.js';\n\n/** A glowing gradient of colors flowing through an input image. The effect creates a smoothly animated wave of intensity across the image */\nexport {\n heatmapMeta,\n heatmapFragmentShader,\n toProcessedHeatmap,\n type HeatmapParams,\n type HeatmapUniforms,\n} from './shaders/heatmap.js';\n\n/** Futuristic liquid metal material applied to uploaded logo or one of pre-defined abstract shape */\nexport {\n liquidMetalFragmentShader,\n LiquidMetalShapes,\n toProcessedLiquidMetal,\n type LiquidMetalShape,\n type LiquidMetalParams,\n type LiquidMetalUniforms,\n} from './shaders/liquid-metal.js';\n\n/** A halftone-dot image filter featuring customizable grids, color palettes, and dot styles */\nexport {\n HalftoneDotsTypes,\n HalftoneDotsGrids,\n halftoneDotsFragmentShader,\n type HalftoneDotsParams,\n type HalftoneDotsUniforms,\n type HalftoneDotsType,\n type HalftoneDotsGrid,\n} from './shaders/halftone-dots.js';\n\n/** A halftone CMYK classic algo */\nexport {\n HalftoneCmykTypes,\n halftoneCmykFragmentShader,\n type HalftoneCmykParams,\n type HalftoneCmykUniforms,\n type HalftoneCmykType,\n} from './shaders/halftone-cmyk.js';\n\n/** Animated color fields running around a glassy logo shape */\nexport {\n gemSmokeMeta,\n gemSmokeFragmentShader,\n toProcessedGemSmoke,\n GemSmokeShapes,\n type GemSmokeShape,\n type GemSmokeParams,\n type GemSmokeUniforms,\n} from './shaders/gem-smoke.js';\n\n// ----- Utils ----- //\nexport { getShaderColorFromString } from './get-shader-color-from-string.js';\nexport { getShaderNoiseTexture } from './get-shader-noise-texture.js';\nexport { emptyPixel } from './empty-pixel.js';\n"],
5
+ "mappings": ";;;;;AACA,SAAS,aAAa,4BAA4B;AAClD,SAAS,+BAA+B;AAUxC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAGP,SAAS,gCAAgF;AAGzF;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,OAIK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAGP,SAAS,iCAAmF;AAG5F,SAAS,aAAa,6BAAuE;AAG7F,SAAS,2BAAiE;AAG1E;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AAGP,SAAS,aAAa,6BAAuE;AAG7F,SAAS,4BAAoE;AAG7E,SAAS,WAAW,2BAAiE;AAGrF;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAKK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAGP,SAAS,2BAAiE;AAG1E;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAKK;AAGP;AAAA,EACE;AAAA,OAGK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAKK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,OAIK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AAGP,SAAS,gCAAgC;AACzC,SAAS,6BAA6B;AACtC,SAAS,kBAAkB;",
6
6
  "names": []
7
7
  }
@@ -32,6 +32,8 @@ export declare class ShaderMount {
32
32
  private uniformCache;
33
33
  private textureUnitMap;
34
34
  private ownerDocument;
35
+ private htmlUniforms;
36
+ private isReactCanvas;
35
37
  constructor(
36
38
  /** The div you'd like to mount the shader to. The shader will match its size. */
37
39
  parentElement: HTMLElement, fragmentShader: string, uniforms: ShaderMountUniforms, webGlContextAttributes?: WebGLContextAttributes,
@@ -81,6 +83,13 @@ export declare class ShaderMount {
81
83
  private requestRender;
82
84
  /** Creates a texture from an image and sets it into a uniform value */
83
85
  private setTextureUniform;
86
+ private createTexture;
87
+ /** Moves the element into the shader canvas and redraws it into the texture on every canvas paint */
88
+ private setHtmlUniform;
89
+ /** Captures each HTML uniform into its texture. On resize only HTML that has a snapshot already, so it can't throw */
90
+ private captureHtml;
91
+ private unsetHtmlUniform;
92
+ private handleCanvasPaint;
84
93
  /** Utility: recursive equality test for all the uniforms */
85
94
  private areUniformValuesEqual;
86
95
  /** Sets the provided uniform values into the WebGL program, can be a partial list of uniforms that have changed */
@@ -100,6 +109,8 @@ export declare class ShaderMount {
100
109
  setMinPixelRatio: (newMinPixelRatio?: number) => void;
101
110
  /** Update the uniforms that are provided by the outside shader, can be a partial set with only the uniforms that have changed */
102
111
  setUniforms: (newUniforms: ShaderMountUniforms) => void;
112
+ /** Render right away only when the rAF loop isn't running */
113
+ private renderUnlessAnimating;
103
114
  private handleDocumentVisibilityChange;
104
115
  /** Dispose of the shader mount, cleaning up all of the WebGL resources */
105
116
  dispose: () => void;
@@ -117,7 +128,7 @@ export declare function isPaperShaderElement(element: HTMLElement): element is P
117
128
  * We just skip setting the uniform if it's undefined. This allows the shader mount to still take up space during server rendering
118
129
  */
119
130
  export interface ShaderMountUniforms {
120
- [key: string]: boolean | number | number[] | number[][] | HTMLImageElement | undefined;
131
+ [key: string]: boolean | number | number[] | number[][] | HTMLImageElement | HTMLElement | undefined;
121
132
  }
122
133
  export interface ShaderMotionParams {
123
134
  speed?: number;
@@ -4,6 +4,13 @@
4
4
  * * * * * * * * * * * * * * * * * * * * * * * * * * * */
5
5
 
6
6
  import { vertexShaderSource } from "./vertex-shader.js";
7
+ import {
8
+ attachHtml,
9
+ drawHtml,
10
+ findReactCanvas,
11
+ isHtmlInCanvasSupported,
12
+ isHtmlUniform
13
+ } from "./html-in-canvas.js";
7
14
  const DEFAULT_MAX_PIXEL_COUNT = 1920 * 1080 * 4;
8
15
  class ShaderMount {
9
16
  parentElement;
@@ -39,6 +46,8 @@ class ShaderMount {
39
46
  uniformCache = {};
40
47
  textureUnitMap = /* @__PURE__ */ new Map();
41
48
  ownerDocument;
49
+ htmlUniforms = /* @__PURE__ */ new Map();
50
+ isReactCanvas = false;
42
51
  constructor(parentElement, fragmentShader, uniforms, webGlContextAttributes, speed = 0, frame = 0, minPixelRatio = 2, maxPixelCount = DEFAULT_MAX_PIXEL_COUNT, mipmaps = []) {
43
52
  if (parentElement?.nodeType === 1) {
44
53
  this.parentElement = parentElement;
@@ -52,20 +61,31 @@ class ShaderMount {
52
61
  styleElement.setAttribute("data-paper-shader", "");
53
62
  this.ownerDocument.head.prepend(styleElement);
54
63
  }
55
- const canvasElement = this.ownerDocument.createElement("canvas");
64
+ const reactCanvas = findReactCanvas(Object.values(uniforms), this.parentElement);
65
+ const canvasElement = reactCanvas ?? this.ownerDocument.createElement("canvas");
56
66
  this.canvasElement = canvasElement;
57
- this.parentElement.prepend(canvasElement);
67
+ this.isReactCanvas = reactCanvas !== null;
68
+ if (!reactCanvas) {
69
+ this.parentElement.prepend(canvasElement);
70
+ }
71
+ canvasElement.addEventListener("paint", this.handleCanvasPaint);
58
72
  this.fragmentShader = fragmentShader;
59
73
  this.providedUniforms = uniforms;
60
74
  this.mipmaps = mipmaps;
61
75
  this.currentFrame = frame;
62
76
  this.minPixelRatio = minPixelRatio;
63
77
  this.maxPixelCount = maxPixelCount;
64
- const gl = canvasElement.getContext("webgl2", webGlContextAttributes);
78
+ const gl = canvasElement.getContext("webgl2", {
79
+ antialias: false,
80
+ depth: false,
81
+ stencil: false,
82
+ ...webGlContextAttributes
83
+ });
65
84
  if (!gl) {
66
85
  throw new Error("Paper Shaders: WebGL is not supported in this browser");
67
86
  }
68
87
  this.gl = gl;
88
+ this.gl.pixelStorei(this.gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
69
89
  this.initProgram();
70
90
  this.setupPositionAttribute();
71
91
  this.setupUniforms();
@@ -82,6 +102,7 @@ class ShaderMount {
82
102
  const program = createProgram(this.gl, vertexShaderSource, this.fragmentShader);
83
103
  if (!program) return;
84
104
  this.program = program;
105
+ this.gl.useProgram(program);
85
106
  };
86
107
  setupPositionAttribute = () => {
87
108
  const positionAttributeLocation = this.gl.getAttribLocation(this.program, "a_position");
@@ -100,9 +121,10 @@ class ShaderMount {
100
121
  };
101
122
  Object.entries(this.providedUniforms).forEach(([key, value]) => {
102
123
  uniformLocations[key] = this.gl.getUniformLocation(this.program, key);
103
- if (value instanceof HTMLImageElement) {
124
+ if (value instanceof HTMLImageElement || isHtmlUniform(value)) {
104
125
  const aspectRatioUniformName = `${key}AspectRatio`;
105
126
  uniformLocations[aspectRatioUniformName] = this.gl.getUniformLocation(this.program, aspectRatioUniformName);
127
+ uniformLocations[`${key}IsHtml`] = this.gl.getUniformLocation(this.program, `${key}IsHtml`);
106
128
  }
107
129
  });
108
130
  this.uniformLocations = uniformLocations;
@@ -187,6 +209,10 @@ class ShaderMount {
187
209
  this.canvasElement.height = newHeight;
188
210
  this.resolutionChanged = true;
189
211
  this.gl.viewport(0, 0, this.gl.canvas.width, this.gl.canvas.height);
212
+ this.captureHtml(true);
213
+ if (this.htmlUniforms.size > 0) {
214
+ this.canvasElement.requestPaint();
215
+ }
190
216
  this.render(performance.now());
191
217
  }
192
218
  };
@@ -202,7 +228,6 @@ class ShaderMount {
202
228
  this.currentFrame += dt * this.currentSpeed;
203
229
  }
204
230
  this.gl.clear(this.gl.COLOR_BUFFER_BIT);
205
- this.gl.useProgram(this.program);
206
231
  this.gl.uniform1f(this.uniformLocations.u_time, this.currentFrame * 1e-3);
207
232
  if (this.resolutionChanged) {
208
233
  this.gl.uniform2f(this.uniformLocations.u_resolution, this.gl.canvas.width, this.gl.canvas.height);
@@ -227,21 +252,8 @@ class ShaderMount {
227
252
  if (!image.complete || image.naturalWidth === 0) {
228
253
  throw new Error(`Paper Shaders: image for uniform ${uniformName} must be fully loaded`);
229
254
  }
230
- const existingTexture = this.textures.get(uniformName);
231
- if (existingTexture) {
232
- this.gl.deleteTexture(existingTexture);
233
- }
234
- if (!this.textureUnitMap.has(uniformName)) {
235
- this.textureUnitMap.set(uniformName, this.textureUnitMap.size);
236
- }
237
- const textureUnit = this.textureUnitMap.get(uniformName);
238
- this.gl.activeTexture(this.gl.TEXTURE0 + textureUnit);
239
- const texture = this.gl.createTexture();
240
- this.gl.bindTexture(this.gl.TEXTURE_2D, texture);
241
- this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);
242
- this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);
243
- this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR);
244
- this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.LINEAR);
255
+ this.unsetHtmlUniform(uniformName);
256
+ const { texture, textureUnit } = this.createTexture(uniformName);
245
257
  this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, this.gl.RGBA, this.gl.UNSIGNED_BYTE, image);
246
258
  if (this.mipmaps.includes(uniformName)) {
247
259
  this.gl.generateMipmap(this.gl.TEXTURE_2D);
@@ -262,8 +274,71 @@ class ShaderMount {
262
274
  const aspectRatio = image.naturalWidth / image.naturalHeight;
263
275
  this.gl.uniform1f(aspectRatioLocation, aspectRatio);
264
276
  }
277
+ this.gl.uniform1f(this.uniformLocations[`${uniformName}IsHtml`] ?? null, 0);
265
278
  }
266
279
  };
280
+ createTexture = (uniformName) => {
281
+ const existingTexture = this.textures.get(uniformName);
282
+ if (existingTexture) {
283
+ this.gl.deleteTexture(existingTexture);
284
+ }
285
+ if (!this.textureUnitMap.has(uniformName)) {
286
+ this.textureUnitMap.set(uniformName, this.textureUnitMap.size);
287
+ }
288
+ const textureUnit = this.textureUnitMap.get(uniformName);
289
+ this.gl.activeTexture(this.gl.TEXTURE0 + textureUnit);
290
+ const texture = this.gl.createTexture();
291
+ this.gl.bindTexture(this.gl.TEXTURE_2D, texture);
292
+ this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);
293
+ this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);
294
+ this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR);
295
+ this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.LINEAR);
296
+ return { texture, textureUnit };
297
+ };
298
+ /** Moves the element into the shader canvas and redraws it into the texture on every canvas paint */
299
+ setHtmlUniform = (uniformName, element) => {
300
+ this.unsetHtmlUniform(uniformName);
301
+ const { texture, textureUnit } = this.createTexture(uniformName);
302
+ if (texture === null) return;
303
+ this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, 1, 1, 0, this.gl.RGBA, this.gl.UNSIGNED_BYTE, null);
304
+ this.textures.set(uniformName, texture);
305
+ this.gl.uniform1i(this.uniformLocations[uniformName] ?? null, textureUnit);
306
+ this.gl.uniform1f(this.uniformLocations[`${uniformName}IsHtml`] ?? null, 1);
307
+ if (!isHtmlInCanvasSupported()) {
308
+ console.warn(
309
+ `Paper Shaders: HTML for ${uniformName} needs HTML in canvas support (chrome://flags/#canvas-draw-element)`
310
+ );
311
+ return;
312
+ }
313
+ const canvas = this.canvasElement;
314
+ this.htmlUniforms.set(uniformName, { element, detach: attachHtml(canvas, element), hasGeometry: false });
315
+ canvas.requestPaint();
316
+ };
317
+ /** Captures each HTML uniform into its texture. On resize only HTML that has a snapshot already, so it can't throw */
318
+ captureHtml = (isResize) => {
319
+ const canvas = this.canvasElement;
320
+ this.htmlUniforms.forEach((html, uniformName) => {
321
+ if (isResize && html.layout === void 0) return;
322
+ this.gl.activeTexture(this.gl.TEXTURE0 + this.textureUnitMap.get(uniformName));
323
+ this.gl.bindTexture(this.gl.TEXTURE_2D, this.textures.get(uniformName));
324
+ html.layout = drawHtml(this.gl, canvas, html.element, html.layout);
325
+ });
326
+ };
327
+ unsetHtmlUniform = (uniformName) => {
328
+ this.htmlUniforms.get(uniformName)?.detach();
329
+ this.htmlUniforms.delete(uniformName);
330
+ };
331
+ handleCanvasPaint = () => {
332
+ const canvas = this.canvasElement;
333
+ this.captureHtml(false);
334
+ this.htmlUniforms.forEach((html) => {
335
+ if (!html.hasGeometry) {
336
+ canvas.updateElementGeometry(html.element, { canvasTransform: new DOMMatrix() });
337
+ html.hasGeometry = true;
338
+ }
339
+ });
340
+ this.renderUnlessAnimating();
341
+ };
267
342
  /** Utility: recursive equality test for all the uniforms */
268
343
  areUniformValuesEqual = (a, b) => {
269
344
  if (a === b) return true;
@@ -274,7 +349,6 @@ class ShaderMount {
274
349
  };
275
350
  /** Sets the provided uniform values into the WebGL program, can be a partial list of uniforms that have changed */
276
351
  setUniformValues = (updatedUniforms) => {
277
- this.gl.useProgram(this.program);
278
352
  Object.entries(updatedUniforms).forEach(([key, value]) => {
279
353
  let cacheValue = value;
280
354
  if (value instanceof HTMLImageElement) {
@@ -289,6 +363,8 @@ class ShaderMount {
289
363
  }
290
364
  if (value instanceof HTMLImageElement) {
291
365
  this.setTextureUniform(key, value);
366
+ } else if (isHtmlUniform(value)) {
367
+ this.setHtmlUniform(key, value);
292
368
  } else if (Array.isArray(value)) {
293
369
  let flatArray = null;
294
370
  let valueLength = null;
@@ -341,7 +417,7 @@ class ShaderMount {
341
417
  setFrame = (newFrame) => {
342
418
  this.currentFrame = newFrame;
343
419
  this.lastRenderTime = performance.now();
344
- this.render(performance.now());
420
+ this.renderUnlessAnimating();
345
421
  };
346
422
  /** Set an animation speed (or 0 to stop animation) */
347
423
  setSpeed = (newSpeed = 1) => {
@@ -377,7 +453,13 @@ class ShaderMount {
377
453
  setUniforms = (newUniforms) => {
378
454
  this.setUniformValues(newUniforms);
379
455
  this.providedUniforms = { ...this.providedUniforms, ...newUniforms };
380
- this.render(performance.now());
456
+ this.renderUnlessAnimating();
457
+ };
458
+ /** Render right away only when the rAF loop isn't running */
459
+ renderUnlessAnimating = () => {
460
+ if (this.rafId === null) {
461
+ this.render(performance.now());
462
+ }
381
463
  };
382
464
  handleDocumentVisibilityChange = () => {
383
465
  this.updateCurrentSpeed();
@@ -389,6 +471,9 @@ class ShaderMount {
389
471
  cancelAnimationFrame(this.rafId);
390
472
  this.rafId = null;
391
473
  }
474
+ this.canvasElement.removeEventListener("paint", this.handleCanvasPaint);
475
+ this.htmlUniforms.forEach(({ detach }) => detach());
476
+ this.htmlUniforms.clear();
392
477
  if (this.gl && this.program) {
393
478
  this.textures.forEach((texture) => {
394
479
  this.gl.deleteTexture(texture);
@@ -413,7 +498,9 @@ class ShaderMount {
413
498
  visualViewport?.removeEventListener("resize", this.handleVisualViewportChange);
414
499
  this.ownerDocument.removeEventListener("visibilitychange", this.handleDocumentVisibilityChange);
415
500
  this.uniformLocations = {};
416
- this.canvasElement.remove();
501
+ if (!this.isReactCanvas) {
502
+ this.canvasElement.remove();
503
+ }
417
504
  delete this.parentElement.paperShaderMount;
418
505
  };
419
506
  }
@@ -462,7 +549,7 @@ const defaultStyle = `@layer paper-shaders {
462
549
  isolation: isolate;
463
550
  position: relative;
464
551
 
465
- & canvas {
552
+ & > canvas {
466
553
  contain: strict;
467
554
  display: block;
468
555
  position: absolute;
@@ -473,6 +560,13 @@ const defaultStyle = `@layer paper-shaders {
473
560
  border-radius: inherit;
474
561
  corner-shape: inherit;
475
562
  }
563
+
564
+ & > canvas > [drawable],
565
+ & > [drawable] {
566
+ box-sizing: border-box;
567
+ width: 100%;
568
+ height: 100%;
569
+ }
476
570
  }
477
571
  }`;
478
572
  function isPaperShaderElement(element) {