music-video-gen/flow-state/src/scenes/shader/voronoi-shatter.js
Dejvino 875c3868dd Three geometric scenes, and two ways to strobe a whole frame
Voronoi Shatter (cells with no fixed shape, re-cut on the phrase), Apollonian
Gasket (a packing built by inversion, so zooming finds more circles rather than
finer noise) and Isometric Blocks (a lit, gridded, solid surface where Floating
Geometry is bodies adrift).

Two flash failures, both the same mistake in different clothes. Apollonian's hard
depth cutoff popped a whole generation of discs in and out as the fold crossed
it — now faded rather than cut. Isometric Blocks drove block height off the low
end, so every tower in the frame grew and shrank together: 4/s. Moving the
reaction to the edges and to a hash-chosen quarter of the tops keeps the pulse
and drops the frame-wide swing.

Voronoi Shatter declares no slow axis: its re-cut puts the ten-second average
0.127 from itself between any two windows, the highest noise floor in the
library, and no parameter competes with that.

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

97 lines
4.2 KiB
JavaScript

// Geometric family: a Voronoi tessellation — every point in the frame belongs
// to whichever seed is nearest, so the plates are irregular, they meet in clean
// straight seams, and they cannot overlap or leave a gap.
//
// Truchet Fold is the other tiling here and it is a regular grid wearing a
// pattern: the cells are square whatever is drawn in them. These cells have no
// fixed shape at all — each one is whatever its neighbours leave it — so when
// the seeds move, every plate in the frame changes shape at once and the seams
// slide along themselves. The seeds jump to new positions on the phrase, which
// re-cuts the whole plane in one frame without anything sliding.
//
// No declared slow axis. The re-cut is the point of the scene and it puts the
// ten-second average 0.127 away from itself between any two windows — the
// highest noise floor of anything in the library — so every candidate axis
// measured at 0.03x to 0.1x. Nothing a parameter can do competes with the plane
// being re-cut, which is the honest description of the scene.
export const voronoiShatter = {
name: 'Voronoi Shatter',
family: 'geometric',
kind: 'fragment',
texture: 0.5,
traits: ['camera', 'style'],
params: {
cells: { type: 'float', range: [1.2, 8], default: 3.0, uniform: 'u_cells', bias: 'density' },
jitter: { type: 'float', range: [0, 1], default: 0.75, uniform: 'u_jitter' },
seam: { type: 'float', range: [0.01, 0.14], default: 0.05, uniform: 'u_seam' },
recut: { type: 'float', range: [0, 1], default: 0.4, uniform: 'u_recut' },
relief: { type: 'float', range: [0, 1], default: 0.5, uniform: 'u_relief' },
glow: { type: 'float', range: [0, 1.5], default: 0.6, uniform: 'u_glow', bias: 'energy' },
drift: { type: 'float', range: [0.01, 0.4], default: 0.09, uniform: 'u_drift', bias: 'motion', rate: true },
palette: { type: 'palette', count: 5 },
},
reactive: {
glow: { feature: 'bandMid', amount: 0.35, response: 'smooth' },
jitter: { feature: 'bandLow', amount: 0.2, response: 'smooth' },
},
shader: `
vec4 scene(vec2 uv, vec2 p) {
float t = u_time * u_drift + u_seed;
p = sigCamera(p);
vec2 g = p * u_cells;
vec2 base = floor(g);
vec2 f = g - base;
// The plane is re-cut on the phrase: the seeds do not travel to their new
// positions, they are simply somewhere else on the next frame. A tiling
// that slides is a texture; a tiling that jumps is an event.
float era = floor(u_phrasePhase * 2.0) * u_recut;
// Nearest and second-nearest seed. The difference between the two is the
// distance to the seam, which is what makes the borders even in width
// instead of pinching at the corners.
float d1 = 8.0, d2 = 8.0;
vec2 id1 = vec2(0.0);
// lint: fixed-cost — the 3x3 neighbourhood a Voronoi cell can reach
for (int j = -1; j <= 1; j++) {
for (int i = -1; i <= 1; i++) {
vec2 cell = base + vec2(float(i), float(j));
vec2 h = hash22(cell + era * 7.3 + u_seed);
vec2 seed = vec2(float(i), float(j)) +
mix(vec2(0.5), h + 0.15 * sin(t * 2.0 + h * 6.2831), u_jitter);
float d = length(f - seed);
if (d < d1) { d2 = d1; d1 = d; id1 = cell; }
else if (d < d2) { d2 = d; }
}
}
float border = (d2 - d1) / u_cells; // scene units to the seam
// Plates: each one flat, tinted by its own identity, and tilted a little so
// the tessellation reads as broken glass rather than as a colour chart.
float who = hash12(id1 * 1.7 + era);
vec3 plate = palRamp(0.15 + who * 0.5);
float tilt = mix(1.0, 0.55 + who * 0.9, u_relief);
vec3 col = plate * 0.28 * tilt;
col += plate * exp(-d1 * 2.5) * u_glow * 0.25;
// Seams: drawn in the track's hand, brightest where three plates meet.
float seam = smoothstep(u_seam, u_seam * 0.15, border);
col += pal(4) * seam * (0.4 + u_glow * 0.8);
col += pal(3) * sigEdge(border - u_seam) * 0.4;
col *= 0.75 + 0.25 * exp(-dot(p, p) * 0.25);
col += sigGrain(uv);
return vec4(col, 1.0);
}
`,
};
export default voronoiShatter;