// Geometric family: a Truchet tiling — every cell carries two quarter-arcs in
// one of two rotations, and the arcs join across cell edges into long continuous
// curves nobody placed.
//
// That emergent continuity is the whole point and the reason this does not
// duplicate Moiré Grid or Circuit Bloom: the structure is a grid, but the thing
// you actually see is a set of wandering closed loops. The tiling re-rolls on
// phrase lines rather than crawling, so the maze reconfigures on the music.

export const truchetFold = {
    name: 'Truchet Fold',
    family: 'geometric',
    kind: 'fragment',
    // Takes the track's surface grain, but lightly — this is drawn, not filmed.
    texture: 0.4,
    consumes: ['ink'],
    traits: ['camera', 'style'],

    params: {
        cells:   { type: 'float', range: [1.5, 12],   default: 4,    uniform: 'u_cells', bias: 'density' },
        weight:  { type: 'float', range: [0.04, 0.3], default: 0.12, uniform: 'u_weight' , slowAxis: true },
        radius:  { type: 'float', range: [0.3, 0.7],  default: 0.5,  uniform: 'u_radius' },
        churn:   { type: 'float', range: [0, 1],      default: 0.35, uniform: 'u_churn' },
        drift:   { type: 'float', range: [0.0, 0.4],  default: 0.08, uniform: 'u_drift', bias: 'motion', rate: true },
        palette: { type: 'palette', count: 5 },
    },

    reactive: {
        weight: { feature: 'beat',    amount: 0.15, response: 'spike' },
    },

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

    // The tiling slides slowly and re-rolls its orientations on the phrase grid.
    vec2 g = p * u_cells + vec2(t, t * 0.6);
    vec2 cell = floor(g);
    vec2 f = fract(g) - 0.5;

    float era = floor(u_phrasePhase * 4.0) * u_churn;
    float flip = step(0.5, hash12(cell + era + u_seed));

    // Mirror one of the two orientations; the arcs then always meet at edge
    // midpoints, which is what makes neighbouring cells join up.
    if (flip > 0.5) f.x = -f.x;

    // Two quarter-arcs, centred on opposite corners.
    float d1 = abs(length(f - vec2(-0.5, -0.5)) - u_radius);
    float d2 = abs(length(f - vec2(0.5, 0.5)) - u_radius);
    float d = min(d1, d2);

    float w = u_weight * (0.5 + u_sigLine);
    float line = smoothstep(w, w * 0.3, d);
    float halo = exp(-d * 9.0);

    // Colour by which arc, and by cell, so the continuous curves change hue
    // along their length rather than being one flat ribbon.
    float which = d1 < d2 ? 0.0 : 1.0;
    vec3 tint = palRamp(hash12(cell * 0.7 + era) * 0.5 + which * 0.2 + 0.1);

    vec3 col = pal(0) * 0.05;
    col += tint * line * 0.75;
    col += tint * halo * 0.5 * 0.35;
    col += pal(4) * inkStroke(d) * 0.5 * 0.25;

    col *= 0.65 + 0.35 * exp(-dot(p, p) * 0.25);
    return vec4(inkValue(col), 1.0);
}
`,
};

export default truchetFold;
