@paper-design/shaders 0.0.57 → 0.0.58-next.2

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 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// ----- Liquid Metal ----- //\n/** Liquid metal effect applied to the abstract shapes */\nexport {\n liquidMetalFragmentShader,\n LiquidMetalShapes,\n type LiquidMetalParams,\n type LiquidMetalUniforms,\n type LiquidMetalShape,\n} from './shaders/liquid-metal.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\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,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;AAGP,SAAS,gCAAgC;AACzC,SAAS,6BAA6B;AACtC,SAAS,qBAAqB;",
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 abstract shapes
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
- u_softness: number;
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
- softness?: number;
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 = v_objectUV;
62
- uv += .5;
63
- uv.y = 1. - uv.y;
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
- float cycleWidth = .5 * u_repetition;
105
+ if (u_isImage == false) {
106
+ uv = v_objectUV + .5;
107
+ uv.y = 1. - uv.y;
108
+ }
66
109
 
67
- float mask = 1.;
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 (u_shape < 1.) {
71
-
72
- vec2 borderUV = v_responsiveUV + .5;
73
- float ratio = v_responsiveBoxGivenSize.x / v_responsiveBoxGivenSize.y;
74
- vec2 edge = min(borderUV, 1. - borderUV);
75
- vec2 pixel_thickness = 250. / v_responsiveBoxGivenSize;
76
- float maskX = smoothstep(0.0, pixel_thickness.x, edge.x);
77
- float maskY = smoothstep(0.0, pixel_thickness.y, edge.y);
78
- maskX = pow(maskX, .25);
79
- maskY = pow(maskY, .25);
80
- mask = clamp(1. - maskX * maskY, 0., 1.);
81
-
82
- uv = v_responsiveUV;
83
- if (ratio > 1.) {
84
- uv.y /= ratio;
85
- } else {
86
- uv.x *= ratio;
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 = 1. - smoothstep(.82 - 2. * fwidth(mask), .82, mask);
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
- float ridge = .15 * (smoothstep(.0, .15, uv.y) * smoothstep(.4, .15, uv.y));
133
- ridge += .05 * (smoothstep(.1, .2, 1. - uv.y) * smoothstep(.4, .2, 1. - uv.y));
134
- mask += ridge;
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
- mask += (1. - mask) * u_distortion * noise;
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 - mask) * bump);
172
- direction *= smoothstep(1., .2, mask);
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
- dispersionRed += bump * noise;
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 = u_softness / 15. + .3 * contour;
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., mask + bump);
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,288 @@ 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
+ img.crossOrigin = "anonymous";
331
+ const totalStartTime = performance.now();
332
+ img.onload = () => {
333
+ let isSVG;
334
+ if (typeof file === "string") {
335
+ isSVG = file.endsWith(".svg") || file.startsWith("data:image/svg+xml");
336
+ } else {
337
+ isSVG = file.type === "image/svg+xml";
338
+ }
339
+ let originalWidth = img.width || img.naturalWidth;
340
+ let originalHeight = img.height || img.naturalHeight;
341
+ if (isSVG) {
342
+ const svgMaxSize = 4064;
343
+ const aspectRatio = originalWidth / originalHeight;
344
+ if (originalWidth > originalHeight) {
345
+ originalWidth = svgMaxSize;
346
+ originalHeight = svgMaxSize / aspectRatio;
347
+ } else {
348
+ originalHeight = svgMaxSize;
349
+ originalWidth = svgMaxSize * aspectRatio;
350
+ }
351
+ img.width = originalWidth;
352
+ img.height = originalHeight;
353
+ }
354
+ const minDimension = Math.min(originalWidth, originalHeight);
355
+ const targetSize = POISSON_CONFIG_OPTIMIZED.workingSize;
356
+ const scaleFactor = targetSize / minDimension;
357
+ const width = Math.round(originalWidth * scaleFactor);
358
+ const height = Math.round(originalHeight * scaleFactor);
359
+ if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {
360
+ console.log(`[Processing Mode]`);
361
+ console.log(` Original: ${originalWidth}\xD7${originalHeight}`);
362
+ console.log(` Working: ${width}\xD7${height} (${(scaleFactor * 100).toFixed(1)}% scale)`);
363
+ if (scaleFactor < 1) {
364
+ console.log(` Speedup: ~${Math.round(1 / (scaleFactor * scaleFactor))}\xD7`);
365
+ }
366
+ }
367
+ canvas.width = originalWidth;
368
+ canvas.height = originalHeight;
369
+ const shapeCanvas = document.createElement("canvas");
370
+ shapeCanvas.width = width;
371
+ shapeCanvas.height = height;
372
+ const shapeCtx = shapeCanvas.getContext("2d");
373
+ shapeCtx.drawImage(img, 0, 0, width, height);
374
+ const startMask = performance.now();
375
+ const shapeImageData = shapeCtx.getImageData(0, 0, width, height);
376
+ const data = shapeImageData.data;
377
+ const shapeMask = new Uint8Array(width * height);
378
+ const boundaryMask = new Uint8Array(width * height);
379
+ let shapePixelCount = 0;
380
+ for (let i = 0, idx = 0; i < data.length; i += 4, idx++) {
381
+ const a = data[i + 3];
382
+ const isShape = a === 0 ? 0 : 1;
383
+ shapeMask[idx] = isShape;
384
+ shapePixelCount += isShape;
385
+ }
386
+ const boundaryIndices = [];
387
+ const interiorIndices = [];
388
+ for (let y = 0; y < height; y++) {
389
+ for (let x = 0; x < width; x++) {
390
+ const idx = y * width + x;
391
+ if (!shapeMask[idx]) continue;
392
+ let isBoundary = false;
393
+ if (x === 0 || x === width - 1 || y === 0 || y === height - 1) {
394
+ isBoundary = true;
395
+ } else {
396
+ isBoundary = !shapeMask[idx - 1] || // left
397
+ !shapeMask[idx + 1] || // right
398
+ !shapeMask[idx - width] || // top
399
+ !shapeMask[idx + width] || // bottom
400
+ !shapeMask[idx - width - 1] || // top-left
401
+ !shapeMask[idx - width + 1] || // top-right
402
+ !shapeMask[idx + width - 1] || // bottom-left
403
+ !shapeMask[idx + width + 1];
404
+ }
405
+ if (isBoundary) {
406
+ boundaryMask[idx] = 1;
407
+ boundaryIndices.push(idx);
408
+ } else {
409
+ interiorIndices.push(idx);
410
+ }
411
+ }
412
+ }
413
+ if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {
414
+ console.log(`[Mask Building] Time: ${(performance.now() - startMask).toFixed(2)}ms`);
415
+ console.log(
416
+ ` Shape pixels: ${shapePixelCount} / ${width * height} (${(shapePixelCount / (width * height) * 100).toFixed(1)}%)`
417
+ );
418
+ console.log(` Interior pixels: ${interiorIndices.length}`);
419
+ console.log(` Boundary pixels: ${boundaryIndices.length}`);
420
+ }
421
+ const sparseData = buildSparseData(
422
+ shapeMask,
423
+ boundaryMask,
424
+ new Uint32Array(interiorIndices),
425
+ new Uint32Array(boundaryIndices),
426
+ width,
427
+ height
428
+ );
429
+ const startSolve = performance.now();
430
+ const u = solvePoissonSparse(sparseData, shapeMask, boundaryMask, width, height);
431
+ if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {
432
+ console.log(`[Poisson Solve] Time: ${(performance.now() - startSolve).toFixed(2)}ms`);
433
+ }
434
+ let maxVal = 0;
435
+ let finalImageData;
436
+ for (let i = 0; i < interiorIndices.length; i++) {
437
+ const idx = interiorIndices[i];
438
+ if (u[idx] > maxVal) maxVal = u[idx];
439
+ }
440
+ const tempCanvas = document.createElement("canvas");
441
+ tempCanvas.width = width;
442
+ tempCanvas.height = height;
443
+ const tempCtx = tempCanvas.getContext("2d");
444
+ const tempImg = tempCtx.createImageData(width, height);
445
+ for (let y = 0; y < height; y++) {
446
+ for (let x = 0; x < width; x++) {
447
+ const idx = y * width + x;
448
+ const px = idx * 4;
449
+ if (!shapeMask[idx]) {
450
+ tempImg.data[px] = 255;
451
+ tempImg.data[px + 1] = 255;
452
+ tempImg.data[px + 2] = 255;
453
+ tempImg.data[px + 3] = 0;
454
+ } else {
455
+ const poissonRatio = u[idx] / maxVal;
456
+ const gray = 255 * (1 - poissonRatio);
457
+ tempImg.data[px] = gray;
458
+ tempImg.data[px + 1] = gray;
459
+ tempImg.data[px + 2] = gray;
460
+ tempImg.data[px + 3] = 255;
461
+ }
462
+ }
463
+ }
464
+ tempCtx.putImageData(tempImg, 0, 0);
465
+ ctx.imageSmoothingEnabled = true;
466
+ ctx.imageSmoothingQuality = "high";
467
+ ctx.drawImage(tempCanvas, 0, 0, width, height, 0, 0, originalWidth, originalHeight);
468
+ const outImg = ctx.getImageData(0, 0, originalWidth, originalHeight);
469
+ const originalCanvas = document.createElement("canvas");
470
+ originalCanvas.width = originalWidth;
471
+ originalCanvas.height = originalHeight;
472
+ const originalCtx = originalCanvas.getContext("2d");
473
+ originalCtx.drawImage(img, 0, 0, originalWidth, originalHeight);
474
+ const originalData = originalCtx.getImageData(0, 0, originalWidth, originalHeight);
475
+ for (let i = 0; i < outImg.data.length; i += 4) {
476
+ const a = originalData.data[i + 3];
477
+ const upscaledAlpha = outImg.data[i + 3];
478
+ if (a === 0) {
479
+ outImg.data[i] = 255;
480
+ outImg.data[i + 1] = 0;
481
+ } else {
482
+ outImg.data[i] = upscaledAlpha === 0 ? 0 : outImg.data[i];
483
+ outImg.data[i + 1] = a;
484
+ }
485
+ outImg.data[i + 2] = 255;
486
+ outImg.data[i + 3] = 255;
487
+ }
488
+ ctx.putImageData(outImg, 0, 0);
489
+ finalImageData = outImg;
490
+ canvas.toBlob((blob) => {
491
+ if (!blob) {
492
+ reject(new Error("Failed to create PNG blob"));
493
+ return;
494
+ }
495
+ if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {
496
+ const totalTime = performance.now() - totalStartTime;
497
+ console.log(`[Total Processing Time] ${totalTime.toFixed(2)}ms`);
498
+ if (scaleFactor < 1) {
499
+ const estimatedFullResTime = totalTime * Math.pow(originalWidth * originalHeight / (width * height), 1.5);
500
+ console.log(`[Estimated time at full resolution] ~${estimatedFullResTime.toFixed(0)}ms`);
501
+ console.log(
502
+ `[Time saved] ~${(estimatedFullResTime - totalTime).toFixed(0)}ms (${Math.round(estimatedFullResTime / totalTime)}\xD7 faster)`
503
+ );
504
+ }
505
+ }
506
+ resolve({
507
+ imageData: finalImageData,
508
+ pngBlob: blob
509
+ });
510
+ }, "image/png");
511
+ };
512
+ img.onerror = () => reject(new Error("Failed to load image"));
513
+ img.src = typeof file === "string" ? file : URL.createObjectURL(file);
514
+ });
515
+ }
516
+ function buildSparseData(shapeMask, boundaryMask, interiorPixels, boundaryPixels, width, height) {
517
+ const pixelCount = interiorPixels.length;
518
+ const neighborIndices = new Int32Array(pixelCount * 4);
519
+ for (let i = 0; i < pixelCount; i++) {
520
+ const idx = interiorPixels[i];
521
+ const x = idx % width;
522
+ const y = Math.floor(idx / width);
523
+ neighborIndices[i * 4 + 0] = x < width - 1 && shapeMask[idx + 1] ? idx + 1 : -1;
524
+ neighborIndices[i * 4 + 1] = x > 0 && shapeMask[idx - 1] ? idx - 1 : -1;
525
+ neighborIndices[i * 4 + 2] = y > 0 && shapeMask[idx - width] ? idx - width : -1;
526
+ neighborIndices[i * 4 + 3] = y < height - 1 && shapeMask[idx + width] ? idx + width : -1;
527
+ }
528
+ return {
529
+ interiorPixels,
530
+ boundaryPixels,
531
+ pixelCount,
532
+ neighborIndices
533
+ };
534
+ }
535
+ function solvePoissonSparse(sparseData, shapeMask, boundaryMask, width, height) {
536
+ const ITERATIONS = POISSON_CONFIG_OPTIMIZED.iterations;
537
+ const C = 0.01;
538
+ const u = new Float32Array(width * height);
539
+ const { interiorPixels, neighborIndices, pixelCount } = sparseData;
540
+ const startTime = performance.now();
541
+ const omega = 1.9;
542
+ const redPixels = [];
543
+ const blackPixels = [];
544
+ for (let i = 0; i < pixelCount; i++) {
545
+ const idx = interiorPixels[i];
546
+ const x = idx % width;
547
+ const y = Math.floor(idx / width);
548
+ if ((x + y) % 2 === 0) {
549
+ redPixels.push(i);
550
+ } else {
551
+ blackPixels.push(i);
552
+ }
553
+ }
554
+ for (let iter = 0; iter < ITERATIONS; iter++) {
555
+ for (const i of redPixels) {
556
+ const idx = interiorPixels[i];
557
+ const eastIdx = neighborIndices[i * 4 + 0];
558
+ const westIdx = neighborIndices[i * 4 + 1];
559
+ const northIdx = neighborIndices[i * 4 + 2];
560
+ const southIdx = neighborIndices[i * 4 + 3];
561
+ let sumN = 0;
562
+ if (eastIdx >= 0) sumN += u[eastIdx];
563
+ if (westIdx >= 0) sumN += u[westIdx];
564
+ if (northIdx >= 0) sumN += u[northIdx];
565
+ if (southIdx >= 0) sumN += u[southIdx];
566
+ const newValue = (C + sumN) / 4;
567
+ u[idx] = omega * newValue + (1 - omega) * u[idx];
568
+ }
569
+ for (const i of blackPixels) {
570
+ const idx = interiorPixels[i];
571
+ const eastIdx = neighborIndices[i * 4 + 0];
572
+ const westIdx = neighborIndices[i * 4 + 1];
573
+ const northIdx = neighborIndices[i * 4 + 2];
574
+ const southIdx = neighborIndices[i * 4 + 3];
575
+ let sumN = 0;
576
+ if (eastIdx >= 0) sumN += u[eastIdx];
577
+ if (westIdx >= 0) sumN += u[westIdx];
578
+ if (northIdx >= 0) sumN += u[northIdx];
579
+ if (southIdx >= 0) sumN += u[southIdx];
580
+ const newValue = (C + sumN) / 4;
581
+ u[idx] = omega * newValue + (1 - omega) * u[idx];
582
+ }
583
+ }
584
+ if (POISSON_CONFIG_OPTIMIZED.measurePerformance) {
585
+ const elapsed = performance.now() - startTime;
586
+ console.log(`[Optimized Poisson Solver (SOR \u03C9=${omega})]`);
587
+ console.log(` Working size: ${width}\xD7${height}`);
588
+ console.log(` Iterations: ${ITERATIONS}`);
589
+ console.log(` Time: ${elapsed.toFixed(2)}ms`);
590
+ console.log(` Interior pixels processed: ${pixelCount}`);
591
+ console.log(` Speed: ${(ITERATIONS * pixelCount / (elapsed * 1e3)).toFixed(2)} Mpixels/sec`);
592
+ }
593
+ return u;
594
+ }
211
595
  const LiquidMetalShapes = {
212
596
  none: 0,
213
597
  circle: 1,
@@ -216,6 +600,8 @@ const LiquidMetalShapes = {
216
600
  };
217
601
  export {
218
602
  LiquidMetalShapes,
219
- liquidMetalFragmentShader
603
+ POISSON_CONFIG_OPTIMIZED,
604
+ liquidMetalFragmentShader,
605
+ toProcessedLiquidMetal
220
606
  };
221
607
  //# 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,EAgB/C,0BAA0B;AAAA;AAAA;AAAA;AAAA,EAI1B,SAAS;AAAA,EACT,SAAS;AAAA,EACT,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAgLV,eAAe;AAAA;AAAA;AAAA;AAAA;AA8BZ,MAAM,oBAAoB;AAAA,EAC/B,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,WAAW;AACb;",
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 img.crossOrigin = 'anonymous';\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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@paper-design/shaders",
3
- "version": "0.0.57",
3
+ "version": "0.0.58-next.2",
4
4
  "license": "SEE LICENSE IN https://github.com/paper-design/shaders/blob/main/LICENSE",
5
5
  "type": "module",
6
6
  "sideEffects": false,