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,384 @@
1
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * *
2
+ * Paper Shaders *
3
+ * https://github.com/paper-design/shaders *
4
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * */
5
+
6
+ const heatmapMeta = {
7
+ maxColorCount: 10
8
+ };
9
+ const heatmapFragmentShader = `#version 300 es
10
+ precision highp float;
11
+
12
+ in mediump vec2 v_imageUV;
13
+ in mediump vec2 v_objectUV;
14
+ out vec4 fragColor;
15
+
16
+ uniform sampler2D u_image;
17
+ uniform float u_time;
18
+
19
+ uniform vec4 u_colorBack;
20
+ uniform vec4 u_colors[${heatmapMeta.maxColorCount}];
21
+ uniform float u_colorsCount;
22
+
23
+ uniform float u_angle;
24
+ uniform float u_noise;
25
+ uniform float u_innerGlow;
26
+ uniform float u_outerGlow;
27
+ uniform float u_contour;
28
+
29
+ #define TWO_PI 6.28318530718
30
+ #define PI 3.14159265358979323846
31
+
32
+ float getImgFrame(vec2 uv, float th) {
33
+ float frame = 1.;
34
+ frame *= smoothstep(0., th, uv.y);
35
+ frame *= 1. - smoothstep(1. - th, 1., uv.y);
36
+ frame *= smoothstep(0., th, uv.x);
37
+ frame *= 1. - smoothstep(1. - th, 1., uv.x);
38
+ return frame;
39
+ }
40
+
41
+ float circle(vec2 uv, vec2 c, vec2 r) {
42
+ return 1. - smoothstep(r[0], r[1], length(uv - c));
43
+ }
44
+
45
+ float lst(float edge0, float edge1, float x) {
46
+ return clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
47
+ }
48
+
49
+ float sst(float edge0, float edge1, float x) {
50
+ return smoothstep(edge0, edge1, x);
51
+ }
52
+
53
+ float shadowShape(vec2 uv, float t, float contour) {
54
+ vec2 scaledUV = uv;
55
+
56
+ // base shape tranjectory
57
+ float posY = mix(-1., 2., t);
58
+
59
+ // scaleX when it's moving down
60
+ scaledUV.y -= .5;
61
+ float mainCircleScale = sst(0., .8, posY) * lst(1.4, .9, posY);
62
+ scaledUV *= vec2(1., 1. + 1.5 * mainCircleScale);
63
+ scaledUV.y += .5;
64
+
65
+ // base shape
66
+ float innerR = .4;
67
+ float outerR = 1. - .3 * (sst(.1, .2, t) * (1. - sst(.2, .5, t)));
68
+ float s = circle(scaledUV, vec2(.5, posY - .2), vec2(innerR, outerR));
69
+ float shapeSizing = sst(.2, .3, t) * sst(.6, .3, t);
70
+ s = pow(s, 1.4);
71
+ s *= 1.2;
72
+
73
+ // flat gradient to take over the shadow shape
74
+ float topFlattener = 0.;
75
+ {
76
+ float pos = posY - uv.y;
77
+ float edge = 1.2;
78
+ topFlattener = lst(-.4, 0., pos) * (1. - sst(.0, edge, pos));
79
+ topFlattener = pow(topFlattener, 3.);
80
+ float topFlattenerMixer = (1. - sst(.0, .3, pos));
81
+ s = mix(topFlattener, s, topFlattenerMixer);
82
+ }
83
+
84
+ // apple right circle
85
+ {
86
+ float visibility = sst(.6, .7, t) * (1. - sst(.8, .9, t));
87
+ float angle = -2. -t * TWO_PI;
88
+ float rightCircle = circle(uv, vec2(.95 - .2 * cos(angle), .4 - .1 * sin(angle)), vec2(.15, .3));
89
+ rightCircle *= visibility;
90
+ s = mix(s, 0., rightCircle);
91
+ }
92
+
93
+ // apple top circle
94
+ {
95
+ float topCircle = circle(uv, vec2(.5, .19), vec2(.05, .25));
96
+ topCircle += 2. * contour * circle(uv, vec2(.5, .19), vec2(.2, .5));
97
+ float visibility = .55 * sst(.2, .3, t) * (1. - sst(.3, .45, t));
98
+ topCircle *= visibility;
99
+ s = mix(s, 0., topCircle);
100
+ }
101
+
102
+ float leafMask = circle(uv, vec2(.53, .13), vec2(.08, .19));
103
+ leafMask = mix(leafMask, 0., 1. - sst(.4, .54, uv.x));
104
+ leafMask = mix(0., leafMask, sst(.0, .2, uv.y));
105
+ leafMask *= (sst(.5, 1.1, posY) * sst(1.5, 1.3, posY));
106
+ s += leafMask;
107
+
108
+ // apple bottom circle
109
+ {
110
+ float visibility = sst(.0, .4, t) * (1. - sst(.6, .8, t));
111
+ s = mix(s, 0., visibility * circle(uv, vec2(.52, .92), vec2(.09, .25)));
112
+ }
113
+
114
+ // random balls that are invisible if apple logo is selected
115
+ {
116
+ float pos = sst(.0, .6, t) * (1. - sst(.6, 1., t));
117
+ s = mix(s, .5, circle(uv, vec2(.0, 1.2 - .5 * pos), vec2(.1, .3)));
118
+ s = mix(s, .0, circle(uv, vec2(1., .5 + .5 * pos), vec2(.1, .3)));
119
+
120
+ s = mix(s, 1., circle(uv, vec2(.95, .2 + .2 * sst(.3, .4, t) * sst(.7, .5, t)), vec2(.07, .22)));
121
+ s = mix(s, 1., circle(uv, vec2(.95, .2 + .2 * sst(.3, .4, t) * (1. - sst(.5, .7, t))), vec2(.07, .22)));
122
+ s /= max(1e-4, sst(1., .85, uv.y));
123
+ }
124
+
125
+ s = clamp(0., 1., s);
126
+ return s;
127
+ }
128
+
129
+ float blurEdge3x3(sampler2D tex, vec2 uv, vec2 dudx, vec2 dudy, float radius, float centerSample) {
130
+ vec2 texel = 1.0 / vec2(textureSize(tex, 0));
131
+ vec2 r = radius * texel;
132
+
133
+ float w1 = 1.0, w2 = 2.0, w4 = 4.0;
134
+ float norm = 16.0;
135
+ float sum = w4 * centerSample;
136
+
137
+ sum += w2 * textureGrad(tex, uv + vec2(0.0, -r.y), dudx, dudy).g;
138
+ sum += w2 * textureGrad(tex, uv + vec2(0.0, r.y), dudx, dudy).g;
139
+ sum += w2 * textureGrad(tex, uv + vec2(-r.x, 0.0), dudx, dudy).g;
140
+ sum += w2 * textureGrad(tex, uv + vec2(r.x, 0.0), dudx, dudy).g;
141
+
142
+ sum += w1 * textureGrad(tex, uv + vec2(-r.x, -r.y), dudx, dudy).g;
143
+ sum += w1 * textureGrad(tex, uv + vec2(r.x, -r.y), dudx, dudy).g;
144
+ sum += w1 * textureGrad(tex, uv + vec2(-r.x, r.y), dudx, dudy).g;
145
+ sum += w1 * textureGrad(tex, uv + vec2(r.x, r.y), dudx, dudy).g;
146
+
147
+ return sum / norm;
148
+ }
149
+
150
+ void main() {
151
+ vec2 uv = v_objectUV + .5;
152
+ uv.y = 1. - uv.y;
153
+
154
+ vec2 imgUV = v_imageUV;
155
+ imgUV -= .5;
156
+ imgUV *= 0.5714285714285714;
157
+ imgUV += .5;
158
+ float imgSoftFrame = getImgFrame(imgUV, .03);
159
+
160
+ vec4 img = texture(u_image, imgUV);
161
+ vec2 dudx = dFdx(imgUV);
162
+ vec2 dudy = dFdy(imgUV);
163
+
164
+ if (img.a == 0.) {
165
+ fragColor = u_colorBack;
166
+ return;
167
+ }
168
+
169
+ float t = .1 * u_time;
170
+ t -= .3;
171
+
172
+ float tCopy = t + 1. / 3.;
173
+ float tCopy2 = t + 2. / 3.;
174
+
175
+ t = mod(t, 1.);
176
+ tCopy = mod(tCopy, 1.);
177
+ tCopy2 = mod(tCopy2, 1.);
178
+
179
+ vec2 animationUV = imgUV - vec2(.5);
180
+ float angle = -u_angle * PI / 180.;
181
+ float cosA = cos(angle);
182
+ float sinA = sin(angle);
183
+ animationUV = vec2(
184
+ animationUV.x * cosA - animationUV.y * sinA,
185
+ animationUV.x * sinA + animationUV.y * cosA
186
+ ) + vec2(.5);
187
+
188
+ float shape = img[0];
189
+
190
+ img[1] = blurEdge3x3(u_image, imgUV, dudx, dudy, 8., img[1]);
191
+
192
+ float outerBlur = 1. - mix(1., img[1], shape);
193
+ float innerBlur = mix(img[1], 0., shape);
194
+ float contour = mix(img[2], 0., shape);
195
+
196
+ outerBlur *= imgSoftFrame;
197
+
198
+ float shadow = shadowShape(animationUV, t, innerBlur);
199
+ float shadowCopy = shadowShape(animationUV, tCopy, innerBlur);
200
+ float shadowCopy2 = shadowShape(animationUV, tCopy2, innerBlur);
201
+
202
+ float inner = .8 + .8 * innerBlur;
203
+ inner = mix(inner, 0., shadow);
204
+ inner = mix(inner, 0., shadowCopy);
205
+ inner = mix(inner, 0., shadowCopy2);
206
+
207
+ inner *= mix(0., 2., u_innerGlow);
208
+
209
+ inner += (u_contour * 2.) * contour;
210
+ inner = min(1., inner);
211
+ inner *= (1. - shape);
212
+
213
+ float outer = 0.;
214
+ {
215
+ t *= 3.;
216
+ t = mod(t - .1, 1.);
217
+
218
+ outer = .9 * pow(outerBlur, .8);
219
+ float y = mod(animationUV.y - t, 1.);
220
+ float animatedMask = sst(.3, .65, y) * (1. - sst(.65, 1., y));
221
+ animatedMask = .5 + animatedMask;
222
+ outer *= animatedMask;
223
+ outer *= mix(0., 5., pow(u_outerGlow, 2.));
224
+ outer *= imgSoftFrame;
225
+ }
226
+
227
+ inner = pow(inner, 1.2);
228
+ float heat = clamp(inner + outer, 0., 1.);
229
+
230
+ heat += (.005 + .35 * u_noise) * (fract(sin(dot(uv, vec2(12.9898, 78.233))) * 43758.5453123) - .5);
231
+
232
+ float mixer = heat * u_colorsCount;
233
+ vec4 gradient = u_colors[0];
234
+ gradient.rgb *= gradient.a;
235
+ float outerShape = 0.;
236
+ for (int i = 1; i < ${heatmapMeta.maxColorCount + 1}; i++) {
237
+ if (i > int(u_colorsCount)) break;
238
+ float m = clamp(mixer - float(i - 1), 0., 1.);
239
+ if (i == 1) {
240
+ outerShape = m;
241
+ }
242
+ vec4 c = u_colors[i - 1];
243
+ c.rgb *= c.a;
244
+ gradient = mix(gradient, c, m);
245
+ }
246
+
247
+ vec3 color = gradient.rgb * outerShape;
248
+ float opacity = gradient.a * outerShape;
249
+
250
+ vec3 bgColor = u_colorBack.rgb * u_colorBack.a;
251
+ color = color + bgColor * (1.0 - opacity);
252
+ opacity = opacity + u_colorBack.a * (1.0 - opacity);
253
+
254
+ color += .02 * (fract(sin(dot(uv + 1., vec2(12.9898, 78.233))) * 43758.5453123) - .5);
255
+
256
+ fragColor = vec4(color, opacity);
257
+ }
258
+ `;
259
+ function toProcessedHeatmap(file) {
260
+ const canvas = document.createElement("canvas");
261
+ const canvasSize = 1e3;
262
+ return new Promise((resolve, reject) => {
263
+ const image = new Image();
264
+ image.crossOrigin = "anonymous";
265
+ image.addEventListener("load", () => {
266
+ if (typeof file === "string" ? file.endsWith(".svg") : file.type === "image/svg+xml") {
267
+ image.width = canvasSize;
268
+ image.height = canvasSize;
269
+ }
270
+ const ratio = image.naturalWidth / image.naturalHeight;
271
+ const maxBlur = Math.floor(canvasSize * 0.15);
272
+ const padding = Math.ceil(maxBlur * 2.5);
273
+ let imgWidth = canvasSize;
274
+ let imgHeight = canvasSize;
275
+ if (ratio > 1) {
276
+ imgHeight = Math.floor(canvasSize / ratio);
277
+ } else {
278
+ imgWidth = Math.floor(canvasSize * ratio);
279
+ }
280
+ canvas.width = imgWidth + 2 * padding;
281
+ canvas.height = imgHeight + 2 * padding;
282
+ const ctx = canvas.getContext("2d", { willReadFrequently: true });
283
+ if (!ctx) {
284
+ throw new Error("Failed to get canvas 2d context");
285
+ }
286
+ ctx.fillStyle = "white";
287
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
288
+ ctx.drawImage(image, padding, padding, imgWidth, imgHeight);
289
+ const { width, height } = canvas;
290
+ const srcImageData = ctx.getImageData(0, 0, width, height);
291
+ const src = srcImageData.data;
292
+ const totalPixels = width * height;
293
+ const gray = new Uint8ClampedArray(totalPixels);
294
+ for (let i = 0; i < totalPixels; i++) {
295
+ const px = i * 4;
296
+ const r = src[px] ?? 0;
297
+ const g = src[px + 1] ?? 0;
298
+ const b = src[px + 2] ?? 0;
299
+ gray[i] = 0.299 * r + 0.587 * g + 0.114 * b | 0;
300
+ }
301
+ const bigBlurRadius = maxBlur;
302
+ const innerBlurRadius = Math.max(1, Math.round(0.12 * maxBlur));
303
+ const contourRadius = 5;
304
+ const bigBlurGray = multiPassBlurGray(gray, width, height, bigBlurRadius, 3);
305
+ const innerBlurGray = multiPassBlurGray(gray, width, height, innerBlurRadius, 3);
306
+ const contourGray = multiPassBlurGray(gray, width, height, contourRadius, 1);
307
+ const processedImageData = ctx.createImageData(width, height);
308
+ const dst = processedImageData.data;
309
+ for (let i = 0; i < totalPixels; i++) {
310
+ const px = i * 4;
311
+ dst[px] = contourGray[i] ?? 0;
312
+ dst[px + 1] = bigBlurGray[i] ?? 0;
313
+ dst[px + 2] = innerBlurGray[i] ?? 0;
314
+ dst[px + 3] = 255;
315
+ }
316
+ ctx.putImageData(processedImageData, 0, 0);
317
+ canvas.toBlob((blob) => {
318
+ if (!blob) {
319
+ reject(new Error("Failed to create PNG blob"));
320
+ return;
321
+ }
322
+ resolve({ blob });
323
+ }, "image/png");
324
+ });
325
+ image.addEventListener("error", () => {
326
+ reject(new Error("Failed to load image"));
327
+ });
328
+ image.src = typeof file === "string" ? file : URL.createObjectURL(file);
329
+ });
330
+ }
331
+ function blurGray(gray, width, height, radius) {
332
+ if (radius <= 0) {
333
+ return gray.slice();
334
+ }
335
+ const out = new Uint8ClampedArray(width * height);
336
+ const integral = new Uint32Array(width * height);
337
+ for (let y = 0; y < height; y++) {
338
+ let rowSum = 0;
339
+ for (let x = 0; x < width; x++) {
340
+ const idx = y * width + x;
341
+ const v = gray[idx] ?? 0;
342
+ rowSum += v;
343
+ integral[idx] = rowSum + (y > 0 ? integral[idx - width] ?? 0 : 0);
344
+ }
345
+ }
346
+ for (let y = 0; y < height; y++) {
347
+ const y1 = Math.max(0, y - radius);
348
+ const y2 = Math.min(height - 1, y + radius);
349
+ for (let x = 0; x < width; x++) {
350
+ const x1 = Math.max(0, x - radius);
351
+ const x2 = Math.min(width - 1, x + radius);
352
+ const idxA = y2 * width + x2;
353
+ const idxB = y2 * width + (x1 - 1);
354
+ const idxC = (y1 - 1) * width + x2;
355
+ const idxD = (y1 - 1) * width + (x1 - 1);
356
+ const A = integral[idxA] ?? 0;
357
+ const B = x1 > 0 ? integral[idxB] ?? 0 : 0;
358
+ const C = y1 > 0 ? integral[idxC] ?? 0 : 0;
359
+ const D = x1 > 0 && y1 > 0 ? integral[idxD] ?? 0 : 0;
360
+ const sum = A - B - C + D;
361
+ const area = (x2 - x1 + 1) * (y2 - y1 + 1);
362
+ out[y * width + x] = Math.round(sum / area);
363
+ }
364
+ }
365
+ return out;
366
+ }
367
+ function multiPassBlurGray(gray, width, height, radius, passes) {
368
+ if (radius <= 0 || passes <= 1) {
369
+ return blurGray(gray, width, height, radius);
370
+ }
371
+ let input = gray;
372
+ let tmp = gray;
373
+ for (let p = 0; p < passes; p++) {
374
+ tmp = blurGray(input, width, height, radius);
375
+ input = tmp;
376
+ }
377
+ return tmp;
378
+ }
379
+ export {
380
+ heatmapFragmentShader,
381
+ heatmapMeta,
382
+ toProcessedHeatmap
383
+ };
384
+ //# sourceMappingURL=heatmap.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/shaders/heatmap.ts"],
4
+ "sourcesContent": ["import type { vec4 } from '../types.js';\r\nimport type { ShaderMotionParams } from '../shader-mount.js';\r\nimport type { ShaderSizingParams, ShaderSizingUniforms } from '../shader-sizing.js';\r\n\r\nexport const heatmapMeta = {\r\n maxColorCount: 10,\r\n} as const;\r\n\r\n/**\r\n * A glowing gradient of colors flowing through an input shape.\r\n * The effect creates a smoothly animated wave of intensity across the image.\r\n *\r\n * Fragment shader uniforms:\r\n * - u_time (float): Animation time\r\n * - u_image (sampler2D): Pre-processed source image texture (R = contour, G = outer blur, B = inner blur)\r\n * - u_colorBack (vec4): Background color in RGBA\r\n * - u_colors (vec4[]): Up to 10 heatmap colors in RGBA\r\n * - u_colorsCount (float): Number of active colors\r\n * - u_contour (float): Heat intensity near the edges of the input shape (0 to 1)\r\n * - u_angle (float): Direction of the heatwaves in degrees, needs innerGlow or outerGlow > 0 (0 to 360)\r\n * - u_noise (float): Grain applied across the entire graphic (0 to 1)\r\n * - u_innerGlow (float): Size of the heated area inside the input shape (0 to 1)\r\n * - u_outerGlow (float): Size of the heated area outside the input shape (0 to 1)\r\n *\r\n * Vertex shader outputs (used in fragment shader):\r\n * - v_imageUV (vec2): UV coordinates for sampling the source image, with fit, scale, rotation, and offset applied\r\n * - v_objectUV (vec2): Object box UV coordinates with global sizing (scale, rotation, offsets, etc) applied\r\n *\r\n * Vertex shader uniforms:\r\n * - u_resolution (vec2): Canvas resolution in pixels\r\n * - u_pixelRatio (float): Device pixel ratio\r\n * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)\r\n * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)\r\n * - u_worldWidth (float): Virtual width of the graphic before it's scaled to fit the canvas\r\n * - u_worldHeight (float): Virtual height of the graphic before it's scaled to fit the canvas\r\n * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)\r\n * - u_scale (float): Overall zoom level of the graphics (0.1 to 4)\r\n * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)\r\n * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)\r\n * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)\r\n * - u_imageAspectRatio (float): Aspect ratio of the source image\r\n *\r\n */\r\n\r\n// language=GLSL\r\nexport const heatmapFragmentShader: string = `#version 300 es\r\nprecision highp float;\r\n\r\nin mediump vec2 v_imageUV;\r\nin mediump vec2 v_objectUV;\r\nout vec4 fragColor;\r\n\r\nuniform sampler2D u_image;\r\nuniform float u_time;\r\n\r\nuniform vec4 u_colorBack;\r\nuniform vec4 u_colors[${ heatmapMeta.maxColorCount }];\r\nuniform float u_colorsCount;\r\n\r\nuniform float u_angle;\r\nuniform float u_noise;\r\nuniform float u_innerGlow;\r\nuniform float u_outerGlow;\r\nuniform float u_contour;\r\n\r\n#define TWO_PI 6.28318530718\r\n#define PI 3.14159265358979323846\r\n\r\nfloat getImgFrame(vec2 uv, float th) {\r\n float frame = 1.;\r\n frame *= smoothstep(0., th, uv.y);\r\n frame *= 1. - smoothstep(1. - th, 1., uv.y);\r\n frame *= smoothstep(0., th, uv.x);\r\n frame *= 1. - smoothstep(1. - th, 1., uv.x);\r\n return frame;\r\n}\r\n\r\nfloat circle(vec2 uv, vec2 c, vec2 r) {\r\n return 1. - smoothstep(r[0], r[1], length(uv - c));\r\n}\r\n\r\nfloat lst(float edge0, float edge1, float x) {\r\n return clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);\r\n}\r\n\r\nfloat sst(float edge0, float edge1, float x) {\r\n return smoothstep(edge0, edge1, x);\r\n}\r\n\r\nfloat shadowShape(vec2 uv, float t, float contour) {\r\n vec2 scaledUV = uv;\r\n\r\n // base shape tranjectory\r\n float posY = mix(-1., 2., t);\r\n\r\n // scaleX when it's moving down\r\n scaledUV.y -= .5;\r\n float mainCircleScale = sst(0., .8, posY) * lst(1.4, .9, posY);\r\n scaledUV *= vec2(1., 1. + 1.5 * mainCircleScale);\r\n scaledUV.y += .5;\r\n\r\n // base shape\r\n float innerR = .4;\r\n float outerR = 1. - .3 * (sst(.1, .2, t) * (1. - sst(.2, .5, t)));\r\n float s = circle(scaledUV, vec2(.5, posY - .2), vec2(innerR, outerR));\r\n float shapeSizing = sst(.2, .3, t) * sst(.6, .3, t);\r\n s = pow(s, 1.4);\r\n s *= 1.2;\r\n\r\n // flat gradient to take over the shadow shape\r\n float topFlattener = 0.;\r\n {\r\n float pos = posY - uv.y;\r\n float edge = 1.2;\r\n topFlattener = lst(-.4, 0., pos) * (1. - sst(.0, edge, pos));\r\n topFlattener = pow(topFlattener, 3.);\r\n float topFlattenerMixer = (1. - sst(.0, .3, pos));\r\n s = mix(topFlattener, s, topFlattenerMixer);\r\n }\r\n\r\n // apple right circle\r\n {\r\n float visibility = sst(.6, .7, t) * (1. - sst(.8, .9, t));\r\n float angle = -2. -t * TWO_PI;\r\n float rightCircle = circle(uv, vec2(.95 - .2 * cos(angle), .4 - .1 * sin(angle)), vec2(.15, .3));\r\n rightCircle *= visibility;\r\n s = mix(s, 0., rightCircle);\r\n }\r\n\r\n // apple top circle\r\n {\r\n float topCircle = circle(uv, vec2(.5, .19), vec2(.05, .25));\r\n topCircle += 2. * contour * circle(uv, vec2(.5, .19), vec2(.2, .5));\r\n float visibility = .55 * sst(.2, .3, t) * (1. - sst(.3, .45, t));\r\n topCircle *= visibility;\r\n s = mix(s, 0., topCircle);\r\n }\r\n\r\n float leafMask = circle(uv, vec2(.53, .13), vec2(.08, .19));\r\n leafMask = mix(leafMask, 0., 1. - sst(.4, .54, uv.x));\r\n leafMask = mix(0., leafMask, sst(.0, .2, uv.y));\r\n leafMask *= (sst(.5, 1.1, posY) * sst(1.5, 1.3, posY));\r\n s += leafMask;\r\n\r\n // apple bottom circle\r\n {\r\n float visibility = sst(.0, .4, t) * (1. - sst(.6, .8, t));\r\n s = mix(s, 0., visibility * circle(uv, vec2(.52, .92), vec2(.09, .25)));\r\n }\r\n\r\n // random balls that are invisible if apple logo is selected\r\n {\r\n float pos = sst(.0, .6, t) * (1. - sst(.6, 1., t));\r\n s = mix(s, .5, circle(uv, vec2(.0, 1.2 - .5 * pos), vec2(.1, .3)));\r\n s = mix(s, .0, circle(uv, vec2(1., .5 + .5 * pos), vec2(.1, .3)));\r\n\r\n s = mix(s, 1., circle(uv, vec2(.95, .2 + .2 * sst(.3, .4, t) * sst(.7, .5, t)), vec2(.07, .22)));\r\n s = mix(s, 1., circle(uv, vec2(.95, .2 + .2 * sst(.3, .4, t) * (1. - sst(.5, .7, t))), vec2(.07, .22)));\r\n s /= max(1e-4, sst(1., .85, uv.y));\r\n }\r\n\r\n s = clamp(0., 1., s);\r\n return s;\r\n}\r\n\r\nfloat blurEdge3x3(sampler2D tex, vec2 uv, vec2 dudx, vec2 dudy, float radius, float centerSample) {\r\n vec2 texel = 1.0 / vec2(textureSize(tex, 0));\r\n vec2 r = radius * texel;\r\n\r\n float w1 = 1.0, w2 = 2.0, w4 = 4.0;\r\n float norm = 16.0;\r\n float sum = w4 * centerSample;\r\n\r\n sum += w2 * textureGrad(tex, uv + vec2(0.0, -r.y), dudx, dudy).g;\r\n sum += w2 * textureGrad(tex, uv + vec2(0.0, r.y), dudx, dudy).g;\r\n sum += w2 * textureGrad(tex, uv + vec2(-r.x, 0.0), dudx, dudy).g;\r\n sum += w2 * textureGrad(tex, uv + vec2(r.x, 0.0), dudx, dudy).g;\r\n\r\n sum += w1 * textureGrad(tex, uv + vec2(-r.x, -r.y), dudx, dudy).g;\r\n sum += w1 * textureGrad(tex, uv + vec2(r.x, -r.y), dudx, dudy).g;\r\n sum += w1 * textureGrad(tex, uv + vec2(-r.x, r.y), dudx, dudy).g;\r\n sum += w1 * textureGrad(tex, uv + vec2(r.x, r.y), dudx, dudy).g;\r\n\r\n return sum / norm;\r\n}\r\n\r\nvoid main() {\r\n vec2 uv = v_objectUV + .5;\r\n uv.y = 1. - uv.y;\r\n\r\n vec2 imgUV = v_imageUV;\r\n imgUV -= .5;\r\n imgUV *= 0.5714285714285714;\r\n imgUV += .5;\r\n float imgSoftFrame = getImgFrame(imgUV, .03);\r\n\r\n vec4 img = texture(u_image, imgUV);\r\n vec2 dudx = dFdx(imgUV);\r\n vec2 dudy = dFdy(imgUV);\r\n\r\n if (img.a == 0.) {\r\n fragColor = u_colorBack;\r\n return;\r\n }\r\n\r\n float t = .1 * u_time;\r\n t -= .3;\r\n\r\n float tCopy = t + 1. / 3.;\r\n float tCopy2 = t + 2. / 3.;\r\n\r\n t = mod(t, 1.);\r\n tCopy = mod(tCopy, 1.);\r\n tCopy2 = mod(tCopy2, 1.);\r\n\r\n vec2 animationUV = imgUV - vec2(.5);\r\n float angle = -u_angle * PI / 180.;\r\n float cosA = cos(angle);\r\n float sinA = sin(angle);\r\n animationUV = vec2(\r\n animationUV.x * cosA - animationUV.y * sinA,\r\n animationUV.x * sinA + animationUV.y * cosA\r\n ) + vec2(.5);\r\n\r\n float shape = img[0];\r\n\r\n img[1] = blurEdge3x3(u_image, imgUV, dudx, dudy, 8., img[1]);\r\n\r\n float outerBlur = 1. - mix(1., img[1], shape);\r\n float innerBlur = mix(img[1], 0., shape);\r\n float contour = mix(img[2], 0., shape);\r\n\r\n outerBlur *= imgSoftFrame;\r\n\r\n float shadow = shadowShape(animationUV, t, innerBlur);\r\n float shadowCopy = shadowShape(animationUV, tCopy, innerBlur);\r\n float shadowCopy2 = shadowShape(animationUV, tCopy2, innerBlur);\r\n\r\n float inner = .8 + .8 * innerBlur;\r\n inner = mix(inner, 0., shadow);\r\n inner = mix(inner, 0., shadowCopy);\r\n inner = mix(inner, 0., shadowCopy2);\r\n\r\n inner *= mix(0., 2., u_innerGlow);\r\n\r\n inner += (u_contour * 2.) * contour;\r\n inner = min(1., inner);\r\n inner *= (1. - shape);\r\n\r\n float outer = 0.;\r\n {\r\n t *= 3.;\r\n t = mod(t - .1, 1.);\r\n\r\n outer = .9 * pow(outerBlur, .8);\r\n float y = mod(animationUV.y - t, 1.);\r\n float animatedMask = sst(.3, .65, y) * (1. - sst(.65, 1., y));\r\n animatedMask = .5 + animatedMask;\r\n outer *= animatedMask;\r\n outer *= mix(0., 5., pow(u_outerGlow, 2.));\r\n outer *= imgSoftFrame;\r\n }\r\n\r\n inner = pow(inner, 1.2);\r\n float heat = clamp(inner + outer, 0., 1.);\r\n\r\n heat += (.005 + .35 * u_noise) * (fract(sin(dot(uv, vec2(12.9898, 78.233))) * 43758.5453123) - .5);\r\n\r\n float mixer = heat * u_colorsCount;\r\n vec4 gradient = u_colors[0];\r\n gradient.rgb *= gradient.a;\r\n float outerShape = 0.;\r\n for (int i = 1; i < ${ heatmapMeta.maxColorCount + 1 }; i++) {\r\n if (i > int(u_colorsCount)) break;\r\n float m = clamp(mixer - float(i - 1), 0., 1.);\r\n if (i == 1) {\r\n outerShape = m;\r\n }\r\n vec4 c = u_colors[i - 1];\r\n c.rgb *= c.a;\r\n gradient = mix(gradient, c, m);\r\n }\r\n\r\n vec3 color = gradient.rgb * outerShape;\r\n float opacity = gradient.a * outerShape;\r\n\r\n vec3 bgColor = u_colorBack.rgb * u_colorBack.a;\r\n color = color + bgColor * (1.0 - opacity);\r\n opacity = opacity + u_colorBack.a * (1.0 - opacity);\r\n\r\n color += .02 * (fract(sin(dot(uv + 1., vec2(12.9898, 78.233))) * 43758.5453123) - .5);\r\n\r\n fragColor = vec4(color, opacity);\r\n}\r\n`;\r\n\r\nexport function toProcessedHeatmap(file: File | string): Promise<{ blob: Blob }> {\r\n const canvas = document.createElement('canvas');\r\n const canvasSize = 1000;\r\n\r\n return new Promise((resolve, reject) => {\r\n const image = new Image();\r\n image.crossOrigin = 'anonymous';\r\n\r\n image.addEventListener('load', () => {\r\n if (typeof file === 'string' ? file.endsWith('.svg') : file.type === 'image/svg+xml') {\r\n // Force SVG to load at a high fidelity size if it's an SVG\r\n image.width = canvasSize;\r\n image.height = canvasSize;\r\n }\r\n\r\n const ratio = image.naturalWidth / image.naturalHeight;\r\n\r\n const maxBlur = Math.floor(canvasSize * 0.15);\r\n const padding = Math.ceil(maxBlur * 2.5);\r\n let imgWidth = canvasSize;\r\n let imgHeight = canvasSize;\r\n if (ratio > 1) {\r\n imgHeight = Math.floor(canvasSize / ratio);\r\n } else {\r\n imgWidth = Math.floor(canvasSize * ratio);\r\n }\r\n\r\n canvas.width = imgWidth + 2 * padding;\r\n canvas.height = imgHeight + 2 * padding;\r\n\r\n const ctx = canvas.getContext('2d', { willReadFrequently: true });\r\n if (!ctx) {\r\n throw new Error('Failed to get canvas 2d context');\r\n }\r\n\r\n // 1) Draw original image once, no filters\r\n ctx.fillStyle = 'white';\r\n ctx.fillRect(0, 0, canvas.width, canvas.height);\r\n ctx.drawImage(image, padding, padding, imgWidth, imgHeight);\r\n\r\n const { width, height } = canvas;\r\n const srcImageData = ctx.getImageData(0, 0, width, height);\r\n const src = srcImageData.data; // RGBA\r\n\r\n // 2) Build grayscale array (luma)\r\n const totalPixels = width * height;\r\n const gray = new Uint8ClampedArray(totalPixels);\r\n for (let i = 0; i < totalPixels; i++) {\r\n const px = i * 4;\r\n const r = src[px] ?? 0;\r\n const g = src[px + 1] ?? 0;\r\n const b = src[px + 2] ?? 0;\r\n // Standard luma conversion\r\n gray[i] = (0.299 * r + 0.587 * g + 0.114 * b) | 0;\r\n }\r\n\r\n // 3) Blur grayscale for each \"filter\" you previously used\r\n const bigBlurRadius = maxBlur;\r\n const innerBlurRadius = Math.max(1, Math.round(0.12 * maxBlur));\r\n const contourRadius = 5;\r\n\r\n const bigBlurGray = multiPassBlurGray(gray, width, height, bigBlurRadius, 3);\r\n const innerBlurGray = multiPassBlurGray(gray, width, height, innerBlurRadius, 3);\r\n const contourGray = multiPassBlurGray(gray, width, height, contourRadius, 1);\r\n\r\n // 4) Combine into final ImageData\r\n const processedImageData = ctx.createImageData(width, height);\r\n const dst = processedImageData.data;\r\n\r\n for (let i = 0; i < totalPixels; i++) {\r\n const px = i * 4;\r\n dst[px] = contourGray[i] ?? 0;\r\n dst[px + 1] = bigBlurGray[i] ?? 0;\r\n dst[px + 2] = innerBlurGray[i] ?? 0;\r\n dst[px + 3] = 255;\r\n }\r\n\r\n ctx.putImageData(processedImageData, 0, 0);\r\n\r\n canvas.toBlob((blob) => {\r\n if (!blob) {\r\n reject(new Error('Failed to create PNG blob'));\r\n return;\r\n }\r\n resolve({ blob });\r\n }, 'image/png');\r\n });\r\n\r\n image.addEventListener('error', () => {\r\n reject(new Error('Failed to load image'));\r\n });\r\n\r\n image.src = typeof file === 'string' ? file : URL.createObjectURL(file);\r\n });\r\n}\r\n\r\n/**\r\n * Fast box blur for grayscale images using an integral image.\r\n * gray: Uint8ClampedArray of length width * height\r\n * radius: blur radius in pixels\r\n */\r\nfunction blurGray(gray: Uint8ClampedArray, width: number, height: number, radius: number): Uint8ClampedArray {\r\n if (radius <= 0) {\r\n return gray.slice();\r\n }\r\n\r\n const out = new Uint8ClampedArray(width * height);\r\n const integral = new Uint32Array(width * height);\r\n\r\n // Build integral image\r\n for (let y = 0; y < height; y++) {\r\n let rowSum = 0;\r\n for (let x = 0; x < width; x++) {\r\n const idx = y * width + x;\r\n const v = gray[idx] ?? 0;\r\n rowSum += v;\r\n integral[idx] = rowSum + (y > 0 ? (integral[idx - width] ?? 0) : 0);\r\n }\r\n }\r\n\r\n // Blur using integral image\r\n for (let y = 0; y < height; y++) {\r\n const y1 = Math.max(0, y - radius);\r\n const y2 = Math.min(height - 1, y + radius);\r\n for (let x = 0; x < width; x++) {\r\n const x1 = Math.max(0, x - radius);\r\n const x2 = Math.min(width - 1, x + radius);\r\n\r\n const idxA = y2 * width + x2;\r\n const idxB = y2 * width + (x1 - 1);\r\n const idxC = (y1 - 1) * width + x2;\r\n const idxD = (y1 - 1) * width + (x1 - 1);\r\n\r\n const A = integral[idxA] ?? 0;\r\n const B = x1 > 0 ? (integral[idxB] ?? 0) : 0;\r\n const C = y1 > 0 ? (integral[idxC] ?? 0) : 0;\r\n const D = x1 > 0 && y1 > 0 ? (integral[idxD] ?? 0) : 0;\r\n\r\n const sum = A - B - C + D;\r\n const area = (x2 - x1 + 1) * (y2 - y1 + 1);\r\n out[y * width + x] = Math.round(sum / area);\r\n }\r\n }\r\n\r\n return out;\r\n}\r\n\r\nfunction multiPassBlurGray(\r\n gray: Uint8ClampedArray,\r\n width: number,\r\n height: number,\r\n radius: number,\r\n passes: number\r\n): Uint8ClampedArray {\r\n if (radius <= 0 || passes <= 1) {\r\n return blurGray(gray, width, height, radius);\r\n }\r\n\r\n let input = gray;\r\n let tmp: Uint8ClampedArray = gray;\r\n\r\n for (let p = 0; p < passes; p++) {\r\n tmp = blurGray(input, width, height, radius);\r\n input = tmp;\r\n }\r\n\r\n return tmp;\r\n}\r\n\r\nexport interface HeatmapUniforms extends ShaderSizingUniforms {\r\n u_image: HTMLImageElement | string;\r\n u_contour: number;\r\n u_angle: number;\r\n u_noise: number;\r\n u_innerGlow: number;\r\n u_outerGlow: number;\r\n u_colorBack: [number, number, number, number];\r\n u_colors: vec4[];\r\n u_colorsCount: number;\r\n}\r\n\r\nexport interface HeatmapParams extends ShaderSizingParams, ShaderMotionParams {\r\n image: HTMLImageElement | string;\r\n contour?: number;\r\n angle?: number;\r\n noise?: number;\r\n innerGlow?: number;\r\n outerGlow?: number;\r\n colorBack?: string;\r\n colors?: string[];\r\n}\r\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,64 @@
1
+ import type { ShaderMotionParams } from '../shader-mount.js';
2
+ import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';
3
+ /**
4
+ * A dithering image filter with support for 4 dithering modes and multiple color palettes
5
+ * (2-color, 3-color, and multicolor options, using either predefined colors or colors sampled
6
+ * from the original image).
7
+ *
8
+ * SIZING NOTE: This shader performs sizing in the fragment shader (not vertex shader) to keep
9
+ * u_pxSize in consistent actual pixels. The pixel grid is computed from gl_FragCoord before any
10
+ * transforms, so scaling/rotating only affects the underlying image.
11
+ * No vertex shader outputs (v_imageUV, v_objectUV, etc.) are used.
12
+ *
13
+ * Fragment shader uniforms:
14
+ * - u_resolution (vec2): Canvas resolution in pixels
15
+ * - u_pixelRatio (float): Device pixel ratio
16
+ * - u_originX (float): Reference point for positioning world width in the canvas (0 to 1)
17
+ * - u_originY (float): Reference point for positioning world height in the canvas (0 to 1)
18
+ * - u_fit (float): How to fit the rendered shader into the canvas dimensions (0 = none, 1 = contain, 2 = cover)
19
+ * - u_scale (float): Overall zoom level of the graphics (0.1 to 4)
20
+ * - u_rotation (float): Overall rotation angle of the graphics in degrees (0 to 360)
21
+ * - u_offsetX (float): Horizontal offset of the graphics center (-1 to 1)
22
+ * - u_offsetY (float): Vertical offset of the graphics center (-1 to 1)
23
+ * - u_image (sampler2D): Source image texture
24
+ * - u_imageAspectRatio (float): Aspect ratio of the source image
25
+ * - u_colorFront (vec4): Foreground color in RGBA, needs originalColors off
26
+ * - u_colorBack (vec4): Background color in RGBA, needs originalColors off
27
+ * - u_colorHighlight (vec4): Secondary foreground color in RGBA (set same as colorFront for classic 2-color dithering), needs originalColors off
28
+ * - u_originalColors (bool): Use the original colors of the image instead of the color palette
29
+ * - u_inverted (bool): Inverts the image luminance, doesn't affect the color scheme
30
+ * - u_type (float): Dithering type (1 = random, 2 = 2x2 Bayer, 3 = 4x4 Bayer, 4 = 8x8 Bayer)
31
+ * - u_pxSize (float): Pixel size of dithering grid (0.5 to 20)
32
+ * - u_colorSteps (float): Number of colors to use, applies to both color modes (1 to 7)
33
+ *
34
+ */
35
+ export declare const imageDitheringFragmentShader: string;
36
+ export interface ImageDitheringUniforms extends ShaderSizingUniforms {
37
+ u_image: HTMLImageElement | string;
38
+ u_colorFront: [number, number, number, number];
39
+ u_colorBack: [number, number, number, number];
40
+ u_colorHighlight: [number, number, number, number];
41
+ u_type: (typeof DitheringTypes)[DitheringType];
42
+ u_pxSize: number;
43
+ u_colorSteps: number;
44
+ u_originalColors: boolean;
45
+ u_inverted: boolean;
46
+ }
47
+ export interface ImageDitheringParams extends ShaderSizingParams, ShaderMotionParams {
48
+ image: HTMLImageElement | string;
49
+ colorFront?: string;
50
+ colorBack?: string;
51
+ colorHighlight?: string;
52
+ type?: DitheringType;
53
+ size?: number;
54
+ colorSteps?: number;
55
+ originalColors?: boolean;
56
+ inverted?: boolean;
57
+ }
58
+ export declare const DitheringTypes: {
59
+ readonly random: 1;
60
+ readonly '2x2': 2;
61
+ readonly '4x4': 3;
62
+ readonly '8x8': 4;
63
+ };
64
+ export type DitheringType = keyof typeof DitheringTypes;