@paper-design/shaders 0.0.67 → 0.0.69
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/index.d.ts +29 -18
- package/dist/index.js +6 -0
- package/dist/index.js.map +2 -2
- package/dist/shader-sizing.d.ts +0 -5
- package/dist/shader-sizing.js +1 -193
- package/dist/shader-sizing.js.map +2 -2
- package/dist/shaders/color-panels.d.ts +32 -12
- package/dist/shaders/color-panels.js +5 -5
- package/dist/shaders/color-panels.js.map +2 -2
- package/dist/shaders/dithering.d.ts +25 -19
- package/dist/shaders/dithering.js +114 -66
- package/dist/shaders/dithering.js.map +2 -2
- package/dist/shaders/dot-grid.d.ts +28 -14
- package/dist/shaders/dot-grid.js +2 -2
- package/dist/shaders/dot-grid.js.map +2 -2
- package/dist/shaders/dot-orbit.d.ts +27 -9
- package/dist/shaders/dot-orbit.js +8 -9
- package/dist/shaders/dot-orbit.js.map +2 -2
- package/dist/shaders/fluted-glass.d.ts +43 -18
- package/dist/shaders/fluted-glass.js +20 -51
- package/dist/shaders/fluted-glass.js.map +2 -2
- package/dist/shaders/god-rays.d.ts +32 -10
- package/dist/shaders/god-rays.js +2 -2
- package/dist/shaders/god-rays.js.map +2 -2
- package/dist/shaders/grain-gradient.d.ts +41 -17
- package/dist/shaders/grain-gradient.js +47 -33
- package/dist/shaders/grain-gradient.js.map +2 -2
- package/dist/shaders/halftone-cmyk.d.ts +105 -0
- package/dist/shaders/halftone-cmyk.js +290 -0
- package/dist/shaders/halftone-cmyk.js.map +7 -0
- package/dist/shaders/halftone-dots.d.ts +35 -6
- package/dist/shaders/halftone-dots.js +18 -55
- package/dist/shaders/halftone-dots.js.map +2 -2
- package/dist/shaders/heatmap.d.ts +36 -0
- package/dist/shaders/heatmap.js +98 -16
- package/dist/shaders/heatmap.js.map +2 -2
- package/dist/shaders/image-dithering.d.ts +29 -15
- package/dist/shaders/image-dithering.js +68 -37
- package/dist/shaders/image-dithering.js.map +2 -2
- package/dist/shaders/liquid-metal.d.ts +38 -14
- package/dist/shaders/liquid-metal.js +5 -2
- package/dist/shaders/liquid-metal.js.map +2 -2
- package/dist/shaders/mesh-gradient.d.ts +27 -8
- package/dist/shaders/mesh-gradient.js +1 -7
- package/dist/shaders/mesh-gradient.js.map +2 -2
- package/dist/shaders/metaballs.d.ts +24 -8
- package/dist/shaders/metaballs.js +2 -2
- package/dist/shaders/metaballs.js.map +2 -2
- package/dist/shaders/neuro-noise.d.ts +27 -5
- package/dist/shaders/neuro-noise.js +2 -3
- package/dist/shaders/neuro-noise.js.map +2 -2
- package/dist/shaders/paper-texture.d.ts +37 -12
- package/dist/shaders/paper-texture.js +20 -20
- package/dist/shaders/paper-texture.js.map +2 -2
- package/dist/shaders/perlin-noise.d.ts +27 -8
- package/dist/shaders/perlin-noise.js +13 -35
- package/dist/shaders/perlin-noise.js.map +2 -2
- package/dist/shaders/pulsing-border.d.ts +39 -13
- package/dist/shaders/pulsing-border.js +9 -7
- package/dist/shaders/pulsing-border.js.map +2 -2
- package/dist/shaders/simplex-noise.d.ts +25 -6
- package/dist/shaders/simplex-noise.js +21 -21
- package/dist/shaders/simplex-noise.js.map +2 -2
- package/dist/shaders/smoke-ring.d.ts +29 -7
- package/dist/shaders/smoke-ring.js +20 -17
- package/dist/shaders/smoke-ring.js.map +2 -2
- package/dist/shaders/spiral.d.ts +30 -10
- package/dist/shaders/spiral.js +4 -4
- package/dist/shaders/spiral.js.map +2 -2
- package/dist/shaders/static-mesh-gradient.d.ts +30 -9
- package/dist/shaders/static-mesh-gradient.js +9 -17
- package/dist/shaders/static-mesh-gradient.js.map +2 -2
- package/dist/shaders/static-radial-gradient.d.ts +33 -11
- package/dist/shaders/static-radial-gradient.js +18 -25
- package/dist/shaders/static-radial-gradient.js.map +2 -2
- package/dist/shaders/swirl.d.ts +29 -8
- package/dist/shaders/swirl.js +4 -4
- package/dist/shaders/swirl.js.map +2 -2
- package/dist/shaders/voronoi.d.ts +31 -10
- package/dist/shaders/voronoi.js +8 -8
- package/dist/shaders/voronoi.js.map +2 -2
- package/dist/shaders/warp.d.ts +31 -13
- package/dist/shaders/warp.js +3 -3
- package/dist/shaders/warp.js.map +2 -2
- package/dist/shaders/water.d.ts +30 -10
- package/dist/shaders/water.js +2 -2
- package/dist/shaders/water.js.map +2 -2
- package/dist/shaders/waves.d.ts +27 -12
- package/dist/shaders/waves.js +3 -3
- package/dist/shaders/waves.js.map +2 -2
- package/dist/vertex-shader.d.ts +1 -1
- package/dist/vertex-shader.js +2 -53
- package/dist/vertex-shader.js.map +2 -2
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/shaders/grain-gradient.ts"],
|
|
4
|
-
"sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport {\n sizingVariablesDeclaration,\n type ShaderSizingParams,\n type ShaderSizingUniforms,\n sizingDebugVariablesDeclaration,\n} from '../shader-sizing.js';\nimport {\n simplexNoise,\n declarePI,\n rotation2,\n textureRandomizerR,\n proceduralHash21,\n proceduralHash11,\n} from '../shader-utils.js';\n\nexport const grainGradientMeta = {\n maxColorCount: 7,\n} as const;\n\n/**\n * Multi-color gradient with noise & grain over animated abstract shapes\n *\n * Uniforms:\n * - u_colorBack (RGBA)\n * - u_colors (vec4[]), u_colorsCount (float used as integer)\n * - u_softness (0..1): blur between color bands\n * - u_intensity (0..1): distortion between color bands\n * - u_noise (0..1): grainy noise independent of softness\n * - u_shape (float used as integer):\n * ---- 1: single sine wave\n * ---- 2: dots pattern\n * ---- 3: truchet pattern\n * ---- 4: corners (2 rounded rectangles)\n * ---- 5: ripple\n * ---- 6: blob (metaballs)\n * ---- 7: circle imitating 3d look\n *\n * - u_noiseTexture (sampler2D): pre-computed randomizer source\n *\n * Note: grains are calculated using gl_FragCoord & u_resolution, meaning grains don't react to scaling and fit\n *\n */\n\n// language=GLSL\nexport const grainGradientFragmentShader: string = `#version 300 es\nprecision lowp float;\n\nuniform mediump float u_time;\nuniform mediump vec2 u_resolution;\nuniform mediump float u_pixelRatio;\n\nuniform sampler2D u_noiseTexture;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colors[${grainGradientMeta.maxColorCount}];\nuniform float u_colorsCount;\nuniform float u_softness;\nuniform float u_intensity;\nuniform float u_noise;\nuniform float u_shape;\n\nuniform mediump float u_originX;\nuniform mediump float u_originY;\nuniform mediump float u_worldWidth;\nuniform mediump float u_worldHeight;\nuniform mediump float u_fit;\n\nuniform mediump float u_scale;\nuniform mediump float u_rotation;\nuniform mediump float u_offsetX;\nuniform mediump float u_offsetY;\n\n${sizingVariablesDeclaration}\n${ sizingDebugVariablesDeclaration }\n\nout vec4 fragColor;\n\n${declarePI}\n${simplexNoise}\n${rotation2}\n${proceduralHash21}\n${textureRandomizerR}\n\nfloat valueNoiseR(vec2 st) {\n vec2 i = floor(st);\n vec2 f = fract(st);\n float a = randomR(i);\n float b = randomR(i + vec2(1.0, 0.0));\n float c = randomR(i + vec2(0.0, 1.0));\n float d = randomR(i + vec2(1.0, 1.0));\n vec2 u = f * f * (3.0 - 2.0 * f);\n float x1 = mix(a, b, u.x);\n float x2 = mix(c, d, u.x);\n return mix(x1, x2, u.y);\n}\nfloat fbmR(vec2 n) {\n float total = 0.;\n float amplitude = .2;\n for (int i = 0; i < 3; i++) {\n n = rotate(n, .3);\n total += valueNoiseR(n) * amplitude;\n n *= 1.99;\n amplitude *= 0.6;\n }\n return total;\n}\n\n${proceduralHash11}\n\nvec2 truchet(vec2 uv, float idx){\n idx = fract(((idx - .5) * 2.));\n if (idx > 0.75) {\n uv = vec2(1.0) - uv;\n } else if (idx > 0.5) {\n uv = vec2(1.0 - uv.x, uv.y);\n } else if (idx > 0.25) {\n uv = 1.0 - vec2(1.0 - uv.x, uv.y);\n }\n return uv;\n}\n\nvoid main() {\n\n const float firstFrameOffset = 7.;\n float t = .1 * (u_time + firstFrameOffset);\n\n vec2 shape_uv = vec2(0.);\n vec2 grain_uv = vec2(0.);\n\n if (u_shape > 3.5) {\n shape_uv = v_objectUV;\n grain_uv = shape_uv;\n\n // apply inverse transform to grain_uv so it respects the originXY\n float r = u_rotation * 3.14159265358979323846 / 180.;\n mat2 graphicRotation = mat2(cos(r), sin(r), -sin(r), cos(r));\n vec2 graphicOffset = vec2(-u_offsetX, u_offsetY);\n grain_uv = transpose(graphicRotation) * grain_uv;\n grain_uv *= u_scale;\n grain_uv -= graphicOffset;\n grain_uv *= v_objectBoxSize;\n grain_uv *= .7;\n } else {\n shape_uv = .5 * v_patternUV;\n grain_uv = 100. * v_patternUV;\n\n // apply inverse transform to grain_uv so it respects the originXY\n float r = u_rotation * 3.14159265358979323846 / 180.;\n mat2 graphicRotation = mat2(cos(r), sin(r), -sin(r), cos(r));\n vec2 graphicOffset = vec2(-u_offsetX, u_offsetY);\n grain_uv = transpose(graphicRotation) * grain_uv;\n grain_uv *= u_scale;\n if (u_fit > 0.) {\n vec2 givenBoxSize = vec2(u_worldWidth, u_worldHeight);\n givenBoxSize = max(givenBoxSize, vec2(1.)) * u_pixelRatio;\n float patternBoxRatio = givenBoxSize.x / givenBoxSize.y;\n vec2 patternBoxGivenSize = vec2(\n (u_worldWidth == 0.) ? u_resolution.x : givenBoxSize.x,\n (u_worldHeight == 0.) ? u_resolution.y : givenBoxSize.y\n );\n patternBoxRatio = patternBoxGivenSize.x / patternBoxGivenSize.y;\n float patternBoxNoFitBoxWidth = patternBoxRatio * min(patternBoxGivenSize.x / patternBoxRatio, patternBoxGivenSize.y);\n grain_uv /= (patternBoxNoFitBoxWidth / v_patternBoxSize.x);\n }\n vec2 patternBoxScale = u_resolution.xy / v_patternBoxSize;\n grain_uv -= graphicOffset / patternBoxScale;\n grain_uv *= 1.6;\n }\n\n\n float shape = 0.;\n\n if (u_shape < 1.5) {\n // Sine wave\n\n float wave = cos(.5 * shape_uv.x - 4. * t) * sin(1.5 * shape_uv.x + 2. * t) * (.75 + .25 * cos(6. * t));\n shape = 1. - smoothstep(-1., 1., shape_uv.y + wave);\n\n } else if (u_shape < 2.5) {\n // Grid (dots)\n\n float stripeIdx = floor(2. * shape_uv.x / TWO_PI);\n float rand = hash11(stripeIdx * 100.);\n rand = sign(rand - .5) * pow(4. * abs(rand), .3);\n shape = sin(shape_uv.x) * cos(shape_uv.y - 5. * rand * t);\n shape = pow(abs(shape), 4.);\n\n } else if (u_shape < 3.5) {\n // Truchet pattern\n\n float n2 = valueNoiseR(shape_uv * .4 - 3.75 * t);\n shape_uv.x += 10.;\n shape_uv *= .6;\n\n vec2 tile = truchet(fract(shape_uv), randomR(floor(shape_uv)));\n\n float distance1 = length(tile);\n float distance2 = length(tile - vec2(1.));\n\n n2 -= .5;\n n2 *= .1;\n shape = smoothstep(.2, .55, distance1 + n2) * (1. - smoothstep(.45, .8, distance1 - n2));\n shape += smoothstep(.2, .55, distance2 + n2) * (1. - smoothstep(.45, .8, distance2 - n2));\n\n shape = pow(shape, 1.5);\n\n } else if (u_shape < 4.5) {\n // Corners\n\n shape_uv *= .6;\n vec2 outer = vec2(.5);\n\n vec2 bl = smoothstep(vec2(0.), outer, shape_uv + vec2(.1 + .1 * sin(3. * t), .2 - .1 * sin(5.25 * t)));\n vec2 tr = smoothstep(vec2(0.), outer, 1. - shape_uv);\n shape = 1. - bl.x * bl.y * tr.x * tr.y;\n\n shape_uv = -shape_uv;\n bl = smoothstep(vec2(0.), outer, shape_uv + vec2(.1 + .1 * sin(3. * t), .2 - .1 * cos(5.25 * t)));\n tr = smoothstep(vec2(0.), outer, 1. - shape_uv);\n shape -= bl.x * bl.y * tr.x * tr.y;\n\n shape = 1. - smoothstep(0., 1., shape);\n\n } else if (u_shape < 5.5) {\n // Ripple\n\n shape_uv *= 2.;\n float dist = length(.4 * shape_uv);\n float waves = sin(pow(dist, 1.2) * 5. - 3. * t) * .5 + .5;\n shape = waves;\n\n } else if (u_shape < 6.5) {\n // Blob\n\n t *= 2.;\n\n vec2 f1_traj = .25 * vec2(1.3 * sin(t), .2 + 1.3 * cos(.6 * t + 4.));\n vec2 f2_traj = .2 * vec2(1.2 * sin(-t), 1.3 * sin(1.6 * t));\n vec2 f3_traj = .25 * vec2(1.7 * cos(-.6 * t), cos(-1.6 * t));\n vec2 f4_traj = .3 * vec2(1.4 * cos(.8 * t), 1.2 * sin(-.6 * t - 3.));\n\n shape = .5 * pow(1. - clamp(0., 1., length(shape_uv + f1_traj)), 5.);\n shape += .5 * pow(1. - clamp(0., 1., length(shape_uv + f2_traj)), 5.);\n shape += .5 * pow(1. - clamp(0., 1., length(shape_uv + f3_traj)), 5.);\n shape += .5 * pow(1. - clamp(0., 1., length(shape_uv + f4_traj)), 5.);\n\n shape = smoothstep(.0, .9, shape);\n float edge = smoothstep(.25, .3, shape);\n shape = mix(.0, shape, edge);\n\n } else {\n // Sphere\n\n shape_uv *= 2.;\n float d = 1. - pow(length(shape_uv), 2.);\n vec3 pos = vec3(shape_uv, sqrt(max(d, 0.)));\n vec3 lightPos = normalize(vec3(cos(1.5 * t), .8, sin(1.25 * t)));\n shape = .5 + .5 * dot(lightPos, pos);\n shape *= step(0., d);\n }\n\n float simplex = snoise(grain_uv * .5);\n float grainDist = simplex * snoise(grain_uv * .2) - fbmR(.002 * grain_uv + 10.) - fbmR(.003 * grain_uv);\n float rawNoise = .75 * simplex - fbmR(rotate(.4 * grain_uv, 2.)) - fbmR(.001 * grain_uv);\n float noise = clamp(rawNoise, 0., 1.);\n\n shape += u_intensity * 2. / u_colorsCount * (grainDist + .5);\n shape += u_noise * 10. / u_colorsCount * noise;\n\n float aa = fwidth(shape);\n\n shape = clamp(shape - .5 / u_colorsCount, 0., 1.);\n float totalShape = smoothstep(0., u_softness + 2. * aa, clamp(shape * u_colorsCount, 0., 1.));\n float mixer = shape * (u_colorsCount - 1.);\n\n vec4 gradient = u_colors[0];\n gradient.rgb *= gradient.a;\n for (int i = 1; i < ${grainGradientMeta.maxColorCount}; i++) {\n if (i > int(u_colorsCount) - 1) break;\n\n float localT = clamp(mixer - float(i - 1), 0., 1.);\n localT = smoothstep(.5 - .5 * u_softness - aa, .5 + .5 * u_softness + aa, localT);\n\n vec4 c = u_colors[i];\n c.rgb *= c.a;\n gradient = mix(gradient, c, localT);\n }\n\n vec3 color = gradient.rgb * totalShape;\n float opacity = gradient.a * totalShape;\n\n vec3 bgColor = u_colorBack.rgb * u_colorBack.a;\n color = color + bgColor * (1.0 - opacity);\n opacity = opacity + u_colorBack.a * (1.0 - opacity);\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface GrainGradientUniforms extends ShaderSizingUniforms {\n u_colorBack: [number, number, number, number];\n u_colors: vec4[];\n u_colorsCount: number;\n u_softness: number;\n u_intensity: number;\n u_noise: number;\n u_shape: (typeof GrainGradientShapes)[GrainGradientShape];\n u_noiseTexture?: HTMLImageElement;\n}\n\nexport interface GrainGradientParams extends ShaderSizingParams, ShaderMotionParams {\n colorBack?: string;\n colors?: string[];\n softness?: number;\n intensity?: number;\n noise?: number;\n shape?: GrainGradientShape;\n}\n\nexport const GrainGradientShapes = {\n wave: 1,\n dots: 2,\n truchet: 3,\n corners: 4,\n ripple: 5,\n blob: 6,\n sphere: 7,\n};\n\nexport type GrainGradientShape = keyof typeof GrainGradientShapes;\n"],
|
|
5
|
-
"mappings": ";;;;;AAEA;AAAA,
|
|
4
|
+
"sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport {\n type ShaderSizingParams,\n type ShaderSizingUniforms,\n} from '../shader-sizing.js';\nimport {\n simplexNoise,\n declarePI,\n rotation2,\n textureRandomizerR,\n proceduralHash11,\n} from '../shader-utils.js';\n\nexport const grainGradientMeta = {\n maxColorCount: 7,\n} as const;\n\n/**\n * Multi-color gradients with grainy, noise-textured distortion available in 7 animated abstract forms.\n *\n * Note: grains are calculated using gl_FragCoord & u_resolution, meaning grains don't react to scaling and fit\n *\n * Fragment shader uniforms:\n * - u_time (float): Animation time\n * - u_resolution (vec2): Canvas resolution in pixels\n * - u_pixelRatio (float): Device pixel ratio\n * - u_originX (float): Reference point for positioning (0 to 1)\n * - u_originY (float): Reference point for positioning (0 to 1)\n * - u_worldWidth (float): Virtual width of the graphic\n * - u_worldHeight (float): Virtual height of the graphic\n * - u_fit (float): Fit mode (0 = none, 1 = contain, 2 = cover)\n * - u_scale (float): Overall zoom level (0.01 to 4)\n * - u_rotation (float): Rotation angle in degrees (0 to 360)\n * - u_offsetX (float): Horizontal offset (-1 to 1)\n * - u_offsetY (float): Vertical offset (-1 to 1)\n * - u_colorBack (vec4): Background color in RGBA\n * - u_colors (vec4[]): Up to 7 gradient colors in RGBA\n * - u_colorsCount (float): Number of active colors\n * - u_softness (float): Color transition sharpness, 0 = hard edge, 1 = smooth gradient (0 to 1)\n * - u_intensity (float): Distortion between color bands (0 to 1)\n * - u_noise (float): Grainy noise overlay (0 to 1)\n * - u_shape (float): Shape type (1 = wave, 2 = dots, 3 = truchet, 4 = corners, 5 = ripple, 6 = blob, 7 = sphere)\n * - u_noiseTexture (sampler2D): Pre-computed randomizer source texture\n *\n * Vertex shader outputs (used in fragment shader):\n * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied (used for shapes 4-7)\n * - v_objectBoxSize (vec2): Size of the object bounding box in pixels\n * - v_patternUV (vec2): UV coordinates for pattern with global sizing (rotation, scale, offset, etc) applied (used for shapes 1-3)\n * - v_patternBoxSize (vec2): Size of the pattern bounding box in pixels\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_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 *\n */\n\n// language=GLSL\nexport const grainGradientFragmentShader: string = `#version 300 es\nprecision lowp float;\n\nuniform mediump float u_time;\nuniform mediump vec2 u_resolution;\nuniform mediump float u_pixelRatio;\n\nuniform sampler2D u_noiseTexture;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colors[${ grainGradientMeta.maxColorCount }];\nuniform float u_colorsCount;\nuniform float u_softness;\nuniform float u_intensity;\nuniform float u_noise;\nuniform float u_shape;\n\nuniform mediump float u_originX;\nuniform mediump float u_originY;\nuniform mediump float u_worldWidth;\nuniform mediump float u_worldHeight;\nuniform mediump float u_fit;\n\nuniform mediump float u_scale;\nuniform mediump float u_rotation;\nuniform mediump float u_offsetX;\nuniform mediump float u_offsetY;\n\nin vec2 v_objectUV;\nin vec2 v_patternUV;\nin vec2 v_objectBoxSize;\nin vec2 v_patternBoxSize;\n\nout vec4 fragColor;\n\n${ declarePI }\n${ simplexNoise }\n${ rotation2 }\n${ textureRandomizerR }\n\nfloat valueNoiseR(vec2 st) {\n vec2 i = floor(st);\n vec2 f = fract(st);\n float a = randomR(i);\n float b = randomR(i + vec2(1.0, 0.0));\n float c = randomR(i + vec2(0.0, 1.0));\n float d = randomR(i + vec2(1.0, 1.0));\n vec2 u = f * f * (3.0 - 2.0 * f);\n float x1 = mix(a, b, u.x);\n float x2 = mix(c, d, u.x);\n return mix(x1, x2, u.y);\n}\nvec4 fbmR(vec2 n0, vec2 n1, vec2 n2, vec2 n3) {\n float amplitude = 0.2;\n vec4 total = vec4(0.);\n for (int i = 0; i < 3; i++) {\n n0 = rotate(n0, 0.3);\n n1 = rotate(n1, 0.3);\n n2 = rotate(n2, 0.3);\n n3 = rotate(n3, 0.3);\n total.x += valueNoiseR(n0) * amplitude;\n total.y += valueNoiseR(n1) * amplitude;\n total.z += valueNoiseR(n2) * amplitude;\n total.z += valueNoiseR(n3) * amplitude;\n n0 *= 1.99;\n n1 *= 1.99;\n n2 *= 1.99;\n n3 *= 1.99;\n amplitude *= 0.6;\n }\n return total;\n}\n\n${ proceduralHash11 }\n\nvec2 truchet(vec2 uv, float idx){\n idx = fract(((idx - .5) * 2.));\n if (idx > 0.75) {\n uv = vec2(1.0) - uv;\n } else if (idx > 0.5) {\n uv = vec2(1.0 - uv.x, uv.y);\n } else if (idx > 0.25) {\n uv = 1.0 - vec2(1.0 - uv.x, uv.y);\n }\n return uv;\n}\n\nvoid main() {\n\n const float firstFrameOffset = 7.;\n float t = .1 * (u_time + firstFrameOffset);\n\n vec2 shape_uv = vec2(0.);\n vec2 grain_uv = vec2(0.);\n\n float r = u_rotation * PI / 180.;\n float cr = cos(r);\n float sr = sin(r);\n mat2 graphicRotation = mat2(cr, sr, -sr, cr);\n vec2 graphicOffset = vec2(-u_offsetX, u_offsetY);\n\n if (u_shape > 3.5) {\n shape_uv = v_objectUV;\n grain_uv = shape_uv;\n\n // apply inverse transform to grain_uv so it respects the originXY\n grain_uv = transpose(graphicRotation) * grain_uv;\n grain_uv *= u_scale;\n grain_uv -= graphicOffset;\n grain_uv *= v_objectBoxSize;\n grain_uv *= .7;\n } else {\n shape_uv = .5 * v_patternUV;\n grain_uv = 100. * v_patternUV;\n\n // apply inverse transform to grain_uv so it respects the originXY\n grain_uv = transpose(graphicRotation) * grain_uv;\n grain_uv *= u_scale;\n if (u_fit > 0.) {\n vec2 givenBoxSize = vec2(u_worldWidth, u_worldHeight);\n givenBoxSize = max(givenBoxSize, vec2(1.)) * u_pixelRatio;\n float patternBoxRatio = givenBoxSize.x / givenBoxSize.y;\n vec2 patternBoxGivenSize = vec2(\n (u_worldWidth == 0.) ? u_resolution.x : givenBoxSize.x,\n (u_worldHeight == 0.) ? u_resolution.y : givenBoxSize.y\n );\n patternBoxRatio = patternBoxGivenSize.x / patternBoxGivenSize.y;\n float patternBoxNoFitBoxWidth = patternBoxRatio * min(patternBoxGivenSize.x / patternBoxRatio, patternBoxGivenSize.y);\n grain_uv /= (patternBoxNoFitBoxWidth / v_patternBoxSize.x);\n }\n vec2 patternBoxScale = u_resolution.xy / v_patternBoxSize;\n grain_uv -= graphicOffset / patternBoxScale;\n grain_uv *= 1.6;\n }\n\n\n float shape = 0.;\n\n if (u_shape < 1.5) {\n // Sine wave\n\n float wave = cos(.5 * shape_uv.x - 4. * t) * sin(1.5 * shape_uv.x + 2. * t) * (.75 + .25 * cos(6. * t));\n shape = 1. - smoothstep(-1., 1., shape_uv.y + wave);\n\n } else if (u_shape < 2.5) {\n // Grid (dots)\n\n float stripeIdx = floor(2. * shape_uv.x / TWO_PI);\n float rand = hash11(stripeIdx * 100.);\n rand = sign(rand - .5) * pow(4. * abs(rand), .3);\n shape = sin(shape_uv.x) * cos(shape_uv.y - 5. * rand * t);\n shape = pow(abs(shape), 4.);\n\n } else if (u_shape < 3.5) {\n // Truchet pattern\n\n float n2 = valueNoiseR(shape_uv * .4 - 3.75 * t);\n shape_uv.x += 10.;\n shape_uv *= .6;\n\n vec2 tile = truchet(fract(shape_uv), randomR(floor(shape_uv)));\n\n float distance1 = length(tile);\n float distance2 = length(tile - vec2(1.));\n\n n2 -= .5;\n n2 *= .1;\n shape = smoothstep(.2, .55, distance1 + n2) * (1. - smoothstep(.45, .8, distance1 - n2));\n shape += smoothstep(.2, .55, distance2 + n2) * (1. - smoothstep(.45, .8, distance2 - n2));\n\n shape = pow(shape, 1.5);\n\n } else if (u_shape < 4.5) {\n // Corners\n\n shape_uv *= .6;\n vec2 outer = vec2(.5);\n\n vec2 bl = smoothstep(vec2(0.), outer, shape_uv + vec2(.1 + .1 * sin(3. * t), .2 - .1 * sin(5.25 * t)));\n vec2 tr = smoothstep(vec2(0.), outer, 1. - shape_uv);\n shape = 1. - bl.x * bl.y * tr.x * tr.y;\n\n shape_uv = -shape_uv;\n bl = smoothstep(vec2(0.), outer, shape_uv + vec2(.1 + .1 * sin(3. * t), .2 - .1 * cos(5.25 * t)));\n tr = smoothstep(vec2(0.), outer, 1. - shape_uv);\n shape -= bl.x * bl.y * tr.x * tr.y;\n\n shape = 1. - smoothstep(0., 1., shape);\n\n } else if (u_shape < 5.5) {\n // Ripple\n\n shape_uv *= 2.;\n float dist = length(.4 * shape_uv);\n float waves = sin(pow(dist, 1.2) * 5. - 3. * t) * .5 + .5;\n shape = waves;\n\n } else if (u_shape < 6.5) {\n // Blob\n\n t *= 2.;\n\n vec2 f1_traj = .25 * vec2(1.3 * sin(t), .2 + 1.3 * cos(.6 * t + 4.));\n vec2 f2_traj = .2 * vec2(1.2 * sin(-t), 1.3 * sin(1.6 * t));\n vec2 f3_traj = .25 * vec2(1.7 * cos(-.6 * t), cos(-1.6 * t));\n vec2 f4_traj = .3 * vec2(1.4 * cos(.8 * t), 1.2 * sin(-.6 * t - 3.));\n\n shape = .5 * pow(1. - clamp(0., 1., length(shape_uv + f1_traj)), 5.);\n shape += .5 * pow(1. - clamp(0., 1., length(shape_uv + f2_traj)), 5.);\n shape += .5 * pow(1. - clamp(0., 1., length(shape_uv + f3_traj)), 5.);\n shape += .5 * pow(1. - clamp(0., 1., length(shape_uv + f4_traj)), 5.);\n\n shape = smoothstep(.0, .9, shape);\n float edge = smoothstep(.25, .3, shape);\n shape = mix(.0, shape, edge);\n\n } else {\n // Sphere\n\n shape_uv *= 2.;\n float d = 1. - pow(length(shape_uv), 2.);\n vec3 pos = vec3(shape_uv, sqrt(max(d, 0.)));\n vec3 lightPos = normalize(vec3(cos(1.5 * t), .8, sin(1.25 * t)));\n shape = .5 + .5 * dot(lightPos, pos);\n shape *= step(0., d);\n }\n\n float baseNoise = snoise(grain_uv * .5);\n vec4 fbmVals = fbmR(\n .002 * grain_uv + 10.,\n .003 * grain_uv,\n .001 * grain_uv,\n rotate(.4 * grain_uv, 2.)\n );\n float grainDist = baseNoise * snoise(grain_uv * .2) - fbmVals.x - fbmVals.y;\n float rawNoise = .75 * baseNoise - fbmVals.w - fbmVals.z;\n float noise = clamp(rawNoise, 0., 1.);\n\n shape += u_intensity * 2. / u_colorsCount * (grainDist + .5);\n shape += u_noise * 10. / u_colorsCount * noise;\n\n float aa = fwidth(shape);\n\n shape = clamp(shape - .5 / u_colorsCount, 0., 1.);\n float totalShape = smoothstep(0., u_softness + 2. * aa, clamp(shape * u_colorsCount, 0., 1.));\n float mixer = shape * (u_colorsCount - 1.);\n\n int cntStop = int(u_colorsCount) - 1;\n vec4 gradient = u_colors[0];\n gradient.rgb *= gradient.a;\n for (int i = 1; i < ${ grainGradientMeta.maxColorCount }; i++) {\n if (i > cntStop) break;\n\n float localT = clamp(mixer - float(i - 1), 0., 1.);\n localT = smoothstep(.5 - .5 * u_softness - aa, .5 + .5 * u_softness + aa, localT);\n\n vec4 c = u_colors[i];\n c.rgb *= c.a;\n gradient = mix(gradient, c, localT);\n }\n\n vec3 color = gradient.rgb * totalShape;\n float opacity = gradient.a * totalShape;\n\n vec3 bgColor = u_colorBack.rgb * u_colorBack.a;\n color = color + bgColor * (1.0 - opacity);\n opacity = opacity + u_colorBack.a * (1.0 - opacity);\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface GrainGradientUniforms extends ShaderSizingUniforms {\n u_colorBack: [number, number, number, number];\n u_colors: vec4[];\n u_colorsCount: number;\n u_softness: number;\n u_intensity: number;\n u_noise: number;\n u_shape: (typeof GrainGradientShapes)[GrainGradientShape];\n u_noiseTexture?: HTMLImageElement;\n}\n\nexport interface GrainGradientParams extends ShaderSizingParams, ShaderMotionParams {\n colorBack?: string;\n colors?: string[];\n softness?: number;\n intensity?: number;\n noise?: number;\n shape?: GrainGradientShape;\n}\n\nexport const GrainGradientShapes = {\n wave: 1,\n dots: 2,\n truchet: 3,\n corners: 4,\n ripple: 5,\n blob: 6,\n sphere: 7,\n};\n\nexport type GrainGradientShape = keyof typeof GrainGradientShapes;\n"],
|
|
5
|
+
"mappings": ";;;;;AAEA;AAAA,OAGO;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEA,MAAM,oBAAoB;AAAA,EAC/B,eAAe;AACjB;AAmDO,MAAM,8BAAsC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAU1B,kBAAkB,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAyBtD,SAAU;AAAA,EACV,YAAa;AAAA,EACb,SAAU;AAAA,EACV,kBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmCnB,gBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAiLK,kBAAkB,aAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA0ClD,MAAM,sBAAsB;AAAA,EACjC,MAAM;AAAA,EACN,MAAM;AAAA,EACN,SAAS;AAAA,EACT,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,QAAQ;AACV;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import type { ShaderMotionParams } from '../shader-mount.js';
|
|
2
|
+
import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';
|
|
3
|
+
/**
|
|
4
|
+
* CMYK halftone printing effect applied to images with customizable dot patterns
|
|
5
|
+
* and ink colors for each channel (Cyan, Magenta, Yellow, Black).
|
|
6
|
+
*
|
|
7
|
+
* Fragment shader uniforms:
|
|
8
|
+
* - u_image (sampler2D): Source image texture
|
|
9
|
+
* - u_imageAspectRatio (float): Aspect ratio of the source image
|
|
10
|
+
* - u_colorBack (vec4): Background (paper) color in RGBA
|
|
11
|
+
* - u_colorC (vec4): Cyan ink color in RGBA
|
|
12
|
+
* - u_colorM (vec4): Magenta ink color in RGBA
|
|
13
|
+
* - u_colorY (vec4): Yellow ink color in RGBA
|
|
14
|
+
* - u_colorK (vec4): Black ink color in RGBA
|
|
15
|
+
* - u_size (float): Halftone cell size (0 to 1)
|
|
16
|
+
* - u_minDot (float): Minimum dot thickness (0 to 1)
|
|
17
|
+
* - u_contrast (float): Image contrast adjustment (0 to 2)
|
|
18
|
+
* - u_softness (float): Edge softness of dots (0 to 1)
|
|
19
|
+
* - u_grainSize (float): Size of grain overlay texture (0 to 1)
|
|
20
|
+
* - u_grainMixer (float): Strength of grain affecting dot size (0 to 1)
|
|
21
|
+
* - u_grainOverlay (float): Strength of grain overlay on final output (0 to 1)
|
|
22
|
+
* - u_gridNoise (float): Strength of smooth noise applied to both dot positions and color sampling (0 to 1)
|
|
23
|
+
* - u_floodC (float): Flat cyan dot size adjustment applied uniformly (-1 to 1)
|
|
24
|
+
* - u_floodM (float): Flat magenta dot size adjustment applied uniformly (-1 to 1)
|
|
25
|
+
* - u_floodY (float): Flat yellow dot size adjustment applied uniformly (-1 to 1)
|
|
26
|
+
* - u_floodK (float): Flat black dot size adjustment applied uniformly (-1 to 1)
|
|
27
|
+
* - u_gainC (float): Proportional cyan dot size gain (enhances existing dots, -1 to 1)
|
|
28
|
+
* - u_gainM (float): Proportional magenta dot size gain (enhances existing dots, -1 to 1)
|
|
29
|
+
* - u_gainY (float): Proportional yellow dot size gain (enhances existing dots, -1 to 1)
|
|
30
|
+
* - u_gainK (float): Proportional black dot size gain (enhances existing dots, -1 to 1)
|
|
31
|
+
* - u_type (float): Dot shape style (0 = dots, 1 = ink, 2 = sharp)
|
|
32
|
+
* - u_noiseTexture (sampler2D): Pre-computed randomizer source texture
|
|
33
|
+
*
|
|
34
|
+
* Vertex shader outputs (used in fragment shader):
|
|
35
|
+
* - v_imageUV (vec2): UV coordinates for sampling the source image, with fit, scale, rotation, and offset applied
|
|
36
|
+
*
|
|
37
|
+
* Vertex shader uniforms:
|
|
38
|
+
* - u_resolution (vec2): Canvas resolution in pixels
|
|
39
|
+
* - u_pixelRatio (float): Device pixel ratio
|
|
40
|
+
* - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)
|
|
41
|
+
* - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)
|
|
42
|
+
* - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)
|
|
43
|
+
* - u_scale (float): Overall zoom level of the graphics (0.01 to 4)
|
|
44
|
+
* - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)
|
|
45
|
+
* - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)
|
|
46
|
+
* - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)
|
|
47
|
+
* - u_imageAspectRatio (float): Aspect ratio of the source image
|
|
48
|
+
*
|
|
49
|
+
*/
|
|
50
|
+
export declare const halftoneCmykFragmentShader: string;
|
|
51
|
+
export interface HalftoneCmykUniforms extends ShaderSizingUniforms {
|
|
52
|
+
u_image: HTMLImageElement | string | undefined;
|
|
53
|
+
u_noiseTexture?: HTMLImageElement;
|
|
54
|
+
u_colorBack: [number, number, number, number];
|
|
55
|
+
u_colorC: [number, number, number, number];
|
|
56
|
+
u_colorM: [number, number, number, number];
|
|
57
|
+
u_colorY: [number, number, number, number];
|
|
58
|
+
u_colorK: [number, number, number, number];
|
|
59
|
+
u_size: number;
|
|
60
|
+
u_contrast: number;
|
|
61
|
+
u_softness: number;
|
|
62
|
+
u_grainSize: number;
|
|
63
|
+
u_grainMixer: number;
|
|
64
|
+
u_grainOverlay: number;
|
|
65
|
+
u_gridNoise: number;
|
|
66
|
+
u_floodC: number;
|
|
67
|
+
u_floodM: number;
|
|
68
|
+
u_floodY: number;
|
|
69
|
+
u_floodK: number;
|
|
70
|
+
u_gainC: number;
|
|
71
|
+
u_gainM: number;
|
|
72
|
+
u_gainY: number;
|
|
73
|
+
u_gainK: number;
|
|
74
|
+
u_type: (typeof HalftoneCmykTypes)[HalftoneCmykType];
|
|
75
|
+
}
|
|
76
|
+
export interface HalftoneCmykParams extends ShaderSizingParams, ShaderMotionParams {
|
|
77
|
+
image?: HTMLImageElement | string;
|
|
78
|
+
colorBack?: string;
|
|
79
|
+
colorC?: string;
|
|
80
|
+
colorM?: string;
|
|
81
|
+
colorY?: string;
|
|
82
|
+
colorK?: string;
|
|
83
|
+
size?: number;
|
|
84
|
+
contrast?: number;
|
|
85
|
+
softness?: number;
|
|
86
|
+
grainSize?: number;
|
|
87
|
+
grainMixer?: number;
|
|
88
|
+
grainOverlay?: number;
|
|
89
|
+
gridNoise?: number;
|
|
90
|
+
floodC?: number;
|
|
91
|
+
floodM?: number;
|
|
92
|
+
floodY?: number;
|
|
93
|
+
floodK?: number;
|
|
94
|
+
gainC?: number;
|
|
95
|
+
gainM?: number;
|
|
96
|
+
gainY?: number;
|
|
97
|
+
gainK?: number;
|
|
98
|
+
type?: HalftoneCmykType;
|
|
99
|
+
}
|
|
100
|
+
export declare const HalftoneCmykTypes: {
|
|
101
|
+
readonly dots: 0;
|
|
102
|
+
readonly ink: 1;
|
|
103
|
+
readonly sharp: 2;
|
|
104
|
+
};
|
|
105
|
+
export type HalftoneCmykType = keyof typeof HalftoneCmykTypes;
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
2
|
+
* Paper Shaders *
|
|
3
|
+
* https://github.com/paper-design/shaders *
|
|
4
|
+
* * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
5
|
+
|
|
6
|
+
import {} from "../shader-sizing.js";
|
|
7
|
+
import { declarePI } from "../shader-utils.js";
|
|
8
|
+
const halftoneCmykFragmentShader = `#version 300 es
|
|
9
|
+
precision mediump float;
|
|
10
|
+
|
|
11
|
+
uniform sampler2D u_image;
|
|
12
|
+
uniform float u_imageAspectRatio;
|
|
13
|
+
|
|
14
|
+
uniform vec4 u_colorBack;
|
|
15
|
+
uniform vec4 u_colorC;
|
|
16
|
+
uniform vec4 u_colorM;
|
|
17
|
+
uniform vec4 u_colorY;
|
|
18
|
+
uniform vec4 u_colorK;
|
|
19
|
+
uniform float u_size;
|
|
20
|
+
uniform float u_minDot;
|
|
21
|
+
uniform float u_contrast;
|
|
22
|
+
uniform float u_grainSize;
|
|
23
|
+
uniform float u_grainMixer;
|
|
24
|
+
uniform float u_grainOverlay;
|
|
25
|
+
uniform float u_gridNoise;
|
|
26
|
+
uniform float u_softness;
|
|
27
|
+
uniform float u_floodC;
|
|
28
|
+
uniform float u_floodM;
|
|
29
|
+
uniform float u_floodY;
|
|
30
|
+
uniform float u_floodK;
|
|
31
|
+
uniform float u_gainC;
|
|
32
|
+
uniform float u_gainM;
|
|
33
|
+
uniform float u_gainY;
|
|
34
|
+
uniform float u_gainK;
|
|
35
|
+
uniform float u_type;
|
|
36
|
+
uniform sampler2D u_noiseTexture;
|
|
37
|
+
|
|
38
|
+
in vec2 v_imageUV;
|
|
39
|
+
out vec4 fragColor;
|
|
40
|
+
|
|
41
|
+
const float shiftC = -.5;
|
|
42
|
+
const float shiftM = -.25;
|
|
43
|
+
const float shiftY = .2;
|
|
44
|
+
const float shiftK = 0.;
|
|
45
|
+
|
|
46
|
+
// Precomputed sin/cos for rotation angles (15\xB0, 75\xB0, 0\xB0, 45\xB0)
|
|
47
|
+
const float cosC = 0.9659258; const float sinC = 0.2588190; // 15\xB0
|
|
48
|
+
const float cosM = 0.2588190; const float sinM = 0.9659258; // 75\xB0
|
|
49
|
+
const float cosY = 1.0; const float sinY = 0.0; // 0\xB0
|
|
50
|
+
const float cosK = 0.7071068; const float sinK = 0.7071068; // 45\xB0
|
|
51
|
+
|
|
52
|
+
${declarePI}
|
|
53
|
+
|
|
54
|
+
vec2 randomRG(vec2 p) {
|
|
55
|
+
vec2 uv = floor(p) / 100. + .5;
|
|
56
|
+
return texture(u_noiseTexture, fract(uv)).rg;
|
|
57
|
+
}
|
|
58
|
+
vec3 hash23(vec2 p) {
|
|
59
|
+
vec3 p3 = fract(vec3(p.xyx) * vec3(0.3183099, 0.3678794, 0.3141592)) + 0.1;
|
|
60
|
+
p3 += dot(p3, p3.yzx + 19.19);
|
|
61
|
+
return fract(vec3(p3.x * p3.y, p3.y * p3.z, p3.z * p3.x));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
float sst(float edge0, float edge1, float x) {
|
|
65
|
+
return smoothstep(edge0, edge1, x);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
vec3 valueNoise3(vec2 st) {
|
|
69
|
+
vec2 i = floor(st);
|
|
70
|
+
vec2 f = fract(st);
|
|
71
|
+
vec3 a = hash23(i);
|
|
72
|
+
vec3 b = hash23(i + vec2(1.0, 0.0));
|
|
73
|
+
vec3 c = hash23(i + vec2(0.0, 1.0));
|
|
74
|
+
vec3 d = hash23(i + vec2(1.0, 1.0));
|
|
75
|
+
vec2 u = f * f * (3.0 - 2.0 * f);
|
|
76
|
+
vec3 x1 = mix(a, b, u.x);
|
|
77
|
+
vec3 x2 = mix(c, d, u.x);
|
|
78
|
+
return mix(x1, x2, u.y);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
float getUvFrame(vec2 uv, vec2 pad) {
|
|
82
|
+
float left = smoothstep(-pad.x, 0., uv.x);
|
|
83
|
+
float right = smoothstep(1. + pad.x, 1., uv.x);
|
|
84
|
+
float bottom = smoothstep(-pad.y, 0., uv.y);
|
|
85
|
+
float top = smoothstep(1. + pad.y, 1., uv.y);
|
|
86
|
+
|
|
87
|
+
return left * right * bottom * top;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
vec4 RGBAtoCMYK(vec4 rgba) {
|
|
91
|
+
float k = 1. - max(max(rgba.r, rgba.g), rgba.b);
|
|
92
|
+
float denom = 1. - k;
|
|
93
|
+
vec3 cmy = vec3(0.);
|
|
94
|
+
if (denom > 1e-5) {
|
|
95
|
+
cmy = (1. - rgba.rgb - vec3(k)) / denom;
|
|
96
|
+
}
|
|
97
|
+
return vec4(cmy, k) * rgba.a;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
vec3 applyContrast(vec3 rgb) {
|
|
101
|
+
return clamp((rgb - 0.5) * u_contrast + 0.5, 0.0, 1.0);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Single-component CMYK extractors with contrast built-in, alpha-aware
|
|
105
|
+
float getCyan(vec4 rgba) {
|
|
106
|
+
vec3 c = clamp((rgba.rgb - 0.5) * u_contrast + 0.5, 0.0, 1.0);
|
|
107
|
+
float maxRGB = max(max(c.r, c.g), c.b);
|
|
108
|
+
return (maxRGB > 1e-5 ? (maxRGB - c.r) / maxRGB : 0.) * rgba.a;
|
|
109
|
+
}
|
|
110
|
+
float getMagenta(vec4 rgba) {
|
|
111
|
+
vec3 c = clamp((rgba.rgb - 0.5) * u_contrast + 0.5, 0.0, 1.0);
|
|
112
|
+
float maxRGB = max(max(c.r, c.g), c.b);
|
|
113
|
+
return (maxRGB > 1e-5 ? (maxRGB - c.g) / maxRGB : 0.) * rgba.a;
|
|
114
|
+
}
|
|
115
|
+
float getYellow(vec4 rgba) {
|
|
116
|
+
vec3 c = clamp((rgba.rgb - 0.5) * u_contrast + 0.5, 0.0, 1.0);
|
|
117
|
+
float maxRGB = max(max(c.r, c.g), c.b);
|
|
118
|
+
return (maxRGB > 1e-5 ? (maxRGB - c.b) / maxRGB : 0.) * rgba.a;
|
|
119
|
+
}
|
|
120
|
+
float getBlack(vec4 rgba) {
|
|
121
|
+
vec3 c = clamp((rgba.rgb - 0.5) * u_contrast + 0.5, 0.0, 1.0);
|
|
122
|
+
return (1. - max(max(c.r, c.g), c.b)) * rgba.a;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
vec2 cellCenterPos(vec2 uv, vec2 cellOffset, float channelIdx) {
|
|
126
|
+
vec2 cellCenter = floor(uv) + .5 + cellOffset;
|
|
127
|
+
return cellCenter + (randomRG(cellCenter + channelIdx * 50.) - .5) * u_gridNoise;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
vec2 gridToImageUV(vec2 cellCenter, float cosA, float sinA, float shift, vec2 pad) {
|
|
131
|
+
vec2 uvGrid = mat2(cosA, -sinA, sinA, cosA) * (cellCenter - shift);
|
|
132
|
+
return uvGrid * pad + 0.5;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
void colorMask(vec2 pos, vec2 cellCenter, float rad, float outOfFrame, float grain, float channelAddon, float channelgain, float generalComp, bool isJoined, inout float outMask) {
|
|
136
|
+
float dist = length(pos - cellCenter);
|
|
137
|
+
|
|
138
|
+
float radius = rad;
|
|
139
|
+
radius *= (1. + generalComp);
|
|
140
|
+
radius += channelAddon + channelgain * radius;
|
|
141
|
+
radius += .15;
|
|
142
|
+
radius = max(0., radius);
|
|
143
|
+
radius = mix(0., radius, outOfFrame);
|
|
144
|
+
radius *= (1. - grain);
|
|
145
|
+
|
|
146
|
+
float mask = 1. - sst(0., radius, dist);
|
|
147
|
+
if (isJoined) {
|
|
148
|
+
// ink or sharp (joined)
|
|
149
|
+
mask = pow(mask, 1.2);
|
|
150
|
+
} else {
|
|
151
|
+
// dots (separate)
|
|
152
|
+
mask = sst(.5 - .5 * u_softness, .51 + .49 * u_softness, mask);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
mask *= mix(1., mix(.5, 1., 1.5 * radius), u_softness);
|
|
156
|
+
outMask += mask;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
vec3 applyInk(vec3 paper, vec3 inkColor, float cov) {
|
|
160
|
+
vec3 inkEffect = mix(vec3(1.0), inkColor, clamp(cov, 0.0, 1.0));
|
|
161
|
+
return paper * inkEffect;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
void main() {
|
|
165
|
+
vec2 uv = v_imageUV;
|
|
166
|
+
|
|
167
|
+
float cellsPerSide = mix(400.0, 7.0, pow(u_size, 0.7));
|
|
168
|
+
float cellSizeY = 1.0 / cellsPerSide;
|
|
169
|
+
vec2 pad = cellSizeY * vec2(1.0 / u_imageAspectRatio, 1.0);
|
|
170
|
+
vec2 uvGrid = (uv - .5) / pad;
|
|
171
|
+
float outOfFrame = getUvFrame(uv, pad);
|
|
172
|
+
|
|
173
|
+
float generalComp = .1 * u_softness + .1 * u_gridNoise + .1 * (1. - step(0.5, u_type)) * (1.5 - u_softness);
|
|
174
|
+
|
|
175
|
+
vec2 uvC = mat2(cosC, sinC, -sinC, cosC) * uvGrid + shiftC;
|
|
176
|
+
vec2 uvM = mat2(cosM, sinM, -sinM, cosM) * uvGrid + shiftM;
|
|
177
|
+
vec2 uvY = mat2(cosY, sinY, -sinY, cosY) * uvGrid + shiftY;
|
|
178
|
+
vec2 uvK = mat2(cosK, sinK, -sinK, cosK) * uvGrid + shiftK;
|
|
179
|
+
|
|
180
|
+
vec2 grainSize = mix(2000., 200., u_grainSize) * vec2(1., 1. / u_imageAspectRatio);
|
|
181
|
+
vec2 grainUV = (v_imageUV - .5) * grainSize + .5;
|
|
182
|
+
vec3 noiseValues = valueNoise3(grainUV);
|
|
183
|
+
float grain = sst(.55, 1., noiseValues.r);
|
|
184
|
+
grain *= u_grainMixer;
|
|
185
|
+
|
|
186
|
+
vec4 outMask = vec4(0.);
|
|
187
|
+
bool isJoined = u_type > 0.5;
|
|
188
|
+
|
|
189
|
+
if (u_type < 1.5) {
|
|
190
|
+
// dots or ink: per-cell color sampling
|
|
191
|
+
for (int dy = -1; dy <= 1; dy++) {
|
|
192
|
+
for (int dx = -1; dx <= 1; dx++) {
|
|
193
|
+
vec2 cellOffset = vec2(float(dx), float(dy));
|
|
194
|
+
|
|
195
|
+
vec2 cellCenterC = cellCenterPos(uvC, cellOffset, 0.);
|
|
196
|
+
vec4 texC = texture(u_image, gridToImageUV(cellCenterC, cosC, sinC, shiftC, pad));
|
|
197
|
+
colorMask(uvC, cellCenterC, getCyan(texC), outOfFrame, grain, u_floodC, u_gainC, generalComp, isJoined, outMask[0]);
|
|
198
|
+
|
|
199
|
+
vec2 cellCenterM = cellCenterPos(uvM, cellOffset, 1.);
|
|
200
|
+
vec4 texM = texture(u_image, gridToImageUV(cellCenterM, cosM, sinM, shiftM, pad));
|
|
201
|
+
colorMask(uvM, cellCenterM, getMagenta(texM), outOfFrame, grain, u_floodM, u_gainM, generalComp, isJoined, outMask[1]);
|
|
202
|
+
|
|
203
|
+
vec2 cellCenterY = cellCenterPos(uvY, cellOffset, 2.);
|
|
204
|
+
vec4 texY = texture(u_image, gridToImageUV(cellCenterY, cosY, sinY, shiftY, pad));
|
|
205
|
+
colorMask(uvY, cellCenterY, getYellow(texY), outOfFrame, grain, u_floodY, u_gainY, generalComp, isJoined, outMask[2]);
|
|
206
|
+
|
|
207
|
+
vec2 cellCenterK = cellCenterPos(uvK, cellOffset, 3.);
|
|
208
|
+
vec4 texK = texture(u_image, gridToImageUV(cellCenterK, cosK, sinK, shiftK, pad));
|
|
209
|
+
colorMask(uvK, cellCenterK, getBlack(texK), outOfFrame, grain, u_floodK, u_gainK, generalComp, isJoined, outMask[3]);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
} else {
|
|
213
|
+
// sharp: direct px color sampling
|
|
214
|
+
vec4 tex = texture(u_image, uv);
|
|
215
|
+
tex.rgb = applyContrast(tex.rgb);
|
|
216
|
+
vec4 cmykOriginal = RGBAtoCMYK(tex);
|
|
217
|
+
for (int dy = -1; dy <= 1; dy++) {
|
|
218
|
+
for (int dx = -1; dx <= 1; dx++) {
|
|
219
|
+
vec2 cellOffset = vec2(float(dx), float(dy));
|
|
220
|
+
|
|
221
|
+
colorMask(uvC, cellCenterPos(uvC, cellOffset, 0.), cmykOriginal.x, outOfFrame, grain, u_floodC, u_gainC, generalComp, isJoined, outMask[0]);
|
|
222
|
+
colorMask(uvM, cellCenterPos(uvM, cellOffset, 1.), cmykOriginal.y, outOfFrame, grain, u_floodM, u_gainM, generalComp, isJoined, outMask[1]);
|
|
223
|
+
colorMask(uvY, cellCenterPos(uvY, cellOffset, 2.), cmykOriginal.z, outOfFrame, grain, u_floodY, u_gainY, generalComp, isJoined, outMask[2]);
|
|
224
|
+
colorMask(uvK, cellCenterPos(uvK, cellOffset, 3.), cmykOriginal.w, outOfFrame, grain, u_floodK, u_gainK, generalComp, isJoined, outMask[3]);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
float shape;
|
|
230
|
+
|
|
231
|
+
float C = outMask[0];
|
|
232
|
+
float M = outMask[1];
|
|
233
|
+
float Y = outMask[2];
|
|
234
|
+
float K = outMask[3];
|
|
235
|
+
|
|
236
|
+
if (isJoined) {
|
|
237
|
+
// ink or sharp: apply threshold for joined dots
|
|
238
|
+
float th = .5;
|
|
239
|
+
float sLeft = th * u_softness;
|
|
240
|
+
float sRight = (1. - th) * u_softness + .01;
|
|
241
|
+
C = smoothstep(th - sLeft - fwidth(C), th + sRight, C);
|
|
242
|
+
M = smoothstep(th - sLeft - fwidth(M), th + sRight, M);
|
|
243
|
+
Y = smoothstep(th - sLeft - fwidth(Y), th + sRight, Y);
|
|
244
|
+
K = smoothstep(th - sLeft - fwidth(K), th + sRight, K);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
C *= u_colorC.a;
|
|
248
|
+
M *= u_colorM.a;
|
|
249
|
+
Y *= u_colorY.a;
|
|
250
|
+
K *= u_colorK.a;
|
|
251
|
+
|
|
252
|
+
vec3 ink = vec3(1.);
|
|
253
|
+
ink = applyInk(ink, u_colorK.rgb, K);
|
|
254
|
+
ink = applyInk(ink, u_colorC.rgb, C);
|
|
255
|
+
ink = applyInk(ink, u_colorM.rgb, M);
|
|
256
|
+
ink = applyInk(ink, u_colorY.rgb, Y);
|
|
257
|
+
|
|
258
|
+
shape = clamp(max(max(C, M), max(Y, K)), 0., 1.);
|
|
259
|
+
|
|
260
|
+
vec3 color = u_colorBack.rgb * u_colorBack.a;
|
|
261
|
+
float opacity = u_colorBack.a;
|
|
262
|
+
color = mix(color, ink, shape);
|
|
263
|
+
opacity += shape;
|
|
264
|
+
opacity = clamp(opacity, 0., 1.);
|
|
265
|
+
|
|
266
|
+
float grainOverlay = mix(noiseValues.g, noiseValues.b, .5);
|
|
267
|
+
grainOverlay = pow(grainOverlay, 1.3);
|
|
268
|
+
|
|
269
|
+
float grainOverlayV = grainOverlay * 2. - 1.;
|
|
270
|
+
vec3 grainOverlayColor = vec3(step(0., grainOverlayV));
|
|
271
|
+
float grainOverlayStrength = u_grainOverlay * abs(grainOverlayV);
|
|
272
|
+
grainOverlayStrength = pow(grainOverlayStrength, .8);
|
|
273
|
+
color = mix(color, grainOverlayColor, .5 * grainOverlayStrength);
|
|
274
|
+
|
|
275
|
+
opacity += .5 * grainOverlayStrength;
|
|
276
|
+
opacity = clamp(opacity, 0., 1.);
|
|
277
|
+
|
|
278
|
+
fragColor = vec4(color, opacity);
|
|
279
|
+
}
|
|
280
|
+
`;
|
|
281
|
+
const HalftoneCmykTypes = {
|
|
282
|
+
dots: 0,
|
|
283
|
+
ink: 1,
|
|
284
|
+
sharp: 2
|
|
285
|
+
};
|
|
286
|
+
export {
|
|
287
|
+
HalftoneCmykTypes,
|
|
288
|
+
halftoneCmykFragmentShader
|
|
289
|
+
};
|
|
290
|
+
//# sourceMappingURL=halftone-cmyk.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 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;AAyRN,MAAM,oBAAoB;AAAA,EAC/B,MAAM;AAAA,EACN,KAAK;AAAA,EACL,OAAO;AACT;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -1,12 +1,41 @@
|
|
|
1
1
|
import type { ShaderMotionParams } from '../shader-mount.js';
|
|
2
2
|
import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';
|
|
3
3
|
/**
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
-
|
|
8
|
-
|
|
9
|
-
-
|
|
4
|
+
* A halftone-dot image filter featuring customizable grids, color palettes, and dot styles.
|
|
5
|
+
*
|
|
6
|
+
* Fragment shader uniforms:
|
|
7
|
+
* - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)
|
|
8
|
+
* - u_time (float): Animation time
|
|
9
|
+
* - u_image (sampler2D): Source image texture
|
|
10
|
+
* - u_imageAspectRatio (float): Aspect ratio of the source image
|
|
11
|
+
* - u_colorFront (vec4): Foreground color in RGBA
|
|
12
|
+
* - u_colorBack (vec4): Background color in RGBA
|
|
13
|
+
* - u_originalColors (bool): Use sampled image's original colors instead of colorFront
|
|
14
|
+
* - u_type (float): Dot style (0 = classic, 1 = gooey, 2 = holes, 3 = soft)
|
|
15
|
+
* - u_inverted (bool): Inverts the image luminance, doesn't affect the color scheme; not effective at zero contrast
|
|
16
|
+
* - u_grid (float): Grid type (0 = square, 1 = hex)
|
|
17
|
+
* - u_size (float): Grid size relative to the image box (0 to 1)
|
|
18
|
+
* - u_radius (float): Maximum dot size relative to grid cell (0 to 2)
|
|
19
|
+
* - u_contrast (float): Contrast applied to the sampled image (0 to 1)
|
|
20
|
+
* - u_grainMixer (float): Strength of grain distortion applied to shape edges (0 to 1)
|
|
21
|
+
* - u_grainOverlay (float): Post-processing black/white grain overlay (0 to 1)
|
|
22
|
+
* - u_grainSize (float): Scale applied to both grain distortion and grain overlay (0 to 1)
|
|
23
|
+
*
|
|
24
|
+
* Vertex shader outputs (used in fragment shader):
|
|
25
|
+
* - v_imageUV (vec2): Image UV coordinates with global sizing (rotation, scale, offset, etc) applied
|
|
26
|
+
*
|
|
27
|
+
* Vertex shader uniforms:
|
|
28
|
+
* - u_resolution (vec2): Canvas resolution in pixels
|
|
29
|
+
* - u_pixelRatio (float): Device pixel ratio
|
|
30
|
+
* - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)
|
|
31
|
+
* - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)
|
|
32
|
+
* - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)
|
|
33
|
+
* - u_scale (float): Overall zoom level of the graphics (0.01 to 4)
|
|
34
|
+
* - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)
|
|
35
|
+
* - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)
|
|
36
|
+
* - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)
|
|
37
|
+
* - u_imageAspectRatio (float): Aspect ratio of the source image
|
|
38
|
+
*
|
|
10
39
|
*/
|
|
11
40
|
export declare const halftoneDotsFragmentShader: string;
|
|
12
41
|
export interface HalftoneDotsUniforms extends ShaderSizingUniforms {
|