shaders-oneshot 0.0.81-shared.1

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 (129) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +5 -0
  3. package/README.md +7 -0
  4. package/dist/empty-pixel.d.ts +1 -0
  5. package/dist/empty-pixel.js +10 -0
  6. package/dist/empty-pixel.js.map +7 -0
  7. package/dist/get-shader-color-from-string.d.ts +3 -0
  8. package/dist/get-shader-color-from-string.js +101 -0
  9. package/dist/get-shader-color-from-string.js.map +7 -0
  10. package/dist/get-shader-color-from-string.test.d.ts +1 -0
  11. package/dist/get-shader-color-from-string.test.js +69 -0
  12. package/dist/get-shader-noise-texture.d.ts +1 -0
  13. package/dist/get-shader-noise-texture.js +18 -0
  14. package/dist/get-shader-noise-texture.js.map +7 -0
  15. package/dist/index.d.ts +68 -0
  16. package/dist/index.js +194 -0
  17. package/dist/index.js.map +7 -0
  18. package/dist/shader-color-spaces.d.ts +6 -0
  19. package/dist/shader-color-spaces.js +96 -0
  20. package/dist/shader-color-spaces.js.map +7 -0
  21. package/dist/shader-mount.d.ts +199 -0
  22. package/dist/shader-mount.js +735 -0
  23. package/dist/shader-mount.js.map +7 -0
  24. package/dist/shader-sizing.d.ts +30 -0
  25. package/dist/shader-sizing.js +38 -0
  26. package/dist/shader-sizing.js.map +7 -0
  27. package/dist/shader-utils.d.ts +10 -0
  28. package/dist/shader-utils.js +131 -0
  29. package/dist/shader-utils.js.map +7 -0
  30. package/dist/shaders/color-panels.d.ts +70 -0
  31. package/dist/shaders/color-panels.js +224 -0
  32. package/dist/shaders/color-panels.js.map +7 -0
  33. package/dist/shaders/dithering.d.ts +62 -0
  34. package/dist/shaders/dithering.js +271 -0
  35. package/dist/shaders/dithering.js.map +7 -0
  36. package/dist/shaders/dot-grid.d.ts +65 -0
  37. package/dist/shaders/dot-grid.js +110 -0
  38. package/dist/shaders/dot-grid.js.map +7 -0
  39. package/dist/shaders/dot-orbit.d.ts +57 -0
  40. package/dist/shaders/dot-orbit.js +123 -0
  41. package/dist/shaders/dot-orbit.js.map +7 -0
  42. package/dist/shaders/fluted-glass.d.ts +112 -0
  43. package/dist/shaders/fluted-glass.js +361 -0
  44. package/dist/shaders/fluted-glass.js.map +7 -0
  45. package/dist/shaders/gem-smoke.d.ts +96 -0
  46. package/dist/shaders/gem-smoke.js +573 -0
  47. package/dist/shaders/gem-smoke.js.map +7 -0
  48. package/dist/shaders/god-rays.d.ts +67 -0
  49. package/dist/shaders/god-rays.js +133 -0
  50. package/dist/shaders/god-rays.js.map +7 -0
  51. package/dist/shaders/grain-gradient.d.ts +80 -0
  52. package/dist/shaders/grain-gradient.js +301 -0
  53. package/dist/shaders/grain-gradient.js.map +7 -0
  54. package/dist/shaders/halftone-cmyk.d.ts +104 -0
  55. package/dist/shaders/halftone-cmyk.js +295 -0
  56. package/dist/shaders/halftone-cmyk.js.map +7 -0
  57. package/dist/shaders/halftone-dots.d.ts +80 -0
  58. package/dist/shaders/halftone-dots.js +321 -0
  59. package/dist/shaders/halftone-dots.js.map +7 -0
  60. package/dist/shaders/heatmap.d.ts +66 -0
  61. package/dist/shaders/heatmap.js +384 -0
  62. package/dist/shaders/heatmap.js.map +7 -0
  63. package/dist/shaders/image-dithering.d.ts +64 -0
  64. package/dist/shaders/image-dithering.js +199 -0
  65. package/dist/shaders/image-dithering.js.map +7 -0
  66. package/dist/shaders/lens-distortion.d.ts +97 -0
  67. package/dist/shaders/lens-distortion.js +276 -0
  68. package/dist/shaders/lens-distortion.js.map +7 -0
  69. package/dist/shaders/liquid-metal.d.ts +89 -0
  70. package/dist/shaders/liquid-metal.js +633 -0
  71. package/dist/shaders/liquid-metal.js.map +7 -0
  72. package/dist/shaders/mesh-gradient.d.ts +52 -0
  73. package/dist/shaders/mesh-gradient.js +131 -0
  74. package/dist/shaders/mesh-gradient.js.map +7 -0
  75. package/dist/shaders/metaballs.d.ts +51 -0
  76. package/dist/shaders/metaballs.js +111 -0
  77. package/dist/shaders/metaballs.js.map +7 -0
  78. package/dist/shaders/neuro-noise.d.ts +47 -0
  79. package/dist/shaders/neuro-noise.js +77 -0
  80. package/dist/shaders/neuro-noise.js.map +7 -0
  81. package/dist/shaders/paper-texture.d.ts +109 -0
  82. package/dist/shaders/paper-texture.js +527 -0
  83. package/dist/shaders/paper-texture.js.map +7 -0
  84. package/dist/shaders/perlin-noise.d.ts +52 -0
  85. package/dist/shaders/perlin-noise.js +167 -0
  86. package/dist/shaders/perlin-noise.js.map +7 -0
  87. package/dist/shaders/pulsing-border.d.ts +98 -0
  88. package/dist/shaders/pulsing-border.js +239 -0
  89. package/dist/shaders/pulsing-border.js.map +7 -0
  90. package/dist/shaders/simplex-noise.d.ts +45 -0
  91. package/dist/shaders/simplex-noise.js +92 -0
  92. package/dist/shaders/simplex-noise.js.map +7 -0
  93. package/dist/shaders/smoke-ring.d.ts +61 -0
  94. package/dist/shaders/smoke-ring.js +133 -0
  95. package/dist/shaders/smoke-ring.js.map +7 -0
  96. package/dist/shaders/spiral.d.ts +61 -0
  97. package/dist/shaders/spiral.js +83 -0
  98. package/dist/shaders/spiral.js.map +7 -0
  99. package/dist/shaders/static-mesh-gradient.d.ts +63 -0
  100. package/dist/shaders/static-mesh-gradient.js +131 -0
  101. package/dist/shaders/static-mesh-gradient.js.map +7 -0
  102. package/dist/shaders/static-radial-gradient.d.ts +72 -0
  103. package/dist/shaders/static-radial-gradient.js +188 -0
  104. package/dist/shaders/static-radial-gradient.js.map +7 -0
  105. package/dist/shaders/swirl.d.ts +63 -0
  106. package/dist/shaders/swirl.js +104 -0
  107. package/dist/shaders/swirl.js.map +7 -0
  108. package/dist/shaders/voronoi.d.ts +65 -0
  109. package/dist/shaders/voronoi.js +139 -0
  110. package/dist/shaders/voronoi.js.map +7 -0
  111. package/dist/shaders/warp.d.ts +70 -0
  112. package/dist/shaders/warp.js +130 -0
  113. package/dist/shaders/warp.js.map +7 -0
  114. package/dist/shaders/water.d.ts +59 -0
  115. package/dist/shaders/water.js +122 -0
  116. package/dist/shaders/water.js.map +7 -0
  117. package/dist/shaders/waves.d.ts +53 -0
  118. package/dist/shaders/waves.js +66 -0
  119. package/dist/shaders/waves.js.map +7 -0
  120. package/dist/shared-webgl-renderer.d.ts +63 -0
  121. package/dist/shared-webgl-renderer.js +262 -0
  122. package/dist/shared-webgl-renderer.js.map +7 -0
  123. package/dist/types.d.ts +3 -0
  124. package/dist/types.js +6 -0
  125. package/dist/types.js.map +7 -0
  126. package/dist/vertex-shader.d.ts +2 -0
  127. package/dist/vertex-shader.js +160 -0
  128. package/dist/vertex-shader.js.map +7 -0
  129. package/package.json +29 -0
