@paper-design/shaders 0.0.40 → 0.0.46

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 (78) hide show
  1. package/README.md +2 -1
  2. package/dist/get-shader-noise-texture.d.ts +1 -1
  3. package/dist/get-shader-noise-texture.js +5 -9
  4. package/dist/get-shader-noise-texture.js.map +2 -2
  5. package/dist/index.d.ts +4 -0
  6. package/dist/index.js +18 -0
  7. package/dist/index.js.map +2 -2
  8. package/dist/shader-mount.d.ts +8 -2
  9. package/dist/shader-mount.js +12 -177
  10. package/dist/shader-mount.js.map +2 -2
  11. package/dist/shader-sizing.d.ts +2 -2
  12. package/dist/shader-sizing.js +39 -1
  13. package/dist/shader-sizing.js.map +2 -2
  14. package/dist/shader-utils.d.ts +8 -5
  15. package/dist/shader-utils.js +70 -51
  16. package/dist/shader-utils.js.map +2 -2
  17. package/dist/shaders/dithering.js +13 -11
  18. package/dist/shaders/dithering.js.map +2 -2
  19. package/dist/shaders/dot-grid.js +2 -2
  20. package/dist/shaders/dot-grid.js.map +2 -2
  21. package/dist/shaders/dot-orbit.d.ts +3 -0
  22. package/dist/shaders/dot-orbit.js +9 -9
  23. package/dist/shaders/dot-orbit.js.map +2 -2
  24. package/dist/shaders/fluted-glass.d.ts +72 -0
  25. package/dist/shaders/fluted-glass.js +188 -0
  26. package/dist/shaders/fluted-glass.js.map +7 -0
  27. package/dist/shaders/god-rays.d.ts +2 -0
  28. package/dist/shaders/god-rays.js +20 -9
  29. package/dist/shaders/god-rays.js.map +2 -2
  30. package/dist/shaders/grain-gradient.d.ts +1 -0
  31. package/dist/shaders/grain-gradient.js +65 -42
  32. package/dist/shaders/grain-gradient.js.map +2 -2
  33. package/dist/shaders/image-dithering.d.ts +49 -0
  34. package/dist/shaders/image-dithering.js +164 -0
  35. package/dist/shaders/image-dithering.js.map +7 -0
  36. package/dist/shaders/liquid-metal.js +4 -4
  37. package/dist/shaders/liquid-metal.js.map +2 -2
  38. package/dist/shaders/mesh-gradient.js +2 -2
  39. package/dist/shaders/mesh-gradient.js.map +2 -2
  40. package/dist/shaders/metaballs.d.ts +3 -0
  41. package/dist/shaders/metaballs.js +8 -7
  42. package/dist/shaders/metaballs.js.map +2 -2
  43. package/dist/shaders/neuro-noise.js +2 -2
  44. package/dist/shaders/neuro-noise.js.map +2 -2
  45. package/dist/shaders/paper-texture.d.ts +53 -0
  46. package/dist/shaders/paper-texture.js +236 -0
  47. package/dist/shaders/paper-texture.js.map +7 -0
  48. package/dist/shaders/perlin-noise.js +111 -117
  49. package/dist/shaders/perlin-noise.js.map +2 -2
  50. package/dist/shaders/pulsing-border.d.ts +1 -0
  51. package/dist/shaders/pulsing-border.js +23 -15
  52. package/dist/shaders/pulsing-border.js.map +2 -2
  53. package/dist/shaders/simplex-noise.js +2 -2
  54. package/dist/shaders/simplex-noise.js.map +2 -2
  55. package/dist/shaders/smoke-ring.js +13 -8
  56. package/dist/shaders/smoke-ring.js.map +2 -2
  57. package/dist/shaders/spiral.js +3 -3
  58. package/dist/shaders/spiral.js.map +2 -2
  59. package/dist/shaders/static-mesh-gradient.d.ts +2 -0
  60. package/dist/shaders/static-mesh-gradient.js +15 -14
  61. package/dist/shaders/static-mesh-gradient.js.map +2 -2
  62. package/dist/shaders/static-radial-gradient.d.ts +2 -0
  63. package/dist/shaders/static-radial-gradient.js +15 -13
  64. package/dist/shaders/static-radial-gradient.js.map +2 -2
  65. package/dist/shaders/swirl.js +3 -3
  66. package/dist/shaders/swirl.js.map +2 -2
  67. package/dist/shaders/voronoi.js +6 -10
  68. package/dist/shaders/voronoi.js.map +2 -2
  69. package/dist/shaders/warp.d.ts +3 -0
  70. package/dist/shaders/warp.js +20 -4
  71. package/dist/shaders/warp.js.map +2 -2
  72. package/dist/shaders/water.d.ts +39 -0
  73. package/dist/shaders/water.js +119 -0
  74. package/dist/shaders/water.js.map +7 -0
  75. package/dist/vertex-shader.d.ts +2 -0
  76. package/dist/vertex-shader.js +212 -0
  77. package/dist/vertex-shader.js.map +7 -0
  78. package/package.json +1 -1
@@ -4,7 +4,7 @@
4
4
  * * * * * * * * * * * * * * * * * * * * * * * * * * * */
5
5
 
6
6
  import { sizingVariablesDeclaration } from "../shader-sizing.js";
