From 17a583a87f444a1619c76c48b6ebac1c7ac83ade Mon Sep 17 00:00:00 2001 From: Dejvino Date: Thu, 6 Aug 2026 19:35:50 +0200 Subject: [PATCH] Side quest 1: give four scenes art direction other than grain MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- flow-state/_audioprobe.html | 52 +++++++ flow-state/_captureprobe.html | 128 +++++++++++++++++ flow-state/_decodetest.html | 85 ++++++++++++ flow-state/_encprobe.html | 131 ++++++++++++++++++ flow-state/_exporttest.html | 43 ++++++ flow-state/_muxprobe.html | 95 +++++++++++++ flow-state/_playtest.html | 60 ++++++++ flow-state/src/scenes/shader/classic-wave.js | 18 ++- .../src/scenes/shader/kaleido-tunnel.js | 13 +- flow-state/src/scenes/shader/silk-ribbon.js | 15 +- flow-state/src/scenes/shader/slow-orb.js | 18 ++- 11 files changed, 641 insertions(+), 17 deletions(-) create mode 100644 flow-state/_audioprobe.html create mode 100644 flow-state/_captureprobe.html create mode 100644 flow-state/_decodetest.html create mode 100644 flow-state/_encprobe.html create mode 100644 flow-state/_exporttest.html create mode 100644 flow-state/_muxprobe.html create mode 100644 flow-state/_playtest.html diff --git a/flow-state/_audioprobe.html b/flow-state/_audioprobe.html new file mode 100644 index 0000000..c91a1ff --- /dev/null +++ b/flow-state/_audioprobe.html @@ -0,0 +1,52 @@ + + +audio probe + +
running…
+ + + diff --git a/flow-state/_captureprobe.html b/flow-state/_captureprobe.html new file mode 100644 index 0000000..fae7e36 --- /dev/null +++ b/flow-state/_captureprobe.html @@ -0,0 +1,128 @@ + + +capture probe + + +
running…
+ + + diff --git a/flow-state/_decodetest.html b/flow-state/_decodetest.html new file mode 100644 index 0000000..67673df --- /dev/null +++ b/flow-state/_decodetest.html @@ -0,0 +1,85 @@ + + +decode test + +
running…
+ + + diff --git a/flow-state/_encprobe.html b/flow-state/_encprobe.html new file mode 100644 index 0000000..ddee619 --- /dev/null +++ b/flow-state/_encprobe.html @@ -0,0 +1,131 @@ + + +encoder probe + +
running…
+ + + + diff --git a/flow-state/_exporttest.html b/flow-state/_exporttest.html new file mode 100644 index 0000000..ed30332 --- /dev/null +++ b/flow-state/_exporttest.html @@ -0,0 +1,43 @@ + + +export test + + +
running…
+ + + diff --git a/flow-state/_muxprobe.html b/flow-state/_muxprobe.html new file mode 100644 index 0000000..98e23aa --- /dev/null +++ b/flow-state/_muxprobe.html @@ -0,0 +1,95 @@ + + +mux probe + + +
running…
+ + + diff --git a/flow-state/_playtest.html b/flow-state/_playtest.html new file mode 100644 index 0000000..7e2f108 --- /dev/null +++ b/flow-state/_playtest.html @@ -0,0 +1,60 @@ + + +play test + + +
running…
+ + + diff --git a/flow-state/src/scenes/shader/classic-wave.js b/flow-state/src/scenes/shader/classic-wave.js index a9b2767..34111c0 100644 --- a/flow-state/src/scenes/shader/classic-wave.js +++ b/flow-state/src/scenes/shader/classic-wave.js @@ -7,9 +7,8 @@ export const classicWave = { family: 'flow', kind: 'fragment', // Personality: see look/Personality.js. - // Grain is this scene's ONLY expression of the style trait — it draws no - // hard edges to weight — so it keeps a share of it rather than opting out. - texture: 0.35, + // Smooth concentric colour: grain only mutes the ramp it is built on. + texture: 0, traits: ['shape', 'camera', 'style'], params: { @@ -47,9 +46,18 @@ vec4 scene(vec2 uv, vec2 p) { float spoke = u_spokes > 0 ? sin(angle * float(u_spokes) + t) * u_beat : 0.0; float v = 0.5 + 0.5 * sin(wave + spoke); - v = mix(v, smoothstep(0.2, 0.8, v), u_softness); - vec3 col = palRamp(t * u_colorRoll + d * 0.25) * v; + // TRAIT style: the track's hand on the crests. The scene's own u_softness + // decides HOW MUCH the wave is contrasted; the track decides what that + // contrast looks like — u_sigSoft widens the transition, u_sigLine tightens + // it. Centred on 0.5 so changing the hand does not change the exposure. + float edge = mix(0.06, 0.42, sat(u_sigSoft)) * mix(1.3, 0.6, sat(u_sigLine)); + v = mix(v, smoothstep(0.5 - edge, 0.5 + edge, v), u_softness); + + // ...and independently of u_softness, which a track is free to sample at + // zero: a heavier line concentrates the crest rather than letting it bloom + // across the whole ring. + vec3 col = palRamp(t * u_colorRoll + d * 0.25) * pow(v, mix(1.0, 2.2, sat(u_sigLine))); // Core glow, the part that reads as the "hit". col += pal(0) * (1.0 - smoothstep(0.0, 0.7, d)) * u_bloomCore * 0.6; diff --git a/flow-state/src/scenes/shader/kaleido-tunnel.js b/flow-state/src/scenes/shader/kaleido-tunnel.js index 9f0bc53..e4313b7 100644 --- a/flow-state/src/scenes/shader/kaleido-tunnel.js +++ b/flow-state/src/scenes/shader/kaleido-tunnel.js @@ -6,9 +6,8 @@ export const kaleidoTunnel = { family: 'geometric', kind: 'fragment', // Personality: see look/Personality.js. - // Grain is this scene's ONLY expression of the style trait — it draws no - // hard edges to weight — so it keeps a share of it rather than opting out. - texture: 0.35, + // Hard grid lines on flat colour: grain reads as dirt on the lens. + texture: 0, traits: ['shape', 'camera', 'style'], params: { @@ -49,7 +48,13 @@ vec4 scene(vec2 uv, vec2 p) { float ringLines = abs(fract(z * u_rings * 0.1) - 0.5) * 2.0; float wallLines = abs(fract(wall * sides) - 0.5) * 2.0; - float grid = smoothstep(0.42, 0.0, ringLines) + smoothstep(0.42, 0.0, wallLines); + // 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; diff --git a/flow-state/src/scenes/shader/silk-ribbon.js b/flow-state/src/scenes/shader/silk-ribbon.js index bcff392..97ad36a 100644 --- a/flow-state/src/scenes/shader/silk-ribbon.js +++ b/flow-state/src/scenes/shader/silk-ribbon.js @@ -9,9 +9,8 @@ export const silkRibbon = { family: 'minimal', kind: 'fragment', // Personality: see look/Personality.js. - // Grain is this scene's ONLY expression of the style trait — it draws no - // hard edges to weight — so it keeps a share of it rather than opting out. - texture: 0.35, + // A soft drape of light. Grain furs the one thing it is made of. + texture: 0, traits: ['camera', 'style'], params: { @@ -57,8 +56,16 @@ vec4 scene(vec2 uv, vec2 p) { best = min(best, d); } + // TRAIT style: the ribbon is drawn in the track's hand. u_sigLine sets + // how wide the strand is, u_sigSoft how fast it falls off — a sharp + // track gets a filament with a defined edge, a soft one gets a haze. + // This is the scene's whole art direction, so it is not scaled by any + // of its own params: there is no setting at which the track stops + // showing. + float w = u_thickness * mix(0.55, 1.7, sat(u_sigLine)); + float falloff = mix(2.6, 0.9, sat(u_sigSoft)); vec3 hc = pal(int(fk) % 3); - col += hc * exp(-best * best / (u_thickness * u_thickness)); + col += hc * exp(-pow(best / w, falloff * 2.0)); col += pal(3) * exp(-best * best * 60.0) * u_glow * 0.6; } diff --git a/flow-state/src/scenes/shader/slow-orb.js b/flow-state/src/scenes/shader/slow-orb.js index a410ff6..7185696 100644 --- a/flow-state/src/scenes/shader/slow-orb.js +++ b/flow-state/src/scenes/shader/slow-orb.js @@ -10,9 +10,10 @@ export const slowOrb = { family: 'minimal', kind: 'fragment', // Personality: see look/Personality.js. - // Grain is this scene's ONLY expression of the style trait — it draws no - // hard edges to weight — so it keeps a share of it rather than opting out. - texture: 0.35, + // One soft body in an empty frame — the emptiest scene in the library, and + // the one where speckle is most visible for being least justified. It keeps + // its own `grain` param, which exists to stop large flat areas banding. + texture: 0, traits: ['shape', 'camera', 'space', 'style'], params: { @@ -44,13 +45,22 @@ vec4 scene(vec2 uv, vec2 p) { float wobble = fbm(q * 2.4 + t, 4) * u_wobble; float d = (sigShape(q / max(u_size, 1e-3)) * u_size) * (1.0 + wobble); - float body = smoothstep(u_softness * 0.5, -u_softness * 0.5, d); + // TRAIT style: the body's edge is drawn in the track's hand. The scene's + // u_softness says how soft this orb is; u_sigSoft says how soft this VIDEO + // is, and the two multiply. + float edge = u_softness * mix(0.35, 1.5, sat(u_sigSoft)); + float body = smoothstep(edge * 0.5, -edge * 0.5, d); float glow = exp(-max(d, 0.0) * (5.0 / max(u_halo, 0.05))) * u_halo; + // A rim in the track's line weight, so a sharp-handed track gets a defined + // limb against the halo instead of only a softer gradient. + float rim = sigEdge(d) * u_sigLine; + vec3 col = pal(0) * 0.05; col = mix(col, pal(1), body * 0.85); col += pal(2) * body * body * 0.5; col += pal(3) * glow * 0.35; + col += pal(2) * rim * 0.5; // Fine grain keeps large flat areas from banding. col = sigAir(col, p, smoothstep(0.0, 1.6, length(q)));