Two helpers made the bulk of it mechanical. `inkStroke` is a drop-in for
sigEdge — the same line at the identity's weight rather than the track's — and
`castForm` is a drop-in for sigForm, same signature so call sites do not change
shape. With those in place the substitution table is one-to-one:
sigForm( -> castForm( sigShape( -> castMain( sigEdge( -> inkStroke(
Forty-seven scenes went through that pass in one run: twenty-six take the cast
and the ink, twenty-one take the ink alone. Then the gate ran over all sixty-five
and found three the pass had broken, which is the entire reason it exists.
Spectrum Sculpture rendered pure black. It had been using sigShape as a RADIAL
METRIC rather than drawing it, and the cast carries notches and a hollow — an
annulus used as a radius turns a sculpture inside out. Reverted to sigShape and
dropped to ink only. The lesson generalises: a scene that reads a form as
geometry is not a scene that draws it, and the classifier cannot tell those
apart from the source.
Eclipse Field stopped honouring its `style` trait. It opts out of surface grain,
so sigEdge was its only style evidence, and the ink replaced it. The trait claim
is now dropped — and so is the lint change that had let inkMask count as style
evidence, which was wrong and was hiding exactly this. A trait is a property of
the track a scene may honour; an artifact is content it draws. Taking the ink
says nothing about whether a scene responds to u_sigLine.
Circuit Bloom went empty at the bottom of its `grown` range, where the pads were
carried by a hairline and the ink's stroke is thinner than the edge it replaced.
Now filled as well as stroked.
Also: the backtick check now covers every shader literal rather than only the
preamble, because a mechanical pass over sixty files reintroduced one
immediately. Three rounds lost to that typo is enough.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
75 lines
3.1 KiB
JavaScript
75 lines
3.1 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,
|
|
consumes: ['cast', 'ink'],
|
|
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(castMain(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(inkValue(col), 1.0);
|
|
}
|
|
`,
|
|
};
|
|
|
|
export default kaleidoTunnel;
|