// Geometric family: a burst of rotating folded prisms. A core sits at the
// centre in the track's signature form, and around it a constellation of folded
// rings counter-rotate and breathe — prism facets read as hard geometry meeting
// a soft bloom. Everything is closed-form, so the whole lattice is seek-exact.

export const prismBloom = {
    name: 'Prism Bloom',
    family: 'geometric',
    kind: 'fragment',
    // Personality: see look/Personality.js.
    // Crisp line work: the track's surface grain would only fur the edges.
    texture: 0,
    consumes: ['cast', 'ink', 'staging'],
    traits: ['shape', 'camera', 'style'],

    params: {
        sites:      { type: 'float', range: [2, 12],      default: 6,    uniform: 'u_sites', bias: 'density' },
        layers:     { type: 'float', range: [1, 8],      default: 5,     uniform: 'u_layers', bias: 'density' },
        thickness:  { type: 'float', range: [0.008, 0.05], default: 0.02, uniform: 'u_thickness' },
        radius:     { type: 'float', range: [0.15, 0.7], default: 0.32, uniform: 'u_radius', bias: 'energy' },
        spin:       { type: 'float', range: [0, 1.5],    default: 0.4,  uniform: 'u_spin', bias: 'motion' },
        speed:      { type: 'float', range: [0.05, 0.8], default: 0.3,  uniform: 'u_speed', bias: 'motion', rate: true },
        palette:    { type: 'palette', count: 6 },
    },

    reactive: {
        radius: { feature: 'bandLow', amount: 0.2 },
        spin:   { feature: 'flux',    amount: 0.15, response: 'smooth' },
    },

    shader: `
// A ring whose radius is folded into N star points, keeping the geometry angular
// rather than circular.
float ring(vec2 q, float sites, float radius, float width) {
    float a = atan(q.y, q.x);
    float seg = 6.28318530718 / sites;
    float wa = abs(mod(a + seg * 0.5, seg) - seg * 0.5);
    float starRadius = radius * max(cos(wa * sites), 1e-3);
    float d = abs(length(q) - starRadius);
    return smoothstep(width + 0.004, width - 0.004, d);
}

vec4 scene(vec2 uv, vec2 p) {
    float t = u_time * u_speed + u_seed;
    p = sigFolded(sigCamera(p));

    // Facet count yields to the song's cast when it names a form.
    float sites = u_castSides > 2.5 ? u_castSides : float(u_sites);

    vec3 col = pal(0) * 0.04;
    for (int i = 0; i < 8; i++) {
        if (float(i) >= u_layers) break;
        float fi = float(i);

        // Layers counter-rotate and breathe independently; all closed-form.
        float layerRadius = u_radius * stageScale() * (0.5 + fi * 0.24);
        float breathe = 0.78 + 0.22 * sin(u_time * 0.9 + fi * 1.7);
        vec2 lp = rot(fi * 0.7 + t * (fi * 0.5 + 0.3) * u_spin) * p;

        float r = ring(lp, sites, layerRadius * breathe, u_thickness);
        col += pal(int(mod(fi, 6.0))) * r * (0.4 + 0.5 * 0.8);

        float halo = exp(-(length(lp) / max(layerRadius * breathe, 1e-3)) * 3.0) * 0.5 * 0.25;
        col += pal(0) * halo;
    }

    // The heart of the bloom is the song's protagonist, drawn in its ink.
    float coreSize = (0.09 + u_beat * 0.06) * stageScale();
    float core = castMain(p / max(coreSize, 1e-3)) * coreSize;
    col = mix(col, pal(3), inkMask(core, uv));

    return vec4(inkValue(col), 1.0);
}
`,
};