Two devices that were built, wired up, and doing nothing. OVERLAYS. buildStack gated layering on `surfaceOf(m) === 'composable'`, and no scene in the library declared `surface` — so the only thing that could ever sit on top was the one scene declaring `role: 'accent'`, and the overlay roster excluded accents by construction. Empty intersection, every time: 0/144 stacks carried an overlay. Every layered frame in every song was the same particle field. Labelled the library from the phase 12 coverage gate rather than by eye: the 37 scenes painting under 30% of the frame are composable. Particle Field loses its privileged slot and becomes one of them, keeping only `background: false`, which is the honest part — points in empty space cannot carry a section alone. The reserved accent slot is gone; one roster, two passes at it. 1 distinct overlay scene becomes 27, and the rate lands at 34% of stacks after trimming a base chance that had been tuned while the branch was dead. THE CAMERA. framing.shift moved the frame by a median of 0.029 of a half-frame at a fresh random angle every shot, so successive offsets cancelled and the median jump at a cut was 0.014. Present in every frame, visible in none. look/Camera.js is the director's camera department: the story says tension, order and which act a section is in, and this turns that into where the frame looks and how it travels there. Each director names a camera. Jump distance follows tension and act, speed follows energy, and the curve is one of four. Cuts choose between reframing and matching, so two scenes can still read as one place. Median offset 0.190, median reframe 0.135, and 94% of shots now move during the shot rather than only at the cut. Four new gates, each with a FLOOR — the device this replaces passed every existing check while doing nothing, because the only bound was a ceiling. Also lands the in-progress Epic 4 story layer it builds on: Story.js, phase 13, and the direction statistic. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
94 lines
4.0 KiB
JavaScript
94 lines
4.0 KiB
JavaScript
// Minimal family: one hairline drawing a harmonograph figure — two pendulums
|
|
// per axis, slightly out of tune with each other — over its own slowly fading
|
|
// ghost. Nothing else is in the frame.
|
|
//
|
|
// Silk Ribbon is the other minimal with a single moving element, and it is a
|
|
// wide band: an area with two edges. This is a line with no width to speak of,
|
|
// and it is the only scene in the library where what you are looking at is the
|
|
// HISTORY of a moving point rather than the point. The figure never repeats
|
|
// exactly, because the two frequencies are deliberately not a whole ratio, so
|
|
// the drawing precesses instead of closing.
|
|
|
|
export const pendulumTrace = {
|
|
name: 'Pendulum Trace',
|
|
family: 'minimal',
|
|
kind: 'fragment',
|
|
// Paints 0% of the frame — see checks/phase12 coverage.
|
|
surface: 'composable',
|
|
// Fine line work; grain only furs it up.
|
|
texture: 0.25,
|
|
consumes: ['ink'],
|
|
traits: ['camera', 'style'],
|
|
|
|
params: {
|
|
ratio: { type: 'float', range: [1.5, 5.5], default: 3.01, uniform: 'u_ratio' },
|
|
detune: { type: 'float', range: [0, 0.08], default: 0.03, uniform: 'u_detune' },
|
|
size: { type: 'float', range: [0.5, 1.5], default: 1.05, uniform: 'u_size' },
|
|
decay: { type: 'float', range: [0, 0.5], default: 0.15, uniform: 'u_decay' },
|
|
weight: { type: 'float', range: [0.002, 0.02], default: 0.006, uniform: 'u_weight' },
|
|
arc: { type: 'float', range: [1.0, 8], default: 3.5, uniform: 'u_arc', bias: 'density' },
|
|
persist: { type: 'float', range: [0.9, 0.996], default: 0.992, uniform: 'u_persist', slowAxis: true },
|
|
speed: { type: 'float', range: [0.05, 0.9], default: 0.3, uniform: 'u_speed', bias: 'motion', rate: true },
|
|
palette: { type: 'palette', count: 5 },
|
|
},
|
|
|
|
reactive: {
|
|
weight: { feature: 'beat', amount: 0.15, response: 'spike' },
|
|
arc: { feature: 'bandMid', amount: 0.2, response: 'smooth' },
|
|
},
|
|
|
|
shader: `
|
|
// Where the pen is at time s. Two pendulums per axis, the second slightly
|
|
// detuned from a whole-number ratio — which is the entire reason a harmonograph
|
|
// figure precesses instead of retracing one closed loop forever.
|
|
vec2 pen(float s) {
|
|
// The swing loses energy and is pushed again on the phrase. A real
|
|
// exponential decay in absolute time would be correct and useless: five
|
|
// minutes in, the figure would have shrunk to a dot.
|
|
float damp = 1.0 - u_decay * (1.0 - cos(u_phrasePhase * 6.28318530718)) * 0.5;
|
|
float x = sin(s) + 0.6 * sin(s * u_ratio + 1.7);
|
|
float y = cos(s * (1.0 + u_detune)) + 0.6 * cos(s * u_ratio * (1.0 - u_detune) + 0.4);
|
|
return vec2(x, y) * 0.5 * u_size * damp;
|
|
}
|
|
|
|
vec4 scene(vec2 uv, vec2 p) {
|
|
float t = u_time * u_speed + u_seed;
|
|
p = sigCamera(p);
|
|
|
|
vec3 col = pal(0) * 0.07;
|
|
|
|
// Vignette wash, so the empty frame is a lit space rather than black.
|
|
col += pal(1) * 0.13 * exp(-dot(p, p) * 0.6);
|
|
|
|
// The live stroke: the last u_arc radians of travel, sampled at a fixed
|
|
// resolution and reduced to the nearest point on the curve.
|
|
float best = 1e9;
|
|
float head = 0.0;
|
|
// lint: fixed-cost — 48 samples along a fixed arc, not a search
|
|
for (int i = 0; i < 48; i++) {
|
|
float f = float(i) / 47.0;
|
|
float s = t * 20.0 - u_arc * (1.0 - f);
|
|
float d = length(p - pen(s));
|
|
if (d < best) { best = d; head = f; }
|
|
}
|
|
|
|
float w = u_weight * (0.4 + u_sigLine * 2.5);
|
|
float line = smoothstep(w, w * 0.2, best);
|
|
|
|
// The tip is brightest and the tail falls away, so the line has a direction
|
|
// of travel even in a still frame.
|
|
vec3 ink = palRamp(0.2 + head * 0.35);
|
|
col += ink * line * (0.5 + head * 0.9) * (0.6 + 0.6 * 0.8);
|
|
|
|
// The ghost: everything the pen has already drawn, fading. Sampled straight
|
|
// rather than smeared, so old strokes stay in place and thin out instead of
|
|
// sliding around the frame.
|
|
col = max(col, prev(uv) * u_persist);
|
|
|
|
return vec4(inkValue(col), 1.0);
|
|
}
|
|
`,
|
|
};
|
|
|
|
export default pendulumTrace;
|