// Minimal family: one soft body drifting through a mostly empty frame.
//
// The quietest scene in the library, and the one an ambient intro or a long
// breakdown should usually land on. Nothing here reacts sharply — the beat
// mapping is deliberately weak, because a scene whose job is stillness should
// not twitch.

export const slowOrb = {
    name: 'Slow Orb',
    family: 'minimal',
    kind: 'fragment',
    // Personality: see look/Personality.js.
    // One soft body in an empty frame — the emptiest scene in the library, and
    // the one where speckle is most visible for being least justified. It keeps
    // its own `grain` param, which exists to stop large flat areas banding.
    texture: 0,
    consumes: ['cast', 'ink'],
    traits: ['shape', 'camera', 'space', 'style'],

    params: {
        size:     { type: 'float', range: [0.15, 0.8], default: 0.38, uniform: 'u_size', bias: 'energy' },
        softness: { type: 'float', range: [0.2, 1.0],  default: 0.7,  uniform: 'u_softness' },
        drift:    { type: 'float', range: [0.01, 0.2], default: 0.05, uniform: 'u_drift', bias: 'motion', rate: true },
        wobble:   { type: 'float', range: [0, 0.5],    default: 0.15, uniform: 'u_wobble' },
        palette:  { type: 'palette', count: 4 },
    },

    reactive: {
        size: { feature: 'loudness', amount: 0.12, response: 'smooth' },
    },

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

    // The orb drifts about the track's horizon rather than about the middle of
    // the frame, so it occupies the same space as the scenes that draw ground.
    vec2 centre = vec2(sin(t * 1.7) * 0.28, cos(t * 1.3) * 0.18 + sigHorizonY() * 0.45);
    vec2 q = sigCamera(p) - centre;

    // The body is the track's signature form — this scene is one shape in an
    // empty frame, so the shape had better be the track's.
    float wobble = fbm(q * 2.4 + t, 4) * u_wobble;
    float d = (castMain(q / max(u_size, 1e-3)) * u_size) * (1.0 + wobble);

    // TRAIT style: the body's edge is drawn in the track's hand. The scene's
    // u_softness says how soft this orb is; u_sigSoft says how soft this VIDEO
    // is, and the two multiply.
    float edge = u_softness * mix(0.35, 1.5, sat(u_sigSoft));
    float body = smoothstep(edge * 0.5, -edge * 0.5, d);
    float glow = exp(-max(d, 0.0) * (5.0 / max(0.4, 0.05))) * 0.4;

    // A rim in the track's line weight, so a sharp-handed track gets a defined
    // limb against the halo instead of only a softer gradient.
    float rim = inkStroke(d) * u_sigLine;

    vec3 col = pal(0) * 0.05;
    col = mix(col, pal(1), body * 0.85);
    col += pal(2) * body * body * 0.5;
    col += pal(3) * glow * 0.35;
    col += pal(2) * rim * 0.5;

    // Fine grain keeps large flat areas from banding.
    col = sigAir(col, p, smoothstep(0.0, 1.6, length(q)));
    col += (hash12(uv * 640.0 + floor(u_frame)) - 0.5) * 0.12 * 0.08;

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

export default slowOrb;
