@paper-design/shaders 0.0.53 → 0.0.55

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dist/get-empty-pixel.d.ts +1 -0
  2. package/dist/get-empty-pixel.js +19 -0
  3. package/dist/get-empty-pixel.js.map +7 -0
  4. package/dist/get-shader-noise-texture.js +1 -1
  5. package/dist/get-shader-noise-texture.js.map +2 -2
  6. package/dist/index.d.ts +2 -1
  7. package/dist/index.js +5 -1
  8. package/dist/index.js.map +2 -2
  9. package/dist/shader-mount.d.ts +3 -1
  10. package/dist/shader-mount.js +58 -34
  11. package/dist/shader-mount.js.map +2 -2
  12. package/dist/shaders/dithering.d.ts +1 -1
  13. package/dist/shaders/dithering.js.map +1 -1
  14. package/dist/shaders/fluted-glass.d.ts +9 -8
  15. package/dist/shaders/fluted-glass.js +13 -14
  16. package/dist/shaders/fluted-glass.js.map +2 -2
  17. package/dist/shaders/heatmap.d.ts +2 -2
  18. package/dist/shaders/heatmap.js +3 -3
  19. package/dist/shaders/heatmap.js.map +1 -1
  20. package/dist/shaders/image-dithering.d.ts +3 -3
  21. package/dist/shaders/image-dithering.js +1 -1
  22. package/dist/shaders/image-dithering.js.map +1 -1
  23. package/dist/shaders/mesh-gradient.d.ts +6 -1
  24. package/dist/shaders/mesh-gradient.js +49 -6
  25. package/dist/shaders/mesh-gradient.js.map +2 -2
  26. package/dist/shaders/paper-texture.d.ts +13 -13
  27. package/dist/shaders/paper-texture.js +26 -16
  28. package/dist/shaders/paper-texture.js.map +2 -2
  29. package/dist/shaders/pulsing-border.d.ts +17 -0
  30. package/dist/shaders/pulsing-border.js +82 -83
  31. package/dist/shaders/pulsing-border.js.map +2 -2
  32. package/dist/shaders/static-mesh-gradient.d.ts +0 -3
  33. package/dist/shaders/static-mesh-gradient.js +38 -14
  34. package/dist/shaders/static-mesh-gradient.js.map +2 -2
  35. package/dist/shaders/static-radial-gradient.d.ts +0 -3
  36. package/dist/shaders/static-radial-gradient.js +49 -14
  37. package/dist/shaders/static-radial-gradient.js.map +2 -2
  38. package/dist/shaders/water.d.ts +4 -4
  39. package/dist/shaders/water.js +12 -12
  40. package/dist/shaders/water.js.map +1 -1
  41. package/package.json +1 -1
