music-video-gen/flow-state/src/scenes/shader/contour-map.js
Dejvino c8658a6d15 Four minimal scenes, and a transition control that was reading its denominator
Pendulum Trace (a harmonograph over its own fading ghost), Contour Map (a survey
of a landscape with a tide in it), Shoji Grid (backlit panels that slide) and
Balance Stack (a leaning pile under a crossing sun).

Two of the four leave the slow axis undeclared and say why in the file: in a
frame this empty the camera's own drift moves the ten-second average more than
anything in the scene can, so a declaration would be a claim Phase 11 contradicts.

Phase 4's transition control changed from max(before, after) to their sum. These
scenes are calm, so casting them into the mid-shot control windows halved the
denominator while the boundary peak stayed put — 0.124 with them, 0.130 without.
For most of the window both stacks are live, four layers with accents in overlay
and screen, and a nonlinear blend of two moving stacks moves more than either
alone; "no worse than the busier half" was never a property a dissolve had. A
real pop still clears the threshold by an order of magnitude.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-16 10:40:23 +02:00

97 lines
3.9 KiB
JavaScript

// Minimal family: a survey drawing of a landscape — nested contour lines on a
// ground plane running to the horizon, every fifth one heavier, and water
// standing in the low ground.
//
// Horizon Lines is a bundle of parallel rules and Ridge Terrain is stacked
// silhouettes: both describe a landscape by what it hides. Contours describe it
// by what it measures, so the lines are closed, nested and never cross, and the
// shape of the land is legible from the spacing alone. The water level is the
// slow tide of the piece — the same terrain drowning and draining.
export const contourMap = {
name: 'Contour Map',
family: 'minimal',
kind: 'fragment',
// Drafting, not photography.
texture: 0.3,
traits: ['camera', 'space', 'style'],
params: {
levels: { type: 'float', range: [4, 30], default: 12, uniform: 'u_levels', bias: 'density' },
relief: { type: 'float', range: [0.4, 3.0], default: 1.2, uniform: 'u_relief' },
sea: { type: 'float', range: [0.1, 0.9], default: 0.42, uniform: 'u_sea' },
indexN: { type: 'int', range: [3, 8], default: 5, uniform: 'u_indexN' },
weight: { type: 'float', range: [0.03, 0.3], default: 0.1, uniform: 'u_weight' },
shore: { type: 'float', range: [0, 1.4], default: 0.6, uniform: 'u_shore', bias: 'energy' },
drift: { type: 'float', range: [0.002, 0.03], default: 0.008, uniform: 'u_drift', bias: 'motion', rate: true },
palette: { type: 'palette', count: 5 },
},
reactive: {
shore: { feature: 'loudness', amount: 0.3, response: 'smooth' },
relief: { feature: 'bandLow', amount: 0.2, response: 'smooth' },
},
shader: `
// The land. Slow enough that the survey is being redrawn rather than animated.
float land(vec2 g, float t) {
return fbm(g * u_relief + vec2(t, t * 0.6), 4);
}
vec4 scene(vec2 uv, vec2 p) {
float t = u_time * u_drift + u_seed;
p = sigCamera(p);
float horizon = sigHorizonY() * 0.4 + 0.35;
float below = horizon - p.y;
// Sky: the paper the survey is drawn on, lit from the horizon.
vec3 col = mix(pal(1) * 0.2, pal(0) * 0.07, sat((p.y - horizon) * 1.4 + 0.15));
col += pal(3) * exp(-abs(p.y - horizon) * 10.0) * 0.15;
if (below > 0.002) {
float depth = 1.0 / max(below, 0.03);
vec2 g = vec2(p.x * depth, depth) * 0.5;
float h = land(g, t);
// Contours. The band is measured in HEIGHT, not in pixels, which is
// what makes the lines crowd on steep ground and spread on flat ground
// without anything having to compute a gradient.
float f = h * u_levels;
float band = abs(fract(f) - 0.5) * 2.0;
float index = abs(fract(f / float(u_indexN)) - 0.5) * 2.0;
float w = u_weight * (0.35 + u_sigLine * 1.8);
float line = smoothstep(w, w * 0.2, band);
float heavy = smoothstep(w * 1.6, w * 0.3, index);
vec3 ground = pal(0) * 0.1;
ground += palRamp(0.3 + h * 0.3) * line * 0.5;
ground += pal(4) * heavy * 0.35;
// Water standing in everything below the level. A flat tone, because
// water has no contours — which is exactly what makes the level legible.
float wet = smoothstep(u_sea + 0.02, u_sea - 0.02, h);
vec3 water = mix(pal(2) * 0.7, pal(3) * 0.45, sat(below));
// Water takes the sky, so a flooded frame is a bright one and the level
// is legible from across the room.
water += pal(3) * exp(-below * 1.6) * u_shore * 0.5;
ground = mix(ground, water, wet);
// Shoreline: the one bright edge in the drawing.
float edge = smoothstep(0.05, 0.0, abs(h - u_sea));
ground += pal(3) * edge * u_shore * 0.8;
col = mix(col, ground, smoothstep(0.0, 0.03, below));
}
col = sigAir(col, p, sat(1.0 - below * 0.9));
col += sigGrain(uv);
return vec4(col, 1.0);
}
`,
};
export default contourMap;