Feature: Drugged Out Flow visualizer
This commit is contained in:
parent
887d3970ab
commit
070f4d6e01
206
party-stage/src/visualizers/DruggedOutFlowVisualizer.js
Normal file
206
party-stage/src/visualizers/DruggedOutFlowVisualizer.js
Normal file
@ -0,0 +1,206 @@
|
||||
import { VisualizerInterface } from './VisualizerInterface.js';
|
||||
|
||||
const fragmentShader = `
|
||||
uniform float u_time;
|
||||
uniform float u_beat;
|
||||
uniform float u_opacity;
|
||||
uniform vec2 u_resolution;
|
||||
uniform vec3 u_colors[16];
|
||||
uniform int u_colorCount;
|
||||
uniform float u_seed;
|
||||
varying vec2 vUv;
|
||||
|
||||
// --- Utility Functions ---
|
||||
float hash(float n) { return fract(sin(n) * 43758.5453123); }
|
||||
vec2 rotate(vec2 p, float a) {
|
||||
float s = sin(a);
|
||||
float c = cos(a);
|
||||
return mat2(c, -s, s, c) * p;
|
||||
}
|
||||
|
||||
// --- SDFs for Shapes ---
|
||||
float sdCircle(vec2 p, float r) {
|
||||
return length(p) - r;
|
||||
}
|
||||
|
||||
float sdStar(vec2 p, float r, float spikes) {
|
||||
float an = atan(p.y, p.x) / (2.0 * 3.14159265359);
|
||||
an = fract(an * spikes);
|
||||
float r2 = r * mix(0.6, 1.0, step(0.5, an));
|
||||
return length(p) - r2;
|
||||
}
|
||||
|
||||
float sdSmiley(vec2 p, float r, float t, float id) {
|
||||
float d = sdCircle(p, r);
|
||||
|
||||
// Eyes: Bigger and higher. Animate blinking.
|
||||
float eyeBlink = smoothstep(0.9, 0.95, sin(t * 0.5 + id * 1.2));
|
||||
float eyeR = 0.18 * r * (1.0 - eyeBlink * 0.9);
|
||||
vec2 eyePos = vec2(0.3, 0.35) * r;
|
||||
d = max(d, -sdCircle(vec2(abs(p.x) - eyePos.x, p.y - eyePos.y), eyeR));
|
||||
|
||||
// Mouth: Changes shape (Smile/Surprise/Small mouth)
|
||||
float mouthType = sin(t * 1.2 + id);
|
||||
if (mouthType > 0.6) { // Surprise
|
||||
d = max(d, -sdCircle(p - vec2(0.0, -0.2) * r, 0.15 * r));
|
||||
} else if (mouthType > -0.6) { // Smile
|
||||
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)); // Open more on beat
|
||||
d = max(d, -mouth);
|
||||
} else { // Small mouth
|
||||
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);
|
||||
}
|
||||
|
||||
// --- Main Shader ---
|
||||
void main() {
|
||||
// LED Grid Setup
|
||||
float ledCountX = u_resolution.x;
|
||||
float ledCountY = u_resolution.y;
|
||||
vec2 gridUV = vec2(vUv.x * ledCountX, vUv.y * ledCountY);
|
||||
vec2 gridDeriv = fwidth(gridUV);
|
||||
float gridDensity = max(gridDeriv.x, gridDeriv.y);
|
||||
float blurFactor = smoothstep(0.3, 0.8, gridDensity);
|
||||
vec2 cell = fract(gridUV);
|
||||
vec2 uv = mix((floor(gridUV) + 0.5) / vec2(ledCountX, ledCountY), vUv, blurFactor);
|
||||
|
||||
float distMask = distance(cell, vec2(0.5));
|
||||
float edgeSoftness = clamp(gridDensity * 1.5, 0.0, 0.5);
|
||||
float mask = 1.0 - smoothstep(0.35 - edgeSoftness, 0.45 + edgeSoftness, distMask);
|
||||
mask = mix(mask, 1.0, blurFactor);
|
||||
|
||||
// Aspect correction
|
||||
vec2 p = (uv - 0.5);
|
||||
p.x *= u_resolution.x / u_resolution.y;
|
||||
|
||||
float t = u_time * 0.2 + u_seed;
|
||||
float beat = u_beat;
|
||||
|
||||
// --- Background: Swirling psychedelic colors ---
|
||||
vec3 colorA = vec3(0.05, 0.0, 0.1);
|
||||
vec3 colorB = vec3(0.1, 0.0, 0.2);
|
||||
if (u_colorCount >= 2) {
|
||||
colorA = u_colors[0] * 0.1;
|
||||
colorB = u_colors[int(mod(1.0, float(u_colorCount)))] * 0.15;
|
||||
}
|
||||
|
||||
float bgNoise = sin(p.x * 3.0 + t) * cos(p.y * 3.0 - t * 0.7) + sin(length(p) * 4.0 - t);
|
||||
vec3 finalColor = mix(colorA, colorB, bgNoise * 0.5 + 0.5);
|
||||
finalColor += colorA * 0.05 * beat; // Flash background on beat
|
||||
|
||||
// --- Scene Switching Logic ---
|
||||
float sceneDuration = 15.0;
|
||||
float sceneIndex = floor(t / sceneDuration);
|
||||
float currentSceneSeed = u_seed + sceneIndex * 100.0;
|
||||
|
||||
// --- "Splitting Eyes" Distortion ---
|
||||
vec2 distortionCenter = vec2(sin(t * 0.3 + currentSceneSeed) * 0.5, cos(t * 0.4 + currentSceneSeed * 1.1) * 0.5);
|
||||
float distortionRadius = 0.35 + beat * 0.15;
|
||||
float distToDistortion = length(p - distortionCenter);
|
||||
|
||||
vec2 distortedP = p;
|
||||
if (distToDistortion < distortionRadius) {
|
||||
float strength = smoothstep(distortionRadius, 0.0, distToDistortion);
|
||||
distortedP += normalize(p - distortionCenter) * strength * (0.15 + beat * 0.2);
|
||||
}
|
||||
|
||||
// --- Pre-calculate Lasers for interaction ---
|
||||
vec2 lp1[3], lp2[3];
|
||||
for (int j = 0; j < 3; j++) {
|
||||
float laserSeed = currentSceneSeed + float(j) * 789.0;
|
||||
lp1[j] = vec2(sin(t * 0.4 + laserSeed) * 0.8, cos(t * 0.3 + laserSeed * 1.1) * 0.5);
|
||||
lp2[j] = vec2(sin(t * 0.5 + laserSeed * 1.5) * 0.8, cos(t * 0.4 + laserSeed * 1.7) * 0.5);
|
||||
}
|
||||
|
||||
// --- Render Symbols ---
|
||||
int numSymbols = 8 + int(mod(currentSceneSeed, 16.0));
|
||||
for (int i = 0; i < 24; i++) {
|
||||
if (i >= numSymbols) break;
|
||||
float fi = float(i);
|
||||
float symbolSeed = currentSceneSeed + fi * 123.456;
|
||||
|
||||
// Motion: Orbital + attraction to distortion center
|
||||
float speed = 0.3 + hash(symbolSeed) * 0.4;
|
||||
vec2 basePos = vec2(
|
||||
sin(t * speed + symbolSeed) * 0.8,
|
||||
cos(t * speed * 0.8 + symbolSeed * 1.4) * 0.5
|
||||
);
|
||||
vec2 pos = mix(basePos, distortionCenter, 0.15 + beat * 0.1);
|
||||
|
||||
vec2 sp = distortedP - pos;
|
||||
sp = rotate(sp, t * (0.1 + fract(symbolSeed * 0.7)));
|
||||
|
||||
float d;
|
||||
float size = 0.06 + fract(symbolSeed * 0.3) * 0.04 + beat * 0.02;
|
||||
|
||||
// Determine symbol type based on seed
|
||||
if (mod(fi + sceneIndex, 3.0) == 0.0) { // Stars
|
||||
d = sdStar(sp, size, 5.0 + floor(hash(symbolSeed * 1.2) * 3.0));
|
||||
} else if (mod(fi + sceneIndex, 3.0) == 1.0) { // Smilies
|
||||
d = sdSmiley(sp, size, u_time, fi);
|
||||
} else { // Circles
|
||||
d = sdCircle(sp, size);
|
||||
}
|
||||
|
||||
// Interaction: Check proximity to lasers
|
||||
float laserHit = 0.0;
|
||||
for (int j = 0; j < 3; j++) {
|
||||
float distToLaser = distToSegment(pos, lp1[j], lp2[j]);
|
||||
laserHit = max(laserHit, smoothstep(0.15, 0.0, distToLaser));
|
||||
}
|
||||
|
||||
float intensity = smoothstep(0.01, 0.0, d);
|
||||
|
||||
// Pick a color
|
||||
vec3 symbolColor = vec3(1.0);
|
||||
if (u_colorCount > 0) {
|
||||
int colorIdx = int(mod(fi + floor(t * 0.1), float(u_colorCount)));
|
||||
symbolColor = u_colors[colorIdx];
|
||||
}
|
||||
|
||||
// Interaction: Laser impact
|
||||
symbolColor = mix(symbolColor, vec3(1.0), laserHit * 0.8);
|
||||
float finalGlow = (0.5 + beat * 0.5 + laserHit * 2.0);
|
||||
|
||||
finalColor = mix(finalColor, symbolColor, intensity * clamp(0.7 + beat * 0.3 + laserHit, 0.0, 1.0));
|
||||
|
||||
// Add a slight glow/aura
|
||||
finalColor += symbolColor * (1.0 - smoothstep(0.0, size * 2.5, abs(d))) * 0.15 * finalGlow;
|
||||
}
|
||||
|
||||
// --- Draw Laser Beams ---
|
||||
for (int i = 0; i < 3; i++) {
|
||||
float distToBeam = distToSegment(distortedP, lp1[i], lp2[i]);
|
||||
float beamWidth = 0.008 + beat * 0.005;
|
||||
float beamIntensity = smoothstep(beamWidth, 0.0, distToBeam);
|
||||
|
||||
vec3 beamColor = vec3(1.0);
|
||||
if (u_colorCount > 0) {
|
||||
int colorIdx = int(mod(float(i) + floor(t * 0.2), float(u_colorCount)));
|
||||
beamColor = u_colors[colorIdx];
|
||||
}
|
||||
|
||||
finalColor += beamColor * beamIntensity * (0.6 + beat * 0.4);
|
||||
}
|
||||
|
||||
gl_FragColor = vec4(finalColor, mask * u_opacity);
|
||||
}
|
||||
`;
|
||||
|
||||
export class DruggedOutFlowVisualizer extends VisualizerInterface {
|
||||
getName() {
|
||||
return "Drugged Out Flow";
|
||||
}
|
||||
|
||||
getFragmentShader() {
|
||||
return fragmentShader;
|
||||
}
|
||||
}
|
||||
@ -2,12 +2,14 @@ import { ClassicVisualizer } from './ClassicVisualizer.js';
|
||||
import { NebulaVisualizer } from './NebulaVisualizer.js';
|
||||
import { FloatingShapesVisualizer } from './FloatingShapesVisualizer.js';
|
||||
import { SynthwaveRunVisualizer } from './SynthwaveRunVisualizer.js';
|
||||
import { DruggedOutFlowVisualizer } from './DruggedOutFlowVisualizer.js';
|
||||
|
||||
export const visualizerLibrary = [
|
||||
new ClassicVisualizer(),
|
||||
new NebulaVisualizer(),
|
||||
new FloatingShapesVisualizer(),
|
||||
new SynthwaveRunVisualizer(),
|
||||
new DruggedOutFlowVisualizer(),
|
||||
];
|
||||
|
||||
export default visualizerLibrary;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user