export const PARAMS = {
density: { value: 8.0, min: 1.5, max: 30, step: 0.1, label: "Cell Density", folder: "Structure" },
edgeSharp: { value: 0.4, min: 0.05, max: 1.5, step: 0.01, label: "Edge Sharpness", folder: "Appearance" },
warp: { value: 0.2, min: 0, max: 1.0, step: 0.01, label: "Domain Warp", folder: "Behavior" },
speed: { value: 0.15, min: 0, max: 1.0, step: 0.01, label: "Animation Speed", folder: "Behavior" },
hue: { value: 200, min: 0, max: 360, step: 1, label: "Base Hue", folder: "Appearance" },
};
export function shaderUniforms(params) {
return {
u_density: { value: params.density },
u_edgeSharp: { value: params.edgeSharp },
u_warp: { value: params.warp },
u_speed: { value: params.speed },
u_hue: { value: params.hue },
};
}
export function shaderAnimate(uniforms, params) {
uniforms.u_density.value = params.density;
uniforms.u_edgeSharp.value = params.edgeSharp;
uniforms.u_warp.value = params.warp;
uniforms.u_speed.value = params.speed;
uniforms.u_hue.value = params.hue;
}
export function fragmentShader() {
return `
uniform float u_time;
uniform vec2 u_resolution;
uniform float u_density;
uniform float u_edgeSharp;
uniform float u_warp;
uniform float u_speed;
uniform float u_hue;
vec2 hash22(vec2 p) {
p = vec2(dot(p, vec2(127.1, 311.7)), dot(p, vec2(269.5, 183.3)));
return -1.0 + 2.0 * fract(sin(p) * 43758.5453);
}
vec2 worley2(vec2 p) {
vec2 i = floor(p);
vec2 f = fract(p);
float F1 = 999.0, F2 = 999.0;
for (int y=-1; y<=1; y++) for (int x=-1; x<=1; x++) {
vec2 g = vec2(float(x), float(y));
vec2 o = 0.5 + 0.5 * sin(u_time * u_speed + 6.2831 * hash22(i + g));
float d = length(g + o - f);
if (d < F1) { F2 = F1; F1 = d; } else if (d < F2) { F2 = d; }
}
return vec2(F1, F2);
}
vec3 palette(float t, float baseHue) {
vec3 a = vec3(0.5), b = vec3(0.5), c = vec3(1.0);
vec3 d = vec3(0.0, 0.10, 0.20) + baseHue / 360.0;
return a + b * cos(6.2831853 * (c * t + d));
}
void main() {
vec2 uv = (gl_FragCoord.xy - 0.5 * u_resolution) / u_resolution.y;
// Domain warp
vec2 q = uv;
if (u_warp > 0.001) {
vec2 wp = uv * u_density * 0.4;
vec2 warpV = u_warp * vec2(
sin(wp.x * 1.7 + u_time * 0.5) * cos(wp.y * 1.3),
cos(wp.x * 1.4) * sin(wp.y * 1.1 + u_time * 0.3)
);
q += warpV;
}
vec2 v = worley2(q * u_density);
float edge = v.y - v.x;
// F2-F1 small at edges, large at centers -- invert and sharpen
float membrane = 1.0 - smoothstep(0.0, u_edgeSharp, edge);
vec3 cellCol = palette(v.x * 0.5, u_hue);
vec3 edgeCol = vec3(0.95, 0.95, 0.98);
vec3 col = mix(cellCol, edgeCol, membrane * 0.7);
col = pow(col, vec3(1.0 / 2.2));
gl_FragColor = vec4(col, 1.0);
}
`;
}