7
- import { declarePI, declareValueNoise, colorBandingFix } from "../shader-utils.js";
7
+ import { declarePI, textureRandomizerGB, colorBandingFix } from "../shader-utils.js";
8
8
  const pulsingBorderMeta = {
9
9
  maxColorCount: 5,
10
10
  maxSpots: 4
@@ -59,17 +59,25 @@ float roundedBoxSmoke(vec2 uv, float distance, float size) {
59
59
  return border;
60
60
  }
61
61
 
62
- float random(vec2 p) {
62
+ ${textureRandomizerGB}
63
+
64
+ float randomG(vec2 p) {
63
65
  vec2 uv = floor(p) / 100. + .5;
64
- return texture(u_noiseTexture, uv).g;
66
+ return texture(u_noiseTexture, fract(uv)).g;
65
67
  }
66
- vec2 rand2(vec2 p) {
67
- vec2 uv = floor(p) / 100. + .5;
68
- return texture(u_noiseTexture, uv).gb;
68
+ float valueNoise(vec2 st) {
69
+ vec2 i = floor(st);
70
+ vec2 f = fract(st);
71
+ float a = randomG(i);
72
+ float b = randomG(i + vec2(1.0, 0.0));
73
+ float c = randomG(i + vec2(0.0, 1.0));
74
+ float d = randomG(i + vec2(1.0, 1.0));
75
+ vec2 u = f * f * (3.0 - 2.0 * f);
76
+ float x1 = mix(a, b, u.x);
77
+ float x2 = mix(c, d, u.x);
78
+ return mix(x1, x2, u.y);
69
79
  }
70
80
 
71
- ${declareValueNoise}
72
-
73
81
  float linearstep(float edge0, float edge1, float x) {
74
82
  return clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
75
83
  }
@@ -95,12 +103,12 @@ void main() {
95
103
  float distance = outsideDistance + insideDistance;
96
104
 
97
105
  float border = roundedBox(borderUV, distance);
98
-
106
+
99
107
  vec2 v0 = borderUV + halfSize;
100
108
  vec2 v1 = borderUV - vec2(-halfSize.x, halfSize.y);
101
109
  vec2 v2 = borderUV - vec2(halfSize.x, -halfSize.y);
102
110
  vec2 v3 = borderUV - halfSize;
103
-
111
+
104
112
  float cornerFade = 1. - abs(v0.x - v0.y);
105
113
  cornerFade = max(cornerFade, 1. - abs(v1.x + v1.y));
106
114
  cornerFade = max(cornerFade, 1. - abs(v2.x + v2.y));
@@ -154,12 +162,12 @@ void main() {
154
162
 
155
163
  border += smoke;
156
164
  border = clamp(border, 0., 1.);
157
-
165
+
158
166
  vec3 blendColor = vec3(0.);
159
167
  float blendAlpha = 0.0;
160
168
  vec3 addColor = vec3(0.);
161
169
  float addAlpha = 0.0;
162
-
170
+
163
171
  float bloom = 4. * u_bloom;
164
172
  float intensity = 1. + 4. * u_intensity;
165
173
 
@@ -174,7 +182,7 @@ void main() {
174
182
  if (spotIdx >= int(u_spots)) break;
175
183
  float spotIdxF = float(spotIdx);
176
184
 
177
- vec2 randVal = rand2(vec2(spotIdxF * 10. + 2., 40. + colorIdxF));
185
+ vec2 randVal = randomGB(vec2(spotIdxF * 10. + 2., 40. + colorIdxF));
178
186
 
179
187
  float time = (.1 + .15 * abs(sin(spotIdxF * (2. + colorIdxF)) * cos(spotIdxF * (2. + 2.5 * colorIdxF)))) * t + randVal.x * 3.;
180
188
  time *= mix(1., -1., step(.5, randVal.y));
@@ -192,7 +200,7 @@ void main() {
192
200
  float spotSize = .05 + .6 * pow(u_spotSize, 2.) + .05 * randVal.x;
193
201
  spotSize = mix(spotSize, .1, p);
194
202
  float sector = smoothstep(.5 - spotSize, .5, atg1) * smoothstep(.5 + spotSize, .5, atg1);
195
-
203
+
196
204
  sector *= mask;
197
205
  sector *= border;
198
206
  sector *= intensity;
@@ -215,7 +223,7 @@ void main() {
215
223
  vec3 bgColor = u_colorBack.rgb * u_colorBack.a;
216
224
  vec3 color = accumColor + (1. - accumAlpha) * bgColor;
217
225
  float opacity = accumAlpha + (1. - accumAlpha) * u_colorBack.a;
218
-
226
+
219
227
  ${colorBandingFix}
220
228
 
221
229
  fragColor = vec4(color, opacity);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/shaders/pulsing-border.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, declareValueNoise, colorBandingFix } from '../shader-utils.js';\n\nexport const pulsingBorderMeta = {\n maxColorCount: 5,\n maxSpots: 4,\n} as const;\n\n/**\n * Color spots traveling around rectangular stroke (border)\n *\n * Uniforms:\n * - u_colorBack (RGBA)\n * - u_colors (vec4[]), u_colorsCount (float used as integer)\n * - u_roundness, u_thickness, u_softness: border parameters\n * - u_intensity: thickness of individual spots\n * - u_bloom: normal / additive color blending\n * - u_spotSize: angular size of spots\n * - u_spots (float used as int): number of spots rendered per color\n * - u_pulse: optional pulsing animation\n * - u_smoke, u_smokeSize: optional noisy shapes around the border\n *\n * - u_noiseTexture (sampler2D): pre-computed randomizer source\n *\n */\n\n// language=GLSL\nexport const pulsingBorderFragmentShader: string = `#version 300 es\nprecision lowp float;\n\nuniform float u_time;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colors[${pulsingBorderMeta.maxColorCount}];\nuniform float u_colorsCount;\nuniform float u_roundness;\nuniform float u_thickness;\nuniform float u_softness;\nuniform float u_intensity;\nuniform float u_bloom;\nuniform float u_spotSize;\nuniform float u_spots;\nuniform float u_pulse;\nuniform float u_smoke;\nuniform float u_smokeSize;\n\nuniform sampler2D u_noiseTexture;\n\n${sizingVariablesDeclaration}\n\nout vec4 fragColor;\n\n${declarePI}\n\nfloat beat(float time) {\n float first = pow(sin(time * TWO_PI), 10.);\n float second = pow(sin((time - 0.15) * TWO_PI), 10.);\n\n return clamp(first + 0.6 * second, 0.0, 1.0);\n}\n\nfloat roundedBox(vec2 uv, float distance) {\n float thickness = .5 * u_thickness;\n float borderDistance = abs(distance);\n float border = 1. - smoothstep(-u_softness * thickness - 2. * fwidth(borderDistance), .5 * u_softness * thickness, borderDistance - .5 * thickness);\n border = pow(border, 2.);\n\n return border;\n}\n\nfloat roundedBoxSmoke(vec2 uv, float distance, float size) {\n float borderDistance = abs(distance);\n float border = 1. - smoothstep(-.75 * size, .75 * size, borderDistance);\n border *= border;\n return border;\n}\n\nfloat random(vec2 p) {\n vec2 uv = floor(p) / 100. + .5;\n return texture(u_noiseTexture, uv).g;\n}\nvec2 rand2(vec2 p) {\n vec2 uv = floor(p) / 100. + .5;\n return texture(u_noiseTexture, uv).gb;\n}\n\n${declareValueNoise}\n\nfloat linearstep(float edge0, float edge1, float x) {\n return clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);\n}\n\nvoid main() {\n\n float t = 1.2 * u_time;\n\n vec2 borderUV = v_responsiveUV;\n\n float angle = atan(borderUV.y, borderUV.x) / TWO_PI;\n\n float pulse = u_pulse * beat(.18 * u_time);\n\n float borderRatio = v_responsiveBoxGivenSize.x / v_responsiveBoxGivenSize.y;\n borderUV.x *= borderRatio;\n vec2 halfSize = vec2(.5);\n halfSize.x *= borderRatio;\n float radius = min(.5 * u_roundness, halfSize.x);\n vec2 d = abs(borderUV) - halfSize + radius;\n float outsideDistance = length(max(d, 0.)) - radius;\n float insideDistance = min(max(d.x, d.y), 0.0);\n float distance = outsideDistance + insideDistance;\n\n float border = roundedBox(borderUV, distance);\n \n vec2 v0 = borderUV + halfSize;\n vec2 v1 = borderUV - vec2(-halfSize.x, halfSize.y);\n vec2 v2 = borderUV - vec2(halfSize.x, -halfSize.y);\n vec2 v3 = borderUV - halfSize;\n \n float cornerFade = 1. - abs(v0.x - v0.y);\n cornerFade = max(cornerFade, 1. - abs(v1.x + v1.y));\n cornerFade = max(cornerFade, 1. - abs(v2.x + v2.y));\n cornerFade = max(cornerFade, 1. - abs(v3.x - v3.y));\n cornerFade = .75 * pow(cornerFade, 20.);\n\n float cornerFadeMask = 0.;\n float maskR = (.35 * u_thickness - .25 * radius);\n float maskHL = linearstep(halfSize.x - .25 * u_thickness, halfSize.x, borderUV.x);\n float maskHR = linearstep(halfSize.x - .25 * u_thickness, halfSize.x, -borderUV.x);\n float maskVT = linearstep(halfSize.y - .25 * u_thickness, halfSize.y, -borderUV.y);\n float maskVB = linearstep(halfSize.y - .25 * u_thickness, halfSize.y, borderUV.y);\n float maskOffset = .25 * (u_thickness + radius);\n {\n float m = maskHR;\n m *= maskVT;\n m *= (1. - clamp(length((v0 - maskOffset) / maskR), 0., 1.));\n cornerFadeMask += m;\n }\n {\n float m = maskHR;\n m *= maskVB;\n m *= (1. - clamp(length((v1 - vec2(1., -1.) * maskOffset) / maskR), 0., 1.));\n cornerFadeMask += m;\n }\n {\n float m = maskHL;\n m *= maskVT;\n m *= (1. - clamp(length((v2 - vec2(-1., 1.) * maskOffset) / maskR), 0., 1.));\n cornerFadeMask += m;\n }\n {\n float m = maskHL;\n m *= maskVB;\n m *= (1. - clamp(length((v3 + maskOffset) / maskR), 0., 1.));\n cornerFadeMask += m;\n }\n\n cornerFade *= cornerFadeMask;\n border += cornerFade;\n\n vec2 smokeUV = .2 * u_smokeSize * v_patternUV;\n float smoke = clamp(3. * valueNoise(2.7 * smokeUV + .5 * t), 0., 1.);\n smoke -= valueNoise(3.4 * smokeUV - .5 * t);\n smoke *= roundedBoxSmoke(borderUV, distance, u_smoke);\n smoke = 30. * pow(smoke, 2.);\n smoke += cornerFadeMask;\n smoke *= u_smoke;\n smoke *= mix(1., pulse, u_pulse);\n smoke = clamp(smoke, 0., 1.);\n\n border += smoke;\n border = clamp(border, 0., 1.);\n \n vec3 blendColor = vec3(0.);\n float blendAlpha = 0.0;\n vec3 addColor = vec3(0.);\n float addAlpha = 0.0;\n \n float bloom = 4. * u_bloom;\n float intensity = 1. + 4. * u_intensity;\n\n for (int colorIdx = 0; colorIdx < ${pulsingBorderMeta.maxColorCount}; colorIdx++) {\n if (colorIdx >= int(u_colorsCount)) break;\n float colorIdxF = float(colorIdx);\n\n vec3 c = u_colors[colorIdx].rgb * u_colors[colorIdx].a;\n float a = u_colors[colorIdx].a;\n\n for (int spotIdx = 0; spotIdx < ${pulsingBorderMeta.maxSpots}; spotIdx++) {\n if (spotIdx >= int(u_spots)) break;\n float spotIdxF = float(spotIdx);\n\n vec2 randVal = rand2(vec2(spotIdxF * 10. + 2., 40. + colorIdxF));\n\n float time = (.1 + .15 * abs(sin(spotIdxF * (2. + colorIdxF)) * cos(spotIdxF * (2. + 2.5 * colorIdxF)))) * t + randVal.x * 3.;\n time *= mix(1., -1., step(.5, randVal.y));\n\n float mask = .5 + .5 * mix(\n sin(t + spotIdxF * (5. - 1.5 * colorIdxF)),\n cos(t + spotIdxF * (3. + 1.3 * colorIdxF)),\n step(mod(colorIdxF, 2.), .5)\n );\n\n float p = clamp(2. * u_pulse - randVal.x, 0., 1.);\n mask = mix(mask, pulse, p);\n\n float atg1 = fract(angle + time);\n float spotSize = .05 + .6 * pow(u_spotSize, 2.) + .05 * randVal.x;\n spotSize = mix(spotSize, .1, p);\n float sector = smoothstep(.5 - spotSize, .5, atg1) * smoothstep(.5 + spotSize, .5, atg1);\n \n sector *= mask;\n sector *= border;\n sector *= intensity;\n sector = clamp(sector, 0., 1.);\n\n vec3 srcColor = c * sector;\n float srcAlpha = a * sector;\n\n blendColor += ((1. - blendAlpha) * srcColor);\n blendAlpha = blendAlpha + (1. - blendAlpha) * srcAlpha;\n addColor += srcColor;\n addAlpha += srcAlpha;\n }\n }\n\n vec3 accumColor = mix(blendColor, addColor, bloom);\n float accumAlpha = mix(blendAlpha, addAlpha, bloom);\n accumAlpha = clamp(accumAlpha, 0., 1.);\n\n vec3 bgColor = u_colorBack.rgb * u_colorBack.a;\n vec3 color = accumColor + (1. - accumAlpha) * bgColor;\n float opacity = accumAlpha + (1. - accumAlpha) * u_colorBack.a;\n \n ${colorBandingFix}\n\n fragColor = vec4(color, opacity);\n}`;\n\nexport interface PulsingBorderUniforms extends ShaderSizingUniforms {\n u_colorBack: [number, number, number, number];\n u_colors: vec4[];\n u_colorsCount: number;\n u_roundness: number;\n u_thickness: number;\n u_softness: number;\n u_intensity: number;\n u_bloom: number;\n u_spots: number;\n u_spotSize: number;\n u_pulse: number;\n u_smoke: number;\n u_smokeSize: number;\n}\n\nexport interface PulsingBorderParams extends ShaderSizingParams, ShaderMotionParams {\n colorBack?: string;\n colors?: string[];\n roundness?: number;\n thickness?: number;\n softness?: number;\n intensity?: number;\n bloom?: number;\n spots?: number;\n spotSize?: number;\n pulse?: number;\n smoke?: number;\n smokeSize?: number;\n}\n"],
5
- "mappings": ";;;;;AAEA,SAAS,kCAAsF;AAC/F,SAAS,WAAW,mBAAmB,uBAAuB;AAEvD,MAAM,oBAAoB;AAAA,EAC/B,eAAe;AAAA,EACf,UAAU;AACZ;AAqBO,MAAM,8BAAsC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAM3B,kBAAkB,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAerD,0BAA0B;AAAA;AAAA;AAAA;AAAA,EAI1B,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,EAkCT,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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sCA+FmB,kBAAkB,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sCAO/B,kBAAkB,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA8C5D,eAAe;AAAA;AAAA;AAAA;",
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, textureRandomizerGB, colorBandingFix } from '../shader-utils.js';\n\nexport const pulsingBorderMeta = {\n maxColorCount: 5,\n maxSpots: 4,\n} as const;\n\n/**\n * Color spots traveling around rectangular stroke (border)\n *\n * Uniforms:\n * - u_colorBack (RGBA)\n * - u_colors (vec4[]), u_colorsCount (float used as integer)\n * - u_roundness, u_thickness, u_softness: border parameters\n * - u_intensity: thickness of individual spots\n * - u_bloom: normal / additive color blending\n * - u_spotSize: angular size of spots\n * - u_spots (float used as int): number of spots rendered per color\n * - u_pulse: optional pulsing animation\n * - u_smoke, u_smokeSize: optional noisy shapes around the border\n *\n * - u_noiseTexture (sampler2D): pre-computed randomizer source\n *\n */\n\n// language=GLSL\nexport const pulsingBorderFragmentShader: string = `#version 300 es\nprecision lowp float;\n\nuniform float u_time;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colors[${pulsingBorderMeta.maxColorCount}];\nuniform float u_colorsCount;\nuniform float u_roundness;\nuniform float u_thickness;\nuniform float u_softness;\nuniform float u_intensity;\nuniform float u_bloom;\nuniform float u_spotSize;\nuniform float u_spots;\nuniform float u_pulse;\nuniform float u_smoke;\nuniform float u_smokeSize;\n\nuniform sampler2D u_noiseTexture;\n\n${sizingVariablesDeclaration}\n\nout vec4 fragColor;\n\n${declarePI}\n\nfloat beat(float time) {\n float first = pow(sin(time * TWO_PI), 10.);\n float second = pow(sin((time - 0.15) * TWO_PI), 10.);\n\n return clamp(first + 0.6 * second, 0.0, 1.0);\n}\n\nfloat roundedBox(vec2 uv, float distance) {\n float thickness = .5 * u_thickness;\n float borderDistance = abs(distance);\n float border = 1. - smoothstep(-u_softness * thickness - 2. * fwidth(borderDistance), .5 * u_softness * thickness, borderDistance - .5 * thickness);\n border = pow(border, 2.);\n\n return border;\n}\n\nfloat roundedBoxSmoke(vec2 uv, float distance, float size) {\n float borderDistance = abs(distance);\n float border = 1. - smoothstep(-.75 * size, .75 * size, borderDistance);\n border *= border;\n return border;\n}\n\n${textureRandomizerGB}\n\nfloat randomG(vec2 p) {\n vec2 uv = floor(p) / 100. + .5;\n return texture(u_noiseTexture, fract(uv)).g;\n}\nfloat valueNoise(vec2 st) {\n vec2 i = floor(st);\n vec2 f = fract(st);\n float a = randomG(i);\n float b = randomG(i + vec2(1.0, 0.0));\n float c = randomG(i + vec2(0.0, 1.0));\n float d = randomG(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 linearstep(float edge0, float edge1, float x) {\n return clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);\n}\n\nvoid main() {\n\n float t = 1.2 * u_time;\n\n vec2 borderUV = v_responsiveUV;\n\n float angle = atan(borderUV.y, borderUV.x) / TWO_PI;\n\n float pulse = u_pulse * beat(.18 * u_time);\n\n float borderRatio = v_responsiveBoxGivenSize.x / v_responsiveBoxGivenSize.y;\n borderUV.x *= borderRatio;\n vec2 halfSize = vec2(.5);\n halfSize.x *= borderRatio;\n float radius = min(.5 * u_roundness, halfSize.x);\n vec2 d = abs(borderUV) - halfSize + radius;\n float outsideDistance = length(max(d, 0.)) - radius;\n float insideDistance = min(max(d.x, d.y), 0.0);\n float distance = outsideDistance + insideDistance;\n\n float border = roundedBox(borderUV, distance);\n\n vec2 v0 = borderUV + halfSize;\n vec2 v1 = borderUV - vec2(-halfSize.x, halfSize.y);\n vec2 v2 = borderUV - vec2(halfSize.x, -halfSize.y);\n vec2 v3 = borderUV - halfSize;\n\n float cornerFade = 1. - abs(v0.x - v0.y);\n cornerFade = max(cornerFade, 1. - abs(v1.x + v1.y));\n cornerFade = max(cornerFade, 1. - abs(v2.x + v2.y));\n cornerFade = max(cornerFade, 1. - abs(v3.x - v3.y));\n cornerFade = .75 * pow(cornerFade, 20.);\n\n float cornerFadeMask = 0.;\n float maskR = (.35 * u_thickness - .25 * radius);\n float maskHL = linearstep(halfSize.x - .25 * u_thickness, halfSize.x, borderUV.x);\n float maskHR = linearstep(halfSize.x - .25 * u_thickness, halfSize.x, -borderUV.x);\n float maskVT = linearstep(halfSize.y - .25 * u_thickness, halfSize.y, -borderUV.y);\n float maskVB = linearstep(halfSize.y - .25 * u_thickness, halfSize.y, borderUV.y);\n float maskOffset = .25 * (u_thickness + radius);\n {\n float m = maskHR;\n m *= maskVT;\n m *= (1. - clamp(length((v0 - maskOffset) / maskR), 0., 1.));\n cornerFadeMask += m;\n }\n {\n float m = maskHR;\n m *= maskVB;\n m *= (1. - clamp(length((v1 - vec2(1., -1.) * maskOffset) / maskR), 0., 1.));\n cornerFadeMask += m;\n }\n {\n float m = maskHL;\n m *= maskVT;\n m *= (1. - clamp(length((v2 - vec2(-1., 1.) * maskOffset) / maskR), 0., 1.));\n cornerFadeMask += m;\n }\n {\n float m = maskHL;\n m *= maskVB;\n m *= (1. - clamp(length((v3 + maskOffset) / maskR), 0., 1.));\n cornerFadeMask += m;\n }\n\n cornerFade *= cornerFadeMask;\n border += cornerFade;\n\n vec2 smokeUV = .2 * u_smokeSize * v_patternUV;\n float smoke = clamp(3. * valueNoise(2.7 * smokeUV + .5 * t), 0., 1.);\n smoke -= valueNoise(3.4 * smokeUV - .5 * t);\n smoke *= roundedBoxSmoke(borderUV, distance, u_smoke);\n smoke = 30. * pow(smoke, 2.);\n smoke += cornerFadeMask;\n smoke *= u_smoke;\n smoke *= mix(1., pulse, u_pulse);\n smoke = clamp(smoke, 0., 1.);\n\n border += smoke;\n border = clamp(border, 0., 1.);\n\n vec3 blendColor = vec3(0.);\n float blendAlpha = 0.0;\n vec3 addColor = vec3(0.);\n float addAlpha = 0.0;\n\n float bloom = 4. * u_bloom;\n float intensity = 1. + 4. * u_intensity;\n\n for (int colorIdx = 0; colorIdx < ${pulsingBorderMeta.maxColorCount}; colorIdx++) {\n if (colorIdx >= int(u_colorsCount)) break;\n float colorIdxF = float(colorIdx);\n\n vec3 c = u_colors[colorIdx].rgb * u_colors[colorIdx].a;\n float a = u_colors[colorIdx].a;\n\n for (int spotIdx = 0; spotIdx < ${pulsingBorderMeta.maxSpots}; spotIdx++) {\n if (spotIdx >= int(u_spots)) break;\n float spotIdxF = float(spotIdx);\n\n vec2 randVal = randomGB(vec2(spotIdxF * 10. + 2., 40. + colorIdxF));\n\n float time = (.1 + .15 * abs(sin(spotIdxF * (2. + colorIdxF)) * cos(spotIdxF * (2. + 2.5 * colorIdxF)))) * t + randVal.x * 3.;\n time *= mix(1., -1., step(.5, randVal.y));\n\n float mask = .5 + .5 * mix(\n sin(t + spotIdxF * (5. - 1.5 * colorIdxF)),\n cos(t + spotIdxF * (3. + 1.3 * colorIdxF)),\n step(mod(colorIdxF, 2.), .5)\n );\n\n float p = clamp(2. * u_pulse - randVal.x, 0., 1.);\n mask = mix(mask, pulse, p);\n\n float atg1 = fract(angle + time);\n float spotSize = .05 + .6 * pow(u_spotSize, 2.) + .05 * randVal.x;\n spotSize = mix(spotSize, .1, p);\n float sector = smoothstep(.5 - spotSize, .5, atg1) * smoothstep(.5 + spotSize, .5, atg1);\n\n sector *= mask;\n sector *= border;\n sector *= intensity;\n sector = clamp(sector, 0., 1.);\n\n vec3 srcColor = c * sector;\n float srcAlpha = a * sector;\n\n blendColor += ((1. - blendAlpha) * srcColor);\n blendAlpha = blendAlpha + (1. - blendAlpha) * srcAlpha;\n addColor += srcColor;\n addAlpha += srcAlpha;\n }\n }\n\n vec3 accumColor = mix(blendColor, addColor, bloom);\n float accumAlpha = mix(blendAlpha, addAlpha, bloom);\n accumAlpha = clamp(accumAlpha, 0., 1.);\n\n vec3 bgColor = u_colorBack.rgb * u_colorBack.a;\n vec3 color = accumColor + (1. - accumAlpha) * bgColor;\n float opacity = accumAlpha + (1. - accumAlpha) * u_colorBack.a;\n\n ${colorBandingFix}\n\n fragColor = vec4(color, opacity);\n}`;\n\nexport interface PulsingBorderUniforms extends ShaderSizingUniforms {\n u_colorBack: [number, number, number, number];\n u_colors: vec4[];\n u_colorsCount: number;\n u_roundness: number;\n u_thickness: number;\n u_softness: number;\n u_intensity: number;\n u_bloom: number;\n u_spots: number;\n u_spotSize: number;\n u_pulse: number;\n u_smoke: number;\n u_smokeSize: number;\n u_noiseTexture?: HTMLImageElement;\n}\n\nexport interface PulsingBorderParams extends ShaderSizingParams, ShaderMotionParams {\n colorBack?: string;\n colors?: string[];\n roundness?: number;\n thickness?: number;\n softness?: number;\n intensity?: number;\n bloom?: number;\n spots?: number;\n spotSize?: number;\n pulse?: number;\n smoke?: number;\n smokeSize?: number;\n}\n"],
5
+ "mappings": ";;;;;AAEA,SAAS,kCAAsF;AAC/F,SAAS,WAAW,qBAAqB,uBAAuB;AAEzD,MAAM,oBAAoB;AAAA,EAC/B,eAAe;AAAA,EACf,UAAU;AACZ;AAqBO,MAAM,8BAAsC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAM3B,kBAAkB,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAerD,0BAA0B;AAAA;AAAA;AAAA;AAAA,EAI1B,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,EAyBT,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sCAgHiB,kBAAkB,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sCAO/B,kBAAkB,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA8C5D,eAAe;AAAA;AAAA;AAAA;",
6
6
  "names": []
7
7
  }
@@ -4,7 +4,7 @@
4
4
  * * * * * * * * * * * * * * * * * * * * * * * * * * * */
5
5
 
6
6
  import { sizingVariablesDeclaration } from "../shader-sizing.js";
7
- import { declareSimplexNoise, colorBandingFix } from "../shader-utils.js";
7
+ import { simplexNoise, colorBandingFix } from "../shader-utils.js";
8
8
  const simplexNoiseMeta = {
9
9
  maxColorCount: 10
10
10
  };
@@ -23,7 +23,7 @@ ${sizingVariablesDeclaration}
23
23
 
24
24
  out vec4 fragColor;
25
25
 
26
- ${declareSimplexNoise}
26
+ ${simplexNoise}
27
27
 
28
28
  float getNoise(vec2 uv, float t) {
29
29
  float noise = .5 * snoise(uv - vec2(0., .3 * t));
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/shaders/simplex-noise.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 { declareSimplexNoise, colorBandingFix } from '../shader-utils.js';\n\nexport const simplexNoiseMeta = {\n maxColorCount: 10,\n} as const;\n\n/**\n * Color Gradient mapped over a combination of 2 Simplex noises\n *\n * Uniforms:\n * - u_colors (vec4[]), u_colorsCount (float used as integer)\n * - u_stepsPerColor (float, used as int): discrete color steps between u_colors\n * - u_softness: color transition sharpness (0 = hard edge, 1 = smooth fade)\n *\n * */\n\n// language=GLSL\nexport const simplexNoiseFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform float u_time;\nuniform float u_scale;\n\nuniform vec4 u_colors[${simplexNoiseMeta.maxColorCount}];\nuniform float u_colorsCount;\nuniform float u_stepsPerColor;\nuniform float u_softness;\n\n${sizingVariablesDeclaration}\n\nout vec4 fragColor;\n\n${declareSimplexNoise}\n\nfloat getNoise(vec2 uv, float t) {\n float noise = .5 * snoise(uv - vec2(0., .3 * t));\n noise += .5 * snoise(2. * uv + vec2(0., .32 * t));\n\n return noise;\n}\n\nfloat steppedSmooth(float m, float steps, float softness) { \n float stepT = floor(m * steps) / steps;\n float f = m * steps - floor(m * steps);\n float smoothed = smoothstep(.5 - softness, .5 + softness, f);\n return stepT + smoothed / steps;\n}\n\nvoid main() {\n vec2 shape_uv = v_patternUV;\n shape_uv *= .1;\n\n float t = .2 * u_time;\n\n float shape = .5 + .5 * getNoise(shape_uv, t);\n\n bool u_extraSides = true;\n\n float mixer = shape * (u_colorsCount - 1.);\n if (u_extraSides == true) {\n mixer = (shape - .5 / u_colorsCount) * u_colorsCount;\n }\n\n float steps = max(1., u_stepsPerColor);\n\n vec4 gradient = u_colors[0];\n gradient.rgb *= gradient.a;\n for (int i = 1; i < ${simplexNoiseMeta.maxColorCount}; i++) {\n if (i >= int(u_colorsCount)) break;\n\n float localM = clamp(mixer - float(i - 1), 0., 1.);\n localM = steppedSmooth(localM, steps, .5 * u_softness + steps * fwidth(localM));\n\n vec4 c = u_colors[i];\n c.rgb *= c.a;\n gradient = mix(gradient, c, localM);\n }\n\n if (u_extraSides == true) {\n if ((mixer < 0.) || (mixer > (u_colorsCount - 1.))) {\n float localM = mixer + 1.;\n if (mixer > (u_colorsCount - 1.)) {\n localM = mixer - (u_colorsCount - 1.);\n }\n localM = steppedSmooth(localM, steps, .5 * u_softness + steps * fwidth(localM));\n vec4 cFst = u_colors[0];\n cFst.rgb *= cFst.a;\n vec4 cLast = u_colors[int(u_colorsCount - 1.)];\n cLast.rgb *= cLast.a;\n gradient = mix(cLast, cFst, localM);\n }\n }\n\n vec3 color = gradient.rgb;\n float opacity = gradient.a;\n\n ${colorBandingFix}\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface SimplexNoiseUniforms extends ShaderSizingUniforms {\n u_colors: vec4[];\n u_colorsCount: number;\n u_stepsPerColor: number;\n u_softness: number;\n}\n\nexport interface SimplexNoiseParams extends ShaderSizingParams, ShaderMotionParams {\n colors?: string[];\n stepsPerColor?: number;\n softness?: number;\n}\n"],
5
- "mappings": ";;;;;AAEA,SAAS,kCAAsF;AAC/F,SAAS,qBAAqB,uBAAuB;AAE9C,MAAM,mBAAmB;AAAA,EAC9B,eAAe;AACjB;AAaO,MAAM,6BAAqC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAM1B,iBAAiB,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA,EAKpD,0BAA0B;AAAA;AAAA;AAAA;AAAA,EAI1B,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAmCG,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;AAAA;AAAA,IA6BlD,eAAe;AAAA;AAAA;AAAA;AAAA;",
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 { simplexNoise, colorBandingFix } from '../shader-utils.js';\n\nexport const simplexNoiseMeta = {\n maxColorCount: 10,\n} as const;\n\n/**\n * Color Gradient mapped over a combination of 2 Simplex noises\n *\n * Uniforms:\n * - u_colors (vec4[]), u_colorsCount (float used as integer)\n * - u_stepsPerColor (float, used as int): discrete color steps between u_colors\n * - u_softness: color transition sharpness (0 = hard edge, 1 = smooth fade)\n *\n * */\n\n// language=GLSL\nexport const simplexNoiseFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform float u_time;\nuniform float u_scale;\n\nuniform vec4 u_colors[${simplexNoiseMeta.maxColorCount}];\nuniform float u_colorsCount;\nuniform float u_stepsPerColor;\nuniform float u_softness;\n\n${sizingVariablesDeclaration}\n\nout vec4 fragColor;\n\n${simplexNoise}\n\nfloat getNoise(vec2 uv, float t) {\n float noise = .5 * snoise(uv - vec2(0., .3 * t));\n noise += .5 * snoise(2. * uv + vec2(0., .32 * t));\n\n return noise;\n}\n\nfloat steppedSmooth(float m, float steps, float softness) { \n float stepT = floor(m * steps) / steps;\n float f = m * steps - floor(m * steps);\n float smoothed = smoothstep(.5 - softness, .5 + softness, f);\n return stepT + smoothed / steps;\n}\n\nvoid main() {\n vec2 shape_uv = v_patternUV;\n shape_uv *= .1;\n\n float t = .2 * u_time;\n\n float shape = .5 + .5 * getNoise(shape_uv, t);\n\n bool u_extraSides = true;\n\n float mixer = shape * (u_colorsCount - 1.);\n if (u_extraSides == true) {\n mixer = (shape - .5 / u_colorsCount) * u_colorsCount;\n }\n\n float steps = max(1., u_stepsPerColor);\n\n vec4 gradient = u_colors[0];\n gradient.rgb *= gradient.a;\n for (int i = 1; i < ${simplexNoiseMeta.maxColorCount}; i++) {\n if (i >= int(u_colorsCount)) break;\n\n float localM = clamp(mixer - float(i - 1), 0., 1.);\n localM = steppedSmooth(localM, steps, .5 * u_softness + steps * fwidth(localM));\n\n vec4 c = u_colors[i];\n c.rgb *= c.a;\n gradient = mix(gradient, c, localM);\n }\n\n if (u_extraSides == true) {\n if ((mixer < 0.) || (mixer > (u_colorsCount - 1.))) {\n float localM = mixer + 1.;\n if (mixer > (u_colorsCount - 1.)) {\n localM = mixer - (u_colorsCount - 1.);\n }\n localM = steppedSmooth(localM, steps, .5 * u_softness + steps * fwidth(localM));\n vec4 cFst = u_colors[0];\n cFst.rgb *= cFst.a;\n vec4 cLast = u_colors[int(u_colorsCount - 1.)];\n cLast.rgb *= cLast.a;\n gradient = mix(cLast, cFst, localM);\n }\n }\n\n vec3 color = gradient.rgb;\n float opacity = gradient.a;\n\n ${colorBandingFix}\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface SimplexNoiseUniforms extends ShaderSizingUniforms {\n u_colors: vec4[];\n u_colorsCount: number;\n u_stepsPerColor: number;\n u_softness: number;\n}\n\nexport interface SimplexNoiseParams extends ShaderSizingParams, ShaderMotionParams {\n colors?: string[];\n stepsPerColor?: number;\n softness?: number;\n}\n"],
5
+ "mappings": ";;;;;AAEA,SAAS,kCAAsF;AAC/F,SAAS,cAAc,uBAAuB;AAEvC,MAAM,mBAAmB;AAAA,EAC9B,eAAe;AACjB;AAaO,MAAM,6BAAqC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAM1B,iBAAiB,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA,EAKpD,0BAA0B;AAAA;AAAA;AAAA;AAAA,EAI1B,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAmCU,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;AAAA;AAAA,IA6BlD,eAAe;AAAA;AAAA;AAAA;AAAA;",
6
6
  "names": []
7
7
  }
@@ -4,7 +4,7 @@
4
4
  * * * * * * * * * * * * * * * * * * * * * * * * * * * */
5
5
 
6
6
  import { sizingVariablesDeclaration } from "../shader-sizing.js";
7
- import { declarePI, declareValueNoise, colorBandingFix } from "../shader-utils.js";
7
+ import { declarePI, textureRandomizerR, colorBandingFix } from "../shader-utils.js";
8
8
  const smokeRingMeta = {
9
9
  maxColorCount: 10,
10
10
  maxNoiseIterations: 8
@@ -31,14 +31,19 @@ ${sizingVariablesDeclaration}
31
31
  out vec4 fragColor;
32
32
 
33
33
  ${declarePI}
34
-
35
- float random(vec2 p) {
36
- vec2 uv = floor(p) / 100. + .5;
37
- return texture(u_noiseTexture, uv).r;
34
+ ${textureRandomizerR}
35
+ float valueNoise(vec2 st) {
36
+ vec2 i = floor(st);
37
+ vec2 f = fract(st);
38
+ float a = randomR(i);
39
+ float b = randomR(i + vec2(1.0, 0.0));
40
+ float c = randomR(i + vec2(0.0, 1.0));
41
+ float d = randomR(i + vec2(1.0, 1.0));
42
+ vec2 u = f * f * (3.0 - 2.0 * f);
43
+ float x1 = mix(a, b, u.x);
44
+ float x2 = mix(c, d, u.x);
45
+ return mix(x1, x2, u.y);
38
46
  }
39
-
40
- ${declareValueNoise}
41
-
42
47
  float fbm(in vec2 n) {
43
48
  float total = 0.0, amplitude = .4;
44
49
  for (int i = 0; i < ${smokeRingMeta.maxNoiseIterations}; i++) {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/shaders/smoke-ring.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, declareValueNoise, colorBandingFix } from '../shader-utils.js';\n\nexport const smokeRingMeta = {\n maxColorCount: 10,\n maxNoiseIterations: 8,\n} as const;\n\n/**\n * Radial gradient with layered FBM displacement, masked with ring shape\n *\n * Uniforms:\n * - u_colorBack (RGBA)\n * - u_colors (vec4[]), u_colorsCount (float used as integer)\n * - u_thickness, u_radius, u_innerShape: ring mask settings\n * - u_noiseIterations, u_noiseScale: how detailed is the noise (number of fbm layers & noise frequency)\n *\n * - u_noiseTexture (sampler2D): pre-computed randomizer source\n */\n\n// language=GLSL\nexport const smokeRingFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform float u_time;\n\nuniform sampler2D u_noiseTexture;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colors[${smokeRingMeta.maxColorCount}];\nuniform float u_colorsCount;\n\nuniform float u_thickness;\nuniform float u_radius;\nuniform float u_innerShape;\nuniform float u_noiseScale;\nuniform float u_noiseIterations;\n\n${sizingVariablesDeclaration}\n\nout vec4 fragColor;\n\n${declarePI}\n\nfloat random(vec2 p) {\n vec2 uv = floor(p) / 100. + .5;\n return texture(u_noiseTexture, uv).r;\n}\n\n${declareValueNoise}\n\nfloat fbm(in vec2 n) {\n float total = 0.0, amplitude = .4;\n for (int i = 0; i < ${smokeRingMeta.maxNoiseIterations}; i++) {\n if (i >= int(u_noiseIterations)) break;\n total += valueNoise(n) * amplitude;\n n *= 1.99;\n amplitude *= 0.65;\n }\n return total;\n}\n\nfloat getNoise(vec2 uv, vec2 pUv, float t) {\n float noiseLeft = fbm(pUv + .03 * t);\n pUv.x = mod(pUv.x, u_noiseScale * TWO_PI);\n float noiseRight = fbm(pUv + .03 * t);\n return mix(noiseRight, noiseLeft, smoothstep(-.25, .25, uv.x));\n}\n\nfloat getRingShape(vec2 uv) {\n float radius = u_radius;\n float thickness = u_thickness;\n\n float distance = length(uv);\n float ringValue = 1. - smoothstep(radius, radius + thickness, distance);\n ringValue *= smoothstep(radius - pow(u_innerShape, 3.) * thickness, radius, distance);\n\n return ringValue;\n}\n\nvoid main() {\n vec2 shape_uv = v_objectUV;\n\n float t = u_time;\n\n float cycleDuration = 3.;\n float localTime1 = mod(.1 * t + cycleDuration, 2. * cycleDuration);\n float localTime2 = mod(.1 * t, 2. * cycleDuration);\n float timeBlend = .5 + .5 * sin(.1 * t * PI / cycleDuration - .5 * PI);\n\n float atg = atan(shape_uv.y, shape_uv.x) + .001;\n float l = length(shape_uv);\n vec2 polar_uv1 = vec2(atg, localTime1 - (.5 * l) + 1. / pow(l, .5));\n polar_uv1 *= u_noiseScale;\n float noise1 = getNoise(shape_uv, polar_uv1, t);\n\n vec2 polar_uv2 = vec2(atg, localTime2 - (.5 * l) + 1. / pow(l, .5));\n polar_uv2 *= u_noiseScale;\n float noise2 = getNoise(shape_uv, polar_uv2, t);\n\n float noise = mix(noise1, noise2, timeBlend);\n\n shape_uv *= (.8 + 1.2 * noise);\n\n float ringShape = getRingShape(shape_uv);\n\n float mixer = pow(ringShape, 3.) * (u_colorsCount - 1.);\n vec4 gradient = u_colors[0];\n gradient.rgb *= gradient.a;\n for (int i = 1; i < ${smokeRingMeta.maxColorCount}; i++) {\n if (i >= int(u_colorsCount)) break;\n float localT = clamp(mixer - float(i - 1), 0., 1.);\n vec4 c = u_colors[i];\n c.rgb *= c.a;\n gradient = mix(gradient, c, localT);\n }\n\n vec3 color = gradient.rgb * ringShape;\n float opacity = gradient.a * ringShape;\n\n vec3 bgColor = u_colorBack.rgb * u_colorBack.a;\n color = color + bgColor * (1. - opacity);\n opacity = opacity + u_colorBack.a * (1. - opacity);\n\n ${colorBandingFix}\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface SmokeRingUniforms extends ShaderSizingUniforms {\n u_colorBack: [number, number, number, number];\n u_colors: vec4[];\n u_colorsCount: number;\n u_noiseScale: number;\n u_thickness: number;\n u_radius: number;\n u_innerShape: number;\n u_noiseIterations: number;\n u_noiseTexture?: HTMLImageElement;\n}\n\nexport interface SmokeRingParams extends ShaderSizingParams, ShaderMotionParams {\n colorBack?: string;\n colors?: string[];\n noiseScale?: number;\n thickness?: number;\n radius?: number;\n innerShape?: number;\n noiseIterations?: number;\n}\n"],
5
- "mappings": ";;;;;AAEA,SAAS,kCAAsF;AAC/F,SAAS,WAAW,mBAAmB,uBAAuB;AAEvD,MAAM,gBAAgB;AAAA,EAC3B,eAAe;AAAA,EACf,oBAAoB;AACtB;AAeO,MAAM,0BAAkC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAQvB,cAAc,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASjD,0BAA0B;AAAA;AAAA;AAAA;AAAA,EAI1B,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOT,iBAAiB;AAAA;AAAA;AAAA;AAAA,wBAIK,cAAc,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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAwDhC,cAAc,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAe/C,eAAe;AAAA;AAAA;AAAA;AAAA;",
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, textureRandomizerR, colorBandingFix } from '../shader-utils.js';\n\nexport const smokeRingMeta = {\n maxColorCount: 10,\n maxNoiseIterations: 8,\n} as const;\n\n/**\n * Radial gradient with layered FBM displacement, masked with ring shape\n *\n * Uniforms:\n * - u_colorBack (RGBA)\n * - u_colors (vec4[]), u_colorsCount (float used as integer)\n * - u_thickness, u_radius, u_innerShape: ring mask settings\n * - u_noiseIterations, u_noiseScale: how detailed is the noise (number of fbm layers & noise frequency)\n *\n * - u_noiseTexture (sampler2D): pre-computed randomizer source\n */\n\n// language=GLSL\nexport const smokeRingFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform float u_time;\n\nuniform sampler2D u_noiseTexture;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colors[${smokeRingMeta.maxColorCount}];\nuniform float u_colorsCount;\n\nuniform float u_thickness;\nuniform float u_radius;\nuniform float u_innerShape;\nuniform float u_noiseScale;\nuniform float u_noiseIterations;\n\n${sizingVariablesDeclaration}\n\nout vec4 fragColor;\n\n${declarePI}\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(in vec2 n) {\n float total = 0.0, amplitude = .4;\n for (int i = 0; i < ${smokeRingMeta.maxNoiseIterations}; i++) {\n if (i >= int(u_noiseIterations)) break;\n total += valueNoise(n) * amplitude;\n n *= 1.99;\n amplitude *= 0.65;\n }\n return total;\n}\n\nfloat getNoise(vec2 uv, vec2 pUv, float t) {\n float noiseLeft = fbm(pUv + .03 * t);\n pUv.x = mod(pUv.x, u_noiseScale * TWO_PI);\n float noiseRight = fbm(pUv + .03 * t);\n return mix(noiseRight, noiseLeft, smoothstep(-.25, .25, uv.x));\n}\n\nfloat getRingShape(vec2 uv) {\n float radius = u_radius;\n float thickness = u_thickness;\n\n float distance = length(uv);\n float ringValue = 1. - smoothstep(radius, radius + thickness, distance);\n ringValue *= smoothstep(radius - pow(u_innerShape, 3.) * thickness, radius, distance);\n\n return ringValue;\n}\n\nvoid main() {\n vec2 shape_uv = v_objectUV;\n\n float t = u_time;\n\n float cycleDuration = 3.;\n float localTime1 = mod(.1 * t + cycleDuration, 2. * cycleDuration);\n float localTime2 = mod(.1 * t, 2. * cycleDuration);\n float timeBlend = .5 + .5 * sin(.1 * t * PI / cycleDuration - .5 * PI);\n\n float atg = atan(shape_uv.y, shape_uv.x) + .001;\n float l = length(shape_uv);\n vec2 polar_uv1 = vec2(atg, localTime1 - (.5 * l) + 1. / pow(l, .5));\n polar_uv1 *= u_noiseScale;\n float noise1 = getNoise(shape_uv, polar_uv1, t);\n\n vec2 polar_uv2 = vec2(atg, localTime2 - (.5 * l) + 1. / pow(l, .5));\n polar_uv2 *= u_noiseScale;\n float noise2 = getNoise(shape_uv, polar_uv2, t);\n\n float noise = mix(noise1, noise2, timeBlend);\n\n shape_uv *= (.8 + 1.2 * noise);\n\n float ringShape = getRingShape(shape_uv);\n\n float mixer = pow(ringShape, 3.) * (u_colorsCount - 1.);\n vec4 gradient = u_colors[0];\n gradient.rgb *= gradient.a;\n for (int i = 1; i < ${smokeRingMeta.maxColorCount}; i++) {\n if (i >= int(u_colorsCount)) break;\n float localT = clamp(mixer - float(i - 1), 0., 1.);\n vec4 c = u_colors[i];\n c.rgb *= c.a;\n gradient = mix(gradient, c, localT);\n }\n\n vec3 color = gradient.rgb * ringShape;\n float opacity = gradient.a * ringShape;\n\n vec3 bgColor = u_colorBack.rgb * u_colorBack.a;\n color = color + bgColor * (1. - opacity);\n opacity = opacity + u_colorBack.a * (1. - opacity);\n\n ${colorBandingFix}\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface SmokeRingUniforms extends ShaderSizingUniforms {\n u_colorBack: [number, number, number, number];\n u_colors: vec4[];\n u_colorsCount: number;\n u_noiseScale: number;\n u_thickness: number;\n u_radius: number;\n u_innerShape: number;\n u_noiseIterations: number;\n u_noiseTexture?: HTMLImageElement;\n}\n\nexport interface SmokeRingParams extends ShaderSizingParams, ShaderMotionParams {\n colorBack?: string;\n colors?: string[];\n noiseScale?: number;\n thickness?: number;\n radius?: number;\n innerShape?: number;\n noiseIterations?: number;\n}\n"],
5
+ "mappings": ";;;;;AAEA,SAAS,kCAAsF;AAC/F,SAAS,WAAW,oBAAoB,uBAAuB;AAExD,MAAM,gBAAgB;AAAA,EAC3B,eAAe;AAAA,EACf,oBAAoB;AACtB;AAeO,MAAM,0BAAkC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAQvB,cAAc,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASjD,0BAA0B;AAAA;AAAA;AAAA;AAAA,EAI1B,SAAS;AAAA,EACT,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAeI,cAAc,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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAwDhC,cAAc,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAe/C,eAAe;AAAA;AAAA;AAAA;AAAA;",
6
6
  "names": []
7
7
  }
@@ -4,7 +4,7 @@
4
4
  * * * * * * * * * * * * * * * * * * * * * * * * * * * */
5
5
 
6
6
  import { sizingVariablesDeclaration } from "../shader-sizing.js";
7
- import { declareSimplexNoise, declarePI, colorBandingFix } from "../shader-utils.js";
7
+ import { simplexNoise, declarePI, colorBandingFix } from "../shader-utils.js";
8
8
  const spiralFragmentShader = `#version 300 es
9
9
  precision mediump float;
10
10
 
@@ -26,7 +26,7 @@ ${sizingVariablesDeclaration}
26
26
  out vec4 fragColor;
27
27
 
28
28
  ${declarePI}
29
- ${declareSimplexNoise}
29
+ ${simplexNoise}
30
30
 
31
31
  void main() {
32
32
  vec2 uv = 2. * v_patternUV;
@@ -45,7 +45,7 @@ void main() {
45
45
  float stripe = fract(offset);
46
46
 
47
47
  float shape = 2. * abs(stripe - .5);
48
- float width = clamp(u_strokeWidth, .005 * u_strokeTaper, 1.);
48
+ float width = 1. - clamp(u_strokeWidth, .005 * u_strokeTaper, 1.);
49
49
 
50
50
 
51
51
  float wCap = mix(width, (1. - stripe) * (1. - step(.5, stripe)), (1. - clamp(l, 0., 1.)));
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/shaders/spiral.ts"],
4
- "sourcesContent": ["import type { ShaderMotionParams } from '../shader-mount.js';\nimport { sizingVariablesDeclaration, type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { declareSimplexNoise, declarePI, colorBandingFix } from '../shader-utils.js';\n\n/**\n * 2-color spiral shape\n *\n * Uniforms:\n * - u_colorBack, u_colorFront (RGBA)\n * - u_density: spacing falloff to simulate radial perspective (0 = no perspective)\n * - u_strokeWidth: thickness of stroke\n * - u_strokeTaper: stroke loosing width further from center (0 for full visibility)\n * - u_distortion: per-arch shift\n * - u_strokeCap: extra width at the center (no effect on u_strokeWidth = 0.5)\n * - u_noiseFrequency, u_noise: simplex noise distortion over the shape\n * - u_softness: color transition sharpness (0 = hard edge, 1 = smooth fade)\n *\n */\n\n// language=GLSL\nexport const spiralFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform float u_time;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colorFront;\nuniform float u_density;\nuniform float u_distortion;\nuniform float u_strokeWidth;\nuniform float u_strokeCap;\nuniform float u_strokeTaper;\nuniform float u_noise;\nuniform float u_noiseFrequency;\nuniform float u_softness;\n\n${sizingVariablesDeclaration}\n\nout vec4 fragColor;\n\n${declarePI}\n${declareSimplexNoise}\n\nvoid main() {\n vec2 uv = 2. * v_patternUV;\n \n float t = u_time;\n float l = length(uv);\n float density = clamp(u_density, 0., 1.);\n l = pow(l, density);\n float angle = atan(uv.y, uv.x) - t;\n float angleNormalised = angle / TWO_PI;\n\n angleNormalised += .125 * u_noise * snoise(16. * pow(u_noiseFrequency, 3.) * uv);\n\n float offset = l + angleNormalised;\n offset -= u_distortion * (sin(4. * l - .5 * t) * cos(PI + l + .5 * t));\n float stripe = fract(offset);\n \n float shape = 2. * abs(stripe - .5);\n float width = clamp(u_strokeWidth, .005 * u_strokeTaper, 1.);\n\n\n float wCap = mix(width, (1. - stripe) * (1. - step(.5, stripe)), (1. - clamp(l, 0., 1.)));\n width = mix(width, wCap, u_strokeCap);\n width *= (1. - clamp(u_strokeTaper, 0., 1.) * l);\n\n float fw = fwidth(offset);\n float fwMult = 4. - 3. * (smoothstep(.05, .4, 2. * u_strokeWidth) * smoothstep(.05, .4, 2. * (1. - u_strokeWidth)));\n float pixelSize = mix(fwMult * fw, fwidth(shape), clamp(fw, 0., 1.));\n pixelSize = mix(pixelSize, .002, u_strokeCap * (1. - clamp(l, 0., 1.)));\n\n float res = smoothstep(width - pixelSize - u_softness, width + pixelSize + u_softness, shape);\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 vec3 color = fgColor * res;\n float opacity = fgOpacity * res;\n\n color += bgColor * (1. - opacity);\n opacity += bgOpacity * (1. - opacity);\n\n ${colorBandingFix}\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface SpiralUniforms extends ShaderSizingUniforms {\n u_colorBack: [number, number, number, number];\n u_colorFront: [number, number, number, number];\n u_density: number;\n u_distortion: number;\n u_strokeWidth: number;\n u_strokeTaper: number;\n u_strokeCap: number;\n u_noise: number;\n u_noiseFrequency: number;\n u_softness: number;\n}\n\nexport interface SpiralParams extends ShaderSizingParams, ShaderMotionParams {\n colorBack?: string;\n colorFront?: string;\n density?: number;\n distortion?: number;\n strokeWidth?: number;\n strokeTaper?: number;\n strokeCap?: number;\n noise?: number;\n noiseFrequency?: number;\n softness?: number;\n}\n"],
5
- "mappings": ";;;;;AACA,SAAS,kCAAsF;AAC/F,SAAS,qBAAqB,WAAW,uBAAuB;AAkBzD,MAAM,uBAA+B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgB1C,0BAA0B;AAAA;AAAA;AAAA;AAAA,EAI1B,SAAS;AAAA,EACT,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA4CjB,eAAe;AAAA;AAAA;AAAA;AAAA;",
4
+ "sourcesContent": ["import type { ShaderMotionParams } from '../shader-mount.js';\nimport { sizingVariablesDeclaration, type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { simplexNoise, declarePI, colorBandingFix } from '../shader-utils.js';\n\n/**\n * 2-color spiral shape\n *\n * Uniforms:\n * - u_colorBack, u_colorFront (RGBA)\n * - u_density: spacing falloff to simulate radial perspective (0 = no perspective)\n * - u_strokeWidth: thickness of stroke\n * - u_strokeTaper: stroke loosing width further from center (0 for full visibility)\n * - u_distortion: per-arch shift\n * - u_strokeCap: extra width at the center (no effect on u_strokeWidth = 0.5)\n * - u_noiseFrequency, u_noise: simplex noise distortion over the shape\n * - u_softness: color transition sharpness (0 = hard edge, 1 = smooth fade)\n *\n */\n\n// language=GLSL\nexport const spiralFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform float u_time;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colorFront;\nuniform float u_density;\nuniform float u_distortion;\nuniform float u_strokeWidth;\nuniform float u_strokeCap;\nuniform float u_strokeTaper;\nuniform float u_noise;\nuniform float u_noiseFrequency;\nuniform float u_softness;\n\n${sizingVariablesDeclaration}\n\nout vec4 fragColor;\n\n${declarePI}\n${simplexNoise}\n\nvoid main() {\n vec2 uv = 2. * v_patternUV;\n \n float t = u_time;\n float l = length(uv);\n float density = clamp(u_density, 0., 1.);\n l = pow(l, density);\n float angle = atan(uv.y, uv.x) - t;\n float angleNormalised = angle / TWO_PI;\n\n angleNormalised += .125 * u_noise * snoise(16. * pow(u_noiseFrequency, 3.) * uv);\n\n float offset = l + angleNormalised;\n offset -= u_distortion * (sin(4. * l - .5 * t) * cos(PI + l + .5 * t));\n float stripe = fract(offset);\n \n float shape = 2. * abs(stripe - .5);\n float width = 1. - clamp(u_strokeWidth, .005 * u_strokeTaper, 1.);\n\n\n float wCap = mix(width, (1. - stripe) * (1. - step(.5, stripe)), (1. - clamp(l, 0., 1.)));\n width = mix(width, wCap, u_strokeCap);\n width *= (1. - clamp(u_strokeTaper, 0., 1.) * l);\n\n float fw = fwidth(offset);\n float fwMult = 4. - 3. * (smoothstep(.05, .4, 2. * u_strokeWidth) * smoothstep(.05, .4, 2. * (1. - u_strokeWidth)));\n float pixelSize = mix(fwMult * fw, fwidth(shape), clamp(fw, 0., 1.));\n pixelSize = mix(pixelSize, .002, u_strokeCap * (1. - clamp(l, 0., 1.)));\n\n float res = smoothstep(width - pixelSize - u_softness, width + pixelSize + u_softness, shape);\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 vec3 color = fgColor * res;\n float opacity = fgOpacity * res;\n\n color += bgColor * (1. - opacity);\n opacity += bgOpacity * (1. - opacity);\n\n ${colorBandingFix}\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface SpiralUniforms extends ShaderSizingUniforms {\n u_colorBack: [number, number, number, number];\n u_colorFront: [number, number, number, number];\n u_density: number;\n u_distortion: number;\n u_strokeWidth: number;\n u_strokeTaper: number;\n u_strokeCap: number;\n u_noise: number;\n u_noiseFrequency: number;\n u_softness: number;\n}\n\nexport interface SpiralParams extends ShaderSizingParams, ShaderMotionParams {\n colorBack?: string;\n colorFront?: string;\n density?: number;\n distortion?: number;\n strokeWidth?: number;\n strokeTaper?: number;\n strokeCap?: number;\n noise?: number;\n noiseFrequency?: number;\n softness?: number;\n}\n"],
5
+ "mappings": ";;;;;AACA,SAAS,kCAAsF;AAC/F,SAAS,cAAc,WAAW,uBAAuB;AAkBlD,MAAM,uBAA+B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgB1C,0BAA0B;AAAA;AAAA;AAAA;AAAA,EAI1B,SAAS;AAAA,EACT,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA4CV,eAAe;AAAA;AAAA;AAAA;AAAA;",
6
6
  "names": []
7
7
  }
@@ -16,6 +16,7 @@ export declare const staticMeshGradientMeta: {
16
16
  * - u_grainMixer - shape distortion
17
17
  * - u_grainOverlay - post-processing blending
18
18
  *
19
+ * - u_noiseTexture (sampler2D): pre-computed randomizer source
19
20
  */
20
21
  export declare const staticMeshGradientFragmentShader: string;
21
22
  export interface StaticMeshGradientUniforms extends ShaderSizingUniforms {
@@ -29,6 +30,7 @@ export interface StaticMeshGradientUniforms extends ShaderSizingUniforms {
29
30
  u_mixing: number;
30
31
  u_grainMixer: number;
31
32
  u_grainOverlay: number;
33
+ u_noiseTexture?: HTMLImageElement;
32
34
  }
33
35
  export interface StaticMeshGradientParams extends ShaderSizingParams, ShaderMotionParams {
34
36
  colors?: string[];
@@ -7,7 +7,7 @@ import {
7
7
  sizingVariablesDeclaration,
8
8
  sizingUniformsDeclaration
9
9
  } from "../shader-sizing.js";
10
- import { declarePI, declareRotate, declareGrainShape, colorBandingFix } from "../shader-utils.js";
10
+ import { declarePI, rotation2, fiberNoise, colorBandingFix } from "../shader-utils.js";
11
11
  const staticMeshGradientMeta = {
12
12
  maxColorCount: 10
13
13
  };
@@ -26,14 +26,16 @@ uniform float u_mixing;
26
26
  uniform float u_grainMixer;
27
27
  uniform float u_grainOverlay;
28
28
 
29
+ uniform sampler2D u_noiseTexture;
30
+
29
31
  ${sizingVariablesDeclaration}
30
32
  ${sizingUniformsDeclaration}
31
33
 
32
34
  out vec4 fragColor;
33
35
 
34
36
  ${declarePI}
35
- ${declareRotate}
36
- ${declareGrainShape}
37
+ ${rotation2}
38
+ ${fiberNoise}
37
39
 
38
40
 
39
41
  vec2 getPosition(int i, float t) {
@@ -51,8 +53,9 @@ void main() {
51
53
  vec2 uv = v_objectUV;
52
54
  uv += .5;
53
55
 
54
- vec2 grainUV = rotate(v_objectUV, 2.) * 180.;
55
- float grain = grainShape(grainUV, vec2(100.));
56
+ vec2 grainUV = v_objectUV * 120.;
57
+ float grain = fiberNoise(grainUV, vec2(0.));
58
+ float mixerGrain = .2 * u_grainMixer * (grain - .5);
56
59
 
57
60
  float radius = smoothstep(0., 1., length(uv - .5));
58
61
  float center = 1. - radius;
@@ -60,9 +63,7 @@ void main() {
60
63
  uv.x += u_waveX * center / i * cos(TWO_PI * u_waveXShift + i * 2. * smoothstep(.0, 1., uv.y));
61
64
  uv.y += u_waveY * center / i * cos(TWO_PI * u_waveYShift + i * 2. * smoothstep(.0, 1., uv.x));
62
65
  }
63
-
64
- float mixerGrain = .4 * u_grainMixer * (grain - .3);
65
-
66
+
66
67
  vec3 color = vec3(0.);
67
68
  float opacity = 0.;
68
69
  float totalWeight = 0.;
@@ -96,12 +97,12 @@ void main() {
96
97
  color /= totalWeight;
97
98
  opacity /= totalWeight;
98
99
 
99
- float rr = grainShape(grainUV, vec2(0.));
100
- float gg = grainShape(grainUV, vec2(-1.));
101
- float bb = grainShape(grainUV, vec2(2.));
102
- vec3 grainColor = 2. * vec3(rr, gg, bb);
103
- color = mix(color, grainColor, u_grainOverlay * grain);
104
-
100
+ float rr = fiberNoise(rotate(grainUV, 1.), vec2(3.));
101
+ float gg = fiberNoise(rotate(grainUV, 2.) + 10., vec2(-1.));
102
+ float bb = fiberNoise(grainUV - 2., vec2(5.));
103
+ vec3 grainColor = vec3(rr, gg, bb) - 1.;
104
+ color = mix(color, grainColor, .2 * u_grainOverlay);
105
+
105
106
  ${colorBandingFix}
106
107
 
107
108
  fragColor = vec4(color, opacity);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/shaders/static-mesh-gradient.ts"],
4
- "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport {\n sizingVariablesDeclaration,\n sizingUniformsDeclaration,\n type ShaderSizingParams,\n type ShaderSizingUniforms,\n} from '../shader-sizing.js';\nimport { declarePI, declareRotate, declareGrainShape, colorBandingFix } from '../shader-utils.js';\n\nexport const staticMeshGradientMeta = {\n maxColorCount: 10,\n} as const;\n\n/**\n * A composition of N color spots (one per color)\n *\n * Uniforms:\n * - u_colorBack (RGBA)\n * - u_colors (vec4[]), u_colorsCount (float used as integer)\n * - u_waveX, u_waveY - power of sine wave distortion along X and Y axes\n * - u_waveXShift, u_waveYShift - each wave phase offset\n * - u_mixing (0 .. 1, float) - 0 for stepped gradient, 0.5 for smooth transitions, 1 for pronounced color points\n * - u_grainMixer - shape distortion\n * - u_grainOverlay - post-processing blending\n *\n */\n\n// language=GLSL\nexport const staticMeshGradientFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform vec4 u_colors[${staticMeshGradientMeta.maxColorCount}];\nuniform float u_colorsCount;\n\nuniform float u_positions;\nuniform float u_waveX;\nuniform float u_waveXShift;\nuniform float u_waveY;\nuniform float u_waveYShift;\nuniform float u_mixing;\nuniform float u_grainMixer;\nuniform float u_grainOverlay;\n\n${sizingVariablesDeclaration}\n${sizingUniformsDeclaration}\n\nout vec4 fragColor;\n\n${declarePI}\n${declareRotate}\n${declareGrainShape}\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 uv = v_objectUV;\n uv += .5;\n\n vec2 grainUV = rotate(v_objectUV, 2.) * 180.;\n float grain = grainShape(grainUV, vec2(100.));\n\n float radius = smoothstep(0., 1., length(uv - .5));\n float center = 1. - radius;\n for (float i = 1.; i <= 2.; i++) {\n uv.x += u_waveX * center / i * cos(TWO_PI * u_waveXShift + i * 2. * smoothstep(.0, 1., uv.y));\n uv.y += u_waveY * center / i * cos(TWO_PI * u_waveYShift + i * 2. * smoothstep(.0, 1., uv.x));\n }\n\n float mixerGrain = .4 * u_grainMixer * (grain - .3);\n\n vec3 color = vec3(0.);\n float opacity = 0.;\n float totalWeight = 0.;\n float positionSeed = 25. + .33 * u_positions;\n\n for (int i = 0; i < ${staticMeshGradientMeta.maxColorCount}; i++) {\n if (i >= int(u_colorsCount)) break;\n\n vec2 pos = getPosition(i, positionSeed) + mixerGrain;\n float dist = length(uv - pos);\n dist = length(uv - pos);\n\n vec3 colorFraction = u_colors[i].rgb * u_colors[i].a;\n float opacityFraction = u_colors[i].a;\n\n float power = 4.;\n if (u_mixing > .5) {\n power = mix(power, .75, 2. * (u_mixing - .5));\n }\n dist = pow(dist, power);\n\n float w = 1. / (dist + 1e-3);\n if (u_mixing < .5) {\n w = pow(w, mix(mix(.01, 5., clamp(w, 0., 1.)), 1., 2. * u_mixing));\n }\n color += colorFraction * w;\n opacity += opacityFraction * w;\n totalWeight += w;\n }\n\n color /= totalWeight;\n opacity /= totalWeight;\n\n float rr = grainShape(grainUV, vec2(0.));\n float gg = grainShape(grainUV, vec2(-1.));\n float bb = grainShape(grainUV, vec2(2.));\n vec3 grainColor = 2. * vec3(rr, gg, bb);\n color = mix(color, grainColor, u_grainOverlay * grain);\n\n ${colorBandingFix}\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface StaticMeshGradientUniforms extends ShaderSizingUniforms {\n u_colors: vec4[];\n u_colorsCount: number;\n u_positions: number;\n u_waveX: number;\n u_waveXShift: number;\n u_waveY: number;\n u_waveYShift: number;\n u_mixing: number;\n u_grainMixer: number;\n u_grainOverlay: number;\n}\n\nexport interface StaticMeshGradientParams extends ShaderSizingParams, ShaderMotionParams {\n colors?: string[];\n positions?: number;\n waveX?: number;\n waveXShift?: number;\n waveY?: number;\n waveYShift?: number;\n mixing?: number;\n grainMixer?: number;\n grainOverlay?: number;\n}\n"],
5
- "mappings": ";;;;;AAEA;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AACP,SAAS,WAAW,eAAe,mBAAmB,uBAAuB;AAEtE,MAAM,yBAAyB;AAAA,EACpC,eAAe;AACjB;AAiBO,MAAM,mCAA2C;AAAA;AAAA;AAAA,wBAGhC,uBAAuB,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAY1D,0BAA0B;AAAA,EAC1B,yBAAyB;AAAA;AAAA;AAAA;AAAA,EAIzB,SAAS;AAAA,EACT,aAAa;AAAA,EACb,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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAmCK,uBAAuB,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAkCxD,eAAe;AAAA;AAAA;AAAA;AAAA;",
4
+ "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport {\n sizingVariablesDeclaration,\n sizingUniformsDeclaration,\n type ShaderSizingParams,\n type ShaderSizingUniforms,\n} from '../shader-sizing.js';\nimport { declarePI, rotation2, fiberNoise, colorBandingFix } from '../shader-utils.js';\n\nexport const staticMeshGradientMeta = {\n maxColorCount: 10,\n} as const;\n\n/**\n * A composition of N color spots (one per color)\n *\n * Uniforms:\n * - u_colorBack (RGBA)\n * - u_colors (vec4[]), u_colorsCount (float used as integer)\n * - u_waveX, u_waveY - power of sine wave distortion along X and Y axes\n * - u_waveXShift, u_waveYShift - each wave phase offset\n * - u_mixing (0 .. 1, float) - 0 for stepped gradient, 0.5 for smooth transitions, 1 for pronounced color points\n * - u_grainMixer - shape distortion\n * - u_grainOverlay - post-processing blending\n *\n * - u_noiseTexture (sampler2D): pre-computed randomizer source\n */\n\n// language=GLSL\nexport const staticMeshGradientFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform vec4 u_colors[${staticMeshGradientMeta.maxColorCount}];\nuniform float u_colorsCount;\n\nuniform float u_positions;\nuniform float u_waveX;\nuniform float u_waveXShift;\nuniform float u_waveY;\nuniform float u_waveYShift;\nuniform float u_mixing;\nuniform float u_grainMixer;\nuniform float u_grainOverlay;\n\nuniform sampler2D u_noiseTexture;\n\n${sizingVariablesDeclaration}\n${sizingUniformsDeclaration}\n\nout vec4 fragColor;\n\n${declarePI}\n${rotation2}\n${fiberNoise}\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 uv = v_objectUV;\n uv += .5;\n\n vec2 grainUV = v_objectUV * 120.;\n float grain = fiberNoise(grainUV, vec2(0.));\n float mixerGrain = .2 * u_grainMixer * (grain - .5);\n\n float radius = smoothstep(0., 1., length(uv - .5));\n float center = 1. - radius;\n for (float i = 1.; i <= 2.; i++) {\n uv.x += u_waveX * center / i * cos(TWO_PI * u_waveXShift + i * 2. * smoothstep(.0, 1., uv.y));\n uv.y += u_waveY * center / i * cos(TWO_PI * u_waveYShift + i * 2. * smoothstep(.0, 1., uv.x));\n }\n \n vec3 color = vec3(0.);\n float opacity = 0.;\n float totalWeight = 0.;\n float positionSeed = 25. + .33 * u_positions;\n\n for (int i = 0; i < ${staticMeshGradientMeta.maxColorCount}; i++) {\n if (i >= int(u_colorsCount)) break;\n\n vec2 pos = getPosition(i, positionSeed) + mixerGrain;\n float dist = length(uv - pos);\n dist = length(uv - pos);\n\n vec3 colorFraction = u_colors[i].rgb * u_colors[i].a;\n float opacityFraction = u_colors[i].a;\n\n float power = 4.;\n if (u_mixing > .5) {\n power = mix(power, .75, 2. * (u_mixing - .5));\n }\n dist = pow(dist, power);\n\n float w = 1. / (dist + 1e-3);\n if (u_mixing < .5) {\n w = pow(w, mix(mix(.01, 5., clamp(w, 0., 1.)), 1., 2. * u_mixing));\n }\n color += colorFraction * w;\n opacity += opacityFraction * w;\n totalWeight += w;\n }\n\n color /= totalWeight;\n opacity /= totalWeight;\n\n float rr = fiberNoise(rotate(grainUV, 1.), vec2(3.));\n float gg = fiberNoise(rotate(grainUV, 2.) + 10., vec2(-1.));\n float bb = fiberNoise(grainUV - 2., vec2(5.));\n vec3 grainColor = vec3(rr, gg, bb) - 1.;\n color = mix(color, grainColor, .2 * u_grainOverlay);\n \n ${colorBandingFix}\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface StaticMeshGradientUniforms extends ShaderSizingUniforms {\n u_colors: vec4[];\n u_colorsCount: number;\n u_positions: number;\n u_waveX: number;\n u_waveXShift: number;\n u_waveY: number;\n u_waveYShift: number;\n u_mixing: number;\n u_grainMixer: number;\n u_grainOverlay: number;\n u_noiseTexture?: HTMLImageElement;\n}\n\nexport interface StaticMeshGradientParams extends ShaderSizingParams, ShaderMotionParams {\n colors?: string[];\n positions?: number;\n waveX?: number;\n waveXShift?: number;\n waveY?: number;\n waveYShift?: number;\n mixing?: number;\n grainMixer?: number;\n grainOverlay?: number;\n}\n"],
5
+ "mappings": ";;;;;AAEA;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AACP,SAAS,WAAW,WAAW,YAAY,uBAAuB;AAE3D,MAAM,yBAAyB;AAAA,EACpC,eAAe;AACjB;AAkBO,MAAM,mCAA2C;AAAA;AAAA;AAAA,wBAGhC,uBAAuB,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAc1D,0BAA0B;AAAA,EAC1B,yBAAyB;AAAA;AAAA;AAAA;AAAA,EAIzB,SAAS;AAAA,EACT,SAAS;AAAA,EACT,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,wBAkCY,uBAAuB,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAkCxD,eAAe;AAAA;AAAA;AAAA;AAAA;",
6
6
  "names": []
7
7
  }
@@ -18,6 +18,7 @@ export declare const staticRadialGradientMeta: {
18
18
  * - u_grainMixer - shape distortion
19
19
  * - u_grainOverlay - post-processing blending
20
20
  *
21
+ * - u_noiseTexture (sampler2D): pre-computed randomizer source
21
22
  */
22
23
  export declare const staticRadialGradientFragmentShader: string;
23
24
  export interface StaticRadialGradientUniforms extends ShaderSizingUniforms {
@@ -34,6 +35,7 @@ export interface StaticRadialGradientUniforms extends ShaderSizingUniforms {
34
35
  u_distortionFreq: number;
35
36
  u_grainMixer: number;
36
37
  u_grainOverlay: number;
38
+ u_noiseTexture?: HTMLImageElement;
37
39
  }
38
40
  export interface StaticRadialGradientParams extends ShaderSizingParams, ShaderMotionParams {
39
41
  colorBack?: string;
@@ -7,7 +7,7 @@ import {
7
7
  sizingVariablesDeclaration,
8
8
  sizingUniformsDeclaration
9
9
  } from "../shader-sizing.js";
10
- import { declarePI, declareRotate, declareGrainShape, colorBandingFix } from "../shader-utils.js";
10
+ import { declarePI, rotation2, colorBandingFix, fiberNoise } from "../shader-utils.js";
11
11
  const staticRadialGradientMeta = {
12
12
  maxColorCount: 10
13
13
  };
@@ -29,14 +29,16 @@ uniform float u_distortionFreq;
29
29
  uniform float u_grainMixer;
30
30
  uniform float u_grainOverlay;
31
31
 
32
+ uniform sampler2D u_noiseTexture;
33
+
32
34
  ${sizingVariablesDeclaration}
33
35
  ${sizingUniformsDeclaration}
34
36
 
35
37
  out vec4 fragColor;
36
38
 
37
39
  ${declarePI}
38
- ${declareRotate}
39
- ${declareGrainShape}
40
+ ${rotation2}
41
+ ${fiberNoise}
40
42
 
41
43
  void main() {
42
44
  vec2 uv = 2. * v_objectUV;
@@ -95,11 +97,10 @@ void main() {
95
97
  float angle = atan(f_to_uv.y, f_to_uv.x);
96
98
  shape -= pow(u_distortion, 2.) * shape * pow(sin(PI * clamp(length(f_to_uv) - .2 + u_distortionShift, 0., 1.)), 4.) * (sin(u_distortionFreq * angle) + cos(floor(.65 * u_distortionFreq) * angle));
97
99
 
100
+ vec2 grainUV = v_objectUV * 120.;
101
+ float grain = fiberNoise(grainUV, vec2(0.));
102
+ float mixerGrain = .2 * u_grainMixer * (grain - 1.);
98
103
 
99
- vec2 grainUV = rotate(v_objectUV, 2.) * 180.;
100
- float grain = grainShape(grainUV, vec2(100.));
101
-
102
- float mixerGrain = u_grainMixer * (grain - .3);
103
104
  float mixer = shape * u_colorsCount + mixerGrain;
104
105
  vec4 gradient = u_colors[0];
105
106
  gradient.rgb *= gradient.a;
@@ -136,12 +137,13 @@ void main() {
136
137
  vec3 bgColor = u_colorBack.rgb * u_colorBack.a;
137
138
  color = color + bgColor * (1.0 - opacity);
138
139
  opacity = opacity + u_colorBack.a * (1.0 - opacity);
139
-
140
- float rr = grainShape(grainUV, vec2(0.));
141
- float gg = grainShape(grainUV, vec2(-1.));
142
- float bb = grainShape(grainUV, vec2(2.));
143
- vec3 grainColor = 2. * vec3(rr, gg, bb);
144
- color = mix(color, grainColor, u_grainOverlay * grain);
140
+
141
+ float rr = fiberNoise(rotate(grainUV, 1.), vec2(3.));
142
+ float gg = fiberNoise(rotate(grainUV, 2.) + 10., vec2(-1.));
143
+ float bb = fiberNoise(grainUV - 2., vec2(5.));
144
+ vec3 grainColor = vec3(rr, gg, bb) - 1.;
145
+ color = mix(color, grainColor, .2 * u_grainOverlay);
146
+ opacity += u_grainOverlay * grain;
145
147
 
146
148
  ${colorBandingFix}
147
149
 
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/shaders/static-radial-gradient.ts"],
4
- "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport {\n sizingVariablesDeclaration,\n sizingUniformsDeclaration,\n type ShaderSizingParams,\n type ShaderSizingUniforms,\n} from '../shader-sizing.js';\nimport { declarePI, declareRotate, declareGrainShape, colorBandingFix } from '../shader-utils.js';\n\nexport const staticRadialGradientMeta = {\n maxColorCount: 10,\n} as const;\n\n/**\n * N-colors radial gradient\n *\n * Uniforms:\n * - u_colorBack (RGBA)\n * - u_colors (vec4[]), u_colorsCount (float used as integer)\n * - u_radius - circle radius\n * - u_focalDistance, u_focalAngle (float) - gradient center offset to the circle center\n * - u_falloff (-1 .. 1, float) - color points distribution (0 for linear gradient)\n * - u_mixing (0 .. 1, float) - 0 for stepped gradient, 0.5 for smooth transitions, 1 for pronounced color points\n * - u_distortion, u_distortionShift, u_distortionFreq - radial distortion (effective with u_distortion > 0)\n * - u_grainMixer - shape distortion\n * - u_grainOverlay - post-processing blending\n *\n */\n\n// language=GLSL\nexport const staticRadialGradientFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colors[${staticRadialGradientMeta.maxColorCount}];\nuniform float u_colorsCount;\n\nuniform float u_radius;\nuniform float u_focalDistance;\nuniform float u_focalAngle;\nuniform float u_falloff;\nuniform float u_mixing;\nuniform float u_distortion;\nuniform float u_distortionShift;\nuniform float u_distortionFreq;\nuniform float u_grainMixer;\nuniform float u_grainOverlay;\n\n${sizingVariablesDeclaration}\n${sizingUniformsDeclaration}\n\nout vec4 fragColor;\n\n${declarePI}\n${declareRotate}\n${declareGrainShape}\n\nvoid main() {\n vec2 uv = 2. * v_objectUV;\n\n\n vec2 center = vec2(0.);\n float angleRad = radians(u_focalAngle - 90.);\n vec2 focalPoint = vec2(cos(angleRad), sin(angleRad)) * u_focalDistance;\n float radius = u_radius;\n \n vec2 c_to_uv = uv - center;\n vec2 f_to_uv = uv - focalPoint;\n vec2 f_to_c = center - focalPoint;\n float r = length(c_to_uv);\n \n float fragAngle = atan(c_to_uv.y, c_to_uv.x);\n float angleDiff = fragAngle - angleRad;\n angleDiff = mod(angleDiff + PI, TWO_PI) - PI;\n \n float halfAngle = acos(clamp(radius / u_focalDistance, 0.0, 1.0));\n float isInSector = 1.0 - smoothstep(.6 * PI, halfAngle, abs(angleDiff));\n \n float a = dot(f_to_uv, f_to_uv);\n float b = -2.0 * dot(f_to_uv, f_to_c);\n float c = dot(f_to_c, f_to_c) - radius * radius;\n\n float discriminant = b * b - 4.0 * a * c;\n float t = 1.0;\n\n if (discriminant >= 0.0) {\n float sqrtD = sqrt(discriminant);\n float t0 = (-b - sqrtD) / (2.0 * a);\n float t1 = (-b + sqrtD) / (2.0 * a);\n t = max(t0, t1);\n if (t < 0.0) t = 0.0;\n }\n\n float dist = length(f_to_uv);\n float normalized = dist / (length(f_to_uv * t));\n float shape = clamp(normalized, 0.0, 1.0);\n\n float falloffMapped = mix(.2 + .8 * max(0., u_falloff + 1.), mix(1., 15., pow(u_falloff, 2.)), step(.0, u_falloff));\n \n float falloffExp = mix(falloffMapped, 1., shape);\n shape = pow(shape, falloffExp);\n shape = 1. - clamp(shape, 0., 1.);\n\n\n float outerMask = .002;\n float outer = smoothstep(radius + outerMask, radius - outerMask, r);\n outer = mix(outer, 1., isInSector);\n \n shape = mix(0., shape, outer);\n shape *= smoothstep(radius, radius - .01, r);\n\n float angle = atan(f_to_uv.y, f_to_uv.x);\n shape -= pow(u_distortion, 2.) * shape * pow(sin(PI * clamp(length(f_to_uv) - .2 + u_distortionShift, 0., 1.)), 4.) * (sin(u_distortionFreq * angle) + cos(floor(.65 * u_distortionFreq) * angle));\n\n\n vec2 grainUV = rotate(v_objectUV, 2.) * 180.;\n float grain = grainShape(grainUV, vec2(100.));\n\n float mixerGrain = u_grainMixer * (grain - .3);\n float mixer = shape * u_colorsCount + mixerGrain;\n vec4 gradient = u_colors[0];\n gradient.rgb *= gradient.a;\n \n float outerShape = 0.;\n for (int i = 1; i < ${staticRadialGradientMeta.maxColorCount + 1}; i++) {\n if (i > int(u_colorsCount)) break;\n float mLinear = clamp(mixer - float(i - 1), 0.0, 1.0);\n \n float m = 0.;\n float mixing = u_mixing * 3.;\n if (mixing > 2.) {\n float tt = pow(mLinear, 2.);\n m = mix(mLinear, tt, .5 * clamp((mixing - 2.), 0., 1.));\n } else if (mixing > 1.) {\n m = mix(smoothstep(0., 1., mLinear), mLinear, clamp((mixing - 1.), 0., 1.));\n } else {\n float aa = fwidth(mLinear);\n m = smoothstep(.5 - .5 * mixing - aa, .5 + .5 * mixing + aa, mLinear);\n }\n \n if (i == 1) {\n outerShape = m;\n }\n\n vec4 c = u_colors[i - 1];\n c.rgb *= c.a;\n gradient = mix(gradient, c, m);\n }\n\n vec3 color = gradient.rgb * outerShape;\n float opacity = gradient.a * outerShape;\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 float rr = grainShape(grainUV, vec2(0.));\n float gg = grainShape(grainUV, vec2(-1.));\n float bb = grainShape(grainUV, vec2(2.));\n vec3 grainColor = 2. * vec3(rr, gg, bb);\n color = mix(color, grainColor, u_grainOverlay * grain);\n \n ${colorBandingFix}\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface StaticRadialGradientUniforms extends ShaderSizingUniforms {\n u_colorBack: [number, number, number, number];\n u_colors: vec4[];\n u_colorsCount: number;\n u_radius: number;\n u_focalDistance: number;\n u_focalAngle: number;\n u_falloff: number;\n u_mixing: number;\n u_distortion: number;\n u_distortionShift: number;\n u_distortionFreq: number;\n u_grainMixer: number;\n u_grainOverlay: number;\n}\n\nexport interface StaticRadialGradientParams extends ShaderSizingParams, ShaderMotionParams {\n colorBack?: string;\n colors?: string[];\n radius?: number;\n focalDistance?: number;\n focalAngle?: number;\n falloff?: number;\n mixing?: number;\n distortion?: number;\n distortionShift?: number;\n distortionFreq?: number;\n grainMixer?: number;\n grainOverlay?: number;\n}\n"],
5
- "mappings": ";;;;;AAEA;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AACP,SAAS,WAAW,eAAe,mBAAmB,uBAAuB;AAEtE,MAAM,2BAA2B;AAAA,EACtC,eAAe;AACjB;AAmBO,MAAM,qCAA6C;AAAA;AAAA;AAAA;AAAA,wBAIlC,yBAAyB,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAc5D,0BAA0B;AAAA,EAC1B,yBAAyB;AAAA;AAAA;AAAA;AAAA,EAIzB,SAAS;AAAA,EACT,aAAa;AAAA,EACb,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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAqEK,yBAAyB,gBAAgB,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAsC9D,eAAe;AAAA;AAAA;AAAA;AAAA;",
4
+ "sourcesContent": ["import type { vec4 } from '../types.js';\nimport type { ShaderMotionParams } from '../shader-mount.js';\nimport {\n sizingVariablesDeclaration,\n sizingUniformsDeclaration,\n type ShaderSizingParams,\n type ShaderSizingUniforms,\n} from '../shader-sizing.js';\nimport { declarePI, rotation2, colorBandingFix, fiberNoise } from '../shader-utils.js';\n\nexport const staticRadialGradientMeta = {\n maxColorCount: 10,\n} as const;\n\n/**\n * N-colors radial gradient\n *\n * Uniforms:\n * - u_colorBack (RGBA)\n * - u_colors (vec4[]), u_colorsCount (float used as integer)\n * - u_radius - circle radius\n * - u_focalDistance, u_focalAngle (float) - gradient center offset to the circle center\n * - u_falloff (-1 .. 1, float) - color points distribution (0 for linear gradient)\n * - u_mixing (0 .. 1, float) - 0 for stepped gradient, 0.5 for smooth transitions, 1 for pronounced color points\n * - u_distortion, u_distortionShift, u_distortionFreq - radial distortion (effective with u_distortion > 0)\n * - u_grainMixer - shape distortion\n * - u_grainOverlay - post-processing blending\n *\n * - u_noiseTexture (sampler2D): pre-computed randomizer source\n */\n\n// language=GLSL\nexport const staticRadialGradientFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colors[${staticRadialGradientMeta.maxColorCount}];\nuniform float u_colorsCount;\n\nuniform float u_radius;\nuniform float u_focalDistance;\nuniform float u_focalAngle;\nuniform float u_falloff;\nuniform float u_mixing;\nuniform float u_distortion;\nuniform float u_distortionShift;\nuniform float u_distortionFreq;\nuniform float u_grainMixer;\nuniform float u_grainOverlay;\n\nuniform sampler2D u_noiseTexture;\n\n${sizingVariablesDeclaration}\n${sizingUniformsDeclaration}\n\nout vec4 fragColor;\n\n${declarePI}\n${rotation2}\n${fiberNoise}\n\nvoid main() {\n vec2 uv = 2. * v_objectUV;\n\n\n vec2 center = vec2(0.);\n float angleRad = radians(u_focalAngle - 90.);\n vec2 focalPoint = vec2(cos(angleRad), sin(angleRad)) * u_focalDistance;\n float radius = u_radius;\n \n vec2 c_to_uv = uv - center;\n vec2 f_to_uv = uv - focalPoint;\n vec2 f_to_c = center - focalPoint;\n float r = length(c_to_uv);\n \n float fragAngle = atan(c_to_uv.y, c_to_uv.x);\n float angleDiff = fragAngle - angleRad;\n angleDiff = mod(angleDiff + PI, TWO_PI) - PI;\n \n float halfAngle = acos(clamp(radius / u_focalDistance, 0.0, 1.0));\n float isInSector = 1.0 - smoothstep(.6 * PI, halfAngle, abs(angleDiff));\n \n float a = dot(f_to_uv, f_to_uv);\n float b = -2.0 * dot(f_to_uv, f_to_c);\n float c = dot(f_to_c, f_to_c) - radius * radius;\n\n float discriminant = b * b - 4.0 * a * c;\n float t = 1.0;\n\n if (discriminant >= 0.0) {\n float sqrtD = sqrt(discriminant);\n float t0 = (-b - sqrtD) / (2.0 * a);\n float t1 = (-b + sqrtD) / (2.0 * a);\n t = max(t0, t1);\n if (t < 0.0) t = 0.0;\n }\n\n float dist = length(f_to_uv);\n float normalized = dist / (length(f_to_uv * t));\n float shape = clamp(normalized, 0.0, 1.0);\n\n float falloffMapped = mix(.2 + .8 * max(0., u_falloff + 1.), mix(1., 15., pow(u_falloff, 2.)), step(.0, u_falloff));\n \n float falloffExp = mix(falloffMapped, 1., shape);\n shape = pow(shape, falloffExp);\n shape = 1. - clamp(shape, 0., 1.);\n\n\n float outerMask = .002;\n float outer = smoothstep(radius + outerMask, radius - outerMask, r);\n outer = mix(outer, 1., isInSector);\n \n shape = mix(0., shape, outer);\n shape *= smoothstep(radius, radius - .01, r);\n\n float angle = atan(f_to_uv.y, f_to_uv.x);\n shape -= pow(u_distortion, 2.) * shape * pow(sin(PI * clamp(length(f_to_uv) - .2 + u_distortionShift, 0., 1.)), 4.) * (sin(u_distortionFreq * angle) + cos(floor(.65 * u_distortionFreq) * angle));\n\n vec2 grainUV = v_objectUV * 120.;\n float grain = fiberNoise(grainUV, vec2(0.));\n float mixerGrain = .2 * u_grainMixer * (grain - 1.);\n\n float mixer = shape * u_colorsCount + mixerGrain;\n vec4 gradient = u_colors[0];\n gradient.rgb *= gradient.a;\n \n float outerShape = 0.;\n for (int i = 1; i < ${staticRadialGradientMeta.maxColorCount + 1}; i++) {\n if (i > int(u_colorsCount)) break;\n float mLinear = clamp(mixer - float(i - 1), 0.0, 1.0);\n \n float m = 0.;\n float mixing = u_mixing * 3.;\n if (mixing > 2.) {\n float tt = pow(mLinear, 2.);\n m = mix(mLinear, tt, .5 * clamp((mixing - 2.), 0., 1.));\n } else if (mixing > 1.) {\n m = mix(smoothstep(0., 1., mLinear), mLinear, clamp((mixing - 1.), 0., 1.));\n } else {\n float aa = fwidth(mLinear);\n m = smoothstep(.5 - .5 * mixing - aa, .5 + .5 * mixing + aa, mLinear);\n }\n \n if (i == 1) {\n outerShape = m;\n }\n\n vec4 c = u_colors[i - 1];\n c.rgb *= c.a;\n gradient = mix(gradient, c, m);\n }\n\n vec3 color = gradient.rgb * outerShape;\n float opacity = gradient.a * outerShape;\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 float rr = fiberNoise(rotate(grainUV, 1.), vec2(3.));\n float gg = fiberNoise(rotate(grainUV, 2.) + 10., vec2(-1.));\n float bb = fiberNoise(grainUV - 2., vec2(5.));\n vec3 grainColor = vec3(rr, gg, bb) - 1.;\n color = mix(color, grainColor, .2 * u_grainOverlay);\n opacity += u_grainOverlay * grain;\n \n ${colorBandingFix}\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface StaticRadialGradientUniforms extends ShaderSizingUniforms {\n u_colorBack: [number, number, number, number];\n u_colors: vec4[];\n u_colorsCount: number;\n u_radius: number;\n u_focalDistance: number;\n u_focalAngle: number;\n u_falloff: number;\n u_mixing: number;\n u_distortion: number;\n u_distortionShift: number;\n u_distortionFreq: number;\n u_grainMixer: number;\n u_grainOverlay: number;\n u_noiseTexture?: HTMLImageElement;\n}\n\nexport interface StaticRadialGradientParams extends ShaderSizingParams, ShaderMotionParams {\n colorBack?: string;\n colors?: string[];\n radius?: number;\n focalDistance?: number;\n focalAngle?: number;\n falloff?: number;\n mixing?: number;\n distortion?: number;\n distortionShift?: number;\n distortionFreq?: number;\n grainMixer?: number;\n grainOverlay?: number;\n}\n"],
5
+ "mappings": ";;;;;AAEA;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AACP,SAAS,WAAW,WAAW,iBAAiB,kBAAkB;AAE3D,MAAM,2BAA2B;AAAA,EACtC,eAAe;AACjB;AAoBO,MAAM,qCAA6C;AAAA;AAAA;AAAA;AAAA,wBAIlC,yBAAyB,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgB5D,0BAA0B;AAAA,EAC1B,yBAAyB;AAAA;AAAA;AAAA;AAAA,EAIzB,SAAS;AAAA,EACT,SAAS;AAAA,EACT,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,wBAoEY,yBAAyB,gBAAgB,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAuC9D,eAAe;AAAA;AAAA;AAAA;AAAA;",
6
6
  "names": []
7
7
  }
@@ -4,7 +4,7 @@
4
4
  * * * * * * * * * * * * * * * * * * * * * * * * * * * */
5
5
 
6
6
  import { sizingVariablesDeclaration } from "../shader-sizing.js";
7
- import { declareSimplexNoise, declarePI, declareRotate, colorBandingFix } from "../shader-utils.js";
7
+ import { simplexNoise, declarePI, rotation2, colorBandingFix } from "../shader-utils.js";
8
8
  const swirlMeta = {
9
9
  maxColorCount: 10
10
10
  };
@@ -27,8 +27,8 @@ ${sizingVariablesDeclaration}
27
27
  out vec4 fragColor;
28
28
 
29
29
  ${declarePI}
30
- ${declareSimplexNoise}
31
- ${declareRotate}
30
+ ${simplexNoise}
31
+ ${rotation2}
32
32
 
33
33
  void main() {
34
34
  vec2 shape_uv = v_objectUV;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/shaders/swirl.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 { declareSimplexNoise, declarePI, declareRotate, colorBandingFix } from '../shader-utils.js';\n\nexport const swirlMeta = {\n maxColorCount: 10,\n} as const;\n\n/**\n * Twisting radial bands\n *\n * Uniforms:\n * - u_colorBack (RGBA)\n * - u_colors (vec4[]), u_colorsCount (float used as integer)\n * - u_bandCount (float, used as int): number of sectors\n * - u_twist: sectors twist intensity (0 = linear)\n * - u_softness: color transition sharpness (0 = hard edge, 1 = smooth fade)\n * - u_noise, u_noiseFrequency: simplex noise distortion over the shape\n *\n */\n\n// language=GLSL\nexport const swirlFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform float u_time;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colors[${swirlMeta.maxColorCount}];\nuniform float u_colorsCount;\nuniform float u_bandCount;\nuniform float u_twist;\nuniform float u_softness;\nuniform float u_noise;\nuniform float u_noiseFrequency;\n\n${sizingVariablesDeclaration}\n\nout vec4 fragColor;\n\n${declarePI}\n${declareSimplexNoise}\n${declareRotate}\n\nvoid main() {\n vec2 shape_uv = v_objectUV;\n\n float l = length(shape_uv);\n\n float t = u_time;\n\n float angle = ceil(u_bandCount) * atan(shape_uv.y, shape_uv.x) + t;\n float angle_norm = angle / TWO_PI;\n\n float twist = 3. * clamp(u_twist, 0., 1.);\n float offset = pow(l, -twist) + angle_norm;\n\n float shape = fract(offset);\n shape = 1. - abs(2. * shape - 1.);\n shape += u_noise * snoise(15. * pow(u_noiseFrequency, 2.) * shape_uv);\n\n float mid = smoothstep(.2, .4, pow(l, twist));\n shape = mix(0., shape, mid);\n\n float mixer = shape * u_colorsCount;\n vec4 gradient = u_colors[0];\n gradient.rgb *= gradient.a;\n \n float outerShape = 0.;\n for (int i = 1; i < ${swirlMeta.maxColorCount + 1}; i++) {\n if (i > int(u_colorsCount)) break;\n\n float m = clamp(mixer - float(i - 1), 0., 1.);\n float aa = fwidth(m);\n m = smoothstep(.5 - .5 * u_softness - aa, .5 + .5 * u_softness + aa, m);\n\n if (i == 1) {\n outerShape = m;\n }\n\n vec4 c = u_colors[i - 1];\n c.rgb *= c.a;\n gradient = mix(gradient, c, m);\n }\n\n vec3 color = gradient.rgb * outerShape;\n float opacity = gradient.a * outerShape;\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 ${colorBandingFix}\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface SwirlUniforms extends ShaderSizingUniforms {\n u_colorBack: [number, number, number, number];\n u_colors: vec4[];\n u_colorsCount: number;\n u_bandCount: number;\n u_twist: number;\n u_softness: number;\n u_noiseFrequency: number;\n u_noise: number;\n}\n\nexport interface SwirlParams extends ShaderSizingParams, ShaderMotionParams {\n colorBack?: string;\n colors?: string[];\n bandCount?: number;\n twist?: number;\n softness?: number;\n noiseFrequency?: number;\n noise?: number;\n}\n"],
5
- "mappings": ";;;;;AAEA,SAAS,kCAAsF;AAC/F,SAAS,qBAAqB,WAAW,eAAe,uBAAuB;AAExE,MAAM,YAAY;AAAA,EACvB,eAAe;AACjB;AAgBO,MAAM,sBAA8B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAMnB,UAAU,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQ7C,0BAA0B;AAAA;AAAA;AAAA;AAAA,EAI1B,SAAS;AAAA,EACT,mBAAmB;AAAA,EACnB,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBA2BS,UAAU,gBAAgB,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAuB/C,eAAe;AAAA;AAAA;AAAA;AAAA;",
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 { simplexNoise, declarePI, rotation2, colorBandingFix } from '../shader-utils.js';\n\nexport const swirlMeta = {\n maxColorCount: 10,\n} as const;\n\n/**\n * Twisting radial bands\n *\n * Uniforms:\n * - u_colorBack (RGBA)\n * - u_colors (vec4[]), u_colorsCount (float used as integer)\n * - u_bandCount (float, used as int): number of sectors\n * - u_twist: sectors twist intensity (0 = linear)\n * - u_softness: color transition sharpness (0 = hard edge, 1 = smooth fade)\n * - u_noise, u_noiseFrequency: simplex noise distortion over the shape\n *\n */\n\n// language=GLSL\nexport const swirlFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform float u_time;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colors[${swirlMeta.maxColorCount}];\nuniform float u_colorsCount;\nuniform float u_bandCount;\nuniform float u_twist;\nuniform float u_softness;\nuniform float u_noise;\nuniform float u_noiseFrequency;\n\n${sizingVariablesDeclaration}\n\nout vec4 fragColor;\n\n${declarePI}\n${simplexNoise}\n${rotation2}\n\nvoid main() {\n vec2 shape_uv = v_objectUV;\n\n float l = length(shape_uv);\n\n float t = u_time;\n\n float angle = ceil(u_bandCount) * atan(shape_uv.y, shape_uv.x) + t;\n float angle_norm = angle / TWO_PI;\n\n float twist = 3. * clamp(u_twist, 0., 1.);\n float offset = pow(l, -twist) + angle_norm;\n\n float shape = fract(offset);\n shape = 1. - abs(2. * shape - 1.);\n shape += u_noise * snoise(15. * pow(u_noiseFrequency, 2.) * shape_uv);\n\n float mid = smoothstep(.2, .4, pow(l, twist));\n shape = mix(0., shape, mid);\n\n float mixer = shape * u_colorsCount;\n vec4 gradient = u_colors[0];\n gradient.rgb *= gradient.a;\n \n float outerShape = 0.;\n for (int i = 1; i < ${swirlMeta.maxColorCount + 1}; i++) {\n if (i > int(u_colorsCount)) break;\n\n float m = clamp(mixer - float(i - 1), 0., 1.);\n float aa = fwidth(m);\n m = smoothstep(.5 - .5 * u_softness - aa, .5 + .5 * u_softness + aa, m);\n\n if (i == 1) {\n outerShape = m;\n }\n\n vec4 c = u_colors[i - 1];\n c.rgb *= c.a;\n gradient = mix(gradient, c, m);\n }\n\n vec3 color = gradient.rgb * outerShape;\n float opacity = gradient.a * outerShape;\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 ${colorBandingFix}\n\n fragColor = vec4(color, opacity);\n}\n`;\n\nexport interface SwirlUniforms extends ShaderSizingUniforms {\n u_colorBack: [number, number, number, number];\n u_colors: vec4[];\n u_colorsCount: number;\n u_bandCount: number;\n u_twist: number;\n u_softness: number;\n u_noiseFrequency: number;\n u_noise: number;\n}\n\nexport interface SwirlParams extends ShaderSizingParams, ShaderMotionParams {\n colorBack?: string;\n colors?: string[];\n bandCount?: number;\n twist?: number;\n softness?: number;\n noiseFrequency?: number;\n noise?: number;\n}\n"],
5
+ "mappings": ";;;;;AAEA,SAAS,kCAAsF;AAC/F,SAAS,cAAc,WAAW,WAAW,uBAAuB;AAE7D,MAAM,YAAY;AAAA,EACvB,eAAe;AACjB;AAgBO,MAAM,sBAA8B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAMnB,UAAU,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQ7C,0BAA0B;AAAA;AAAA;AAAA;AAAA,EAI1B,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,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,wBA2Ba,UAAU,gBAAgB,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAuB/C,eAAe;AAAA;AAAA;AAAA;AAAA;",
6
6
  "names": []
7
7
  }