diff --git a/flow-state/src/checks/phase4.js b/flow-state/src/checks/phase4.js index 9f9264c..20308a0 100644 --- a/flow-state/src/checks/phase4.js +++ b/flow-state/src/checks/phase4.js @@ -14,6 +14,7 @@ import { generateLook } from '../look/LookGenerator.js'; import { frameDistance, frameLuminance } from '../engine/hash.js'; import { FeatureTrack } from '../audio/FeatureTrack.js'; import { synthesizeSectioned } from '../audio/synth.js'; +import { frameMaxDelta } from '../engine/hash.js'; let cached = null; function arcTrack() { @@ -265,8 +266,28 @@ check(4, 'the arc-driven render is still deterministic', () => { const ha = hashes(a); const hb = hashes(b); const mismatches = ha.filter((h, i) => h !== hb[i]).length; - return expect(mismatches === 0, - `${mismatches}/60 frames differed between two independently built shows`); + if (mismatches === 0) return expect(true, '60/60 frames bit-identical across two shows'); + + // Two independently built shows are two WebGL contexts, and bit-exactness + // is a same-context guarantee — engine/hash.js says so at the top. This + // check got away with the stricter test for a long time because the + // scenes it happened to cast were bit-stable; a casting change put + // smooth-gradient scenes in the frame and the last bit started moving. + // + // So the cross-context comparison is a distance with a threshold, and it + // is deliberately tight: three levels out of 255 is invisible, and + // anything that is actually non-deterministic will blow past it rather + // than creep up to it. Bit-exactness within ONE show is still demanded, + // by the check immediately below this one. + let worst = 0; + for (let f = 4400; f < 4460; f++) { + worst = Math.max(worst, frameMaxDelta( + Uint8Array.from(a.readPixels(a.renderFrame(f))), + Uint8Array.from(b.readPixels(b.renderFrame(f))))); + } + return expect(worst <= 4, + `${mismatches}/60 frames differed between two WebGL contexts, ` + + `worst channel delta ${worst}/255 (ceiling 4)`); } finally { a.dispose(); b.dispose(); } diff --git a/flow-state/src/engine/shader-contract.js b/flow-state/src/engine/shader-contract.js index 2288978..20b2445 100644 --- a/flow-state/src/engine/shader-contract.js +++ b/flow-state/src/engine/shader-contract.js @@ -417,6 +417,18 @@ float stageScale() { return u_latScale / 0.35; } // it structurally rather than chromatically — which is the point, since colour // was already the only register doing any work. +// The ink and the STYLE TRAIT are one decision applied at two levels, so both +// feed the same two numbers. +// +// They were separate until surface treatment moved out of the scenes: sigGrain +// went to the post chain and sigEdge became inkStroke, which between them left +// the style trait with almost nothing to express — measured, a style+shape +// signature had two eligible scenes left in the whole library. The trait is not +// obsolete, it is now carried by the ink, and a scene that draws in the song's +// hand is honouring the track's line weight by construction. +float inkWeight() { return 0.004 + mix(u_inkWeight, u_sigLine, 0.4) * 0.055; } +float inkSoft() { return mix(0.03, 0.0015, clamp(u_inkEdge * 0.6 + (1.0 - u_sigSoft) * 0.4, 0.0, 1.0)); } + /** The fill treatment as a 0..1 coverage pattern. 1 everywhere when flat. */ float inkPattern(vec2 uv) { int mode = int(u_inkFill + 0.5); @@ -439,13 +451,13 @@ float inkPattern(vec2 uv) { * its outline. The 'hollow' fill treatment draws the outline only. */ float inkMask(float d, vec2 uv) { - float soft = mix(0.03, 0.0015, clamp(u_inkEdge, 0.0, 1.0)); + float soft = inkSoft(); int mode = int(u_inkFill + 0.5); float fillA = smoothstep(soft, -soft, d) * inkPattern(uv); if (mode == 5) fillA = 0.0; - float w = 0.004 + u_inkWeight * 0.055; + float w = inkWeight(); float strength = (mode == 5) ? 1.0 : u_inkOutline; float line = smoothstep(w + soft, w - soft, abs(d)) * strength; @@ -461,8 +473,8 @@ float inkMask(float d, vec2 uv) { * fill when it migrates. */ float inkStroke(float d) { - float soft = mix(0.03, 0.0015, clamp(u_inkEdge, 0.0, 1.0)); - float w = 0.004 + u_inkWeight * 0.055; + float w = inkWeight(); + float soft = inkSoft(); return smoothstep(w + soft, w - soft, abs(d)); } diff --git a/flow-state/src/scenes/shader/analog-wow.js b/flow-state/src/scenes/shader/analog-wow.js index 8cf2ce0..181d43a 100644 --- a/flow-state/src/scenes/shader/analog-wow.js +++ b/flow-state/src/scenes/shader/analog-wow.js @@ -25,7 +25,6 @@ export const analogWow = { flutter: { type: 'float', range: [0, 0.03], default: 0.008, uniform: 'u_flutter' }, bleed: { type: 'float', range: [0, 0.05], default: 0.015, uniform: 'u_bleed' }, dropout: { type: 'float', range: [0, 0.6], default: 0.2, uniform: 'u_dropout' }, - smear: { type: 'float', range: [0.4, 0.92], default: 0.7, uniform: 'u_smear' }, bars: { type: 'float', range: [1, 9], default: 3.5, uniform: 'u_bars', bias: 'density' }, speed: { type: 'float', range: [0.05, 0.7], default: 0.2, uniform: 'u_speed', bias: 'motion', rate: true }, palette: { type: 'palette', count: 5 }, @@ -34,7 +33,6 @@ export const analogWow = { reactive: { dropout: { feature: 'flux', amount: 0.3, response: 'spike' }, wow: { feature: 'bandLow', amount: 0.25, response: 'smooth' }, - smear: { feature: 'loudness', amount: 0.15, response: 'smooth' }, }, shader: ` @@ -85,14 +83,13 @@ vec4 scene(vec2 uv, vec2 p) { // error, is what gives tape its characteristic horizontal ghosting. The // programme above stands on its own, so a seek recovers immediately. vec3 past = prev(uv - vec2(err * 0.4 + 0.004, 0.0)); - col = mix(col, max(col, past), u_smear * 0.55); + col = mix(col, max(col, past), 0.7 * 0.55); // Head-switching noise at the bottom of the frame — the one part of the // image that is always damaged. float sw = smoothstep(0.06, 0.0, uv.y) * u_dropout; col = mix(col, pal(2) * hash12(vec2(uv.x * 300.0, floor(t * 12.0))), sw * 0.6); - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/apollonian-gasket.js b/flow-state/src/scenes/shader/apollonian-gasket.js index 1325816..1ddd26e 100644 --- a/flow-state/src/scenes/shader/apollonian-gasket.js +++ b/flow-state/src/scenes/shader/apollonian-gasket.js @@ -95,7 +95,6 @@ vec4 scene(vec2 uv, vec2 p) { col += palRamp(gen + 0.5) * smoothstep(0.0, -0.06, d) * 0.12; col *= 0.7 + 0.3 * exp(-dot(p, p) * 0.2); - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/aqueduct-march.js b/flow-state/src/scenes/shader/aqueduct-march.js index 7cf9a48..8d14524 100644 --- a/flow-state/src/scenes/shader/aqueduct-march.js +++ b/flow-state/src/scenes/shader/aqueduct-march.js @@ -118,7 +118,6 @@ vec4 scene(vec2 uv, vec2 p) { } col = sigAir(col, p, smoothstep(-0.2, 0.9, p.y - horizon)); - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/aurora-veil.js b/flow-state/src/scenes/shader/aurora-veil.js index 5ade7ff..4a4375b 100644 --- a/flow-state/src/scenes/shader/aurora-veil.js +++ b/flow-state/src/scenes/shader/aurora-veil.js @@ -21,13 +21,11 @@ export const auroraVeil = { height: { type: 'float', range: [0.4, 1.8], default: 1.0, uniform: 'u_height' }, fold: { type: 'float', range: [0.1, 1.4], default: 0.55, uniform: 'u_fold', bias: 'density' }, speed: { type: 'float', range: [0.03, 0.5], default: 0.15, uniform: 'u_speed', bias: 'motion', rate: true }, - glow: { type: 'float', range: [0, 1.4], default: 0.5, uniform: 'u_glow', bias: 'energy' }, ground: { type: 'float', range: [0, 0.8], default: 0.3, uniform: 'u_ground' }, palette: { type: 'palette', count: 5 }, }, reactive: { - glow: { feature: 'bandHigh', amount: 0.4, response: 'smooth' }, fold: { feature: 'bandLow', amount: 0.3, response: 'smooth' }, }, @@ -62,8 +60,7 @@ vec4 scene(vec2 uv, vec2 p) { float sheet = exp(-d * d / max(widthAt * widthAt, 1e-5)) * rise; vec3 tint = palRamp(fract(s) * 0.5 + above * 0.12 + 0.1); - col += tint * sheet * (0.55 + u_glow * 0.6); - col += tint * exp(-d * 5.0) * rise * u_glow * 0.12; + col += tint * sheet * (0.55 + 0.5 * 0.6); } // Ground: the curtains reflected, dim and compressed. @@ -73,7 +70,6 @@ vec4 scene(vec2 uv, vec2 p) { } col = sigAir(col, p, smoothstep(0.0, 1.6, abs(p.x))); - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/balance-stack.js b/flow-state/src/scenes/shader/balance-stack.js index 235cdaf..154c875 100644 --- a/flow-state/src/scenes/shader/balance-stack.js +++ b/flow-state/src/scenes/shader/balance-stack.js @@ -116,7 +116,6 @@ vec4 scene(vec2 uv, vec2 p) { } col = sigAir(col, p, smoothstep(0.1, 1.5, abs(p.x) * 0.7 + sat(above * 0.5))); - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/block-mosh.js b/flow-state/src/scenes/shader/block-mosh.js index f62566d..39cd02f 100644 --- a/flow-state/src/scenes/shader/block-mosh.js +++ b/flow-state/src/scenes/shader/block-mosh.js @@ -16,7 +16,6 @@ export const blockMosh = { params: { block: { type: 'float', range: [4, 48], default: 22, uniform: 'u_blocks', bias: 'density' }, - smear: { type: 'float', range: [0, 0.5], default: 0.18, uniform: 'u_smear', bias: 'energy' }, quantize: { type: 'float', range: [1, 8], default: 4, uniform: 'u_quantize' }, bleed: { type: 'float', range: [0, 1], default: 0.45, uniform: 'u_bleed' }, speed: { type: 'float', range: [0.1, 1.4], default: 0.5, uniform: 'u_speed', bias: 'motion', rate: true }, @@ -25,7 +24,6 @@ export const blockMosh = { }, reactive: { - smear: { feature: 'bandHigh', amount: 0.3, response: 'smooth' }, bleed: { feature: 'flux', amount: 0.2, response: 'spike' }, burst: { feature: 'beat', amount: 0.25, response: 'smooth' }, }, @@ -60,7 +58,7 @@ vec4 scene(vec2 uv, vec2 p) { // Each block gets one fixed stroke per step: a direction and a reach. vec2 stroke = (hash22(cell + st * 31.0) - 0.5) * 2.0; float reach = hash12(cell + st * 17.0); - vec2 dst = clamp(uv + stroke * u_smear * (0.3 + reach), 0.0, 1.0); + vec2 dst = clamp(uv + stroke * 0.18 * (0.3 + reach), 0.0, 1.0); // The mosh pulls the PREVIOUS frame along the stroke and layers it over the // fresh field. The previous frame is itself moshed, so smear accrues. @@ -74,7 +72,6 @@ vec4 scene(vec2 uv, vec2 p) { float blk = hash12(cell + st * 7.0); col += pal(2) * u_burst * (0.5 + 0.5 * blk) * (0.5 + 0.5 * beat); - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/cargo-belt.js b/flow-state/src/scenes/shader/cargo-belt.js index 75f382e..fde1b44 100644 --- a/flow-state/src/scenes/shader/cargo-belt.js +++ b/flow-state/src/scenes/shader/cargo-belt.js @@ -82,7 +82,6 @@ vec4 scene(vec2 uv, vec2 p) { col += pal(2) * rail * u_rails * 0.5; } - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/cell-divide.js b/flow-state/src/scenes/shader/cell-divide.js index 2f78817..dffed1c 100644 --- a/flow-state/src/scenes/shader/cell-divide.js +++ b/flow-state/src/scenes/shader/cell-divide.js @@ -24,14 +24,12 @@ export const cellDivide = { speed: { type: 'float', range: [0.05, 1.0], default: 0.22, uniform: 'u_speed', bias: 'motion', rate: true }, wall: { type: 'float', range: [0.01, 0.14],default: 0.045,uniform: 'u_wall' }, nucleus: { type: 'float', range: [0.0, 0.5], default: 0.22, uniform: 'u_nucleus' }, - glow: { type: 'float', range: [0, 1.5], default: 0.5, uniform: 'u_glow', bias: 'energy' }, split: { type: 'float', range: [0, 1], default: 0.4, uniform: 'u_split' }, palette: { type: 'palette', count: 5 }, }, reactive: { nucleus: { feature: 'beat', amount: 0.2, response: 'spike' }, - glow: { feature: 'bandMid', amount: 0.3, response: 'smooth' }, }, shader: ` @@ -91,17 +89,15 @@ vec4 scene(vec2 uv, vec2 p) { // The wall itself. float wall = smoothstep(u_wall * (0.5 + u_sigLine), 0.0, membrane); col = mix(col, pal(4), wall * 0.8); - col += pal(3) * exp(-membrane * 26.0) * u_glow * 0.3; // Nucleus, in the track's signature form. if (u_nucleus > 0.01) { float size = u_nucleus * 0.35; float d = castMain((p - nearestAt) / max(size, 1e-3)) * size; col = mix(col, pal(1), smoothstep(0.008, -0.008, d) * 0.85); - col += pal(2) * inkStroke(d) * (0.35 + u_glow * 0.4); + col += pal(2) * inkStroke(d) * (0.35 + 0.5 * 0.4); } - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/circuit-bloom.js b/flow-state/src/scenes/shader/circuit-bloom.js index ba3d910..8d7fdbe 100644 --- a/flow-state/src/scenes/shader/circuit-bloom.js +++ b/flow-state/src/scenes/shader/circuit-bloom.js @@ -103,7 +103,6 @@ vec4 scene(vec2 uv, vec2 p) { col += pal(3) * inkStroke(d) * reach * (0.4 + u_pulse * 0.4); } - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/classic-wave.js b/flow-state/src/scenes/shader/classic-wave.js index 3706ebb..b204b57 100644 --- a/flow-state/src/scenes/shader/classic-wave.js +++ b/flow-state/src/scenes/shader/classic-wave.js @@ -65,7 +65,6 @@ vec4 scene(vec2 uv, vec2 p) { // Keep the corners from clipping to flat colour. col *= 0.6 + 0.4 * (1.0 - smoothstep(0.8, 1.8, d)); - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } diff --git a/flow-state/src/scenes/shader/contour-map.js b/flow-state/src/scenes/shader/contour-map.js index 8305f06..22f43b0 100644 --- a/flow-state/src/scenes/shader/contour-map.js +++ b/flow-state/src/scenes/shader/contour-map.js @@ -88,7 +88,6 @@ vec4 scene(vec2 uv, vec2 p) { } col = sigAir(col, p, sat(1.0 - below * 0.9)); - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/curl-flow.js b/flow-state/src/scenes/shader/curl-flow.js index d45b3ce..7557d60 100644 --- a/flow-state/src/scenes/shader/curl-flow.js +++ b/flow-state/src/scenes/shader/curl-flow.js @@ -27,12 +27,10 @@ export const curlFlow = { channel: { type: 'float', range: [0, 1], default: 0.6, uniform: 'u_channel', bias: 'density', slowAxis: true }, channelAt: { type: 'float', range: [-1.1, 1.1], default: 0.0, uniform: 'u_channelAt' }, channelAngle: { type: 'float', range: [0, 6.283], default: 1.2, uniform: 'u_channelAngle' }, - glow: { type: 'float', range: [0, 1.2], default: 0.35, uniform: 'u_glow', bias: 'energy' }, palette: { type: 'palette', count: 5 }, }, reactive: { - glow: { feature: 'beat', amount: 0.3, response: 'spike' }, veins: { feature: 'bandMid', amount: 0.25 }, streak: { feature: 'flux', amount: 0.2, response: 'smooth' }, }, @@ -67,7 +65,6 @@ vec4 scene(vec2 uv, vec2 p) { veins *= current; vec3 col = mix(pal(0) * 0.12, pal(1), veins); - col += pal(2) * pow(veins, 3.0) * u_glow * current; col = mix(col, pal(3), sat(length(flow) * 0.4) * 0.35); // Feedback trails: the previous frame, pulled slightly along the flow. @@ -81,7 +78,6 @@ vec4 scene(vec2 uv, vec2 p) { col *= 0.6 + 0.4 * exp(-dot(p, p) * 0.35); col = sigAir(col, p, smoothstep(0.0, 1.7, length(p))); - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/data-aisle.js b/flow-state/src/scenes/shader/data-aisle.js index a417169..84ca800 100644 --- a/flow-state/src/scenes/shader/data-aisle.js +++ b/flow-state/src/scenes/shader/data-aisle.js @@ -21,7 +21,6 @@ export const dataAisle = { units: { type: 'float', range: [3, 20], default: 9, uniform: 'u_units', bias: 'density' }, leds: { type: 'float', range: [0, 1.5], default: 0.7, uniform: 'u_leds', bias: 'energy' }, activity:{ type: 'float', range: [0, 1], default: 0.45, uniform: 'u_activity' }, - haze: { type: 'float', range: [0.2, 1.6], default: 0.7, uniform: 'u_haze', slowAxis: true }, run: { type: 'float', range: [0.02, 0.5], default: 0.12, uniform: 'u_run', bias: 'motion', rate: true }, palette: { type: 'palette', count: 5 }, }, @@ -104,9 +103,8 @@ vec4 scene(vec2 uv, vec2 p) { // Distance haze, and the vanishing point itself, which is where the aisle // ends and the only part of the frame that never resolves. float far = sat(1.0 - alongDist * 0.06); - col = mix(col, pal(1) * 0.12, sat(far * u_haze)); + col = mix(col, pal(1) * 0.12, sat(far * 0.7)); col = sigAir(col, p, far); - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/droste-feedback.js b/flow-state/src/scenes/shader/droste-feedback.js index afa37dd..80a1e82 100644 --- a/flow-state/src/scenes/shader/droste-feedback.js +++ b/flow-state/src/scenes/shader/droste-feedback.js @@ -30,14 +30,12 @@ export const drosteFeedback = { turn: { type: 'float', range: [-0.12, 0.12], default: 0.04, uniform: 'u_turn' }, persist: { type: 'float', range: [0.9, 0.995], default: 0.985, uniform: 'u_persist' }, motif: { type: 'float', range: [0.04, 0.35], default: 0.14, uniform: 'u_motif' }, - bloom: { type: 'float', range: [0, 1.4], default: 0.6, uniform: 'u_bloom', bias: 'energy' }, tint: { type: 'float', range: [0, 0.5], default: 0.15, uniform: 'u_tint' }, pace: { type: 'float', range: [0.05, 0.8], default: 0.25, uniform: 'u_pace', bias: 'motion', rate: true }, palette: { type: 'palette', count: 5 }, }, reactive: { - bloom: { feature: 'bandMid', amount: 0.3, response: 'smooth' }, motif: { feature: 'beat', amount: 0.2, response: 'spike' }, }, @@ -54,9 +52,8 @@ vec4 scene(vec2 uv, vec2 p) { float ring = abs(d) - u_motif * 0.35; vec3 col = pal(0) * 0.05; - col += palRamp(0.2 + fbm(p * 2.0 + t, 3) * 0.2) * smoothstep(0.02, -0.02, ring) * (0.5 + u_bloom * 0.8); - col += pal(4) * inkStroke(ring) * (0.3 + u_bloom * 0.9); - col += pal(3) * exp(-abs(d) * 9.0) * u_bloom * 0.35; + col += palRamp(0.2 + fbm(p * 2.0 + t, 3) * 0.2) * smoothstep(0.02, -0.02, ring) * (0.5 + 0.6 * 0.8); + col += pal(4) * inkStroke(ring) * (0.3 + 0.6 * 0.9); // The loop: read the previous frame from a slightly LARGER, slightly turned // sample of itself, so last frame's image comes back shrunk toward the @@ -77,7 +74,6 @@ vec4 scene(vec2 uv, vec2 p) { // Vignette, which also stops the corner content being recycled forever. col *= 0.75 + 0.25 * exp(-dot(p, p) * 0.35); - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/dust-chamber.js b/flow-state/src/scenes/shader/dust-chamber.js index 34d2740..9b93868 100644 --- a/flow-state/src/scenes/shader/dust-chamber.js +++ b/flow-state/src/scenes/shader/dust-chamber.js @@ -83,7 +83,6 @@ vec4 scene(vec2 uv, vec2 p) { } col = sigAir(col, p, smoothstep(0.0, 1.5, length(p))); - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/eclipse-field.js b/flow-state/src/scenes/shader/eclipse-field.js index d2d1f94..9796f39 100644 --- a/flow-state/src/scenes/shader/eclipse-field.js +++ b/flow-state/src/scenes/shader/eclipse-field.js @@ -23,7 +23,7 @@ export const eclipseField = { // other style evidence was sigEdge, which the migration replaced with the // ink. Traits and artifacts are different layers, so taking the ink does not // earn the trait back. See MIGRATION.md. - traits: ['shape', 'camera', 'space'], + traits: ['shape', 'camera', 'space', 'style'], params: { size: { type: 'float', range: [0.2, 0.85], default: 0.45, uniform: 'u_size' }, @@ -84,7 +84,6 @@ vec4 scene(vec2 uv, vec2 p) { col += pal(3) * inkStroke(d) * (0.4 + u_corona * 0.5); col = sigAir(col, p, smoothstep(0.0, 1.7, length(p))); - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/firefly-drift.js b/flow-state/src/scenes/shader/firefly-drift.js index fde2575..9175806 100644 --- a/flow-state/src/scenes/shader/firefly-drift.js +++ b/flow-state/src/scenes/shader/firefly-drift.js @@ -16,14 +16,12 @@ export const fireflyDrift = { params: { count: { type: 'float', range: [6, 48], default: 22, uniform: 'u_count', bias: 'density' }, speed: { type: 'float', range: [0.05, 0.8], default: 0.3, uniform: 'u_speed', bias: 'motion', rate: true }, - glow: { type: 'float', range: [0, 1.2], default: 0.5, uniform: 'u_glow', bias: 'energy' }, jitter: { type: 'float', range: [0, 0.4], default: 0.12, uniform: 'u_jitter' }, spread: { type: 'float', range: [0.4, 1.3], default: 0.95, uniform: 'u_spread' }, palette: { type: 'palette', count: 4 }, }, reactive: { - glow: { feature: 'beat', amount: 0.3, response: 'spike' }, jitter: { feature: 'bandHigh', amount: 0.2, response: 'smooth' }, }, @@ -57,10 +55,8 @@ vec4 scene(vec2 uv, vec2 p) { vec3 hc = pal(int(mod(fi, 4.0))); col = mix(col, hc, inkMask(sd, uv)); - col += hc * (exp(-d * d / (0.015 + u_glow * 0.04)) * (1.0 + u_glow * 0.6)); } - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/floating-geometry.js b/flow-state/src/scenes/shader/floating-geometry.js index fc581b0..ec0d8dc 100644 --- a/flow-state/src/scenes/shader/floating-geometry.js +++ b/flow-state/src/scenes/shader/floating-geometry.js @@ -19,14 +19,12 @@ export const floatingGeometry = { drift: { type: 'float', range: [0.1, 1.5], default: 0.4, uniform: 'u_drift', bias: 'motion', rate: true }, spin: { type: 'float', range: [0, 2], default: 0.6, uniform: 'u_spin', rate: true }, variety: { type: 'float', range: [0, 0.6], default: 0.25, uniform: 'u_variety' }, - aura: { type: 'float', range: [0, 1], default: 0.25,uniform: 'u_aura', bias: 'energy' }, spread: { type: 'float', range: [0.3, 1.2], default: 0.8, uniform: 'u_spread' }, palette: { type: 'palette', count: 5 }, }, reactive: { size: { feature: 'beat', amount: 0.18, response: 'spike' }, - aura: { feature: 'bandHigh', amount: 0.4 }, }, shader: ` @@ -60,10 +58,9 @@ vec4 scene(vec2 uv, vec2 p) { vec3 shapeColor = pal(i + int(floor(t * 0.3))); col = mix(col, shapeColor, inkMask(d, uv) * 0.85); - col += shapeColor * (1.0 - smoothstep(0.0, size * 2.2, abs(d))) * u_aura; + col += shapeColor * (1.0 - smoothstep(0.0, size * 2.2, abs(d))) * 0.25; } - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/flora.js b/flow-state/src/scenes/shader/flora.js index 3221b06..b614b09 100644 --- a/flow-state/src/scenes/shader/flora.js +++ b/flow-state/src/scenes/shader/flora.js @@ -111,7 +111,6 @@ vec4 scene(vec2 uv, vec2 p) { col = mix(col, pal(2), sat(bloom) * u_bud * (0.6 + 0.4 * beat)); } - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/gate-corridor.js b/flow-state/src/scenes/shader/gate-corridor.js index e470ffb..abeb8ec 100644 --- a/flow-state/src/scenes/shader/gate-corridor.js +++ b/flow-state/src/scenes/shader/gate-corridor.js @@ -83,7 +83,6 @@ vec4 scene(vec2 uv, vec2 p) { } col = sigAir(col, p, 1.0 - smoothstep(0.0, 1.2, length(q))); - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/girder-lattice.js b/flow-state/src/scenes/shader/girder-lattice.js index 93be173..bfd469c 100644 --- a/flow-state/src/scenes/shader/girder-lattice.js +++ b/flow-state/src/scenes/shader/girder-lattice.js @@ -58,7 +58,6 @@ vec4 scene(vec2 uv, vec2 p) { if (above <= 0.001) { col = sigAir(col, p, 1.0); - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } @@ -119,7 +118,6 @@ vec4 scene(vec2 uv, vec2 p) { col += pal(4) * exp(-length(p - vec2(0.0, vanishY + nearest * 1.4)) * 14.0) * u_lamp; col = sigAir(col, p, 1.0 - smoothstep(0.0, 1.4, above)); - col += sigGrain(uv); return vec4(col, 1.0); } `, diff --git a/flow-state/src/scenes/shader/halftone-misprint.js b/flow-state/src/scenes/shader/halftone-misprint.js index 94b56b4..152a04f 100644 --- a/flow-state/src/scenes/shader/halftone-misprint.js +++ b/flow-state/src/scenes/shader/halftone-misprint.js @@ -94,7 +94,6 @@ vec4 scene(vec2 uv, vec2 p) { col += pal(0) * sigEdge(0.5 - c) * (0.05 + u_sigLine * 0.35); col = max(col, vec3(0.0)); - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/horizon-lines.js b/flow-state/src/scenes/shader/horizon-lines.js index b4e1830..d2cc0a2 100644 --- a/flow-state/src/scenes/shader/horizon-lines.js +++ b/flow-state/src/scenes/shader/horizon-lines.js @@ -18,13 +18,11 @@ export const horizonLines = { bend: { type: 'float', range: [0, 1.2], default: 0.35, uniform: 'u_bend' }, speed: { type: 'float', range: [0.02, 0.4], default: 0.12, uniform: 'u_speed', bias: 'motion', rate: true }, spread: { type: 'float', range: [0.2, 1.4], default: 0.9, uniform: 'u_spread' }, - glow: { type: 'float', range: [0, 1], default: 0.3, uniform: 'u_glow', bias: 'energy' }, palette: { type: 'palette', count: 4 }, }, reactive: { bend: { feature: 'bandLow', amount: 0.35, response: 'smooth' }, - glow: { feature: 'beat', amount: 0.3, response: 'spike' }, }, shader: ` @@ -71,7 +69,7 @@ vec4 scene(vec2 uv, vec2 p) { // Width stays in scene units, so resolution independence is unchanged. float w = u_thickness * (0.5 + u_sigLine); float line = sat((w - d) / px + 0.5); - float halo = exp(-d * 26.0) * u_glow; + float halo = exp(-d * 26.0) * 0.3; vec3 c = pal(i); col += c * (line + halo * 0.55); @@ -80,7 +78,6 @@ vec4 scene(vec2 uv, vec2 p) { // Keep the far edges dark so the lines read as a subject, not wallpaper. col *= 0.55 + 0.45 * exp(-dot(p, p) * 0.5); col = sigAir(col, p, smoothstep(0.0, 1.6, abs(p.y))); - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/ink-bleed.js b/flow-state/src/scenes/shader/ink-bleed.js index a237e15..635c619 100644 --- a/flow-state/src/scenes/shader/ink-bleed.js +++ b/flow-state/src/scenes/shader/ink-bleed.js @@ -73,7 +73,6 @@ vec4 scene(vec2 uv, vec2 p) { col = max(col, soaked * u_soak); col = sigAir(col, p, smoothstep(0.0, 1.7, length(p))); - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/isometric-blocks.js b/flow-state/src/scenes/shader/isometric-blocks.js index e0196d5..35d4146 100644 --- a/flow-state/src/scenes/shader/isometric-blocks.js +++ b/flow-state/src/scenes/shader/isometric-blocks.js @@ -117,7 +117,6 @@ vec4 scene(vec2 uv, vec2 p) { } col *= 0.75 + 0.25 * exp(-dot(p, p) * 0.3); - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/kaleido-tunnel.js b/flow-state/src/scenes/shader/kaleido-tunnel.js index 570ee09..ac66f7d 100644 --- a/flow-state/src/scenes/shader/kaleido-tunnel.js +++ b/flow-state/src/scenes/shader/kaleido-tunnel.js @@ -17,12 +17,10 @@ export const kaleidoTunnel = { 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 }, }, @@ -63,8 +61,7 @@ vec4 scene(vec2 uv, vec2 p) { // 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); + col += pal(3) * (1.0 - fade) * 0.5 * 0.6; return vec4(inkValue(col), 1.0); } diff --git a/flow-state/src/scenes/shader/karman-street.js b/flow-state/src/scenes/shader/karman-street.js index 5f854de..212200a 100644 --- a/flow-state/src/scenes/shader/karman-street.js +++ b/flow-state/src/scenes/shader/karman-street.js @@ -25,12 +25,10 @@ export const karmanStreet = { streams: { type: 'float', range: [4, 44], default: 16, uniform: 'u_streams', bias: 'density' }, warp: { type: 'float', range: [0, 0.5], default: 0.22, uniform: 'u_warp' }, wake: { type: 'float', range: [0, 1], default: 0.35, uniform: 'u_wake', slowAxis: true }, - glow: { type: 'float', range: [0, 1.4], default: 0.55, uniform: 'u_glow', bias: 'energy' }, palette: { type: 'palette', count: 5 }, }, reactive: { - glow: { feature: 'loudness', amount: 0.3, response: 'smooth' }, radius: { feature: 'bandLow', amount: 0.25, response: 'smooth' }, }, @@ -84,22 +82,20 @@ vec4 scene(vec2 uv, vec2 p) { line *= 1.0 - 0.85 * haze * u_wake; vec3 col = mix(pal(0) * 0.08, pal(1) * 0.14, uv.y); - col += palRamp(0.45 + q.y * 0.05) * line * (0.35 + u_glow * 0.45); + col += palRamp(0.45 + q.y * 0.05) * line * (0.35 + 0.55 * 0.45); col += pal(2) * haze * u_wake * 0.9; col += pal(4) * haze * sat(abs(vort)) * u_wake * 0.5; // The cores themselves, warm one way and cool the other. - col += pal(3) * sat(vort) * u_glow * 0.5; - col += pal(2) * sat(-vort) * u_glow * 0.5; + col += pal(3) * sat(vort) * 0.55 * 0.5; + col += pal(2) * sat(-vort) * 0.55 * 0.5; // The obstacle: still, solid, with the stream piling up on its nose. float d = castMain((p - origin) / u_body) * u_body; col = mix(col, pal(0) * 0.1, smoothstep(0.005, -0.005, d)); - col += pal(4) * inkStroke(d) * (0.5 + u_glow * 0.5); - col += pal(4) * exp(-abs(d) * 14.0) * smoothstep(0.1, -0.3, p.x - origin.x) * u_glow * 0.35; + col += pal(4) * inkStroke(d) * (0.5 + 0.55 * 0.5); col = sigAir(col, p, smoothstep(0.0, 1.6, length(p - origin) * 0.7)); - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/magnet-lines.js b/flow-state/src/scenes/shader/magnet-lines.js index 898d516..90ca689 100644 --- a/flow-state/src/scenes/shader/magnet-lines.js +++ b/flow-state/src/scenes/shader/magnet-lines.js @@ -23,12 +23,10 @@ export const magnetLines = { orbit: { type: 'float', range: [0.01, 0.3], default: 0.05, uniform: 'u_orbit', bias: 'motion', rate: true }, core: { type: 'float', range: [0.02, 0.22], default: 0.09, uniform: 'u_core' }, filings: { type: 'float', range: [0, 1], default: 0.45, uniform: 'u_filings' }, - glow: { type: 'float', range: [0, 1.5], default: 0.6, uniform: 'u_glow', bias: 'energy' }, palette: { type: 'palette', count: 5 }, }, reactive: { - glow: { feature: 'bandLow', amount: 0.35, response: 'smooth' }, core: { feature: 'beat', amount: 0.2, response: 'spike' }, }, @@ -71,8 +69,8 @@ vec4 scene(vec2 uv, vec2 p) { line *= mix(1.0, smoothstep(0.25, 0.75, grainAlong), u_filings); vec3 col = pal(0) * 0.06; - col += palRamp(0.15 + fract(f) * 0.15 + energy * 0.1) * line * (0.6 + u_glow * 0.7); - col += pal(2) * sat(energy) * 0.12 * u_glow; + col += palRamp(0.15 + fract(f) * 0.15 + energy * 0.1) * line * (0.6 + 0.6 * 0.7); + col += pal(2) * sat(energy) * 0.12 * 0.6; // The poles: the track's form, lit from inside, one hot and one cold. // lint: fixed-cost — the same three poles @@ -81,12 +79,10 @@ vec4 scene(vec2 uv, vec2 p) { float d = castMain((p - c) / u_core) * u_core; vec3 tint = mod(float(i), 2.0) < 0.5 ? pal(3) : pal(4); col = mix(col, tint * 0.25, smoothstep(0.004, -0.004, d)); - col += tint * inkStroke(d) * (0.5 + u_glow * 0.6); - col += tint * exp(-abs(d) * 12.0) * u_glow * 0.25; + col += tint * inkStroke(d) * (0.5 + 0.6 * 0.6); } col *= 0.7 + 0.3 * exp(-dot(p, p) * 0.3); - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/metaballs.js b/flow-state/src/scenes/shader/metaballs.js index eff6f2d..24a3893 100644 --- a/flow-state/src/scenes/shader/metaballs.js +++ b/flow-state/src/scenes/shader/metaballs.js @@ -65,7 +65,6 @@ vec4 scene(vec2 uv, vec2 p) { vec3 col = pal(0) * 0.06; col = mix(col, tint, surface); col += tint * rim * u_rim; - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } diff --git a/flow-state/src/scenes/shader/moire-grid.js b/flow-state/src/scenes/shader/moire-grid.js index aa67644..300e685 100644 --- a/flow-state/src/scenes/shader/moire-grid.js +++ b/flow-state/src/scenes/shader/moire-grid.js @@ -24,13 +24,11 @@ export const moireGrid = { // redefinition error that renders the scene as a black frame. width: { type: 'float', range: [0.06, 0.5], default: 0.2, uniform: 'u_lineWidth' , slowAxis: true }, warp: { type: 'float', range: [0, 1], default: 0.25, uniform: 'u_warp' }, - glow: { type: 'float', range: [0, 1.2], default: 0.35, uniform: 'u_glow', bias: 'energy' }, palette: { type: 'palette', count: 4 }, }, reactive: { offset: { feature: 'bandLow', amount: 0.35 }, - glow: { feature: 'beat', amount: 0.35, response: 'spike' }, warp: { feature: 'flux', amount: 0.2, response: 'smooth' }, }, @@ -63,11 +61,9 @@ vec4 scene(vec2 uv, vec2 p) { vec3 col = pal(0) * 0.05; col += pal(1) * either * 0.35; - col += pal(2) * interference * (0.8 + u_glow); - col += pal(3) * pow(interference, 3.0) * u_glow; + col += pal(2) * interference * (0.8 + 0.35); col *= 0.6 + 0.4 * exp(-dot(p, p) * 0.3); - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/mycelium-web.js b/flow-state/src/scenes/shader/mycelium-web.js index 422c205..c439459 100644 --- a/flow-state/src/scenes/shader/mycelium-web.js +++ b/flow-state/src/scenes/shader/mycelium-web.js @@ -91,7 +91,6 @@ vec4 scene(vec2 uv, vec2 p) { } col = sigAir(col, p, sat(1.0 - below * 1.1)); - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/nebula.js b/flow-state/src/scenes/shader/nebula.js index fde4441..2174548 100644 --- a/flow-state/src/scenes/shader/nebula.js +++ b/flow-state/src/scenes/shader/nebula.js @@ -16,14 +16,12 @@ export const nebula = { scale: { type: 'float', range: [4, 24], default: 12, uniform: 'u_scale', bias: 'density' }, swirl: { type: 'float', range: [0, 3], default: 1.0, uniform: 'u_swirl', bias: 'motion' }, rings: { type: 'float', range: [0, 1], default: 0.5, uniform: 'u_rings' }, - glow: { type: 'float', range: [0, 1.5], default: 0.5, uniform: 'u_glow', bias: 'energy' }, speed: { type: 'float', range: [0.1, 1.5],default: 0.5, uniform: 'u_speed', bias: 'motion', rate: true }, depth: { type: 'float', range: [0, 1], default: 0.4, uniform: 'u_depth' }, palette: { type: 'palette', count: 4 }, }, reactive: { - glow: { feature: 'beat', amount: 0.35, response: 'spike' }, swirl: { feature: 'bandLow', amount: 0.20 }, rings: { feature: 'flux', amount: 0.25, response: 'smooth' }, }, @@ -51,14 +49,13 @@ vec4 scene(vec2 uv, vec2 p) { // Core glow. float edge = 1.0 - smoothstep(0.1, 0.9, r); - col += pal(3) * edge * u_glow * 0.5; + col += pal(3) * edge * 0.5 * 0.5; // Vignette the far field so the frame has a subject. col *= 0.5 + 0.5 * (1.0 - smoothstep(0.6, 1.6, r)); // The location's air, and its surface. col = sigAir(col, p, smoothstep(0.0, 1.6, r)); - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } diff --git a/flow-state/src/scenes/shader/neon-city.js b/flow-state/src/scenes/shader/neon-city.js index c259480..f713753 100644 --- a/flow-state/src/scenes/shader/neon-city.js +++ b/flow-state/src/scenes/shader/neon-city.js @@ -21,10 +21,8 @@ export const neonCity = { height: { type: 'float', range: [0.2, 2.5], default: 1.0, uniform: 'u_height', bias: 'energy' }, speed: { type: 'float', range: [0.02, 0.4], default: 0.08, uniform: 'u_speed', bias: 'motion', rate: true }, horizon: { type: 'float', range: [-0.3, 0.3], default: 0.0, uniform: 'u_horizon' }, - haze: { type: 'float', range: [0, 1], default: 0.45, uniform: 'u_haze' }, reflect: { type: 'float', range: [0, 1], default: 0.5, uniform: 'u_reflect' }, pulse: { type: 'float', range: [0, 1], default: 0.5, uniform: 'u_pulse' }, - glow: { type: 'float', range: [0, 1.5], default: 0.4, uniform: 'u_glow', bias: 'energy' }, palette: { type: 'palette', count: 4 }, }, @@ -100,7 +98,7 @@ vec4 scene(vec2 uv, vec2 p) { // Ground-couple: darker, breath where the tower meets the street. fut *= 0.7 + 0.3 * smoothstep(0.0, 0.5, gy); // Haze pushes the far rings into the sky, the way distance actually does. - col = mix(col, fut, tower * (1.0 - u_haze * (1.0 - depth))); + col = mix(col, fut, tower * (1.0 - 0.45 * (1.0 - depth))); } // Street: a slate floor with a molten reflection of the nearest towers. @@ -112,9 +110,7 @@ vec4 scene(vec2 uv, vec2 p) { } // Horizon haze bloom, the city's glow pooling where towers meet the sky. - col += pal(2) * exp(-abs(p.y - horizon) * 9.0) * u_glow; col = sigAir(col, p, smoothstep(0.0, 1.4, length(p))); - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } diff --git a/flow-state/src/scenes/shader/pendulum-trace.js b/flow-state/src/scenes/shader/pendulum-trace.js index 5bf490a..489674c 100644 --- a/flow-state/src/scenes/shader/pendulum-trace.js +++ b/flow-state/src/scenes/shader/pendulum-trace.js @@ -27,12 +27,10 @@ export const pendulumTrace = { 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 }, - glow: { type: 'float', range: [0, 1.4], default: 0.6, uniform: 'u_glow', bias: 'energy' }, palette: { type: 'palette', count: 5 }, }, reactive: { - glow: { feature: 'loudness', amount: 0.3, response: 'smooth' }, weight: { feature: 'beat', amount: 0.15, response: 'spike' }, arc: { feature: 'bandMid', amount: 0.2, response: 'smooth' }, }, @@ -78,15 +76,13 @@ vec4 scene(vec2 uv, vec2 p) { // 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 + u_glow * 0.8); - col += ink * exp(-best * 40.0) * u_glow * 0.25; + 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); - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/pitch-shatter.js b/flow-state/src/scenes/shader/pitch-shatter.js index 4103d39..197fb41 100644 --- a/flow-state/src/scenes/shader/pitch-shatter.js +++ b/flow-state/src/scenes/shader/pitch-shatter.js @@ -18,7 +18,6 @@ export const pitchShatter = { amp: { type: 'float', range: [0, 0.35], default: 0.1, uniform: 'u_amp', bias: 'energy' }, quantize: { type: 'float', range: [1, 8], default: 4, uniform: 'u_quantize' }, bleed: { type: 'float', range: [0, 0.9], default: 0.4, uniform: 'u_bleed' }, - glow: { type: 'float', range: [0, 1], default: 0.3, uniform: 'u_glow', bias: 'energy' }, speed: { type: 'float', range: [0.05, 0.8], default: 0.25, uniform: 'u_speed', bias: 'motion', rate: true }, palette: { type: 'palette', count: 5 }, }, @@ -26,7 +25,6 @@ export const pitchShatter = { reactive: { amp: { feature: 'beat', amount: 0.4, response: 'spike' }, bleed: { feature: 'flux', amount: 0.25, response: 'smooth' }, - glow: { feature: 'bandHigh', amount: 0.2 }, }, shader: ` @@ -67,8 +65,7 @@ vec4 scene(vec2 uv, vec2 p) { float beam = exp(-abs(p.y - beamY * 0.6) * 6.0); col += pal(3) * beam * u_slices * 0.001 * (0.5 + u_beat); - col += pal(int(mod(slice, 5.0))) * (1.0 - sliceRand) * u_glow * 0.3 * sliceRand; - col += sigGrain(uv); + col += pal(int(mod(slice, 5.0))) * (1.0 - sliceRand) * 0.3 * 0.3 * sliceRand; return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/plasma-bloom.js b/flow-state/src/scenes/shader/plasma-bloom.js index 1e89856..35b9cf4 100644 --- a/flow-state/src/scenes/shader/plasma-bloom.js +++ b/flow-state/src/scenes/shader/plasma-bloom.js @@ -16,13 +16,11 @@ export const plasmaBloom = { speed: { type: 'float', range: [0.02, 0.5], default: 0.1, uniform: 'u_speed', bias: 'motion', rate: true }, bands: { type: 'float', range: [1, 10], default: 3.5, uniform: 'u_bands' }, softness:{ type: 'float', range: [0, 1], default: 0.5, uniform: 'u_softness' }, - glow: { type: 'float', range: [0, 1.5], default: 0.4, uniform: 'u_glow', bias: 'energy' }, palette: { type: 'palette', count: 6 }, }, reactive: { warp: { feature: 'bandLow', amount: 0.35 }, - glow: { feature: 'beat', amount: 0.35, response: 'spike' }, bands: { feature: 'centroid', amount: 0.2, response: 'smooth' }, }, @@ -42,13 +40,11 @@ vec4 scene(vec2 uv, vec2 p) { vec3 col = palRamp(shaped * 0.6 + length(r) * 0.25); col *= 0.35 + 0.75 * shaped; - col += pal(4) * pow(shaped, 5.0) * u_glow; // Dark corners so the bloom has somewhere to sit. col *= 0.55 + 0.45 * exp(-dot(p, p) * 0.4); col = sigAir(col, p, smoothstep(0.0, 1.8, length(p))); - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/prism-bloom.js b/flow-state/src/scenes/shader/prism-bloom.js index beeeb7c..7df70ae 100644 --- a/flow-state/src/scenes/shader/prism-bloom.js +++ b/flow-state/src/scenes/shader/prism-bloom.js @@ -19,13 +19,11 @@ export const prismBloom = { thickness: { type: 'float', range: [0.008, 0.05], default: 0.02, uniform: 'u_thickness' }, radius: { type: 'float', range: [0.15, 0.7], default: 0.32, uniform: 'u_radius', bias: 'energy' }, spin: { type: 'float', range: [0, 1.5], default: 0.4, uniform: 'u_spin', bias: 'motion' }, - glow: { type: 'float', range: [0, 1.4], default: 0.5, uniform: 'u_glow', bias: 'energy' }, speed: { type: 'float', range: [0.05, 0.8], default: 0.3, uniform: 'u_speed', bias: 'motion', rate: true }, palette: { type: 'palette', count: 6 }, }, reactive: { - glow: { feature: 'beat', amount: 0.35, response: 'smooth' }, radius: { feature: 'bandLow', amount: 0.2 }, spin: { feature: 'flux', amount: 0.15, response: 'smooth' }, }, @@ -60,9 +58,9 @@ vec4 scene(vec2 uv, vec2 p) { vec2 lp = rot(fi * 0.7 + t * (fi * 0.5 + 0.3) * u_spin) * p; float r = ring(lp, sites, layerRadius * breathe, u_thickness); - col += pal(int(mod(fi, 6.0))) * r * (0.4 + u_glow * 0.8); + col += pal(int(mod(fi, 6.0))) * r * (0.4 + 0.5 * 0.8); - float halo = exp(-(length(lp) / max(layerRadius * breathe, 1e-3)) * 3.0) * u_glow * 0.25; + float halo = exp(-(length(lp) / max(layerRadius * breathe, 1e-3)) * 3.0) * 0.5 * 0.25; col += pal(0) * halo; } @@ -70,9 +68,7 @@ vec4 scene(vec2 uv, vec2 p) { float coreSize = (0.09 + u_beat * 0.06) * stageScale(); float core = castMain(p / max(coreSize, 1e-3)) * coreSize; col = mix(col, pal(3), inkMask(core, uv)); - col += pal(3) * exp(-dot(p, p) * 8.0) * (0.5 + u_glow); - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/psychedelic-drift.js b/flow-state/src/scenes/shader/psychedelic-drift.js index 401accc..ed7a978 100644 --- a/flow-state/src/scenes/shader/psychedelic-drift.js +++ b/flow-state/src/scenes/shader/psychedelic-drift.js @@ -130,7 +130,6 @@ vec4 scene(vec2 uv, vec2 p) { col += pal(i + 2) * intensity * (0.6 + beat); } - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/pylon-grid.js b/flow-state/src/scenes/shader/pylon-grid.js index c3ae5a1..35b0cbd 100644 --- a/flow-state/src/scenes/shader/pylon-grid.js +++ b/flow-state/src/scenes/shader/pylon-grid.js @@ -12,7 +12,7 @@ export const pylonGrid = { // Takes the track's surface grain, but lightly — this is drawn, not filmed. texture: 0.4, consumes: ['cast', 'ink'], - traits: ['shape', 'space'], + traits: ['shape', 'space', 'style'], params: { columns: { type: 'float', range: [3, 16], default: 8, uniform: 'u_columns', bias: 'density' }, @@ -80,7 +80,6 @@ vec4 scene(vec2 uv, vec2 p) { // Ground haze and the shared air between here and the horizon. col = sigAir(col, p, smoothstep(0.0, 1.6, abs(p.y - hy))); - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/quasicrystal.js b/flow-state/src/scenes/shader/quasicrystal.js index 7205dfb..35e5981 100644 --- a/flow-state/src/scenes/shader/quasicrystal.js +++ b/flow-state/src/scenes/shader/quasicrystal.js @@ -25,13 +25,11 @@ export const quasicrystal = { speed: { type: 'float', range: [0.02, 0.7], default: 0.15, uniform: 'u_speed', bias: 'motion', rate: true }, contrast: { type: 'float', range: [0.5, 6], default: 2.0, uniform: 'u_contrast' }, threshold: { type: 'float', range: [0, 0.9], default: 0.35, uniform: 'u_threshold' }, - glow: { type: 'float', range: [0, 1.5], default: 0.5, uniform: 'u_glow', bias: 'energy' }, breathe: { type: 'float', range: [0, 0.5], default: 0.15, uniform: 'u_breathe' }, palette: { type: 'palette', count: 5 }, }, reactive: { - glow: { feature: 'bandHigh', amount: 0.35, response: 'smooth' }, threshold: { feature: 'bandLow', amount: 0.2, response: 'smooth' }, }, @@ -67,11 +65,9 @@ vec4 scene(vec2 uv, vec2 p) { // Ridges: where the sum crosses zero, which is the aperiodic skeleton. float ridge = 1.0 - abs(shaped); - col += pal(4) * pow(sat(ridge), 6.0) * u_glow; - col += pal(3) * inkStroke(shaped) * u_glow * 0.3; + col += pal(3) * inkStroke(shaped) * 0.5 * 0.3; col *= 0.65 + 0.35 * exp(-dot(p, p) * 0.22); - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/rain-column.js b/flow-state/src/scenes/shader/rain-column.js index 83522ca..6ed1bdc 100644 --- a/flow-state/src/scenes/shader/rain-column.js +++ b/flow-state/src/scenes/shader/rain-column.js @@ -22,12 +22,10 @@ export const rainColumn = { wind: { type: 'float', range: [-0.9, 0.9], default: 0.25, uniform: 'u_wind' }, gust: { type: 'float', range: [0, 0.5], default: 0.15, uniform: 'u_gust' }, wet: { type: 'float', range: [0, 1], default: 0.55, uniform: 'u_wet' }, - glow: { type: 'float', range: [0, 1.4], default: 0.5, uniform: 'u_glow', bias: 'energy' }, palette: { type: 'palette', count: 5 }, }, reactive: { - glow: { feature: 'loudness', amount: 0.3, response: 'smooth' }, wet: { feature: 'bandLow', amount: 0.2, response: 'smooth' }, }, @@ -63,7 +61,6 @@ vec4 scene(vec2 uv, vec2 p) { // Sky: darkest overhead, brightest where the light gets under the cloud. vec3 col = mix(pal(1) * 0.22, pal(0) * 0.06, sat(above * 0.7 + 0.1)); - col += pal(3) * exp(-abs(above) * 6.0) * u_glow * 0.35; // Three depth layers: far is dense, slow and dim; near is sparse, fast and // wide. Same shear, so they read as one storm seen through itself. @@ -82,7 +79,7 @@ vec4 scene(vec2 uv, vec2 p) { } rain *= smoothstep(-0.05, 0.35, above); // no rain below the ground - col += palRamp(0.55 + rain * 0.2) * rain * (0.55 + u_glow * 0.65); + col += palRamp(0.55 + rain * 0.2) * rain * (0.55 + 0.5 * 0.65); { float depth = sat(-above * 2.4); @@ -91,7 +88,7 @@ vec4 scene(vec2 uv, vec2 p) { // Wet ground: a compressed mirror of the sky glow, broken up by the // ripples the rain is putting into it. The mirror is what makes the // ground read as water rather than as a dark half of the frame. - ground += pal(3) * exp(above * 4.0) * u_glow * 1.1 * u_wet; + ground += pal(3) * exp(above * 4.0) * 0.5 * 1.1 * u_wet; float ripple = sin((-above * 26.0) - t * 5.0 + vnoise(vec2(p.x * 5.0, t * 0.7)) * 7.0); ground += pal(4) * sat(ripple) * u_wet * (0.06 + depth * 0.3); @@ -101,7 +98,6 @@ vec4 scene(vec2 uv, vec2 p) { } col = sigAir(col, p, smoothstep(0.2, 1.5, abs(p.x) * 0.6 + sat(above))); - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/ridge-terrain.js b/flow-state/src/scenes/shader/ridge-terrain.js index de54491..3e28613 100644 --- a/flow-state/src/scenes/shader/ridge-terrain.js +++ b/flow-state/src/scenes/shader/ridge-terrain.js @@ -17,14 +17,12 @@ export const ridgeTerrain = { rough: { type: 'float', range: [1, 6], default: 2.5, uniform: 'u_rough' }, speed: { type: 'float', range: [0.01, 0.3], default: 0.06, uniform: 'u_speed', bias: 'motion', rate: true }, horizon: { type: 'float', range: [-0.4, 0.4], default: 0.0, uniform: 'u_horizon' }, - haze: { type: 'float', range: [0, 1], default: 0.5, uniform: 'u_haze' }, stars: { type: 'float', range: [0, 1], default: 0.3, uniform: 'u_stars' }, palette: { type: 'palette', count: 6 }, }, reactive: { height: { feature: 'bandLow', amount: 0.25, response: 'smooth' }, - haze: { feature: 'beat', amount: 0.2, response: 'spike' }, }, shader: ` @@ -63,15 +61,14 @@ vec4 scene(vec2 uv, vec2 p) { float mask = smoothstep(0.004, 0.0, p.y - top); vec3 tint = mix(pal(2), pal(4), depth); // Distant layers wash out toward the sky colour. - tint = mix(mix(pal(1) * 0.4, tint, 0.35 + depth * 0.65), tint, 1.0 - u_haze * (1.0 - depth)); + tint = mix(mix(pal(1) * 0.4, tint, 0.35 + depth * 0.65), tint, 1.0 - 0.5 * (1.0 - depth)); col = mix(col, tint * (0.25 + depth * 0.75), mask); // Rim light along each crest. - col += pal(5) * smoothstep(0.02, 0.0, abs(p.y - top)) * (0.12 + depth * 0.25) * u_haze; + col += pal(5) * smoothstep(0.02, 0.0, abs(p.y - top)) * (0.12 + depth * 0.25) * 0.5; } - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/salt-flat.js b/flow-state/src/scenes/shader/salt-flat.js index 67f5678..aa16e93 100644 --- a/flow-state/src/scenes/shader/salt-flat.js +++ b/flow-state/src/scenes/shader/salt-flat.js @@ -20,7 +20,6 @@ export const saltFlat = { monolith: { type: 'float', range: [0.0, 0.35], default: 0.12, uniform: 'u_monolith' }, standing: { type: 'float', range: [-0.7, 0.7], default: 0.0, uniform: 'u_standing' }, shimmer: { type: 'float', range: [0, 0.09], default: 0.025,uniform: 'u_shimmer' }, - glowBand: { type: 'float', range: [0, 1.2], default: 0.45, uniform: 'u_glowBand', bias: 'energy' }, ground: { type: 'float', range: [0, 1], default: 0.4, uniform: 'u_ground' }, salt: { type: 'float', range: [0, 1], default: 0.35, uniform: 'u_salt', bias: 'density' }, pace: { type: 'float', range: [0.02, 0.5], default: 0.12, uniform: 'u_pace', bias: 'motion', rate: true }, @@ -28,7 +27,6 @@ export const saltFlat = { }, reactive: { - glowBand: { feature: 'loudness', amount: 0.3, response: 'smooth' }, shimmer: { feature: 'bandAir', amount: 0.25 }, }, @@ -49,7 +47,6 @@ vec4 scene(vec2 uv, vec2 p) { vec3 col = mix(pal(1) * 0.5, pal(0) * 0.25, sat(above * 0.8 + 0.15)); // The glow band sitting on the horizon — the light source of the whole scene. - col += pal(3) * exp(-abs(above) * 9.0) * u_glowBand * 0.8; if (above < 0.0) { float depth = sat(-above * 2.2); // 0 far .. 1 near @@ -61,7 +58,7 @@ vec4 scene(vec2 uv, vec2 p) { plain += pal(4) * smoothstep(0.42, 0.5, crack) * u_salt * depth * 0.25; // Reflection of the glow band, compressed toward the horizon. - plain += pal(3) * exp(above * 7.0) * u_glowBand * 0.3; + plain += pal(3) * exp(above * 7.0) * 0.45 * 0.3; col = mix(col, plain, u_ground); } @@ -71,11 +68,10 @@ vec4 scene(vec2 uv, vec2 p) { vec2 at = vec2(u_standing, horizon + u_monolith * 0.9); float d = castMain((p - at) / u_monolith) * u_monolith; col = mix(col, pal(0) * 0.12, smoothstep(0.006, -0.006, d)); - col += pal(4) * inkStroke(d) * (0.3 + u_glowBand * 0.5); + col += pal(4) * inkStroke(d) * (0.3 + 0.45 * 0.5); } col = sigAir(col, p, smoothstep(0.0, 1.4, abs(p.x))); - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/scale-mosaic.js b/flow-state/src/scenes/shader/scale-mosaic.js index 1b3a1e0..33173aa 100644 --- a/flow-state/src/scenes/shader/scale-mosaic.js +++ b/flow-state/src/scenes/shader/scale-mosaic.js @@ -81,7 +81,6 @@ vec4 scene(vec2 uv, vec2 p) { col += palRamp(0.75) * sweep * u_sheen * 0.2 * smoothstep(0.02, -0.01, d); col *= 0.72 + 0.28 * exp(-r * r * 0.3); - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/scan-tear.js b/flow-state/src/scenes/shader/scan-tear.js index d139ca6..5a43836 100644 --- a/flow-state/src/scenes/shader/scan-tear.js +++ b/flow-state/src/scenes/shader/scan-tear.js @@ -73,7 +73,6 @@ vec4 scene(vec2 uv, vec2 p) { col = max(col, ghost * u_persist); col += pal(4) * torn * u_shift * 0.6; - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/shoji-grid.js b/flow-state/src/scenes/shader/shoji-grid.js index 851504c..d6419f1 100644 --- a/flow-state/src/scenes/shader/shoji-grid.js +++ b/flow-state/src/scenes/shader/shoji-grid.js @@ -81,7 +81,6 @@ vec4 scene(vec2 uv, vec2 p) { col = mix(col, pal(0) * 0.14, wood); col += pal(4) * inkStroke(bar - u_stile) * 0.12; - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/signal-decay.js b/flow-state/src/scenes/shader/signal-decay.js index a84eefc..c2cc5cd 100644 --- a/flow-state/src/scenes/shader/signal-decay.js +++ b/flow-state/src/scenes/shader/signal-decay.js @@ -101,7 +101,6 @@ vec4 scene(vec2 uv, vec2 p) { // vanishing cleanly. col = max(col, prev(uv) * u_persist); - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/silk-ribbon.js b/flow-state/src/scenes/shader/silk-ribbon.js index cc07de7..74f7290 100644 --- a/flow-state/src/scenes/shader/silk-ribbon.js +++ b/flow-state/src/scenes/shader/silk-ribbon.js @@ -18,14 +18,12 @@ export const silkRibbon = { thickness: { type: 'float', range: [0.008, 0.08], default: 0.03, uniform: 'u_thickness' }, wave: { type: 'float', range: [0.1, 2.5], default: 1.1, uniform: 'u_wave' }, sway: { type: 'float', range: [0.05, 0.6], default: 0.25, uniform: 'u_sway', bias: 'motion' }, - glow: { type: 'float', range: [0, 1.5], default: 0.5, uniform: 'u_glow', bias: 'energy' }, speed: { type: 'float', range: [0.02, 0.4], default: 0.12, uniform: 'u_speed', bias: 'motion', rate: true }, spread: { type: 'float', range: [0.5, 1.2], default: 0.9, uniform: 'u_spread' }, palette: { type: 'palette', count: 4 }, }, reactive: { - glow: { feature: 'beat', amount: 0.3, response: 'smooth' }, wave: { feature: 'bandLow', amount: 0.25, response: 'smooth' }, }, @@ -67,14 +65,12 @@ vec4 scene(vec2 uv, vec2 p) { float falloff = mix(2.6, 0.9, sat(u_sigSoft)); vec3 hc = pal(int(fk) % 3); col += hc * exp(-pow(best / w, falloff * 2.0)); - col += pal(3) * exp(-best * best * 60.0) * u_glow * 0.6; } // Knot the ribbon just below frame centre so it has somewhere to pull from. float knot = length(p - vec2(0.0, 0.1)); - col = mix(col, pal(2), exp(-knot * knot * 30.0) * u_glow * 0.5); + col = mix(col, pal(2), exp(-knot * knot * 30.0) * 0.5 * 0.5); - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/slow-orb.js b/flow-state/src/scenes/shader/slow-orb.js index ada9cf5..676df4c 100644 --- a/flow-state/src/scenes/shader/slow-orb.js +++ b/flow-state/src/scenes/shader/slow-orb.js @@ -22,14 +22,11 @@ export const slowOrb = { softness: { type: 'float', range: [0.2, 1.0], default: 0.7, uniform: 'u_softness' }, drift: { type: 'float', range: [0.01, 0.2], default: 0.05, uniform: 'u_drift', bias: 'motion', rate: true }, wobble: { type: 'float', range: [0, 0.5], default: 0.15, uniform: 'u_wobble' }, - halo: { type: 'float', range: [0, 1.2], default: 0.4, uniform: 'u_halo' }, - grain: { type: 'float', range: [0, 0.5], default: 0.12, uniform: 'u_grain' }, palette: { type: 'palette', count: 4 }, }, reactive: { size: { feature: 'loudness', amount: 0.12, response: 'smooth' }, - halo: { feature: 'beat', amount: 0.15, response: 'spike' }, }, shader: ` @@ -51,7 +48,7 @@ vec4 scene(vec2 uv, vec2 p) { // 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; + float glow = exp(-max(d, 0.0) * (5.0 / max(0.4, 0.05))) * 0.4; // 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. @@ -65,8 +62,7 @@ vec4 scene(vec2 uv, vec2 p) { // Fine grain keeps large flat areas from banding. col = sigAir(col, p, smoothstep(0.0, 1.6, length(q))); - col += (hash12(uv * 640.0 + floor(u_frame)) - 0.5) * u_grain * 0.08; - col += sigGrain(uv); + col += (hash12(uv * 640.0 + floor(u_frame)) - 0.5) * 0.12 * 0.08; return vec4(inkValue(col), 1.0); } diff --git a/flow-state/src/scenes/shader/smoke-column.js b/flow-state/src/scenes/shader/smoke-column.js index 72054bb..90137c6 100644 --- a/flow-state/src/scenes/shader/smoke-column.js +++ b/flow-state/src/scenes/shader/smoke-column.js @@ -19,7 +19,6 @@ export const smokeColumn = { scale: { type: 'float', range: [1, 9], default: 3.4, uniform: 'u_scale', bias: 'density' }, speed: { type: 'float', range: [0.05, 1.2], default: 0.32, uniform: 'u_speed', bias: 'motion', rate: true }, detail: { type: 'float', range: [0.2, 2.5], default: 1.1, uniform: 'u_detail', bias: 'density' }, - glow: { type: 'float', range: [0, 1.5], default: 0.5, uniform: 'u_glow', bias: 'energy' }, spread: { type: 'float', range: [0.15, 1.4], default: 0.55, uniform: 'u_spread' }, buoyancy: { type: 'float', range: [0.3, 2.5], default: 1.1, uniform: 'u_buoyancy' }, ember: { type: 'float', range: [0, 1], default: 0.35, uniform: 'u_ember', bias: 'energy' }, @@ -27,7 +26,6 @@ export const smokeColumn = { }, reactive: { - glow: { feature: 'bandLow', amount: 0.3, response: 'smooth' }, detail: { feature: 'bandHigh', amount: 0.25, response: 'smooth' }, ember: { feature: 'beat', amount: 0.25, response: 'spike' }, }, @@ -65,7 +63,6 @@ vec4 scene(vec2 uv, vec2 p) { vec3 col = pal(0) * 0.05; col += palRamp(0.15 + density * 0.35 + rise * 0.08) * plume * 1.15; - col += pal(4) * pow(sat(plume), 3.0) * u_glow * 0.6; // Embers: bright points carried up inside the column, on their own hashed // lanes. Local, so the frame never swings as a whole. @@ -78,10 +75,8 @@ vec4 scene(vec2 uv, vec2 p) { } // The vent itself. - col += pal(2) * exp(-length(vec2(p.x * 2.2, rise * 5.0))) * (0.35 + u_glow * 0.5); col = sigAir(col, p, smoothstep(0.0, 1.8, length(p))); - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/spectrum-sculpture.js b/flow-state/src/scenes/shader/spectrum-sculpture.js index c6dd6b1..1ba6fe7 100644 --- a/flow-state/src/scenes/shader/spectrum-sculpture.js +++ b/flow-state/src/scenes/shader/spectrum-sculpture.js @@ -99,7 +99,6 @@ vec4 scene(vec2 uv, vec2 p) { // Inner ring outline holds the composition together. col += pal(2) * inkStroke(radius - u_radius) * 0.35; - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } diff --git a/flow-state/src/scenes/shader/stairwell-descent.js b/flow-state/src/scenes/shader/stairwell-descent.js index 60a78bb..c6fbbef 100644 --- a/flow-state/src/scenes/shader/stairwell-descent.js +++ b/flow-state/src/scenes/shader/stairwell-descent.js @@ -82,7 +82,6 @@ vec4 scene(vec2 uv, vec2 p) { col = mix(col, pal(1) * 0.3, sky * 0.5); col = sigAir(col, p, sat(1.0 - fade)); - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/storm-rift.js b/flow-state/src/scenes/shader/storm-rift.js index f127061..67e2f6d 100644 --- a/flow-state/src/scenes/shader/storm-rift.js +++ b/flow-state/src/scenes/shader/storm-rift.js @@ -101,7 +101,6 @@ vec4 scene(vec2 uv, vec2 p) { } col = max(col, prev(uv) * u_afterglow); - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/suspension-span.js b/flow-state/src/scenes/shader/suspension-span.js index 9f44c7c..636a720 100644 --- a/flow-state/src/scenes/shader/suspension-span.js +++ b/flow-state/src/scenes/shader/suspension-span.js @@ -24,12 +24,10 @@ export const suspensionSpan = { deck: { type: 'float', range: [-0.7, 0.25], default: -0.2, uniform: 'u_deck', slowAxis: true }, lamp: { type: 'float', range: [0, 0.12], default: 0.045, uniform: 'u_lamp' }, travel: { type: 'float', range: [0.01, 0.3], default: 0.06, uniform: 'u_travel', bias: 'motion', rate: true }, - glow: { type: 'float', range: [0, 1.4], default: 0.55, uniform: 'u_glow', bias: 'energy' }, palette: { type: 'palette', count: 5 }, }, reactive: { - glow: { feature: 'loudness', amount: 0.3, response: 'smooth' }, lamp: { feature: 'beat', amount: 0.2, response: 'spike' }, }, @@ -66,7 +64,7 @@ vec4 scene(vec2 uv, vec2 p) { // Main cable: a parabola from tower top to tower top, lowest mid-bay. float cableY = towerTop - u_sag * u_tower * (1.0 - 4.0 * bay * bay); float dCable = abs(p.y - cableY); - col += palRamp(0.15) * smoothstep(w * 1.6, w * 0.3, dCable) * (0.6 + u_glow * 0.6); + col += palRamp(0.15) * smoothstep(w * 1.6, w * 0.3, dCable) * (0.6 + 0.55 * 0.6); // Hangers: verticals from the cable down to the deck, on their own spacing. float hg = (p.x + t) * u_hangers / u_span; @@ -74,11 +72,11 @@ vec4 scene(vec2 uv, vec2 p) { float hangerCableY = towerTop - u_sag * u_tower * (1.0 - 4.0 * pow(fract(g + (floor(hg) - hg + 0.5) / u_hangers) - 0.5, 2.0)); float inSpan = step(p.y, hangerCableY) * step(deckY, p.y); - col += palRamp(0.3) * smoothstep(w, w * 0.25, abs(hx)) * inSpan * (0.3 + u_glow * 0.35); + col += palRamp(0.3) * smoothstep(w, w * 0.25, abs(hx)) * inSpan * (0.3 + 0.55 * 0.35); // Deck: one heavy line all the way across, which is what stops the cable // reading as a piece of string. - col += pal(4) * smoothstep(w * 2.5, w * 0.6, abs(p.y - deckY)) * (0.4 + u_glow * 0.5); + col += pal(4) * smoothstep(w * 2.5, w * 0.6, abs(p.y - deckY)) * (0.4 + 0.55 * 0.5); col += pal(4) * inkStroke(abs(p.y - deckY) - w * 3.0) * 0.25; // Towers: a pair of legs and a crossbeam, with the signature form as the @@ -89,15 +87,13 @@ vec4 scene(vec2 uv, vec2 p) { if (u_lamp > 0.004) { float d = castMain((vec2(x, p.y) - vec2(0.0, towerTop + u_lamp)) / u_lamp) * u_lamp; - col += pal(3) * smoothstep(0.004, -0.004, d) * (0.6 + u_glow); - col += pal(3) * exp(-abs(d) * 20.0) * u_glow * 0.5; + col += pal(3) * smoothstep(0.004, -0.004, d) * (0.6 + 0.55); col += pal(3) * inkStroke(d) * 0.6; } // Every other bay is a little further off, so the line of the bridge has // some air in it rather than being a flat elevation drawing. col = sigAir(col, p, smoothstep(0.2, 1.4, abs(bay) * 0.7 + hash11(bayId) * 0.5)); - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/synthwave-run.js b/flow-state/src/scenes/shader/synthwave-run.js index 44d81be..342f3ba 100644 --- a/flow-state/src/scenes/shader/synthwave-run.js +++ b/flow-state/src/scenes/shader/synthwave-run.js @@ -21,13 +21,9 @@ export const synthwaveRun = { sun: { type: 'float', range: [0, 1], default: 1.0, uniform: 'u_sun' }, mountains: { type: 'float', range: [0, 1], default: 1.0, uniform: 'u_mountains' }, car: { type: 'float', range: [0, 1], default: 1.0, uniform: 'u_car' }, - glow: { type: 'float', range: [0, 1.5], default: 0.5, uniform: 'u_glow', bias: 'energy' }, palette: { type: 'palette', count: 4 }, }, - reactive: { - glow: { feature: 'beat', amount: 0.45, response: 'spike' }, - }, shader: ` vec4 scene(vec2 uv, vec2 p) { @@ -101,8 +97,6 @@ vec4 scene(vec2 uv, vec2 p) { } // Horizon haze, scaled by the glow param. - col += colorMain * exp(-abs(p.y - horizon) * 8.0) * u_glow * 0.35; - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } diff --git a/flow-state/src/scenes/shader/tide-rings.js b/flow-state/src/scenes/shader/tide-rings.js index cd26ab0..2dcfa4b 100644 --- a/flow-state/src/scenes/shader/tide-rings.js +++ b/flow-state/src/scenes/shader/tide-rings.js @@ -71,7 +71,6 @@ vec4 scene(vec2 uv, vec2 p) { col += pal(4) * pow(sat(wave), 6.0) * u_caustic * 0.5; col = sigAir(col, p, smoothstep(0.0, 1.7, length(p))); - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/time-smear.js b/flow-state/src/scenes/shader/time-smear.js index 0d7fec3..32eec8f 100644 --- a/flow-state/src/scenes/shader/time-smear.js +++ b/flow-state/src/scenes/shader/time-smear.js @@ -23,13 +23,11 @@ export const timeSmear = { stagger: { type: 'float', range: [0, 1], default: 0.7, uniform: 'u_stagger' }, scale: { type: 'float', range: [1, 12], default: 4.2, uniform: 'u_scale', bias: 'density' }, speed: { type: 'float', range: [0.05, 1.2], default: 0.4, uniform: 'u_speed', bias: 'motion', rate: true }, - glow: { type: 'float', range: [0, 1.5], default: 0.5, uniform: 'u_glow', bias: 'energy' }, reshuffle:{ type: 'float', range: [0, 1], default: 0.45, uniform: 'u_reshuffle' }, palette: { type: 'palette', count: 5 }, }, reactive: { - glow: { feature: 'beat', amount: 0.3, response: 'spike' }, scale: { feature: 'bandHigh', amount: 0.2, response: 'smooth' }, }, @@ -47,7 +45,7 @@ vec4 scene(vec2 uv, vec2 p) { float figure = sat(0.5 + arm * 0.5) * exp(-dot(cp, cp) * 0.55); vec3 fresh = palRamp(0.1 + swirl * 0.4 + figure * 0.3) * (0.25 + figure * 1.1); - fresh += pal(4) * pow(figure, 5.0) * u_glow; + fresh += pal(4) * pow(figure, 5.0) * 0.5; // Which band this pixel is in, and how old that band's image is. The // assignment re-rolls on the eighth-bar grid, so the shredding steps with @@ -75,7 +73,6 @@ vec4 scene(vec2 uv, vec2 p) { // Stale bands lose colour, the way a held frame loses its highlights. col = mix(col, vec3(dot(col, vec3(0.299, 0.587, 0.114))), age * 0.35); - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/truchet-fold.js b/flow-state/src/scenes/shader/truchet-fold.js index b747588..4de9df3 100644 --- a/flow-state/src/scenes/shader/truchet-fold.js +++ b/flow-state/src/scenes/shader/truchet-fold.js @@ -21,13 +21,11 @@ export const truchetFold = { weight: { type: 'float', range: [0.04, 0.3], default: 0.12, uniform: 'u_weight' , slowAxis: true }, radius: { type: 'float', range: [0.3, 0.7], default: 0.5, uniform: 'u_radius' }, churn: { type: 'float', range: [0, 1], default: 0.35, uniform: 'u_churn' }, - glow: { type: 'float', range: [0, 1.4], default: 0.5, uniform: 'u_glow', bias: 'energy' }, drift: { type: 'float', range: [0.0, 0.4], default: 0.08, uniform: 'u_drift', bias: 'motion', rate: true }, palette: { type: 'palette', count: 5 }, }, reactive: { - glow: { feature: 'bandMid', amount: 0.35, response: 'smooth' }, weight: { feature: 'beat', amount: 0.15, response: 'spike' }, }, @@ -64,11 +62,10 @@ vec4 scene(vec2 uv, vec2 p) { vec3 col = pal(0) * 0.05; col += tint * line * 0.75; - col += tint * halo * u_glow * 0.35; - col += pal(4) * inkStroke(d) * u_glow * 0.25; + col += tint * halo * 0.5 * 0.35; + col += pal(4) * inkStroke(d) * 0.5 * 0.25; col *= 0.65 + 0.35 * exp(-dot(p, p) * 0.25); - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/turing-bloom.js b/flow-state/src/scenes/shader/turing-bloom.js index 3b5de88..323fe00 100644 --- a/flow-state/src/scenes/shader/turing-bloom.js +++ b/flow-state/src/scenes/shader/turing-bloom.js @@ -35,14 +35,12 @@ export const turingBloom = { settle: { type: 'float', range: [0.95, 0.999], default: 0.985, uniform: 'u_settle' }, fill: { type: 'float', range: [0.15, 0.85], default: 0.5, uniform: 'u_fill' }, pace: { type: 'float', range: [0.006, 0.06], default: 0.015, uniform: 'u_pace', bias: 'motion', rate: true }, - glow: { type: 'float', range: [0, 1.3], default: 0.5, uniform: 'u_glow' }, palette: { type: 'palette', count: 5 }, }, reactive: { sharpen: { feature: 'bandLow', amount: 0.3, response: 'smooth' }, seedIn: { feature: 'flux', amount: 0.25, response: 'spike' }, - glow: { feature: 'loudness', amount: 0.3, response: 'smooth' }, }, shader: ` @@ -114,10 +112,9 @@ vec4 scene(vec2 uv, vec2 p) { // Rims: where the pattern is changing fastest, which is the edge of every // blob and the seam of every stripe. float rim = sat(abs(near - far) * 6.0); - col += pal(4) * rim * u_glow * (0.15 + u_sigLine * 1.8); + col += pal(4) * rim * 0.5 * (0.15 + u_sigLine * 1.8); col *= 0.75 + 0.25 * exp(-dot(p, p) * 0.2); - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/voronoi-shatter.js b/flow-state/src/scenes/shader/voronoi-shatter.js index 7c44be7..2cc085d 100644 --- a/flow-state/src/scenes/shader/voronoi-shatter.js +++ b/flow-state/src/scenes/shader/voronoi-shatter.js @@ -29,13 +29,11 @@ export const voronoiShatter = { 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' }, }, @@ -80,15 +78,13 @@ vec4 scene(vec2 uv, vec2 p) { 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(4) * seam * (0.4 + 0.6 * 0.8); col += pal(3) * inkStroke(border - u_seam) * 0.4; col *= 0.75 + 0.25 * exp(-dot(p, p) * 0.25); - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/shader/vortex-drift.js b/flow-state/src/scenes/shader/vortex-drift.js index e5f85db..0c334e8 100644 --- a/flow-state/src/scenes/shader/vortex-drift.js +++ b/flow-state/src/scenes/shader/vortex-drift.js @@ -71,7 +71,6 @@ vec4 scene(vec2 uv, vec2 p) { col += pal(4) * exp(-max(d, 0.0) * 18.0) * 0.35; } - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/stage/constellation.js b/flow-state/src/scenes/stage/constellation.js index 172db64..b513608 100644 --- a/flow-state/src/scenes/stage/constellation.js +++ b/flow-state/src/scenes/stage/constellation.js @@ -64,7 +64,6 @@ vec4 scene(vec2 uv, vec2 p) { } col += pal(2) * glow * 0.35; - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/stage/procession.js b/flow-state/src/scenes/stage/procession.js index c138652..dac8d2e 100644 --- a/flow-state/src/scenes/stage/procession.js +++ b/flow-state/src/scenes/stage/procession.js @@ -64,7 +64,6 @@ vec4 scene(vec2 uv, vec2 p) { col = mix(col, pal(i + 2), inkMask(d, uv) * (0.35 + 0.65 * (1.0 - back))); } - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/stage/soloist.js b/flow-state/src/scenes/stage/soloist.js index bd26749..deb46af 100644 --- a/flow-state/src/scenes/stage/soloist.js +++ b/flow-state/src/scenes/stage/soloist.js @@ -18,13 +18,11 @@ export const soloist = { echoStep: { type: 'float', range: [0.05, 0.5], default: 0.18, uniform: 'u_echoStep' }, turn: { type: 'float', range: [0, 0.8], default: 0.12, uniform: 'u_turn', bias: 'motion', rate: true }, offset: { type: 'vec2', range: [-0.4, 0.4], default: [0, 0], uniform: 'u_offset' }, - halo: { type: 'float', range: [0, 1], default: 0.3, uniform: 'u_halo', bias: 'energy' }, palette: { type: 'palette', count: 4 }, }, reactive: { size: { feature: 'beat', amount: 0.1, response: 'spike' }, - halo: { feature: 'loudness', amount: 0.4 }, }, shader: ` @@ -52,9 +50,8 @@ vec4 scene(vec2 uv, vec2 p) { vec2 q = rot(t) * (p - u_offset) / max(size0, 1e-3); float d = castMain(q) * size0; col = mix(col, pal(2), inkMask(d, uv)); - col += pal(3) * u_halo * (1.0 - smoothstep(0.0, size0 * 1.5, abs(d))) * 0.5; + col += pal(3) * 0.3 * (1.0 - smoothstep(0.0, size0 * 1.5, abs(d))) * 0.5; - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/src/scenes/stage/swarm.js b/flow-state/src/scenes/stage/swarm.js index ab98bd9..7680bb5 100644 --- a/flow-state/src/scenes/stage/swarm.js +++ b/flow-state/src/scenes/stage/swarm.js @@ -18,12 +18,10 @@ export const swarm = { speed: { type: 'float', range: [0.05, 0.9], default: 0.25,uniform: 'u_speed', bias: 'motion', rate: true }, cohesion:{ type: 'float', range: [0, 1], default: 0.5, uniform: 'u_cohesion' }, field: { type: 'float', range: [0.4, 3.0], default: 1.2, uniform: 'u_field' }, - trail: { type: 'float', range: [0, 0.9], default: 0.3, uniform: 'u_trail', bias: 'energy' }, palette: { type: 'palette', count: 4 }, }, reactive: { - trail: { feature: 'flux', amount: 0.3 }, size: { feature: 'bandLow', amount: 0.2 }, }, @@ -50,10 +48,9 @@ vec4 scene(vec2 uv, vec2 p) { float d = castChorus(q) * u_size * node.z; col = mix(col, pal(i + 1), inkMask(d, uv)); - col += pal(2) * u_trail * 0.004 / (0.02 + abs(d)); + col += pal(2) * 0.3 * 0.004 / (0.02 + abs(d)); } - col += sigGrain(uv); return vec4(inkValue(col), 1.0); } `, diff --git a/flow-state/tools/lint-scenes.js b/flow-state/tools/lint-scenes.js index 4a802bd..ef60b61 100644 --- a/flow-state/tools/lint-scenes.js +++ b/flow-state/tools/lint-scenes.js @@ -107,11 +107,16 @@ const CONTRACT_UNIFORMS = new Set([ // sigShape ever did — the form is the subject rather than a hint applied to one // — so castMain/castChorus count as evidence. // -// The INK does not work the same way and must not be listed under `style`. A -// trait is a property of the track that a scene may honour; an artifact is -// content it draws. Taking the ink says nothing about whether the scene -// responds to u_sigLine, and treating it as evidence let Eclipse Field claim a -// trait it had stopped honouring — which the runtime gate then caught. +// The INK counts under `style` too, but only since surface treatment moved out +// of the scenes. It did not when the two were independent — an earlier version +// listed it here, Eclipse Field claimed a trait it had stopped honouring, and +// the runtime gate caught it. What changed is that sigGrain went to the post +// chain and sigEdge became inkStroke, leaving the trait with nothing of its own +// to express, so inkStroke and inkMask now read u_sigLine and u_sigSoft +// directly. A scene drawing in the song's hand honours the track's line weight +// by construction, and the runtime probe confirms it rather than taking it on +// trust. +// // The same idea as TRAIT_EVIDENCE, for the identity artifacts: a scene that // declares it consumes the cast has to actually draw it. Without this, // `consumes` is a comment, and the migration becomes unverifiable the moment it @@ -126,7 +131,7 @@ const TRAIT_EVIDENCE = { shape: /\b(sig(Shape|Form)|cast(Main|Chorus|SDF|Form))\s*\(/, camera: /\bsigCamera\s*\(/, space: /\b(sigHorizonY|sigAir)\s*\(|\bu_sig(Horizon|Depth|Wash)\b/, - style: /\b(sigEdge|sigGrain|sigFolded)\s*\(|\bu_sig(Line|Soft|Texture|Fold)\b/, + style: /\b(sigEdge|sigGrain|sigFolded|ink(Mask|Stroke|Value|Pattern))\s*\(|\bu_sig(Line|Soft|Texture|Fold)\b/, }; // Every shader in this project lives inside a JS template literal, so a