music-video-gen/flow-state/src/scenes/shader/kaleido-tunnel.js
Dejvino 17a583a87f Side quest 1: give four scenes art direction other than grain
Classic Wave, Silk Ribbon, Kaleido Tunnel and Slow Orb all declared the
`style` trait and honoured it with `col += sigGrain(uv)` and nothing else. A
declared trait is a contract — the disqualification rule in Personality.js is
the only thing keeping off-design scenes out of a track — so honouring it
with dirt meant these four could not take the `texture: 0` opt-out the grain
work introduced. Phase 9 measured their style response at exactly 0. They sat
at texture: 0.35 as a stopgap, which kept speckle on the library's cleanest
scenes purely to keep a gate green.

Each already had the knob; it just was not wired to the track:

- Classic Wave contrasts its wave through a bare smoothstep(0.2, 0.8). The
  transition width now comes from u_sigSoft and u_sigLine, centred on 0.5 so
  changing the hand does not change the exposure. Crest concentration is
  driven separately by u_sigLine, because a track is free to sample the
  scene's own u_softness at zero and the art direction must still show.
- Silk Ribbon's strand width is u_sigLine and its falloff exponent u_sigSoft:
  a sharp track gets a filament with a defined edge, a soft one a haze.
- Kaleido Tunnel drew its grid against a bare 0.42 — a line weight with no
  name. It is now a weight and a feather, both from the track.
- Slow Orb's body edge multiplies the scene's softness by the video's, and
  gains a sigEdge rim so a sharp-handed track gets a defined limb.

All four are now texture: 0. Style response measured against a maximally
soft-handed versus maximally sharp-handed personality: Classic Wave 111,
Silk Ribbon 216, Kaleido Tunnel 206, Slow Orb 102, out of 255 — previously 0.

104/104 checks pass including the slow set. See SIDE-QUESTS.md §1.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 19:35:50 +02:00

74 lines
3.0 KiB
JavaScript

// Geometric family: a kaleidoscopic tunnel. The default drop scene — strong
// forward motion, hard symmetry, and it takes the beat well.
export const kaleidoTunnel = {
name: 'Kaleido Tunnel',
family: 'geometric',
kind: 'fragment',
// Personality: see look/Personality.js.
// Hard grid lines on flat colour: grain reads as dirt on the lens.
texture: 0,
traits: ['shape', 'camera', 'style'],
params: {
sides: { type: 'int', range: [2, 12], default: 6, uniform: 'u_sides' },
depth: { type: 'float', range: [1, 8], default: 3.0, uniform: 'u_depth', bias: 'density' },
speed: { type: 'float', range: [0.1, 1.5], default: 0.45, uniform: 'u_speed', bias: 'motion', rate: true },
twist: { type: 'float', range: [0, 2], default: 0.5, uniform: 'u_twist' },
rings: { type: 'float', range: [2, 24], default: 8, uniform: 'u_rings', bias: 'density' },
glow: { type: 'float', range: [0, 1.5], default: 0.5, uniform: 'u_glow', bias: 'energy' },
palette: { type: 'palette', count: 6 },
},
reactive: {
glow: { feature: 'beat', amount: 0.45, response: 'spike' },
twist: { feature: 'bandLow', amount: 0.3 },
rings: { feature: 'bandHigh', amount: 0.2 },
},
shader: `
vec4 scene(vec2 uv, vec2 p) {
float t = u_time * u_speed + u_seed;
p = sigCamera(p);
// A track with a signature polygon dictates the fold count — this is the
// scene where that reads most strongly, so its own sides yields to it.
float sides = u_sigSides > 2.5 ? u_sigSides : float(u_sides);
// Cross-section measured in the signature form: the tunnel mouth is the
// track's shape rather than a circle.
float radius = max(sigShape(p) + 1.0, 1e-4);
vec2 folded = kaleido(p, sides);
float angle = atan(folded.y, folded.x);
// Tunnel coordinates: 1/r is depth, angle is the wall.
float z = u_depth / radius + t * 2.0;
float wall = angle / 3.14159265 + sin(z * 0.5 + t) * u_twist * 0.25;
float ringLines = abs(fract(z * u_rings * 0.1) - 0.5) * 2.0;
float wallLines = abs(fract(wall * sides) - 0.5) * 2.0;
// TRAIT style: the grid is the whole image, so the track draws it. The
// threshold was a bare 0.42 — a line weight with no name. u_sigLine sets how
// much of the cell the line occupies, u_sigSoft how far it feathers.
float weight = mix(0.22, 0.6, sat(u_sigLine));
float feather = weight * mix(0.15, 1.0, sat(u_sigSoft));
float grid = smoothstep(weight, max(weight - feather, 0.0), ringLines)
+ smoothstep(weight, max(weight - feather, 0.0), wallLines);
vec3 col = palRamp(z * 0.05 + wall * 0.2) * 0.35;
col += pal(int(mod(floor(z * u_rings * 0.1), 6.0))) * grid * 0.7;
// Depth cue: far end of the tunnel darkens, mouth glows.
float fade = smoothstep(0.0, 1.1, radius);
col *= 0.25 + 0.9 * fade;
col += pal(3) * (1.0 - fade) * u_glow * 0.6;
col += sigGrain(uv);
return vec4(col, 1.0);
}
`,
};
export default kaleidoTunnel;