// Ported from party-stage's "Drugged Out Flow". // // The original ran its own 15-second internal scene timer to keep itself // interesting. That job now belongs to the arc driver, which knows where the // song's actual transitions are — so the internal timer is gone and the scene // variety is driven by `variant`, a param the arc can step. export const psychedelicDrift = { name: 'Psychedelic Drift', family: 'glitch', kind: 'fragment', // Personality: see look/Personality.js. traits: ['shape', 'camera', 'style'], params: { count: { type: 'int', range: [4, 24], default: 12, uniform: 'u_count', bias: 'density' }, variant: { type: 'float', range: [0, 8], default: 0, uniform: 'u_variant' }, warp: { type: 'float', range: [0, 0.6], default: 0.2, uniform: 'u_warp', bias: 'energy' }, beams: { type: 'int', range: [0, 5], default: 3, uniform: 'u_beams' }, symbolSize: { type: 'float', range: [0.03, 0.14], default: 0.07, uniform: 'u_symbolSize' }, speed: { type: 'float', range: [0.05, 0.8], default: 0.2, uniform: 'u_speed', bias: 'motion', rate: true }, palette: { type: 'palette', count: 6 }, }, reactive: { warp: { feature: 'beat', amount: 0.35, response: 'spike' }, symbolSize: { feature: 'bandLow', amount: 0.25 }, }, shader: ` float sdCircle(vec2 p, float r) { return length(p) - r; } float sdStar(vec2 p, float r, float points) { float a = atan(p.y, p.x); float seg = 6.28318530718 / points; a = mod(a + seg * 0.5, seg) - seg * 0.5; return length(p) * cos(a) - r * 0.5; } float sdSmiley(vec2 p, float r, float t, float id) { float d = sdCircle(p, r); float blink = smoothstep(0.9, 0.95, sin(t * 0.5 + id * 1.2)); float eyeR = 0.18 * r * (1.0 - blink * 0.9); d = max(d, -sdCircle(vec2(abs(p.x) - 0.3 * r, p.y - 0.35 * r), eyeR)); float mouthType = sin(t * 1.2 + id); if (mouthType > 0.6) { d = max(d, -sdCircle(p - vec2(0.0, -0.2) * r, 0.15 * r)); } else if (mouthType > -0.6) { float mouth = sdCircle(p - vec2(0.0, -0.1) * r, 0.45 * r); mouth = max(mouth, -(p.y - (0.05 + 0.1 * u_beat) * r)); d = max(d, -mouth); } else { d = max(d, -sdCircle(p - vec2(0.0, -0.25) * r, 0.08 * r)); } return d; } float distToSegment(vec2 p, vec2 a, vec2 b) { vec2 pa = p - a, ba = b - a; float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0); return length(pa - ba * h); } vec4 scene(vec2 uv, vec2 p) { float t = u_time * u_speed + u_seed; float beat = u_beat; float vs = u_seed + floor(u_variant) * 100.0; // Swirling background. p = sigCamera(p); float bg = sin(p.x * 3.0 + t) * cos(p.y * 3.0 - t * 0.7) + sin(length(p) * 4.0 - t); vec3 col = mix(pal(0) * 0.12, pal(1) * 0.18, bg * 0.5 + 0.5); col += pal(0) * 0.05 * beat; // Lens distortion that drags everything toward a wandering centre. vec2 centre = vec2(sin(t * 0.3 + vs) * 0.5, cos(t * 0.4 + vs * 1.1) * 0.5); float radius = 0.35 + beat * 0.15; float dc = length(p - centre); vec2 dp = p; if (dc < radius && dc > 1e-4) { dp += normalize(p - centre) * smoothstep(radius, 0.0, dc) * (u_warp + beat * 0.2); } // Beam endpoints, precomputed so symbols can react to them. vec2 b1[5], b2[5]; for (int j = 0; j < 5; j++) { float ls = vs + float(j) * 789.0; b1[j] = vec2(sin(t * 0.4 + ls) * 0.8, cos(t * 0.3 + ls * 1.1) * 0.5); b2[j] = vec2(sin(t * 0.5 + ls * 1.5) * 0.8, cos(t * 0.4 + ls * 1.7) * 0.5); } for (int i = 0; i < 24; i++) { if (i >= u_count) break; float fi = float(i); float s = vs + fi * 123.456; float speed = 0.3 + hash11(s) * 0.4; vec2 basePos = vec2(sin(t * speed + s) * 0.8, cos(t * speed * 0.8 + s * 1.4) * 0.5); vec2 pos = mix(basePos, centre, 0.15 + beat * 0.1); vec2 sp = rot(t * (0.1 + fract(s * 0.7))) * (dp - pos); float size = u_symbolSize * (0.7 + fract(s * 0.3) * 0.6); float d; float kind = mod(fi + floor(u_variant), 3.0); // One of the three symbol kinds is the track's own form, so its cast of // characters includes the one every other scene is built from. if (kind == 0.0) d = sdStar(sp, size, 5.0 + floor(hash11(s * 1.2) * 3.0)); else if (kind == 1.0) d = sdSmiley(sp, size, u_time, fi); else d = sigShape(sp / max(size, 1e-3)) * size; float hit = 0.0; for (int j = 0; j < 5; j++) { if (j >= u_beams) break; hit = max(hit, smoothstep(0.15, 0.0, distToSegment(pos, b1[j], b2[j]))); } vec3 sc = mix(pal(i + int(floor(t * 0.3))), vec3(1.0), hit * 0.8); float intensity = smoothstep(0.012, 0.0, d); col = mix(col, sc, intensity * sat(0.7 + beat * 0.3 + hit)); col += sc * (1.0 - smoothstep(0.0, size * 2.5, abs(d))) * 0.15 * (0.5 + beat * 0.5 + hit * 2.0); } for (int i = 0; i < 5; i++) { if (i >= u_beams) break; float w = 0.008 + beat * 0.005; float intensity = smoothstep(w, 0.0, distToSegment(dp, b1[i], b2[i])); col += pal(i + 2) * intensity * (0.6 + beat); } col += sigGrain(uv); return vec4(col, 1.0); } `, }; export default psychedelicDrift;