// Organic family: ink dropped into wet paper, spreading along the fibre.
//
// The bleed is done with feedback — each frame the previous one is sampled
// slightly outward along a noise-warped direction and darkened, which is a
// diffusion step in everything but name. Distinct from Curl Flow's trails
// (advected along a flow field, so they streak) because this expands in all
// directions at once, so it blooms.
//
// A base field is always drawn, so the scene stands alone before feedback has
// converged and survives a seek.

export const inkBleed = {
    name: 'Ink Bleed',
    family: 'organic',
    kind: 'fragment',
    traits: ['camera', 'space', 'style'],

    params: {
        drops:   { type: 'int',   range: [1, 6],      default: 3,    uniform: 'u_drops', bias: 'density' },
        spread:  { type: 'float', range: [0.002, 0.02], default: 0.007, uniform: 'u_spread' },
        fibre:   { type: 'float', range: [0.5, 8],    default: 3.0,  uniform: 'u_fibre', bias: 'density' },
        soak:    { type: 'float', range: [0.7, 0.99], default: 0.93, uniform: 'u_soak' },
        density: { type: 'float', range: [0.1, 1.2],  default: 0.5,  uniform: 'u_density', bias: 'energy' },
        pace:    { type: 'float', range: [0.02, 0.4], default: 0.1,  uniform: 'u_pace', bias: 'motion', rate: true },
        palette: { type: 'palette', count: 5 },
    },

    reactive: {
        density: { feature: 'bandLow', amount: 0.35, response: 'smooth' },
        fibre:   { feature: 'bandAir', amount: 0.2 },
    },

    shader: `
vec4 scene(vec2 uv, vec2 p) {
    float t = u_time * u_pace + u_seed;
    p = sigCamera(p);

    // Paper: a still fibre texture that the ink will follow.
    float grainField = fbm(p * u_fibre * 2.0 + 17.0, 4);
    vec3 col = mix(pal(0) * 0.09, pal(1) * 0.14, grainField);

    // Fresh ink. Each drop pulses in and out on its own slow cycle, so the page
    // is never uniformly saturated and there is always somewhere new bleeding.
    float ink = 0.0;
    for (int i = 0; i < 6; i++) {
        if (i >= u_drops) break;
        float fi = float(i);
        float s = u_seed + fi * 61.3;

        vec2 at = vec2(sin(t * 0.6 + s) * 0.6, cos(t * 0.47 + s * 1.7) * 0.45);
        float life = 0.5 + 0.5 * sin(t * 1.3 + s * 2.1);
        float d = length(p - at) + (grainField - 0.5) * 0.15;
        ink += exp(-d * d * 90.0) * life;
    }
    ink = sat(ink) * u_density;

    vec3 inkColor = palRamp(0.45 + grainField * 0.3);
    col = mix(col, inkColor, ink);

    // The bleed: sample the previous frame outward along the fibre. Reading four
    // offsets rather than one is what makes it spread in every direction instead
    // of sliding — one sample is a smear, four is diffusion.
    vec2 warp = (vec2(fbm(p * u_fibre + 3.0, 3), fbm(p * u_fibre - 7.0, 3)) - 0.5) * 2.0;
    float r = u_spread;
    vec3 soaked = (
        prev(uv + (vec2( 1.0,  0.0) + warp * 0.6) * r) +
        prev(uv + (vec2(-1.0,  0.0) + warp * 0.6) * r) +
        prev(uv + (vec2( 0.0,  1.0) + warp * 0.6) * r) +
        prev(uv + (vec2( 0.0, -1.0) + warp * 0.6) * r)
    ) * 0.25;

    col = max(col, soaked * u_soak);

    col = sigAir(col, p, smoothstep(0.0, 1.7, length(p)));
    col += sigGrain(uv);
    return vec4(col, 1.0);
}
`,
};

export default inkBleed;
