// Organic family: a mosaic of overlapping scales spiralling out from the centre,
// the way a pinecone looks from the tip — every scale the same shape, each one
// larger and further round than the one inside it, no straight row anywhere.
// The whole surface breathes on the bar.
//
// Cell Divide is the other packed organic and it is about the event: cells split
// and the arrangement changes. Nothing here ever divides. The lattice is fixed
// and what moves is the surface itself — scales lifting, tilting and catching
// the light. Built in log-polar space with a shear, so the rows ARE the spirals
// rather than being rings with a pattern painted on them. Each scale is the
// track's signature form, so a hexagonal video is tiled in hexagons.

export const scaleMosaic = {
    name: 'Scale Mosaic',
    family: 'organic',
    kind: 'fragment',
    texture: 0.8,
    traits: ['shape', 'camera', 'style'],

    params: {
        arms:    { type: 'int',   range: [8, 40],       default: 22,   uniform: 'u_arms', bias: 'density' },
        growth:  { type: 'float', range: [0.1, 0.45],   default: 0.22, uniform: 'u_growth', slowAxis: true },
        twist:   { type: 'float', range: [-3, 3],       default: 1.6,  uniform: 'u_twist' },
        size:    { type: 'float', range: [0.25, 0.48],  default: 0.42, uniform: 'u_size' },
        lift:    { type: 'float', range: [0, 0.6],      default: 0.25, uniform: 'u_lift' },
        breathe: { type: 'float', range: [0, 0.3],      default: 0.1,  uniform: 'u_breathe' },
        spin:    { type: 'float', range: [0.0, 0.35],   default: 0.05, uniform: 'u_spin', bias: 'motion', rate: true },
        sheen:   { type: 'float', range: [0, 1.4],      default: 0.6,  uniform: 'u_sheen', bias: 'energy' },
        palette: { type: 'palette', count: 5 },
    },

    reactive: {
        sheen: { feature: 'bandHigh', amount: 0.35, response: 'smooth' },
        lift:  { feature: 'beat',     amount: 0.2,  response: 'spike' },
    },

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

    float r = length(p) + 0.02;
    float th = atan(p.y, p.x) + t;

    // Log-polar: one unit of q.y is one ring outward, one unit of q.x is one
    // scale around. The shear is what turns the rings into spirals — without it
    // this is a set of concentric rows, which is the one thing a phyllotactic
    // surface never has.
    vec2 q = vec2(th / 6.28318530718 * float(u_arms), log(r) / u_growth);
    q.x += q.y * u_twist;

    vec2 cell = floor(q);
    vec2 f = fract(q) - 0.5;

    // Overlap: the scale is drawn slightly larger than its cell, so each one
    // laps over the one below and the surface reads as layered rather than tiled.
    float lift = sin(cell.y * 1.7 + cell.x * 0.9 + u_barPhase * 6.2831 + hash12(cell) * 6.0) * u_lift;
    float breath = 1.0 + sin(u_barPhase * 6.28318530718) * u_breathe;
    float rad = u_size * breath * (1.0 + lift * 0.3);

    // Drawn in cell space, where the cell is the unit square, and converted
    // back to screen distance at the end. A scale is therefore as wide as its
    // slice of the turn and as tall as its ring — wider ones further out, which
    // is what growing on a cone looks like.
    float d = sigShape(f / max(rad, 1e-3)) * max(rad, 1e-3) * u_growth * r;

    // Shade by lift, so the surface has a direction of light across it.
    float shade = 0.3 + 0.7 * sat(0.5 + lift * 1.4);
    vec3 body = palRamp(fract(cell.y * 0.13 + cell.x * 0.037) * 0.5 + 0.2) * shade;

    vec3 col = pal(0) * 0.07;
    col = mix(col, body * 0.6, smoothstep(0.004, -0.02, d));

    // Rim light along every scale edge, in the track's line weight.
    col += pal(4) * sigEdge(d) * (0.3 + u_sheen * 0.8);

    // A specular sweep across the whole head, which is what makes hundreds of
    // separate tiles read as one surface.
    float sweep = sat(0.5 + 0.5 * sin(dot(p, vec2(0.7, 0.5)) * 2.2 - u_time * 0.35));
    col += palRamp(0.75) * sweep * u_sheen * 0.2 * smoothstep(0.02, -0.01, d);

    col *= 0.72 + 0.28 * exp(-r * r * 0.3);
    col += sigGrain(uv);
    return vec4(col, 1.0);
}
`,
};

export default scaleMosaic;