@@ -12,7 +12,8 @@ export declare const meshGradientMeta: {
12
12
  * - u_colors (vec4[]), u_colorsCount (float used as integer)
13
13
  * - u_distortion: warp distortion
14
14
  * - u_swirl: vortex distortion
15
- *
15
+ * - u_grainMixer: shape distortion
16
+ * - u_grainOverlay: post-processing blending
16
17
  */
17
18
  export declare const meshGradientFragmentShader: string;
18
19
  export interface MeshGradientUniforms extends ShaderSizingUniforms {
@@ -20,9 +21,13 @@ export interface MeshGradientUniforms extends ShaderSizingUniforms {
20
21
  u_colorsCount: number;
21
22
  u_distortion: number;
22
23
  u_swirl: number;
24
+ u_grainMixer: number;
25
+ u_grainOverlay: number;
23
26
  }
24
27
  export interface MeshGradientParams extends ShaderSizingParams, ShaderMotionParams {
25
28
  colors?: string[];
26
29
  distortion?: number;
27
30
  swirl?: number;
31
+ grainMixer?: number;
32
+ grainOverlay?: number;
28
33
  }
@@ -3,8 +3,12 @@
3
3
  * https://github.com/paper-design/shaders *
4
4
  * * * * * * * * * * * * * * * * * * * * * * * * * * * */
5
5
 
6
- import { sizingVariablesDeclaration } from "../shader-sizing.js";
7
- import { declarePI, rotation2, colorBandingFix } from "../shader-utils.js";
6
+ import {
7
+ sizingDebugVariablesDeclaration,
8
+ sizingVariablesDeclaration,
9
+ sizingUniformsDeclaration
10
+ } from "../shader-sizing.js";
11
+ import { declarePI, rotation2, proceduralHash21 } from "../shader-utils.js";
8
12
  const meshGradientMeta = {
9
13
  maxColorCount: 10
10
14
  };
@@ -18,13 +22,35 @@ uniform float u_colorsCount;
18
22
 
19
23
  uniform float u_distortion;
20
24
  uniform float u_swirl;
25
+ uniform float u_grainMixer;
26
+ uniform float u_grainOverlay;
21
27
 
22
28
  ${sizingVariablesDeclaration}
29
+ ${sizingDebugVariablesDeclaration}
30
+ ${sizingUniformsDeclaration}
23
31
 
24
32
  out vec4 fragColor;
25
33
 
26
34
  ${declarePI}
27
35
  ${rotation2}
36
+ ${proceduralHash21}
37
+
38
+ float valueNoise(vec2 st) {
39
+ vec2 i = floor(st);
40
+ vec2 f = fract(st);
41
+ float a = hash21(i);
42
+ float b = hash21(i + vec2(1.0, 0.0));
43
+ float c = hash21(i + vec2(0.0, 1.0));
44
+ float d = hash21(i + vec2(1.0, 1.0));
45
+ vec2 u = f * f * (3.0 - 2.0 * f);
46
+ float x1 = mix(a, b, u.x);
47
+ float x2 = mix(c, d, u.x);
48
+ return mix(x1, x2, u.y);
49
+ }
50
+
51
+ float noise(vec2 n, vec2 seedOffset) {
52
+ return valueNoise(n + seedOffset);
53
+ }
28
54
 
29
55
  vec2 getPosition(int i, float t) {
30
56
  float a = float(i) * .37;
@@ -39,9 +65,22 @@ vec2 getPosition(int i, float t) {
39
65
 
40
66
  void main() {
41
67
  vec2 shape_uv = v_objectUV;
42
-
43
68
  shape_uv += .5;
44
69
 
70
+ vec2 grainUV = v_objectUV;
71
+ // apply inverse transform to grain_uv so it respects the originXY
72
+ float grainUVRot = u_rotation * 3.14159265358979323846 / 180.;
73
+ mat2 graphicRotation = mat2(cos(grainUVRot), sin(grainUVRot), -sin(grainUVRot), cos(grainUVRot));
74
+ vec2 graphicOffset = vec2(-u_offsetX, u_offsetY);
75
+ grainUV = transpose(graphicRotation) * grainUV;
76
+ grainUV *= u_scale;
77
+ grainUV *= .7;
78
+ grainUV -= graphicOffset;
79
+ grainUV *= v_objectBoxSize;
80
+
81
+ float grain = noise(grainUV, vec2(0.));
82
+ float mixerGrain = .4 * u_grainMixer * (grain - .5);
83
+
45
84
  const float firstFrameOffset = 41.5;
46
85
  float t = .5 * (u_time + firstFrameOffset);
47
86
 
@@ -65,7 +104,7 @@ void main() {
65
104
  for (int i = 0; i < ${meshGradientMeta.maxColorCount}; i++) {
66
105
  if (i >= int(u_colorsCount)) break;
67
106
 
68
- vec2 pos = getPosition(i, t);
107
+ vec2 pos = getPosition(i, t) + mixerGrain;
69
108
  vec3 colorFraction = u_colors[i].rgb * u_colors[i].a;
70
109
  float opacityFraction = u_colors[i].a;
71
110
 
@@ -81,8 +120,12 @@ void main() {
81
120
  color /= totalWeight;
82
121
  opacity /= totalWeight;
83
122
 
84
- ${colorBandingFix}
85
-
123
+ float rr = noise(rotate(grainUV, 1.), vec2(3.));
124
+ float gg = noise(rotate(grainUV, 2.) + 10., vec2(-1.));
125
+ float bb = noise(grainUV - 2., vec2(5.));
126
+ vec3 grainColor = vec3(rr, gg, bb);
127
+ color = mix(color, grainColor, .01 + .3 * u_grainOverlay);
128
+
86
129
  fragColor = vec4(color, opacity);
87
130
  }
88
131
  `;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/shaders/mesh-gradient.ts"],
4
- "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport { sizingVariablesDeclaration, type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { declarePI, rotation2, colorBandingFix } from '../shader-utils.js';\n\nexport const meshGradientMeta = {\n maxColorCount: 10,\n} as const;\n\n/**\n * A composition of N color spots (one per color) with 2 types of\n * distortions applied to the coordinate space\n *\n * Uniforms:\n * - u_colors (vec4[]), u_colorsCount (float used as integer)\n * - u_distortion: warp distortion\n * - u_swirl: vortex distortion\n *\n */\n\n// language=GLSL\nexport const meshGradientFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform float u_time;\n\nuniform vec4 u_colors[${meshGradientMeta.maxColorCount}];\nuniform float u_colorsCount;\n\nuniform float u_distortion;\nuniform float u_swirl;\n\n${sizingVariablesDeclaration}\n\nout vec4 fragColor;\n\n${declarePI}\n${rotation2}\n\nvec2 getPosition(int i, float t) {\n float a = float(i) * .37;\n float b = .6 + mod(float(i), 3.) * .3;\n float c = .8 + mod(float(i + 1), 4.) * 0.25;\n\n float x = sin(t * b + a);\n float y = cos(t * c + a * 1.5);\n\n return .5 + .5 * vec2(x, y);\n}\n\nvoid main() {\n vec2 shape_uv = v_objectUV;\n\n shape_uv += .5;\n\n const float firstFrameOffset = 41.5;\n float t = .5 * (u_time + firstFrameOffset);\n\n float radius = smoothstep(0., 1., length(shape_uv - .5));\n float center = 1. - radius;\n for (float i = 1.; i <= 2.; i++) {\n shape_uv.x += u_distortion * center / i * sin(t + i * .4 * smoothstep(.0, 1., shape_uv.y)) * cos(.2 * t + i * 2.4 * smoothstep(.0, 1., shape_uv.y));\n shape_uv.y += u_distortion * center / i * cos(t + i * 2. * smoothstep(.0, 1., shape_uv.x));\n }\n\n vec2 uvRotated = shape_uv;\n uvRotated -= vec2(.5);\n float angle = 3. * u_swirl * radius;\n uvRotated = rotate(uvRotated, -angle);\n uvRotated += vec2(.5);\n\n vec3 color = vec3(0.);\n float opacity = 0.;\n float totalWeight = 0.;\n\n for (int i = 0; i < ${meshGradientMeta.maxColorCount}; i++) {\n if (i >= int(u_colorsCount)) break;\n\n vec2 pos = getPosition(i, t);\n vec3 colorFraction = u_colors[i].rgb * u_colors[i].a;\n float opacityFraction = u_colors[i].a;\n\n float dist = length(uvRotated - pos);\n\n dist = pow(dist, 3.5);\n float weight = 1. / (dist + 1e-3);\n color += colorFraction * weight;\n opacity += opacityFraction * weight;\n totalWeight += weight;\n }\n\n color /= totalWeight;\n opacity /= totalWeight;\n\n ${colorBandingFix}\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface MeshGradientUniforms extends ShaderSizingUniforms {\n u_colors: vec4[];\n u_colorsCount: number;\n u_distortion: number;\n u_swirl: number;\n}\n\nexport interface MeshGradientParams extends ShaderSizingParams, ShaderMotionParams {\n colors?: string[];\n distortion?: number;\n swirl?: number;\n}\n"],
5
- "mappings": ";;;;;AAEA,SAAS,kCAAsF;AAC/F,SAAS,WAAW,WAAW,uBAAuB;AAE/C,MAAM,mBAAmB;AAAA,EAC9B,eAAe;AACjB;AAcO,MAAM,6BAAqC;AAAA;AAAA;AAAA;AAAA;AAAA,wBAK1B,iBAAiB,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMpD,0BAA0B;AAAA;AAAA;AAAA;AAAA,EAI1B,SAAS;AAAA,EACT,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAsCa,iBAAiB,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAmBlD,eAAe;AAAA;AAAA;AAAA;AAAA;",
4
+ "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport {\n sizingDebugVariablesDeclaration,\n sizingVariablesDeclaration,\n sizingUniformsDeclaration,\n type ShaderSizingParams,\n type ShaderSizingUniforms,\n} from '../shader-sizing.js';\nimport { declarePI, rotation2, proceduralHash21 } from '../shader-utils.js';\n\nexport const meshGradientMeta = {\n maxColorCount: 10,\n} as const;\n\n/**\n * A composition of N color spots (one per color) with 2 types of\n * distortions applied to the coordinate space\n *\n * Uniforms:\n * - u_colors (vec4[]), u_colorsCount (float used as integer)\n * - u_distortion: warp distortion\n * - u_swirl: vortex distortion\n * - u_grainMixer: shape distortion\n * - u_grainOverlay: post-processing blending\n */\n\n// language=GLSL\nexport const meshGradientFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform float u_time;\n\nuniform vec4 u_colors[${meshGradientMeta.maxColorCount}];\nuniform float u_colorsCount;\n\nuniform float u_distortion;\nuniform float u_swirl;\nuniform float u_grainMixer;\nuniform float u_grainOverlay;\n\n${sizingVariablesDeclaration}\n${sizingDebugVariablesDeclaration}\n${sizingUniformsDeclaration}\n\nout vec4 fragColor;\n\n${declarePI}\n${rotation2}\n${proceduralHash21}\n\nfloat valueNoise(vec2 st) {\n vec2 i = floor(st);\n vec2 f = fract(st);\n float a = hash21(i);\n float b = hash21(i + vec2(1.0, 0.0));\n float c = hash21(i + vec2(0.0, 1.0));\n float d = hash21(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}\n\nfloat noise(vec2 n, vec2 seedOffset) {\n return valueNoise(n + seedOffset);\n}\n\nvec2 getPosition(int i, float t) {\n float a = float(i) * .37;\n float b = .6 + mod(float(i), 3.) * .3;\n float c = .8 + mod(float(i + 1), 4.) * 0.25;\n\n float x = sin(t * b + a);\n float y = cos(t * c + a * 1.5);\n\n return .5 + .5 * vec2(x, y);\n}\n\nvoid main() {\n vec2 shape_uv = v_objectUV;\n shape_uv += .5;\n\n vec2 grainUV = v_objectUV;\n // apply inverse transform to grain_uv so it respects the originXY\n float grainUVRot = u_rotation * 3.14159265358979323846 / 180.;\n mat2 graphicRotation = mat2(cos(grainUVRot), sin(grainUVRot), -sin(grainUVRot), cos(grainUVRot));\n vec2 graphicOffset = vec2(-u_offsetX, u_offsetY);\n grainUV = transpose(graphicRotation) * grainUV;\n grainUV *= u_scale;\n grainUV *= .7;\n grainUV -= graphicOffset;\n grainUV *= v_objectBoxSize;\n \n float grain = noise(grainUV, vec2(0.));\n float mixerGrain = .4 * u_grainMixer * (grain - .5);\n\n const float firstFrameOffset = 41.5;\n float t = .5 * (u_time + firstFrameOffset);\n\n float radius = smoothstep(0., 1., length(shape_uv - .5));\n float center = 1. - radius;\n for (float i = 1.; i <= 2.; i++) {\n shape_uv.x += u_distortion * center / i * sin(t + i * .4 * smoothstep(.0, 1., shape_uv.y)) * cos(.2 * t + i * 2.4 * smoothstep(.0, 1., shape_uv.y));\n shape_uv.y += u_distortion * center / i * cos(t + i * 2. * smoothstep(.0, 1., shape_uv.x));\n }\n\n vec2 uvRotated = shape_uv;\n uvRotated -= vec2(.5);\n float angle = 3. * u_swirl * radius;\n uvRotated = rotate(uvRotated, -angle);\n uvRotated += vec2(.5);\n\n vec3 color = vec3(0.);\n float opacity = 0.;\n float totalWeight = 0.;\n\n for (int i = 0; i < ${meshGradientMeta.maxColorCount}; i++) {\n if (i >= int(u_colorsCount)) break;\n\n vec2 pos = getPosition(i, t) + mixerGrain;\n vec3 colorFraction = u_colors[i].rgb * u_colors[i].a;\n float opacityFraction = u_colors[i].a;\n\n float dist = length(uvRotated - pos);\n\n dist = pow(dist, 3.5);\n float weight = 1. / (dist + 1e-3);\n color += colorFraction * weight;\n opacity += opacityFraction * weight;\n totalWeight += weight;\n }\n\n color /= totalWeight;\n opacity /= totalWeight;\n\n float rr = noise(rotate(grainUV, 1.), vec2(3.));\n float gg = noise(rotate(grainUV, 2.) + 10., vec2(-1.));\n float bb = noise(grainUV - 2., vec2(5.));\n vec3 grainColor = vec3(rr, gg, bb);\n color = mix(color, grainColor, .01 + .3 * u_grainOverlay);\n \n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface MeshGradientUniforms extends ShaderSizingUniforms {\n u_colors: vec4[];\n u_colorsCount: number;\n u_distortion: number;\n u_swirl: number;\n u_grainMixer: number;\n u_grainOverlay: number;\n}\n\nexport interface MeshGradientParams extends ShaderSizingParams, ShaderMotionParams {\n colors?: string[];\n distortion?: number;\n swirl?: number;\n grainMixer?: number;\n grainOverlay?: number;\n}\n"],
5
+ "mappings": ";;;;;AAEA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AACP,SAAS,WAAW,WAAW,wBAAwB;AAEhD,MAAM,mBAAmB;AAAA,EAC9B,eAAe;AACjB;AAeO,MAAM,6BAAqC;AAAA;AAAA;AAAA;AAAA;AAAA,wBAK1B,iBAAiB,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQpD,0BAA0B;AAAA,EAC1B,+BAA+B;AAAA,EAC/B,yBAAyB;AAAA;AAAA;AAAA;AAAA,EAIzB,SAAS;AAAA,EACT,SAAS;AAAA,EACT,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAoEM,iBAAiB,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;",
6
6
  "names": []
7
7
  }
@@ -7,12 +7,12 @@ import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-si
7
7
  * - u_colorFront, u_colorBack (RGBA)
8
8
  * - u_contrast - mixing front and back colors
9
9
  * - u_roughness - pixel noise, related to canvas => not scalable
10
- * - u_fiber, u_fiberScale - curly shaped noise
11
- * - u_crumples, u_crumplesScale - cell-based pattern
12
- * - u_folds, u_foldsNumber - lines pattern, 15 max
10
+ * - u_fiber, u_fiberSize - curly shaped noise
11
+ * - u_crumples, u_crumpleSize - cell-based pattern
12
+ * - u_folds, u_foldCount - lines pattern, 15 max
13
13
  * - u_drops - metaballs-like pattern
14
14
  * - u_seed - applied to folds, crumples and dots
15
- * - u_blur - big-scale noise mask applied to everything but roughness
15
+ * - u_fade - big-scale noise mask applied to everything but roughness
16
16
  *
17
17
  * - u_noiseTexture (sampler2D): pre-computed randomizer source
18
18
  *
@@ -26,28 +26,28 @@ export interface PaperTextureUniforms extends ShaderSizingUniforms {
26
26
  u_contrast: number;
27
27
  u_roughness: number;
28
28
  u_fiber: number;
29
- u_fiberScale: number;
29
+ u_fiberSize: number;
30
30
  u_crumples: number;
31
- u_foldsNumber: number;
31
+ u_foldCount: number;
32
32
  u_folds: number;
33
- u_blur: number;
34
- u_crumplesScale: number;
33
+ u_fade: number;
34
+ u_crumpleSize: number;
35
35
  u_drops: number;
36
36
  u_seed: number;
37
37
  }
38
38
  export interface PaperTextureParams extends ShaderSizingParams, ShaderMotionParams {
39
- image?: HTMLImageElement | string | undefined;
39
+ image?: HTMLImageElement | string;
40
40
  colorFront?: string;
41
41
  colorBack?: string;
42
42
  contrast?: number;
43
43
  roughness?: number;
44
44
  fiber?: number;
45
- fiberScale?: number;
45
+ fiberSize?: number;
46
46
  crumples?: number;
47
- foldsNumber?: number;
47
+ foldCount?: number;
48
48
  folds?: number;
49
- blur?: number;
50
- crumplesScale?: number;
49
+ fade?: number;
50
+ crumpleSize?: number;
51
51
  drops?: number;
52
52
  seed?: number;
53
53
  }
@@ -20,14 +20,14 @@ uniform float u_imageAspectRatio;
20
20
  uniform float u_contrast;
21
21
  uniform float u_roughness;
22
22
  uniform float u_fiber;
23
- uniform float u_fiberScale;
23
+ uniform float u_fiberSize;
24
24
  uniform float u_crumples;
25
- uniform float u_crumplesScale;
25
+ uniform float u_crumpleSize;
26
26
  uniform float u_folds;
27
- uniform float u_foldsNumber;
27
+ uniform float u_foldCount;
28
28
  uniform float u_drops;
29
29
  uniform float u_seed;
30
- uniform float u_blur;
30
+ uniform float u_fade;
31
31
 
32
32
  uniform sampler2D u_noiseTexture;
33
33
 
@@ -125,13 +125,13 @@ vec2 folds(vec2 uv) {
125
125
  vec3 pp = vec3(0.);
126
126
  float l = 9.;
127
127
  for (float i = 0.; i < 15.; i++) {
128
- if (i >= u_foldsNumber) break;
128
+ if (i >= u_foldCount) break;
129
129
  vec2 rand = randomGB(vec2(i, i * u_seed));
130
130
  float an = rand.x * TWO_PI;
131
131
  vec2 p = vec2(cos(an), sin(an)) * rand.y;
132
132
  float dist = distance(uv, p);
133
133
  l = min(l, dist);
134
-
134
+
135
135
  if (l == dist) {
136
136
  pp.xy = (uv - p.xy);
137
137
  pp.z = dist;
@@ -157,6 +157,10 @@ float drops(vec2 uv) {
157
157
  return 1. - smoothstep(.05, .09, pow(dropsMinDist, .5));
158
158
  }
159
159
 
160
+ float lst(float edge0, float edge1, float x) {
161
+ return clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
162
+ }
163
+
160
164
  void main() {
161
165
 
162
166
  vec2 imageUV = v_imageUV;
@@ -166,10 +170,10 @@ void main() {
166
170
  vec2 roughnessUv = 1.5 * (gl_FragCoord.xy - .5 * u_resolution) / u_pixelRatio;
167
171
  float roughness = roughness(roughnessUv + vec2(1., 0.)) - roughness(roughnessUv - vec2(1., 0.));
168
172
 
169
- vec2 crumplesUV = fract(patternUV * .1 * u_crumplesScale - u_seed) * 32.;
173
+ vec2 crumplesUV = fract(patternUV * .02 / u_crumpleSize - u_seed) * 32.;
170
174
  float crumples = u_crumples * (crumplesShape(crumplesUV + vec2(.05, 0.)) - crumplesShape(crumplesUV));
171
175
 
172
- vec2 fiberUV = 10. * u_fiberScale * patternUV;
176
+ vec2 fiberUV = 2. / u_fiberSize * patternUV;
173
177
  float fiber = fiberNoise(fiberUV, vec2(0.));
174
178
  fiber = .5 * u_fiber * (fiber - 1.);
175
179
 
@@ -183,7 +187,17 @@ void main() {
183
187
  vec2 w2 = folds(foldsUV);
184
188
 
185
189
  float drops = u_drops * drops(patternUV * 2.);
186
-
190
+
191
+ float fade = u_fade * fbm(.17 * patternUV + 10. * u_seed);
192
+ fade = clamp(8. * pow(fade, 3.), 0., 1.);
193
+
194
+ w = mix(w, vec2(0.), fade);
195
+ w2 = mix(w2, vec2(0.), fade);
196
+ crumples = mix(crumples, 0., fade);
197
+ drops = mix(drops, 0., fade);
198
+ fiber *= mix(1., .5, fade);
199
+ roughness *= mix(1., .5, fade);
200
+
187
201
  normal.xy += u_folds * min(5. * u_contrast, 1.) * 4. * max(vec2(0.), w + w2);
188
202
  normalImage.xy += u_folds * 2. * w;
189
203
 
@@ -193,13 +207,9 @@ void main() {
193
207
  normal.xy += 3. * drops;
194
208
  normalImage.xy += .2 * drops;
195
209
 
196
- float blur = u_blur * smoothstep(0., 1., fbm(.17 * patternUV + 10. * u_seed));
197
- normal *= (1. - 2. * blur);
198
- fiber *= (1. - blur);
199
-
200
210
  normal.xy += u_roughness * 1.5 * roughness;
201
211
  normal.xy += fiber;
202
-
212
+
203
213
  normalImage += u_roughness * .75 * roughness;
204
214
  normalImage += .2 * fiber;
205
215
 
@@ -215,7 +225,7 @@ void main() {
215
225
  float frame = getUvFrame(imageUV);
216
226
  vec4 image = texture(u_image, imageUV);
217
227
  image.rgb += .6 * pow(u_contrast, .4) * (res - .7);
218
-
228
+
219
229
  frame *= image.a;
220
230
 
221
231
  vec3 color = fgColor * res;
@@ -224,7 +234,7 @@ void main() {
224
234
  color += bgColor * (1. - opacity);
225
235
  opacity += bgOpacity * (1. - opacity);
226
236
  opacity = mix(opacity, 1., frame);
227
-
237
+
228
238
  color -= .007 * drops;
229
239
 
230
240
  color.rgb = mix(color, image.rgb, frame);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/shaders/paper-texture.ts"],
4
- "sourcesContent": ["import type { ShaderMotionParams } from '../shader-mount.js';\nimport { sizingVariablesDeclaration, type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { rotation2, declarePI, fiberNoise, textureRandomizerR } from '../shader-utils.js';\n\n/**\n * Mimicking paper texture with a combination of noises\n *\n * Uniforms:\n * - u_colorFront, u_colorBack (RGBA)\n * - u_contrast - mixing front and back colors\n * - u_roughness - pixel noise, related to canvas => not scalable\n * - u_fiber, u_fiberScale - curly shaped noise\n * - u_crumples, u_crumplesScale - cell-based pattern\n * - u_folds, u_foldsNumber - lines pattern, 15 max\n * - u_drops - metaballs-like pattern\n * - u_seed - applied to folds, crumples and dots\n * - u_blur - big-scale noise mask applied to everything but roughness\n *\n * - u_noiseTexture (sampler2D): pre-computed randomizer source\n *\n */\n\n// language=GLSL\nexport const paperTextureFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform vec2 u_resolution;\nuniform float u_pixelRatio;\n\nuniform vec4 u_colorFront;\nuniform vec4 u_colorBack;\n\nuniform sampler2D u_image;\nuniform float u_imageAspectRatio;\n\nuniform float u_contrast;\nuniform float u_roughness;\nuniform float u_fiber;\nuniform float u_fiberScale;\nuniform float u_crumples;\nuniform float u_crumplesScale;\nuniform float u_folds;\nuniform float u_foldsNumber;\nuniform float u_drops;\nuniform float u_seed;\nuniform float u_blur;\n\nuniform sampler2D u_noiseTexture;\n\n${sizingVariablesDeclaration}\n\nout vec4 fragColor;\n\nfloat getUvFrame(vec2 uv) {\n float aax = 2. * fwidth(uv.x);\n float aay = 2. * fwidth(uv.y);\n\n float left = smoothstep(0., aax, uv.x);\n float right = smoothstep(1., 1. - aax, uv.x);\n float bottom = smoothstep(0., aay, uv.y);\n float top = smoothstep(1., 1. - aay, uv.y);\n\n return left * right * bottom * top;\n}\n\n${declarePI}\n${rotation2}\n${textureRandomizerR}\nfloat valueNoise(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 fbm(vec2 n) {\n float total = 0.0, amplitude = .4;\n for (int i = 0; i < 3; i++) {\n total += valueNoise(n) * amplitude;\n n *= 1.99;\n amplitude *= 0.65;\n }\n return total;\n}\n\n\nfloat randomG(vec2 p) {\n vec2 uv = floor(p) / 50. + .5;\n return texture(u_noiseTexture, fract(uv)).g;\n}\nfloat roughness(vec2 p) {\n p *= .1;\n float o = 0.;\n for (float i = 0.; ++i < 4.; p *= 2.1) {\n vec4 w = vec4(floor(p), ceil(p));\n vec2 f = fract(p);\n o += mix(\n mix(randomG(w.xy), randomG(w.xw), f.y),\n mix(randomG(w.zy), randomG(w.zw), f.y),\n f.x);\n o += .2 / exp(2. * abs(sin(.2 * p.x + .5 * p.y)));\n }\n return o / 3.;\n}\n\n${fiberNoise}\n\nvec2 randomGB(vec2 p) {\n vec2 uv = floor(p) / 50. + .5;\n return texture(u_noiseTexture, fract(uv)).gb;\n}\nfloat crumpledNoise(vec2 t, float pw) {\n vec2 p = floor(t);\n float wsum = 0.;\n float cl = 0.;\n for (int y = -1; y < 2; y += 1) {\n for (int x = -1; x < 2; x += 1) {\n vec2 b = vec2(float(x), float(y));\n vec2 q = b + p;\n vec2 q2 = q - floor(q / 8.) * 8.;\n vec2 c = q + randomGB(q2);\n vec2 r = c - t;\n float w = pow(smoothstep(0., 1., 1. - abs(r.x)), pw) * pow(smoothstep(0., 1., 1. - abs(r.y)), pw);\n cl += (.5 + .5 * sin((q2.x + q2.y * 5.) * 8.)) * w;\n wsum += w;\n }\n }\n return pow(cl / wsum, .5) * 2.;\n}\nfloat crumplesShape(vec2 uv) {\n return crumpledNoise(uv * .25, 16.) * crumpledNoise(uv * .5, 2.);\n}\n\n\nvec2 folds(vec2 uv) {\n vec3 pp = vec3(0.);\n float l = 9.;\n for (float i = 0.; i < 15.; i++) {\n if (i >= u_foldsNumber) break;\n vec2 rand = randomGB(vec2(i, i * u_seed));\n float an = rand.x * TWO_PI;\n vec2 p = vec2(cos(an), sin(an)) * rand.y;\n float dist = distance(uv, p);\n l = min(l, dist);\n \n if (l == dist) {\n pp.xy = (uv - p.xy);\n pp.z = dist;\n }\n }\n return mix(pp.xy, vec2(0.), pow(pp.z, .25));\n}\n\nfloat drops(vec2 uv) {\n vec2 iDropsUV = floor(uv);\n vec2 fDropsUV = fract(uv);\n float dropsMinDist = 1.;\n for (int j = -1; j <= 1; j++) {\n for (int i = -1; i <= 1; i++) {\n vec2 neighbor = vec2(float(i), float(j));\n vec2 offset = randomGB(iDropsUV + neighbor);\n offset = .5 + .5 * sin(10. * u_seed + TWO_PI * offset);\n vec2 pos = neighbor + offset - fDropsUV;\n float dist = length(pos);\n dropsMinDist = min(dropsMinDist, dropsMinDist*dist);\n }\n }\n return 1. - smoothstep(.05, .09, pow(dropsMinDist, .5));\n}\n\nvoid main() {\n\n vec2 imageUV = v_imageUV;\n vec2 patternUV = v_imageUV - .5;\n patternUV = 5. * (patternUV * vec2(u_imageAspectRatio, 1.));\n\n vec2 roughnessUv = 1.5 * (gl_FragCoord.xy - .5 * u_resolution) / u_pixelRatio;\n float roughness = roughness(roughnessUv + vec2(1., 0.)) - roughness(roughnessUv - vec2(1., 0.));\n\n vec2 crumplesUV = fract(patternUV * .1 * u_crumplesScale - u_seed) * 32.;\n float crumples = u_crumples * (crumplesShape(crumplesUV + vec2(.05, 0.)) - crumplesShape(crumplesUV));\n\n vec2 fiberUV = 10. * u_fiberScale * patternUV;\n float fiber = fiberNoise(fiberUV, vec2(0.));\n fiber = .5 * u_fiber * (fiber - 1.);\n\n vec2 normal = vec2(0.);\n vec2 normalImage = vec2(0.);\n\n vec2 foldsUV = patternUV * .12;\n foldsUV = rotate(foldsUV, 4. * u_seed);\n vec2 w = folds(foldsUV);\n foldsUV = rotate(foldsUV + .007 * cos(u_seed), .01 * sin(u_seed));\n vec2 w2 = folds(foldsUV);\n\n float drops = u_drops * drops(patternUV * 2.);\n \n normal.xy += u_folds * min(5. * u_contrast, 1.) * 4. * max(vec2(0.), w + w2);\n normalImage.xy += u_folds * 2. * w;\n\n normal.xy += crumples;\n normalImage.xy += 1.5 * crumples;\n\n normal.xy += 3. * drops;\n normalImage.xy += .2 * drops;\n\n float blur = u_blur * smoothstep(0., 1., fbm(.17 * patternUV + 10. * u_seed));\n normal *= (1. - 2. * blur);\n fiber *= (1. - blur);\n\n normal.xy += u_roughness * 1.5 * roughness;\n normal.xy += fiber;\n \n normalImage += u_roughness * .75 * roughness;\n normalImage += .2 * fiber;\n\n vec3 lightPos = vec3(1., 2., 1.);\n float res = dot(normalize(vec3(normal, 9.5 - 9. * pow(u_contrast, .1))), normalize(lightPos));\n\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\n imageUV += .02 * normalImage;\n float frame = getUvFrame(imageUV);\n vec4 image = texture(u_image, imageUV);\n image.rgb += .6 * pow(u_contrast, .4) * (res - .7);\n \n frame *= image.a;\n\n vec3 color = fgColor * res;\n float opacity = fgOpacity * res;\n\n color += bgColor * (1. - opacity);\n opacity += bgOpacity * (1. - opacity);\n opacity = mix(opacity, 1., frame);\n \n color -= .007 * drops;\n\n color.rgb = mix(color, image.rgb, frame);\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface PaperTextureUniforms extends ShaderSizingUniforms {\n u_image: HTMLImageElement | string | undefined;\n u_noiseTexture?: HTMLImageElement;\n u_colorFront: [number, number, number, number];\n u_colorBack: [number, number, number, number];\n u_contrast: number;\n u_roughness: number;\n u_fiber: number;\n u_fiberScale: number;\n u_crumples: number;\n u_foldsNumber: number;\n u_folds: number;\n u_blur: number;\n u_crumplesScale: number;\n u_drops: number;\n u_seed: number;\n}\n\nexport interface PaperTextureParams extends ShaderSizingParams, ShaderMotionParams {\n image?: HTMLImageElement | string | undefined;\n colorFront?: string;\n colorBack?: string;\n contrast?: number;\n roughness?: number;\n fiber?: number;\n fiberScale?: number;\n crumples?: number;\n foldsNumber?: number;\n folds?: number;\n blur?: number;\n crumplesScale?: number;\n drops?: number;\n seed?: number;\n}\n"],
5
- "mappings": ";;;;;AACA,SAAS,kCAAsF;AAC/F,SAAS,WAAW,WAAW,YAAY,0BAA0B;AAqB9D,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,EA0BhD,0BAA0B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgB1B,SAAS;AAAA,EACT,SAAS;AAAA,EACT,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA2ClB,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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 { sizingVariablesDeclaration, type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { rotation2, declarePI, fiberNoise, textureRandomizerR } from '../shader-utils.js';\n\n/**\n * Mimicking paper texture with a combination of noises\n *\n * Uniforms:\n * - u_colorFront, u_colorBack (RGBA)\n * - u_contrast - mixing front and back colors\n * - u_roughness - pixel noise, related to canvas => not scalable\n * - u_fiber, u_fiberSize - curly shaped noise\n * - u_crumples, u_crumpleSize - cell-based pattern\n * - u_folds, u_foldCount - lines pattern, 15 max\n * - u_drops - metaballs-like pattern\n * - u_seed - applied to folds, crumples and dots\n * - u_fade - big-scale noise mask applied to everything but roughness\n *\n * - u_noiseTexture (sampler2D): pre-computed randomizer source\n *\n */\n\n// language=GLSL\nexport const paperTextureFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform vec2 u_resolution;\nuniform float u_pixelRatio;\n\nuniform vec4 u_colorFront;\nuniform vec4 u_colorBack;\n\nuniform sampler2D u_image;\nuniform float u_imageAspectRatio;\n\nuniform float u_contrast;\nuniform float u_roughness;\nuniform float u_fiber;\nuniform float u_fiberSize;\nuniform float u_crumples;\nuniform float u_crumpleSize;\nuniform float u_folds;\nuniform float u_foldCount;\nuniform float u_drops;\nuniform float u_seed;\nuniform float u_fade;\n\nuniform sampler2D u_noiseTexture;\n\n${sizingVariablesDeclaration}\n\nout vec4 fragColor;\n\nfloat getUvFrame(vec2 uv) {\n float aax = 2. * fwidth(uv.x);\n float aay = 2. * fwidth(uv.y);\n\n float left = smoothstep(0., aax, uv.x);\n float right = smoothstep(1., 1. - aax, uv.x);\n float bottom = smoothstep(0., aay, uv.y);\n float top = smoothstep(1., 1. - aay, uv.y);\n\n return left * right * bottom * top;\n}\n\n${declarePI}\n${rotation2}\n${textureRandomizerR}\nfloat valueNoise(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 fbm(vec2 n) {\n float total = 0.0, amplitude = .4;\n for (int i = 0; i < 3; i++) {\n total += valueNoise(n) * amplitude;\n n *= 1.99;\n amplitude *= 0.65;\n }\n return total;\n}\n\n\nfloat randomG(vec2 p) {\n vec2 uv = floor(p) / 50. + .5;\n return texture(u_noiseTexture, fract(uv)).g;\n}\nfloat roughness(vec2 p) {\n p *= .1;\n float o = 0.;\n for (float i = 0.; ++i < 4.; p *= 2.1) {\n vec4 w = vec4(floor(p), ceil(p));\n vec2 f = fract(p);\n o += mix(\n mix(randomG(w.xy), randomG(w.xw), f.y),\n mix(randomG(w.zy), randomG(w.zw), f.y),\n f.x);\n o += .2 / exp(2. * abs(sin(.2 * p.x + .5 * p.y)));\n }\n return o / 3.;\n}\n\n${fiberNoise}\n\nvec2 randomGB(vec2 p) {\n vec2 uv = floor(p) / 50. + .5;\n return texture(u_noiseTexture, fract(uv)).gb;\n}\nfloat crumpledNoise(vec2 t, float pw) {\n vec2 p = floor(t);\n float wsum = 0.;\n float cl = 0.;\n for (int y = -1; y < 2; y += 1) {\n for (int x = -1; x < 2; x += 1) {\n vec2 b = vec2(float(x), float(y));\n vec2 q = b + p;\n vec2 q2 = q - floor(q / 8.) * 8.;\n vec2 c = q + randomGB(q2);\n vec2 r = c - t;\n float w = pow(smoothstep(0., 1., 1. - abs(r.x)), pw) * pow(smoothstep(0., 1., 1. - abs(r.y)), pw);\n cl += (.5 + .5 * sin((q2.x + q2.y * 5.) * 8.)) * w;\n wsum += w;\n }\n }\n return pow(cl / wsum, .5) * 2.;\n}\nfloat crumplesShape(vec2 uv) {\n return crumpledNoise(uv * .25, 16.) * crumpledNoise(uv * .5, 2.);\n}\n\n\nvec2 folds(vec2 uv) {\n vec3 pp = vec3(0.);\n float l = 9.;\n for (float i = 0.; i < 15.; i++) {\n if (i >= u_foldCount) break;\n vec2 rand = randomGB(vec2(i, i * u_seed));\n float an = rand.x * TWO_PI;\n vec2 p = vec2(cos(an), sin(an)) * rand.y;\n float dist = distance(uv, p);\n l = min(l, dist);\n\n if (l == dist) {\n pp.xy = (uv - p.xy);\n pp.z = dist;\n }\n }\n return mix(pp.xy, vec2(0.), pow(pp.z, .25));\n}\n\nfloat drops(vec2 uv) {\n vec2 iDropsUV = floor(uv);\n vec2 fDropsUV = fract(uv);\n float dropsMinDist = 1.;\n for (int j = -1; j <= 1; j++) {\n for (int i = -1; i <= 1; i++) {\n vec2 neighbor = vec2(float(i), float(j));\n vec2 offset = randomGB(iDropsUV + neighbor);\n offset = .5 + .5 * sin(10. * u_seed + TWO_PI * offset);\n vec2 pos = neighbor + offset - fDropsUV;\n float dist = length(pos);\n dropsMinDist = min(dropsMinDist, dropsMinDist*dist);\n }\n }\n return 1. - smoothstep(.05, .09, pow(dropsMinDist, .5));\n}\n\nfloat lst(float edge0, float edge1, float x) {\n return clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);\n}\n\nvoid main() {\n\n vec2 imageUV = v_imageUV;\n vec2 patternUV = v_imageUV - .5;\n patternUV = 5. * (patternUV * vec2(u_imageAspectRatio, 1.));\n\n vec2 roughnessUv = 1.5 * (gl_FragCoord.xy - .5 * u_resolution) / u_pixelRatio;\n float roughness = roughness(roughnessUv + vec2(1., 0.)) - roughness(roughnessUv - vec2(1., 0.));\n\n vec2 crumplesUV = fract(patternUV * .02 / u_crumpleSize - u_seed) * 32.;\n float crumples = u_crumples * (crumplesShape(crumplesUV + vec2(.05, 0.)) - crumplesShape(crumplesUV));\n\n vec2 fiberUV = 2. / u_fiberSize * patternUV;\n float fiber = fiberNoise(fiberUV, vec2(0.));\n fiber = .5 * u_fiber * (fiber - 1.);\n\n vec2 normal = vec2(0.);\n vec2 normalImage = vec2(0.);\n\n vec2 foldsUV = patternUV * .12;\n foldsUV = rotate(foldsUV, 4. * u_seed);\n vec2 w = folds(foldsUV);\n foldsUV = rotate(foldsUV + .007 * cos(u_seed), .01 * sin(u_seed));\n vec2 w2 = folds(foldsUV);\n\n float drops = u_drops * drops(patternUV * 2.);\n\n float fade = u_fade * fbm(.17 * patternUV + 10. * u_seed);\n fade = clamp(8. * pow(fade, 3.), 0., 1.);\n\n w = mix(w, vec2(0.), fade);\n w2 = mix(w2, vec2(0.), fade);\n crumples = mix(crumples, 0., fade);\n drops = mix(drops, 0., fade);\n fiber *= mix(1., .5, fade);\n roughness *= mix(1., .5, fade);\n\n normal.xy += u_folds * min(5. * u_contrast, 1.) * 4. * max(vec2(0.), w + w2);\n normalImage.xy += u_folds * 2. * w;\n\n normal.xy += crumples;\n normalImage.xy += 1.5 * crumples;\n\n normal.xy += 3. * drops;\n normalImage.xy += .2 * drops;\n\n normal.xy += u_roughness * 1.5 * roughness;\n normal.xy += fiber;\n\n normalImage += u_roughness * .75 * roughness;\n normalImage += .2 * fiber;\n\n vec3 lightPos = vec3(1., 2., 1.);\n float res = dot(normalize(vec3(normal, 9.5 - 9. * pow(u_contrast, .1))), normalize(lightPos));\n\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\n imageUV += .02 * normalImage;\n float frame = getUvFrame(imageUV);\n vec4 image = texture(u_image, imageUV);\n image.rgb += .6 * pow(u_contrast, .4) * (res - .7);\n\n frame *= image.a;\n\n vec3 color = fgColor * res;\n float opacity = fgOpacity * res;\n\n color += bgColor * (1. - opacity);\n opacity += bgOpacity * (1. - opacity);\n opacity = mix(opacity, 1., frame);\n\n color -= .007 * drops;\n\n color.rgb = mix(color, image.rgb, frame);\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface PaperTextureUniforms extends ShaderSizingUniforms {\n u_image: HTMLImageElement | string | undefined;\n u_noiseTexture?: HTMLImageElement;\n u_colorFront: [number, number, number, number];\n u_colorBack: [number, number, number, number];\n u_contrast: number;\n u_roughness: number;\n u_fiber: number;\n u_fiberSize: number;\n u_crumples: number;\n u_foldCount: number;\n u_folds: number;\n u_fade: number;\n u_crumpleSize: number;\n u_drops: number;\n u_seed: number;\n}\n\nexport interface PaperTextureParams extends ShaderSizingParams, ShaderMotionParams {\n image?: HTMLImageElement | string;\n colorFront?: string;\n colorBack?: string;\n contrast?: number;\n roughness?: number;\n fiber?: number;\n fiberSize?: number;\n crumples?: number;\n foldCount?: number;\n folds?: number;\n fade?: number;\n crumpleSize?: number;\n drops?: number;\n seed?: number;\n}\n"],
5
+ "mappings": ";;;;;AACA,SAAS,kCAAsF;AAC/F,SAAS,WAAW,WAAW,YAAY,0BAA0B;AAqB9D,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,EA0BhD,0BAA0B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgB1B,SAAS;AAAA,EACT,SAAS;AAAA,EACT,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA2ClB,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;",
6
6
  "names": []
7
7
  }
@@ -12,6 +12,7 @@ export declare const pulsingBorderMeta: {
12
12
  * - u_colorBack (RGBA)
13
13
  * - u_colors (vec4[]), u_colorsCount (float used as integer)
14
14
  * - u_roundness, u_thickness, u_softness: border parameters
15
+ * - u_aspectRatio
15
16
  * - u_intensity: thickness of individual spots
16
17
  * - u_bloom: normal / additive color blending
17
18
  * - u_spotSize: angular size of spots
@@ -29,6 +30,11 @@ export interface PulsingBorderUniforms extends ShaderSizingUniforms {
29
30
  u_colorsCount: number;
30
31
  u_roundness: number;
31
32
  u_thickness: number;
33
+ u_marginLeft: number;
34
+ u_marginRight: number;
35
+ u_marginTop: number;
36
+ u_marginBottom: number;
37
+ u_aspectRatio: (typeof PulsingBorderAspectRatios)[PulsingBorderAspectRatio];
32
38
  u_softness: number;
33
39
  u_intensity: number;
34
40
  u_bloom: number;
@@ -44,6 +50,12 @@ export interface PulsingBorderParams extends ShaderSizingParams, ShaderMotionPar
44
50
  colors?: string[];
45
51
  roundness?: number;
46
52
  thickness?: number;
53
+ margin?: number;
54
+ marginLeft?: number;
55
+ marginRight?: number;
56
+ marginTop?: number;
57
+ marginBottom?: number;
58
+ aspectRatio?: PulsingBorderAspectRatio;
47
59
  softness?: number;
48
60
  intensity?: number;
49
61
  bloom?: number;
@@ -53,3 +65,8 @@ export interface PulsingBorderParams extends ShaderSizingParams, ShaderMotionPar
53
65
  smoke?: number;
54
66
  smokeSize?: number;
55
67
  }
68
+ export declare const PulsingBorderAspectRatios: {
69
+ readonly auto: 0;
70
+ readonly square: 1;
71
+ };
72
+ export type PulsingBorderAspectRatio = keyof typeof PulsingBorderAspectRatios;
@@ -19,6 +19,11 @@ uniform vec4 u_colors[${pulsingBorderMeta.maxColorCount}];
19
19
  uniform float u_colorsCount;
20
20
  uniform float u_roundness;
21
21
  uniform float u_thickness;
22
+ uniform float u_marginLeft;
23
+ uniform float u_marginRight;
24
+ uniform float u_marginTop;
25
+ uniform float u_marginBottom;
26
+ uniform float u_aspectRatio;
22
27
  uniform float u_softness;
23
28
  uniform float u_intensity;
24
29
  uniform float u_bloom;
@@ -43,19 +48,23 @@ float beat(float time) {
43
48
  return clamp(first + 0.6 * second, 0.0, 1.0);
44
49
  }
45
50
 
46
- float roundedBox(vec2 uv, float distance) {
47
- float thickness = .5 * u_thickness;
48
- float borderDistance = abs(distance);
49
- float border = 1. - smoothstep(-u_softness * thickness - 2. * fwidth(borderDistance), .5 * u_softness * thickness, borderDistance - .5 * thickness);
50
- border = pow(border, 2.);
51
-
52
- return border;
51
+ float sst(float edge0, float edge1, float x) {
52
+ return smoothstep(edge0, edge1, x);
53
53
  }
54
54
 
55
- float roundedBoxSmoke(vec2 uv, float distance, float size) {
55
+ float roundedBox(vec2 uv, vec2 halfSize, float distance, float cornerDistance, float thickness, float softness) {
56
56
  float borderDistance = abs(distance);
57
- float border = 1. - smoothstep(-.75 * size, .75 * size, borderDistance);
58
- border *= border;
57
+ float aa = 2. * fwidth(distance);
58
+ float border = 1. - sst(mix(thickness, -thickness, softness), thickness + aa, borderDistance);
59
+ float cornerFadeCircles = 0.;
60
+ cornerFadeCircles = mix(1., cornerFadeCircles, sst(0., 1., length((uv + halfSize) / thickness)));
61
+ cornerFadeCircles = mix(1., cornerFadeCircles, sst(0., 1., length((uv - vec2(-halfSize.x, halfSize.y)) / thickness)));
62
+ cornerFadeCircles = mix(1., cornerFadeCircles, sst(0., 1., length((uv - vec2(halfSize.x, -halfSize.y)) / thickness)));
63
+ cornerFadeCircles = mix(1., cornerFadeCircles, sst(0., 1., length((uv - halfSize) / thickness)));
64
+ aa = fwidth(cornerDistance);
65
+ float cornerFade = sst(0., mix(aa, thickness, softness), cornerDistance);
66
+ cornerFade *= cornerFadeCircles;
67
+ border += cornerFade;
59
68
  return border;
60
69
  }
61
70
 
@@ -78,101 +87,86 @@ float valueNoise(vec2 st) {
78
87
  return mix(x1, x2, u.y);
79
88
  }
80
89
 
81
- float linearstep(float edge0, float edge1, float x) {
82
- return clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
83
- }
84
-
85
90
  void main() {
86
-
87
- const float firstFrameOffset = 4.;
91
+ const float firstFrameOffset = 109.;
88
92
  float t = 1.2 * (u_time + firstFrameOffset);
89
93
 
90
94
  vec2 borderUV = v_responsiveUV;
91
-
92
- float angle = atan(borderUV.y, borderUV.x) / TWO_PI;
93
-
94
95
  float pulse = u_pulse * beat(.18 * u_time);
95
96
 
96
- float borderRatio = v_responsiveBoxGivenSize.x / v_responsiveBoxGivenSize.y;
97
- borderUV.x *= borderRatio;
97
+ float canvasRatio = v_responsiveBoxGivenSize.x / v_responsiveBoxGivenSize.y;
98
98
  vec2 halfSize = vec2(.5);
99
- halfSize.x *= borderRatio;
100
- float radius = min(.5 * u_roundness, halfSize.x);
99
+ borderUV.x *= max(canvasRatio, 1.);
100
+ borderUV.y /= min(canvasRatio, 1.);
101
+ halfSize.x *= max(canvasRatio, 1.);
102
+ halfSize.y /= min(canvasRatio, 1.);
103
+
104
+ float mL = u_marginLeft;
105
+ float mR = u_marginRight;
106
+ float mT = u_marginTop;
107
+ float mB = u_marginBottom;
108
+ float mX = mL + mR;
109
+ float mY = mT + mB;
110
+
111
+ if (u_aspectRatio > 0.) {
112
+ float shapeRatio = canvasRatio * (1. - mX) / (1. - mY);
113
+ float freeX = shapeRatio > 1. ? (1. - mX) * (1. - 1. / shapeRatio) : 0.;
114
+ float freeY = shapeRatio < 1. ? (1. - mY) * (1. - shapeRatio) : 0.;
115
+ mL += freeX * 0.5;
116
+ mR += freeX * 0.5;
117
+ mT += freeY * 0.5;
118
+ mB += freeY * 0.5;
119
+ mX = mL + mR;
120
+ mY = mT + mB;
121
+ }
122
+
123
+ float thickness = .5 * u_thickness * min(halfSize.x, halfSize.y);
124
+
125
+ halfSize.x *= (1. - mX);
126
+ halfSize.y *= (1. - mY);
127
+
128
+ vec2 centerShift = vec2(
129
+ (mL - mR) * max(canvasRatio, 1.) * 0.5,
130
+ (mB - mT) / min(canvasRatio, 1.) * 0.5
131
+ );
132
+
133
+ borderUV -= centerShift;
134
+ halfSize -= mix(thickness, 0., u_softness);
135
+
136
+ float radius = mix(0., min(halfSize.x, halfSize.y), u_roundness);
101
137
  vec2 d = abs(borderUV) - halfSize + radius;
102
- float outsideDistance = length(max(d, 0.)) - radius;
103
- float insideDistance = min(max(d.x, d.y), 0.0);
138
+ float outsideDistance = length(max(d, .0001)) - radius;
139
+ float insideDistance = min(max(d.x, d.y), .0001);
140
+ float cornerDistance = abs(min(max(d.x, d.y) - .45 * radius, .0));
104
141
  float distance = outsideDistance + insideDistance;
105
142
 
106
- float border = roundedBox(borderUV, distance);
107
-
108
- vec2 v0 = borderUV + halfSize;
109
- vec2 v1 = borderUV - vec2(-halfSize.x, halfSize.y);
110
- vec2 v2 = borderUV - vec2(halfSize.x, -halfSize.y);
111
- vec2 v3 = borderUV - halfSize;
112
-
113
- float cornerFade = 1. - abs(v0.x - v0.y);
114
- cornerFade = max(cornerFade, 1. - abs(v1.x + v1.y));
115
- cornerFade = max(cornerFade, 1. - abs(v2.x + v2.y));
116
- cornerFade = max(cornerFade, 1. - abs(v3.x - v3.y));
117
- cornerFade = .75 * pow(cornerFade, 20.);
118
-
119
- float cornerFadeMask = 0.;
120
- float maskR = (.35 * u_thickness - .25 * radius);
121
- float maskHL = linearstep(halfSize.x - .25 * u_thickness, halfSize.x, borderUV.x);
122
- float maskHR = linearstep(halfSize.x - .25 * u_thickness, halfSize.x, -borderUV.x);
123
- float maskVT = linearstep(halfSize.y - .25 * u_thickness, halfSize.y, -borderUV.y);
124
- float maskVB = linearstep(halfSize.y - .25 * u_thickness, halfSize.y, borderUV.y);
125
- float maskOffset = .25 * (u_thickness + radius);
126
- {
127
- float m = maskHR;
128
- m *= maskVT;
129
- m *= (1. - clamp(length((v0 - maskOffset) / maskR), 0., 1.));
130
- cornerFadeMask += m;
131
- }
132
- {
133
- float m = maskHR;
134
- m *= maskVB;
135
- m *= (1. - clamp(length((v1 - vec2(1., -1.) * maskOffset) / maskR), 0., 1.));
136
- cornerFadeMask += m;
137
- }
138
- {
139
- float m = maskHL;
140
- m *= maskVT;
141
- m *= (1. - clamp(length((v2 - vec2(-1., 1.) * maskOffset) / maskR), 0., 1.));
142
- cornerFadeMask += m;
143
- }
144
- {
145
- float m = maskHL;
146
- m *= maskVB;
147
- m *= (1. - clamp(length((v3 + maskOffset) / maskR), 0., 1.));
148
- cornerFadeMask += m;
149
- }
150
- cornerFade = clamp(cornerFade, 0., 1.);
151
- cornerFade *= cornerFadeMask;
152
- border += cornerFade;
143
+ float borderThickness = mix(thickness, 3. * thickness, u_softness);
144
+ float border = roundedBox(borderUV, halfSize, distance, cornerDistance, borderThickness, u_softness);
145
+ border = pow(border, 1. + u_softness);
153
146
 
154
- vec2 smokeUV = .2 * u_smokeSize * v_patternUV;
147
+ vec2 smokeUV = .3 * u_smokeSize * v_patternUV;
155
148
  float smoke = clamp(3. * valueNoise(2.7 * smokeUV + .5 * t), 0., 1.);
156
149
  smoke -= valueNoise(3.4 * smokeUV - .5 * t);
157
- smoke *= roundedBoxSmoke(borderUV, distance, u_smoke);
150
+ float smokeThickness = thickness + .2;
151
+ smokeThickness = min(.4, max(smokeThickness, .1));
152
+ smoke *= roundedBox(borderUV, halfSize, distance, cornerDistance, smokeThickness, 1.);
158
153
  smoke = 30. * pow(smoke, 2.);
159
- smoke += cornerFadeMask;
160
- smoke *= u_smoke;
154
+ smoke *= mix(0., .5, pow(u_smoke, 2.));
161
155
  smoke *= mix(1., pulse, u_pulse);
162
156
  smoke = clamp(smoke, 0., 1.);
163
-
164
157
  border += smoke;
165
- float borderBounds = 1. - smoothstep(.9, 1., length(v_responsiveUV));
166
- border *= borderBounds;
158
+
167
159
  border = clamp(border, 0., 1.);
168
160
 
169
161
  vec3 blendColor = vec3(0.);
170
- float blendAlpha = 0.0;
162
+ float blendAlpha = 0.;
171
163
  vec3 addColor = vec3(0.);
172
- float addAlpha = 0.0;
164
+ float addAlpha = 0.;
173
165
 
174
166
  float bloom = 4. * u_bloom;
175
- float intensity = 1. + 4. * u_intensity;
167
+ float intensity = 1. + (1. + 4. * u_softness) * u_intensity;
168
+
169
+ float angle = atan(borderUV.y, borderUV.x) / TWO_PI;
176
170
 
177
171
  for (int colorIdx = 0; colorIdx < ${pulsingBorderMeta.maxColorCount}; colorIdx++) {
178
172
  if (colorIdx >= int(u_colorsCount)) break;
@@ -202,7 +196,7 @@ void main() {
202
196
  float atg1 = fract(angle + time);
203
197
  float spotSize = .05 + .6 * pow(u_spotSize, 2.) + .05 * randVal.x;
204
198
  spotSize = mix(spotSize, .1, p);
205
- float sector = smoothstep(.5 - spotSize, .5, atg1) * smoothstep(.5 + spotSize, .5, atg1);
199
+ float sector = sst(.5 - spotSize, .5, atg1) * sst(.5 + spotSize, .5, atg1);
206
200
 
207
201
  sector *= mask;
208
202
  sector *= border;
@@ -231,7 +225,12 @@ void main() {
231
225
 
232
226
  fragColor = vec4(color, opacity);
233
227
  }`;
228
+ const PulsingBorderAspectRatios = {
229
+ auto: 0,
230
+ square: 1
231
+ };
234
232
  export {
233
+ PulsingBorderAspectRatios,
235
234
  pulsingBorderFragmentShader,
236
235
  pulsingBorderMeta
237
236
  };