// Minimal family: a nearly empty volume with a shaft of light through it and a // few motes suspended in the beam. // // Distinct from Firefly Drift (a swarm advected along a flow) and Slow Orb (one // body): almost nothing moves here. The motes hold position and only breathe; // what changes is the light. That makes this one of the very few scenes in the // library that can hold a thirty-second intro without asking for attention. // // The beam lands on the track's horizon, so the room is the same room every // other scene with a floor is standing in. export const dustChamber = { name: 'Dust Chamber', family: 'minimal', kind: 'fragment', traits: ['shape', 'camera', 'space', 'style'], params: { motes: { type: 'int', range: [6, 40], default: 18, uniform: 'u_motes', bias: 'density' }, moteSize: { type: 'float', range: [0.004, 0.05], default: 0.014, uniform: 'u_moteSize' }, beam: { type: 'float', range: [0.1, 1.0], default: 0.45, uniform: 'u_beam', bias: 'energy' }, beamWidth:{ type: 'float', range: [0.15, 1.2], default: 0.5, uniform: 'u_beamWidth' }, sway: { type: 'float', range: [0, 0.12], default: 0.04, uniform: 'u_sway' }, drift: { type: 'float', range: [0.01, 0.3], default: 0.06, uniform: 'u_drift', bias: 'motion', rate: true }, palette: { type: 'palette', count: 4 }, }, reactive: { beam: { feature: 'loudness', amount: 0.25, response: 'smooth' }, moteSize: { feature: 'beat', amount: 0.2, response: 'spike' }, }, shader: ` vec4 scene(vec2 uv, vec2 p) { float t = u_time * u_drift + u_seed; p = sigCamera(p); float floorY = sigHorizonY() * 0.7 - 0.6; // The shaft: a soft wedge widening as it falls, cut off at the floor. float axis = sin(u_seed * 0.7) * 0.35; float down = sat((1.0 - (p.y - floorY)) * 0.6); float halfWidth = u_beamWidth * (0.25 + down * 0.75); float inBeam = exp(-pow((p.x - axis) / max(halfWidth, 1e-3), 2.0) * 2.2); inBeam *= smoothstep(floorY - 0.05, floorY + 0.5, p.y); vec3 col = pal(0) * 0.05; col += pal(1) * inBeam * u_beam * 0.5; // The pool where the shaft meets the floor. float pool = exp(-abs(p.y - floorY) * 14.0) * exp(-pow((p.x - axis) / max(halfWidth * 1.3, 1e-3), 2.0)); col += pal(2) * pool * u_beam * 0.7; // Motes: fixed positions, breathing brightness, only visible in the light. for (int i = 0; i < 40; i++) { if (i >= u_motes) break; float fi = float(i); float s = u_seed + fi * 53.7; vec2 at = vec2( (hash11(s) - 0.5) * 2.4 + sin(t * 0.8 + s) * u_sway, (hash11(s + 9.1) - 0.5) * 1.8 + cos(t * 0.6 + s * 1.3) * u_sway ); float lit = exp(-pow((at.x - axis) / max(halfWidth, 1e-3), 2.0) * 2.0); float pulse = 0.55 + 0.45 * sin(t * 2.0 + s * 3.0); float m = sigForm(p, at, u_moteSize * (0.6 + hash11(s + 3.3))); col += pal(3) * m * lit * pulse * (0.5 + u_beam); } col = sigAir(col, p, smoothstep(0.0, 1.5, length(p))); col += sigGrain(uv); return vec4(col, 1.0); } `, }; export default dustChamber;