@@ -0,0 +1,633 @@
1
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * *
2
+ * Paper Shaders *
3
+ * https://github.com/paper-design/shaders *
4
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * */
5
+
6
+ import {} from "../shader-sizing.js";
7
+ import { declarePI, rotation2, simplexNoise, colorBandingFix } from "../shader-utils.js";
8
+ const liquidMetalFragmentShader = `#version 300 es
9
+ precision mediump float;
10
+
11
+ uniform sampler2D u_image;
12
+
13
+ uniform vec2 u_resolution;
14
+ uniform float u_time;
15
+
16
+ uniform vec4 u_colorBack;
17
+ uniform vec4 u_colorTint;
18
+
19
+ uniform float u_softness;
20
+ uniform float u_repetition;
21
+ uniform float u_shiftRed;
22
+ uniform float u_shiftBlue;
23
+ uniform float u_distortion;
24
+ uniform float u_contour;
25
+ uniform float u_angle;
26
+
27
+ uniform float u_shape;
28
+ uniform bool u_isImage;
29
+
30
+ in vec2 v_objectUV;
31
+ in vec2 v_responsiveUV;
32
+ in vec2 v_responsiveBoxGivenSize;
33
+ in vec2 v_imageUV;
34
+
35
+ out vec4 fragColor;
36
+
37
+ ${declarePI}
38
+ ${rotation2}
39
+ ${simplexNoise}
40
+
41
+ float getColorChanges(float c1, float c2, float stripe_p, vec3 w, float blur, float bump, float tint) {
42
+
43
+ float ch = mix(c2, c1, smoothstep(.0, 2. * blur, stripe_p));
44
+
45
+ float border = w[0];
46
+ ch = mix(ch, c2, smoothstep(border, border + 2. * blur, stripe_p));
47
+
48
+ if (u_isImage == true) {
49
+ bump = smoothstep(.2, .8, bump);
50
+ }
51
+ border = w[0] + .4 * (1. - bump) * w[1];
52
+ ch = mix(ch, c1, smoothstep(border, border + 2. * blur, stripe_p));
53
+
54
+ border = w[0] + .5 * (1. - bump) * w[1];
55
+ ch = mix(ch, c2, smoothstep(border, border + 2. * blur, stripe_p));
56
+
57
+ border = w[0] + w[1];
58
+ ch = mix(ch, c1, smoothstep(border, border + 2. * blur, stripe_p));
59
+
60
+ float gradient_t = (stripe_p - w[0] - w[1]) / w[2];
61
+ float gradient = mix(c1, c2, smoothstep(0., 1., gradient_t));
62
+ ch = mix(ch, gradient, smoothstep(border, border + .5 * blur, stripe_p));
63
+
64
+ // Tint color is applied with color burn blending
65
+ ch = mix(ch, 1. - min(1., (1. - ch) / max(tint, 0.0001)), u_colorTint.a);
66
+ return ch;
67
+ }
68
+
69
+ float getImgFrame(vec2 uv, float th) {
70
+ float frame = 1.;
71
+ frame *= smoothstep(0., th, uv.y);
72
+ frame *= 1.0 - smoothstep(1. - th, 1., uv.y);
73
+ frame *= smoothstep(0., th, uv.x);
74
+ frame *= 1.0 - smoothstep(1. - th, 1., uv.x);
75
+ return frame;
76
+ }
77
+
78
+ float blurEdge3x3(sampler2D tex, vec2 uv, vec2 dudx, vec2 dudy, float radius, float centerSample) {
79
+ vec2 texel = 1.0 / vec2(textureSize(tex, 0));
80
+ vec2 r = radius * texel;
81
+
82
+ float w1 = 1.0, w2 = 2.0, w4 = 4.0;
83
+ float norm = 16.0;
84
+ float sum = w4 * centerSample;
85
+
86
+ sum += w2 * textureGrad(tex, uv + vec2(0.0, -r.y), dudx, dudy).r;
87
+ sum += w2 * textureGrad(tex, uv + vec2(0.0, r.y), dudx, dudy).r;
88
+ sum += w2 * textureGrad(tex, uv + vec2(-r.x, 0.0), dudx, dudy).r;
89
+ sum += w2 * textureGrad(tex, uv + vec2(r.x, 0.0), dudx, dudy).r;
90
+
91
+ sum += w1 * textureGrad(tex, uv + vec2(-r.x, -r.y), dudx, dudy).r;
92
+ sum += w1 * textureGrad(tex, uv + vec2(r.x, -r.y), dudx, dudy).r;
93
+ sum += w1 * textureGrad(tex, uv + vec2(-r.x, r.y), dudx, dudy).r;
94
+ sum += w1 * textureGrad(tex, uv + vec2(r.x, r.y), dudx, dudy).r;
95
+
96
+ return sum / norm;
97
+ }
98
+
99
+ float lst(float edge0, float edge1, float x) {
100
+ return clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
101
+ }
102
+
103
+ void main() {
104
+
105
+ const float firstFrameOffset = 2.8;
106
+ float t = .3 * (u_time + firstFrameOffset);
107
+
108
+ vec2 uv = v_imageUV;
109
+ vec2 dudx = dFdx(v_imageUV);
110
+ vec2 dudy = dFdy(v_imageUV);
111
+ vec4 img = textureGrad(u_image, uv, dudx, dudy);
112
+
113
+ if (u_isImage == false) {
114
+ uv = v_objectUV + .5;
115
+ uv.y = 1. - uv.y;
116
+ }
117
+
118
+ float cycleWidth = u_repetition;
119
+ float edge = 0.;
120
+ float contOffset = 1.;
121
+
122
+ vec2 rotatedUV = uv - vec2(.5);
123
+ float angle = (-u_angle + 70.) * PI / 180.;
124
+ float cosA = cos(angle);
125
+ float sinA = sin(angle);
126
+ rotatedUV = vec2(
127
+ rotatedUV.x * cosA - rotatedUV.y * sinA,
128
+ rotatedUV.x * sinA + rotatedUV.y * cosA
129
+ ) + vec2(.5);
130
+
131
+ // u_contour is applied in 2 separate ranges:
132
+ // - 0 to .4 sets the edge hardness, saturated above .4 (both branches below)
133
+ // - .5 to 1 warps the stripes direction along the edges, inactive below .5 (see u_contour range 2)
134
+ if (u_isImage == true) {
135
+ float edgeRaw = img.r;
136
+ edge = blurEdge3x3(u_image, uv, dudx, dudy, 6., edgeRaw);
137
+ edge = pow(edge, 1.6);
138
+ edge *= mix(0.0, 1.0, smoothstep(0.0, 0.4, u_contour));
139
+ } else {
140
+ if (u_shape < 1.) {
141
+ // full-fill on canvas
142
+ vec2 borderUV = v_responsiveUV + .5;
143
+ float ratio = v_responsiveBoxGivenSize.x / v_responsiveBoxGivenSize.y;
144
+ vec2 mask = min(borderUV, 1. - borderUV);
145
+ vec2 pixel_thickness = min(250. / v_responsiveBoxGivenSize, vec2(.5));
146
+ float maskX = smoothstep(0.0, pixel_thickness.x, mask.x);
147
+ float maskY = smoothstep(0.0, pixel_thickness.y, mask.y);
148
+ maskX = pow(maskX, .25);
149
+ maskY = pow(maskY, .25);
150
+ edge = clamp(1. - maskX * maskY, 0., 1.);
151
+
152
+ uv = v_responsiveUV;
153
+ if (ratio > 1.) {
154
+ uv.y /= ratio;
155
+ } else {
156
+ uv.x *= ratio;
157
+ }
158
+ uv += .5;
159
+ uv.y = 1. - uv.y;
160
+
161
+ cycleWidth *= 2.;
162
+ contOffset = 1.5;
163
+
164
+ } else if (u_shape < 2.) {
165
+ // circle
166
+ vec2 shapeUV = uv - .5;
167
+ shapeUV *= .67;
168
+ edge = pow(clamp(3. * length(shapeUV), 0., 1.), 18.);
169
+ } else if (u_shape < 3.) {
170
+ // daisy
171
+ vec2 shapeUV = uv - .5;
172
+ shapeUV *= 1.68;
173
+
174
+ float r = length(shapeUV) * 2.;
175
+ float a = atan(shapeUV.y, shapeUV.x) + .2;
176
+ r *= (1. + .05 * sin(3. * a + 2. * t));
177
+ float f = abs(cos(a * 3.));
178
+ edge = smoothstep(f, f + .7, r);
179
+ edge *= edge;
180
+
181
+ uv *= .8;
182
+ cycleWidth *= 1.6;
183
+
184
+ } else if (u_shape < 4.) {
185
+ // diamond
186
+ vec2 shapeUV = uv - .5;
187
+ shapeUV = rotate(shapeUV, .25 * PI);
188
+ shapeUV *= 1.42;
189
+ shapeUV += .5;
190
+ vec2 mask = min(shapeUV, 1. - shapeUV);
191
+ vec2 pixel_thickness = vec2(.15);
192
+ float maskX = smoothstep(0.0, pixel_thickness.x, mask.x);
193
+ float maskY = smoothstep(0.0, pixel_thickness.y, mask.y);
194
+ maskX = pow(maskX, .25);
195
+ maskY = pow(maskY, .25);
196
+ edge = clamp(1. - maskX * maskY, 0., 1.);
197
+ } else if (u_shape < 5.) {
198
+ // metaballs
199
+ vec2 shapeUV = uv - .5;
200
+ shapeUV *= 1.3;
201
+ edge = 0.;
202
+ for (int i = 0; i < 5; i++) {
203
+ float fi = float(i);
204
+ float speed = 1.5 + 2./3. * sin(fi * 12.345);
205
+ float angle = -fi * 1.5;
206
+ vec2 dir1 = vec2(cos(angle), sin(angle));
207
+ vec2 dir2 = vec2(cos(angle + 1.57), sin(angle + 1.));
208
+ vec2 traj = .4 * (dir1 * sin(t * speed + fi * 1.23) + dir2 * cos(t * (speed * 0.7) + fi * 2.17));
209
+ float d = length(shapeUV + traj);
210
+ edge += pow(1.0 - clamp(d, 0.0, 1.0), 4.0);
211
+ }
212
+ edge = 1. - smoothstep(.65, .9, edge);
213
+ edge = pow(edge, 4.);
214
+ }
215
+
216
+ edge = mix(smoothstep(.9 - 2. * fwidth(edge), .9, edge), edge, smoothstep(0.0, 0.4, u_contour));
217
+
218
+ }
219
+
220
+ float opacity = 0.;
221
+ if (u_isImage == true) {
222
+ opacity = img.g;
223
+ float frame = getImgFrame(v_imageUV, 0.);
224
+ opacity *= frame;
225
+ } else {
226
+ opacity = 1. - smoothstep(.9 - 2. * fwidth(edge), .9, edge);
227
+ if (u_shape < 2.) {
228
+ edge = 1.2 * edge;
229
+ } else if (u_shape < 5.) {
230
+ edge = 1.8 * pow(edge, 1.5);
231
+ }
232
+ }
233
+
234
+ float diagBLtoTR = rotatedUV.x - rotatedUV.y;
235
+ float diagTLtoBR = rotatedUV.x + rotatedUV.y;
236
+
237
+ vec3 color = vec3(0.);
238
+ vec3 color1 = vec3(.98, 0.98, 1.);
239
+ vec3 color2 = vec3(.1, .1, .1 + .1 * smoothstep(.7, 1.3, diagTLtoBR));
240
+
241
+ vec2 grad_uv = uv - .5;
242
+
243
+ float dist = length(grad_uv + vec2(0., .2 * diagBLtoTR));
244
+ grad_uv = rotate(grad_uv, (.25 - .2 * diagBLtoTR) * PI);
245
+ float direction = grad_uv.x;
246
+
247
+ float bump = pow(1.8 * dist, 1.2);
248
+ bump = 1. - bump;
249
+ bump *= pow(uv.y, .3);
250
+
251
+
252
+ float thin_strip_1_ratio = .12 / cycleWidth * (1. - .4 * bump);
253
+ float thin_strip_2_ratio = .07 / cycleWidth * (1. + .4 * bump);
254
+ float wide_strip_ratio = (1. - thin_strip_1_ratio - thin_strip_2_ratio);
255
+
256
+ float thin_strip_1_width = cycleWidth * thin_strip_1_ratio;
257
+ float thin_strip_2_width = cycleWidth * thin_strip_2_ratio;
258
+
259
+ float noise = snoise(uv - t);
260
+
261
+ edge += (1. - edge) * u_distortion * noise;
262
+
263
+ direction += diagBLtoTR;
264
+ float contour = 0.;
265
+ direction -= 2. * noise * diagBLtoTR * (smoothstep(0., 1., edge) * (1.0 - smoothstep(0., 1., edge)));
266
+ // u_contour range 2
267
+ direction *= mix(1., 1. - edge, smoothstep(.5, 1., u_contour));
268
+ direction -= 1.7 * edge * smoothstep(.5, 1., u_contour);
269
+ direction += .2 * pow(u_contour, 4.) * (1.0 - smoothstep(0., 1., edge));
270
+
271
+ bump *= clamp(pow(uv.y, .1), .3, 1.);
272
+ direction *= (.1 + (1.1 - edge) * bump);
273
+
274
+ direction *= (.4 + .6 * (1.0 - smoothstep(.5, 1., edge)));
275
+ direction += .18 * (smoothstep(.1, .2, uv.y) * (1.0 - smoothstep(.2, .4, uv.y)));
276
+ direction += .03 * (smoothstep(.1, .2, 1. - uv.y) * (1.0 - smoothstep(.2, .4, 1. - uv.y)));
277
+
278
+ direction *= (.5 + .5 * pow(uv.y, 2.));
279
+ direction *= cycleWidth;
280
+ direction -= t;
281
+
282
+
283
+ float colorDispersion = (1. - bump);
284
+ colorDispersion = clamp(colorDispersion, 0., 1.);
285
+ float dispersionRed = colorDispersion;
286
+ dispersionRed += .03 * bump * noise;
287
+ dispersionRed += 5. * (smoothstep(-.1, .2, uv.y) * (1.0 - smoothstep(.1, .5, uv.y))) * (smoothstep(.4, .6, bump) * (1.0 - smoothstep(.4, 1., bump)));
288
+ dispersionRed -= diagBLtoTR;
289
+
290
+ float dispersionBlue = colorDispersion;
291
+ dispersionBlue *= 1.3;
292
+ dispersionBlue += (smoothstep(0., .4, uv.y) * (1.0 - smoothstep(.1, .8, uv.y))) * (smoothstep(.4, .6, bump) * (1.0 - smoothstep(.4, .8, bump)));
293
+ dispersionBlue -= .2 * edge;
294
+
295
+ dispersionRed *= (u_shiftRed / 20.);
296
+ dispersionBlue *= (u_shiftBlue / 20.);
297
+
298
+ float blur = 0.;
299
+ float rExtraBlur = 0.;
300
+ float gExtraBlur = 0.;
301
+ if (u_isImage == true) {
302
+ float softness = 0.05 * u_softness;
303
+ blur = softness + .5 * smoothstep(1., 10., u_repetition) * smoothstep(.0, 1., edge);
304
+ float smallCanvasT = 1.0 - smoothstep(100., 500., min(u_resolution.x, u_resolution.y));
305
+ blur += smallCanvasT * smoothstep(.0, 1., edge);
306
+ rExtraBlur = softness * (0.05 + .1 * (u_shiftRed / 20.) * bump);
307
+ gExtraBlur = softness * 0.05 / max(0.001, abs(1. - diagBLtoTR));
308
+ } else {
309
+ blur = u_softness / 15. + .3 * contour;
310
+ }
311
+
312
+ vec3 w = vec3(thin_strip_1_width, thin_strip_2_width, wide_strip_ratio);
313
+ w[1] -= .02 * smoothstep(.0, 1., edge + bump);
314
+ float stripe_r = fract(direction + dispersionRed);
315
+ float r = getColorChanges(color1.r, color2.r, stripe_r, w, blur + fwidth(stripe_r) + rExtraBlur, bump, u_colorTint.r);
316
+ float stripe_g = fract(direction);
317
+ float g = getColorChanges(color1.g, color2.g, stripe_g, w, blur + fwidth(stripe_g) + gExtraBlur, bump, u_colorTint.g);
318
+ float stripe_b = fract(direction - dispersionBlue);
319
+ float b = getColorChanges(color1.b, color2.b, stripe_b, w, blur + fwidth(stripe_b), bump, u_colorTint.b);
320
+
321
+ color = vec3(r, g, b);
322
+ color *= opacity;
323
+
324
+ vec3 bgColor = u_colorBack.rgb * u_colorBack.a;
325
+ color = color + bgColor * (1. - opacity);
326
+ opacity = opacity + u_colorBack.a * (1. - opacity);
327
+
328
+ ${colorBandingFix}
329
+
330
+ fragColor = vec4(color, opacity);
331
+ }
332
+ `;
333
+ const POISSON_CONFIG_OPTIMIZED = {
334
+ measurePerformance: false,
335
+ // Set to true to see performance metrics
336
+ workingSize: 512,
337
+ // Size to solve Poisson at (will upscale to original size)
338
+ iterations: 40
339
+ // SOR converges ~2-20x faster than standard Gauss-Seidel
340
+ };
341
+ function toProcessedLiquidMetal(file) {
342
+ const canvas = document.createElement("canvas");
343
+ const ctx = canvas.getContext("2d");
344
+ const isBlob = typeof file === "string" && file.startsWith("blob:");
345
+ return new Promise((resolve, reject) => {
346
+ if (!file || !ctx) {
347
+ reject(new Error("Invalid file or canvas context"));
348
+ return;
349
+ }
350
+ const blobContentTypePromise = isBlob && fetch(file).then((res) => res.headers.get("Content-Type"));
351
+ const img = new Image();
352
+ img.crossOrigin = "anonymous";
353
+ const totalStartTime = performance.now();
354
+ img.onload = async () => {
355
+ let isSVG;
356
+ const blobContentType = await blobContentTypePromise;
357
+ if (blobContentType) {
358
+ isSVG = blobContentType === "image/svg+xml";
359
+ } else if (typeof file === "string") {
360
+ isSVG = file.endsWith(".svg") || file.startsWith("data:image/svg+xml");
361
+ } else {
362
+ isSVG = file.type === "image/svg+xml";
363
+ }
364
+ let originalWidth = img.width || img.naturalWidth;
365
+ let originalHeight = img.height || img.naturalHeight;
366
+ if (isSVG) {
367
+ const svgMaxSize = 4096;
368
+ const aspectRatio = originalWidth / originalHeight;
369
+ if (originalWidth > originalHeight) {
370
+ originalWidth = svgMaxSize;
371
+ originalHeight = svgMaxSize / aspectRatio;
372
+ } else {
373
+ originalHeight = svgMaxSize;
374
+ originalWidth = svgMaxSize * aspectRatio;
375
+ }
376
+ img.width = originalWidth;
377
+ img.height = originalHeight;
378
+ }
379
+ const minDimension = Math.min(originalWidth, originalHeight);
380
+ const targetSize = POISSON_CONFIG_OPTIMIZED.workingSize;
381
+ const scaleFactor = targetSize / minDimension;
382
+ const width = Math.round(originalWidth * scaleFactor);
383
+ const height = Math.round(originalHeight * scaleFactor);
384
+ if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {
385
+ console.log(`[Processing Mode]`);
386
+ console.log(` Original: ${originalWidth}\xD7${originalHeight}`);
387
+ console.log(` Working: ${width}\xD7${height} (${(scaleFactor * 100).toFixed(1)}% scale)`);
388
+ if (scaleFactor < 1) {
389
+ console.log(` Speedup: ~${Math.round(1 / (scaleFactor * scaleFactor))}\xD7`);
390
+ }
391
+ }
392
+ canvas.width = originalWidth;
393
+ canvas.height = originalHeight;
394
+ const shapeCanvas = document.createElement("canvas");
395
+ shapeCanvas.width = width;
396
+ shapeCanvas.height = height;
397
+ const shapeCtx = shapeCanvas.getContext("2d");
398
+ shapeCtx.drawImage(img, 0, 0, width, height);
399
+ const startMask = performance.now();
400
+ const shapeImageData = shapeCtx.getImageData(0, 0, width, height);
401
+ const data = shapeImageData.data;
402
+ const shapeMask = new Uint8Array(width * height);
403
+ const boundaryMask = new Uint8Array(width * height);
404
+ let shapePixelCount = 0;
405
+ for (let i = 0, idx = 0; i < data.length; i += 4, idx++) {
406
+ const a = data[i + 3];
407
+ const isShape = a === 0 ? 0 : 1;
408
+ shapeMask[idx] = isShape;
409
+ shapePixelCount += isShape;
410
+ }
411
+ const boundaryIndices = [];
412
+ const interiorIndices = [];
413
+ for (let y = 0; y < height; y++) {
414
+ for (let x = 0; x < width; x++) {
415
+ const idx = y * width + x;
416
+ if (!shapeMask[idx]) continue;
417
+ let isBoundary = false;
418
+ if (x === 0 || x === width - 1 || y === 0 || y === height - 1) {
419
+ isBoundary = true;
420
+ } else {
421
+ isBoundary = !shapeMask[idx - 1] || // left
422
+ !shapeMask[idx + 1] || // right
423
+ !shapeMask[idx - width] || // top
424
+ !shapeMask[idx + width] || // bottom
425
+ !shapeMask[idx - width - 1] || // top-left
426
+ !shapeMask[idx - width + 1] || // top-right
427
+ !shapeMask[idx + width - 1] || // bottom-left
428
+ !shapeMask[idx + width + 1];
429
+ }
430
+ if (isBoundary) {
431
+ boundaryMask[idx] = 1;
432
+ boundaryIndices.push(idx);
433
+ } else {
434
+ interiorIndices.push(idx);
435
+ }
436
+ }
437
+ }
438
+ if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {
439
+ console.log(`[Mask Building] Time: ${(performance.now() - startMask).toFixed(2)}ms`);
440
+ console.log(
441
+ ` Shape pixels: ${shapePixelCount} / ${width * height} (${(shapePixelCount / (width * height) * 100).toFixed(1)}%)`
442
+ );
443
+ console.log(` Interior pixels: ${interiorIndices.length}`);
444
+ console.log(` Boundary pixels: ${boundaryIndices.length}`);
445
+ }
446
+ const sparseData = buildSparseData(
447
+ shapeMask,
448
+ boundaryMask,
449
+ new Uint32Array(interiorIndices),
450
+ new Uint32Array(boundaryIndices),
451
+ width,
452
+ height
453
+ );
454
+ const startSolve = performance.now();
455
+ const u = solvePoissonSparse(sparseData, shapeMask, boundaryMask, width, height);
456
+ if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {
457
+ console.log(`[Poisson Solve] Time: ${(performance.now() - startSolve).toFixed(2)}ms`);
458
+ }
459
+ let maxVal = 0;
460
+ let finalImageData;
461
+ for (let i = 0; i < interiorIndices.length; i++) {
462
+ const idx = interiorIndices[i];
463
+ if (u[idx] > maxVal) maxVal = u[idx];
464
+ }
465
+ const tempCanvas = document.createElement("canvas");
466
+ tempCanvas.width = width;
467
+ tempCanvas.height = height;
468
+ const tempCtx = tempCanvas.getContext("2d");
469
+ const tempImg = tempCtx.createImageData(width, height);
470
+ for (let y = 0; y < height; y++) {
471
+ for (let x = 0; x < width; x++) {
472
+ const idx = y * width + x;
473
+ const px = idx * 4;
474
+ if (!shapeMask[idx]) {
475
+ tempImg.data[px] = 255;
476
+ tempImg.data[px + 1] = 255;
477
+ tempImg.data[px + 2] = 255;
478
+ tempImg.data[px + 3] = 0;
479
+ } else {
480
+ const poissonRatio = u[idx] / maxVal;
481
+ const gray = 255 * (1 - poissonRatio);
482
+ tempImg.data[px] = gray;
483
+ tempImg.data[px + 1] = gray;
484
+ tempImg.data[px + 2] = gray;
485
+ tempImg.data[px + 3] = 255;
486
+ }
487
+ }
488
+ }
489
+ tempCtx.putImageData(tempImg, 0, 0);
490
+ ctx.imageSmoothingEnabled = true;
491
+ ctx.imageSmoothingQuality = "high";
492
+ ctx.drawImage(tempCanvas, 0, 0, width, height, 0, 0, originalWidth, originalHeight);
493
+ const outImg = ctx.getImageData(0, 0, originalWidth, originalHeight);
494
+ const originalCanvas = document.createElement("canvas");
495
+ originalCanvas.width = originalWidth;
496
+ originalCanvas.height = originalHeight;
497
+ const originalCtx = originalCanvas.getContext("2d");
498
+ originalCtx.drawImage(img, 0, 0, originalWidth, originalHeight);
499
+ const originalData = originalCtx.getImageData(0, 0, originalWidth, originalHeight);
500
+ for (let i = 0; i < outImg.data.length; i += 4) {
501
+ const a = originalData.data[i + 3];
502
+ const upscaledAlpha = outImg.data[i + 3];
503
+ if (a === 0) {
504
+ outImg.data[i] = 255;
505
+ outImg.data[i + 1] = 0;
506
+ } else {
507
+ outImg.data[i] = upscaledAlpha === 0 ? 0 : outImg.data[i];
508
+ outImg.data[i + 1] = a;
509
+ }
510
+ outImg.data[i + 2] = 255;
511
+ outImg.data[i + 3] = 255;
512
+ }
513
+ ctx.putImageData(outImg, 0, 0);
514
+ finalImageData = outImg;
515
+ canvas.toBlob((blob) => {
516
+ if (!blob) {
517
+ reject(new Error("Failed to create PNG blob"));
518
+ return;
519
+ }
520
+ if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {
521
+ const totalTime = performance.now() - totalStartTime;
522
+ console.log(`[Total Processing Time] ${totalTime.toFixed(2)}ms`);
523
+ if (scaleFactor < 1) {
524
+ const estimatedFullResTime = totalTime * Math.pow(originalWidth * originalHeight / (width * height), 1.5);
525
+ console.log(`[Estimated time at full resolution] ~${estimatedFullResTime.toFixed(0)}ms`);
526
+ console.log(
527
+ `[Time saved] ~${(estimatedFullResTime - totalTime).toFixed(0)}ms (${Math.round(estimatedFullResTime / totalTime)}\xD7 faster)`
528
+ );
529
+ }
530
+ }
531
+ resolve({
532
+ imageData: finalImageData,
533
+ pngBlob: blob
534
+ });
535
+ }, "image/png");
536
+ };
537
+ img.onerror = () => reject(new Error("Failed to load image"));
538
+ img.src = typeof file === "string" ? file : URL.createObjectURL(file);
539
+ });
540
+ }
541
+ function buildSparseData(shapeMask, boundaryMask, interiorPixels, boundaryPixels, width, height) {
542
+ const pixelCount = interiorPixels.length;
543
+ const neighborIndices = new Int32Array(pixelCount * 4);
544
+ for (let i = 0; i < pixelCount; i++) {
545
+ const idx = interiorPixels[i];
546
+ const x = idx % width;
547
+ const y = Math.floor(idx / width);
548
+ neighborIndices[i * 4 + 0] = x < width - 1 && shapeMask[idx + 1] ? idx + 1 : -1;
549
+ neighborIndices[i * 4 + 1] = x > 0 && shapeMask[idx - 1] ? idx - 1 : -1;
550
+ neighborIndices[i * 4 + 2] = y > 0 && shapeMask[idx - width] ? idx - width : -1;
551
+ neighborIndices[i * 4 + 3] = y < height - 1 && shapeMask[idx + width] ? idx + width : -1;
552
+ }
553
+ return {
554
+ interiorPixels,
555
+ boundaryPixels,
556
+ pixelCount,
557
+ neighborIndices
558
+ };
559
+ }
560
+ function solvePoissonSparse(sparseData, shapeMask, boundaryMask, width, height) {
561
+ const ITERATIONS = POISSON_CONFIG_OPTIMIZED.iterations;
562
+ const C = 0.01;
563
+ const u = new Float32Array(width * height);
564
+ const { interiorPixels, neighborIndices, pixelCount } = sparseData;
565
+ const startTime = performance.now();
566
+ const omega = 1.9;
567
+ const redPixels = [];
568
+ const blackPixels = [];
569
+ for (let i = 0; i < pixelCount; i++) {
570
+ const idx = interiorPixels[i];
571
+ const x = idx % width;
572
+ const y = Math.floor(idx / width);
573
+ if ((x + y) % 2 === 0) {
574
+ redPixels.push(i);
575
+ } else {
576
+ blackPixels.push(i);
577
+ }
578
+ }
579
+ for (let iter = 0; iter < ITERATIONS; iter++) {
580
+ for (const i of redPixels) {
581
+ const idx = interiorPixels[i];
582
+ const eastIdx = neighborIndices[i * 4 + 0];
583
+ const westIdx = neighborIndices[i * 4 + 1];
584
+ const northIdx = neighborIndices[i * 4 + 2];
585
+ const southIdx = neighborIndices[i * 4 + 3];
586
+ let sumN = 0;
587
+ if (eastIdx >= 0) sumN += u[eastIdx];
588
+ if (westIdx >= 0) sumN += u[westIdx];
589
+ if (northIdx >= 0) sumN += u[northIdx];
590
+ if (southIdx >= 0) sumN += u[southIdx];
591
+ const newValue = (C + sumN) / 4;
592
+ u[idx] = omega * newValue + (1 - omega) * u[idx];
593
+ }
594
+ for (const i of blackPixels) {
595
+ const idx = interiorPixels[i];
596
+ const eastIdx = neighborIndices[i * 4 + 0];
597
+ const westIdx = neighborIndices[i * 4 + 1];
598
+ const northIdx = neighborIndices[i * 4 + 2];
599
+ const southIdx = neighborIndices[i * 4 + 3];
600
+ let sumN = 0;
601
+ if (eastIdx >= 0) sumN += u[eastIdx];
602
+ if (westIdx >= 0) sumN += u[westIdx];
603
+ if (northIdx >= 0) sumN += u[northIdx];
604
+ if (southIdx >= 0) sumN += u[southIdx];
605
+ const newValue = (C + sumN) / 4;
606
+ u[idx] = omega * newValue + (1 - omega) * u[idx];
607
+ }
608
+ }
609
+ if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {
610
+ const elapsed = performance.now() - startTime;
611
+ console.log(`[Optimized Poisson Solver (SOR \u03C9=${omega})]`);
612
+ console.log(` Working size: ${width}\xD7${height}`);
613
+ console.log(` Iterations: ${ITERATIONS}`);
614
+ console.log(` Time: ${elapsed.toFixed(2)}ms`);
615
+ console.log(` Interior pixels processed: ${pixelCount}`);
616
+ console.log(` Speed: ${(ITERATIONS * pixelCount / (elapsed * 1e3)).toFixed(2)} Mpixels/sec`);
617
+ }
618
+ return u;
619
+ }
620
+ const LiquidMetalShapes = {
621
+ none: 0,
622
+ circle: 1,
623
+ daisy: 2,
624
+ diamond: 3,
625
+ metaballs: 4
626
+ };
627
+ export {
628
+ LiquidMetalShapes,
629
+ POISSON_CONFIG_OPTIMIZED,
630
+ liquidMetalFragmentShader,
631
+ toProcessedLiquidMetal
632
+ };
633
+ //# sourceMappingURL=liquid-metal.js.map