@paper-design/shaders 0.0.57 → 0.0.58-next.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.
- package/dist/index.d.ts +1 -2
- package/dist/index.js +6 -4
- package/dist/index.js.map +2 -2
- package/dist/shaders/liquid-metal.d.ts +17 -5
- package/dist/shaders/liquid-metal.js +465 -80
- package/dist/shaders/liquid-metal.js.map +2 -2
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -35,8 +35,6 @@ export { swirlMeta, swirlFragmentShader, type SwirlParams, type SwirlUniforms }
|
|
|
35
35
|
export { ditheringFragmentShader, DitheringShapes, DitheringTypes, type DitheringParams, type DitheringUniforms, type DitheringShape, type DitheringType, } from './shaders/dithering.js';
|
|
36
36
|
/** N-color gradient applied to the abstract shapes w/ grainy overlay & distortion */
|
|
37
37
|
export { grainGradientFragmentShader, grainGradientMeta, GrainGradientShapes, type GrainGradientParams, type GrainGradientUniforms, type GrainGradientShape, } from './shaders/grain-gradient.js';
|
|
38
|
-
/** Liquid metal effect applied to the abstract shapes */
|
|
39
|
-
export { liquidMetalFragmentShader, LiquidMetalShapes, type LiquidMetalParams, type LiquidMetalUniforms, type LiquidMetalShape, } from './shaders/liquid-metal.js';
|
|
40
38
|
/** Border with configurable size & radius ade of rotating pulsing light spots */
|
|
41
39
|
export { pulsingBorderMeta, pulsingBorderFragmentShader, PulsingBorderAspectRatios, type PulsingBorderParams, type PulsingBorderUniforms, type PulsingBorderAspectRatio, } from './shaders/pulsing-border.js';
|
|
42
40
|
/** */
|
|
@@ -48,6 +46,7 @@ export { waterFragmentShader, type WaterParams, type WaterUniforms } from './sha
|
|
|
48
46
|
export { flutedGlassFragmentShader, GlassDistortionShapes, GlassGridShapes, type GlassDistortionShape, type GlassGridShape, type FlutedGlassParams, type FlutedGlassUniforms, } from './shaders/fluted-glass.js';
|
|
49
47
|
export { imageDitheringFragmentShader, type ImageDitheringParams, type ImageDitheringUniforms, } from './shaders/image-dithering.js';
|
|
50
48
|
export { heatmapMeta, heatmapFragmentShader, toProcessedHeatmap, type HeatmapParams, type HeatmapUniforms, } from './shaders/heatmap.js';
|
|
49
|
+
export { liquidMetalFragmentShader, LiquidMetalShapes, toProcessedLiquidMetal, type LiquidMetalShape, type LiquidMetalParams, type LiquidMetalUniforms, } from './shaders/liquid-metal.js';
|
|
51
50
|
export { getShaderColorFromString } from './get-shader-color-from-string.js';
|
|
52
51
|
export { getShaderNoiseTexture } from './get-shader-noise-texture.js';
|
|
53
52
|
export { getEmptyPixel } from './get-empty-pixel.js';
|
package/dist/index.js
CHANGED
|
@@ -55,10 +55,6 @@ import {
|
|
|
55
55
|
grainGradientMeta,
|
|
56
56
|
GrainGradientShapes
|
|
57
57
|
} from "./shaders/grain-gradient.js";
|
|
58
|
-
import {
|
|
59
|
-
liquidMetalFragmentShader,
|
|
60
|
-
LiquidMetalShapes
|
|
61
|
-
} from "./shaders/liquid-metal.js";
|
|
62
58
|
import {
|
|
63
59
|
pulsingBorderMeta,
|
|
64
60
|
pulsingBorderFragmentShader,
|
|
@@ -93,6 +89,11 @@ import {
|
|
|
93
89
|
heatmapFragmentShader,
|
|
94
90
|
toProcessedHeatmap
|
|
95
91
|
} from "./shaders/heatmap.js";
|
|
92
|
+
import {
|
|
93
|
+
liquidMetalFragmentShader,
|
|
94
|
+
LiquidMetalShapes,
|
|
95
|
+
toProcessedLiquidMetal
|
|
96
|
+
} from "./shaders/liquid-metal.js";
|
|
96
97
|
import { getShaderColorFromString } from "./get-shader-color-from-string.js";
|
|
97
98
|
import { getShaderNoiseTexture } from "./get-shader-noise-texture.js";
|
|
98
99
|
import { getEmptyPixel } from "./get-empty-pixel.js";
|
|
@@ -150,6 +151,7 @@ export {
|
|
|
150
151
|
swirlFragmentShader,
|
|
151
152
|
swirlMeta,
|
|
152
153
|
toProcessedHeatmap,
|
|
154
|
+
toProcessedLiquidMetal,
|
|
153
155
|
voronoiFragmentShader,
|
|
154
156
|
voronoiMeta,
|
|
155
157
|
warpFragmentShader,
|
package/dist/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["/** The core Shader Mount class. Pass it a parent element and a fragment shader to get started. */\nexport { ShaderMount, isPaperShaderElement } from './shader-mount.js';\nexport type {\n PaperShaderElement,\n ShaderMotionParams,\n ShaderMountUniforms,\n ShaderPreset,\n ImageShaderPreset,\n} from './shader-mount.js';\n\n/** Shader sizing options and uniforms */\nexport {\n defaultObjectSizing,\n defaultPatternSizing,\n ShaderFitOptions,\n type ShaderFit,\n type ShaderSizingParams,\n type ShaderSizingUniforms,\n} from './shader-sizing.js';\n\n// ----- Mesh gradient ----- //\n/** A shader that renders a mesh gradient with a rotating noise pattern and several layers of fractal noise */\nexport {\n meshGradientFragmentShader,\n meshGradientMeta,\n type MeshGradientParams,\n type MeshGradientUniforms,\n} from './shaders/mesh-gradient.js';\n\n// ----- Smoke ring ----- //\n/** Fractional Brownian motion (fBm) noise over the polar coordinates, masked with ring shape */\nexport {\n smokeRingMeta,\n smokeRingFragmentShader,\n type SmokeRingParams,\n type SmokeRingUniforms,\n} from './shaders/smoke-ring.js';\n\n// ----- Neuro noise ----- //\n/** A shader rendering a fractal-like structure made of several layers of since-arches */\nexport { neuroNoiseFragmentShader, type NeuroNoiseParams, type NeuroNoiseUniforms } from './shaders/neuro-noise.js';\n\n// ----- Animated dot pattern: orbit type of animation ----- //\n/** A shader rendering an animated dot pattern based on Voronoi diagram */\nexport {\n dotOrbitMeta,\n dotOrbitFragmentShader,\n type DotOrbitParams,\n type DotOrbitUniforms,\n} from './shaders/dot-orbit.js';\n\n// ----- Dot Grid ----- //\n/** A shader rendering a static dot pattern */\nexport {\n dotGridFragmentShader,\n DotGridShapes,\n type DotGridShape,\n type DotGridParams,\n type DotGridUniforms,\n} from './shaders/dot-grid.js';\n\n// ----- Simplex noise ----- //\n/** A shader that calculates a combination of 2 simplex noises with result rendered as a gradient */\nexport {\n simplexNoiseMeta,\n simplexNoiseFragmentShader,\n type SimplexNoiseParams,\n type SimplexNoiseUniforms,\n} from './shaders/simplex-noise.js';\n\n// ----- Metaballs ----- //\n/** A number of circlular shapes blened in a gooey way */\nexport {\n metaballsMeta,\n metaballsFragmentShader,\n type MetaballsParams,\n type MetaballsUniforms,\n} from './shaders/metaballs.js';\n\n// ----- Perlin noise ----- //\n/** 2d noise with max number of parameters to be exposed to users */\nexport { perlinNoiseFragmentShader, type PerlinNoiseParams, type PerlinNoiseUniforms } from './shaders/perlin-noise.js';\n\n// ----- Voronoi Diagram ----- //\n/** Voronoi diagram: classic + rounded edges */\nexport { voronoiMeta, voronoiFragmentShader, type VoronoiParams, type VoronoiUniforms } from './shaders/voronoi.js';\n\n// ----- Waves ----- //\n/** Waves pattern */\nexport { wavesFragmentShader, type WavesParams, type WavesUniforms } from './shaders/waves.js';\n\n// ----- Warping Distortion ----- //\n/** Warp: distortion + swirl + underlying shapes */\nexport {\n warpMeta,\n warpFragmentShader,\n WarpPatterns,\n type WarpParams,\n type WarpUniforms,\n type WarpPattern,\n} from './shaders/warp.js';\n\n// ----- God Rays Effect ----- //\n/** Radial shape made of randomized stripes */\nexport { godRaysMeta, godRaysFragmentShader, type GodRaysParams, type GodRaysUniforms } from './shaders/god-rays.js';\n\n// ----- Spiral Shape ----- //\n/** Single-color spiral shape */\nexport { spiralFragmentShader, type SpiralParams, type SpiralUniforms } from './shaders/spiral.js';\n\n// ----- Swirl gradient ----- //\n/** Multi-color radial swirl */\nexport { swirlMeta, swirlFragmentShader, type SwirlParams, type SwirlUniforms } from './shaders/swirl.js';\n\n// ----- Dithering ----- //\n/** Dithering effect applied over abstract shapes */\nexport {\n ditheringFragmentShader,\n DitheringShapes,\n DitheringTypes,\n type DitheringParams,\n type DitheringUniforms,\n type DitheringShape,\n type DitheringType,\n} from './shaders/dithering.js';\n\n// ----- Grainy Gradient ----- //\n/** N-color gradient applied to the abstract shapes w/ grainy overlay & distortion */\nexport {\n grainGradientFragmentShader,\n grainGradientMeta,\n GrainGradientShapes,\n type GrainGradientParams,\n type GrainGradientUniforms,\n type GrainGradientShape,\n} from './shaders/grain-gradient.js';\n\n// -----
|
|
5
|
-
"mappings": ";;;;;AACA,SAAS,aAAa,4BAA4B;AAUlD;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AAIP;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAIP;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAIP,SAAS,gCAAgF;AAIzF;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAIP;AAAA,EACE;AAAA,EACA;AAAA,OAIK;AAIP;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAIP;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAIP,SAAS,iCAAmF;AAI5F,SAAS,aAAa,6BAAuE;AAI7F,SAAS,2BAAiE;AAI1E;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AAIP,SAAS,aAAa,6BAAuE;AAI7F,SAAS,4BAAoE;AAI7E,SAAS,WAAW,2BAAiE;AAIrF;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAKK;AAIP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AAIP;AAAA,EACE;AAAA,EACA;AAAA,
|
|
4
|
+
"sourcesContent": ["/** The core Shader Mount class. Pass it a parent element and a fragment shader to get started. */\nexport { ShaderMount, isPaperShaderElement } from './shader-mount.js';\nexport type {\n PaperShaderElement,\n ShaderMotionParams,\n ShaderMountUniforms,\n ShaderPreset,\n ImageShaderPreset,\n} from './shader-mount.js';\n\n/** Shader sizing options and uniforms */\nexport {\n defaultObjectSizing,\n defaultPatternSizing,\n ShaderFitOptions,\n type ShaderFit,\n type ShaderSizingParams,\n type ShaderSizingUniforms,\n} from './shader-sizing.js';\n\n// ----- Mesh gradient ----- //\n/** A shader that renders a mesh gradient with a rotating noise pattern and several layers of fractal noise */\nexport {\n meshGradientFragmentShader,\n meshGradientMeta,\n type MeshGradientParams,\n type MeshGradientUniforms,\n} from './shaders/mesh-gradient.js';\n\n// ----- Smoke ring ----- //\n/** Fractional Brownian motion (fBm) noise over the polar coordinates, masked with ring shape */\nexport {\n smokeRingMeta,\n smokeRingFragmentShader,\n type SmokeRingParams,\n type SmokeRingUniforms,\n} from './shaders/smoke-ring.js';\n\n// ----- Neuro noise ----- //\n/** A shader rendering a fractal-like structure made of several layers of since-arches */\nexport { neuroNoiseFragmentShader, type NeuroNoiseParams, type NeuroNoiseUniforms } from './shaders/neuro-noise.js';\n\n// ----- Animated dot pattern: orbit type of animation ----- //\n/** A shader rendering an animated dot pattern based on Voronoi diagram */\nexport {\n dotOrbitMeta,\n dotOrbitFragmentShader,\n type DotOrbitParams,\n type DotOrbitUniforms,\n} from './shaders/dot-orbit.js';\n\n// ----- Dot Grid ----- //\n/** A shader rendering a static dot pattern */\nexport {\n dotGridFragmentShader,\n DotGridShapes,\n type DotGridShape,\n type DotGridParams,\n type DotGridUniforms,\n} from './shaders/dot-grid.js';\n\n// ----- Simplex noise ----- //\n/** A shader that calculates a combination of 2 simplex noises with result rendered as a gradient */\nexport {\n simplexNoiseMeta,\n simplexNoiseFragmentShader,\n type SimplexNoiseParams,\n type SimplexNoiseUniforms,\n} from './shaders/simplex-noise.js';\n\n// ----- Metaballs ----- //\n/** A number of circlular shapes blened in a gooey way */\nexport {\n metaballsMeta,\n metaballsFragmentShader,\n type MetaballsParams,\n type MetaballsUniforms,\n} from './shaders/metaballs.js';\n\n// ----- Perlin noise ----- //\n/** 2d noise with max number of parameters to be exposed to users */\nexport { perlinNoiseFragmentShader, type PerlinNoiseParams, type PerlinNoiseUniforms } from './shaders/perlin-noise.js';\n\n// ----- Voronoi Diagram ----- //\n/** Voronoi diagram: classic + rounded edges */\nexport { voronoiMeta, voronoiFragmentShader, type VoronoiParams, type VoronoiUniforms } from './shaders/voronoi.js';\n\n// ----- Waves ----- //\n/** Waves pattern */\nexport { wavesFragmentShader, type WavesParams, type WavesUniforms } from './shaders/waves.js';\n\n// ----- Warping Distortion ----- //\n/** Warp: distortion + swirl + underlying shapes */\nexport {\n warpMeta,\n warpFragmentShader,\n WarpPatterns,\n type WarpParams,\n type WarpUniforms,\n type WarpPattern,\n} from './shaders/warp.js';\n\n// ----- God Rays Effect ----- //\n/** Radial shape made of randomized stripes */\nexport { godRaysMeta, godRaysFragmentShader, type GodRaysParams, type GodRaysUniforms } from './shaders/god-rays.js';\n\n// ----- Spiral Shape ----- //\n/** Single-color spiral shape */\nexport { spiralFragmentShader, type SpiralParams, type SpiralUniforms } from './shaders/spiral.js';\n\n// ----- Swirl gradient ----- //\n/** Multi-color radial swirl */\nexport { swirlMeta, swirlFragmentShader, type SwirlParams, type SwirlUniforms } from './shaders/swirl.js';\n\n// ----- Dithering ----- //\n/** Dithering effect applied over abstract shapes */\nexport {\n ditheringFragmentShader,\n DitheringShapes,\n DitheringTypes,\n type DitheringParams,\n type DitheringUniforms,\n type DitheringShape,\n type DitheringType,\n} from './shaders/dithering.js';\n\n// ----- Grainy Gradient ----- //\n/** N-color gradient applied to the abstract shapes w/ grainy overlay & distortion */\nexport {\n grainGradientFragmentShader,\n grainGradientMeta,\n GrainGradientShapes,\n type GrainGradientParams,\n type GrainGradientUniforms,\n type GrainGradientShape,\n} from './shaders/grain-gradient.js';\n\n// ----- Pulsing Border ----- //\n/** Border with configurable size & radius ade of rotating pulsing light spots */\nexport {\n pulsingBorderMeta,\n pulsingBorderFragmentShader,\n PulsingBorderAspectRatios,\n type PulsingBorderParams,\n type PulsingBorderUniforms,\n type PulsingBorderAspectRatio,\n} from './shaders/pulsing-border.js';\n\n// ----- Color Gradient Panels ----- //\n/** */\nexport {\n colorPanelsFragmentShader,\n colorPanelsMeta,\n type ColorPanelsParams,\n type ColorPanelsUniforms,\n} from './shaders/color-panels.js';\n\nexport {\n staticMeshGradientFragmentShader,\n staticMeshGradientMeta,\n type StaticMeshGradientParams,\n type StaticMeshGradientUniforms,\n} from './shaders/static-mesh-gradient.js';\n\nexport {\n staticRadialGradientFragmentShader,\n staticRadialGradientMeta,\n type StaticRadialGradientParams,\n type StaticRadialGradientUniforms,\n} from './shaders/static-radial-gradient.js';\n\nexport {\n paperTextureFragmentShader,\n type PaperTextureParams,\n type PaperTextureUniforms,\n} from './shaders/paper-texture.js';\n\nexport { waterFragmentShader, type WaterParams, type WaterUniforms } from './shaders/water.js';\n\nexport {\n flutedGlassFragmentShader,\n GlassDistortionShapes,\n GlassGridShapes,\n type GlassDistortionShape,\n type GlassGridShape,\n type FlutedGlassParams,\n type FlutedGlassUniforms,\n} from './shaders/fluted-glass.js';\n\nexport {\n imageDitheringFragmentShader,\n type ImageDitheringParams,\n type ImageDitheringUniforms,\n} from './shaders/image-dithering.js';\n\nexport {\n heatmapMeta,\n heatmapFragmentShader,\n toProcessedHeatmap,\n type HeatmapParams,\n type HeatmapUniforms,\n} from './shaders/heatmap.js';\n\nexport {\n liquidMetalFragmentShader,\n LiquidMetalShapes,\n toProcessedLiquidMetal,\n type LiquidMetalShape,\n type LiquidMetalParams,\n type LiquidMetalUniforms,\n} from './shaders/liquid-metal.js';\n\n// ----- Utils ----- //\nexport { getShaderColorFromString } from './get-shader-color-from-string.js';\nexport { getShaderNoiseTexture } from './get-shader-noise-texture.js';\nexport { getEmptyPixel } from './get-empty-pixel.js';\n"],
|
|
5
|
+
"mappings": ";;;;;AACA,SAAS,aAAa,4BAA4B;AAUlD;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AAIP;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAIP;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAIP,SAAS,gCAAgF;AAIzF;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAIP;AAAA,EACE;AAAA,EACA;AAAA,OAIK;AAIP;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAIP;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAIP,SAAS,iCAAmF;AAI5F,SAAS,aAAa,6BAAuE;AAI7F,SAAS,2BAAiE;AAI1E;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AAIP,SAAS,aAAa,6BAAuE;AAI7F,SAAS,4BAAoE;AAI7E,SAAS,WAAW,2BAAiE;AAIrF;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAKK;AAIP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AAIP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AAIP;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAEP;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAEP;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAEP;AAAA,EACE;AAAA,OAGK;AAEP,SAAS,2BAAiE;AAE1E;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAKK;AAEP;AAAA,EACE;AAAA,OAGK;AAEP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AAEP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AAGP,SAAS,gCAAgC;AACzC,SAAS,6BAA6B;AACtC,SAAS,qBAAqB;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -2,7 +2,7 @@ import type { ShaderMotionParams } from '../shader-mount.js';
|
|
|
2
2
|
import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';
|
|
3
3
|
/**
|
|
4
4
|
*
|
|
5
|
-
* Fluid motion imitation applied over
|
|
5
|
+
* Fluid motion imitation applied over user image
|
|
6
6
|
* (animated stripe pattern getting distorted with shape edges)
|
|
7
7
|
*
|
|
8
8
|
* Uniforms:
|
|
@@ -20,26 +20,38 @@ import { type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-si
|
|
|
20
20
|
*
|
|
21
21
|
*/
|
|
22
22
|
export declare const liquidMetalFragmentShader: string;
|
|
23
|
+
export declare const POISSON_CONFIG_OPTIMIZED: {
|
|
24
|
+
measurePerformance: boolean;
|
|
25
|
+
workingSize: number;
|
|
26
|
+
iterations: number;
|
|
27
|
+
};
|
|
28
|
+
export declare function toProcessedLiquidMetal(file: File | string): Promise<{
|
|
29
|
+
imageData: ImageData;
|
|
30
|
+
pngBlob: Blob;
|
|
31
|
+
}>;
|
|
23
32
|
export interface LiquidMetalUniforms extends ShaderSizingUniforms {
|
|
24
33
|
u_colorBack: [number, number, number, number];
|
|
25
34
|
u_colorTint: [number, number, number, number];
|
|
26
|
-
|
|
35
|
+
u_image: HTMLImageElement | string | undefined;
|
|
27
36
|
u_repetition: number;
|
|
28
37
|
u_shiftRed: number;
|
|
29
38
|
u_shiftBlue: number;
|
|
30
|
-
u_distortion: number;
|
|
31
39
|
u_contour: number;
|
|
40
|
+
u_softness: number;
|
|
41
|
+
u_distortion: number;
|
|
32
42
|
u_shape: (typeof LiquidMetalShapes)[LiquidMetalShape];
|
|
43
|
+
u_isImage: boolean;
|
|
33
44
|
}
|
|
34
45
|
export interface LiquidMetalParams extends ShaderSizingParams, ShaderMotionParams {
|
|
35
46
|
colorBack?: string;
|
|
36
47
|
colorTint?: string;
|
|
37
|
-
|
|
48
|
+
image?: HTMLImageElement | string | undefined;
|
|
38
49
|
repetition?: number;
|
|
39
50
|
shiftRed?: number;
|
|
40
51
|
shiftBlue?: number;
|
|
41
|
-
distortion?: number;
|
|
42
52
|
contour?: number;
|
|
53
|
+
softness?: number;
|
|
54
|
+
distortion?: number;
|
|
43
55
|
shape?: LiquidMetalShape;
|
|
44
56
|
}
|
|
45
57
|
export declare const LiquidMetalShapes: {
|
|
@@ -8,6 +8,9 @@ import { declarePI, rotation2, simplexNoise, colorBandingFix } from "../shader-u
|
|
|
8
8
|
const liquidMetalFragmentShader = `#version 300 es
|
|
9
9
|
precision mediump float;
|
|
10
10
|
|
|
11
|
+
uniform sampler2D u_image;
|
|
12
|
+
uniform float u_imageAspectRatio;
|
|
13
|
+
|
|
11
14
|
uniform float u_time;
|
|
12
15
|
|
|
13
16
|
uniform vec4 u_colorBack;
|
|
@@ -19,7 +22,9 @@ uniform float u_shiftRed;
|
|
|
19
22
|
uniform float u_shiftBlue;
|
|
20
23
|
uniform float u_distortion;
|
|
21
24
|
uniform float u_contour;
|
|
25
|
+
|
|
22
26
|
uniform float u_shape;
|
|
27
|
+
uniform bool u_isImage;
|
|
23
28
|
|
|
24
29
|
${sizingVariablesDeclaration}
|
|
25
30
|
|
|
@@ -30,12 +35,15 @@ ${rotation2}
|
|
|
30
35
|
${simplexNoise}
|
|
31
36
|
|
|
32
37
|
float getColorChanges(float c1, float c2, float stripe_p, vec3 w, float blur, float bump, float tint) {
|
|
33
|
-
|
|
38
|
+
|
|
34
39
|
float ch = mix(c2, c1, smoothstep(.0, 2. * blur, stripe_p));
|
|
35
40
|
|
|
36
41
|
float border = w[0];
|
|
37
42
|
ch = mix(ch, c2, smoothstep(border, border + 2. * blur, stripe_p));
|
|
38
43
|
|
|
44
|
+
if (u_isImage == true) {
|
|
45
|
+
bump = smoothstep(.2, .8, bump);
|
|
46
|
+
}
|
|
39
47
|
border = w[0] + .4 * (1. - bump) * w[1];
|
|
40
48
|
ch = mix(ch, c1, smoothstep(border, border + 2. * blur, stripe_p));
|
|
41
49
|
|
|
@@ -48,90 +56,147 @@ float getColorChanges(float c1, float c2, float stripe_p, vec3 w, float blur, fl
|
|
|
48
56
|
float gradient_t = (stripe_p - w[0] - w[1]) / w[2];
|
|
49
57
|
float gradient = mix(c1, c2, smoothstep(0., 1., gradient_t));
|
|
50
58
|
ch = mix(ch, gradient, smoothstep(border, border + .5 * blur, stripe_p));
|
|
51
|
-
|
|
59
|
+
|
|
52
60
|
// Tint color is applied with color burn blending
|
|
53
61
|
ch = mix(ch, 1. - min(1., (1. - ch) / max(tint, 0.0001)), u_colorTint.a);
|
|
54
62
|
return ch;
|
|
55
63
|
}
|
|
56
64
|
|
|
65
|
+
float getImgFrame(vec2 uv, float th) {
|
|
66
|
+
float frame = 1.;
|
|
67
|
+
frame *= smoothstep(0., th, uv.y);
|
|
68
|
+
frame *= smoothstep(1., 1. - th, uv.y);
|
|
69
|
+
frame *= smoothstep(0., th, uv.x);
|
|
70
|
+
frame *= smoothstep(1., 1. - th, uv.x);
|
|
71
|
+
return frame;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
float blurEdge3x3(sampler2D tex, vec2 uv, vec2 dudx, vec2 dudy, float radius, float centerSample) {
|
|
75
|
+
vec2 texel = 1.0 / vec2(textureSize(tex, 0));
|
|
76
|
+
vec2 r = radius * texel;
|
|
77
|
+
|
|
78
|
+
float w1 = 1.0, w2 = 2.0, w4 = 4.0;
|
|
79
|
+
float norm = 16.0;
|
|
80
|
+
float sum = w4 * centerSample;
|
|
81
|
+
|
|
82
|
+
sum += w2 * textureGrad(tex, uv + vec2(0.0, -r.y), dudx, dudy).r;
|
|
83
|
+
sum += w2 * textureGrad(tex, uv + vec2(0.0, r.y), dudx, dudy).r;
|
|
84
|
+
sum += w2 * textureGrad(tex, uv + vec2(-r.x, 0.0), dudx, dudy).r;
|
|
85
|
+
sum += w2 * textureGrad(tex, uv + vec2(r.x, 0.0), dudx, dudy).r;
|
|
86
|
+
|
|
87
|
+
sum += w1 * textureGrad(tex, uv + vec2(-r.x, -r.y), dudx, dudy).r;
|
|
88
|
+
sum += w1 * textureGrad(tex, uv + vec2(r.x, -r.y), dudx, dudy).r;
|
|
89
|
+
sum += w1 * textureGrad(tex, uv + vec2(-r.x, r.y), dudx, dudy).r;
|
|
90
|
+
sum += w1 * textureGrad(tex, uv + vec2(r.x, r.y), dudx, dudy).r;
|
|
91
|
+
|
|
92
|
+
return sum / norm;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
|
|
57
96
|
void main() {
|
|
58
97
|
|
|
59
|
-
float t = .1 * u_time;
|
|
98
|
+
float t = (u_isImage ? .3 : .1) * u_time;
|
|
60
99
|
|
|
61
|
-
vec2 uv =
|
|
62
|
-
|
|
63
|
-
|
|
100
|
+
vec2 uv = v_imageUV;
|
|
101
|
+
vec2 dudx = dFdx(v_imageUV);
|
|
102
|
+
vec2 dudy = dFdy(v_imageUV);
|
|
103
|
+
vec4 img = textureGrad(u_image, uv, dudx, dudy);
|
|
64
104
|
|
|
65
|
-
|
|
105
|
+
if (u_isImage == false) {
|
|
106
|
+
uv = v_objectUV + .5;
|
|
107
|
+
uv.y = 1. - uv.y;
|
|
108
|
+
}
|
|
66
109
|
|
|
67
|
-
float
|
|
110
|
+
float cycleWidth = u_repetition;
|
|
111
|
+
if (u_isImage == false) {
|
|
112
|
+
cycleWidth *= .5;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
float edge = 0.;
|
|
68
116
|
float contOffset = 1.;
|
|
69
117
|
|
|
70
|
-
if (
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
118
|
+
if (u_isImage == true) {
|
|
119
|
+
float edgeRaw = img.r;
|
|
120
|
+
edge = blurEdge3x3(u_image, uv, dudx, dudy, 6., edgeRaw);
|
|
121
|
+
edge = pow(edge, 1.6);
|
|
122
|
+
edge *= mix(0.0, 1.0, smoothstep(0.0, 0.4, u_contour));
|
|
123
|
+
} else {
|
|
124
|
+
if (u_shape < 1.) {
|
|
125
|
+
|
|
126
|
+
vec2 borderUV = v_responsiveUV + .5;
|
|
127
|
+
float ratio = v_responsiveBoxGivenSize.x / v_responsiveBoxGivenSize.y;
|
|
128
|
+
vec2 mask = min(borderUV, 1. - borderUV);
|
|
129
|
+
vec2 pixel_thickness = 250. / v_responsiveBoxGivenSize;
|
|
130
|
+
float maskX = smoothstep(0.0, pixel_thickness.x, mask.x);
|
|
131
|
+
float maskY = smoothstep(0.0, pixel_thickness.y, mask.y);
|
|
132
|
+
maskX = pow(maskX, .25);
|
|
133
|
+
maskY = pow(maskY, .25);
|
|
134
|
+
edge = clamp(1. - maskX * maskY, 0., 1.);
|
|
135
|
+
|
|
136
|
+
uv = v_responsiveUV;
|
|
137
|
+
if (ratio > 1.) {
|
|
138
|
+
uv.y /= ratio;
|
|
139
|
+
} else {
|
|
140
|
+
uv.x *= ratio;
|
|
141
|
+
}
|
|
142
|
+
uv += .5;
|
|
143
|
+
uv.y = 1. - uv.y;
|
|
144
|
+
|
|
145
|
+
cycleWidth *= 2.;
|
|
146
|
+
contOffset = 1.5;
|
|
147
|
+
|
|
148
|
+
} else if (u_shape < 2.) {
|
|
149
|
+
vec2 shapeUV = uv - .5;
|
|
150
|
+
shapeUV *= .67;
|
|
151
|
+
edge = pow(clamp(3. * length(shapeUV), 0., 1.), 18.);
|
|
152
|
+
} else if (u_shape < 3.) {
|
|
153
|
+
vec2 shapeUV = uv - .5;
|
|
154
|
+
shapeUV *= 1.68;
|
|
155
|
+
|
|
156
|
+
float r = length(shapeUV) * 2.;
|
|
157
|
+
float a = atan(shapeUV.y, shapeUV.x) + .2;
|
|
158
|
+
r *= (1. + .05 * sin(3. * a + 2. * t));
|
|
159
|
+
float f = abs(cos(a * 3.));
|
|
160
|
+
edge = smoothstep(f, f + .7, r);
|
|
161
|
+
edge = pow(edge, 2.);
|
|
162
|
+
|
|
163
|
+
uv *= .8;
|
|
164
|
+
cycleWidth *= 1.6;
|
|
165
|
+
|
|
166
|
+
} else if (u_shape < 4.) {
|
|
167
|
+
vec2 shapeUV = uv - .5;
|
|
168
|
+
shapeUV *= 1.3;
|
|
169
|
+
edge = 0.;
|
|
170
|
+
for (int i = 0; i < 5; i++) {
|
|
171
|
+
float fi = float(i);
|
|
172
|
+
float speed = 4.5 + 2. * sin(fi * 12.345);
|
|
173
|
+
float angle = -fi * 1.5;
|
|
174
|
+
vec2 dir1 = vec2(cos(angle), sin(angle));
|
|
175
|
+
vec2 dir2 = vec2(cos(angle + 1.57), sin(angle + 1.));
|
|
176
|
+
vec2 traj = .4 * (dir1 * sin(t * speed + fi * 1.23) + dir2 * cos(t * (speed * 0.7) + fi * 2.17));
|
|
177
|
+
float d = length(shapeUV + traj);
|
|
178
|
+
edge += pow(1.0 - clamp(d, 0.0, 1.0), 4.0);
|
|
179
|
+
}
|
|
180
|
+
edge = 1. - smoothstep(.65, .9, edge);
|
|
181
|
+
edge = pow(edge, 4.);
|
|
87
182
|
}
|
|
88
|
-
uv += .5;
|
|
89
|
-
uv.y = 1. - uv.y;
|
|
90
183
|
|
|
91
|
-
cycleWidth *= 2.;
|
|
92
|
-
contOffset = 1.5;
|
|
93
|
-
|
|
94
|
-
} else if (u_shape < 2.) {
|
|
95
|
-
vec2 shapeUV = uv - .5;
|
|
96
|
-
shapeUV *= .67;
|
|
97
|
-
mask = pow(clamp(3. * length(shapeUV), 0., 1.), 18.);
|
|
98
|
-
} else if (u_shape < 3.) {
|
|
99
|
-
vec2 shapeUV = uv - .5;
|
|
100
|
-
shapeUV *= 1.68;
|
|
101
|
-
|
|
102
|
-
float r = length(shapeUV) * 2.;
|
|
103
|
-
float a = atan(shapeUV.y, shapeUV.x) + .2;
|
|
104
|
-
r *= (1. + .05 * sin(3. * a + 2. * t));
|
|
105
|
-
float f = abs(cos(a * 3.));
|
|
106
|
-
mask = smoothstep(f, f + .7, r);
|
|
107
|
-
mask = pow(mask, 2.);
|
|
108
|
-
|
|
109
|
-
uv *= .8;
|
|
110
|
-
cycleWidth *= 1.6;
|
|
111
|
-
|
|
112
|
-
} else if (u_shape < 4.) {
|
|
113
|
-
vec2 shapeUV = uv - .5;
|
|
114
|
-
shapeUV *= 1.3;
|
|
115
|
-
mask = 0.;
|
|
116
|
-
for (int i = 0; i < 5; i++) {
|
|
117
|
-
float fi = float(i);
|
|
118
|
-
float speed = 4.5 + 2. * sin(fi * 12.345);
|
|
119
|
-
float angle = -fi * 1.5;
|
|
120
|
-
vec2 dir1 = vec2(cos(angle), sin(angle));
|
|
121
|
-
vec2 dir2 = vec2(cos(angle + 1.57), sin(angle + 1.));
|
|
122
|
-
vec2 traj = .4 * (dir1 * sin(t * speed + fi * 1.23) + dir2 * cos(t * (speed * 0.7) + fi * 2.17));
|
|
123
|
-
float d = length(shapeUV + traj);
|
|
124
|
-
mask += pow(1.0 - clamp(d, 0.0, 1.0), 4.0);
|
|
125
|
-
}
|
|
126
|
-
mask = 1. - smoothstep(.65, .9, mask);
|
|
127
|
-
mask = pow(mask, 4.);
|
|
128
184
|
}
|
|
129
185
|
|
|
130
|
-
float opacity =
|
|
186
|
+
float opacity = 0.;
|
|
187
|
+
if (u_isImage == true) {
|
|
188
|
+
opacity = img.g;
|
|
189
|
+
float frame = getImgFrame(v_imageUV, 0.);
|
|
190
|
+
opacity *= frame;
|
|
191
|
+
} else {
|
|
192
|
+
opacity = 1. - smoothstep(.82 - 2. * fwidth(edge), .82, edge);
|
|
193
|
+
}
|
|
131
194
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
195
|
+
if (u_isImage == false) {
|
|
196
|
+
float ridge = .15 * (smoothstep(.0, .15, uv.y) * smoothstep(.4, .15, uv.y));
|
|
197
|
+
ridge += .05 * (smoothstep(.1, .2, 1. - uv.y) * smoothstep(.4, .2, 1. - uv.y));
|
|
198
|
+
edge += ridge;
|
|
199
|
+
}
|
|
135
200
|
|
|
136
201
|
float diagBLtoTR = uv.x - uv.y;
|
|
137
202
|
float diagTLtoBR = uv.x + uv.y;
|
|
@@ -160,17 +225,31 @@ void main() {
|
|
|
160
225
|
|
|
161
226
|
float noise = snoise(uv - t);
|
|
162
227
|
|
|
163
|
-
|
|
228
|
+
edge += (1. - edge) * u_distortion * noise;
|
|
164
229
|
|
|
165
230
|
direction += diagBLtoTR;
|
|
231
|
+
float contour = 0.;
|
|
232
|
+
if (u_isImage == false) {
|
|
233
|
+
contour = u_contour * smoothstep(0., contOffset + .01, edge) * smoothstep(contOffset + .01, 0., edge);
|
|
234
|
+
direction -= 14. * noise * contour;
|
|
235
|
+
} else {
|
|
236
|
+
direction -= 2. * noise * diagBLtoTR * (smoothstep(0., 1., edge) * smoothstep(1., 0., edge));
|
|
237
|
+
direction *= mix(1., 1. - edge, smoothstep(.5, 1., u_contour));
|
|
238
|
+
direction -= 1.7 * edge * smoothstep(.5, 1., u_contour);
|
|
239
|
+
direction += .2 * pow(u_contour, 4.) * smoothstep(1., 0., edge);
|
|
240
|
+
}
|
|
166
241
|
|
|
167
|
-
float contour = u_contour * smoothstep(0., contOffset + .01, mask) * smoothstep(contOffset + .01, 0., mask);
|
|
168
|
-
direction -= 14. * noise * contour;
|
|
169
242
|
|
|
170
243
|
bump *= clamp(pow(uv.y, .1), .3, 1.);
|
|
171
|
-
direction *= (.1 + (1.1 -
|
|
172
|
-
|
|
173
|
-
|
|
244
|
+
direction *= (.1 + (1.1 - edge) * bump);
|
|
245
|
+
|
|
246
|
+
if (u_isImage == false) {
|
|
247
|
+
direction *= smoothstep(1., .2, edge);
|
|
248
|
+
} else {
|
|
249
|
+
direction *= (.4 + .6 * smoothstep(1., .5, edge));
|
|
250
|
+
direction += .18 * (smoothstep(.1, .2, uv.y) * smoothstep(.4, .2, uv.y));
|
|
251
|
+
direction += .03 * (smoothstep(.1, .2, 1. - uv.y) * smoothstep(.4, .2, 1. - uv.y));
|
|
252
|
+
}
|
|
174
253
|
|
|
175
254
|
direction *= (.5 + .5 * pow(uv.y, 2.));
|
|
176
255
|
direction *= cycleWidth;
|
|
@@ -178,21 +257,44 @@ void main() {
|
|
|
178
257
|
|
|
179
258
|
|
|
180
259
|
float colorDispersion = (1. - bump);
|
|
260
|
+
colorDispersion = clamp(colorDispersion, 0., 1.);
|
|
181
261
|
float dispersionRed = colorDispersion;
|
|
182
|
-
|
|
262
|
+
if (u_isImage == true) {
|
|
263
|
+
dispersionRed += .03 * bump * noise;
|
|
264
|
+
dispersionRed += 5. * (smoothstep(-.1, .2, uv.y) * smoothstep(.5, .1, uv.y)) * (smoothstep(.4, .6, bump) * smoothstep(1., .4, bump));
|
|
265
|
+
dispersionRed -= diagBLtoTR;
|
|
266
|
+
} else {
|
|
267
|
+
dispersionRed += bump * noise;
|
|
268
|
+
}
|
|
269
|
+
|
|
183
270
|
float dispersionBlue = colorDispersion;
|
|
271
|
+
if (u_isImage == true) {
|
|
272
|
+
dispersionBlue *= 1.3;
|
|
273
|
+
dispersionBlue += (smoothstep(0., .4, uv.y) * smoothstep(.8, .1, uv.y)) * (smoothstep(.4, .6, bump) * smoothstep(.8, .4, bump));
|
|
274
|
+
dispersionBlue -= .2 * edge;
|
|
275
|
+
}
|
|
184
276
|
|
|
185
277
|
dispersionRed *= (u_shiftRed / 20.);
|
|
186
278
|
dispersionBlue *= (u_shiftBlue / 20.);
|
|
187
279
|
|
|
188
|
-
float blur =
|
|
280
|
+
float blur = 0.;
|
|
281
|
+
float rExtraBlur = 0.;
|
|
282
|
+
float gExtraBlur = 0.;
|
|
283
|
+
if (u_isImage == true) {
|
|
284
|
+
float softness = 0.05 * u_softness;
|
|
285
|
+
blur = softness + .5 * smoothstep(1., 10., u_repetition) * smoothstep(.0, 1., edge);
|
|
286
|
+
rExtraBlur = softness * (0.05 + .1 * (u_shiftRed / 20.) * bump);
|
|
287
|
+
gExtraBlur = softness * 0.05 / (1. - diagBLtoTR);
|
|
288
|
+
} else {
|
|
289
|
+
blur = u_softness / 15. + .3 * contour;
|
|
290
|
+
}
|
|
189
291
|
|
|
190
292
|
vec3 w = vec3(thin_strip_1_width, thin_strip_2_width, wide_strip_ratio);
|
|
191
|
-
w[1] -= .02 * smoothstep(.0, 1.,
|
|
293
|
+
w[1] -= .02 * smoothstep(.0, 1., edge + bump);
|
|
192
294
|
float stripe_r = mod(direction + dispersionRed, 1.);
|
|
193
|
-
float r = getColorChanges(color1.r, color2.r, stripe_r, w, blur + fwidth(stripe_r), bump, u_colorTint.r);
|
|
295
|
+
float r = getColorChanges(color1.r, color2.r, stripe_r, w, blur + fwidth(stripe_r) + rExtraBlur, bump, u_colorTint.r);
|
|
194
296
|
float stripe_g = mod(direction, 1.);
|
|
195
|
-
float g = getColorChanges(color1.g, color2.g, stripe_g, w, blur + fwidth(stripe_g), bump, u_colorTint.g);
|
|
297
|
+
float g = getColorChanges(color1.g, color2.g, stripe_g, w, blur + fwidth(stripe_g) + gExtraBlur, bump, u_colorTint.g);
|
|
196
298
|
float stripe_b = mod(direction - dispersionBlue, 1.);
|
|
197
299
|
float b = getColorChanges(color1.b, color2.b, stripe_b, w, blur + fwidth(stripe_b), bump, u_colorTint.b);
|
|
198
300
|
|
|
@@ -208,6 +310,287 @@ void main() {
|
|
|
208
310
|
fragColor = vec4(color, opacity);
|
|
209
311
|
}
|
|
210
312
|
`;
|
|
313
|
+
const POISSON_CONFIG_OPTIMIZED = {
|
|
314
|
+
measurePerformance: false,
|
|
315
|
+
// Set to true to see performance metrics
|
|
316
|
+
workingSize: 500,
|
|
317
|
+
// Size to solve Poisson at (will upscale to original size)
|
|
318
|
+
iterations: 30
|
|
319
|
+
// SOR converges ~2-20x faster than standard Gauss-Seidel
|
|
320
|
+
};
|
|
321
|
+
function toProcessedLiquidMetal(file) {
|
|
322
|
+
const canvas = document.createElement("canvas");
|
|
323
|
+
const ctx = canvas.getContext("2d");
|
|
324
|
+
return new Promise((resolve, reject) => {
|
|
325
|
+
if (!file || !ctx) {
|
|
326
|
+
reject(new Error("Invalid file or canvas context"));
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
const img = new Image();
|
|
330
|
+
const totalStartTime = performance.now();
|
|
331
|
+
img.onload = () => {
|
|
332
|
+
let isSVG;
|
|
333
|
+
if (typeof file === "string") {
|
|
334
|
+
isSVG = file.endsWith(".svg") || file.startsWith("data:image/svg+xml");
|
|
335
|
+
} else {
|
|
336
|
+
isSVG = file.type === "image/svg+xml";
|
|
337
|
+
}
|
|
338
|
+
let originalWidth = img.width || img.naturalWidth;
|
|
339
|
+
let originalHeight = img.height || img.naturalHeight;
|
|
340
|
+
if (isSVG) {
|
|
341
|
+
const svgMaxSize = 4064;
|
|
342
|
+
const aspectRatio = originalWidth / originalHeight;
|
|
343
|
+
if (originalWidth > originalHeight) {
|
|
344
|
+
originalWidth = svgMaxSize;
|
|
345
|
+
originalHeight = svgMaxSize / aspectRatio;
|
|
346
|
+
} else {
|
|
347
|
+
originalHeight = svgMaxSize;
|
|
348
|
+
originalWidth = svgMaxSize * aspectRatio;
|
|
349
|
+
}
|
|
350
|
+
img.width = originalWidth;
|
|
351
|
+
img.height = originalHeight;
|
|
352
|
+
}
|
|
353
|
+
const minDimension = Math.min(originalWidth, originalHeight);
|
|
354
|
+
const targetSize = POISSON_CONFIG_OPTIMIZED.workingSize;
|
|
355
|
+
const scaleFactor = targetSize / minDimension;
|
|
356
|
+
const width = Math.round(originalWidth * scaleFactor);
|
|
357
|
+
const height = Math.round(originalHeight * scaleFactor);
|
|
358
|
+
if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {
|
|
359
|
+
console.log(`[Processing Mode]`);
|
|
360
|
+
console.log(` Original: ${originalWidth}\xD7${originalHeight}`);
|
|
361
|
+
console.log(` Working: ${width}\xD7${height} (${(scaleFactor * 100).toFixed(1)}% scale)`);
|
|
362
|
+
if (scaleFactor < 1) {
|
|
363
|
+
console.log(` Speedup: ~${Math.round(1 / (scaleFactor * scaleFactor))}\xD7`);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
canvas.width = originalWidth;
|
|
367
|
+
canvas.height = originalHeight;
|
|
368
|
+
const shapeCanvas = document.createElement("canvas");
|
|
369
|
+
shapeCanvas.width = width;
|
|
370
|
+
shapeCanvas.height = height;
|
|
371
|
+
const shapeCtx = shapeCanvas.getContext("2d");
|
|
372
|
+
shapeCtx.drawImage(img, 0, 0, width, height);
|
|
373
|
+
const startMask = performance.now();
|
|
374
|
+
const shapeImageData = shapeCtx.getImageData(0, 0, width, height);
|
|
375
|
+
const data = shapeImageData.data;
|
|
376
|
+
const shapeMask = new Uint8Array(width * height);
|
|
377
|
+
const boundaryMask = new Uint8Array(width * height);
|
|
378
|
+
let shapePixelCount = 0;
|
|
379
|
+
for (let i = 0, idx = 0; i < data.length; i += 4, idx++) {
|
|
380
|
+
const a = data[i + 3];
|
|
381
|
+
const isShape = a === 0 ? 0 : 1;
|
|
382
|
+
shapeMask[idx] = isShape;
|
|
383
|
+
shapePixelCount += isShape;
|
|
384
|
+
}
|
|
385
|
+
const boundaryIndices = [];
|
|
386
|
+
const interiorIndices = [];
|
|
387
|
+
for (let y = 0; y < height; y++) {
|
|
388
|
+
for (let x = 0; x < width; x++) {
|
|
389
|
+
const idx = y * width + x;
|
|
390
|
+
if (!shapeMask[idx]) continue;
|
|
391
|
+
let isBoundary = false;
|
|
392
|
+
if (x === 0 || x === width - 1 || y === 0 || y === height - 1) {
|
|
393
|
+
isBoundary = true;
|
|
394
|
+
} else {
|
|
395
|
+
isBoundary = !shapeMask[idx - 1] || // left
|
|
396
|
+
!shapeMask[idx + 1] || // right
|
|
397
|
+
!shapeMask[idx - width] || // top
|
|
398
|
+
!shapeMask[idx + width] || // bottom
|
|
399
|
+
!shapeMask[idx - width - 1] || // top-left
|
|
400
|
+
!shapeMask[idx - width + 1] || // top-right
|
|
401
|
+
!shapeMask[idx + width - 1] || // bottom-left
|
|
402
|
+
!shapeMask[idx + width + 1];
|
|
403
|
+
}
|
|
404
|
+
if (isBoundary) {
|
|
405
|
+
boundaryMask[idx] = 1;
|
|
406
|
+
boundaryIndices.push(idx);
|
|
407
|
+
} else {
|
|
408
|
+
interiorIndices.push(idx);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {
|
|
413
|
+
console.log(`[Mask Building] Time: ${(performance.now() - startMask).toFixed(2)}ms`);
|
|
414
|
+
console.log(
|
|
415
|
+
` Shape pixels: ${shapePixelCount} / ${width * height} (${(shapePixelCount / (width * height) * 100).toFixed(1)}%)`
|
|
416
|
+
);
|
|
417
|
+
console.log(` Interior pixels: ${interiorIndices.length}`);
|
|
418
|
+
console.log(` Boundary pixels: ${boundaryIndices.length}`);
|
|
419
|
+
}
|
|
420
|
+
const sparseData = buildSparseData(
|
|
421
|
+
shapeMask,
|
|
422
|
+
boundaryMask,
|
|
423
|
+
new Uint32Array(interiorIndices),
|
|
424
|
+
new Uint32Array(boundaryIndices),
|
|
425
|
+
width,
|
|
426
|
+
height
|
|
427
|
+
);
|
|
428
|
+
const startSolve = performance.now();
|
|
429
|
+
const u = solvePoissonSparse(sparseData, shapeMask, boundaryMask, width, height);
|
|
430
|
+
if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {
|
|
431
|
+
console.log(`[Poisson Solve] Time: ${(performance.now() - startSolve).toFixed(2)}ms`);
|
|
432
|
+
}
|
|
433
|
+
let maxVal = 0;
|
|
434
|
+
let finalImageData;
|
|
435
|
+
for (let i = 0; i < interiorIndices.length; i++) {
|
|
436
|
+
const idx = interiorIndices[i];
|
|
437
|
+
if (u[idx] > maxVal) maxVal = u[idx];
|
|
438
|
+
}
|
|
439
|
+
const tempCanvas = document.createElement("canvas");
|
|
440
|
+
tempCanvas.width = width;
|
|
441
|
+
tempCanvas.height = height;
|
|
442
|
+
const tempCtx = tempCanvas.getContext("2d");
|
|
443
|
+
const tempImg = tempCtx.createImageData(width, height);
|
|
444
|
+
for (let y = 0; y < height; y++) {
|
|
445
|
+
for (let x = 0; x < width; x++) {
|
|
446
|
+
const idx = y * width + x;
|
|
447
|
+
const px = idx * 4;
|
|
448
|
+
if (!shapeMask[idx]) {
|
|
449
|
+
tempImg.data[px] = 255;
|
|
450
|
+
tempImg.data[px + 1] = 255;
|
|
451
|
+
tempImg.data[px + 2] = 255;
|
|
452
|
+
tempImg.data[px + 3] = 0;
|
|
453
|
+
} else {
|
|
454
|
+
const poissonRatio = u[idx] / maxVal;
|
|
455
|
+
const gray = 255 * (1 - poissonRatio);
|
|
456
|
+
tempImg.data[px] = gray;
|
|
457
|
+
tempImg.data[px + 1] = gray;
|
|
458
|
+
tempImg.data[px + 2] = gray;
|
|
459
|
+
tempImg.data[px + 3] = 255;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
tempCtx.putImageData(tempImg, 0, 0);
|
|
464
|
+
ctx.imageSmoothingEnabled = true;
|
|
465
|
+
ctx.imageSmoothingQuality = "high";
|
|
466
|
+
ctx.drawImage(tempCanvas, 0, 0, width, height, 0, 0, originalWidth, originalHeight);
|
|
467
|
+
const outImg = ctx.getImageData(0, 0, originalWidth, originalHeight);
|
|
468
|
+
const originalCanvas = document.createElement("canvas");
|
|
469
|
+
originalCanvas.width = originalWidth;
|
|
470
|
+
originalCanvas.height = originalHeight;
|
|
471
|
+
const originalCtx = originalCanvas.getContext("2d");
|
|
472
|
+
originalCtx.drawImage(img, 0, 0, originalWidth, originalHeight);
|
|
473
|
+
const originalData = originalCtx.getImageData(0, 0, originalWidth, originalHeight);
|
|
474
|
+
for (let i = 0; i < outImg.data.length; i += 4) {
|
|
475
|
+
const a = originalData.data[i + 3];
|
|
476
|
+
const upscaledAlpha = outImg.data[i + 3];
|
|
477
|
+
if (a === 0) {
|
|
478
|
+
outImg.data[i] = 255;
|
|
479
|
+
outImg.data[i + 1] = 0;
|
|
480
|
+
} else {
|
|
481
|
+
outImg.data[i] = upscaledAlpha === 0 ? 0 : outImg.data[i];
|
|
482
|
+
outImg.data[i + 1] = a;
|
|
483
|
+
}
|
|
484
|
+
outImg.data[i + 2] = 255;
|
|
485
|
+
outImg.data[i + 3] = 255;
|
|
486
|
+
}
|
|
487
|
+
ctx.putImageData(outImg, 0, 0);
|
|
488
|
+
finalImageData = outImg;
|
|
489
|
+
canvas.toBlob((blob) => {
|
|
490
|
+
if (!blob) {
|
|
491
|
+
reject(new Error("Failed to create PNG blob"));
|
|
492
|
+
return;
|
|
493
|
+
}
|
|
494
|
+
if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {
|
|
495
|
+
const totalTime = performance.now() - totalStartTime;
|
|
496
|
+
console.log(`[Total Processing Time] ${totalTime.toFixed(2)}ms`);
|
|
497
|
+
if (scaleFactor < 1) {
|
|
498
|
+
const estimatedFullResTime = totalTime * Math.pow(originalWidth * originalHeight / (width * height), 1.5);
|
|
499
|
+
console.log(`[Estimated time at full resolution] ~${estimatedFullResTime.toFixed(0)}ms`);
|
|
500
|
+
console.log(
|
|
501
|
+
`[Time saved] ~${(estimatedFullResTime - totalTime).toFixed(0)}ms (${Math.round(estimatedFullResTime / totalTime)}\xD7 faster)`
|
|
502
|
+
);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
resolve({
|
|
506
|
+
imageData: finalImageData,
|
|
507
|
+
pngBlob: blob
|
|
508
|
+
});
|
|
509
|
+
}, "image/png");
|
|
510
|
+
};
|
|
511
|
+
img.onerror = () => reject(new Error("Failed to load image"));
|
|
512
|
+
img.src = typeof file === "string" ? file : URL.createObjectURL(file);
|
|
513
|
+
});
|
|
514
|
+
}
|
|
515
|
+
function buildSparseData(shapeMask, boundaryMask, interiorPixels, boundaryPixels, width, height) {
|
|
516
|
+
const pixelCount = interiorPixels.length;
|
|
517
|
+
const neighborIndices = new Int32Array(pixelCount * 4);
|
|
518
|
+
for (let i = 0; i < pixelCount; i++) {
|
|
519
|
+
const idx = interiorPixels[i];
|
|
520
|
+
const x = idx % width;
|
|
521
|
+
const y = Math.floor(idx / width);
|
|
522
|
+
neighborIndices[i * 4 + 0] = x < width - 1 && shapeMask[idx + 1] ? idx + 1 : -1;
|
|
523
|
+
neighborIndices[i * 4 + 1] = x > 0 && shapeMask[idx - 1] ? idx - 1 : -1;
|
|
524
|
+
neighborIndices[i * 4 + 2] = y > 0 && shapeMask[idx - width] ? idx - width : -1;
|
|
525
|
+
neighborIndices[i * 4 + 3] = y < height - 1 && shapeMask[idx + width] ? idx + width : -1;
|
|
526
|
+
}
|
|
527
|
+
return {
|
|
528
|
+
interiorPixels,
|
|
529
|
+
boundaryPixels,
|
|
530
|
+
pixelCount,
|
|
531
|
+
neighborIndices
|
|
532
|
+
};
|
|
533
|
+
}
|
|
534
|
+
function solvePoissonSparse(sparseData, shapeMask, boundaryMask, width, height) {
|
|
535
|
+
const ITERATIONS = POISSON_CONFIG_OPTIMIZED.iterations;
|
|
536
|
+
const C = 0.01;
|
|
537
|
+
const u = new Float32Array(width * height);
|
|
538
|
+
const { interiorPixels, neighborIndices, pixelCount } = sparseData;
|
|
539
|
+
const startTime = performance.now();
|
|
540
|
+
const omega = 1.9;
|
|
541
|
+
const redPixels = [];
|
|
542
|
+
const blackPixels = [];
|
|
543
|
+
for (let i = 0; i < pixelCount; i++) {
|
|
544
|
+
const idx = interiorPixels[i];
|
|
545
|
+
const x = idx % width;
|
|
546
|
+
const y = Math.floor(idx / width);
|
|
547
|
+
if ((x + y) % 2 === 0) {
|
|
548
|
+
redPixels.push(i);
|
|
549
|
+
} else {
|
|
550
|
+
blackPixels.push(i);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
for (let iter = 0; iter < ITERATIONS; iter++) {
|
|
554
|
+
for (const i of redPixels) {
|
|
555
|
+
const idx = interiorPixels[i];
|
|
556
|
+
const eastIdx = neighborIndices[i * 4 + 0];
|
|
557
|
+
const westIdx = neighborIndices[i * 4 + 1];
|
|
558
|
+
const northIdx = neighborIndices[i * 4 + 2];
|
|
559
|
+
const southIdx = neighborIndices[i * 4 + 3];
|
|
560
|
+
let sumN = 0;
|
|
561
|
+
if (eastIdx >= 0) sumN += u[eastIdx];
|
|
562
|
+
if (westIdx >= 0) sumN += u[westIdx];
|
|
563
|
+
if (northIdx >= 0) sumN += u[northIdx];
|
|
564
|
+
if (southIdx >= 0) sumN += u[southIdx];
|
|
565
|
+
const newValue = (C + sumN) / 4;
|
|
566
|
+
u[idx] = omega * newValue + (1 - omega) * u[idx];
|
|
567
|
+
}
|
|
568
|
+
for (const i of blackPixels) {
|
|
569
|
+
const idx = interiorPixels[i];
|
|
570
|
+
const eastIdx = neighborIndices[i * 4 + 0];
|
|
571
|
+
const westIdx = neighborIndices[i * 4 + 1];
|
|
572
|
+
const northIdx = neighborIndices[i * 4 + 2];
|
|
573
|
+
const southIdx = neighborIndices[i * 4 + 3];
|
|
574
|
+
let sumN = 0;
|
|
575
|
+
if (eastIdx >= 0) sumN += u[eastIdx];
|
|
576
|
+
if (westIdx >= 0) sumN += u[westIdx];
|
|
577
|
+
if (northIdx >= 0) sumN += u[northIdx];
|
|
578
|
+
if (southIdx >= 0) sumN += u[southIdx];
|
|
579
|
+
const newValue = (C + sumN) / 4;
|
|
580
|
+
u[idx] = omega * newValue + (1 - omega) * u[idx];
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {
|
|
584
|
+
const elapsed = performance.now() - startTime;
|
|
585
|
+
console.log(`[Optimized Poisson Solver (SOR \u03C9=${omega})]`);
|
|
586
|
+
console.log(` Working size: ${width}\xD7${height}`);
|
|
587
|
+
console.log(` Iterations: ${ITERATIONS}`);
|
|
588
|
+
console.log(` Time: ${elapsed.toFixed(2)}ms`);
|
|
589
|
+
console.log(` Interior pixels processed: ${pixelCount}`);
|
|
590
|
+
console.log(` Speed: ${(ITERATIONS * pixelCount / (elapsed * 1e3)).toFixed(2)} Mpixels/sec`);
|
|
591
|
+
}
|
|
592
|
+
return u;
|
|
593
|
+
}
|
|
211
594
|
const LiquidMetalShapes = {
|
|
212
595
|
none: 0,
|
|
213
596
|
circle: 1,
|
|
@@ -216,6 +599,8 @@ const LiquidMetalShapes = {
|
|
|
216
599
|
};
|
|
217
600
|
export {
|
|
218
601
|
LiquidMetalShapes,
|
|
219
|
-
|
|
602
|
+
POISSON_CONFIG_OPTIMIZED,
|
|
603
|
+
liquidMetalFragmentShader,
|
|
604
|
+
toProcessedLiquidMetal
|
|
220
605
|
};
|
|
221
606
|
//# sourceMappingURL=liquid-metal.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/shaders/liquid-metal.ts"],
|
|
4
|
-
"sourcesContent": ["import type { ShaderMotionParams } from '../shader-mount.js';\nimport { sizingVariablesDeclaration, type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { declarePI, rotation2, simplexNoise, colorBandingFix } from '../shader-utils.js';\n\n/**\n *\n * Fluid motion imitation applied over abstract shapes\n * (animated stripe pattern getting distorted with shape edges)\n *\n * Uniforms:\n * - u_colorBack, u_colorTint (RGBA)\n * - u_repetition: density of pattern stripes\n * - u_softness: blur between stripes\n * - u_shiftRed & u_shiftBlue: color dispersion between the stripes\n * - u_distortion: pattern distortion on the whole canvas\n * - u_contour: distortion power over the shape edges\n * - u_shape (float used as integer):\n * ---- 0: canvas-screen rectangle, needs u_worldWidth = u_worldHeight = 0 to be responsive (see vertex shader)\n * ---- 1: static circle\n * ---- 2: animated flower-like polar shape\n * ---- 3: animated metaballs\n *\n */\n\n// language=GLSL\nexport const liquidMetalFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform float u_time;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colorTint;\n\nuniform float u_softness;\nuniform float u_repetition;\nuniform float u_shiftRed;\nuniform float u_shiftBlue;\nuniform float u_distortion;\nuniform float u_contour;\nuniform float u_shape;\n\n${sizingVariablesDeclaration}\n\nout vec4 fragColor;\n\n${declarePI}\n${rotation2}\n${simplexNoise}\n\nfloat getColorChanges(float c1, float c2, float stripe_p, vec3 w, float blur, float bump, float tint) {\n \n float ch = mix(c2, c1, smoothstep(.0, 2. * blur, stripe_p));\n\n float border = w[0];\n ch = mix(ch, c2, smoothstep(border, border + 2. * blur, stripe_p));\n\n border = w[0] + .4 * (1. - bump) * w[1];\n ch = mix(ch, c1, smoothstep(border, border + 2. * blur, stripe_p));\n\n border = w[0] + .5 * (1. - bump) * w[1];\n ch = mix(ch, c2, smoothstep(border, border + 2. * blur, stripe_p));\n\n border = w[0] + w[1];\n ch = mix(ch, c1, smoothstep(border, border + 2. * blur, stripe_p));\n\n float gradient_t = (stripe_p - w[0] - w[1]) / w[2];\n float gradient = mix(c1, c2, smoothstep(0., 1., gradient_t));\n ch = mix(ch, gradient, smoothstep(border, border + .5 * blur, stripe_p));\n \n // Tint color is applied with color burn blending\n ch = mix(ch, 1. - min(1., (1. - ch) / max(tint, 0.0001)), u_colorTint.a);\n return ch;\n}\n\nvoid main() {\n\n float t = .1 * u_time;\n\n vec2 uv = v_objectUV;\n uv += .5;\n uv.y = 1. - uv.y;\n\n float cycleWidth = .5 * u_repetition;\n\n float mask = 1.;\n float contOffset = 1.;\n\n if (u_shape < 1.) {\n\n vec2 borderUV = v_responsiveUV + .5;\n float ratio = v_responsiveBoxGivenSize.x / v_responsiveBoxGivenSize.y;\n vec2 edge = min(borderUV, 1. - borderUV);\n vec2 pixel_thickness = 250. / v_responsiveBoxGivenSize;\n float maskX = smoothstep(0.0, pixel_thickness.x, edge.x);\n float maskY = smoothstep(0.0, pixel_thickness.y, edge.y);\n maskX = pow(maskX, .25);\n maskY = pow(maskY, .25);\n mask = clamp(1. - maskX * maskY, 0., 1.);\n\n uv = v_responsiveUV;\n if (ratio > 1.) {\n uv.y /= ratio;\n } else {\n uv.x *= ratio;\n }\n uv += .5;\n uv.y = 1. - uv.y;\n\n cycleWidth *= 2.;\n contOffset = 1.5;\n\n } else if (u_shape < 2.) {\n vec2 shapeUV = uv - .5;\n shapeUV *= .67;\n mask = pow(clamp(3. * length(shapeUV), 0., 1.), 18.);\n } else if (u_shape < 3.) {\n vec2 shapeUV = uv - .5;\n shapeUV *= 1.68;\n\n float r = length(shapeUV) * 2.;\n float a = atan(shapeUV.y, shapeUV.x) + .2;\n r *= (1. + .05 * sin(3. * a + 2. * t));\n float f = abs(cos(a * 3.));\n mask = smoothstep(f, f + .7, r);\n mask = pow(mask, 2.);\n\n uv *= .8;\n cycleWidth *= 1.6;\n\n } else if (u_shape < 4.) {\n vec2 shapeUV = uv - .5;\n shapeUV *= 1.3;\n mask = 0.;\n for (int i = 0; i < 5; i++) {\n float fi = float(i);\n float speed = 4.5 + 2. * sin(fi * 12.345);\n float angle = -fi * 1.5;\n vec2 dir1 = vec2(cos(angle), sin(angle));\n vec2 dir2 = vec2(cos(angle + 1.57), sin(angle + 1.));\n vec2 traj = .4 * (dir1 * sin(t * speed + fi * 1.23) + dir2 * cos(t * (speed * 0.7) + fi * 2.17));\n float d = length(shapeUV + traj);\n mask += pow(1.0 - clamp(d, 0.0, 1.0), 4.0);\n }\n mask = 1. - smoothstep(.65, .9, mask);\n mask = pow(mask, 4.);\n }\n\n float opacity = 1. - smoothstep(.82 - 2. * fwidth(mask), .82, mask);\n\n float ridge = .15 * (smoothstep(.0, .15, uv.y) * smoothstep(.4, .15, uv.y));\n ridge += .05 * (smoothstep(.1, .2, 1. - uv.y) * smoothstep(.4, .2, 1. - uv.y));\n mask += ridge;\n\n float diagBLtoTR = uv.x - uv.y;\n float diagTLtoBR = uv.x + uv.y;\n\n vec3 color = vec3(0.);\n vec3 color1 = vec3(.98, 0.98, 1.);\n vec3 color2 = vec3(.1, .1, .1 + .1 * smoothstep(.7, 1.3, diagTLtoBR));\n\n vec2 grad_uv = uv - .5;\n\n float dist = length(grad_uv + vec2(0., .2 * diagBLtoTR));\n grad_uv = rotate(grad_uv, (.25 - .2 * diagBLtoTR) * PI);\n float direction = grad_uv.x;\n\n float bump = pow(1.8 * dist, 1.2);\n bump = 1. - bump;\n bump *= pow(uv.y, .3);\n\n\n float thin_strip_1_ratio = .12 / cycleWidth * (1. - .4 * bump);\n float thin_strip_2_ratio = .07 / cycleWidth * (1. + .4 * bump);\n float wide_strip_ratio = (1. - thin_strip_1_ratio - thin_strip_2_ratio);\n\n float thin_strip_1_width = cycleWidth * thin_strip_1_ratio;\n float thin_strip_2_width = cycleWidth * thin_strip_2_ratio;\n\n float noise = snoise(uv - t);\n\n mask += (1. - mask) * u_distortion * noise;\n\n direction += diagBLtoTR;\n\n float contour = u_contour * smoothstep(0., contOffset + .01, mask) * smoothstep(contOffset + .01, 0., mask);\n direction -= 14. * noise * contour;\n\n bump *= clamp(pow(uv.y, .1), .3, 1.);\n direction *= (.1 + (1.1 - mask) * bump);\n direction *= smoothstep(1., .2, mask);\n\n\n direction *= (.5 + .5 * pow(uv.y, 2.));\n direction *= cycleWidth;\n direction -= t;\n\n\n float colorDispersion = (1. - bump);\n float dispersionRed = colorDispersion;\n dispersionRed += bump * noise;\n float dispersionBlue = colorDispersion;\n\n dispersionRed *= (u_shiftRed / 20.);\n dispersionBlue *= (u_shiftBlue / 20.);\n\n float blur = u_softness / 15. + .3 * contour;\n\n vec3 w = vec3(thin_strip_1_width, thin_strip_2_width, wide_strip_ratio);\n w[1] -= .02 * smoothstep(.0, 1., mask + bump);\n float stripe_r = mod(direction + dispersionRed, 1.);\n float r = getColorChanges(color1.r, color2.r, stripe_r, w, blur + fwidth(stripe_r), bump, u_colorTint.r);\n float stripe_g = mod(direction, 1.);\n float g = getColorChanges(color1.g, color2.g, stripe_g, w, blur + fwidth(stripe_g), bump, u_colorTint.g);\n float stripe_b = mod(direction - dispersionBlue, 1.);\n float b = getColorChanges(color1.b, color2.b, stripe_b, w, blur + fwidth(stripe_b), bump, u_colorTint.b);\n\n color = vec3(r, g, b);\n color *= opacity;\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 LiquidMetalUniforms extends ShaderSizingUniforms {\n u_colorBack: [number, number, number, number];\n u_colorTint: [number, number, number, number];\n u_softness: number;\n u_repetition: number;\n u_shiftRed: number;\n u_shiftBlue: number;\n u_distortion: number;\n u_contour: number;\n u_shape: (typeof LiquidMetalShapes)[LiquidMetalShape];\n}\n\nexport interface LiquidMetalParams extends ShaderSizingParams, ShaderMotionParams {\n colorBack?: string;\n colorTint?: string;\n softness?: number;\n repetition?: number;\n shiftRed?: number;\n shiftBlue?: number;\n distortion?: number;\n contour?: number;\n shape?: LiquidMetalShape;\n}\n\nexport const LiquidMetalShapes = {\n none: 0,\n circle: 1,\n daisy: 2,\n metaballs: 3,\n} as const;\n\nexport type LiquidMetalShape = keyof typeof LiquidMetalShapes;\n"],
|
|
5
|
-
"mappings": ";;;;;AACA,SAAS,kCAAsF;AAC/F,SAAS,WAAW,WAAW,cAAc,uBAAuB;AAuB7D,MAAM,4BAAoC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,
|
|
4
|
+
"sourcesContent": ["import type { ShaderMotionParams } from '../shader-mount.js';\nimport { sizingVariablesDeclaration, type ShaderSizingParams, type ShaderSizingUniforms } from '../shader-sizing.js';\nimport { declarePI, rotation2, simplexNoise, colorBandingFix } from '../shader-utils.js';\n\n/**\n *\n * Fluid motion imitation applied over user image\n * (animated stripe pattern getting distorted with shape edges)\n *\n * Uniforms:\n * - u_colorBack, u_colorTint (RGBA)\n * - u_repetition: density of pattern stripes\n * - u_softness: blur between stripes\n * - u_shiftRed & u_shiftBlue: color dispersion between the stripes\n * - u_distortion: pattern distortion on the whole canvas\n * - u_contour: distortion power over the shape edges\n * - u_shape (float used as integer):\n * ---- 0: canvas-screen rectangle, needs u_worldWidth = u_worldHeight = 0 to be responsive (see vertex shader)\n * ---- 1: static circle\n * ---- 2: animated flower-like polar shape\n * ---- 3: animated metaballs\n *\n */\n\n// language=GLSL\nexport const liquidMetalFragmentShader: string = `#version 300 es\nprecision mediump float;\n\nuniform sampler2D u_image;\nuniform float u_imageAspectRatio;\n\nuniform float u_time;\n\nuniform vec4 u_colorBack;\nuniform vec4 u_colorTint;\n\nuniform float u_softness;\nuniform float u_repetition;\nuniform float u_shiftRed;\nuniform float u_shiftBlue;\nuniform float u_distortion;\nuniform float u_contour;\n\nuniform float u_shape;\nuniform bool u_isImage;\n\n${sizingVariablesDeclaration}\n\nout vec4 fragColor;\n\n${declarePI}\n${rotation2}\n${simplexNoise}\n\nfloat getColorChanges(float c1, float c2, float stripe_p, vec3 w, float blur, float bump, float tint) {\n\n float ch = mix(c2, c1, smoothstep(.0, 2. * blur, stripe_p));\n\n float border = w[0];\n ch = mix(ch, c2, smoothstep(border, border + 2. * blur, stripe_p));\n\n if (u_isImage == true) {\n bump = smoothstep(.2, .8, bump);\n }\n border = w[0] + .4 * (1. - bump) * w[1];\n ch = mix(ch, c1, smoothstep(border, border + 2. * blur, stripe_p));\n\n border = w[0] + .5 * (1. - bump) * w[1];\n ch = mix(ch, c2, smoothstep(border, border + 2. * blur, stripe_p));\n\n border = w[0] + w[1];\n ch = mix(ch, c1, smoothstep(border, border + 2. * blur, stripe_p));\n\n float gradient_t = (stripe_p - w[0] - w[1]) / w[2];\n float gradient = mix(c1, c2, smoothstep(0., 1., gradient_t));\n ch = mix(ch, gradient, smoothstep(border, border + .5 * blur, stripe_p));\n\n // Tint color is applied with color burn blending\n ch = mix(ch, 1. - min(1., (1. - ch) / max(tint, 0.0001)), u_colorTint.a);\n return ch;\n}\n\nfloat getImgFrame(vec2 uv, float th) {\n float frame = 1.;\n frame *= smoothstep(0., th, uv.y);\n frame *= smoothstep(1., 1. - th, uv.y);\n frame *= smoothstep(0., th, uv.x);\n frame *= smoothstep(1., 1. - th, uv.x);\n return frame;\n}\n\nfloat blurEdge3x3(sampler2D tex, vec2 uv, vec2 dudx, vec2 dudy, float radius, float centerSample) {\n vec2 texel = 1.0 / vec2(textureSize(tex, 0));\n vec2 r = radius * texel;\n\n float w1 = 1.0, w2 = 2.0, w4 = 4.0;\n float norm = 16.0;\n float sum = w4 * centerSample;\n\n sum += w2 * textureGrad(tex, uv + vec2(0.0, -r.y), dudx, dudy).r;\n sum += w2 * textureGrad(tex, uv + vec2(0.0, r.y), dudx, dudy).r;\n sum += w2 * textureGrad(tex, uv + vec2(-r.x, 0.0), dudx, dudy).r;\n sum += w2 * textureGrad(tex, uv + vec2(r.x, 0.0), dudx, dudy).r;\n\n sum += w1 * textureGrad(tex, uv + vec2(-r.x, -r.y), dudx, dudy).r;\n sum += w1 * textureGrad(tex, uv + vec2(r.x, -r.y), dudx, dudy).r;\n sum += w1 * textureGrad(tex, uv + vec2(-r.x, r.y), dudx, dudy).r;\n sum += w1 * textureGrad(tex, uv + vec2(r.x, r.y), dudx, dudy).r;\n\n return sum / norm;\n}\n\n\nvoid main() {\n\n float t = (u_isImage ? .3 : .1) * u_time;\n\n vec2 uv = v_imageUV;\n vec2 dudx = dFdx(v_imageUV);\n vec2 dudy = dFdy(v_imageUV);\n vec4 img = textureGrad(u_image, uv, dudx, dudy);\n\n if (u_isImage == false) {\n uv = v_objectUV + .5;\n uv.y = 1. - uv.y;\n }\n\n float cycleWidth = u_repetition;\n if (u_isImage == false) {\n cycleWidth *= .5;\n }\n\n float edge = 0.;\n float contOffset = 1.;\n\n if (u_isImage == true) {\n float edgeRaw = img.r;\n edge = blurEdge3x3(u_image, uv, dudx, dudy, 6., edgeRaw);\n edge = pow(edge, 1.6);\n edge *= mix(0.0, 1.0, smoothstep(0.0, 0.4, u_contour));\n } else {\n if (u_shape < 1.) {\n\n vec2 borderUV = v_responsiveUV + .5;\n float ratio = v_responsiveBoxGivenSize.x / v_responsiveBoxGivenSize.y;\n vec2 mask = min(borderUV, 1. - borderUV);\n vec2 pixel_thickness = 250. / v_responsiveBoxGivenSize;\n float maskX = smoothstep(0.0, pixel_thickness.x, mask.x);\n float maskY = smoothstep(0.0, pixel_thickness.y, mask.y);\n maskX = pow(maskX, .25);\n maskY = pow(maskY, .25);\n edge = clamp(1. - maskX * maskY, 0., 1.);\n\n uv = v_responsiveUV;\n if (ratio > 1.) {\n uv.y /= ratio;\n } else {\n uv.x *= ratio;\n }\n uv += .5;\n uv.y = 1. - uv.y;\n\n cycleWidth *= 2.;\n contOffset = 1.5;\n\n } else if (u_shape < 2.) {\n vec2 shapeUV = uv - .5;\n shapeUV *= .67;\n edge = pow(clamp(3. * length(shapeUV), 0., 1.), 18.);\n } else if (u_shape < 3.) {\n vec2 shapeUV = uv - .5;\n shapeUV *= 1.68;\n\n float r = length(shapeUV) * 2.;\n float a = atan(shapeUV.y, shapeUV.x) + .2;\n r *= (1. + .05 * sin(3. * a + 2. * t));\n float f = abs(cos(a * 3.));\n edge = smoothstep(f, f + .7, r);\n edge = pow(edge, 2.);\n\n uv *= .8;\n cycleWidth *= 1.6;\n\n } else if (u_shape < 4.) {\n vec2 shapeUV = uv - .5;\n shapeUV *= 1.3;\n edge = 0.;\n for (int i = 0; i < 5; i++) {\n float fi = float(i);\n float speed = 4.5 + 2. * sin(fi * 12.345);\n float angle = -fi * 1.5;\n vec2 dir1 = vec2(cos(angle), sin(angle));\n vec2 dir2 = vec2(cos(angle + 1.57), sin(angle + 1.));\n vec2 traj = .4 * (dir1 * sin(t * speed + fi * 1.23) + dir2 * cos(t * (speed * 0.7) + fi * 2.17));\n float d = length(shapeUV + traj);\n edge += pow(1.0 - clamp(d, 0.0, 1.0), 4.0);\n }\n edge = 1. - smoothstep(.65, .9, edge);\n edge = pow(edge, 4.);\n }\n\n }\n\n float opacity = 0.;\n if (u_isImage == true) {\n opacity = img.g;\n float frame = getImgFrame(v_imageUV, 0.);\n opacity *= frame;\n } else {\n opacity = 1. - smoothstep(.82 - 2. * fwidth(edge), .82, edge);\n }\n\n if (u_isImage == false) {\n float ridge = .15 * (smoothstep(.0, .15, uv.y) * smoothstep(.4, .15, uv.y));\n ridge += .05 * (smoothstep(.1, .2, 1. - uv.y) * smoothstep(.4, .2, 1. - uv.y));\n edge += ridge;\n }\n\n float diagBLtoTR = uv.x - uv.y;\n float diagTLtoBR = uv.x + uv.y;\n\n vec3 color = vec3(0.);\n vec3 color1 = vec3(.98, 0.98, 1.);\n vec3 color2 = vec3(.1, .1, .1 + .1 * smoothstep(.7, 1.3, diagTLtoBR));\n\n vec2 grad_uv = uv - .5;\n\n float dist = length(grad_uv + vec2(0., .2 * diagBLtoTR));\n grad_uv = rotate(grad_uv, (.25 - .2 * diagBLtoTR) * PI);\n float direction = grad_uv.x;\n\n float bump = pow(1.8 * dist, 1.2);\n bump = 1. - bump;\n bump *= pow(uv.y, .3);\n\n\n float thin_strip_1_ratio = .12 / cycleWidth * (1. - .4 * bump);\n float thin_strip_2_ratio = .07 / cycleWidth * (1. + .4 * bump);\n float wide_strip_ratio = (1. - thin_strip_1_ratio - thin_strip_2_ratio);\n\n float thin_strip_1_width = cycleWidth * thin_strip_1_ratio;\n float thin_strip_2_width = cycleWidth * thin_strip_2_ratio;\n\n float noise = snoise(uv - t);\n\n edge += (1. - edge) * u_distortion * noise;\n\n direction += diagBLtoTR;\n float contour = 0.;\n if (u_isImage == false) {\n contour = u_contour * smoothstep(0., contOffset + .01, edge) * smoothstep(contOffset + .01, 0., edge);\n direction -= 14. * noise * contour;\n } else {\n direction -= 2. * noise * diagBLtoTR * (smoothstep(0., 1., edge) * smoothstep(1., 0., edge));\n direction *= mix(1., 1. - edge, smoothstep(.5, 1., u_contour));\n direction -= 1.7 * edge * smoothstep(.5, 1., u_contour);\n direction += .2 * pow(u_contour, 4.) * smoothstep(1., 0., edge);\n }\n\n\n bump *= clamp(pow(uv.y, .1), .3, 1.);\n direction *= (.1 + (1.1 - edge) * bump);\n\n if (u_isImage == false) {\n direction *= smoothstep(1., .2, edge);\n } else {\n direction *= (.4 + .6 * smoothstep(1., .5, edge));\n direction += .18 * (smoothstep(.1, .2, uv.y) * smoothstep(.4, .2, uv.y));\n direction += .03 * (smoothstep(.1, .2, 1. - uv.y) * smoothstep(.4, .2, 1. - uv.y));\n }\n\n direction *= (.5 + .5 * pow(uv.y, 2.));\n direction *= cycleWidth;\n direction -= t;\n\n\n float colorDispersion = (1. - bump);\n colorDispersion = clamp(colorDispersion, 0., 1.);\n float dispersionRed = colorDispersion;\n if (u_isImage == true) {\n dispersionRed += .03 * bump * noise;\n dispersionRed += 5. * (smoothstep(-.1, .2, uv.y) * smoothstep(.5, .1, uv.y)) * (smoothstep(.4, .6, bump) * smoothstep(1., .4, bump));\n dispersionRed -= diagBLtoTR;\n } else {\n dispersionRed += bump * noise;\n }\n\n float dispersionBlue = colorDispersion;\n if (u_isImage == true) {\n dispersionBlue *= 1.3;\n dispersionBlue += (smoothstep(0., .4, uv.y) * smoothstep(.8, .1, uv.y)) * (smoothstep(.4, .6, bump) * smoothstep(.8, .4, bump));\n dispersionBlue -= .2 * edge;\n }\n\n dispersionRed *= (u_shiftRed / 20.);\n dispersionBlue *= (u_shiftBlue / 20.);\n\n float blur = 0.;\n float rExtraBlur = 0.;\n float gExtraBlur = 0.;\n if (u_isImage == true) {\n float softness = 0.05 * u_softness;\n blur = softness + .5 * smoothstep(1., 10., u_repetition) * smoothstep(.0, 1., edge);\n rExtraBlur = softness * (0.05 + .1 * (u_shiftRed / 20.) * bump);\n gExtraBlur = softness * 0.05 / (1. - diagBLtoTR);\n } else {\n blur = u_softness / 15. + .3 * contour;\n }\n\n vec3 w = vec3(thin_strip_1_width, thin_strip_2_width, wide_strip_ratio);\n w[1] -= .02 * smoothstep(.0, 1., edge + bump);\n float stripe_r = mod(direction + dispersionRed, 1.);\n float r = getColorChanges(color1.r, color2.r, stripe_r, w, blur + fwidth(stripe_r) + rExtraBlur, bump, u_colorTint.r);\n float stripe_g = mod(direction, 1.);\n float g = getColorChanges(color1.g, color2.g, stripe_g, w, blur + fwidth(stripe_g) + gExtraBlur, bump, u_colorTint.g);\n float stripe_b = mod(direction - dispersionBlue, 1.);\n float b = getColorChanges(color1.b, color2.b, stripe_b, w, blur + fwidth(stripe_b), bump, u_colorTint.b);\n\n color = vec3(r, g, b);\n color *= opacity;\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\n// Configuration for Poisson solver\nexport const POISSON_CONFIG_OPTIMIZED = {\n measurePerformance: false, // Set to true to see performance metrics\n workingSize: 500, // Size to solve Poisson at (will upscale to original size)\n iterations: 30, // SOR converges ~2-20x faster than standard Gauss-Seidel\n};\n\n// Precomputed pixel data for sparse processing\ninterface SparsePixelData {\n interiorPixels: Uint32Array; // Indices of interior pixels\n boundaryPixels: Uint32Array; // Indices of boundary pixels\n pixelCount: number;\n // Neighbor indices for each interior pixel (4 neighbors per pixel)\n // Layout: [east, west, north, south] for each pixel\n neighborIndices: Int32Array;\n}\n\nexport function toProcessedLiquidMetal(file: File | string): Promise<{ imageData: ImageData; pngBlob: Blob }> {\n const canvas = document.createElement('canvas');\n const ctx = canvas.getContext('2d');\n\n return new Promise((resolve, reject) => {\n if (!file || !ctx) {\n reject(new Error('Invalid file or canvas context'));\n return;\n }\n\n const img = new Image();\n const totalStartTime = performance.now();\n\n img.onload = () => {\n // Force SVG to load at a high fidelity size if it's an SVG\n let isSVG;\n if (typeof file === 'string') {\n isSVG = file.endsWith('.svg') || file.startsWith('data:image/svg+xml');\n } else {\n isSVG = file.type === 'image/svg+xml';\n }\n\n let originalWidth = img.width || img.naturalWidth;\n let originalHeight = img.height || img.naturalHeight;\n\n if (isSVG) {\n // Scale SVG to max dimension while preserving aspect ratio\n const svgMaxSize = 4064;\n const aspectRatio = originalWidth / originalHeight;\n\n if (originalWidth > originalHeight) {\n originalWidth = svgMaxSize;\n originalHeight = svgMaxSize / aspectRatio;\n } else {\n originalHeight = svgMaxSize;\n originalWidth = svgMaxSize * aspectRatio;\n }\n\n img.width = originalWidth;\n img.height = originalHeight;\n }\n\n // Always scale to working resolution for consistency\n const minDimension = Math.min(originalWidth, originalHeight);\n const targetSize = POISSON_CONFIG_OPTIMIZED.workingSize;\n\n // Calculate scale to fit within workingSize\n const scaleFactor = targetSize / minDimension;\n const width = Math.round(originalWidth * scaleFactor);\n const height = Math.round(originalHeight * scaleFactor);\n\n if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {\n console.log(`[Processing Mode]`);\n console.log(` Original: ${originalWidth}\u00D7${originalHeight}`);\n console.log(` Working: ${width}\u00D7${height} (${(scaleFactor * 100).toFixed(1)}% scale)`);\n if (scaleFactor < 1) {\n console.log(` Speedup: ~${Math.round(1 / (scaleFactor * scaleFactor))}\u00D7`);\n }\n }\n\n canvas.width = originalWidth;\n canvas.height = originalHeight;\n\n // Use a smaller canvas for shape detection and Poisson solving\n const shapeCanvas = document.createElement('canvas');\n shapeCanvas.width = width;\n shapeCanvas.height = height;\n\n const shapeCtx = shapeCanvas.getContext('2d')!;\n shapeCtx.drawImage(img, 0, 0, width, height);\n\n // 1) Build optimized masks using TypedArrays\n const startMask = performance.now();\n\n const shapeImageData = shapeCtx.getImageData(0, 0, width, height);\n const data = shapeImageData.data;\n\n // Use Uint8Array for masks (1 byte per pixel vs 8+ bytes for boolean array)\n const shapeMask = new Uint8Array(width * height);\n const boundaryMask = new Uint8Array(width * height);\n\n // First pass: identify shape pixels\n let shapePixelCount = 0;\n for (let i = 0, idx = 0; i < data.length; i += 4, idx++) {\n const a = data[i + 3];\n const isShape = a === 0 ? 0 : 1;\n shapeMask[idx] = isShape;\n shapePixelCount += isShape;\n }\n\n // 2) Optimized boundary detection using sparse approach\n // Only check shape pixels, not all pixels\n const boundaryIndices: number[] = [];\n const interiorIndices: number[] = [];\n\n for (let y = 0; y < height; y++) {\n for (let x = 0; x < width; x++) {\n const idx = y * width + x;\n if (!shapeMask[idx]) continue;\n\n // Check if pixel is on boundary (optimized: early exit)\n let isBoundary = false;\n\n // Check 4-connected neighbors first (most common case)\n if (x === 0 || x === width - 1 || y === 0 || y === height - 1) {\n isBoundary = true;\n } else {\n // Check all 8 neighbors (including diagonals) for comprehensive boundary detection\n isBoundary =\n !shapeMask[idx - 1] || // left\n !shapeMask[idx + 1] || // right\n !shapeMask[idx - width] || // top\n !shapeMask[idx + width] || // bottom\n !shapeMask[idx - width - 1] || // top-left\n !shapeMask[idx - width + 1] || // top-right\n !shapeMask[idx + width - 1] || // bottom-left\n !shapeMask[idx + width + 1]; // bottom-right\n }\n\n if (isBoundary) {\n boundaryMask[idx] = 1;\n boundaryIndices.push(idx);\n } else {\n interiorIndices.push(idx);\n }\n }\n }\n\n if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {\n console.log(`[Mask Building] Time: ${(performance.now() - startMask).toFixed(2)}ms`);\n console.log(\n ` Shape pixels: ${shapePixelCount} / ${width * height} (${((shapePixelCount / (width * height)) * 100).toFixed(1)}%)`\n );\n console.log(` Interior pixels: ${interiorIndices.length}`);\n console.log(` Boundary pixels: ${boundaryIndices.length}`);\n }\n\n // 3) Precompute sparse data structure for solver\n const sparseData = buildSparseData(\n shapeMask,\n boundaryMask,\n new Uint32Array(interiorIndices),\n new Uint32Array(boundaryIndices),\n width,\n height\n );\n\n // 4) Solve Poisson equation with optimized sparse solver\n const startSolve = performance.now();\n const u = solvePoissonSparse(sparseData, shapeMask, boundaryMask, width, height);\n\n if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {\n console.log(`[Poisson Solve] Time: ${(performance.now() - startSolve).toFixed(2)}ms`);\n }\n\n // 5) Generate output image\n let maxVal = 0;\n let finalImageData: ImageData;\n\n // Only check shape pixels for max value\n for (let i = 0; i < interiorIndices.length; i++) {\n const idx = interiorIndices[i]!;\n if (u[idx]! > maxVal) maxVal = u[idx]!;\n }\n\n // Create gradient image at working resolution\n const tempCanvas = document.createElement('canvas');\n tempCanvas.width = width;\n tempCanvas.height = height;\n const tempCtx = tempCanvas.getContext('2d')!;\n\n const tempImg = tempCtx.createImageData(width, height);\n for (let y = 0; y < height; y++) {\n for (let x = 0; x < width; x++) {\n const idx = y * width + x;\n const px = idx * 4;\n\n if (!shapeMask[idx]) {\n tempImg.data[px] = 255;\n tempImg.data[px + 1] = 255;\n tempImg.data[px + 2] = 255;\n tempImg.data[px + 3] = 0; // Alpha = 0 for background\n } else {\n const poissonRatio = u[idx]! / maxVal;\n const gray = 255 * (1 - poissonRatio);\n tempImg.data[px] = gray;\n tempImg.data[px + 1] = gray;\n tempImg.data[px + 2] = gray;\n tempImg.data[px + 3] = 255; // Alpha = 255 for shape\n }\n }\n }\n tempCtx.putImageData(tempImg, 0, 0);\n\n // Upscale to original resolution with smooth interpolation\n ctx.imageSmoothingEnabled = true;\n ctx.imageSmoothingQuality = 'high';\n ctx.drawImage(tempCanvas, 0, 0, width, height, 0, 0, originalWidth, originalHeight);\n\n // Now get the upscaled image data for final output\n const outImg = ctx.getImageData(0, 0, originalWidth, originalHeight);\n\n // Re-apply edges from original resolution with anti-aliasing\n // This ensures edges are pixel-perfect while gradient is smooth\n const originalCanvas = document.createElement('canvas');\n originalCanvas.width = originalWidth;\n originalCanvas.height = originalHeight;\n const originalCtx = originalCanvas.getContext('2d')!;\n // originalCtx.fillStyle = \"white\";\n // originalCtx.fillRect(0, 0, originalWidth, originalHeight);\n originalCtx.drawImage(img, 0, 0, originalWidth, originalHeight);\n const originalData = originalCtx.getImageData(0, 0, originalWidth, originalHeight);\n\n // Process each pixel: Red channel = gradient, Alpha channel = original alpha\n for (let i = 0; i < outImg.data.length; i += 4) {\n const a = originalData.data[i + 3]!;\n // Use only alpha to determine background vs shape\n const upscaledAlpha = outImg.data[i + 3]!;\n if (a === 0) {\n // Background pixel\n outImg.data[i] = 255;\n outImg.data[i + 1] = 0;\n } else {\n // Red channel carries the gradient\n // Check if upscale missed this pixel by looking at alpha channel\n // If upscaled alpha is 0, the low-res version thought this was background\n outImg.data[i] = upscaledAlpha === 0 ? 0 : outImg.data[i]!; // gradient or 0\n outImg.data[i + 1] = a; // original alpha\n }\n\n // Unused channels fixed\n outImg.data[i + 2] = 255;\n outImg.data[i + 3] = 255;\n }\n\n ctx.putImageData(outImg, 0, 0);\n finalImageData = outImg;\n canvas.toBlob((blob) => {\n if (!blob) {\n reject(new Error('Failed to create PNG blob'));\n return;\n }\n\n if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {\n const totalTime = performance.now() - totalStartTime;\n console.log(`[Total Processing Time] ${totalTime.toFixed(2)}ms`);\n if (scaleFactor < 1) {\n const estimatedFullResTime = totalTime * Math.pow((originalWidth * originalHeight) / (width * height), 1.5);\n console.log(`[Estimated time at full resolution] ~${estimatedFullResTime.toFixed(0)}ms`);\n console.log(\n `[Time saved] ~${(estimatedFullResTime - totalTime).toFixed(0)}ms (${Math.round(estimatedFullResTime / totalTime)}\u00D7 faster)`\n );\n }\n }\n\n resolve({\n imageData: finalImageData,\n pngBlob: blob,\n });\n }, 'image/png');\n };\n\n img.onerror = () => reject(new Error('Failed to load image'));\n img.src = typeof file === 'string' ? file : URL.createObjectURL(file);\n });\n}\n\nfunction buildSparseData(\n shapeMask: Uint8Array,\n boundaryMask: Uint8Array,\n interiorPixels: Uint32Array,\n boundaryPixels: Uint32Array,\n width: number,\n height: number\n): SparsePixelData {\n const pixelCount = interiorPixels.length;\n\n // Build neighbor indices for sparse processing\n // For each interior pixel, store indices of its 4 neighbors\n // Use -1 for out-of-bounds or non-shape neighbors\n const neighborIndices = new Int32Array(pixelCount * 4);\n\n for (let i = 0; i < pixelCount; i++) {\n const idx = interiorPixels[i]!;\n const x = idx % width;\n const y = Math.floor(idx / width);\n\n // East neighbor\n neighborIndices[i * 4 + 0] = x < width - 1 && shapeMask[idx + 1] ? idx + 1 : -1;\n // West neighbor\n neighborIndices[i * 4 + 1] = x > 0 && shapeMask[idx - 1] ? idx - 1 : -1;\n // North neighbor\n neighborIndices[i * 4 + 2] = y > 0 && shapeMask[idx - width] ? idx - width : -1;\n // South neighbor\n neighborIndices[i * 4 + 3] = y < height - 1 && shapeMask[idx + width] ? idx + width : -1;\n }\n\n return {\n interiorPixels,\n boundaryPixels,\n pixelCount,\n neighborIndices,\n };\n}\n\nfunction solvePoissonSparse(\n sparseData: SparsePixelData,\n shapeMask: Uint8Array,\n boundaryMask: Uint8Array,\n width: number,\n height: number\n): Float32Array {\n // This controls how smooth the falloff gradient will be and extend into the shape\n const ITERATIONS = POISSON_CONFIG_OPTIMIZED.iterations;\n\n // Keep C constant - only iterations control gradient spread\n const C = 0.01;\n\n const u = new Float32Array(width * height);\n const { interiorPixels, neighborIndices, pixelCount } = sparseData;\n\n // Performance tracking\n const startTime = performance.now();\n\n // Red-Black SOR for better symmetry with fewer iterations\n // omega between 1.8-1.95 typically gives best convergence for Poisson\n const omega = 1.9;\n\n // Pre-classify pixels as red or black for efficient processing\n const redPixels: number[] = [];\n const blackPixels: number[] = [];\n\n for (let i = 0; i < pixelCount; i++) {\n const idx = interiorPixels[i]!;\n const x = idx % width;\n const y = Math.floor(idx / width);\n\n if ((x + y) % 2 === 0) {\n redPixels.push(i);\n } else {\n blackPixels.push(i);\n }\n }\n\n for (let iter = 0; iter < ITERATIONS; iter++) {\n // Red pass: update red pixels\n for (const i of redPixels) {\n const idx = interiorPixels[i]!;\n\n // Get precomputed neighbor indices\n const eastIdx = neighborIndices[i * 4 + 0]!;\n const westIdx = neighborIndices[i * 4 + 1]!;\n const northIdx = neighborIndices[i * 4 + 2]!;\n const southIdx = neighborIndices[i * 4 + 3]!;\n\n // Sum neighbors (use 0 for out-of-bounds)\n let sumN = 0;\n if (eastIdx >= 0) sumN += u[eastIdx]!;\n if (westIdx >= 0) sumN += u[westIdx]!;\n if (northIdx >= 0) sumN += u[northIdx]!;\n if (southIdx >= 0) sumN += u[southIdx]!;\n\n // SOR update: blend new value with old value\n const newValue = (C + sumN) / 4;\n u[idx] = omega * newValue + (1 - omega) * u[idx]!;\n }\n\n // Black pass: update black pixels\n for (const i of blackPixels) {\n const idx = interiorPixels[i]!;\n\n // Get precomputed neighbor indices\n const eastIdx = neighborIndices[i * 4 + 0]!;\n const westIdx = neighborIndices[i * 4 + 1]!;\n const northIdx = neighborIndices[i * 4 + 2]!;\n const southIdx = neighborIndices[i * 4 + 3]!;\n\n // Sum neighbors (use 0 for out-of-bounds)\n let sumN = 0;\n if (eastIdx >= 0) sumN += u[eastIdx]!;\n if (westIdx >= 0) sumN += u[westIdx]!;\n if (northIdx >= 0) sumN += u[northIdx]!;\n if (southIdx >= 0) sumN += u[southIdx]!;\n\n // SOR update: blend new value with old value\n const newValue = (C + sumN) / 4;\n u[idx] = omega * newValue + (1 - omega) * u[idx]!;\n }\n }\n\n if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {\n const elapsed = performance.now() - startTime;\n\n console.log(`[Optimized Poisson Solver (SOR \u03C9=${omega})]`);\n console.log(` Working size: ${width}\u00D7${height}`);\n console.log(` Iterations: ${ITERATIONS}`);\n console.log(` Time: ${elapsed.toFixed(2)}ms`);\n console.log(` Interior pixels processed: ${pixelCount}`);\n console.log(` Speed: ${((ITERATIONS * pixelCount) / (elapsed * 1000)).toFixed(2)} Mpixels/sec`);\n }\n\n return u;\n}\n\nexport interface LiquidMetalUniforms extends ShaderSizingUniforms {\n u_colorBack: [number, number, number, number];\n u_colorTint: [number, number, number, number];\n u_image: HTMLImageElement | string | undefined;\n u_repetition: number;\n u_shiftRed: number;\n u_shiftBlue: number;\n u_contour: number;\n u_softness: number;\n u_distortion: number;\n u_shape: (typeof LiquidMetalShapes)[LiquidMetalShape];\n u_isImage: boolean;\n}\n\nexport interface LiquidMetalParams extends ShaderSizingParams, ShaderMotionParams {\n colorBack?: string;\n colorTint?: string;\n image?: HTMLImageElement | string | undefined;\n repetition?: number;\n shiftRed?: number;\n shiftBlue?: number;\n contour?: number;\n softness?: number;\n distortion?: number;\n shape?: LiquidMetalShape;\n}\n\nexport const LiquidMetalShapes = {\n none: 0,\n circle: 1,\n daisy: 2,\n metaballs: 3,\n} as const;\n\nexport type LiquidMetalShape = keyof typeof LiquidMetalShapes;\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|