// Minimal family: backlit paper screens in a wooden frame. A few big panels, a // lamp somewhere behind them, and the track's signature form showing through // one or two as a soft silhouette. The screens slide. // // Moiré Grid is the other minimal built on a grid, and it is a grid of hundreds // of lines existing to interfere. This is a grid of six or eight PANELS: the // count is small enough to read as objects, the frame is opaque, and almost the // whole image is flat diffuse paper. What changes is which panel the light is // behind and how far the screens have slid — not the pattern. export const shojiGrid = { name: 'Shoji Grid', family: 'minimal', kind: 'fragment', // Paper has a tooth, and this is the one scene that wants it. texture: 1.0, consumes: ['cast', 'ink'], traits: ['shape', 'camera', 'style'], params: { cols: { type: 'int', range: [2, 7], default: 4, uniform: 'u_cols', bias: 'density' }, rows: { type: 'int', range: [1, 4], default: 2, uniform: 'u_rows' }, slide: { type: 'float', range: [-1.2, 1.2], default: 0.0, uniform: 'u_slide' }, stile: { type: 'float', range: [0.02, 0.16], default: 0.06, uniform: 'u_stile' }, lamp: { type: 'float', range: [0.15, 1.6], default: 0.7, uniform: 'u_lamp', bias: 'energy', slowAxis: true }, form: { type: 'float', range: [0, 0.5], default: 0.26, uniform: 'u_form' }, fibre: { type: 'float', range: [0, 1], default: 0.45, uniform: 'u_fibre' }, sway: { type: 'float', range: [0.06, 0.5], default: 0.16, uniform: 'u_sway', bias: 'motion', rate: true }, palette: { type: 'palette', count: 5 }, }, reactive: { form: { feature: 'loudness', amount: 0.25, response: 'smooth' }, fibre: { feature: 'bandAir', amount: 0.3, response: 'smooth' }, }, shader: ` vec4 scene(vec2 uv, vec2 p) { float t = u_time * u_sway + u_seed; p = sigCamera(p); // The lamp behind the screens. One soft source, wandering slowly, and the // only reason any panel is brighter than another. vec2 lampAt = vec2(sin(t * 1.6) * 0.9, cos(t * 1.13) * 0.5); float glowField = exp(-length(p - lampAt) * 1.3) * u_lamp; // The screen grid. Alternate rows slide in opposite directions, which is // what makes it read as panels that MOVE rather than as a printed grid. float ry = floor((p.y * 0.5 + 0.5) * float(u_rows)); float dir = mod(ry, 2.0) < 0.5 ? 1.0 : -1.0; float gx = (p.x * 0.5 + 0.5) * float(u_cols) + u_slide * dir; float gy = (p.y * 0.5 + 0.5) * float(u_rows); vec2 cell = vec2(floor(gx), floor(gy)); vec2 f = vec2(fract(gx), fract(gy)) - 0.5; // Paper: warm, flat, with the light from behind soaking through it. float paperN = fbm(vec2(p.x * 40.0, p.y * 6.0) + cell * 3.7, 3); vec3 col = pal(1) * (0.12 + glowField * 0.55); col += pal(3) * glowField * 0.5; col *= 0.85 + 0.3 * paperN * u_fibre; // A panel or two is lacquered darker, so the row has a rhythm. float shade = hash12(cell + 3.0); col *= mix(0.55, 1.0, smoothstep(0.25, 0.4, shade)); // The signature form, showing through the panel it stands behind. if (u_form > 0.01) { float which = step(0.62, hash12(cell * 1.7 + 9.0)); vec2 at = vec2(f.x * 2.0 / float(u_cols), f.y * 2.0 / float(u_rows)); float d = castMain(at / u_form) * u_form; col = mix(col, col * 0.35 + pal(4) * glowField * 0.35, smoothstep(0.01, -0.01, d) * which); col += pal(4) * inkStroke(d) * which * glowField * 0.7; } // The frame. Opaque, in front of everything, and the thing that makes the // panels objects instead of regions. float bar = min(0.5 - abs(f.x), 0.5 - abs(f.y)); float wood = smoothstep(u_stile, u_stile * 0.4, bar); col = mix(col, pal(0) * 0.14, wood); col += pal(4) * inkStroke(bar - u_stile) * 0.12; return vec4(inkValue(col), 1.0); } `, }; export default shojiGrid;