@paper-design/shaders 0.0.70 → 0.0.72
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/empty-pixel.d.ts +1 -0
- package/dist/{get-empty-pixel.js → empty-pixel.js} +2 -11
- package/dist/empty-pixel.js.map +7 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +2 -2
- package/dist/shader-mount.d.ts +1 -0
- package/dist/shader-mount.js +14 -12
- package/dist/shader-mount.js.map +2 -2
- package/dist/shaders/halftone-cmyk.js +15 -13
- package/dist/shaders/halftone-cmyk.js.map +2 -2
- package/dist/shaders/image-dithering.d.ts +3 -0
- package/dist/shaders/image-dithering.js +2 -0
- package/dist/shaders/image-dithering.js.map +2 -2
- package/package.json +1 -1
- package/dist/get-empty-pixel.d.ts +0 -1
- package/dist/get-empty-pixel.js.map +0 -7
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const emptyPixel = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
|
|
@@ -3,17 +3,8 @@
|
|
|
3
3
|
* https://github.com/paper-design/shaders *
|
|
4
4
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
5
5
|
|
|
6
|
-
function getEmptyPixel() {
|
|
7
|
-
if (typeof window === "undefined") {
|
|
8
|
-
console.warn("Paper Shaders: can\u2019t create an image on the server");
|
|
9
|
-
return void 0;
|
|
10
|
-
}
|
|
11
|
-
const img = new Image();
|
|
12
|
-
img.src = emptyPixel;
|
|
13
|
-
return img;
|
|
14
|
-
}
|
|
15
6
|
const emptyPixel = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
|
|
16
7
|
export {
|
|
17
|
-
|
|
8
|
+
emptyPixel
|
|
18
9
|
};
|
|
19
|
-
//# sourceMappingURL=
|
|
10
|
+
//# sourceMappingURL=empty-pixel.js.map
|
package/dist/index.d.ts
CHANGED
|
@@ -61,4 +61,4 @@ export { HalftoneDotsTypes, HalftoneDotsGrids, halftoneDotsFragmentShader, type
|
|
|
61
61
|
export { HalftoneCmykTypes, halftoneCmykFragmentShader, type HalftoneCmykParams, type HalftoneCmykUniforms, type HalftoneCmykType, } from './shaders/halftone-cmyk.js';
|
|
62
62
|
export { getShaderColorFromString } from './get-shader-color-from-string.js';
|
|
63
63
|
export { getShaderNoiseTexture } from './get-shader-noise-texture.js';
|
|
64
|
-
export {
|
|
64
|
+
export { emptyPixel } from './empty-pixel.js';
|
package/dist/index.js
CHANGED
|
@@ -105,7 +105,7 @@ import {
|
|
|
105
105
|
} from "./shaders/halftone-cmyk.js";
|
|
106
106
|
import { getShaderColorFromString } from "./get-shader-color-from-string.js";
|
|
107
107
|
import { getShaderNoiseTexture } from "./get-shader-noise-texture.js";
|
|
108
|
-
import {
|
|
108
|
+
import { emptyPixel } from "./empty-pixel.js";
|
|
109
109
|
export {
|
|
110
110
|
DitheringShapes,
|
|
111
111
|
DitheringTypes,
|
|
@@ -129,8 +129,8 @@ export {
|
|
|
129
129
|
dotGridFragmentShader,
|
|
130
130
|
dotOrbitFragmentShader,
|
|
131
131
|
dotOrbitMeta,
|
|
132
|
+
emptyPixel,
|
|
132
133
|
flutedGlassFragmentShader,
|
|
133
|
-
getEmptyPixel,
|
|
134
134
|
getShaderColorFromString,
|
|
135
135
|
getShaderNoiseTexture,
|
|
136
136
|
godRaysFragmentShader,
|
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 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/** 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// ----- Utils ----- //\nexport { getShaderColorFromString } from './get-shader-color-from-string.js';\nexport { getShaderNoiseTexture } from './get-shader-noise-texture.js';\nexport {
|
|
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,OAGK;AAGP,SAAS,2BAAiE;AAG1E;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAKK;AAGP;AAAA,EACE;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,SAAS,gCAAgC;AACzC,SAAS,6BAA6B;AACtC,SAAS,
|
|
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 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/** 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// ----- 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,OAGK;AAGP,SAAS,2BAAiE;AAG1E;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAKK;AAGP;AAAA,EACE;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,SAAS,gCAAgC;AACzC,SAAS,6BAA6B;AACtC,SAAS,kBAAkB;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/shader-mount.d.ts
CHANGED
|
@@ -31,6 +31,7 @@ export declare class ShaderMount {
|
|
|
31
31
|
private isSafari;
|
|
32
32
|
private uniformCache;
|
|
33
33
|
private textureUnitMap;
|
|
34
|
+
private ownerDocument;
|
|
34
35
|
constructor(
|
|
35
36
|
/** The div you'd like to mount the shader to. The shader will match its size. */
|
|
36
37
|
parentElement: HTMLElement, fragmentShader: string, uniforms: ShaderMountUniforms, webGlContextAttributes?: WebGLContextAttributes,
|
package/dist/shader-mount.js
CHANGED
|
@@ -38,19 +38,21 @@ class ShaderMount {
|
|
|
38
38
|
isSafari = isSafari();
|
|
39
39
|
uniformCache = {};
|
|
40
40
|
textureUnitMap = /* @__PURE__ */ new Map();
|
|
41
|
+
ownerDocument;
|
|
41
42
|
constructor(parentElement, fragmentShader, uniforms, webGlContextAttributes, speed = 0, frame = 0, minPixelRatio = 2, maxPixelCount = DEFAULT_MAX_PIXEL_COUNT, mipmaps = []) {
|
|
42
|
-
if (parentElement
|
|
43
|
+
if (parentElement?.nodeType === 1) {
|
|
43
44
|
this.parentElement = parentElement;
|
|
44
45
|
} else {
|
|
45
46
|
throw new Error("Paper Shaders: parent element must be an HTMLElement");
|
|
46
47
|
}
|
|
47
|
-
|
|
48
|
-
|
|
48
|
+
this.ownerDocument = parentElement.ownerDocument;
|
|
49
|
+
if (!this.ownerDocument.querySelector("style[data-paper-shader]")) {
|
|
50
|
+
const styleElement = this.ownerDocument.createElement("style");
|
|
49
51
|
styleElement.innerHTML = defaultStyle;
|
|
50
52
|
styleElement.setAttribute("data-paper-shader", "");
|
|
51
|
-
|
|
53
|
+
this.ownerDocument.head.prepend(styleElement);
|
|
52
54
|
}
|
|
53
|
-
const canvasElement =
|
|
55
|
+
const canvasElement = this.ownerDocument.createElement("canvas");
|
|
54
56
|
this.canvasElement = canvasElement;
|
|
55
57
|
this.parentElement.prepend(canvasElement);
|
|
56
58
|
this.fragmentShader = fragmentShader;
|
|
@@ -73,7 +75,7 @@ class ShaderMount {
|
|
|
73
75
|
this.setSpeed(speed);
|
|
74
76
|
this.parentElement.setAttribute("data-paper-shader", "");
|
|
75
77
|
this.parentElement.paperShaderMount = this;
|
|
76
|
-
|
|
78
|
+
this.ownerDocument.addEventListener("visibilitychange", this.handleDocumentVisibilityChange);
|
|
77
79
|
}
|
|
78
80
|
initProgram = () => {
|
|
79
81
|
const program = createProgram(this.gl, vertexShaderSource, this.fragmentShader);
|
|
@@ -156,7 +158,7 @@ class ShaderMount {
|
|
|
156
158
|
} else {
|
|
157
159
|
let targetRenderScale = Math.max(dpr, this.minPixelRatio) * pinchZoom;
|
|
158
160
|
if (this.isSafari) {
|
|
159
|
-
const zoomLevel = bestGuessBrowserZoom();
|
|
161
|
+
const zoomLevel = bestGuessBrowserZoom(this.ownerDocument);
|
|
160
162
|
targetRenderScale *= Math.max(1, zoomLevel);
|
|
161
163
|
}
|
|
162
164
|
targetPixelWidth = Math.round(this.parentWidth) * targetRenderScale;
|
|
@@ -332,7 +334,7 @@ class ShaderMount {
|
|
|
332
334
|
/** Set an animation speed (or 0 to stop animation) */
|
|
333
335
|
setSpeed = (newSpeed = 1) => {
|
|
334
336
|
this.speed = newSpeed;
|
|
335
|
-
this.setCurrentSpeed(
|
|
337
|
+
this.setCurrentSpeed(this.ownerDocument.hidden ? 0 : newSpeed);
|
|
336
338
|
};
|
|
337
339
|
setCurrentSpeed = (newSpeed) => {
|
|
338
340
|
this.currentSpeed = newSpeed;
|
|
@@ -362,7 +364,7 @@ class ShaderMount {
|
|
|
362
364
|
this.render(performance.now());
|
|
363
365
|
};
|
|
364
366
|
handleDocumentVisibilityChange = () => {
|
|
365
|
-
this.setCurrentSpeed(
|
|
367
|
+
this.setCurrentSpeed(this.ownerDocument.hidden ? 0 : this.speed);
|
|
366
368
|
};
|
|
367
369
|
/** Dispose of the shader mount, cleaning up all of the WebGL resources */
|
|
368
370
|
dispose = () => {
|
|
@@ -389,7 +391,7 @@ class ShaderMount {
|
|
|
389
391
|
this.resizeObserver = null;
|
|
390
392
|
}
|
|
391
393
|
visualViewport?.removeEventListener("resize", this.handleVisualViewportChange);
|
|
392
|
-
|
|
394
|
+
this.ownerDocument.removeEventListener("visibilitychange", this.handleDocumentVisibilityChange);
|
|
393
395
|
this.uniformLocations = {};
|
|
394
396
|
this.canvasElement.remove();
|
|
395
397
|
delete this.parentElement.paperShaderMount;
|
|
@@ -460,10 +462,10 @@ function isSafari() {
|
|
|
460
462
|
const ua = navigator.userAgent.toLowerCase();
|
|
461
463
|
return ua.includes("safari") && !ua.includes("chrome") && !ua.includes("android");
|
|
462
464
|
}
|
|
463
|
-
function bestGuessBrowserZoom() {
|
|
465
|
+
function bestGuessBrowserZoom(doc) {
|
|
464
466
|
const viewportScale = visualViewport?.scale ?? 1;
|
|
465
467
|
const viewportWidth = visualViewport?.width ?? window.innerWidth;
|
|
466
|
-
const scrollbarWidth = window.innerWidth -
|
|
468
|
+
const scrollbarWidth = window.innerWidth - doc.documentElement.clientWidth;
|
|
467
469
|
const innerWidth = viewportScale * viewportWidth + scrollbarWidth;
|
|
468
470
|
const ratio = outerWidth / innerWidth;
|
|
469
471
|
const zoomPercentageRounded = Math.round(100 * ratio);
|
package/dist/shader-mount.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/shader-mount.ts"],
|
|
4
|
-
"sourcesContent": ["import { vertexShaderSource } from './vertex-shader.js';\n\nconst DEFAULT_MAX_PIXEL_COUNT: number = 1920 * 1080 * 4;\n\nexport class ShaderMount {\n public parentElement: PaperShaderElement;\n public canvasElement: HTMLCanvasElement;\n private gl: WebGL2RenderingContext;\n private program: WebGLProgram | null = null;\n private uniformLocations: Record<string, WebGLUniformLocation | null> = {};\n /** The fragment shader that we are using */\n private fragmentShader: string;\n /** Stores the RAF for the render loop */\n private rafId: number | null = null;\n /** Time of the last rendered frame */\n private lastRenderTime = 0;\n /** Total time that we have played any animation, passed as a uniform to the shader for time-based VFX */\n private currentFrame = 0;\n /** The speed that we progress through animation time (multiplies by delta time every update). Allows negatives to play in reverse. If set to 0, rAF will stop entirely so static shaders have no recurring performance costs */\n private speed = 0;\n /** Actual speed used that accounts for document visibility (we pause the shader if the tab is hidden) */\n private currentSpeed = 0;\n /** Uniforms that are provided by the user for the specific shader being mounted (not including uniforms that this Mount adds, like time and resolution) */\n private providedUniforms: ShaderMountUniforms;\n /** Names of the uniforms that should have mipmaps generated for them */\n private mipmaps: string[] = [];\n /** Just a sanity check to make sure frames don't run after we're disposed */\n private hasBeenDisposed = false;\n /** If the resolution of the canvas has changed since the last render */\n private resolutionChanged = true;\n /** Store textures that are provided by the user */\n private textures: Map<string, WebGLTexture> = new Map();\n private minPixelRatio;\n private maxPixelCount;\n private isSafari = isSafari();\n private uniformCache: Record<string, unknown> = {};\n private textureUnitMap: Map<string, number> = new Map();\n\n constructor(\n /** The div you'd like to mount the shader to. The shader will match its size. */\n parentElement: HTMLElement,\n fragmentShader: string,\n uniforms: ShaderMountUniforms,\n webGlContextAttributes?: WebGLContextAttributes,\n /** The speed of the animation, or 0 to stop it. Supports negative values to play in reverse. */\n speed = 0,\n /** Pass a frame to offset the starting u_time value and give deterministic results*/\n frame = 0,\n /**\n * The minimum pixel ratio to render at, defaults to 2.\n * May be reduced to improve performance or increased together with `maxPixelCount` to improve antialiasing.\n */\n minPixelRatio = 2,\n /**\n * The maximum amount of physical device pixels to render for the shader,\n * by default it's 1920 * 1080 * 2x dpi (per each side) = 8,294,400 pixels of a 4K screen.\n * Actual DOM size of the canvas can be larger, it will just lose quality after this.\n *\n * May be reduced to improve performance or increased to improve quality on high-resolution screens.\n */\n maxPixelCount: number = DEFAULT_MAX_PIXEL_COUNT,\n /** Names of the uniforms that should have mipmaps generated for them */\n mipmaps: string[] = []\n ) {\n if (parentElement instanceof HTMLElement) {\n this.parentElement = parentElement as PaperShaderElement;\n } else {\n throw new Error('Paper Shaders: parent element must be an HTMLElement');\n }\n\n if (!document.querySelector('style[data-paper-shader]')) {\n const styleElement = document.createElement('style');\n styleElement.innerHTML = defaultStyle;\n styleElement.setAttribute('data-paper-shader', '');\n document.head.prepend(styleElement);\n }\n\n // Create the canvas element and mount it into the provided element\n const canvasElement = document.createElement('canvas');\n this.canvasElement = canvasElement;\n this.parentElement.prepend(canvasElement);\n this.fragmentShader = fragmentShader;\n this.providedUniforms = uniforms;\n this.mipmaps = mipmaps;\n // Base our starting animation time on the provided frame value\n this.currentFrame = frame;\n this.minPixelRatio = minPixelRatio;\n this.maxPixelCount = maxPixelCount;\n\n const gl = canvasElement.getContext('webgl2', webGlContextAttributes);\n if (!gl) {\n throw new Error('Paper Shaders: WebGL is not supported in this browser');\n }\n this.gl = gl;\n\n this.initProgram();\n this.setupPositionAttribute();\n // Grab the locations of the uniforms in the fragment shader\n this.setupUniforms();\n // Put the user provided values into the uniforms\n this.setUniformValues(this.providedUniforms);\n // Set up the resize observer to handle window resizing and set u_resolution\n this.setupResizeObserver();\n // Set up the visual viewport change listener to handle zoom changes (pinch zoom and classic browser zoom)\n visualViewport?.addEventListener('resize', this.handleVisualViewportChange);\n\n // Set the animation speed after everything is ready to go\n this.setSpeed(speed);\n\n // Mark parent element as paper shader mount\n this.parentElement.setAttribute('data-paper-shader', '');\n\n // Add the shaderMount instance to the div mount element to make it easily accessible\n this.parentElement.paperShaderMount = this;\n\n // Listen for document visibility changes to pause the shader when the tab is hidden\n document.addEventListener('visibilitychange', this.handleDocumentVisibilityChange);\n }\n\n private initProgram = () => {\n const program = createProgram(this.gl, vertexShaderSource, this.fragmentShader);\n if (!program) return;\n this.program = program;\n };\n\n private setupPositionAttribute = () => {\n const positionAttributeLocation = this.gl.getAttribLocation(this.program!, 'a_position');\n const positionBuffer = this.gl.createBuffer();\n this.gl.bindBuffer(this.gl.ARRAY_BUFFER, positionBuffer);\n const positions = [-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1];\n this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(positions), this.gl.STATIC_DRAW);\n this.gl.enableVertexAttribArray(positionAttributeLocation);\n this.gl.vertexAttribPointer(positionAttributeLocation, 2, this.gl.FLOAT, false, 0, 0);\n };\n\n private setupUniforms = () => {\n // Create a map to store all uniform locations\n const uniformLocations: Record<string, WebGLUniformLocation | null> = {\n u_time: this.gl.getUniformLocation(this.program!, 'u_time'),\n u_pixelRatio: this.gl.getUniformLocation(this.program!, 'u_pixelRatio'),\n u_resolution: this.gl.getUniformLocation(this.program!, 'u_resolution'),\n };\n\n // Add locations for all provided uniforms\n Object.entries(this.providedUniforms).forEach(([key, value]) => {\n uniformLocations[key] = this.gl.getUniformLocation(this.program!, key);\n\n // For texture uniforms, also look for the aspect ratio uniform\n if (value instanceof HTMLImageElement) {\n const aspectRatioUniformName = `${key}AspectRatio`;\n uniformLocations[aspectRatioUniformName] = this.gl.getUniformLocation(this.program!, aspectRatioUniformName);\n }\n });\n\n this.uniformLocations = uniformLocations;\n };\n\n /**\n * The scale that we should render at.\n * - Used to target 2x rendering even on 1x screens for better antialiasing\n * - Prevents the virtual resolution from going beyond the maximum resolution\n * - Accounts for the page zoom level so we render in physical device pixels rather than CSS pixels\n */\n private renderScale = 1;\n private parentWidth = 0;\n private parentHeight = 0;\n private parentDevicePixelWidth = 0;\n private parentDevicePixelHeight = 0;\n private devicePixelsSupported = false;\n\n private resizeObserver: ResizeObserver | null = null;\n private setupResizeObserver = () => {\n this.resizeObserver = new ResizeObserver(([entry]) => {\n if (entry?.borderBoxSize[0]) {\n const physicalPixelSize = entry.devicePixelContentBoxSize?.[0];\n\n if (physicalPixelSize !== undefined) {\n this.devicePixelsSupported = true;\n this.parentDevicePixelWidth = physicalPixelSize.inlineSize;\n this.parentDevicePixelHeight = physicalPixelSize.blockSize;\n }\n\n this.parentWidth = entry.borderBoxSize[0].inlineSize;\n this.parentHeight = entry.borderBoxSize[0].blockSize;\n }\n\n this.handleResize();\n });\n\n this.resizeObserver.observe(this.parentElement);\n };\n\n // Visual viewport resize handler, mainly used to react to browser zoom changes.\n // Resize observer by itself does not react to pinch zoom, and although it usually\n // reacts to classic browser zoom, it's not guaranteed in edge cases.\n // Since timing between visual viewport changes and resize observer is complex\n // and because we'd like to know the device pixel sizes of elements, we just restart\n // the observer to get a guaranteed fresh callback regardless if it would have triggered or not.\n private handleVisualViewportChange = () => {\n this.resizeObserver?.disconnect();\n this.setupResizeObserver();\n\n // In case of debugging timing, from here on:\n // - animation frame 1: a paint after the visual viewport resize\n // - animation frame 2: a paint after the resize observer has been handled, if it was ever triggered\n };\n\n /** Resize handler for when the container div changes size or the max pixel count changes and we want to resize our canvas to match */\n private handleResize = () => {\n // Aim to render at least as many pixels as physically displayed\n // This will overshoot when the user zooms out, but that's acceptable\n\n let targetPixelWidth = 0;\n let targetPixelHeight = 0;\n\n // If window.devicePixelRatio is below 1, it's safe to say the browser is just zoomed out\n // We can use 1 as the minimum value not to upscale it needlessly to meet the min pixel ratio param\n const dpr = Math.max(1, window.devicePixelRatio);\n const pinchZoom = visualViewport?.scale ?? 1;\n\n if (this.devicePixelsSupported) {\n // Use the real pixel size if we know it, plus meet the min pixel ratio requirement and add in pinch zoom\n const scaleToMeetMinPixelRatio = Math.max(1, this.minPixelRatio / dpr);\n targetPixelWidth = this.parentDevicePixelWidth * scaleToMeetMinPixelRatio * pinchZoom;\n targetPixelHeight = this.parentDevicePixelHeight * scaleToMeetMinPixelRatio * pinchZoom;\n } else {\n // Otherwise try to approximate the element size in device pixels using devicePixelRatio.\n // (devicePixelRatio is imprecise and element's width/height may be fractional CSS sizes, not real pixels).\n let targetRenderScale = Math.max(dpr, this.minPixelRatio) * pinchZoom;\n\n if (this.isSafari) {\n // As of 2025, Safari reports physical devicePixelRatio, but other browsers add the current zoom level:\n // https://bugs.webkit.org/show_bug.cgi?id=124862\n //\n // In Safari we need to factor in the zoom level manually in order to set the target resolution.\n // To avoid sidebars upscaling the target resolution, set a minimum zoom level of 1.\n // This will render at higher resolution when zoomed out, but that's fine.\n // (We mostly care about maintaining good quality when zoomed in).\n const zoomLevel = bestGuessBrowserZoom();\n targetRenderScale *= Math.max(1, zoomLevel);\n }\n\n // Rounding the client width/height since they may be fractional in CSS layout values\n targetPixelWidth = Math.round(this.parentWidth) * targetRenderScale;\n targetPixelHeight = Math.round(this.parentHeight) * targetRenderScale;\n }\n\n // Prevent the total rendered pixel count from exceeding maxPixelCount\n const maxPixelCountHeadroom = Math.sqrt(this.maxPixelCount) / Math.sqrt(targetPixelWidth * targetPixelHeight);\n const scaleToMeetMaxPixelCount = Math.min(1, maxPixelCountHeadroom);\n const newWidth = Math.round(targetPixelWidth * scaleToMeetMaxPixelCount);\n const newHeight = Math.round(targetPixelHeight * scaleToMeetMaxPixelCount);\n const newRenderScale = newWidth / Math.round(this.parentWidth);\n\n if (\n this.canvasElement.width !== newWidth ||\n this.canvasElement.height !== newHeight ||\n this.renderScale !== newRenderScale // Usually, only render scale changes when the user zooms in/out\n ) {\n this.renderScale = newRenderScale;\n this.canvasElement.width = newWidth;\n this.canvasElement.height = newHeight;\n this.resolutionChanged = true;\n this.gl.viewport(0, 0, this.gl.canvas.width, this.gl.canvas.height);\n\n // this is necessary to avoid flashes while resizing (the next scheduled render will set uniforms)\n this.render(performance.now());\n }\n };\n\n private render = (currentTime: number) => {\n if (this.hasBeenDisposed) return;\n\n if (this.program === null) {\n console.warn('Tried to render before program or gl was initialized');\n return;\n }\n\n // Calculate the delta time\n const dt = currentTime - this.lastRenderTime;\n this.lastRenderTime = currentTime;\n // Increase the total animation time by dt * animationSpeed\n if (this.currentSpeed !== 0) {\n this.currentFrame += dt * this.currentSpeed;\n }\n\n // Clear the canvas\n this.gl.clear(this.gl.COLOR_BUFFER_BIT);\n\n // Update uniforms\n this.gl.useProgram(this.program);\n\n // Update the time uniform\n this.gl.uniform1f(this.uniformLocations.u_time!, this.currentFrame * 0.001);\n\n // If the resolution has changed, we need to update the uniform\n if (this.resolutionChanged) {\n this.gl.uniform2f(this.uniformLocations.u_resolution!, this.gl.canvas.width, this.gl.canvas.height);\n this.gl.uniform1f(this.uniformLocations.u_pixelRatio!, this.renderScale);\n this.resolutionChanged = false;\n }\n\n this.gl.drawArrays(this.gl.TRIANGLES, 0, 6);\n\n // Loop if we're animating\n if (this.currentSpeed !== 0) {\n this.requestRender();\n } else {\n this.rafId = null;\n }\n };\n\n private requestRender = () => {\n if (this.rafId !== null) {\n cancelAnimationFrame(this.rafId);\n }\n this.rafId = requestAnimationFrame(this.render);\n };\n\n /** Creates a texture from an image and sets it into a uniform value */\n private setTextureUniform = (uniformName: string, image: HTMLImageElement): void => {\n if (!image.complete || image.naturalWidth === 0) {\n throw new Error(`Paper Shaders: image for uniform ${uniformName} must be fully loaded`);\n }\n\n // Clean up existing texture if present\n const existingTexture = this.textures.get(uniformName);\n if (existingTexture) {\n this.gl.deleteTexture(existingTexture);\n }\n\n // Get texture unit\n if (!this.textureUnitMap.has(uniformName)) {\n this.textureUnitMap.set(uniformName, this.textureUnitMap.size);\n }\n const textureUnit = this.textureUnitMap.get(uniformName)!;\n // Activate correct texture unit before creating the texture\n this.gl.activeTexture(this.gl.TEXTURE0 + textureUnit);\n\n // Create and set up the new texture\n const texture = this.gl.createTexture();\n this.gl.bindTexture(this.gl.TEXTURE_2D, texture);\n\n // Set texture parameters\n this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);\n this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);\n this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR);\n this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.LINEAR);\n\n // Upload image to texture\n this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, this.gl.RGBA, this.gl.UNSIGNED_BYTE, image);\n\n // Generate mipmaps if the uniform is in the mipmaps list\n if (this.mipmaps.includes(uniformName)) {\n this.gl.generateMipmap(this.gl.TEXTURE_2D);\n this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR_MIPMAP_LINEAR);\n }\n\n const error = this.gl.getError();\n if (error !== this.gl.NO_ERROR || texture === null) {\n console.error('Paper Shaders: WebGL error when uploading texture:', error);\n return;\n }\n\n // Store the texture\n this.textures.set(uniformName, texture);\n\n // Set up texture unit and uniform\n const location = this.uniformLocations[uniformName];\n if (location) {\n this.gl.uniform1i(location, textureUnit);\n\n // Calculate and set the aspect ratio uniform\n const aspectRatioUniformName = `${uniformName}AspectRatio`;\n const aspectRatioLocation = this.uniformLocations[aspectRatioUniformName];\n if (aspectRatioLocation) {\n const aspectRatio = image.naturalWidth / image.naturalHeight;\n this.gl.uniform1f(aspectRatioLocation, aspectRatio);\n }\n }\n };\n\n /** Utility: recursive equality test for all the uniforms */\n private areUniformValuesEqual = (a: any, b: any): boolean => {\n if (a === b) return true;\n if (Array.isArray(a) && Array.isArray(b) && a.length === b.length) {\n return a.every((val, i) => this.areUniformValuesEqual(val, (b as any)[i]));\n }\n return false;\n };\n\n /** Sets the provided uniform values into the WebGL program, can be a partial list of uniforms that have changed */\n private setUniformValues = (updatedUniforms: ShaderMountUniforms) => {\n this.gl.useProgram(this.program);\n Object.entries(updatedUniforms).forEach(([key, value]) => {\n // Grab the value to use in the uniform cache\n let cacheValue: ShaderMountUniforms[keyof ShaderMountUniforms] | string = value;\n if (value instanceof HTMLImageElement) {\n // Images use their src for the cache value to save memory\n cacheValue = `${value.src.slice(0, 200)}|${value.naturalWidth}x${value.naturalHeight}`;\n }\n\n // Check if the uniform value has changed and, if not, bail early to avoid extra work\n if (this.areUniformValuesEqual(this.uniformCache[key], cacheValue)) return;\n // Update the uniform cache if we are still here\n this.uniformCache[key] = cacheValue;\n\n const location = this.uniformLocations[key];\n if (!location) {\n console.warn(`Uniform location for ${key} not found`);\n return;\n }\n\n if (value instanceof HTMLImageElement) {\n // Texture case, requires a good amount of code so it gets its own function:\n this.setTextureUniform(key, value);\n } else if (Array.isArray(value)) {\n // Array case\n let flatArray: number[] | null = null;\n let valueLength: number | null = null;\n\n // If it's an array of same-sized arrays, flatten it down so we can set the uniform\n if (value[0] !== undefined && Array.isArray(value[0])) {\n const firstChildLength = value[0].length;\n if (value.every((arr) => (arr as number[]).length === firstChildLength)) {\n // Array of same-sized arrays case, flattens the array sets it\n flatArray = value.flat();\n valueLength = firstChildLength;\n } else {\n console.warn(`All child arrays must be the same length for ${key}`);\n return;\n }\n } else {\n // Array of primitive values case, supports 2, 3, 4, 9, 16 length arrays\n flatArray = value as number[];\n valueLength = flatArray.length;\n }\n\n // Set the uniform based on array length... supports 2, 3, 4, 9, 16 length arrays of primitive values\n // or arbitrary length arrays of arrays\n switch (valueLength) {\n case 2:\n this.gl.uniform2fv(location, flatArray);\n break;\n case 3:\n this.gl.uniform3fv(location, flatArray);\n break;\n case 4:\n this.gl.uniform4fv(location, flatArray);\n break;\n case 9:\n this.gl.uniformMatrix3fv(location, false, flatArray);\n break;\n case 16:\n this.gl.uniformMatrix4fv(location, false, flatArray);\n break;\n default:\n console.warn(`Unsupported uniform array length: ${valueLength}`);\n }\n } else if (typeof value === 'number') {\n // Number case, supports floats and ints\n this.gl.uniform1f(location, value);\n } else if (typeof value === 'boolean') {\n // Boolean case, supports true and false\n this.gl.uniform1i(location, value ? 1 : 0);\n } else {\n // May happen on the server for SSR when undefined images are passed in\n console.warn(`Unsupported uniform type for ${key}: ${typeof value}`);\n }\n });\n };\n\n /** Gets the current total animation time from 0ms */\n public getCurrentFrame = (): number => {\n return this.currentFrame;\n };\n\n /** Set a frame to get a deterministic result, frames are literally just milliseconds from zero since the animation started */\n public setFrame = (newFrame: number): void => {\n this.currentFrame = newFrame;\n this.lastRenderTime = performance.now();\n this.render(performance.now());\n };\n\n /** Set an animation speed (or 0 to stop animation) */\n public setSpeed = (newSpeed = 1): void => {\n // Set the new animation speed\n this.speed = newSpeed;\n this.setCurrentSpeed(document.hidden ? 0 : newSpeed);\n };\n\n private setCurrentSpeed = (newSpeed: number): void => {\n this.currentSpeed = newSpeed;\n\n if (this.rafId === null && newSpeed !== 0) {\n // Moving from 0 to animating, kick off a new rAF loop\n this.lastRenderTime = performance.now();\n this.rafId = requestAnimationFrame(this.render);\n }\n\n if (this.rafId !== null && newSpeed === 0) {\n // Moving from animating to not animating, cancel the rAF loop\n cancelAnimationFrame(this.rafId);\n this.rafId = null;\n }\n };\n\n /** Set the maximum pixel count for the shader, this will limit the number of pixels that will be rendered */\n public setMaxPixelCount = (newMaxPixelCount: number = DEFAULT_MAX_PIXEL_COUNT): void => {\n this.maxPixelCount = newMaxPixelCount;\n\n this.handleResize();\n };\n\n /** Set the minimum pixel ratio for the shader */\n public setMinPixelRatio = (newMinPixelRatio: number = 2): void => {\n this.minPixelRatio = newMinPixelRatio;\n\n this.handleResize();\n };\n\n /** Update the uniforms that are provided by the outside shader, can be a partial set with only the uniforms that have changed */\n public setUniforms = (newUniforms: ShaderMountUniforms): void => {\n this.setUniformValues(newUniforms);\n this.providedUniforms = { ...this.providedUniforms, ...newUniforms };\n\n this.render(performance.now());\n };\n\n private handleDocumentVisibilityChange = () => {\n this.setCurrentSpeed(document.hidden ? 0 : this.speed);\n };\n\n /** Dispose of the shader mount, cleaning up all of the WebGL resources */\n public dispose = (): void => {\n // Immediately mark as disposed to prevent future renders from leaking in\n this.hasBeenDisposed = true;\n\n // Cancel the rAF loop\n if (this.rafId !== null) {\n cancelAnimationFrame(this.rafId);\n this.rafId = null;\n }\n\n if (this.gl && this.program) {\n // Clean up all textures\n this.textures.forEach((texture) => {\n this.gl.deleteTexture(texture);\n });\n this.textures.clear();\n\n this.gl.deleteProgram(this.program);\n this.program = null;\n\n // Reset the WebGL context\n this.gl.bindBuffer(this.gl.ARRAY_BUFFER, null);\n this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, null);\n this.gl.bindRenderbuffer(this.gl.RENDERBUFFER, null);\n this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, null);\n\n // Clear any errors\n this.gl.getError();\n }\n\n if (this.resizeObserver) {\n this.resizeObserver.disconnect();\n this.resizeObserver = null;\n }\n\n visualViewport?.removeEventListener('resize', this.handleVisualViewportChange);\n document.removeEventListener('visibilitychange', this.handleDocumentVisibilityChange);\n\n this.uniformLocations = {};\n\n // Remove the shader from the div wrapper element\n this.canvasElement.remove();\n // Free up the reference to self to enable garbage collection\n delete this.parentElement.paperShaderMount;\n };\n}\n\nfunction createShader(gl: WebGL2RenderingContext, type: number, source: string): WebGLShader | null {\n const shader = gl.createShader(type);\n if (!shader) return null;\n\n gl.shaderSource(shader, source);\n gl.compileShader(shader);\n\n if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n console.error('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(shader));\n gl.deleteShader(shader);\n return null;\n }\n\n return shader;\n}\n\nfunction createProgram(\n gl: WebGL2RenderingContext,\n vertexShaderSource: string,\n fragmentShaderSource: string\n): WebGLProgram | null {\n const format = gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT);\n const precision = format ? format.precision : null;\n // MEDIUM_FLOAT precision can be 10, 16 or 23 bits depending on device;\n // Shaders fail on 10 bit (and 16 bit is hard to test) => we force 23-bit by switching to highp\n if (precision && precision < 23) {\n vertexShaderSource = vertexShaderSource.replace(/precision\\s+(lowp|mediump)\\s+float;/g, 'precision highp float;');\n fragmentShaderSource = fragmentShaderSource\n .replace(/precision\\s+(lowp|mediump)\\s+float/g, 'precision highp float')\n .replace(/\\b(uniform|varying|attribute)\\s+(lowp|mediump)\\s+(\\w+)/g, '$1 highp $3');\n }\n\n const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);\n const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);\n\n if (!vertexShader || !fragmentShader) return null;\n\n const program = gl.createProgram();\n if (!program) return null;\n\n gl.attachShader(program, vertexShader);\n gl.attachShader(program, fragmentShader);\n gl.linkProgram(program);\n\n if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n console.error('Unable to initialize the shader program: ' + gl.getProgramInfoLog(program));\n gl.deleteProgram(program);\n gl.deleteShader(vertexShader);\n gl.deleteShader(fragmentShader);\n return null;\n }\n\n // Clean up shaders after successful linking\n gl.detachShader(program, vertexShader);\n gl.detachShader(program, fragmentShader);\n gl.deleteShader(vertexShader);\n gl.deleteShader(fragmentShader);\n\n return program;\n}\n\nconst defaultStyle = `@layer paper-shaders {\n :where([data-paper-shader]) {\n isolation: isolate;\n position: relative;\n\n & canvas {\n contain: strict;\n display: block;\n position: absolute;\n inset: 0;\n z-index: -1;\n width: 100%;\n height: 100%;\n border-radius: inherit;\n corner-shape: inherit;\n }\n }\n}`;\n\n/** The parent `<div>` element that has a ShaderMount available on it */\nexport interface PaperShaderElement extends HTMLElement {\n paperShaderMount: ShaderMount | undefined;\n}\n\n/** Check if an element is a Paper shader element */\nexport function isPaperShaderElement(element: HTMLElement): element is PaperShaderElement {\n return 'paperShaderMount' in element;\n}\n\n/**\n * Uniform types that we support to be auto-mapped into the fragment shader\n *\n * We accept undefined as a convenience for server rendering, when some things may be undefined\n * We just skip setting the uniform if it's undefined. This allows the shader mount to still take up space during server rendering\n */\nexport interface ShaderMountUniforms {\n [key: string]: boolean | number | number[] | number[][] | HTMLImageElement | undefined;\n}\n\nexport interface ShaderMotionParams {\n speed?: number;\n frame?: number;\n}\n\nexport type ShaderPreset<T> = {\n name: string;\n params: Required<T>;\n};\n\nexport type ImageShaderPreset<T> = {\n name: string;\n /**\n * Params for the shader excluding the image.\n * Image is excluded as it isn't considered a preset,\n * e.g. when switching between presets it shouldn't switch the image.\n *\n * While we exclude images from presets they should still be set with a default prop value so the code-first usage of shaders remains great.\n */\n params: Required<Omit<T, 'image'>>;\n};\n\nfunction isSafari() {\n const ua = navigator.userAgent.toLowerCase();\n return ua.includes('safari') && !ua.includes('chrome') && !ua.includes('android');\n}\n\n// Zoom level can be estimated comparing the browser's outerWidth and the viewport width.\n// It's nowhere near perfect because it's affected by the presence of browser sidebars,\n// like a vertical web inspector or Arc's sidebar. Also, both outerWidth and innerWidth\n// are integers, which would almost never give us a perfect ratio at face values.\n//\n// Still, this is pretty accurate in the vast majority of cases.\n//\n// Note 1:\n// Avoid innerWidth, use visualViewport.width instead.\n// - innerWidth is affected by pinch zoom in Safari, but not other browsers.\n// visualViewport.width works consistently in all browsers.\n// - innerWidth is rounded to integer, but not visualViewport.width.\n// - visualViewport.width is affected by hard scrollbars, so they need to be added manually\n//\n// Note 2:\n// Opening a sidebar in Safari like web inspector or bookmarks will throw off the zoom\n// level detection and result in a larger target resolution. Not a concern in real-world usage\n// with Safari, but we'd rather not try to detect zoom levels with other browsers\n// (e.g. Arc always has a sidebar, which affects outerWidth vs visualViewport.width).\nfunction bestGuessBrowserZoom() {\n const viewportScale = visualViewport?.scale ?? 1;\n const viewportWidth = visualViewport?.width ?? window.innerWidth;\n const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;\n const innerWidth = viewportScale * viewportWidth + scrollbarWidth;\n\n // outerWidth and innerWidth are always integers so we won't often get the original zoom ratio\n // E.g. given a 125% zoom, outerWidth = 1657, innerWidth = 1325, 1657 / 1325 = 1.2505660377\n // We check for common zoom levels and return the closest one if found.\n\n const ratio = outerWidth / innerWidth;\n const zoomPercentageRounded = Math.round(100 * ratio);\n\n // All zoom levels divisible by 5%\n if (zoomPercentageRounded % 5 === 0) {\n return zoomPercentageRounded / 100;\n }\n\n // 33% zoom\n if (zoomPercentageRounded === 33) {\n return 1 / 3;\n }\n\n // 67% zoom\n if (zoomPercentageRounded === 67) {\n return 2 / 3;\n }\n\n // 133% zoom\n if (zoomPercentageRounded === 133) {\n return 4 / 3;\n }\n\n return ratio;\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import { vertexShaderSource } from './vertex-shader.js';\n\nconst DEFAULT_MAX_PIXEL_COUNT: number = 1920 * 1080 * 4;\n\nexport class ShaderMount {\n public parentElement: PaperShaderElement;\n public canvasElement: HTMLCanvasElement;\n private gl: WebGL2RenderingContext;\n private program: WebGLProgram | null = null;\n private uniformLocations: Record<string, WebGLUniformLocation | null> = {};\n /** The fragment shader that we are using */\n private fragmentShader: string;\n /** Stores the RAF for the render loop */\n private rafId: number | null = null;\n /** Time of the last rendered frame */\n private lastRenderTime = 0;\n /** Total time that we have played any animation, passed as a uniform to the shader for time-based VFX */\n private currentFrame = 0;\n /** The speed that we progress through animation time (multiplies by delta time every update). Allows negatives to play in reverse. If set to 0, rAF will stop entirely so static shaders have no recurring performance costs */\n private speed = 0;\n /** Actual speed used that accounts for document visibility (we pause the shader if the tab is hidden) */\n private currentSpeed = 0;\n /** Uniforms that are provided by the user for the specific shader being mounted (not including uniforms that this Mount adds, like time and resolution) */\n private providedUniforms: ShaderMountUniforms;\n /** Names of the uniforms that should have mipmaps generated for them */\n private mipmaps: string[] = [];\n /** Just a sanity check to make sure frames don't run after we're disposed */\n private hasBeenDisposed = false;\n /** If the resolution of the canvas has changed since the last render */\n private resolutionChanged = true;\n /** Store textures that are provided by the user */\n private textures: Map<string, WebGLTexture> = new Map();\n private minPixelRatio;\n private maxPixelCount;\n private isSafari = isSafari();\n private uniformCache: Record<string, unknown> = {};\n private textureUnitMap: Map<string, number> = new Map();\n private ownerDocument: Document;\n\n constructor(\n /** The div you'd like to mount the shader to. The shader will match its size. */\n parentElement: HTMLElement,\n fragmentShader: string,\n uniforms: ShaderMountUniforms,\n webGlContextAttributes?: WebGLContextAttributes,\n /** The speed of the animation, or 0 to stop it. Supports negative values to play in reverse. */\n speed = 0,\n /** Pass a frame to offset the starting u_time value and give deterministic results*/\n frame = 0,\n /**\n * The minimum pixel ratio to render at, defaults to 2.\n * May be reduced to improve performance or increased together with `maxPixelCount` to improve antialiasing.\n */\n minPixelRatio = 2,\n /**\n * The maximum amount of physical device pixels to render for the shader,\n * by default it's 1920 * 1080 * 2x dpi (per each side) = 8,294,400 pixels of a 4K screen.\n * Actual DOM size of the canvas can be larger, it will just lose quality after this.\n *\n * May be reduced to improve performance or increased to improve quality on high-resolution screens.\n */\n maxPixelCount: number = DEFAULT_MAX_PIXEL_COUNT,\n /** Names of the uniforms that should have mipmaps generated for them */\n mipmaps: string[] = []\n ) {\n // nodeType check instead of `instanceof` to work across document boundaries (iframes, PiP windows)\n if (parentElement?.nodeType === 1) {\n this.parentElement = parentElement as PaperShaderElement;\n } else {\n throw new Error('Paper Shaders: parent element must be an HTMLElement');\n }\n\n this.ownerDocument = parentElement.ownerDocument;\n\n if (!this.ownerDocument.querySelector('style[data-paper-shader]')) {\n const styleElement = this.ownerDocument.createElement('style');\n styleElement.innerHTML = defaultStyle;\n styleElement.setAttribute('data-paper-shader', '');\n this.ownerDocument.head.prepend(styleElement);\n }\n\n // Create the canvas element and mount it into the provided element\n const canvasElement = this.ownerDocument.createElement('canvas');\n this.canvasElement = canvasElement;\n this.parentElement.prepend(canvasElement);\n this.fragmentShader = fragmentShader;\n this.providedUniforms = uniforms;\n this.mipmaps = mipmaps;\n // Base our starting animation time on the provided frame value\n this.currentFrame = frame;\n this.minPixelRatio = minPixelRatio;\n this.maxPixelCount = maxPixelCount;\n\n const gl = canvasElement.getContext('webgl2', webGlContextAttributes);\n if (!gl) {\n throw new Error('Paper Shaders: WebGL is not supported in this browser');\n }\n this.gl = gl;\n\n this.initProgram();\n this.setupPositionAttribute();\n // Grab the locations of the uniforms in the fragment shader\n this.setupUniforms();\n // Put the user provided values into the uniforms\n this.setUniformValues(this.providedUniforms);\n // Set up the resize observer to handle window resizing and set u_resolution\n this.setupResizeObserver();\n // Set up the visual viewport change listener to handle zoom changes (pinch zoom and classic browser zoom)\n visualViewport?.addEventListener('resize', this.handleVisualViewportChange);\n\n // Set the animation speed after everything is ready to go\n this.setSpeed(speed);\n\n // Mark parent element as paper shader mount\n this.parentElement.setAttribute('data-paper-shader', '');\n\n // Add the shaderMount instance to the div mount element to make it easily accessible\n this.parentElement.paperShaderMount = this;\n\n // Listen for document visibility changes to pause the shader when the tab is hidden\n this.ownerDocument.addEventListener('visibilitychange', this.handleDocumentVisibilityChange);\n }\n\n private initProgram = () => {\n const program = createProgram(this.gl, vertexShaderSource, this.fragmentShader);\n if (!program) return;\n this.program = program;\n };\n\n private setupPositionAttribute = () => {\n const positionAttributeLocation = this.gl.getAttribLocation(this.program!, 'a_position');\n const positionBuffer = this.gl.createBuffer();\n this.gl.bindBuffer(this.gl.ARRAY_BUFFER, positionBuffer);\n const positions = [-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1];\n this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(positions), this.gl.STATIC_DRAW);\n this.gl.enableVertexAttribArray(positionAttributeLocation);\n this.gl.vertexAttribPointer(positionAttributeLocation, 2, this.gl.FLOAT, false, 0, 0);\n };\n\n private setupUniforms = () => {\n // Create a map to store all uniform locations\n const uniformLocations: Record<string, WebGLUniformLocation | null> = {\n u_time: this.gl.getUniformLocation(this.program!, 'u_time'),\n u_pixelRatio: this.gl.getUniformLocation(this.program!, 'u_pixelRatio'),\n u_resolution: this.gl.getUniformLocation(this.program!, 'u_resolution'),\n };\n\n // Add locations for all provided uniforms\n Object.entries(this.providedUniforms).forEach(([key, value]) => {\n uniformLocations[key] = this.gl.getUniformLocation(this.program!, key);\n\n // For texture uniforms, also look for the aspect ratio uniform\n if (value instanceof HTMLImageElement) {\n const aspectRatioUniformName = `${key}AspectRatio`;\n uniformLocations[aspectRatioUniformName] = this.gl.getUniformLocation(this.program!, aspectRatioUniformName);\n }\n });\n\n this.uniformLocations = uniformLocations;\n };\n\n /**\n * The scale that we should render at.\n * - Used to target 2x rendering even on 1x screens for better antialiasing\n * - Prevents the virtual resolution from going beyond the maximum resolution\n * - Accounts for the page zoom level so we render in physical device pixels rather than CSS pixels\n */\n private renderScale = 1;\n private parentWidth = 0;\n private parentHeight = 0;\n private parentDevicePixelWidth = 0;\n private parentDevicePixelHeight = 0;\n private devicePixelsSupported = false;\n\n private resizeObserver: ResizeObserver | null = null;\n private setupResizeObserver = () => {\n this.resizeObserver = new ResizeObserver(([entry]) => {\n if (entry?.borderBoxSize[0]) {\n const physicalPixelSize = entry.devicePixelContentBoxSize?.[0];\n\n if (physicalPixelSize !== undefined) {\n this.devicePixelsSupported = true;\n this.parentDevicePixelWidth = physicalPixelSize.inlineSize;\n this.parentDevicePixelHeight = physicalPixelSize.blockSize;\n }\n\n this.parentWidth = entry.borderBoxSize[0].inlineSize;\n this.parentHeight = entry.borderBoxSize[0].blockSize;\n }\n\n this.handleResize();\n });\n\n this.resizeObserver.observe(this.parentElement);\n };\n\n // Visual viewport resize handler, mainly used to react to browser zoom changes.\n // Resize observer by itself does not react to pinch zoom, and although it usually\n // reacts to classic browser zoom, it's not guaranteed in edge cases.\n // Since timing between visual viewport changes and resize observer is complex\n // and because we'd like to know the device pixel sizes of elements, we just restart\n // the observer to get a guaranteed fresh callback regardless if it would have triggered or not.\n private handleVisualViewportChange = () => {\n this.resizeObserver?.disconnect();\n this.setupResizeObserver();\n\n // In case of debugging timing, from here on:\n // - animation frame 1: a paint after the visual viewport resize\n // - animation frame 2: a paint after the resize observer has been handled, if it was ever triggered\n };\n\n /** Resize handler for when the container div changes size or the max pixel count changes and we want to resize our canvas to match */\n private handleResize = () => {\n // Aim to render at least as many pixels as physically displayed\n // This will overshoot when the user zooms out, but that's acceptable\n\n let targetPixelWidth = 0;\n let targetPixelHeight = 0;\n\n // If window.devicePixelRatio is below 1, it's safe to say the browser is just zoomed out\n // We can use 1 as the minimum value not to upscale it needlessly to meet the min pixel ratio param\n const dpr = Math.max(1, window.devicePixelRatio);\n const pinchZoom = visualViewport?.scale ?? 1;\n\n if (this.devicePixelsSupported) {\n // Use the real pixel size if we know it, plus meet the min pixel ratio requirement and add in pinch zoom\n const scaleToMeetMinPixelRatio = Math.max(1, this.minPixelRatio / dpr);\n targetPixelWidth = this.parentDevicePixelWidth * scaleToMeetMinPixelRatio * pinchZoom;\n targetPixelHeight = this.parentDevicePixelHeight * scaleToMeetMinPixelRatio * pinchZoom;\n } else {\n // Otherwise try to approximate the element size in device pixels using devicePixelRatio.\n // (devicePixelRatio is imprecise and element's width/height may be fractional CSS sizes, not real pixels).\n let targetRenderScale = Math.max(dpr, this.minPixelRatio) * pinchZoom;\n\n if (this.isSafari) {\n // As of 2025, Safari reports physical devicePixelRatio, but other browsers add the current zoom level:\n // https://bugs.webkit.org/show_bug.cgi?id=124862\n //\n // In Safari we need to factor in the zoom level manually in order to set the target resolution.\n // To avoid sidebars upscaling the target resolution, set a minimum zoom level of 1.\n // This will render at higher resolution when zoomed out, but that's fine.\n // (We mostly care about maintaining good quality when zoomed in).\n const zoomLevel = bestGuessBrowserZoom(this.ownerDocument);\n targetRenderScale *= Math.max(1, zoomLevel);\n }\n\n // Rounding the client width/height since they may be fractional in CSS layout values\n targetPixelWidth = Math.round(this.parentWidth) * targetRenderScale;\n targetPixelHeight = Math.round(this.parentHeight) * targetRenderScale;\n }\n\n // Prevent the total rendered pixel count from exceeding maxPixelCount\n const maxPixelCountHeadroom = Math.sqrt(this.maxPixelCount) / Math.sqrt(targetPixelWidth * targetPixelHeight);\n const scaleToMeetMaxPixelCount = Math.min(1, maxPixelCountHeadroom);\n const newWidth = Math.round(targetPixelWidth * scaleToMeetMaxPixelCount);\n const newHeight = Math.round(targetPixelHeight * scaleToMeetMaxPixelCount);\n const newRenderScale = newWidth / Math.round(this.parentWidth);\n\n if (\n this.canvasElement.width !== newWidth ||\n this.canvasElement.height !== newHeight ||\n this.renderScale !== newRenderScale // Usually, only render scale changes when the user zooms in/out\n ) {\n this.renderScale = newRenderScale;\n this.canvasElement.width = newWidth;\n this.canvasElement.height = newHeight;\n this.resolutionChanged = true;\n this.gl.viewport(0, 0, this.gl.canvas.width, this.gl.canvas.height);\n\n // this is necessary to avoid flashes while resizing (the next scheduled render will set uniforms)\n this.render(performance.now());\n }\n };\n\n private render = (currentTime: number) => {\n if (this.hasBeenDisposed) return;\n\n if (this.program === null) {\n console.warn('Tried to render before program or gl was initialized');\n return;\n }\n\n // Calculate the delta time\n const dt = currentTime - this.lastRenderTime;\n this.lastRenderTime = currentTime;\n // Increase the total animation time by dt * animationSpeed\n if (this.currentSpeed !== 0) {\n this.currentFrame += dt * this.currentSpeed;\n }\n\n // Clear the canvas\n this.gl.clear(this.gl.COLOR_BUFFER_BIT);\n\n // Update uniforms\n this.gl.useProgram(this.program);\n\n // Update the time uniform\n this.gl.uniform1f(this.uniformLocations.u_time!, this.currentFrame * 0.001);\n\n // If the resolution has changed, we need to update the uniform\n if (this.resolutionChanged) {\n this.gl.uniform2f(this.uniformLocations.u_resolution!, this.gl.canvas.width, this.gl.canvas.height);\n this.gl.uniform1f(this.uniformLocations.u_pixelRatio!, this.renderScale);\n this.resolutionChanged = false;\n }\n\n this.gl.drawArrays(this.gl.TRIANGLES, 0, 6);\n\n // Loop if we're animating\n if (this.currentSpeed !== 0) {\n this.requestRender();\n } else {\n this.rafId = null;\n }\n };\n\n private requestRender = () => {\n if (this.rafId !== null) {\n cancelAnimationFrame(this.rafId);\n }\n this.rafId = requestAnimationFrame(this.render);\n };\n\n /** Creates a texture from an image and sets it into a uniform value */\n private setTextureUniform = (uniformName: string, image: HTMLImageElement): void => {\n if (!image.complete || image.naturalWidth === 0) {\n throw new Error(`Paper Shaders: image for uniform ${uniformName} must be fully loaded`);\n }\n\n // Clean up existing texture if present\n const existingTexture = this.textures.get(uniformName);\n if (existingTexture) {\n this.gl.deleteTexture(existingTexture);\n }\n\n // Get texture unit\n if (!this.textureUnitMap.has(uniformName)) {\n this.textureUnitMap.set(uniformName, this.textureUnitMap.size);\n }\n const textureUnit = this.textureUnitMap.get(uniformName)!;\n // Activate correct texture unit before creating the texture\n this.gl.activeTexture(this.gl.TEXTURE0 + textureUnit);\n\n // Create and set up the new texture\n const texture = this.gl.createTexture();\n this.gl.bindTexture(this.gl.TEXTURE_2D, texture);\n\n // Set texture parameters\n this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);\n this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);\n this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR);\n this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.LINEAR);\n\n // Upload image to texture\n this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, this.gl.RGBA, this.gl.UNSIGNED_BYTE, image);\n\n // Generate mipmaps if the uniform is in the mipmaps list\n if (this.mipmaps.includes(uniformName)) {\n this.gl.generateMipmap(this.gl.TEXTURE_2D);\n this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR_MIPMAP_LINEAR);\n }\n\n const error = this.gl.getError();\n if (error !== this.gl.NO_ERROR || texture === null) {\n console.error('Paper Shaders: WebGL error when uploading texture:', error);\n return;\n }\n\n // Store the texture\n this.textures.set(uniformName, texture);\n\n // Set up texture unit and uniform\n const location = this.uniformLocations[uniformName];\n if (location) {\n this.gl.uniform1i(location, textureUnit);\n\n // Calculate and set the aspect ratio uniform\n const aspectRatioUniformName = `${uniformName}AspectRatio`;\n const aspectRatioLocation = this.uniformLocations[aspectRatioUniformName];\n if (aspectRatioLocation) {\n const aspectRatio = image.naturalWidth / image.naturalHeight;\n this.gl.uniform1f(aspectRatioLocation, aspectRatio);\n }\n }\n };\n\n /** Utility: recursive equality test for all the uniforms */\n private areUniformValuesEqual = (a: any, b: any): boolean => {\n if (a === b) return true;\n if (Array.isArray(a) && Array.isArray(b) && a.length === b.length) {\n return a.every((val, i) => this.areUniformValuesEqual(val, (b as any)[i]));\n }\n return false;\n };\n\n /** Sets the provided uniform values into the WebGL program, can be a partial list of uniforms that have changed */\n private setUniformValues = (updatedUniforms: ShaderMountUniforms) => {\n this.gl.useProgram(this.program);\n Object.entries(updatedUniforms).forEach(([key, value]) => {\n // Grab the value to use in the uniform cache\n let cacheValue: ShaderMountUniforms[keyof ShaderMountUniforms] | string = value;\n if (value instanceof HTMLImageElement) {\n // Images use their src for the cache value to save memory\n cacheValue = `${value.src.slice(0, 200)}|${value.naturalWidth}x${value.naturalHeight}`;\n }\n\n // Check if the uniform value has changed and, if not, bail early to avoid extra work\n if (this.areUniformValuesEqual(this.uniformCache[key], cacheValue)) return;\n // Update the uniform cache if we are still here\n this.uniformCache[key] = cacheValue;\n\n const location = this.uniformLocations[key];\n if (!location) {\n console.warn(`Uniform location for ${key} not found`);\n return;\n }\n\n if (value instanceof HTMLImageElement) {\n // Texture case, requires a good amount of code so it gets its own function:\n this.setTextureUniform(key, value);\n } else if (Array.isArray(value)) {\n // Array case\n let flatArray: number[] | null = null;\n let valueLength: number | null = null;\n\n // If it's an array of same-sized arrays, flatten it down so we can set the uniform\n if (value[0] !== undefined && Array.isArray(value[0])) {\n const firstChildLength = value[0].length;\n if (value.every((arr) => (arr as number[]).length === firstChildLength)) {\n // Array of same-sized arrays case, flattens the array sets it\n flatArray = value.flat();\n valueLength = firstChildLength;\n } else {\n console.warn(`All child arrays must be the same length for ${key}`);\n return;\n }\n } else {\n // Array of primitive values case, supports 2, 3, 4, 9, 16 length arrays\n flatArray = value as number[];\n valueLength = flatArray.length;\n }\n\n // Set the uniform based on array length... supports 2, 3, 4, 9, 16 length arrays of primitive values\n // or arbitrary length arrays of arrays\n switch (valueLength) {\n case 2:\n this.gl.uniform2fv(location, flatArray);\n break;\n case 3:\n this.gl.uniform3fv(location, flatArray);\n break;\n case 4:\n this.gl.uniform4fv(location, flatArray);\n break;\n case 9:\n this.gl.uniformMatrix3fv(location, false, flatArray);\n break;\n case 16:\n this.gl.uniformMatrix4fv(location, false, flatArray);\n break;\n default:\n console.warn(`Unsupported uniform array length: ${valueLength}`);\n }\n } else if (typeof value === 'number') {\n // Number case, supports floats and ints\n this.gl.uniform1f(location, value);\n } else if (typeof value === 'boolean') {\n // Boolean case, supports true and false\n this.gl.uniform1i(location, value ? 1 : 0);\n } else {\n // May happen on the server for SSR when undefined images are passed in\n console.warn(`Unsupported uniform type for ${key}: ${typeof value}`);\n }\n });\n };\n\n /** Gets the current total animation time from 0ms */\n public getCurrentFrame = (): number => {\n return this.currentFrame;\n };\n\n /** Set a frame to get a deterministic result, frames are literally just milliseconds from zero since the animation started */\n public setFrame = (newFrame: number): void => {\n this.currentFrame = newFrame;\n this.lastRenderTime = performance.now();\n this.render(performance.now());\n };\n\n /** Set an animation speed (or 0 to stop animation) */\n public setSpeed = (newSpeed = 1): void => {\n // Set the new animation speed\n this.speed = newSpeed;\n this.setCurrentSpeed(this.ownerDocument.hidden ? 0 : newSpeed);\n };\n\n private setCurrentSpeed = (newSpeed: number): void => {\n this.currentSpeed = newSpeed;\n\n if (this.rafId === null && newSpeed !== 0) {\n // Moving from 0 to animating, kick off a new rAF loop\n this.lastRenderTime = performance.now();\n this.rafId = requestAnimationFrame(this.render);\n }\n\n if (this.rafId !== null && newSpeed === 0) {\n // Moving from animating to not animating, cancel the rAF loop\n cancelAnimationFrame(this.rafId);\n this.rafId = null;\n }\n };\n\n /** Set the maximum pixel count for the shader, this will limit the number of pixels that will be rendered */\n public setMaxPixelCount = (newMaxPixelCount: number = DEFAULT_MAX_PIXEL_COUNT): void => {\n this.maxPixelCount = newMaxPixelCount;\n\n this.handleResize();\n };\n\n /** Set the minimum pixel ratio for the shader */\n public setMinPixelRatio = (newMinPixelRatio: number = 2): void => {\n this.minPixelRatio = newMinPixelRatio;\n\n this.handleResize();\n };\n\n /** Update the uniforms that are provided by the outside shader, can be a partial set with only the uniforms that have changed */\n public setUniforms = (newUniforms: ShaderMountUniforms): void => {\n this.setUniformValues(newUniforms);\n this.providedUniforms = { ...this.providedUniforms, ...newUniforms };\n\n this.render(performance.now());\n };\n\n private handleDocumentVisibilityChange = () => {\n this.setCurrentSpeed(this.ownerDocument.hidden ? 0 : this.speed);\n };\n\n /** Dispose of the shader mount, cleaning up all of the WebGL resources */\n public dispose = (): void => {\n // Immediately mark as disposed to prevent future renders from leaking in\n this.hasBeenDisposed = true;\n\n // Cancel the rAF loop\n if (this.rafId !== null) {\n cancelAnimationFrame(this.rafId);\n this.rafId = null;\n }\n\n if (this.gl && this.program) {\n // Clean up all textures\n this.textures.forEach((texture) => {\n this.gl.deleteTexture(texture);\n });\n this.textures.clear();\n\n this.gl.deleteProgram(this.program);\n this.program = null;\n\n // Reset the WebGL context\n this.gl.bindBuffer(this.gl.ARRAY_BUFFER, null);\n this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, null);\n this.gl.bindRenderbuffer(this.gl.RENDERBUFFER, null);\n this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, null);\n\n // Clear any errors\n this.gl.getError();\n }\n\n if (this.resizeObserver) {\n this.resizeObserver.disconnect();\n this.resizeObserver = null;\n }\n\n visualViewport?.removeEventListener('resize', this.handleVisualViewportChange);\n this.ownerDocument.removeEventListener('visibilitychange', this.handleDocumentVisibilityChange);\n\n this.uniformLocations = {};\n\n // Remove the shader from the div wrapper element\n this.canvasElement.remove();\n // Free up the reference to self to enable garbage collection\n delete this.parentElement.paperShaderMount;\n };\n}\n\nfunction createShader(gl: WebGL2RenderingContext, type: number, source: string): WebGLShader | null {\n const shader = gl.createShader(type);\n if (!shader) return null;\n\n gl.shaderSource(shader, source);\n gl.compileShader(shader);\n\n if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n console.error('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(shader));\n gl.deleteShader(shader);\n return null;\n }\n\n return shader;\n}\n\nfunction createProgram(\n gl: WebGL2RenderingContext,\n vertexShaderSource: string,\n fragmentShaderSource: string\n): WebGLProgram | null {\n const format = gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT);\n const precision = format ? format.precision : null;\n // MEDIUM_FLOAT precision can be 10, 16 or 23 bits depending on device;\n // Shaders fail on 10 bit (and 16 bit is hard to test) => we force 23-bit by switching to highp\n if (precision && precision < 23) {\n vertexShaderSource = vertexShaderSource.replace(/precision\\s+(lowp|mediump)\\s+float;/g, 'precision highp float;');\n fragmentShaderSource = fragmentShaderSource\n .replace(/precision\\s+(lowp|mediump)\\s+float/g, 'precision highp float')\n .replace(/\\b(uniform|varying|attribute)\\s+(lowp|mediump)\\s+(\\w+)/g, '$1 highp $3');\n }\n\n const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);\n const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);\n\n if (!vertexShader || !fragmentShader) return null;\n\n const program = gl.createProgram();\n if (!program) return null;\n\n gl.attachShader(program, vertexShader);\n gl.attachShader(program, fragmentShader);\n gl.linkProgram(program);\n\n if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n console.error('Unable to initialize the shader program: ' + gl.getProgramInfoLog(program));\n gl.deleteProgram(program);\n gl.deleteShader(vertexShader);\n gl.deleteShader(fragmentShader);\n return null;\n }\n\n // Clean up shaders after successful linking\n gl.detachShader(program, vertexShader);\n gl.detachShader(program, fragmentShader);\n gl.deleteShader(vertexShader);\n gl.deleteShader(fragmentShader);\n\n return program;\n}\n\nconst defaultStyle = `@layer paper-shaders {\n :where([data-paper-shader]) {\n isolation: isolate;\n position: relative;\n\n & canvas {\n contain: strict;\n display: block;\n position: absolute;\n inset: 0;\n z-index: -1;\n width: 100%;\n height: 100%;\n border-radius: inherit;\n corner-shape: inherit;\n }\n }\n}`;\n\n/** The parent `<div>` element that has a ShaderMount available on it */\nexport interface PaperShaderElement extends HTMLElement {\n paperShaderMount: ShaderMount | undefined;\n}\n\n/** Check if an element is a Paper shader element */\nexport function isPaperShaderElement(element: HTMLElement): element is PaperShaderElement {\n return 'paperShaderMount' in element;\n}\n\n/**\n * Uniform types that we support to be auto-mapped into the fragment shader\n *\n * We accept undefined as a convenience for server rendering, when some things may be undefined\n * We just skip setting the uniform if it's undefined. This allows the shader mount to still take up space during server rendering\n */\nexport interface ShaderMountUniforms {\n [key: string]: boolean | number | number[] | number[][] | HTMLImageElement | undefined;\n}\n\nexport interface ShaderMotionParams {\n speed?: number;\n frame?: number;\n}\n\nexport type ShaderPreset<T> = {\n name: string;\n params: Required<T>;\n};\n\nexport type ImageShaderPreset<T> = {\n name: string;\n /**\n * Params for the shader excluding the image.\n * Image is excluded as it isn't considered a preset,\n * e.g. when switching between presets it shouldn't switch the image.\n *\n * While we exclude images from presets they should still be set with a default prop value so the code-first usage of shaders remains great.\n */\n params: Required<Omit<T, 'image'>>;\n};\n\nfunction isSafari() {\n const ua = navigator.userAgent.toLowerCase();\n return ua.includes('safari') && !ua.includes('chrome') && !ua.includes('android');\n}\n\n// Zoom level can be estimated comparing the browser's outerWidth and the viewport width.\n// It's nowhere near perfect because it's affected by the presence of browser sidebars,\n// like a vertical web inspector or Arc's sidebar. Also, both outerWidth and innerWidth\n// are integers, which would almost never give us a perfect ratio at face values.\n//\n// Still, this is pretty accurate in the vast majority of cases.\n//\n// Note 1:\n// Avoid innerWidth, use visualViewport.width instead.\n// - innerWidth is affected by pinch zoom in Safari, but not other browsers.\n// visualViewport.width works consistently in all browsers.\n// - innerWidth is rounded to integer, but not visualViewport.width.\n// - visualViewport.width is affected by hard scrollbars, so they need to be added manually\n//\n// Note 2:\n// Opening a sidebar in Safari like web inspector or bookmarks will throw off the zoom\n// level detection and result in a larger target resolution. Not a concern in real-world usage\n// with Safari, but we'd rather not try to detect zoom levels with other browsers\n// (e.g. Arc always has a sidebar, which affects outerWidth vs visualViewport.width).\nfunction bestGuessBrowserZoom(doc: Document) {\n const viewportScale = visualViewport?.scale ?? 1;\n const viewportWidth = visualViewport?.width ?? window.innerWidth;\n const scrollbarWidth = window.innerWidth - doc.documentElement.clientWidth;\n const innerWidth = viewportScale * viewportWidth + scrollbarWidth;\n\n // outerWidth and innerWidth are always integers so we won't often get the original zoom ratio\n // E.g. given a 125% zoom, outerWidth = 1657, innerWidth = 1325, 1657 / 1325 = 1.2505660377\n // We check for common zoom levels and return the closest one if found.\n\n const ratio = outerWidth / innerWidth;\n const zoomPercentageRounded = Math.round(100 * ratio);\n\n // All zoom levels divisible by 5%\n if (zoomPercentageRounded % 5 === 0) {\n return zoomPercentageRounded / 100;\n }\n\n // 33% zoom\n if (zoomPercentageRounded === 33) {\n return 1 / 3;\n }\n\n // 67% zoom\n if (zoomPercentageRounded === 67) {\n return 2 / 3;\n }\n\n // 133% zoom\n if (zoomPercentageRounded === 133) {\n return 4 / 3;\n }\n\n return ratio;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["vertexShaderSource"]
|
|
7
7
|
}
|
|
@@ -132,15 +132,15 @@ vec2 gridToImageUV(vec2 cellCenter, float cosA, float sinA, float shift, vec2 pa
|
|
|
132
132
|
return uvGrid * pad + 0.5;
|
|
133
133
|
}
|
|
134
134
|
|
|
135
|
-
void colorMask(vec2 pos, vec2 cellCenter, float rad, float
|
|
135
|
+
void colorMask(vec2 pos, vec2 cellCenter, float rad, float transparency, float grain, float channelAddon, float channelgain, float generalComp, bool isJoined, inout float outMask) {
|
|
136
136
|
float dist = length(pos - cellCenter);
|
|
137
137
|
|
|
138
138
|
float radius = rad;
|
|
139
139
|
radius *= (1. + generalComp);
|
|
140
|
-
radius +=
|
|
141
|
-
radius += .15;
|
|
140
|
+
radius += (.15 + channelgain * radius);
|
|
142
141
|
radius = max(0., radius);
|
|
143
|
-
radius = mix(0., radius,
|
|
142
|
+
radius = mix(0., radius, transparency);
|
|
143
|
+
radius += channelAddon;
|
|
144
144
|
radius *= (1. - grain);
|
|
145
145
|
|
|
146
146
|
float mask = 1. - sst(0., radius, dist);
|
|
@@ -168,7 +168,7 @@ void main() {
|
|
|
168
168
|
float cellSizeY = 1.0 / cellsPerSide;
|
|
169
169
|
vec2 pad = cellSizeY * vec2(1.0 / u_imageAspectRatio, 1.0);
|
|
170
170
|
vec2 uvGrid = (uv - .5) / pad;
|
|
171
|
-
float
|
|
171
|
+
float insideImageBox = getUvFrame(uv, pad);
|
|
172
172
|
|
|
173
173
|
float generalComp = .1 * u_softness + .1 * u_gridNoise + .1 * (1. - step(0.5, u_type)) * (1.5 - u_softness);
|
|
174
174
|
|
|
@@ -194,34 +194,35 @@ void main() {
|
|
|
194
194
|
|
|
195
195
|
vec2 cellCenterC = cellCenterPos(uvC, cellOffset, 0.);
|
|
196
196
|
vec4 texC = texture(u_image, gridToImageUV(cellCenterC, cosC, sinC, shiftC, pad));
|
|
197
|
-
colorMask(uvC, cellCenterC, getCyan(texC),
|
|
197
|
+
colorMask(uvC, cellCenterC, getCyan(texC), insideImageBox * texC.a, grain, u_floodC, u_gainC, generalComp, isJoined, outMask[0]);
|
|
198
198
|
|
|
199
199
|
vec2 cellCenterM = cellCenterPos(uvM, cellOffset, 1.);
|
|
200
200
|
vec4 texM = texture(u_image, gridToImageUV(cellCenterM, cosM, sinM, shiftM, pad));
|
|
201
|
-
colorMask(uvM, cellCenterM, getMagenta(texM),
|
|
201
|
+
colorMask(uvM, cellCenterM, getMagenta(texM), insideImageBox * texM.a, grain, u_floodM, u_gainM, generalComp, isJoined, outMask[1]);
|
|
202
202
|
|
|
203
203
|
vec2 cellCenterY = cellCenterPos(uvY, cellOffset, 2.);
|
|
204
204
|
vec4 texY = texture(u_image, gridToImageUV(cellCenterY, cosY, sinY, shiftY, pad));
|
|
205
|
-
colorMask(uvY, cellCenterY, getYellow(texY),
|
|
205
|
+
colorMask(uvY, cellCenterY, getYellow(texY), insideImageBox * texY.a, grain, u_floodY, u_gainY, generalComp, isJoined, outMask[2]);
|
|
206
206
|
|
|
207
207
|
vec2 cellCenterK = cellCenterPos(uvK, cellOffset, 3.);
|
|
208
208
|
vec4 texK = texture(u_image, gridToImageUV(cellCenterK, cosK, sinK, shiftK, pad));
|
|
209
|
-
colorMask(uvK, cellCenterK, getBlack(texK),
|
|
209
|
+
colorMask(uvK, cellCenterK, getBlack(texK), insideImageBox * texK.a, grain, u_floodK, u_gainK, generalComp, isJoined, outMask[3]);
|
|
210
210
|
}
|
|
211
211
|
}
|
|
212
212
|
} else {
|
|
213
213
|
// sharp: direct px color sampling
|
|
214
214
|
vec4 tex = texture(u_image, uv);
|
|
215
215
|
tex.rgb = applyContrast(tex.rgb);
|
|
216
|
+
insideImageBox *= tex.a;
|
|
216
217
|
vec4 cmykOriginal = RGBAtoCMYK(tex);
|
|
217
218
|
for (int dy = -1; dy <= 1; dy++) {
|
|
218
219
|
for (int dx = -1; dx <= 1; dx++) {
|
|
219
220
|
vec2 cellOffset = vec2(float(dx), float(dy));
|
|
220
221
|
|
|
221
|
-
colorMask(uvC, cellCenterPos(uvC, cellOffset, 0.), cmykOriginal.x,
|
|
222
|
-
colorMask(uvM, cellCenterPos(uvM, cellOffset, 1.), cmykOriginal.y,
|
|
223
|
-
colorMask(uvY, cellCenterPos(uvY, cellOffset, 2.), cmykOriginal.z,
|
|
224
|
-
colorMask(uvK, cellCenterPos(uvK, cellOffset, 3.), cmykOriginal.w,
|
|
222
|
+
colorMask(uvC, cellCenterPos(uvC, cellOffset, 0.), cmykOriginal.x, insideImageBox, grain, u_floodC, u_gainC, generalComp, isJoined, outMask[0]);
|
|
223
|
+
colorMask(uvM, cellCenterPos(uvM, cellOffset, 1.), cmykOriginal.y, insideImageBox, grain, u_floodM, u_gainM, generalComp, isJoined, outMask[1]);
|
|
224
|
+
colorMask(uvY, cellCenterPos(uvY, cellOffset, 2.), cmykOriginal.z, insideImageBox, grain, u_floodY, u_gainY, generalComp, isJoined, outMask[2]);
|
|
225
|
+
colorMask(uvK, cellCenterPos(uvK, cellOffset, 3.), cmykOriginal.w, insideImageBox, grain, u_floodK, u_gainK, generalComp, isJoined, outMask[3]);
|
|
225
226
|
}
|
|
226
227
|
}
|
|
227
228
|
}
|
|
@@ -258,6 +259,7 @@ void main() {
|
|
|
258
259
|
shape = clamp(max(max(C, M), max(Y, K)), 0., 1.);
|
|
259
260
|
|
|
260
261
|
vec3 color = u_colorBack.rgb * u_colorBack.a;
|
|
262
|
+
|
|
261
263
|
float opacity = u_colorBack.a;
|
|
262
264
|
color = mix(color, ink, shape);
|
|
263
265
|
opacity += shape;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/shaders/halftone-cmyk.ts"],
|
|
4
|
-
"sourcesContent": ["import type { ShaderMotionParams } from '../shader-mount.js';\nimport { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { declarePI } from '../shader-utils.js';\n\n/**\n * CMYK halftone printing effect applied to images with customizable dot patterns\n * and ink colors for each channel (Cyan, Magenta, Yellow, Black).\n *\n * Fragment shader uniforms:\n * - u_image (sampler2D): Source image texture\n * - u_imageAspectRatio (float): Aspect ratio of the source image\n * - u_colorBack (vec4): Background (paper) color in RGBA\n * - u_colorC (vec4): Cyan ink color in RGBA\n * - u_colorM (vec4): Magenta ink color in RGBA\n * - u_colorY (vec4): Yellow ink color in RGBA\n * - u_colorK (vec4): Black ink color in RGBA\n * - u_size (float): Halftone cell size (0 to 1)\n * - u_minDot (float): Minimum dot thickness (0 to 1)\n * - u_contrast (float): Image contrast adjustment (0 to 2)\n * - u_softness (float): Edge softness of dots (0 to 1)\n * - u_grainSize (float): Size of grain overlay texture (0 to 1)\n * - u_grainMixer (float): Strength of grain affecting dot size (0 to 1)\n * - u_grainOverlay (float): Strength of grain overlay on final output (0 to 1)\n * - u_gridNoise (float): Strength of smooth noise applied to both dot positions and color sampling (0 to 1)\n * - u_floodC (float): Flat cyan dot size adjustment applied uniformly (-1 to 1)\n * - u_floodM (float): Flat magenta dot size adjustment applied uniformly (-1 to 1)\n * - u_floodY (float): Flat yellow dot size adjustment applied uniformly (-1 to 1)\n * - u_floodK (float): Flat black dot size adjustment applied uniformly (-1 to 1)\n * - u_gainC (float): Proportional cyan dot size gain (enhances existing dots, -1 to 1)\n * - u_gainM (float): Proportional magenta dot size gain (enhances existing dots, -1 to 1)\n * - u_gainY (float): Proportional yellow dot size gain (enhances existing dots, -1 to 1)\n * - u_gainK (float): Proportional black dot size gain (enhances existing dots, -1 to 1)\n * - u_type (float): Dot shape style (0 = dots, 1 = ink, 2 = sharp)\n * - u_noiseTexture (sampler2D): Pre-computed randomizer source texture\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_imageUV (vec2): UV coordinates for sampling the source image, with fit, scale, rotation, and offset applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n * - u_imageAspectRatio (float): Aspect ratio of the source image\n *\n */\n\n// language=GLSL\nexport const halftoneCmykFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform sampler2D u_image;\nuniform float u_imageAspectRatio;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colorC;\nuniform vec4 u_colorM;\nuniform vec4 u_colorY;\nuniform vec4 u_colorK;\nuniform float u_size;\nuniform float u_minDot;\nuniform float u_contrast;\nuniform float u_grainSize;\nuniform float u_grainMixer;\nuniform float u_grainOverlay;\nuniform float u_gridNoise;\nuniform float u_softness;\nuniform float u_floodC;\nuniform float u_floodM;\nuniform float u_floodY;\nuniform float u_floodK;\nuniform float u_gainC;\nuniform float u_gainM;\nuniform float u_gainY;\nuniform float u_gainK;\nuniform float u_type;\nuniform sampler2D u_noiseTexture;\n\nin vec2 v_imageUV;\nout vec4 fragColor;\n\nconst float shiftC = -.5;\nconst float shiftM = -.25;\nconst float shiftY = .2;\nconst float shiftK = 0.;\n\n// Precomputed sin/cos for rotation angles (15\u00B0, 75\u00B0, 0\u00B0, 45\u00B0)\nconst float cosC = 0.9659258; const float sinC = 0.2588190; // 15\u00B0\nconst float cosM = 0.2588190; const float sinM = 0.9659258; // 75\u00B0\nconst float cosY = 1.0; const float sinY = 0.0; // 0\u00B0\nconst float cosK = 0.7071068; const float sinK = 0.7071068; // 45\u00B0\n\n${ declarePI }\n\nvec2 randomRG(vec2 p) {\n vec2 uv = floor(p) / 100. + .5;\n return texture(u_noiseTexture, fract(uv)).rg;\n}\nvec3 hash23(vec2 p) {\n vec3 p3 = fract(vec3(p.xyx) * vec3(0.3183099, 0.3678794, 0.3141592)) + 0.1;\n p3 += dot(p3, p3.yzx + 19.19);\n return fract(vec3(p3.x * p3.y, p3.y * p3.z, p3.z * p3.x));\n}\n\nfloat sst(float edge0, float edge1, float x) {\n return smoothstep(edge0, edge1, x);\n}\n\nvec3 valueNoise3(vec2 st) {\n vec2 i = floor(st);\n vec2 f = fract(st);\n vec3 a = hash23(i);\n vec3 b = hash23(i + vec2(1.0, 0.0));\n vec3 c = hash23(i + vec2(0.0, 1.0));\n vec3 d = hash23(i + vec2(1.0, 1.0));\n vec2 u = f * f * (3.0 - 2.0 * f);\n vec3 x1 = mix(a, b, u.x);\n vec3 x2 = mix(c, d, u.x);\n return mix(x1, x2, u.y);\n}\n\nfloat getUvFrame(vec2 uv, vec2 pad) {\n float left = smoothstep(-pad.x, 0., uv.x);\n float right = smoothstep(1. + pad.x, 1., uv.x);\n float bottom = smoothstep(-pad.y, 0., uv.y);\n float top = smoothstep(1. + pad.y, 1., uv.y);\n\n return left * right * bottom * top;\n}\n\nvec4 RGBAtoCMYK(vec4 rgba) {\n float k = 1. - max(max(rgba.r, rgba.g), rgba.b);\n float denom = 1. - k;\n vec3 cmy = vec3(0.);\n if (denom > 1e-5) {\n cmy = (1. - rgba.rgb - vec3(k)) / denom;\n }\n return vec4(cmy, k) * rgba.a;\n}\n\nvec3 applyContrast(vec3 rgb) {\n return clamp((rgb - 0.5) * u_contrast + 0.5, 0.0, 1.0);\n}\n\n// Single-component CMYK extractors with contrast built-in, alpha-aware\nfloat getCyan(vec4 rgba) {\n vec3 c = clamp((rgba.rgb - 0.5) * u_contrast + 0.5, 0.0, 1.0);\n float maxRGB = max(max(c.r, c.g), c.b);\n return (maxRGB > 1e-5 ? (maxRGB - c.r) / maxRGB : 0.) * rgba.a;\n}\nfloat getMagenta(vec4 rgba) {\n vec3 c = clamp((rgba.rgb - 0.5) * u_contrast + 0.5, 0.0, 1.0);\n float maxRGB = max(max(c.r, c.g), c.b);\n return (maxRGB > 1e-5 ? (maxRGB - c.g) / maxRGB : 0.) * rgba.a;\n}\nfloat getYellow(vec4 rgba) {\n vec3 c = clamp((rgba.rgb - 0.5) * u_contrast + 0.5, 0.0, 1.0);\n float maxRGB = max(max(c.r, c.g), c.b);\n return (maxRGB > 1e-5 ? (maxRGB - c.b) / maxRGB : 0.) * rgba.a;\n}\nfloat getBlack(vec4 rgba) {\n vec3 c = clamp((rgba.rgb - 0.5) * u_contrast + 0.5, 0.0, 1.0);\n return (1. - max(max(c.r, c.g), c.b)) * rgba.a;\n}\n\nvec2 cellCenterPos(vec2 uv, vec2 cellOffset, float channelIdx) {\n vec2 cellCenter = floor(uv) + .5 + cellOffset;\n return cellCenter + (randomRG(cellCenter + channelIdx * 50.) - .5) * u_gridNoise;\n}\n\nvec2 gridToImageUV(vec2 cellCenter, float cosA, float sinA, float shift, vec2 pad) {\n vec2 uvGrid = mat2(cosA, -sinA, sinA, cosA) * (cellCenter - shift);\n return uvGrid * pad + 0.5;\n}\n\nvoid colorMask(vec2 pos, vec2 cellCenter, float rad, float outOfFrame, float grain, float channelAddon, float channelgain, float generalComp, bool isJoined, inout float outMask) {\n float dist = length(pos - cellCenter);\n\n float radius = rad;\n radius *= (1. + generalComp);\n radius += channelAddon + channelgain * radius;\n radius += .15;\n radius = max(0., radius);\n radius = mix(0., radius, outOfFrame);\n radius *= (1. - grain);\n\n float mask = 1. - sst(0., radius, dist);\n if (isJoined) {\n // ink or sharp (joined)\n mask = pow(mask, 1.2);\n } else {\n // dots (separate)\n mask = sst(.5 - .5 * u_softness, .51 + .49 * u_softness, mask);\n }\n\n mask *= mix(1., mix(.5, 1., 1.5 * radius), u_softness);\n outMask += mask;\n}\n\nvec3 applyInk(vec3 paper, vec3 inkColor, float cov) {\n vec3 inkEffect = mix(vec3(1.0), inkColor, clamp(cov, 0.0, 1.0));\n return paper * inkEffect;\n}\n\nvoid main() {\n vec2 uv = v_imageUV;\n\n float cellsPerSide = mix(400.0, 7.0, pow(u_size, 0.7));\n float cellSizeY = 1.0 / cellsPerSide;\n vec2 pad = cellSizeY * vec2(1.0 / u_imageAspectRatio, 1.0);\n vec2 uvGrid = (uv - .5) / pad;\n float outOfFrame = getUvFrame(uv, pad);\n\n float generalComp = .1 * u_softness + .1 * u_gridNoise + .1 * (1. - step(0.5, u_type)) * (1.5 - u_softness);\n\n vec2 uvC = mat2(cosC, sinC, -sinC, cosC) * uvGrid + shiftC;\n vec2 uvM = mat2(cosM, sinM, -sinM, cosM) * uvGrid + shiftM;\n vec2 uvY = mat2(cosY, sinY, -sinY, cosY) * uvGrid + shiftY;\n vec2 uvK = mat2(cosK, sinK, -sinK, cosK) * uvGrid + shiftK;\n\n vec2 grainSize = mix(2000., 200., u_grainSize) * vec2(1., 1. / u_imageAspectRatio);\n vec2 grainUV = (v_imageUV - .5) * grainSize + .5;\n vec3 noiseValues = valueNoise3(grainUV);\n float grain = sst(.55, 1., noiseValues.r);\n grain *= u_grainMixer;\n\n vec4 outMask = vec4(0.);\n bool isJoined = u_type > 0.5;\n\n if (u_type < 1.5) {\n // dots or ink: per-cell color sampling\n for (int dy = -1; dy <= 1; dy++) {\n for (int dx = -1; dx <= 1; dx++) {\n vec2 cellOffset = vec2(float(dx), float(dy));\n\n vec2 cellCenterC = cellCenterPos(uvC, cellOffset, 0.);\n vec4 texC = texture(u_image, gridToImageUV(cellCenterC, cosC, sinC, shiftC, pad));\n colorMask(uvC, cellCenterC, getCyan(texC), outOfFrame, grain, u_floodC, u_gainC, generalComp, isJoined, outMask[0]);\n\n vec2 cellCenterM = cellCenterPos(uvM, cellOffset, 1.);\n vec4 texM = texture(u_image, gridToImageUV(cellCenterM, cosM, sinM, shiftM, pad));\n colorMask(uvM, cellCenterM, getMagenta(texM), outOfFrame, grain, u_floodM, u_gainM, generalComp, isJoined, outMask[1]);\n\n vec2 cellCenterY = cellCenterPos(uvY, cellOffset, 2.);\n vec4 texY = texture(u_image, gridToImageUV(cellCenterY, cosY, sinY, shiftY, pad));\n colorMask(uvY, cellCenterY, getYellow(texY), outOfFrame, grain, u_floodY, u_gainY, generalComp, isJoined, outMask[2]);\n\n vec2 cellCenterK = cellCenterPos(uvK, cellOffset, 3.);\n vec4 texK = texture(u_image, gridToImageUV(cellCenterK, cosK, sinK, shiftK, pad));\n colorMask(uvK, cellCenterK, getBlack(texK), outOfFrame, grain, u_floodK, u_gainK, generalComp, isJoined, outMask[3]);\n }\n }\n } else {\n // sharp: direct px color sampling\n vec4 tex = texture(u_image, uv);\n tex.rgb = applyContrast(tex.rgb);\n vec4 cmykOriginal = RGBAtoCMYK(tex);\n for (int dy = -1; dy <= 1; dy++) {\n for (int dx = -1; dx <= 1; dx++) {\n vec2 cellOffset = vec2(float(dx), float(dy));\n\n colorMask(uvC, cellCenterPos(uvC, cellOffset, 0.), cmykOriginal.x, outOfFrame, grain, u_floodC, u_gainC, generalComp, isJoined, outMask[0]);\n colorMask(uvM, cellCenterPos(uvM, cellOffset, 1.), cmykOriginal.y, outOfFrame, grain, u_floodM, u_gainM, generalComp, isJoined, outMask[1]);\n colorMask(uvY, cellCenterPos(uvY, cellOffset, 2.), cmykOriginal.z, outOfFrame, grain, u_floodY, u_gainY, generalComp, isJoined, outMask[2]);\n colorMask(uvK, cellCenterPos(uvK, cellOffset, 3.), cmykOriginal.w, outOfFrame, grain, u_floodK, u_gainK, generalComp, isJoined, outMask[3]);\n }\n }\n }\n\n float shape;\n\n float C = outMask[0];\n float M = outMask[1];\n float Y = outMask[2];\n float K = outMask[3];\n\n if (isJoined) {\n // ink or sharp: apply threshold for joined dots\n float th = .5;\n float sLeft = th * u_softness;\n float sRight = (1. - th) * u_softness + .01;\n C = smoothstep(th - sLeft - fwidth(C), th + sRight, C);\n M = smoothstep(th - sLeft - fwidth(M), th + sRight, M);\n Y = smoothstep(th - sLeft - fwidth(Y), th + sRight, Y);\n K = smoothstep(th - sLeft - fwidth(K), th + sRight, K);\n }\n\n C *= u_colorC.a;\n M *= u_colorM.a;\n Y *= u_colorY.a;\n K *= u_colorK.a;\n\n vec3 ink = vec3(1.);\n ink = applyInk(ink, u_colorK.rgb, K);\n ink = applyInk(ink, u_colorC.rgb, C);\n ink = applyInk(ink, u_colorM.rgb, M);\n ink = applyInk(ink, u_colorY.rgb, Y);\n\n shape = clamp(max(max(C, M), max(Y, K)), 0., 1.);\n\n vec3 color = u_colorBack.rgb * u_colorBack.a;\n float opacity = u_colorBack.a;\n color = mix(color, ink, shape);\n opacity += shape;\n opacity = clamp(opacity, 0., 1.);\n\n float grainOverlay = mix(noiseValues.g, noiseValues.b, .5);\n grainOverlay = pow(grainOverlay, 1.3);\n\n float grainOverlayV = grainOverlay * 2. - 1.;\n vec3 grainOverlayColor = vec3(step(0., grainOverlayV));\n float grainOverlayStrength = u_grainOverlay * abs(grainOverlayV);\n grainOverlayStrength = pow(grainOverlayStrength, .8);\n color = mix(color, grainOverlayColor, .5 * grainOverlayStrength);\n\n opacity += .5 * grainOverlayStrength;\n opacity = clamp(opacity, 0., 1.);\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface HalftoneCmykUniforms extends ShaderSizingUniforms {\n u_image: HTMLImageElement | string | undefined;\n u_noiseTexture?: HTMLImageElement;\n u_colorBack: [number, number, number, number];\n u_colorC: [number, number, number, number];\n u_colorM: [number, number, number, number];\n u_colorY: [number, number, number, number];\n u_colorK: [number, number, number, number];\n u_size: number;\n u_contrast: number;\n u_softness: number;\n u_grainSize: number;\n u_grainMixer: number;\n u_grainOverlay: number;\n u_gridNoise: number;\n u_floodC: number;\n u_floodM: number;\n u_floodY: number;\n u_floodK: number;\n u_gainC: number;\n u_gainM: number;\n u_gainY: number;\n u_gainK: number;\n u_type: (typeof HalftoneCmykTypes)[HalftoneCmykType];\n}\n\nexport interface HalftoneCmykParams extends ShaderSizingParams, ShaderMotionParams {\n image?: HTMLImageElement | string;\n colorBack?: string;\n colorC?: string;\n colorM?: string;\n colorY?: string;\n colorK?: string;\n size?: number;\n contrast?: number;\n softness?: number;\n grainSize?: number;\n grainMixer?: number;\n grainOverlay?: number;\n gridNoise?: number;\n floodC?: number;\n floodM?: number;\n floodY?: number;\n floodK?: number;\n gainC?: number;\n gainM?: number;\n gainY?: number;\n gainK?: number;\n type?: HalftoneCmykType;\n}\n\nexport const HalftoneCmykTypes = {\n dots: 0,\n ink: 1,\n sharp: 2,\n} as const;\n\nexport type HalftoneCmykType = keyof typeof HalftoneCmykTypes;\n\n"],
|
|
5
|
-
"mappings": ";;;;;AACA,eAAmE;AACnE,SAAS,iBAAiB;AAmDnB,MAAM,6BAAqC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA4C/C,SAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;
|
|
4
|
+
"sourcesContent": ["import type { ShaderMotionParams } from '../shader-mount.js';\nimport { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { declarePI } from '../shader-utils.js';\n\n/**\n * CMYK halftone printing effect applied to images with customizable dot patterns\n * and ink colors for each channel (Cyan, Magenta, Yellow, Black).\n *\n * Fragment shader uniforms:\n * - u_image (sampler2D): Source image texture\n * - u_imageAspectRatio (float): Aspect ratio of the source image\n * - u_colorBack (vec4): Background (paper) color in RGBA\n * - u_colorC (vec4): Cyan ink color in RGBA\n * - u_colorM (vec4): Magenta ink color in RGBA\n * - u_colorY (vec4): Yellow ink color in RGBA\n * - u_colorK (vec4): Black ink color in RGBA\n * - u_size (float): Halftone cell size (0 to 1)\n * - u_minDot (float): Minimum dot thickness (0 to 1)\n * - u_contrast (float): Image contrast adjustment (0 to 2)\n * - u_softness (float): Edge softness of dots (0 to 1)\n * - u_grainSize (float): Size of grain overlay texture (0 to 1)\n * - u_grainMixer (float): Strength of grain affecting dot size (0 to 1)\n * - u_grainOverlay (float): Strength of grain overlay on final output (0 to 1)\n * - u_gridNoise (float): Strength of smooth noise applied to both dot positions and color sampling (0 to 1)\n * - u_floodC (float): Flat cyan dot size adjustment applied uniformly (-1 to 1)\n * - u_floodM (float): Flat magenta dot size adjustment applied uniformly (-1 to 1)\n * - u_floodY (float): Flat yellow dot size adjustment applied uniformly (-1 to 1)\n * - u_floodK (float): Flat black dot size adjustment applied uniformly (-1 to 1)\n * - u_gainC (float): Proportional cyan dot size gain (enhances existing dots, -1 to 1)\n * - u_gainM (float): Proportional magenta dot size gain (enhances existing dots, -1 to 1)\n * - u_gainY (float): Proportional yellow dot size gain (enhances existing dots, -1 to 1)\n * - u_gainK (float): Proportional black dot size gain (enhances existing dots, -1 to 1)\n * - u_type (float): Dot shape style (0 = dots, 1 = ink, 2 = sharp)\n * - u_noiseTexture (sampler2D): Pre-computed randomizer source texture\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_imageUV (vec2): UV coordinates for sampling the source image, with fit, scale, rotation, and offset applied\n *\n * Vertex shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n * - u_imageAspectRatio (float): Aspect ratio of the source image\n *\n */\n\n// language=GLSL\nexport const halftoneCmykFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform sampler2D u_image;\nuniform float u_imageAspectRatio;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colorC;\nuniform vec4 u_colorM;\nuniform vec4 u_colorY;\nuniform vec4 u_colorK;\nuniform float u_size;\nuniform float u_minDot;\nuniform float u_contrast;\nuniform float u_grainSize;\nuniform float u_grainMixer;\nuniform float u_grainOverlay;\nuniform float u_gridNoise;\nuniform float u_softness;\nuniform float u_floodC;\nuniform float u_floodM;\nuniform float u_floodY;\nuniform float u_floodK;\nuniform float u_gainC;\nuniform float u_gainM;\nuniform float u_gainY;\nuniform float u_gainK;\nuniform float u_type;\nuniform sampler2D u_noiseTexture;\n\nin vec2 v_imageUV;\nout vec4 fragColor;\n\nconst float shiftC = -.5;\nconst float shiftM = -.25;\nconst float shiftY = .2;\nconst float shiftK = 0.;\n\n// Precomputed sin/cos for rotation angles (15\u00B0, 75\u00B0, 0\u00B0, 45\u00B0)\nconst float cosC = 0.9659258; const float sinC = 0.2588190; // 15\u00B0\nconst float cosM = 0.2588190; const float sinM = 0.9659258; // 75\u00B0\nconst float cosY = 1.0; const float sinY = 0.0; // 0\u00B0\nconst float cosK = 0.7071068; const float sinK = 0.7071068; // 45\u00B0\n\n${ declarePI }\n\nvec2 randomRG(vec2 p) {\n vec2 uv = floor(p) / 100. + .5;\n return texture(u_noiseTexture, fract(uv)).rg;\n}\nvec3 hash23(vec2 p) {\n vec3 p3 = fract(vec3(p.xyx) * vec3(0.3183099, 0.3678794, 0.3141592)) + 0.1;\n p3 += dot(p3, p3.yzx + 19.19);\n return fract(vec3(p3.x * p3.y, p3.y * p3.z, p3.z * p3.x));\n}\n\nfloat sst(float edge0, float edge1, float x) {\n return smoothstep(edge0, edge1, x);\n}\n\nvec3 valueNoise3(vec2 st) {\n vec2 i = floor(st);\n vec2 f = fract(st);\n vec3 a = hash23(i);\n vec3 b = hash23(i + vec2(1.0, 0.0));\n vec3 c = hash23(i + vec2(0.0, 1.0));\n vec3 d = hash23(i + vec2(1.0, 1.0));\n vec2 u = f * f * (3.0 - 2.0 * f);\n vec3 x1 = mix(a, b, u.x);\n vec3 x2 = mix(c, d, u.x);\n return mix(x1, x2, u.y);\n}\n\nfloat getUvFrame(vec2 uv, vec2 pad) {\n float left = smoothstep(-pad.x, 0., uv.x);\n float right = smoothstep(1. + pad.x, 1., uv.x);\n float bottom = smoothstep(-pad.y, 0., uv.y);\n float top = smoothstep(1. + pad.y, 1., uv.y);\n\n return left * right * bottom * top;\n}\n\nvec4 RGBAtoCMYK(vec4 rgba) {\n float k = 1. - max(max(rgba.r, rgba.g), rgba.b);\n float denom = 1. - k;\n vec3 cmy = vec3(0.);\n if (denom > 1e-5) {\n cmy = (1. - rgba.rgb - vec3(k)) / denom;\n }\n return vec4(cmy, k) * rgba.a;\n}\n\nvec3 applyContrast(vec3 rgb) {\n return clamp((rgb - 0.5) * u_contrast + 0.5, 0.0, 1.0);\n}\n\n// Single-component CMYK extractors with contrast built-in, alpha-aware\nfloat getCyan(vec4 rgba) {\n vec3 c = clamp((rgba.rgb - 0.5) * u_contrast + 0.5, 0.0, 1.0);\n float maxRGB = max(max(c.r, c.g), c.b);\n return (maxRGB > 1e-5 ? (maxRGB - c.r) / maxRGB : 0.) * rgba.a;\n}\nfloat getMagenta(vec4 rgba) {\n vec3 c = clamp((rgba.rgb - 0.5) * u_contrast + 0.5, 0.0, 1.0);\n float maxRGB = max(max(c.r, c.g), c.b);\n return (maxRGB > 1e-5 ? (maxRGB - c.g) / maxRGB : 0.) * rgba.a;\n}\nfloat getYellow(vec4 rgba) {\n vec3 c = clamp((rgba.rgb - 0.5) * u_contrast + 0.5, 0.0, 1.0);\n float maxRGB = max(max(c.r, c.g), c.b);\n return (maxRGB > 1e-5 ? (maxRGB - c.b) / maxRGB : 0.) * rgba.a;\n}\nfloat getBlack(vec4 rgba) {\n vec3 c = clamp((rgba.rgb - 0.5) * u_contrast + 0.5, 0.0, 1.0);\n return (1. - max(max(c.r, c.g), c.b)) * rgba.a;\n}\n\nvec2 cellCenterPos(vec2 uv, vec2 cellOffset, float channelIdx) {\n vec2 cellCenter = floor(uv) + .5 + cellOffset;\n return cellCenter + (randomRG(cellCenter + channelIdx * 50.) - .5) * u_gridNoise;\n}\n\nvec2 gridToImageUV(vec2 cellCenter, float cosA, float sinA, float shift, vec2 pad) {\n vec2 uvGrid = mat2(cosA, -sinA, sinA, cosA) * (cellCenter - shift);\n return uvGrid * pad + 0.5;\n}\n\nvoid colorMask(vec2 pos, vec2 cellCenter, float rad, float transparency, float grain, float channelAddon, float channelgain, float generalComp, bool isJoined, inout float outMask) {\n float dist = length(pos - cellCenter);\n\n float radius = rad;\n radius *= (1. + generalComp);\n radius += (.15 + channelgain * radius);\n radius = max(0., radius);\n radius = mix(0., radius, transparency);\n radius += channelAddon;\n radius *= (1. - grain);\n\n float mask = 1. - sst(0., radius, dist);\n if (isJoined) {\n // ink or sharp (joined)\n mask = pow(mask, 1.2);\n } else {\n // dots (separate)\n mask = sst(.5 - .5 * u_softness, .51 + .49 * u_softness, mask);\n }\n\n mask *= mix(1., mix(.5, 1., 1.5 * radius), u_softness);\n outMask += mask;\n}\n\nvec3 applyInk(vec3 paper, vec3 inkColor, float cov) {\n vec3 inkEffect = mix(vec3(1.0), inkColor, clamp(cov, 0.0, 1.0));\n return paper * inkEffect;\n}\n\nvoid main() {\n vec2 uv = v_imageUV;\n\n float cellsPerSide = mix(400.0, 7.0, pow(u_size, 0.7));\n float cellSizeY = 1.0 / cellsPerSide;\n vec2 pad = cellSizeY * vec2(1.0 / u_imageAspectRatio, 1.0);\n vec2 uvGrid = (uv - .5) / pad;\n float insideImageBox = getUvFrame(uv, pad);\n\n float generalComp = .1 * u_softness + .1 * u_gridNoise + .1 * (1. - step(0.5, u_type)) * (1.5 - u_softness);\n\n vec2 uvC = mat2(cosC, sinC, -sinC, cosC) * uvGrid + shiftC;\n vec2 uvM = mat2(cosM, sinM, -sinM, cosM) * uvGrid + shiftM;\n vec2 uvY = mat2(cosY, sinY, -sinY, cosY) * uvGrid + shiftY;\n vec2 uvK = mat2(cosK, sinK, -sinK, cosK) * uvGrid + shiftK;\n\n vec2 grainSize = mix(2000., 200., u_grainSize) * vec2(1., 1. / u_imageAspectRatio);\n vec2 grainUV = (v_imageUV - .5) * grainSize + .5;\n vec3 noiseValues = valueNoise3(grainUV);\n float grain = sst(.55, 1., noiseValues.r);\n grain *= u_grainMixer;\n\n vec4 outMask = vec4(0.);\n bool isJoined = u_type > 0.5;\n\n if (u_type < 1.5) {\n // dots or ink: per-cell color sampling\n for (int dy = -1; dy <= 1; dy++) {\n for (int dx = -1; dx <= 1; dx++) {\n vec2 cellOffset = vec2(float(dx), float(dy));\n\n vec2 cellCenterC = cellCenterPos(uvC, cellOffset, 0.);\n vec4 texC = texture(u_image, gridToImageUV(cellCenterC, cosC, sinC, shiftC, pad));\n colorMask(uvC, cellCenterC, getCyan(texC), insideImageBox * texC.a, grain, u_floodC, u_gainC, generalComp, isJoined, outMask[0]);\n\n vec2 cellCenterM = cellCenterPos(uvM, cellOffset, 1.);\n vec4 texM = texture(u_image, gridToImageUV(cellCenterM, cosM, sinM, shiftM, pad));\n colorMask(uvM, cellCenterM, getMagenta(texM), insideImageBox * texM.a, grain, u_floodM, u_gainM, generalComp, isJoined, outMask[1]);\n\n vec2 cellCenterY = cellCenterPos(uvY, cellOffset, 2.);\n vec4 texY = texture(u_image, gridToImageUV(cellCenterY, cosY, sinY, shiftY, pad));\n colorMask(uvY, cellCenterY, getYellow(texY), insideImageBox * texY.a, grain, u_floodY, u_gainY, generalComp, isJoined, outMask[2]);\n\n vec2 cellCenterK = cellCenterPos(uvK, cellOffset, 3.);\n vec4 texK = texture(u_image, gridToImageUV(cellCenterK, cosK, sinK, shiftK, pad));\n colorMask(uvK, cellCenterK, getBlack(texK), insideImageBox * texK.a, grain, u_floodK, u_gainK, generalComp, isJoined, outMask[3]);\n }\n }\n } else {\n // sharp: direct px color sampling\n vec4 tex = texture(u_image, uv);\n tex.rgb = applyContrast(tex.rgb);\n insideImageBox *= tex.a;\n vec4 cmykOriginal = RGBAtoCMYK(tex);\n for (int dy = -1; dy <= 1; dy++) {\n for (int dx = -1; dx <= 1; dx++) {\n vec2 cellOffset = vec2(float(dx), float(dy));\n\n colorMask(uvC, cellCenterPos(uvC, cellOffset, 0.), cmykOriginal.x, insideImageBox, grain, u_floodC, u_gainC, generalComp, isJoined, outMask[0]);\n colorMask(uvM, cellCenterPos(uvM, cellOffset, 1.), cmykOriginal.y, insideImageBox, grain, u_floodM, u_gainM, generalComp, isJoined, outMask[1]);\n colorMask(uvY, cellCenterPos(uvY, cellOffset, 2.), cmykOriginal.z, insideImageBox, grain, u_floodY, u_gainY, generalComp, isJoined, outMask[2]);\n colorMask(uvK, cellCenterPos(uvK, cellOffset, 3.), cmykOriginal.w, insideImageBox, grain, u_floodK, u_gainK, generalComp, isJoined, outMask[3]);\n }\n }\n }\n\n float shape;\n\n float C = outMask[0];\n float M = outMask[1];\n float Y = outMask[2];\n float K = outMask[3];\n\n if (isJoined) {\n // ink or sharp: apply threshold for joined dots\n float th = .5;\n float sLeft = th * u_softness;\n float sRight = (1. - th) * u_softness + .01;\n C = smoothstep(th - sLeft - fwidth(C), th + sRight, C);\n M = smoothstep(th - sLeft - fwidth(M), th + sRight, M);\n Y = smoothstep(th - sLeft - fwidth(Y), th + sRight, Y);\n K = smoothstep(th - sLeft - fwidth(K), th + sRight, K);\n }\n\n C *= u_colorC.a;\n M *= u_colorM.a;\n Y *= u_colorY.a;\n K *= u_colorK.a;\n\n vec3 ink = vec3(1.);\n ink = applyInk(ink, u_colorK.rgb, K);\n ink = applyInk(ink, u_colorC.rgb, C);\n ink = applyInk(ink, u_colorM.rgb, M);\n ink = applyInk(ink, u_colorY.rgb, Y);\n\n shape = clamp(max(max(C, M), max(Y, K)), 0., 1.);\n\n vec3 color = u_colorBack.rgb * u_colorBack.a;\n\n float opacity = u_colorBack.a;\n color = mix(color, ink, shape);\n opacity += shape;\n opacity = clamp(opacity, 0., 1.);\n\n float grainOverlay = mix(noiseValues.g, noiseValues.b, .5);\n grainOverlay = pow(grainOverlay, 1.3);\n\n float grainOverlayV = grainOverlay * 2. - 1.;\n vec3 grainOverlayColor = vec3(step(0., grainOverlayV));\n float grainOverlayStrength = u_grainOverlay * abs(grainOverlayV);\n grainOverlayStrength = pow(grainOverlayStrength, .8);\n color = mix(color, grainOverlayColor, .5 * grainOverlayStrength);\n\n opacity += .5 * grainOverlayStrength;\n opacity = clamp(opacity, 0., 1.);\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface HalftoneCmykUniforms extends ShaderSizingUniforms {\n u_image: HTMLImageElement | string | undefined;\n u_noiseTexture?: HTMLImageElement;\n u_colorBack: [number, number, number, number];\n u_colorC: [number, number, number, number];\n u_colorM: [number, number, number, number];\n u_colorY: [number, number, number, number];\n u_colorK: [number, number, number, number];\n u_size: number;\n u_contrast: number;\n u_softness: number;\n u_grainSize: number;\n u_grainMixer: number;\n u_grainOverlay: number;\n u_gridNoise: number;\n u_floodC: number;\n u_floodM: number;\n u_floodY: number;\n u_floodK: number;\n u_gainC: number;\n u_gainM: number;\n u_gainY: number;\n u_gainK: number;\n u_type: (typeof HalftoneCmykTypes)[HalftoneCmykType];\n}\n\nexport interface HalftoneCmykParams extends ShaderSizingParams, ShaderMotionParams {\n image?: HTMLImageElement | string;\n colorBack?: string;\n colorC?: string;\n colorM?: string;\n colorY?: string;\n colorK?: string;\n size?: number;\n contrast?: number;\n softness?: number;\n grainSize?: number;\n grainMixer?: number;\n grainOverlay?: number;\n gridNoise?: number;\n floodC?: number;\n floodM?: number;\n floodY?: number;\n floodK?: number;\n gainC?: number;\n gainM?: number;\n gainY?: number;\n gainK?: number;\n type?: HalftoneCmykType;\n}\n\nexport const HalftoneCmykTypes = {\n dots: 0,\n ink: 1,\n sharp: 2,\n} as const;\n\nexport type HalftoneCmykType = keyof typeof HalftoneCmykTypes;\n\n"],
|
|
5
|
+
"mappings": ";;;;;AACA,eAAmE;AACnE,SAAS,iBAAiB;AAmDnB,MAAM,6BAAqC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA4C/C,SAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA2RN,MAAM,oBAAoB;AAAA,EAC/B,MAAM;AAAA,EACN,KAAK;AAAA,EACL,OAAO;AACT;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -28,6 +28,7 @@ import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-si
|
|
|
28
28
|
* - u_colorBack (vec4): Background color in RGBA
|
|
29
29
|
* - u_colorHighlight (vec4): Secondary foreground color in RGBA (set same as colorFront for classic 2-color dithering)
|
|
30
30
|
* - u_originalColors (bool): Use the original colors of the image instead of the color palette
|
|
31
|
+
* - u_inverted (bool): Inverts the image luminance, doesn't affect the color scheme; not effective at zero contrast
|
|
31
32
|
* - u_type (float): Dithering type (1 = random, 2 = 2x2 Bayer, 3 = 4x4 Bayer, 4 = 8x8 Bayer)
|
|
32
33
|
* - u_pxSize (float): Pixel size of dithering grid (0.5 to 20)
|
|
33
34
|
* - u_colorSteps (float): Number of colors to use, applies to both color modes (1 to 7)
|
|
@@ -43,6 +44,7 @@ export interface ImageDitheringUniforms extends ShaderSizingUniforms {
|
|
|
43
44
|
u_pxSize: number;
|
|
44
45
|
u_colorSteps: number;
|
|
45
46
|
u_originalColors: boolean;
|
|
47
|
+
u_inverted: boolean;
|
|
46
48
|
}
|
|
47
49
|
export interface ImageDitheringParams extends ShaderSizingParams, ShaderMotionParams {
|
|
48
50
|
image: HTMLImageElement | string;
|
|
@@ -53,6 +55,7 @@ export interface ImageDitheringParams extends ShaderSizingParams, ShaderMotionPa
|
|
|
53
55
|
size?: number;
|
|
54
56
|
colorSteps?: number;
|
|
55
57
|
originalColors?: boolean;
|
|
58
|
+
inverted?: boolean;
|
|
56
59
|
}
|
|
57
60
|
export declare const DitheringTypes: {
|
|
58
61
|
readonly random: 1;
|
|
@@ -31,6 +31,7 @@ uniform float u_imageAspectRatio;
|
|
|
31
31
|
uniform float u_type;
|
|
32
32
|
uniform float u_pxSize;
|
|
33
33
|
uniform bool u_originalColors;
|
|
34
|
+
uniform bool u_inverted;
|
|
34
35
|
uniform float u_colorSteps;
|
|
35
36
|
|
|
36
37
|
out vec4 fragColor;
|
|
@@ -133,6 +134,7 @@ void main() {
|
|
|
133
134
|
float dithering = 0.0;
|
|
134
135
|
|
|
135
136
|
float lum = dot(vec3(.2126, .7152, .0722), image.rgb);
|
|
137
|
+
lum = u_inverted ? (1. - lum) : lum;
|
|
136
138
|
|
|
137
139
|
switch (type) {
|
|
138
140
|
case 1: {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/shaders/image-dithering.ts"],
|
|
4
|
-
"sourcesContent": ["import type { ShaderMotionParams } from '../shader-mount.js';\nimport { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { proceduralHash21, declarePI } from '../shader-utils.js';\n\n/**\n * A dithering image filter with support for 4 dithering modes and multiple color palettes\n * (2-color, 3-color, and multicolor options, using either predefined colors or colors sampled\n * from the original image).\n *\n * SIZING NOTE: This shader performs sizing in the fragment shader (not vertex shader) to keep\n * u_pxSize in consistent actual pixels. The pixel grid is computed from gl_FragCoord before any\n * transforms, so scaling/rotating only affects the underlying image.\n * No vertex shader outputs (v_imageUV, v_objectUV, etc.) are used.\n *\n * Fragment shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n * - u_image (sampler2D): Source image texture\n * - u_imageAspectRatio (float): Aspect ratio of the source image\n * - u_colorFront (vec4): Foreground color in RGBA\n * - u_colorBack (vec4): Background color in RGBA\n * - u_colorHighlight (vec4): Secondary foreground color in RGBA (set same as colorFront for classic 2-color dithering)\n * - u_originalColors (bool): Use the original colors of the image instead of the color palette\n * - u_type (float): Dithering type (1 = random, 2 = 2x2 Bayer, 3 = 4x4 Bayer, 4 = 8x8 Bayer)\n * - u_pxSize (float): Pixel size of dithering grid (0.5 to 20)\n * - u_colorSteps (float): Number of colors to use, applies to both color modes (1 to 7)\n *\n */\n\n// language=GLSL\nexport const imageDitheringFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform vec2 u_resolution;\nuniform float u_pixelRatio;\nuniform float u_originX;\nuniform float u_originY;\nuniform float u_worldWidth;\nuniform float u_worldHeight;\nuniform float u_fit;\n\nuniform float u_scale;\nuniform float u_rotation;\nuniform float u_offsetX;\nuniform float u_offsetY;\n\nuniform vec4 u_colorFront;\nuniform vec4 u_colorBack;\nuniform vec4 u_colorHighlight;\n\nuniform sampler2D u_image;\nuniform float u_imageAspectRatio;\n\nuniform float u_type;\nuniform float u_pxSize;\nuniform bool u_originalColors;\nuniform float u_colorSteps;\n\nout vec4 fragColor;\n\n\n${ proceduralHash21 }\n${ declarePI }\n\nfloat getUvFrame(vec2 uv, vec2 pad) {\n float aa = 0.0001;\n\n float left = smoothstep(-pad.x, -pad.x + aa, uv.x);\n float right = smoothstep(1.0 + pad.x, 1.0 + pad.x - aa, uv.x);\n float bottom = smoothstep(-pad.y, -pad.y + aa, uv.y);\n float top = smoothstep(1.0 + pad.y, 1.0 + pad.y - aa, uv.y);\n\n return left * right * bottom * top;\n}\n\nvec2 getImageUV(vec2 uv) {\n vec2 boxOrigin = vec2(.5 - u_originX, u_originY - .5);\n float r = u_rotation * PI / 180.;\n mat2 graphicRotation = mat2(cos(r), sin(r), -sin(r), cos(r));\n vec2 graphicOffset = vec2(-u_offsetX, u_offsetY);\n\n vec2 imageBoxSize;\n if (u_fit == 1.) { // contain\n imageBoxSize.x = min(u_resolution.x / u_imageAspectRatio, u_resolution.y) * u_imageAspectRatio;\n } else if (u_fit == 2.) { // cover\n imageBoxSize.x = max(u_resolution.x / u_imageAspectRatio, u_resolution.y) * u_imageAspectRatio;\n } else {\n imageBoxSize.x = min(10.0, 10.0 / u_imageAspectRatio * u_imageAspectRatio);\n }\n imageBoxSize.y = imageBoxSize.x / u_imageAspectRatio;\n vec2 imageBoxScale = u_resolution.xy / imageBoxSize;\n\n vec2 imageUV = uv;\n imageUV *= imageBoxScale;\n imageUV += boxOrigin * (imageBoxScale - 1.);\n imageUV += graphicOffset;\n imageUV /= u_scale;\n imageUV.x *= u_imageAspectRatio;\n imageUV = graphicRotation * imageUV;\n imageUV.x /= u_imageAspectRatio;\n\n imageUV += .5;\n imageUV.y = 1. - imageUV.y;\n\n return imageUV;\n}\n\nconst int bayer2x2[4] = int[4](0, 2, 3, 1);\nconst int bayer4x4[16] = int[16](\n0, 8, 2, 10,\n12, 4, 14, 6,\n3, 11, 1, 9,\n15, 7, 13, 5\n);\n\nconst int bayer8x8[64] = int[64](\n0, 32, 8, 40, 2, 34, 10, 42,\n48, 16, 56, 24, 50, 18, 58, 26,\n12, 44, 4, 36, 14, 46, 6, 38,\n60, 28, 52, 20, 62, 30, 54, 22,\n3, 35, 11, 43, 1, 33, 9, 41,\n51, 19, 59, 27, 49, 17, 57, 25,\n15, 47, 7, 39, 13, 45, 5, 37,\n63, 31, 55, 23, 61, 29, 53, 21\n);\n\nfloat getBayerValue(vec2 uv, int size) {\n ivec2 pos = ivec2(fract(uv / float(size)) * float(size));\n int index = pos.y * size + pos.x;\n\n if (size == 2) {\n return float(bayer2x2[index]) / 4.0;\n } else if (size == 4) {\n return float(bayer4x4[index]) / 16.0;\n } else if (size == 8) {\n return float(bayer8x8[index]) / 64.0;\n }\n return 0.0;\n}\n\n\nvoid main() {\n\n float pxSize = u_pxSize * u_pixelRatio;\n vec2 pxSizeUV = gl_FragCoord.xy - .5 * u_resolution;\n pxSizeUV /= pxSize;\n vec2 canvasPixelizedUV = (floor(pxSizeUV) + .5) * pxSize;\n vec2 normalizedUV = canvasPixelizedUV / u_resolution;\n\n vec2 imageUV = getImageUV(normalizedUV);\n vec2 ditheringNoiseUV = canvasPixelizedUV;\n vec4 image = texture(u_image, imageUV);\n float frame = getUvFrame(imageUV, pxSize / u_resolution);\n\n int type = int(floor(u_type));\n float dithering = 0.0;\n\n float lum = dot(vec3(.2126, .7152, .0722), image.rgb);\n\n switch (type) {\n case 1: {\n dithering = step(hash21(ditheringNoiseUV), lum);\n } break;\n case 2:\n dithering = getBayerValue(pxSizeUV, 2);\n break;\n case 3:\n dithering = getBayerValue(pxSizeUV, 4);\n break;\n default :\n dithering = getBayerValue(pxSizeUV, 8);\n break;\n }\n\n float colorSteps = max(floor(u_colorSteps), 1.);\n vec3 color = vec3(0.0);\n float opacity = 1.;\n\n dithering -= .5;\n float brightness = clamp(lum + dithering / colorSteps, 0.0, 1.0);\n brightness = mix(0.0, brightness, frame);\n brightness = mix(0.0, brightness, image.a);\n float quantLum = floor(brightness * colorSteps + 0.5) / colorSteps;\n quantLum = mix(0.0, quantLum, frame);\n\n if (u_originalColors == true) {\n vec3 normColor = image.rgb / max(lum, 0.001);\n color = normColor * quantLum;\n\n float quantAlpha = floor(image.a * colorSteps + 0.5) / colorSteps;\n opacity = mix(quantLum, 1., quantAlpha);\n } else {\n vec3 fgColor = u_colorFront.rgb * u_colorFront.a;\n float fgOpacity = u_colorFront.a;\n vec3 bgColor = u_colorBack.rgb * u_colorBack.a;\n float bgOpacity = u_colorBack.a;\n vec3 hlColor = u_colorHighlight.rgb * u_colorHighlight.a;\n float hlOpacity = u_colorHighlight.a;\n\n fgColor = mix(fgColor, hlColor, step(1.02 - .02 * u_colorSteps, brightness));\n fgOpacity = mix(fgOpacity, hlOpacity, step(1.02 - .02 * u_colorSteps, brightness));\n\n color = fgColor * quantLum;\n opacity = fgOpacity * quantLum;\n color += bgColor * (1.0 - opacity);\n opacity += bgOpacity * (1.0 - opacity);\n }\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface ImageDitheringUniforms extends ShaderSizingUniforms {\n u_image: HTMLImageElement | string;\n u_colorFront: [number, number, number, number];\n u_colorBack: [number, number, number, number];\n u_colorHighlight: [number, number, number, number];\n u_type: (typeof DitheringTypes)[DitheringType];\n u_pxSize: number;\n u_colorSteps: number;\n u_originalColors: boolean;\n}\n\nexport interface ImageDitheringParams extends ShaderSizingParams, ShaderMotionParams {\n image: HTMLImageElement | string;\n colorFront?: string;\n colorBack?: string;\n colorHighlight?: string;\n type?: DitheringType;\n size?: number;\n colorSteps?: number;\n originalColors?: boolean;\n}\n\nexport const DitheringTypes = {\n 'random': 1,\n '2x2': 2,\n '4x4': 3,\n '8x8': 4,\n} as const;\n\nexport type DitheringType = keyof typeof DitheringTypes;\n"],
|
|
5
|
-
"mappings": ";;;;;AACA,eAAmE;AACnE,SAAS,kBAAkB,iBAAiB;
|
|
4
|
+
"sourcesContent": ["import type { ShaderMotionParams } from '../shader-mount.js';\nimport { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { proceduralHash21, declarePI } from '../shader-utils.js';\n\n/**\n * A dithering image filter with support for 4 dithering modes and multiple color palettes\n * (2-color, 3-color, and multicolor options, using either predefined colors or colors sampled\n * from the original image).\n *\n * SIZING NOTE: This shader performs sizing in the fragment shader (not vertex shader) to keep\n * u_pxSize in consistent actual pixels. The pixel grid is computed from gl_FragCoord before any\n * transforms, so scaling/rotating only affects the underlying image.\n * No vertex shader outputs (v_imageUV, v_objectUV, etc.) are used.\n *\n * Fragment shader uniforms:\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level of the graphics (0.01 to 4)\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\n * - u_image (sampler2D): Source image texture\n * - u_imageAspectRatio (float): Aspect ratio of the source image\n * - u_colorFront (vec4): Foreground color in RGBA\n * - u_colorBack (vec4): Background color in RGBA\n * - u_colorHighlight (vec4): Secondary foreground color in RGBA (set same as colorFront for classic 2-color dithering)\n * - u_originalColors (bool): Use the original colors of the image instead of the color palette\n * - u_inverted (bool): Inverts the image luminance, doesn't affect the color scheme; not effective at zero contrast\n * - u_type (float): Dithering type (1 = random, 2 = 2x2 Bayer, 3 = 4x4 Bayer, 4 = 8x8 Bayer)\n * - u_pxSize (float): Pixel size of dithering grid (0.5 to 20)\n * - u_colorSteps (float): Number of colors to use, applies to both color modes (1 to 7)\n *\n */\n\n// language=GLSL\nexport const imageDitheringFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform vec2 u_resolution;\nuniform float u_pixelRatio;\nuniform float u_originX;\nuniform float u_originY;\nuniform float u_worldWidth;\nuniform float u_worldHeight;\nuniform float u_fit;\n\nuniform float u_scale;\nuniform float u_rotation;\nuniform float u_offsetX;\nuniform float u_offsetY;\n\nuniform vec4 u_colorFront;\nuniform vec4 u_colorBack;\nuniform vec4 u_colorHighlight;\n\nuniform sampler2D u_image;\nuniform float u_imageAspectRatio;\n\nuniform float u_type;\nuniform float u_pxSize;\nuniform bool u_originalColors;\nuniform bool u_inverted;\nuniform float u_colorSteps;\n\nout vec4 fragColor;\n\n\n${ proceduralHash21 }\n${ declarePI }\n\nfloat getUvFrame(vec2 uv, vec2 pad) {\n float aa = 0.0001;\n\n float left = smoothstep(-pad.x, -pad.x + aa, uv.x);\n float right = smoothstep(1.0 + pad.x, 1.0 + pad.x - aa, uv.x);\n float bottom = smoothstep(-pad.y, -pad.y + aa, uv.y);\n float top = smoothstep(1.0 + pad.y, 1.0 + pad.y - aa, uv.y);\n\n return left * right * bottom * top;\n}\n\nvec2 getImageUV(vec2 uv) {\n vec2 boxOrigin = vec2(.5 - u_originX, u_originY - .5);\n float r = u_rotation * PI / 180.;\n mat2 graphicRotation = mat2(cos(r), sin(r), -sin(r), cos(r));\n vec2 graphicOffset = vec2(-u_offsetX, u_offsetY);\n\n vec2 imageBoxSize;\n if (u_fit == 1.) { // contain\n imageBoxSize.x = min(u_resolution.x / u_imageAspectRatio, u_resolution.y) * u_imageAspectRatio;\n } else if (u_fit == 2.) { // cover\n imageBoxSize.x = max(u_resolution.x / u_imageAspectRatio, u_resolution.y) * u_imageAspectRatio;\n } else {\n imageBoxSize.x = min(10.0, 10.0 / u_imageAspectRatio * u_imageAspectRatio);\n }\n imageBoxSize.y = imageBoxSize.x / u_imageAspectRatio;\n vec2 imageBoxScale = u_resolution.xy / imageBoxSize;\n\n vec2 imageUV = uv;\n imageUV *= imageBoxScale;\n imageUV += boxOrigin * (imageBoxScale - 1.);\n imageUV += graphicOffset;\n imageUV /= u_scale;\n imageUV.x *= u_imageAspectRatio;\n imageUV = graphicRotation * imageUV;\n imageUV.x /= u_imageAspectRatio;\n\n imageUV += .5;\n imageUV.y = 1. - imageUV.y;\n\n return imageUV;\n}\n\nconst int bayer2x2[4] = int[4](0, 2, 3, 1);\nconst int bayer4x4[16] = int[16](\n0, 8, 2, 10,\n12, 4, 14, 6,\n3, 11, 1, 9,\n15, 7, 13, 5\n);\n\nconst int bayer8x8[64] = int[64](\n0, 32, 8, 40, 2, 34, 10, 42,\n48, 16, 56, 24, 50, 18, 58, 26,\n12, 44, 4, 36, 14, 46, 6, 38,\n60, 28, 52, 20, 62, 30, 54, 22,\n3, 35, 11, 43, 1, 33, 9, 41,\n51, 19, 59, 27, 49, 17, 57, 25,\n15, 47, 7, 39, 13, 45, 5, 37,\n63, 31, 55, 23, 61, 29, 53, 21\n);\n\nfloat getBayerValue(vec2 uv, int size) {\n ivec2 pos = ivec2(fract(uv / float(size)) * float(size));\n int index = pos.y * size + pos.x;\n\n if (size == 2) {\n return float(bayer2x2[index]) / 4.0;\n } else if (size == 4) {\n return float(bayer4x4[index]) / 16.0;\n } else if (size == 8) {\n return float(bayer8x8[index]) / 64.0;\n }\n return 0.0;\n}\n\n\nvoid main() {\n\n float pxSize = u_pxSize * u_pixelRatio;\n vec2 pxSizeUV = gl_FragCoord.xy - .5 * u_resolution;\n pxSizeUV /= pxSize;\n vec2 canvasPixelizedUV = (floor(pxSizeUV) + .5) * pxSize;\n vec2 normalizedUV = canvasPixelizedUV / u_resolution;\n\n vec2 imageUV = getImageUV(normalizedUV);\n vec2 ditheringNoiseUV = canvasPixelizedUV;\n vec4 image = texture(u_image, imageUV);\n float frame = getUvFrame(imageUV, pxSize / u_resolution);\n\n int type = int(floor(u_type));\n float dithering = 0.0;\n\n float lum = dot(vec3(.2126, .7152, .0722), image.rgb);\n lum = u_inverted ? (1. - lum) : lum;\n\n switch (type) {\n case 1: {\n dithering = step(hash21(ditheringNoiseUV), lum);\n } break;\n case 2:\n dithering = getBayerValue(pxSizeUV, 2);\n break;\n case 3:\n dithering = getBayerValue(pxSizeUV, 4);\n break;\n default :\n dithering = getBayerValue(pxSizeUV, 8);\n break;\n }\n\n float colorSteps = max(floor(u_colorSteps), 1.);\n vec3 color = vec3(0.0);\n float opacity = 1.;\n\n dithering -= .5;\n float brightness = clamp(lum + dithering / colorSteps, 0.0, 1.0);\n brightness = mix(0.0, brightness, frame);\n brightness = mix(0.0, brightness, image.a);\n float quantLum = floor(brightness * colorSteps + 0.5) / colorSteps;\n quantLum = mix(0.0, quantLum, frame);\n\n if (u_originalColors == true) {\n vec3 normColor = image.rgb / max(lum, 0.001);\n color = normColor * quantLum;\n\n float quantAlpha = floor(image.a * colorSteps + 0.5) / colorSteps;\n opacity = mix(quantLum, 1., quantAlpha);\n } else {\n vec3 fgColor = u_colorFront.rgb * u_colorFront.a;\n float fgOpacity = u_colorFront.a;\n vec3 bgColor = u_colorBack.rgb * u_colorBack.a;\n float bgOpacity = u_colorBack.a;\n vec3 hlColor = u_colorHighlight.rgb * u_colorHighlight.a;\n float hlOpacity = u_colorHighlight.a;\n\n fgColor = mix(fgColor, hlColor, step(1.02 - .02 * u_colorSteps, brightness));\n fgOpacity = mix(fgOpacity, hlOpacity, step(1.02 - .02 * u_colorSteps, brightness));\n\n color = fgColor * quantLum;\n opacity = fgOpacity * quantLum;\n color += bgColor * (1.0 - opacity);\n opacity += bgOpacity * (1.0 - opacity);\n }\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface ImageDitheringUniforms extends ShaderSizingUniforms {\n u_image: HTMLImageElement | string;\n u_colorFront: [number, number, number, number];\n u_colorBack: [number, number, number, number];\n u_colorHighlight: [number, number, number, number];\n u_type: (typeof DitheringTypes)[DitheringType];\n u_pxSize: number;\n u_colorSteps: number;\n u_originalColors: boolean;\n u_inverted: boolean;\n}\n\nexport interface ImageDitheringParams extends ShaderSizingParams, ShaderMotionParams {\n image: HTMLImageElement | string;\n colorFront?: string;\n colorBack?: string;\n colorHighlight?: string;\n type?: DitheringType;\n size?: number;\n colorSteps?: number;\n originalColors?: boolean;\n inverted?: boolean;\n}\n\nexport const DitheringTypes = {\n 'random': 1,\n '2x2': 2,\n '4x4': 3,\n '8x8': 4,\n} as const;\n\nexport type DitheringType = keyof typeof DitheringTypes;\n"],
|
|
5
|
+
"mappings": ";;;;;AACA,eAAmE;AACnE,SAAS,kBAAkB,iBAAiB;AAsCrC,MAAM,+BAAuC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgCjD,gBAAiB;AAAA,EACjB,SAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA+KN,MAAM,iBAAiB;AAAA,EAC5B,UAAU;AAAA,EACV,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AACT;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function getEmptyPixel(): HTMLImageElement | undefined;
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/get-empty-pixel.ts"],
|
|
4
|
-
"sourcesContent": ["export function getEmptyPixel(): HTMLImageElement | undefined {\n if (typeof window === 'undefined') {\n console.warn('Paper Shaders: can\u2019t create an image on the server');\n return undefined;\n }\n\n const img = new Image();\n img.src = emptyPixel;\n return img;\n}\n\nconst emptyPixel = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==';\n"],
|
|
5
|
-
"mappings": ";;;;;AAAO,SAAS,gBAA8C;AAC5D,MAAI,OAAO,WAAW,aAAa;AACjC,YAAQ,KAAK,yDAAoD;AACjE,WAAO;AAAA,EACT;AAEA,QAAM,MAAM,IAAI,MAAM;AACtB,MAAI,MAAM;AACV,SAAO;AACT;AAEA,MAAM,aAAa;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|