// Geometric family: two rotating line grids interfering.
//
// Moiré is a spatial-aliasing effect by nature, so this scene is the most likely
// in the library to alias badly. Line width is held above a floor and scaled by
// u_pixelScale, which is what keeps a 720p preview and a 4K export looking the
// same rather than the preview shimmering.

export const moireGrid = {
    name: 'Moiré Grid',
    family: 'geometric',
    kind: 'fragment',
    // Personality: see look/Personality.js.
    // Crisp line work: the track's surface grain would only fur the edges.
    texture: 0,
    traits: ['camera', 'style'],

    params: {
        density:  { type: 'float', range: [6, 60],   default: 22,  uniform: 'u_density', bias: 'density' },
        offset:   { type: 'float', range: [0.0, 0.5], default: 0.08, uniform: 'u_offset' },
        rotate:   { type: 'float', range: [0, 0.25], default: 0.04, uniform: 'u_rotate', bias: 'motion', rate: true },
        // Named u_lineWidth, not u_width: the shader contract already declares
        // `uniform float u_width` for stereo width, and a colliding name is a
        // redefinition error that renders the scene as a black frame.
        width:    { type: 'float', range: [0.06, 0.5], default: 0.2, uniform: 'u_lineWidth' , slowAxis: true },
        warp:     { type: 'float', range: [0, 1],    default: 0.25, uniform: 'u_warp' },
        glow:     { type: 'float', range: [0, 1.2],  default: 0.35, uniform: 'u_glow', bias: 'energy' },
        palette:  { type: 'palette', count: 4 },
    },

    reactive: {
        offset: { feature: 'bandLow', amount: 0.35 },
        glow:   { feature: 'beat',    amount: 0.35, response: 'spike' },
        warp:   { feature: 'flux',    amount: 0.2,  response: 'smooth' },
    },

    shader: `
// Anti-aliased line grid: the smoothstep edge is widened by the screen-space
// derivative, so lines stay a consistent visual weight at any resolution.
float grid(vec2 q, float density, float width) {
    vec2 g = q * density;
    vec2 f = abs(fract(g) - 0.5);
    float d = min(f.x, f.y);
    float aa = max(fwidth(d), 0.001);
    return smoothstep(width * 0.5 + aa, width * 0.5 - aa, d);
}

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

    vec2 warp = vec2(fbm(p * 1.5 + t, 3), fbm(p * 1.5 - t, 3)) - 0.5;
    vec2 q = p + warp * u_warp;

    // Drawn in the track's hand: its line weight scales this scene's.
    float weight = u_lineWidth * (0.5 + u_sigLine);
    float a = grid(rot(t * 6.28318530718) * q, u_density, weight);
    float b = grid(rot(-t * 6.28318530718 + u_offset * 3.14159) * (q + u_offset), u_density, weight);

    // The interference term is the point: where both grids land, it peaks.
    float interference = a * b;
    float either = max(a, b);

    vec3 col = pal(0) * 0.05;
    col += pal(1) * either * 0.35;
    col += pal(2) * interference * (0.8 + u_glow);
    col += pal(3) * pow(interference, 3.0) * u_glow;

    col *= 0.6 + 0.4 * exp(-dot(p, p) * 0.3);
    col += sigGrain(uv);
    return vec4(col, 1.0);
}
`,
};

export default moireGrid;
